Skip to content

Instantly share code, notes, and snippets.

@amadio
Created April 20, 2017 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amadio/b006524d903e86578df765dffee47605 to your computer and use it in GitHub Desktop.
Save amadio/b006524d903e86578df765dffee47605 to your computer and use it in GitHub Desktop.
TDataFrame Prototype with std::vector as data source
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <vector>
class TDFBranchMap {
public:
template<typename T>
T& CreateBranch(std::string name)
{
branches.emplace(name, new T());
return *(static_cast<T*>(branches[name]));
}
template<typename T>
T& Get(std::string name)
{
return *static_cast<T*>(branches[name]);
}
private:
std::map<std::string, void*> branches;
};
class TDFAction {
public:
virtual ~TDFAction() {}
virtual void init(void) = 0;
virtual void eval(void) = 0;
virtual void end(void) = 0;
};
template<class Action>
class TDFActionCRTP : public TDFAction {
public:
void init() override final { static_cast<Action*>(this)->init_impl(); }
void eval() override final { static_cast<Action*>(this)->eval_impl(); }
void end() override final { static_cast<Action*>(this)->end_impl(); }
};
template<typename T>
class TDFAverage : public TDFActionCRTP<TDFAverage<T>> {
public:
TDFAverage(T& avg, T& cur)
: average(avg), current(cur) {}
void init_impl() { n = 0UL; average = T(0), current = T(0); }
void eval_impl() { average += current; ++n; }
void end_impl() { average /= static_cast<T>(n); }
protected:
size_t n;
T& average;
T& current;
};
template<typename T>
class TDFMaximum : public TDFActionCRTP<TDFMaximum<T>> {
public:
TDFMaximum(T& m, T& cur)
: maximum(m), current(cur) {}
void init_impl() { maximum = std::numeric_limits<T>::lowest(); }
void eval_impl() { maximum = std::max(maximum, current); }
void end_impl() { /* empty */ }
protected:
T& maximum;
T& current;
};
template<typename Element, template <typename> class Container>
class TDFNode {
public:
TDFNode(const Container<Element>& v) : data(v)
{
/* map data from container */
NewBranch<Element>("default");
}
template <typename T>
T& NewBranch(std::string name)
{
return bmap.CreateBranch<T>(name);
}
template <typename T>
T& GetBranch(const std::string& name)
{
return bmap.Get<T>(name);
}
template<typename DefFunc, typename... Args>
auto Define(std::string name, DefFunc f, Args&&... args)
-> typename std::result_of<DefFunc(Args...)>::type&
{
using ResultType = typename std::result_of<DefFunc(Args...)>::type;
/* create new branch */
NewBranch<ResultType>(name);
/* create an update function for it */
branches.push_back([&, f, name]() -> void
{
GetBranch<ResultType>(name) = f(std::forward<Args>(args)...);
});
return GetBranch<ResultType>(name);
}
template<typename FilterFunc, typename... Args>
void Filter(FilterFunc f, Args... args)
{
filters.emplace_back([&, f]() -> bool
{
return f(std::forward<Args>(args)...);
});
}
template <typename T>
void Average(std::string name, T& average)
{
T& b = GetBranch<T>(name);
actions.emplace_back(new TDFAverage<T>(average, b));
}
template <typename T>
void Maximum(std::string name, T& maximum)
{
T& b = GetBranch<T>(name);
actions.emplace_back(new TDFMaximum<T>(maximum, b));
}
void Run()
{
for (auto action : actions)
action->init();
for (auto&& x : data) {
/* map default branch to data */
GetBranch<Element>("default") = x;
/* compute defined branches */
for (auto&& branch : branches)
branch();
/* check filters */
bool status = true;
for (auto&& filter : filters)
status = status && filter();
/* compute actions */
if (status == true)
for (auto action : actions)
action->eval();
}
for (auto action : actions)
action->end();
}
private:
TDFBranchMap bmap;
const Container<Element>& data;
std::vector<TDFAction*> actions;
std::vector<std::function<void(void)>> branches;
std::vector<std::function<bool(void)>> filters;
};
using Element = double;
template<typename T>
using Container = std::vector<T>;
int main(int argc, char** argv)
{
Container<Element> v{0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
TDFNode<Element, Container> df(v);
auto& x = df.GetBranch<Element>("default");
auto& sq = df.Define("sq", [&x]() { return x*x; });
df.Filter([&sq]() { return sq < 10.0; });
double average, maximum;
df.Average("sq", average);
df.Maximum("sq", maximum);
df.Run();
std::cout << "average: " << average << std::endl;
std::cout << "maximum: " << maximum << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment