Skip to content

Instantly share code, notes, and snippets.

@mythagel
Created April 27, 2017 05:37
Show Gist options
  • Save mythagel/2d87ebb861e3cd0019a6dfc2545311a9 to your computer and use it in GitHub Desktop.
Save mythagel/2d87ebb861e3cd0019a6dfc2545311a9 to your computer and use it in GitHub Desktop.
#include <cstdint>
#include <cstdio>
#include <stdexcept>
#include <vector>
// C compatible external api
extern "C" {
// Input / Output value types
enum {
tagFeedrate = 'feed',
tagSpindleSpeed = 'sspd',
tagCutterTeeth = 'ctth',
tagFeedPerTooth = 'fpth',
};
// Input / Output tagged value
struct TaggedValue {
unsigned tag;
double value;
};
// TODO entry point function
// void calculate(TaggedValue* x, unsigned n, ...);
}
// Implementation
// Introduce distinct types for value type enumeration
template <unsigned TAG>
struct Tag {
static constexpr unsigned value = TAG;
};
// A list of the above tag types
template <typename...Tags>
struct TagList { };
// Uses parameter pack to find arguments for function and call from generic list of parameters.
template <typename OUT, typename...IN>
struct TaggedFn {
static unsigned out() {
return OUT::value;
}
template<typename Arg, typename... Args>
static bool all_of(Arg arg, Args... args) { return arg && all_of(args...); }
static bool all_of(bool arg) { return arg; }
static bool has_in(TaggedValue* params, unsigned n) {
auto contains = [params, n](unsigned tag) {
for (unsigned i = 0; i < n; ++i)
if (params[i].tag == tag)
return true;
return false;
};
return all_of(contains(IN::value)...);
}
template <typename Fn>
static double call(Fn fn, TaggedValue* params, unsigned n) {
auto get = [params, n](unsigned tag) {
for (unsigned i = 0; i < n; ++i)
if (params[i].tag == tag)
return params[i].value;
throw std::logic_error("Required input tag not present.");
};
return fn(get(IN::value)...);
}
};
// Helpers to expand TagList back to parameter pack
// base case
template <typename OUT, typename...IN>
struct TagFunction {
using type = TaggedFn<OUT, IN...>;
};
// specialisation for TagList
template <typename OUT, typename...IN>
struct TagFunction<OUT, TagList<IN...>> {
using type = typename TagFunction<OUT, IN...>::type;
};
// List of defined feedrate functions
enum class Functions {
fz
};
template <Functions FunctionTag>
struct traits {};
template <unsigned TAGOUT, unsigned... TAGIN>
struct traits_helper {
using OUT = Tag<TAGOUT>;
using IN = TagList<Tag<TAGIN>...>;
};
// Generic interface type for feedrate functions
template<Functions FunctionTag>
struct Function {
using type = typename TagFunction<typename traits<FunctionTag>::OUT, typename traits<FunctionTag>::IN>::type;
static unsigned out() {
return type::out();
}
static bool has_in(TaggedValue* params, unsigned n) {
return type::has_in(params, n);
}
static double call(TaggedValue* x, unsigned n) {
return type::template call<>(traits<FunctionTag>::fn, x, n);
}
};
// fz function
template <>
struct traits <Functions::fz> : traits_helper<tagFeedPerTooth, tagFeedrate, tagSpindleSpeed, tagCutterTeeth> {
static double fn(double Vf, double n, unsigned Zc) {
return Vf / (n * Zc);
}
};
int main() {
std::vector<TaggedValue> in = {
{tagSpindleSpeed, 3000},
{tagFeedrate, 400},
{tagCutterTeeth, 4}
};
std::vector<TaggedValue> out = {
{tagFeedPerTooth, 0}
};
if (Function<Functions::fz>::has_in(in.data(), in.size())) {
auto v = Function<Functions::fz>::call(in.data(), in.size());
fprintf(stderr, "%f\n", v);
} else {
fprintf(stderr, "Input parameters missing.\n");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment