Created
June 24, 2012 02:08
-
-
Save anonymous/2981060 to your computer and use it in GitHub Desktop.
Lazy operators in C++ for fun and data fetch batching
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 <memory> | |
#include <iostream> | |
#include <unordered_map> | |
#include <string> | |
template <typename N> | |
struct LBase { | |
virtual N Eval() const = 0; | |
virtual void Walk(std::function<void(LBase<N> const&)> walker) const | |
{ | |
walker(*this); | |
} | |
virtual ~LBase() {} | |
}; | |
template <typename N> | |
struct LVal : LBase<N> { | |
N val; | |
LVal(N v) : val(v) {} | |
N Eval() const { return val; } | |
}; | |
template <typename N> struct L : std::shared_ptr<LBase<N> > { | |
L() {} | |
L(LBase<N>* p) : std::shared_ptr<LBase<N> >(p) {} | |
L(N val) : std::shared_ptr<LBase<N> >(new LVal<N>(val)) {} | |
operator N () const { return (*this)->Eval(); } | |
}; | |
template <typename N> | |
struct LBinary : LBase<N> { | |
L<N> left, right; | |
LBinary(L<N> l, L<N> r) | |
: left(l), right(r) {} | |
void Walk(std::function<void(LBase<N> const&)> walker) const | |
{ | |
LBase<N>::Walk(walker); | |
left->Walk(walker); | |
right->Walk(walker); | |
} | |
}; | |
#define DEF_BIN_OP(op, name) \ | |
template<typename N> \ | |
struct LBin##name : LBinary<N> { \ | |
LBin##name(L<N> l, L<N> r) \ | |
: LBinary<N>(l, r) {} \ | |
N Eval() const { \ | |
return LBinary<N>::left->Eval() op LBinary<N>::right->Eval(); \ | |
} \ | |
}; \ | |
template <typename N> \ | |
L<N> operator op (L<N> l, L<N> r) { \ | |
return L<N>(new LBin##name <N>(l, r)); \ | |
} \ | |
template <typename N> \ | |
L<N> operator op (N l, L<N> r) { \ | |
return L<N>(new LBin##name <N>(L<N>(l), r)); \ | |
} \ | |
template <typename N> \ | |
L<N> operator op (L<N> l, N r) { \ | |
return L<N>(new LBin##name <N>(l, L<N>(r))); \ | |
} | |
DEF_BIN_OP(+, Plus); | |
DEF_BIN_OP(*, Star); | |
DEF_BIN_OP(-, Minus); | |
DEF_BIN_OP(/, Slash); | |
template <typename N> | |
struct LHash : LBase<N> { | |
std::string name; | |
std::shared_ptr<std::unordered_map<std::string, N> > map; | |
LHash(std::shared_ptr<std::unordered_map<std::string, N> > m, std::string n) | |
: name(n), map(m) {} | |
N Eval() const { return (*map)[name]; } | |
}; | |
template <typename N> | |
L<N> H(std::shared_ptr<std::unordered_map<std::string, N> > m, std::string n) | |
{ | |
return L<N>(new LHash<N>(m, n)); | |
} | |
template <typename N> | |
void hash_walker(LBase<N> const&l) { | |
if (auto i = dynamic_cast<LHash<N> const*>(&l)) { | |
std::cout << i->name << std::endl; | |
} | |
} | |
int main() | |
{ | |
auto map = std::make_shared<std::unordered_map<std::string, double> >(); | |
auto x = H<double>(map, "x"); | |
auto y = H<double>(map, "y"); | |
auto expr = (x + y)/2.; | |
expr->Walk(hash_walker<double>); | |
(*map)["x"] = 400; | |
(*map)["y"] = -200; | |
std::cout << expr->Eval() << std::endl; | |
(*map)["y"] = 0; | |
std::cout << expr->Eval() << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment