Simplify the router
There's a lot of complexity left in the router. The recent decision to
only support string arguments means that this can be significantly
cleaned up.
In some cases, this is done to simply expand the variadic template and
handle all parameter cases up to 5 (which should be the max we ever
see). While this might seem like it's not very DRY friendly (Don't
repeat yourself) this is significantly better than what we had, which
was very tough to deciper.
Tested: Redfish service validator passes
Change-Id: Ic72e54cffd7b9f4a85e6c9d143c45fa20530a2cd
Signed-off-by: Ed Tanous <edtanous@google.com>
diff --git a/http/routing.hpp b/http/routing.hpp
index 97daef1..1b2c131 100644
--- a/http/routing.hpp
+++ b/http/routing.hpp
@@ -376,16 +376,60 @@
}
template <uint64_t N>
- typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
- newRuleTagged(const std::string& rule)
+ auto& newRuleTagged(const std::string& rule)
{
- using RuleT = typename black_magic::Arguments<N>::type::template rebind<
- TaggedRule>;
- std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
- RuleT* ptr = ruleObject.get();
- allRules.emplace_back(std::move(ruleObject));
-
- return *ptr;
+ constexpr size_t numArgs = utility::numArgsFromTag(N);
+ if constexpr (numArgs == 0)
+ {
+ using RuleT = TaggedRule<>;
+ std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
+ RuleT* ptr = ruleObject.get();
+ allRules.emplace_back(std::move(ruleObject));
+ return *ptr;
+ }
+ else if constexpr (numArgs == 1)
+ {
+ using RuleT = TaggedRule<std::string>;
+ std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
+ RuleT* ptr = ruleObject.get();
+ allRules.emplace_back(std::move(ruleObject));
+ return *ptr;
+ }
+ else if constexpr (numArgs == 2)
+ {
+ using RuleT = TaggedRule<std::string, std::string>;
+ std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
+ RuleT* ptr = ruleObject.get();
+ allRules.emplace_back(std::move(ruleObject));
+ return *ptr;
+ }
+ else if constexpr (numArgs == 3)
+ {
+ using RuleT = TaggedRule<std::string, std::string, std::string>;
+ std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
+ RuleT* ptr = ruleObject.get();
+ allRules.emplace_back(std::move(ruleObject));
+ return *ptr;
+ }
+ else if constexpr (numArgs == 4)
+ {
+ using RuleT =
+ TaggedRule<std::string, std::string, std::string, std::string>;
+ std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
+ RuleT* ptr = ruleObject.get();
+ allRules.emplace_back(std::move(ruleObject));
+ return *ptr;
+ }
+ else
+ {
+ using RuleT = TaggedRule<std::string, std::string, std::string,
+ std::string, std::string>;
+ std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
+ RuleT* ptr = ruleObject.get();
+ allRules.emplace_back(std::move(ruleObject));
+ return *ptr;
+ }
+ static_assert(numArgs < 5, "Max number of args supported is 5");
}
void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
diff --git a/http/routing/dynamicrule.hpp b/http/routing/dynamicrule.hpp
index 746765c..03452d8 100644
--- a/http/routing/dynamicrule.hpp
+++ b/http/routing/dynamicrule.hpp
@@ -16,160 +16,47 @@
{
namespace routing_handler_call_helper
{
-template <typename T, int Pos>
-struct CallPair
-{
- using type = T;
- static const int pos = Pos;
-};
-
-template <typename H1>
-struct CallParams
-{
- H1& handler;
- const std::vector<std::string>& params;
- const Request& req;
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
-};
-
-template <typename F, int NString, typename S1, typename S2>
-struct Call
-{};
-
-template <typename F, int NString, typename... Args1, typename... Args2>
-struct Call<F, NString, black_magic::S<std::string, Args1...>,
- black_magic::S<Args2...>>
-{
- void operator()(F cparams)
- {
- using pushed = typename black_magic::S<Args2...>::template push_back<
- CallPair<std::string, NString>>;
- Call<F, NString + 1, black_magic::S<Args1...>, pushed>()(cparams);
- }
-};
-
-template <typename F, int NString, typename... Args1>
-struct Call<F, NString, black_magic::S<>, black_magic::S<Args1...>>
-{
- void operator()(F cparams)
- {
- cparams.handler(cparams.req, cparams.asyncResp,
- cparams.params[Args1::pos]...);
- }
-};
template <typename Func, typename... ArgsWrapped>
struct Wrapped
{
template <typename... Args>
- void set(
- Func f,
- typename std::enable_if<
- !std::is_same<
- typename std::tuple_element<0, std::tuple<Args..., void>>::type,
- const Request&>::value,
- int>::type /*enable*/
- = 0)
- {
- handler = [f = std::forward<Func>(f)](
- const Request&,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- Args... args) { asyncResp->res.result(f(args...)); };
- }
-
- template <typename Req, typename... Args>
- struct ReqHandlerWrapper
- {
- explicit ReqHandlerWrapper(Func fIn) : f(std::move(fIn)) {}
-
- void operator()(const Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- Args... args)
- {
- asyncResp->res.result(f(req, args...));
- }
-
- Func f;
- };
-
- template <typename... Args>
- void set(
- Func f,
- typename std::enable_if<
- std::is_same<
- typename std::tuple_element<0, std::tuple<Args..., void>>::type,
- const Request&>::value &&
- !std::is_same<typename std::tuple_element<
- 1, std::tuple<Args..., void, void>>::type,
- const std::shared_ptr<bmcweb::AsyncResp>&>::value,
- int>::type /*enable*/
- = 0)
- {
- handler = ReqHandlerWrapper<Args...>(std::move(f));
- /*handler = (
- [f = std::move(f)]
- (const Request& req, Response& res, Args... args){
- res.result(f(req, args...));
- res.end();
- });*/
- }
-
- template <typename... Args>
- void set(
- Func f,
- typename std::enable_if<
- std::is_same<
- typename std::tuple_element<0, std::tuple<Args..., void>>::type,
- const Request&>::value &&
- std::is_same<typename std::tuple_element<
- 1, std::tuple<Args..., void, void>>::type,
- const std::shared_ptr<bmcweb::AsyncResp>&>::value,
- int>::type /*enable*/
- = 0)
+ void set(Func f)
{
handler = std::move(f);
}
- template <typename... Args>
- struct HandlerTypeHelper
- {
- using type = std::function<void(
- const crow::Request& /*req*/,
- const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
- using args_type = black_magic::S<Args...>;
- };
-
- template <typename... Args>
- struct HandlerTypeHelper<const Request&, Args...>
- {
- using type = std::function<void(
- const crow::Request& /*req*/,
- const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
- using args_type = black_magic::S<Args...>;
- };
-
- template <typename... Args>
- struct HandlerTypeHelper<const Request&,
- const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
- {
- using type = std::function<void(
- const crow::Request& /*req*/,
- const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
- using args_type = black_magic::S<Args...>;
- };
-
- typename HandlerTypeHelper<ArgsWrapped...>::type handler;
+ std::function<void(ArgsWrapped...)> handler;
void operator()(const Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::vector<std::string>& params)
{
- detail::routing_handler_call_helper::Call<
- detail::routing_handler_call_helper::CallParams<decltype(handler)>,
- 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
- black_magic::S<>>()(
- detail::routing_handler_call_helper::CallParams<decltype(handler)>{
- handler, params, req, asyncResp});
+ if constexpr (sizeof...(ArgsWrapped) == 2)
+ {
+ handler(req, asyncResp);
+ }
+ else if constexpr (sizeof...(ArgsWrapped) == 3)
+ {
+ handler(req, asyncResp, params[0]);
+ }
+ else if constexpr (sizeof...(ArgsWrapped) == 4)
+ {
+ handler(req, asyncResp, params[0], params[1]);
+ }
+ else if constexpr (sizeof...(ArgsWrapped) == 5)
+ {
+ handler(req, asyncResp, params[0], params[1], params[2]);
+ }
+ else if constexpr (sizeof...(ArgsWrapped) == 6)
+ {
+ handler(req, asyncResp, params[0], params[1], params[2], params[3]);
+ }
+ else if constexpr (sizeof...(ArgsWrapped) == 7)
+ {
+ handler(req, asyncResp, params[0], params[1], params[2], params[3],
+ params[4]);
+ }
}
};
} // namespace routing_handler_call_helper
diff --git a/http/routing/taggedrule.hpp b/http/routing/taggedrule.hpp
index ef62ab0..5c0fe82 100644
--- a/http/routing/taggedrule.hpp
+++ b/http/routing/taggedrule.hpp
@@ -33,17 +33,14 @@
void operator()(Func&& f)
{
static_assert(
- black_magic::CallHelper<
- Func, black_magic::S<crow::Request,
- std::shared_ptr<bmcweb::AsyncResp>&,
- Args...>>::value,
+ std::is_invocable_v<Func, crow::Request,
+ std::shared_ptr<bmcweb::AsyncResp>&, Args...>,
"Handler type is mismatched with URL parameters");
static_assert(
- std::is_same<
- void,
- decltype(f(std::declval<crow::Request>(),
- std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
- std::declval<Args>()...))>::value,
+ std::is_same_v<
+ void, std::invoke_result_t<Func, crow::Request,
+ std::shared_ptr<bmcweb::AsyncResp>&,
+ Args...>>,
"Handler function with response argument should have void return type");
handler = std::forward<Func>(f);
@@ -53,11 +50,32 @@
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::vector<std::string>& params) override
{
- detail::routing_handler_call_helper::Call<
- detail::routing_handler_call_helper::CallParams<decltype(handler)>,
- 0, black_magic::S<Args...>, black_magic::S<>>()(
- detail::routing_handler_call_helper::CallParams<decltype(handler)>{
- handler, params, req, asyncResp});
+ if constexpr (sizeof...(Args) == 0)
+ {
+ handler(req, asyncResp);
+ }
+ else if constexpr (sizeof...(Args) == 1)
+ {
+ handler(req, asyncResp, params[0]);
+ }
+ else if constexpr (sizeof...(Args) == 2)
+ {
+ handler(req, asyncResp, params[0], params[1]);
+ }
+ else if constexpr (sizeof...(Args) == 3)
+ {
+ handler(req, asyncResp, params[0], params[1], params[2]);
+ }
+ else if constexpr (sizeof...(Args) == 4)
+ {
+ handler(req, asyncResp, params[0], params[1], params[2], params[3]);
+ }
+ else if constexpr (sizeof...(Args) == 5)
+ {
+ handler(req, asyncResp, params[0], params[1], params[2], params[3],
+ params[4]);
+ }
+ static_assert(sizeof...(Args) <= 5, "More args than are supported");
}
private:
diff --git a/http/utility.hpp b/http/utility.hpp
index 59ddf98..94d89fb 100644
--- a/http/utility.hpp
+++ b/http/utility.hpp
@@ -101,47 +101,6 @@
}
return tagValue;
}
-
-template <typename... T>
-struct S
-{
- template <typename U>
- using push = S<U, T...>;
- template <typename U>
- using push_back = S<T..., U>;
- template <template <typename... Args> class U>
- using rebind = U<T...>;
-};
-
-template <typename F, typename Set>
-struct CallHelper;
-
-template <typename F, typename... Args>
-struct CallHelper<F, S<Args...>>
-{
- template <typename F1, typename... Args1,
- typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
- static char test(int);
-
- template <typename...>
- static int test(...);
-
- static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char);
-};
-
-template <uint64_t Tag>
-struct Arguments
-{
- using subarguments = typename Arguments<Tag / 3>::type;
- using type = typename subarguments::template push<std::string>;
-};
-
-template <>
-struct Arguments<0>
-{
- using type = S<>;
-};
-
} // namespace black_magic
namespace utility
@@ -154,6 +113,18 @@
using arg = std::tuple_element_t<i, boost::callable_traits::args_t<T>>;
};
+constexpr size_t numArgsFromTag(int tag)
+{
+ size_t ret = 0;
+ while (tag > 0)
+ {
+ // Move to the next tag by removing the bottom bits from the number
+ tag /= black_magic::toUnderlying(black_magic::TypeCode::Max);
+ ret++;
+ }
+ return ret;
+};
+
inline std::string base64encode(std::string_view data)
{
const std::array<char, 64> key = {