Created
February 7, 2015 22:10
-
-
Save flandr/7a9effe0008e0fdbdf8a to your computer and use it in GitHub Desktop.
Some basically insane template-based function dispatching magic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "exp.h" | |
void no_args() { | |
printf("no args\n"); | |
} | |
void just_pathparams(PathParam<std::string> p1) { | |
printf("just path params: %s\n", p1.value().c_str()); | |
} | |
void multiple_pathparams(PathParam<std::string> p1, PathParam<std::string> p2) { | |
printf("multiple path params: %s %s\n", p1.value().c_str(), p2.value().c_str()); | |
} | |
void mixed_params(PathParam<std::string> p1, QueryParams query, PathParam<std::string> p2) { | |
printf("with query params: %s <qp> %s\n", p1.value().c_str(), p2.value().c_str()); | |
} | |
void foo(std::vector<std::string> const& pp, UriInfo const& ui) { | |
Dispatcher::dispatch(no_args, pp, ui); | |
} | |
void bar(std::vector<std::string> const& pp, UriInfo const& ui) { | |
Dispatcher::dispatch(just_pathparams, pp, ui); | |
} | |
void baz(std::vector<std::string> const& pp, UriInfo const& ui) { | |
Dispatcher::dispatch(mixed_params, pp, ui); | |
} | |
int main(int argc, char **argv) { | |
std::vector<std::string> pathParams { "foo", "bar", "baz" }; | |
UriInfo uriInfo; | |
Dispatcher::dispatch(no_args, pathParams, uriInfo); | |
Dispatcher::dispatch(just_pathparams, pathParams, uriInfo); | |
Dispatcher::dispatch(multiple_pathparams, pathParams, uriInfo); | |
Dispatcher::dispatch(mixed_params, pathParams, uriInfo); | |
foo(pathParams, uriInfo); | |
bar(pathParams, uriInfo); | |
baz(pathParams, uriInfo); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string> | |
#include <vector> | |
template<typename T> | |
T convert(std::string const& str); | |
template<typename T> | |
class PathParam { | |
public: | |
explicit PathParam(std::string const& str) : value_(convert<T>(str)) { } | |
T const& value() const { return value_; } | |
private: | |
T value_; | |
}; | |
template<> | |
std::string convert<std::string>(std::string const& str) { | |
return str; | |
} | |
template<> | |
int convert<int>(std::string const& str) { | |
return atoi(str.c_str()); | |
} | |
class QueryParams { | |
public: | |
}; | |
class PostParams { | |
public: | |
}; | |
class Entity { | |
public: | |
}; | |
class QueryInfo { | |
public: | |
}; | |
class UriInfo { | |
public: | |
QueryParams queryParams; | |
PostParams postParams; | |
Entity entity; | |
}; | |
template<typename T> | |
class NextIndex { | |
public: | |
constexpr static int next(int index) { | |
// By default, don't advance | |
return index; | |
} | |
}; | |
template<typename PT> | |
class NextIndex<PathParam<PT>> { | |
public: | |
constexpr static int next(int index) { | |
return index + 1; | |
} | |
}; | |
template<typename ParamType> | |
class GetParam { | |
public: | |
static typename std::remove_reference<ParamType>::type | |
get(std::vector<std::string> const& params, int index, UriInfo const& uriInfo); | |
}; | |
template<> | |
QueryParams GetParam<QueryParams>::get(std::vector<std::string> const& params, int index, UriInfo const& uriInfo) { | |
return uriInfo.queryParams; | |
} | |
template<> | |
PostParams GetParam<PostParams>::get(std::vector<std::string> const& params, int index, UriInfo const& uriInfo) { | |
return uriInfo.postParams; | |
} | |
template<> | |
Entity GetParam<Entity>::get(std::vector<std::string> const& params, int index, UriInfo const& uriInfo) { | |
return uriInfo.entity; | |
} | |
template<typename PT> | |
class GetParam<PathParam<PT>> { | |
public: | |
static PathParam<PT> | |
get(std::vector<std::string> const& params, int index, UriInfo const& uriInfo) { | |
return PathParam<PT>(params[index]); | |
} | |
}; | |
template<int Length, int Index, typename R1, typename... R> | |
class ExtractorHelper { | |
public: | |
static std::tuple<typename std::remove_reference<R1>::type, | |
typename std::remove_reference<R>::type...> | |
// need R1-specific method to choose the right value (either | |
// convering a path parameter or pulling a field from the uri info | |
// This is "GetParam" | |
// need R1-specific method to determine whether to increment the | |
// index into the path parameters vector. This is "NextIndex" | |
extract(std::vector<std::string> const& pathparams, UriInfo const& uriInfo) { | |
return std::tuple_cat(std::tuple<R1>(GetParam<R1>::get(pathparams, Index, uriInfo)), | |
ExtractorHelper<Length - 1, NextIndex<R1>::next(Index), R...>::extract(pathparams, uriInfo)); | |
} | |
}; | |
// Base case | |
template<int Index, typename R> | |
class ExtractorHelper<1, Index, R> { | |
public: | |
static std::tuple<typename std::remove_reference<R>::type> | |
extract(std::vector<std::string> const& pathparams, UriInfo const& uriInfo) { | |
return std::tuple<typename std::remove_reference<R>::type>(GetParam<R>::get(pathparams, Index, uriInfo)); | |
} | |
}; | |
template<int Length, typename... R> | |
class Extractor { | |
public: | |
static std::tuple<typename std::remove_reference<R>::type...> extract(std::vector<std::string> const& v, | |
UriInfo const& uriInfo) { | |
return ExtractorHelper<Length, 0, R...>::extract(v, uriInfo); | |
} | |
}; | |
template<> | |
class Extractor<0> { | |
public: | |
static std::tuple<> extract(std::vector<std::string> const& v, UriInfo const& uriInfo) { | |
return std::tuple<>(); | |
} | |
}; | |
template<unsigned...> struct index_tuple{}; | |
template<unsigned I, typename IndexTuple, typename... Types> | |
struct make_indices_impl; | |
template<unsigned I, unsigned... Indices, typename T, typename... Types> | |
struct make_indices_impl<I, index_tuple<Indices...>, T, Types...> | |
{ | |
typedef typename | |
make_indices_impl<I + 1, | |
index_tuple<Indices..., I>, | |
Types...>::type type; | |
}; | |
template<unsigned I, unsigned... Indices> | |
struct make_indices_impl<I, index_tuple<Indices...> > | |
{ | |
typedef index_tuple<Indices...> type; | |
}; | |
template<typename... Types> | |
struct make_indices | |
: make_indices_impl<0, index_tuple<>, Types...> | |
{}; | |
template<typename Super, typename Derived, typename Ret, typename... Args, | |
unsigned int... Indices> | |
Ret invoke_member_helper(Super *c, Ret (Derived::*f)(Args...) const, | |
index_tuple<Indices...> /*unused*/, std::tuple<typename std::remove_reference<Args>::type...> const& args) { | |
return (static_cast<const Derived*>(c)->*f)(std::get<Indices>(args)...); | |
} | |
template<typename Ret, typename... Args, unsigned int... Indices> | |
Ret invoke_helper(Ret (*f)(Args...), index_tuple<Indices...> /*unused*/, | |
std::tuple<Args...> const& args) { | |
return f(std::get<Indices>(args)...); | |
} | |
// Invokes a function on a tuple of arguments | |
template<typename Ret, typename... Args> | |
Ret invoke(Ret (*f)(Args...), std::tuple<Args...> const& args) { | |
return invoke_helper(f, typename make_indices<Args...>::type(), args); | |
} | |
// Invokes a member function on a tuple of arguments | |
template<typename Super, typename Derived, typename Ret, typename... Args> | |
Ret invoke_member(Super *c, Ret (Derived::*f)(Args...) const, | |
std::tuple<typename std::remove_reference<Args>::type...> const& args) { | |
return invoke_member_helper(c, f, typename make_indices<Args...>::type(), | |
args); | |
} | |
class Dispatcher { | |
public: | |
template<typename Ret, typename... Args> | |
static Ret dispatch(Ret (*f)(Args...), std::vector<std::string> const& v, UriInfo const& uriInfo) { | |
return invoke(f, Extractor<sizeof...(Args), Args...>::extract(v, uriInfo)); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment