123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- /**
- * @file
- * @author Caleb Fangmeier <caleb@fangmeier.tech>
- * @version 0.1
- *
- * @section LICENSE
- *
- *
- * MIT License
- *
- * Copyright (c) 2017 Caleb Fangmeier
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * @section DESCRIPTION
- * This header defines a set of generic classes that wrap up "values". In
- * essence, a Value<T> object is just something that contains a value of type T
- * and can provide it when requested. The usefulness stems from composing
- * values together with calculations. This enables very clear dependency
- * mapping and a way to know clearly how every value was arrived at. This could
- * be used to, for example, automatically generate commentary for plots that
- * explain the exect calculation used to create it. Or easily making a series
- * of plots contrasting different values that have been composed slightly
- * differently.
- */
- #ifndef value_hpp
- #define value_hpp
- #include <algorithm>
- #include <functional>
- #include <initializer_list>
- #include <iomanip>
- #include <iostream>
- #include <limits>
- #include <map>
- #include <sstream>
- #include <tuple>
- #include <typeindex>
- #include <utility>
- #include <vector>
- #include "log.hpp"
- #include "config.hpp"
- /**
- * The namespace containing all filval classes and functions.
- */
- namespace fv {
- template<typename T>
- class Value;
- /**
- * A type-agnostic value.
- * It is necessary to create a type-agnostic parent class to Value so that
- * it is possible to handle collections of them. GenValue also provides the
- * rest of the type-independent interface to Value.
- */
- class GenValue;
- typedef std::map<std::string, GenValue *> ValueSet;
- class GenValue {
- private:
- /**
- * The name of the value.
- * This is used to allow for dynamic lookup of
- * values based on their name via GenValue::get_value.
- */
- std::string name;
- protected:
- /**
- * Mark the internal value as invalid. This is needed for DerivedValue
- * to force a recalculation of the internal value when a new
- * observation is loaded into memory. It is called automatically for
- * all GenValue objects when reset is called.
- */
- bool value_valid;
- void _reset() {
- this->value_valid = false;
- }
- /**
- * A static mapping containing all created Value objects.
- * Every value object must have a unique name, and this name is used as
- * a key in values to that object. This is used to enable more dynamic
- * creation of objects as well as avoiding the uneccesary passing of
- * pointers.
- */
- inline static std::map<std::pair<const std::type_index, const std::string>, GenValue *> values;
- /**
- * Composite value names are typically nested. This makes complex
- * values have rather unwieldy names. Therefore, one can declare
- * aliases which allow for more human-usable names to be used. When a
- * value is requested by name, an alias with that value takes precidence
- * over a name with that value.
- */
- inline static std::map<std::pair<const std::type_index, const std::string>, GenValue *> aliases;
- public:
- GenValue(const std::type_index &&ti, const std::string &name, const std::string &alias)
- : name(name), value_valid(false) {
- if (alias != "")
- INFO("Registered value: \"" << name << "\" with alias: \"" << alias << "\"");
- else
- INFO("Registered value: \"" << name);
- values[std::make_pair(ti, name)] = this;
- if (alias != "")
- GenValue::alias(ti, alias, this);
- }
- const std::string &get_name() {
- return name;
- }
- static void reset() {
- for (auto val : values) {
- if (val.second != nullptr) {
- val.second->_reset();
- }
- }
- }
- template<typename T>
- static Value<T> *get_value(const std::string &name) {
- const std::type_index &ti = typeid(T);
- auto lookup_id = std::make_pair(ti, name);
- if (aliases[lookup_id] != nullptr)
- return (Value<T> *) aliases[lookup_id];
- else
- return (Value<T> *) values[lookup_id];
- }
- static void alias(const std::type_index &ti, const std::string &name, GenValue *value) {
- auto lookup_id = std::make_pair(ti, name);
- if (aliases[lookup_id] != nullptr) {
- WARNING("WARNING: alias \"" << name << "\" overrides previous entry.");
- }
- aliases[lookup_id] = value;
- }
- template<typename T>
- static void alias(const std::string &name, Value<T> *value) {
- alias(typeid(T), name, value);
- }
- static std::string summary() {
- std::stringstream ss;
- ss << "The following values have been created:" << std::endl;
- for (auto item : values) {
- auto &key = item.first;
- auto &value = item.second;
- if (value == nullptr) continue;
- ss << "\tVALUE::\"" << key.second << "\" at address " << value << std::endl;
- }
- ss << "And these aliases:" << std::endl;
- for (auto item : aliases) {
- auto &key = item.first;
- auto &value = item.second;
- std::string orig("VOID");
- if (value == nullptr) continue;
- for (auto v_item : values) {
- auto &v_value = v_item.second;
- if (v_value == value) {
- orig = v_value->get_name();
- break;
- }
- }
- ss << "\tALIAS::\"" << key.second << "\" referring to \"" << orig << "\"" << std::endl;
- }
- return ss.str();
- }
- friend std::ostream &operator<<(std::ostream &os, const GenValue &gv);
- };
- std::ostream &operator<<(std::ostream &os, GenValue &gv) {
- os << gv.get_name();
- return os;
- }
- /**
- * A templated value.
- * In order to facilitate run-time creation of analysis routines, it is
- * necessary to have some ability to get and store *values*. Values can either
- * be directly taken from some original data source (i.e. ObservedValue), or
- * they can be a function of some other set of values (i.e. DerivedValue). They
- * template class T of Value<T> is the type of thing that is returned upon
- * calling get_value().
- */
- template<typename T>
- class Value : public GenValue {
- public:
- Value(const std::string &name, const std::string &alias = "")
- : GenValue(typeid(T), name, alias) {}
- /** Calculate, if necessary, and return the value held by this object.
- */
- virtual T &operator() () = 0;
- };
- /**
- * A value supplied by the dataset, not derived.
- * An ObservedValue is the interface to your dataset. Upon creation, an
- * ObservedValue is given a pointer to an object of type T. When an observation
- * is loaded into memory, the value at the location referenced by that pointer
- * must be updated with the associated data from that observation. This is the
- * responsibility of whatever DataSet implementation is being used. This object
- * then will read that data and return it when requested.
- */
- template<typename T>
- class ObservedValue : public Value<T> {
- private:
- T *val_ref;
- public:
- ObservedValue(const std::string &name, T *val_ref, const std::string &alias = "")
- : Value<T>(name, alias),
- val_ref(val_ref) {}
- static std::string fmt_name(const std::string &name) {
- return name;
- }
- T &operator() (){
- if (!this->value_valid) {
- if (fv_util::debug_on) {
- std::cout << "Calculating Value: " << this->get_name() << std::endl;
- }
- this->value_valid = true;
- }
- return *val_ref;
- }
- };
- /**
- * A Value derived from some other Values, not directly from the dataset.
- * A DerivedValue is generally defined as some function of other Value objects.
- * For example, a Pair is a function of two other Value objects that makes a
- * pair of them. Note that these other Value objects are free to be either
- * ObservedValues or other DerivedValues.
- *
- * It is desireable from a performance standpoint that each DerivedValue be
- * calculated no more than once per observation. Therefore, when a get_value is
- * called on a DerivedValue, it first checks whether the value that it holds is
- * **valid**, meaning it has already been calculated for this observation. If
- * so, it simply returns the value. If not, the update_value function is called
- * to calculate the value. and then the newly calculated value is marked as
- * valid and returned.
- */
- template<typename T>
- class DerivedValue : public Value<T> {
- protected:
- T value;
- /**
- * Updates the internal value.
- * This function should be overridden by any child class to do the
- * actual work of updating value based on whatever rules the class
- * chooses. Normally, this consists of geting the values from some
- * associated Value objects, doing some calculation on them, and
- * storing the result in value.
- */
- virtual void update_value() = 0;
- public:
- DerivedValue(const std::string &name, const std::string &alias = "")
- : Value<T>(name, alias) {}
- T &operator() () {
- if (!this->value_valid) {
- if (fv_util::debug_on) {
- std::cout << "Calculating Value: " << this->get_name() << std::endl;
- }
- update_value();
- this->value_valid = true;
- }
- return value;
- }
- };
- /**
- * A Value of a pointer. The pointer is constant, however the data the pointer
- * points to is variable.
- */
- template<typename T>
- class PointerValue : public DerivedValue<T *> {
- protected:
- void update_value() {}
- public:
- PointerValue(const std::string &name, T *ptr, const std::string alias = "")
- : DerivedValue<T *>(name, alias) {
- this->value = ptr;
- }
- };
- /**
- * Used for when the value is an object whose location in memory is changing,
- * but one has a pointer to a pointer that points to the always updated
- * location. (Mainly when reading objects such as stl containers from a root
- * TTree)
- */
- template<typename T>
- class ObjectValue : public DerivedValue<T> {
- protected:
- T **obj_pointer;
- void update_value() {
- this->value = **obj_pointer;
- }
- public:
- ObjectValue(const std::string &name, T **ptr, const std::string alias = "")
- : DerivedValue<T>(name, alias),
- obj_pointer(ptr) {}
- };
- /**
- * A Value which always returns the same value, supplied in the constructor.
- */
- template<typename T>
- class ConstantValue : public DerivedValue<T> {
- protected:
- void update_value() {}
- public:
- static std::string fmt_name(const std::string &name) {
- return "const::" + name;
- }
- ConstantValue(const std::string &name, T const_value, const std::string alias = "")
- : DerivedValue<T>(fmt_name(name), alias) {
- this->value = const_value;
- }
- };
- }
- #endif // value_hpp
|