Created
April 20, 2017 09:33
-
-
Save amadio/b006524d903e86578df765dffee47605 to your computer and use it in GitHub Desktop.
TDataFrame Prototype with std::vector as data source
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 <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