Skip to content

Instantly share code, notes, and snippets.

Created Jun 24, 2012
Embed
What would you like to do?
Lazy operators in C++ for fun and data fetch batching
#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