value.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /**
  2. * @file
  3. * @author Caleb Fangmeier <caleb@fangmeier.tech>
  4. * @version 0.1
  5. *
  6. * @section LICENSE
  7. *
  8. *
  9. * MIT License
  10. *
  11. * Copyright (c) 2017 Caleb Fangmeier
  12. *
  13. * Permission is hereby granted, free of charge, to any person obtaining a copy
  14. * of this software and associated documentation files (the "Software"), to deal
  15. * in the Software without restriction, including without limitation the rights
  16. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  17. * copies of the Software, and to permit persons to whom the Software is
  18. * furnished to do so, subject to the following conditions:
  19. *
  20. * The above copyright notice and this permission notice shall be included in all
  21. * copies or substantial portions of the Software.
  22. *
  23. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  25. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  26. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  27. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  28. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  29. * SOFTWARE.
  30. *
  31. * @section DESCRIPTION
  32. * This header defines a set of generic classes that wrap up "values". In
  33. * essence, a Value<T> object is just something that contains a value of type T
  34. * and can provide it when requested. The usefulness stems from composing
  35. * values together with calculations. This enables very clear dependency
  36. * mapping and a way to know clearly how every value was arrived at. This could
  37. * be used to, for example, automatically generate commentary for plots that
  38. * explain the exect calculation used to create it. Or easily making a series
  39. * of plots contrasting different values that have been composed slightly
  40. * differently.
  41. */
  42. #ifndef value_hpp
  43. #define value_hpp
  44. #include <algorithm>
  45. #include <functional>
  46. #include <initializer_list>
  47. #include <iomanip>
  48. #include <iostream>
  49. #include <limits>
  50. #include <map>
  51. #include <sstream>
  52. #include <tuple>
  53. #include <typeindex>
  54. #include <utility>
  55. #include <vector>
  56. #include "log.hpp"
  57. #include "config.hpp"
  58. /**
  59. * The namespace containing all filval classes and functions.
  60. */
  61. namespace fv {
  62. template<typename T>
  63. class Value;
  64. /**
  65. * A type-agnostic value.
  66. * It is necessary to create a type-agnostic parent class to Value so that
  67. * it is possible to handle collections of them. GenValue also provides the
  68. * rest of the type-independent interface to Value.
  69. */
  70. class GenValue;
  71. typedef std::map<std::string, GenValue *> ValueSet;
  72. class GenValue {
  73. private:
  74. /**
  75. * The name of the value.
  76. * This is used to allow for dynamic lookup of
  77. * values based on their name via GenValue::get_value.
  78. */
  79. std::string name;
  80. protected:
  81. /**
  82. * Mark the internal value as invalid. This is needed for DerivedValue
  83. * to force a recalculation of the internal value when a new
  84. * observation is loaded into memory. It is called automatically for
  85. * all GenValue objects when reset is called.
  86. */
  87. bool value_valid;
  88. void _reset() {
  89. this->value_valid = false;
  90. }
  91. /**
  92. * A static mapping containing all created Value objects.
  93. * Every value object must have a unique name, and this name is used as
  94. * a key in values to that object. This is used to enable more dynamic
  95. * creation of objects as well as avoiding the uneccesary passing of
  96. * pointers.
  97. */
  98. inline static std::map<std::pair<const std::type_index, const std::string>, GenValue *> values;
  99. /**
  100. * Composite value names are typically nested. This makes complex
  101. * values have rather unwieldy names. Therefore, one can declare
  102. * aliases which allow for more human-usable names to be used. When a
  103. * value is requested by name, an alias with that value takes precidence
  104. * over a name with that value.
  105. */
  106. inline static std::map<std::pair<const std::type_index, const std::string>, GenValue *> aliases;
  107. public:
  108. GenValue(const std::type_index &&ti, const std::string &name, const std::string &alias)
  109. : name(name), value_valid(false) {
  110. if (alias != "")
  111. INFO("Registered value: \"" << name << "\" with alias: \"" << alias << "\"");
  112. else
  113. INFO("Registered value: \"" << name);
  114. values[std::make_pair(ti, name)] = this;
  115. if (alias != "")
  116. GenValue::alias(ti, alias, this);
  117. }
  118. const std::string &get_name() {
  119. return name;
  120. }
  121. static void reset() {
  122. for (auto val : values) {
  123. if (val.second != nullptr) {
  124. val.second->_reset();
  125. }
  126. }
  127. }
  128. template<typename T>
  129. static Value<T> *get_value(const std::string &name) {
  130. const std::type_index &ti = typeid(T);
  131. auto lookup_id = std::make_pair(ti, name);
  132. if (aliases[lookup_id] != nullptr)
  133. return (Value<T> *) aliases[lookup_id];
  134. else
  135. return (Value<T> *) values[lookup_id];
  136. }
  137. static void alias(const std::type_index &ti, const std::string &name, GenValue *value) {
  138. auto lookup_id = std::make_pair(ti, name);
  139. if (aliases[lookup_id] != nullptr) {
  140. WARNING("WARNING: alias \"" << name << "\" overrides previous entry.");
  141. }
  142. aliases[lookup_id] = value;
  143. }
  144. template<typename T>
  145. static void alias(const std::string &name, Value<T> *value) {
  146. alias(typeid(T), name, value);
  147. }
  148. static std::string summary() {
  149. std::stringstream ss;
  150. ss << "The following values have been created:" << std::endl;
  151. for (auto item : values) {
  152. auto &key = item.first;
  153. auto &value = item.second;
  154. if (value == nullptr) continue;
  155. ss << "\tVALUE::\"" << key.second << "\" at address " << value << std::endl;
  156. }
  157. ss << "And these aliases:" << std::endl;
  158. for (auto item : aliases) {
  159. auto &key = item.first;
  160. auto &value = item.second;
  161. std::string orig("VOID");
  162. if (value == nullptr) continue;
  163. for (auto v_item : values) {
  164. auto &v_value = v_item.second;
  165. if (v_value == value) {
  166. orig = v_value->get_name();
  167. break;
  168. }
  169. }
  170. ss << "\tALIAS::\"" << key.second << "\" referring to \"" << orig << "\"" << std::endl;
  171. }
  172. return ss.str();
  173. }
  174. friend std::ostream &operator<<(std::ostream &os, const GenValue &gv);
  175. };
  176. std::ostream &operator<<(std::ostream &os, GenValue &gv) {
  177. os << gv.get_name();
  178. return os;
  179. }
  180. /**
  181. * A templated value.
  182. * In order to facilitate run-time creation of analysis routines, it is
  183. * necessary to have some ability to get and store *values*. Values can either
  184. * be directly taken from some original data source (i.e. ObservedValue), or
  185. * they can be a function of some other set of values (i.e. DerivedValue). They
  186. * template class T of Value<T> is the type of thing that is returned upon
  187. * calling get_value().
  188. */
  189. template<typename T>
  190. class Value : public GenValue {
  191. public:
  192. Value(const std::string &name, const std::string &alias = "")
  193. : GenValue(typeid(T), name, alias) {}
  194. /** Calculate, if necessary, and return the value held by this object.
  195. */
  196. virtual T &operator() () = 0;
  197. };
  198. /**
  199. * A value supplied by the dataset, not derived.
  200. * An ObservedValue is the interface to your dataset. Upon creation, an
  201. * ObservedValue is given a pointer to an object of type T. When an observation
  202. * is loaded into memory, the value at the location referenced by that pointer
  203. * must be updated with the associated data from that observation. This is the
  204. * responsibility of whatever DataSet implementation is being used. This object
  205. * then will read that data and return it when requested.
  206. */
  207. template<typename T>
  208. class ObservedValue : public Value<T> {
  209. private:
  210. T *val_ref;
  211. public:
  212. ObservedValue(const std::string &name, T *val_ref, const std::string &alias = "")
  213. : Value<T>(name, alias),
  214. val_ref(val_ref) {}
  215. static std::string fmt_name(const std::string &name) {
  216. return name;
  217. }
  218. T &operator() (){
  219. if (!this->value_valid) {
  220. if (fv_util::debug_on) {
  221. std::cout << "Calculating Value: " << this->get_name() << std::endl;
  222. }
  223. this->value_valid = true;
  224. }
  225. return *val_ref;
  226. }
  227. };
  228. /**
  229. * A Value derived from some other Values, not directly from the dataset.
  230. * A DerivedValue is generally defined as some function of other Value objects.
  231. * For example, a Pair is a function of two other Value objects that makes a
  232. * pair of them. Note that these other Value objects are free to be either
  233. * ObservedValues or other DerivedValues.
  234. *
  235. * It is desireable from a performance standpoint that each DerivedValue be
  236. * calculated no more than once per observation. Therefore, when a get_value is
  237. * called on a DerivedValue, it first checks whether the value that it holds is
  238. * **valid**, meaning it has already been calculated for this observation. If
  239. * so, it simply returns the value. If not, the update_value function is called
  240. * to calculate the value. and then the newly calculated value is marked as
  241. * valid and returned.
  242. */
  243. template<typename T>
  244. class DerivedValue : public Value<T> {
  245. protected:
  246. T value;
  247. /**
  248. * Updates the internal value.
  249. * This function should be overridden by any child class to do the
  250. * actual work of updating value based on whatever rules the class
  251. * chooses. Normally, this consists of geting the values from some
  252. * associated Value objects, doing some calculation on them, and
  253. * storing the result in value.
  254. */
  255. virtual void update_value() = 0;
  256. public:
  257. DerivedValue(const std::string &name, const std::string &alias = "")
  258. : Value<T>(name, alias) {}
  259. T &operator() () {
  260. if (!this->value_valid) {
  261. if (fv_util::debug_on) {
  262. std::cout << "Calculating Value: " << this->get_name() << std::endl;
  263. }
  264. update_value();
  265. this->value_valid = true;
  266. }
  267. return value;
  268. }
  269. };
  270. /**
  271. * A Value of a pointer. The pointer is constant, however the data the pointer
  272. * points to is variable.
  273. */
  274. template<typename T>
  275. class PointerValue : public DerivedValue<T *> {
  276. protected:
  277. void update_value() {}
  278. public:
  279. PointerValue(const std::string &name, T *ptr, const std::string alias = "")
  280. : DerivedValue<T *>(name, alias) {
  281. this->value = ptr;
  282. }
  283. };
  284. /**
  285. * Used for when the value is an object whose location in memory is changing,
  286. * but one has a pointer to a pointer that points to the always updated
  287. * location. (Mainly when reading objects such as stl containers from a root
  288. * TTree)
  289. */
  290. template<typename T>
  291. class ObjectValue : public DerivedValue<T> {
  292. protected:
  293. T **obj_pointer;
  294. void update_value() {
  295. this->value = **obj_pointer;
  296. }
  297. public:
  298. ObjectValue(const std::string &name, T **ptr, const std::string alias = "")
  299. : DerivedValue<T>(name, alias),
  300. obj_pointer(ptr) {}
  301. };
  302. /**
  303. * A Value which always returns the same value, supplied in the constructor.
  304. */
  305. template<typename T>
  306. class ConstantValue : public DerivedValue<T> {
  307. protected:
  308. void update_value() {}
  309. public:
  310. static std::string fmt_name(const std::string &name) {
  311. return "const::" + name;
  312. }
  313. ConstantValue(const std::string &name, T const_value, const std::string alias = "")
  314. : DerivedValue<T>(fmt_name(name), alias) {
  315. this->value = const_value;
  316. }
  317. };
  318. }
  319. #endif // value_hpp