TTTT Analysis  0.1
value.hpp
Go to the documentation of this file.
1 
42 #ifndef value_hpp
43 #define value_hpp
44 #include <iomanip>
45 #include <iostream>
46 #include <sstream>
47 #include <utility>
48 #include <algorithm>
49 #include <map>
50 #include <vector>
51 #include <tuple>
52 #include <initializer_list>
53 #include <functional>
54 
55 #include "log.hpp"
56 
60 namespace fv{
61 
62 /* bool in_register_function = false; */
63 template<typename> class Function; // undefined
68 class GenFunction {
69  private:
70  std::string name;
71  std::string impl;
72  protected:
73  inline static bool in_register_function=false;
74 
75  public:
80  inline static std::map<const std::string, GenFunction*> function_registry;
81 
82  GenFunction(const std::string& name, const std::string& impl)
83  :impl(impl), name(name){ }
84 
85  virtual ~GenFunction() { };
86 
87  std::string& get_name(){
88  return name;
89  }
90 
96  static std::string format_code(const std::string& code){
97  std::stringstream code_out("");
98  std::string command("echo \""+code+"\" | clang-format");
99  char buffer[255];
100  FILE *stream = popen(command.c_str(), "r");
101  while (fgets(buffer, 255, stream) != NULL)
102  code_out << buffer;
103  if (pclose(stream) == 0)
104  return code_out.str();
105  else
106  return code;
107  }
108 
109  static std::string summary(){
110  std::stringstream ss;
111  ss << "The following functions have been registered" << std::endl;
112  for(auto p : function_registry){
113  if (p.second == nullptr) continue;
114  ss << "-->" << p.second->name << std::endl;
115  ss << format_code(p.second->impl);
116  }
117  return ss.str();
118  }
119 
120  template <typename T>
121  static Function<T>& register_function(const std::string& name, std::function<T> f, const std::string& impl){
122  in_register_function = true;
123  Function<T>* func;
124  if (GenFunction::function_registry[name] != nullptr){
125  func = dynamic_cast<Function<T>*>(GenFunction::function_registry[name]);
126  if (func == nullptr){
127  ERROR("Trying to register function which has already been registered with a different type");
128  }
129  } else {
130  func = new Function<T>(name, impl, f);
131  GenFunction::function_registry[name] = func;
132  }
133  in_register_function = false;
134  return *func;
135  }
136 };
137 
138 
150 template <typename R, typename... ArgTypes>
151 class Function<R(ArgTypes...)> : public GenFunction {
152  private:
153  std::function<R(ArgTypes...)> f;
154 
155  public:
156  Function(const std::string& name, const std::string& impl, std::function<R(ArgTypes...)> f)
157  :GenFunction(name, impl), f(f){
158  if (!in_register_function) {
159  WARNING("Don't instantiate Function objects directly! Use GenFunction::register_function instead.");
160  }
161  }
162  Function(const std::string& name, std::function<R(ArgTypes...)> f)
163  :Function(name, "N/A", f){ }
164  ~Function() { }
165 
166  R operator()(ArgTypes ...args){
167  return f(args...);
168  }
169 
170 };
171 
172 
173 #define FUNC(f) f, #f
174 
181 class GenValue;
182 typedef std::map<std::string, GenValue*> ValueSet;
183 class GenValue{
184  private:
190  std::string name;
191 
192  protected:
199  virtual void _reset() = 0;
207  inline static std::map<const std::string, GenValue*> values;
215  inline static std::map<const std::string, GenValue*> aliases;
216 
225  virtual void verify_integrity() = 0;
226 
227  public:
228  GenValue(const std::string& name, const std::string& alias)
229  :name(name){
230  values[name] = this;
231  if (alias != "")
232  GenValue::alias(alias, this);
233  }
234 
235  const std::string& get_name(){
236  return name;
237  }
238 
239  static void reset(){
240  for (auto val : values){
241  val.second->_reset();
242  }
243  }
244 
245  static GenValue* get_value(const std::string& name){
246  if (aliases[name] != nullptr)
247  return aliases[name];
248  else if (values[name] != nullptr)
249  return values[name];
250  else{
251  ERROR("Could not find alias or value \"" << name << "\". I'll tell you the ones I know about." << std::endl
252  << summary());
253  CRITICAL("Aborting... :(",-1);
254  }
255  }
256 
257  static void alias(const std::string& name, GenValue* value){
258  if (aliases[name] != nullptr){
259  WARNING("WARNING: alias \"" << name << "\" overrides previous entry.");
260  }
261  aliases[name] = value;
262  }
263 
264  static GenValue* alias(const std::string& name){
265  if (values[name] != nullptr){
266  WARNING("Alias \"" << name << "\" does not exist.");
267  }
268  return aliases[name];
269  }
270 
271  static std::string summary(){
272  std::stringstream ss;
273  ss << "The following values have been created: " << std::endl;
274  for (auto value : values){
275  if (value.second == nullptr) continue;
276  ss << "\t\"" << value.first << "\" at address " << value.second << std::endl;
277  }
278  ss << "And these aliases:" << std::endl;
279  for (auto alias : aliases){
280  std::string orig("VOID");
281  if (alias.second == nullptr) continue;
282  for (auto value : values){
283  if (alias.second == value.second){
284  orig = value.second->get_name();
285  break;
286  }
287  }
288  ss << "\t\"" << alias.first << "\" referring to \"" << orig << "\"" << std::endl;
289  }
290  return ss.str();
291  }
292  friend std::ostream& operator<<(std::ostream& os, const GenValue& gv);
293 };
294 std::ostream& operator<<(std::ostream& os, GenValue& gv){
295  os << gv.get_name();
296  return os;
297 }
298 
299 
309 template <typename T>
310 class Value : public GenValue{
311  public:
312  Value(const std::string& name, const std::string& alias="")
313  :GenValue(name, alias){ }
316  virtual T& get_value() = 0;
317 };
318 
319 
329 template <typename T>
330 class ObservedValue : public Value<T>{
331  private:
332  T *val_ref;
333  void _reset(){ }
334 
336  if (val_ref == nullptr)
337  CRITICAL("ObservedValue " << this->get_name() << " created with null pointer",-1);
338  }
339 
340  public:
341  ObservedValue(const std::string& name, T* val_ref, const std::string& alias="")
342  :Value<T>(name, alias),
343  val_ref(val_ref){ }
344  T& get_value(){
345  return *val_ref;
346  }
347 };
348 
349 
365 template <typename T>
366 class DerivedValue : public Value<T>{
367  private:
368  void _reset(){
369  value_valid = false;
370  }
371  protected:
372  T value;
373  bool value_valid;
374 
383  virtual void update_value() = 0;
384  public:
385  DerivedValue(const std::string& name, const std::string& alias="")
386  :Value<T>(name, alias),
387  value_valid(false) { }
388 
389  T& get_value(){
390  if (!value_valid){
391  update_value();
392  value_valid = true;
393  }
394  return value;
395  }
396 };
397 
398 
408 template <typename T>
409 class WrapperVector : public DerivedValue<std::vector<T> >{
410  private:
411  Value<int>* size;
412  Value<T*>* data;
413 
414  void update_value(){
415  int n = size->get_value();
416  T* data_ref = data->get_value();
417  this->value.assign(data_ref, data_ref+n);
418  }
419 
421  if (size == nullptr)
422  CRITICAL("WrapperVector " << this->get_name() << " created with invalid size.",-1);
423  if (data == nullptr)
424  CRITICAL("WrapperVector " << this->get_name() << " created with invalid value.",-1);
425  }
426 
427  public:
428  WrapperVector(Value<int>* size, Value<T*>* data, const std::string& alias="")
429  :DerivedValue<std::vector<T> >("vectorOf("+size->get_name()+","+data->get_name()+")", alias),
430  size(size), data(data){ }
431 
432  WrapperVector(const std::string &label_size, const std::string &label_data, const std::string& alias="")
433  :WrapperVector(dynamic_cast<Value<int>*>(GenValue::get_value(label_size)),
434  dynamic_cast<Value<T*>*>(GenValue::get_value(label_data)), alias) { }
435 };
436 
440 template <typename T1, typename T2>
441 class Pair : public DerivedValue<std::pair<T1, T2> >{
442  protected:
443  std::pair<Value<T1>*, Value<T2>* > value_pair;
444  void update_value(){
445  this->value.first = value_pair.first->get_value();
446  this->value.second = value_pair.second->get_value();
447  }
448 
450  if (value_pair.first == nullptr)
451  CRITICAL("Pair " << this->get_name() << " created with invalid first value.",-1);
452  if (value_pair.second == nullptr)
453  CRITICAL("Pair " << this->get_name() << " created with invalid second value.",-1);
454  }
455 
456  public:
457  Pair(Value<T1> *value1, Value<T2> *value2, const std::string alias="")
458  :DerivedValue<std::pair<T1, T2> >("pair("+value1->get_name()+","+value2->get_name()+")", alias),
459  value_pair(value1, value2){ }
460  Pair(const std::string& label1, const std::string& label2, const std::string alias="")
461  :Pair(dynamic_cast<Value<T1>*>(GenValue::get_value(label1)),
462  dynamic_cast<Value<T1>*>(GenValue::get_value(label2)),
463  alias){ }
464 };
465 
479 template <typename R, typename T>
480 class ZipMapFour : public DerivedValue<std::vector<R> >{
481  private:
483  Value<std::vector<T> >* v1;
484  Value<std::vector<T> >* v2;
485  Value<std::vector<T> >* v3;
486  Value<std::vector<T> >* v4;
487 
488  void update_value(){
489  std::vector<T> v1_val = v1->get_value();
490  std::vector<T> v2_val = v2->get_value();
491  std::vector<T> v3_val = v3->get_value();
492  std::vector<T> v4_val = v4->get_value();
493 
494  int n;
495  std::tie(n, std::ignore) = std::minmax({v1_val.size(), v2_val.size(), v3_val.size(), v4_val.size()});
496  this->value.resize(n);
497  for (int i=0; i<n; i++){
498  this->value[i] = f(v1_val[i], v2_val[i], v3_val[i], v4_val[i]);
499  }
500  }
501 
503  if (v1 == nullptr)
504  CRITICAL("ZipMapFour " << this->get_name() << " created with invalid first value.",-1);
505  if (v2 == nullptr)
506  CRITICAL("ZipMapFour " << this->get_name() << " created with invalid second value.",-1);
507  if (v3 == nullptr)
508  CRITICAL("ZipMapFour " << this->get_name() << " created with invalid third value.",-1);
509  if (v4 == nullptr)
510  CRITICAL("ZipMapFour " << this->get_name() << " created with invalid fourth value.",-1);
511  }
512 
513  public:
514  ZipMapFour(Function<R(T, T, T, T)>& f,
515  Value<std::vector<T> >* v1, Value<std::vector<T> >* v2,
516  Value<std::vector<T> >* v3, Value<std::vector<T> >* v4, const std::string alias="")
517  :DerivedValue<std::vector<R> >("zipmap("+f.get_name()+":"+v1->get_name()+","+v2->get_name()+","+
518  v3->get_name()+","+v4->get_name()+")", alias),
519  f(f), v1(v1), v2(v2), v3(v3), v4(v4) { }
520 
521  ZipMapFour(Function<R(T, T, T, T)>& f,
522  const std::string& label1, const std::string& label2,
523  const std::string& label3, const std::string& label4, const std::string alias="")
524  :ZipMapFour(f,
525  dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(label1)),
526  dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(label2)),
527  dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(label3)),
528  dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(label4)),
529  alias){ }
530 };
531 
535 template<typename T>
536 class Count : public DerivedValue<int>{
537  private:
538  Function<bool(T)>& selector;
540 
541  void update_value(){
542  value = 0;
543  for(auto val : v->get_value()){
544  if(selector(val))
545  value++;
546  }
547  }
548 
550  if (v == nullptr)
551  CRITICAL("Count " << this->get_name() << " created with invalid value.",-1);
552  }
553 
554  public:
555  Count(Function<bool(T)>& selector, Value<std::vector<T>>* v, const std::string alias="")
556  :DerivedValue<int>("count("+selector.get_name()+":"+v->get_name()+")", alias),
557  selector(selector), v(v) { }
558 
559  Count(Function<bool(T)>& selector, const std::string& v_name, const std::string alias="")
560  :Count(selector, dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(v_name)), alias) { }
561 };
562 
563 
570 template <typename T>
571 class Reduce : public DerivedValue<T>{
572  private:
573  Function<T(std::vector<T>)>& reduce;
574 
575  void update_value(){
576  this->value = reduce(v->get_value());
577  }
578 
579  virtual void verify_integrity() {
580  if (v == nullptr)
581  CRITICAL("Reduce " << this->get_name() << " created with invalid value.",-1);
582  }
583 
584  protected:
586 
587  public:
588  Reduce(Function<T(std::vector<T>)>& reduce, Value<std::vector<T> >* v, const std::string alias="")
589  :DerivedValue<T>("reduceWith("+reduce.get_name()+":"+v->get_name()+")", alias),
590  reduce(reduce), v(v) { }
591 
592  Reduce(Function<T(std::vector<T>)>& reduce, const std::string& v_name, const std::string alias="")
593  :Reduce(reduce, dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(v_name)), alias) { }
594 };
595 
599 template <typename T>
600 class Max : public Reduce<T>{
601  private:
603  if (this->v == nullptr)
604  CRITICAL("Max " << this->get_name() << " created with invalid value.",-1);
605  }
606  public:
607  Max(const std::string& v_name, const std::string alias="")
608  :Reduce<T>(GenFunction::register_function<T(std::vector<T>)>("max",
609  FUNC(([](std::vector<T> vec){
610  return *std::max_element(vec.begin(), vec.end());}))),
611  v_name, alias) { }
612 };
613 
617 template <typename T>
618 class Min : public Reduce<T>{
619  private:
621  if (this->v == nullptr)
622  CRITICAL("Min " << this->get_name() << " created with invalid value.",-1);
623  }
624  public:
625  Min(const std::string& v_name, const std::string alias="")
626  :Reduce<T>(GenFunction::register_function<T(std::vector<T>)>("min",
627  FUNC(([](std::vector<T> vec){
628  return *std::min_element(vec.begin(), vec.end());}))),
629  v_name, alias) { }
630 };
631 
635 template <typename T>
636 class Mean : public Reduce<T>{
637  private:
639  if (this->v == nullptr)
640  CRITICAL("Mean " << this->get_name() << " created with invalid value.",-1);
641  }
642 
643  public:
644  Mean(const std::string& v_name, const std::string alias="")
645  :Reduce<T>(GenFunction::register_function<T(std::vector<T>)>("mean",
646  FUNC(([](std::vector<T> vec){
647  int n = 0; T sum = 0;
648  for (T e : vec){ n++; sum += e; }
649  return n>0 ? sum / n : 0; }))),
650  v_name, alias) { }
651 };
652 
656 template <typename T>
657 class Range : public Reduce<T>{
658  private:
660  if (this->v == nullptr)
661  CRITICAL("Range " << this->get_name() << " created with invalid value.",-1);
662  }
663 
664  public:
665  Range(const std::string& v_name, const std::string alias="")
666  :Reduce<T>(GenFunction::register_function<T(std::vector<T>)>("range",
667  FUNC(([](std::vector<T> vec){
668  auto minmax = std::minmax_element(vec.begin(), vec.end());
669  return (*minmax.second) - (*minmax.first); }))),
670  v_name, alias) { }
671 };
672 
676 template <typename T>
677 class ElementOf : public Reduce<T>{
678  private:
680  if (this->v == nullptr)
681  CRITICAL("ElementOf " << this->get_name() << " created with invalid value.",-1);
682  }
683 
684  public:
685  ElementOf(Value<int>* index, const std::string& v_name, const std::string alias="")
686  :Reduce<T>(GenFunction::register_function<T(std::vector<T>)>("elementOf",
687  FUNC(([index](std::vector<T> vec){return vec[index->get_value()];}))),
688  v_name, alias) { }
689  ElementOf(const std::string& name, int index, const std::string& v_name, const std::string alias="")
690  :Reduce<T>(name, [index](std::vector<T> vec){return vec[index];}, v_name, alias) { }
691 };
692 
698 template <typename T>
699 class ReduceIndex : public DerivedValue<std::pair<T, int> >{
700  private:
701  Function<std::pair<T,int>(std::vector<T>)>& reduce;
703 
704  void update_value(){
705  this->value = reduce(v->get_value());
706  }
707 
708  virtual void verify_integrity() {
709  if (v == nullptr)
710  CRITICAL("ReduceIndex " << this->get_name() << " created with invalid value.",-1);
711  }
712 
713  public:
714  ReduceIndex(Function<std::pair<T,int>(std::vector<T>)>& reduce, Value<std::vector<T> >* v, const std::string alias="")
715  :DerivedValue<T>("reduceIndexWith("+reduce.get_name()+":"+v->get_name()+")", alias),
716  reduce(reduce), v(v) { }
717 
718  ReduceIndex(Function<std::pair<T,int>(std::vector<T>)>& reduce, const std::string& v_name, const std::string alias="")
719  :ReduceIndex(reduce, dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(v_name)), alias) { }
720 };
721 
725 template <typename T>
726 class MaxIndex : public ReduceIndex<T>{
727  private:
729  if (this->v == nullptr)
730  CRITICAL("MaxIndex " << this->get_name() << " created with invalid value.",-1);
731  }
732 
733  public:
734  MaxIndex(const std::string& v_name, const std::string alias="")
735  :ReduceIndex<T>(GenFunction::register_function<T(std::vector<T>)>("maxIndex",
736  FUNC(([](std::vector<T> vec){
737  auto elptr = std::max_element(vec.begin(), vec.end());
738  return std::pair<T,int>(*elptr, int(elptr-vec.begin())); }
739  ))), v_name, alias) { }
740 };
741 
745 template <typename T>
746 class MinIndex : public ReduceIndex<T>{
747  private:
749  if (this->v == nullptr)
750  CRITICAL("MinIndex " << this->get_name() << " created with invalid value.",-1);
751  }
752 
753  public:
754  MinIndex(const std::string& v_name, const std::string alias="")
755  :ReduceIndex<T>(GenFunction::register_function<T(std::vector<T>)>("minIndex",
756  FUNC(([](std::vector<T> vec){
757  auto elptr = std::min_element(vec.begin(), vec.end());
758  return std::pair<T,int>(*elptr, int(elptr-vec.begin())); }
759  ))), v_name, alias) { }
760 };
761 
767 template <typename T>
768 class BoundValue : public DerivedValue<T>{
769  private:
770  void verify_integrity() { }
771  protected:
772  Function<T()>& f;
773  void update_value(){
774  this->value = f();
775  }
776  public:
777  BoundValue(Function<T()>& f, const std::string alias="")
778  :DerivedValue<T>(f.get_name()+"(<bound>)", alias),
779  f(f) { }
780 };
781 
786 template <typename T>
787 class PointerValue : public DerivedValue<T*>{
788  private:
790  if(this->value == nullptr)
791  CRITICAL("PointerValue " << this->get_name() << " created with null pointer",-1);
792  }
793 
794  protected:
795  void update_value(){ }
796 
797  public:
798  PointerValue(const std::string& name, T* ptr, const std::string alias="")
799  :DerivedValue<T*>(name, alias){
800  this->value = ptr;
801  }
802 };
803 
807 template <typename T>
808 class ConstantValue : public DerivedValue<T>{
809  private:
810  void verify_integrity() { }
811 
812  protected:
813  void update_value(){ }
814 
815  public:
816  ConstantValue(const std::string& name, T const_value, const std::string alias="")
817  :DerivedValue<T>("const::"+name, alias),
818  Value<T>::value(const_value) { }
819 };
820 }
821 #endif // value_hpp
Definition: value.hpp:183
void update_value()
Updates the internal value.
Definition: value.hpp:773
Find and return the maximum value of a vector.
Definition: value.hpp:600
Reduce a Value of type vector<T> to just a T.
Definition: value.hpp:571
void update_value()
Updates the internal value.
Definition: value.hpp:541
void update_value()
Updates the internal value.
Definition: value.hpp:444
Find and return the minimum value of a vector and its index.
Definition: value.hpp:746
void _reset()
Mark the internal value as invalid.
Definition: value.hpp:368
A generic value owning only a function object.
Definition: value.hpp:768
T & get_value()
Calculate, if necessary, and return the value held by this object.
Definition: value.hpp:389
virtual void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:579
Calculate the range of the values in a vector.
Definition: value.hpp:657
A std::vector wrapper around a C-style array.
Definition: value.hpp:409
Similar to Reduce, but returns a pair of a T and an int.
Definition: value.hpp:699
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:728
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:602
std::string name
The name of the value.
Definition: value.hpp:190
void update_value()
Updates the internal value.
Definition: value.hpp:488
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:789
Returns the count of elements in the input vector passing a test function.
Definition: value.hpp:536
Find and return the maximum value of a vector and its index.
Definition: value.hpp:726
void update_value()
Updates the internal value.
Definition: value.hpp:575
Parent class to all Function classes.
Definition: value.hpp:68
void _reset()
Mark the internal value as invalid.
Definition: value.hpp:333
Takes a set of four Value<std::vector<T> > objects and a function of four Ts and returns a std::vecto...
Definition: value.hpp:480
static std::map< const std::string, GenValue * > aliases
Composite value names are typically nested.
Definition: value.hpp:215
A generic, observed, value.
Definition: value.hpp:330
Find and return the minimum value of a vector.
Definition: value.hpp:618
Creates a std::pair type from a two other Value objects.
Definition: value.hpp:441
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:420
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:335
T & get_value()
Calculate, if necessary, and return the value held by this object.
Definition: value.hpp:344
void update_value()
Updates the internal value.
Definition: value.hpp:704
void update_value()
Updates the internal value.
Definition: value.hpp:813
The namespace containing all filval classes and functions.
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:502
Extract the element at a specific index from a vector.
Definition: value.hpp:677
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:748
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:679
Calculate the mean value of a vector.
Definition: value.hpp:636
void update_value()
Updates the internal value.
Definition: value.hpp:414
A generic value.
Definition: value.hpp:310
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:638
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:620
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:659
static std::map< const std::string, GenValue * > values
A static mapping containing all created Value objects.
Definition: value.hpp:207
static std::string format_code(const std::string &code)
Attempt to invoke clang-format for the purpose of printing out nicely formatted functions to the log ...
Definition: value.hpp:96
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:770
A generic, derived, value.
Definition: value.hpp:366
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:449
virtual void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:708
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:810
void update_value()
Updates the internal value.
Definition: value.hpp:795
Definition: value.hpp:63
virtual T & get_value()=0
Calculate, if necessary, and return the value held by this object.
void verify_integrity()
This function serves to check that this Value has been created with real, i.e.
Definition: value.hpp:549
A Value which always returns the same value, supplied in the constructor.
Definition: value.hpp:808
static std::map< const std::string, GenFunction * > function_registry
Static mapping of functions from their name to the object wrapper of the function.
Definition: value.hpp:80
A Value of a pointer.
Definition: value.hpp:787