#ifndef value_hpp #define value_hpp #include #include #include #include #include #include #include #include namespace filval{ class GenValue{ private: inline static std::vector values; virtual void _reset() = 0; public: GenValue(){ values.push_back(this); } static void reset(){ for (auto val : values){ val->_reset(); } } }; typedef std::map ValueSet; template class Value : public GenValue{ public: Value(): GenValue(){} virtual T& get_value() = 0; }; template class ObservedValue : public Value{ /* For "observed" values, there is nothing to calculate since this is * merely a wrapper around a field in the observation. A pointer to the * value is kept and it's value is read when requested. */ private: T *val_ref; void _reset(){ } public: ObservedValue(T* val_ref) :Value(), val_ref(val_ref){ } T& get_value(){ return *val_ref; } }; template class DerivedValue : public Value{ /* A "derived" value is the result of some sort of calculation. Since it is * desireable for the calculation to occur at most a single time for each * observation, the result of the calculation is stored in the object. be * sure that "reset" is called between processing observations to force a * re-calculation. */ private: void _reset(){ value_valid = false; } protected: T value; bool value_valid; virtual void update_value() = 0; public: DerivedValue() :Value(), value_valid(false) { } T& get_value(){ if (!value_valid){ update_value(); value_valid = true; } return value; } }; template class WrapperVector : public DerivedValue >{ private: Value* size; Value* data; void update_value(){ int n = size->get_value(); T* data_ref = data->get_value(); this->value.resize(n); for (int i=0; ivalue[i] = *(data_ref+i); } } public: WrapperVector(Value* _size, Value* _data) :DerivedValue >(), size(_size), data(_data){ } WrapperVector(ValueSet *values, const std::string &label_size, const std::string &label_data) :WrapperVector(dynamic_cast*>(values->at(label_size)), dynamic_cast*>(values->at(label_data))) { } }; template class Pair : public DerivedValue >{ protected: std::pair*, Value* > value_pair; void update_value(){ this->value.first = value_pair.first->get_value(); this->value.second = value_pair.second->get_value(); } public: Pair(Value *value1, Value *value2) :DerivedValue >(), value_pair(value1, value2){ } Pair(ValueSet *values, const std::string &label1, const std::string &label2) :Pair((Value*) values->at(label1), (Value*) values->at(label2)){ } }; template class ZipMapFour : public DerivedValue >{ private: std::function f; Value >* v1; Value >* v2; Value >* v3; Value >* v4; void update_value(){ std::vector v1_val = v1->get_value(); std::vector v2_val = v2->get_value(); std::vector v3_val = v3->get_value(); std::vector v4_val = v4->get_value(); int n; std::tie(n, std::ignore) = std::minmax({v1_val.size(), v2_val.size(), v3_val.size(), v4_val.size()}); this->value.resize(n); for (int i=0; ivalue[i] = f(v1_val[i], v2_val[i], v3_val[i], v4_val[i]); } } public: ZipMapFour(std::function f, Value >* v1, Value >* v2, Value >* v3, Value >* v4) :DerivedValue >(), f(f), v1(v1), v2(v2), v3(v3), v4(v4) { } ZipMapFour(std::function f, ValueSet *values, const std::string &label1, const std::string &label2, const std::string &label3, const std::string &label4) :ZipMapFour(f, dynamic_cast >*>(values->at(label1)), dynamic_cast >*>(values->at(label2)), dynamic_cast >*>(values->at(label3)), dynamic_cast >*>(values->at(label4))){ } }; template class Reduce : public DerivedValue{ private: std::function)> reduce; Value >* v; void update_value(){ this->value = reduce(v->get_value()); } public: Reduce(std::function)> reduce, Value >* v) :DerivedValue(), reduce(reduce), v(v) { } }; template class MultiFunc : public DerivedValue{ private: std::function f; std::tuple value_tuple; void update_value(){ this->value = f(value_tuple); } public: MultiFunc(std::function)> f, T... varargs) :f(f), value_tuple(varargs...){ } }; template class BoundValue : public DerivedValue{ /* A "bound" value has it's dependencies bound into a function object. */ protected: std::function f; void update_value(){ this->value = f(); } public: BoundValue(std::function f) :f(f) { } }; template class ConstantValue : public DerivedValue{ protected: T const_value; void update_value(){ this->value = const_value; } public: ConstantValue(T const_value) :const_value(const_value) { } }; } #endif // value_hpp