Skip to content

Instantly share code, notes, and snippets.

@flandr
Created February 7, 2015 22:10
Show Gist options
  • Save flandr/7a9effe0008e0fdbdf8a to your computer and use it in GitHub Desktop.
Save flandr/7a9effe0008e0fdbdf8a to your computer and use it in GitHub Desktop.
Some basically insane template-based function dispatching magic
#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);
}
#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