AnySet Documentation
AnyNode.h
1 #ifndef ANY_NODE_H
2 #define ANY_NODE_H
3 
4 #ifdef _MSC_VER
5 # include <iso646.h>
6 #endif
7 
8 #include <typeinfo>
9 #include <cassert>
10 #include <type_traits>
11 #include <ostream>
12 #include <memory>
13 #include "ValueHolder.h"
14 
15 namespace te {
16 
17 /* Forward declarations. */
18 
19 template <class H, class E, class A>
20 struct AnySet;
21 
22 template <class H, class E, class A>
23 std::ostream& operator<<(std::ostream& os, const AnySet<H, E, A>& set);
24 
25 
27 namespace detail {
28 
29 /* Some type traits. */
30 
31 template <class S, class T>
33 {
34  template<class Stream, class Type>
35  static auto test(int) -> decltype(
36  (std::declval<Stream>() << std::declval<Type>()), std::true_type()
37  );
38 
39  template<class, class>
40  static auto test(...) -> std::false_type;
41 
42 public:
43  static constexpr const bool value = decltype(test<S,T>(0))::value;
44 };
45 
46 template <class T>
48 
49 template <class T>
50 inline constexpr const bool is_streamable_v = is_streamable<T>::value;
51 
52 template <class T, class = void>
54 template <class T>
56  T,
57  std::enable_if_t<
58  true,
59  decltype((void)(std::declval<T>() == std::declval<T>()))
60  >
61  >: std::true_type {};
62 template <class T>
63 inline constexpr const bool is_equality_comparable_v = is_equality_comparable<T>::value;
64 
65 template <class T, class = void>
67 template <class T>
69  T,
70  std::enable_if_t<
71  true,
72  decltype((void)(std::declval<T>() != std::declval<T>()), (void)0)
73  >
74  >: std::true_type {};
75 template <class T>
76 inline constexpr const bool is_inequality_comparable_v = is_inequality_comparable<T>::value;
77 
78 template <class Value, class HashFn, class Compare>
79 struct TypedValue;
80 
81 template <class Value, class HashFn, class Compare>
82 struct AnyValueLink;
83 
84 template <class HashFn, class Compare>
85 struct AnyList;
86 
87 } /* namespace detail */
89 
90 /* More forward declarations. */
91 
92 template <class HashFn, class Compare>
93 struct AnyValue;
96 
112 template <class T, class H, class C>
113 bool is(const AnyValue<H, C>& any_v);
114 
116 
117 template <class T, class H, class C>
118 const T* try_as(const AnyValue<H, C>& self);
119 
120 template <class T, class H, class C>
121 const T& as(const AnyValue<H, C>& self);
122 
123 
130 {
137  std::logic_error("Attempt to copy construct type that is not copy constructible."),
138  typeinfo(ti)
139  {
140 
141  }
142 
143  virtual const char* what() const noexcept override
144  {
145  // make what() visible to doxygen
146  return this->std::logic_error::what();
147  }
148 
154 };
155 
163 template <class T>
165  public CopyConstructionError
166 {
167  static_assert(not std::is_copy_constructible_v<T>);
168 
170  CopyConstructionError(typeid(T))
171  {
172 
173  }
174 };
175 
177 namespace detail {
178 
179 template <class T, class H, class C, class ... Args>
180 std::unique_ptr<TypedValue<T, H, C>> make_typed_value(std::size_t hash_v, Args&& ... args);
181 
182 template <class T, class H, class C, class ... Args>
183 std::unique_ptr<TypedValue<T, H, C>> make_typed_value(H hash_fn, Args&& ... args);
184 
185 } /* namespace detail */
187 
191 
216 template <class T, class H, class C, class ... Args>
217 std::unique_ptr<AnyValue<H, C>> make_any_value(std::size_t hash_value, Args&& ... args);
218 
238 template <class T, class H, class C, class ... Args>
239 std::unique_ptr<AnyValue<H, C>> make_any_value(H hasher, Args&& ... args);
240 
242 
268 template <class HashFn, class Compare>
269 struct AnyValue
270 {
271  using self_type = AnyValue<HashFn, Compare>;
272  using hasher = HashFn;
273  using key_equal = Compare;
274  virtual ~AnyValue() = default;
275 
276  AnyValue(const AnyValue&) = delete;
277  AnyValue(AnyValue&&) = delete;
278 
281 
283  template <class T>
284  friend bool operator==(const AnyValue& left, const T& right)
285  {
286  if(const T* p = try_as<T>(left); static_cast<bool>(p))
287  return *p == right;
288  return false;
289  }
290 
292  template <class T>
293  friend bool operator==(const T& left, const AnyValue& right)
294  {
295  if(const T* p = try_as<T>(right); static_cast<bool>(p))
296  return left == *p;
297  return false;
298  }
299 
301  template <class T>
302  friend bool operator!=(const T& left, const AnyValue& right)
303  {
304  if(const T* p = try_as<T>(right); static_cast<bool>(p))
305  return left != *p;
306  return true;
307  }
308 
310  template <class T>
311  friend bool operator!=(const AnyValue& left, const T& right)
312  {
313  if(const T* p = try_as<T>(left); static_cast<bool>(p))
314  return *p != right;
315  return true;
316  }
317 
330  friend bool operator==(const AnyValue& left, const AnyValue& right)
331  { return left.equals(right); }
332 
346  friend bool operator!=(const AnyValue& left, const AnyValue& right)
347  { return left.not_equals(right); }
348 
363  friend bool compare(const AnyValue& left, const AnyValue& right, Compare comp)
364  { return left.compare_to(right, comp); }
365 
379  template <class T, class Comp = Compare, class = std::enable_if_t<not std::is_same_v<T, self_type>>>
380  friend bool compare(const T& left, const AnyValue& right, Comp comp)
381  {
382  if(const T* p = try_as<T>(right); static_cast<bool>(p))
383  return comp(left, *p);
384  return false;
385  }
386 
400  template <class T, class Comp = Compare, class = std::enable_if_t<not std::is_same_v<T, self_type>>>
401  friend bool compare(const AnyValue& left, const T& right, Comp comp)
402  {
403  if(const T* p = try_as<T>(left); static_cast<bool>(p))
404  return comp(*p, right);
405  return false;
406  }
407 
409 
410 
418  friend std::ostream& operator<<(std::ostream& os, const AnyValue& any_v)
419  {
420  any_v.write(os);
421  return os;
422  }
423 
430  virtual const std::type_info& typeinfo() const = 0;
431 
432 protected:
433  AnyValue(std::size_t hash_v):
434  hash(hash_v)
435  {
436 
437  }
438 
439  virtual bool compare_to(const AnyValue& other, Compare comp) const = 0;
440  virtual bool equals(const AnyValue& other) const = 0;
441  virtual bool not_equals(const AnyValue& other) const = 0;
442  virtual void write(std::ostream& os) const = 0;
443  virtual std::unique_ptr<self_type> clone() const = 0;
444 
445 public:
454 private:
455  self_type* next{nullptr};
456  template <class, class, class>
457  friend struct AnySet;
458  friend struct detail::AnyList<HashFn, Compare>;
459 
460 };
461 
463 namespace detail {
464 
465 template <class Value, class HashFn, class Compare>
466 struct AnyValueLink;
467 
482 template <class Value, class HashFn, class Compare>
483 struct TypedValue:
484  public AnyValue<HashFn, Compare>
485 {
486  using base_type = AnyValue<HashFn, Compare>;
487  using value_type = Value;
488  using holder_type = ConstValueHolder<value_type>;
489  using self_type = TypedValue<Value, HashFn, Compare>;
490  using link_type = AnyValueLink<Value, HashFn, Compare>;
491 
492  virtual ~TypedValue() = default;
493 
494  TypedValue(const self_type&) = delete;
495  TypedValue(self_type&&) = delete;
496 
497  self_type& operator=(const self_type&) = delete;
498  self_type& operator=(self_type&&) = delete;
499 
500 protected:
501  TypedValue(std::size_t hash_v):
502  base_type(hash_v)
503  {
504 
505  }
506 public:
507 
508  bool equals(const base_type& other) const final override
509  {
510  if constexpr(detail::is_equality_comparable_v<Value>)
511  if(const Value* v = try_as<Value>(other); static_cast<bool>(v))
512  return (*v) == this->value();
513  else
514  return false;
515  else
516  return false;
517  }
518 
519  bool not_equals(const base_type& other) const final override
520  {
521  if constexpr(detail::is_inequality_comparable_v<Value>)
522  if(const Value* v = try_as<Value>(other); static_cast<bool>(v))
523  return (*v) != this->value();
524  else
525  return false;
526  else
527  return true;
528  }
529 
530  bool compare_to(const base_type& other, Compare comp) const final override
531  {
532  auto* p = try_as<Value>(other);
533  return static_cast<bool>(p) and comp(*p, this->value());
534  }
535 
536  void write(std::ostream& os) const final override
537  {
538  if constexpr(detail::is_streamable_v<Value>)
539  os << this->value();
540  else
541  os << "AnyValue(typeid.name='" << typeinfo().name() << "', hash=" << this->hash << ')';
542  }
543 
544  std::unique_ptr<base_type> clone() const final override
545  {
546  if constexpr(std::is_copy_constructible_v<Value>)
547  return make_any_value<Value, HashFn, Compare>(this->hash, this->value());
548  else
550  }
551 
552  const std::type_info& typeinfo() const final override
553  { return typeid(Value); }
554 
555  const value_type& value() const&
556  { return get_value(as_link()); }
557 
558  const value_type&& value() const&&
559  { return std::move(get_value(as_link())); }
560 
561 private:
562  const link_type& as_link() const& noexcept
563  { return static_cast<const link_type&>(*this); }
564 
565  const link_type&& as_link() const&& noexcept
566  { return static_cast<const link_type&&>(*this); }
567 
568  friend const Value* try_as<Value>(const AnyValue<HashFn, Compare>& self);
569 };
570 
592 template <class Value, class HashFn, class Compare>
593 struct AnyValueLink final:
594  public ConstValueHolder<Value>,
595  public TypedValue<Value, HashFn, Compare>
596 {
597  friend struct TypedValue<Value, HashFn, Compare>;
601 public:
602  virtual ~AnyValueLink() final = default;
603 
604  template <class ... Args>
605  AnyValueLink(std::size_t hash_v, Args&& ... args):
606  holder_type(std::forward<Args>(args)...),
607  base_type(hash_v)
608  {
609 
610  }
611 
612  template <class ... Args>
613  AnyValueLink(HashFn hasher, Args&& ... args):
614  holder_type(std::forward<Args>(args)...),
615  base_type(hasher(get_value(*this)))
616  {
617 
618  }
619 
620  friend const Value& get_value(const self_type& self)
621  { return get_value(static_cast<const holder_type&>(self)); }
622 
623  friend const Value&& get_value(const self_type&& self)
624  { return get_value(static_cast<const holder_type&&>(self)); }
625 
626 };
627 
628 } /* namespace detail */
630 
631 
632 template <class T, class H, class C, class ... Args>
633 std::unique_ptr<detail::TypedValue<T, H, C>> detail::make_typed_value(std::size_t hash_v, Args&& ... args)
634 {
635  auto tmp = std::make_unique<AnyValueLink<T, H, C>>(hash_v, std::forward<Args>(args) ...);
637  static_cast<TypedValue<T, H, C>*>(tmp.release())
638  );
639 }
640 
641 template <class T, class H, class C, class ... Args>
642 std::unique_ptr<detail::TypedValue<T, H, C>> detail::make_typed_value(H hash_fn, Args&& ... args)
643 {
644  auto tmp = std::make_unique<AnyValueLink<T, H, C>>(hash_fn, std::forward<Args>(args) ...);
646  static_cast<TypedValue<T, H, C>*>(tmp.release())
647  );
648 }
649 
650 template <class T, class H, class C, class ... Args>
651 std::unique_ptr<AnyValue<H, C>> make_any_value(std::size_t hash_value, Args&& ... args)
652 {
653  auto tmp = detail::make_typed_value<T, H, C>(hash_value, std::forward<Args>(args)...);
655  static_cast<AnyValue<H, C>*>(tmp.release())
656  );
657 }
658 
659 template <class T, class H, class C, class ... Args>
660 std::unique_ptr<AnyValue<H, C>> make_any_value(H hasher, Args&& ... args)
661 {
662  auto tmp = detail::make_typed_value<T, H, C>(hasher, std::forward<Args>(args)...);
664  static_cast<AnyValue<H, C>*>(tmp.release())
665  );
666 }
667 
668 
671 
707 template <class To, class H, class C>
709 {
710  static_assert(
711  std::is_same_v<const std::decay_t<To>&, To>,
712  "Can only polymorphic_cast an AnyValue reference to a const reference type."
713  );
714  static_assert(
715  std::is_class_v<std::decay_t<To>> and not std::is_final_v<std::decay_t<To>>,
716  "Cannot 'polymorphic_cast()' to final or non-class type."
717  );
718  return dynamic_cast<To>(any_v);
719 }
720 
754 template <class To, class H, class C>
756 {
757  using type = std::decay_t<std::remove_pointer_t<std::decay_t<To>>>;
758  static_assert(
759  std::is_same_v<const type*, To>,
760  "Can only polymorphic_cast an AnyValue pointer to a pointer to const type."
761  );
762  static_assert(std::is_class_v<type> and not std::is_final_v<type>,
763  "Cannot 'polymorphic_cast()' to final or non-class type."
764  );
765  return dynamic_cast<To>(any_v);
766 }
767 
790 template <class To, class H, class C>
791 To exact_cast(const AnyValue<H, C>& any_v)
792 {
793  using to_type = std::decay_t<To>;
794  if(is<to_type>(any_v))
795  return static_cast<const detail::TypedValue<to_type, H, C>&>(any_v).value();
796  else
797  throw std::bad_cast();
798 }
799 
819 template <class To, class H, class C>
820 To exact_cast(const AnyValue<H, C>* any_v)
821 {
822  static_assert(
823  std::is_pointer_v<To>,
824  "exact_cast<T>(const AnyValue<H, C>*) requires that T be a pointer type."
825  );
826  using to_type = std::decay_t<std::remove_pointer_t<To>>;
827  if(is<to_type>(*any_v))
828  return std::addressof(
829  static_cast<const detail::TypedValue<to_type, H, C>&>(*any_v).value()
830  );
831  else
832  return nullptr;
833 }
834 
856 template <class To, class H, class C>
857 To unsafe_cast(const AnyValue<H, C>& any_v)
858 {
859  return static_cast<const detail::TypedValue<std::decay_t<To>, H, C>&>(any_v).value();
860 }
861 
863 
866 
890 template <class T, class H, class C>
891 const T* try_as(const AnyValue<H, C>& any_v)
892 {
893  static_assert(std::is_object_v<T>);
894  if(const T* p = exact_cast<const T*>(&any_v); static_cast<bool>(p))
895  return p;
896  else if constexpr(std::is_class_v<T> and not std::is_final_v<T>)
897  {
898  if(p = polymorphic_cast<const T*>(&any_v); static_cast<bool>(p))
899  return p;
900  }
901  return nullptr;
902 }
903 
928 template <class T, class H, class C>
929 const T& as(const AnyValue<H, C>& self)
930 {
931  if(const auto* p = try_as<T>(self); static_cast<bool>(p))
932  return *p;
933  throw std::bad_cast();
934 }
935 
936 template <class T, class H, class C>
937 bool is(const AnyValue<H, C>& any_v)
938 { return any_v.typeinfo() == typeid(T); }
939 
940 
952 template <class T, class H, class C>
953 const T& get(const AnyValue<H, C>& any_v)
954 {
955  return as<T>(any_v);
956 }
957 
987 template <class T, class H, class C, class DefaultRef>
988 const std::decay_t<T>& get_default_ref(const AnyValue<H, C>& any_v, DefaultRef&& default_ref)
989 {
990  static_assert(
991  std::is_same_v<T, std::decay_t<T>>,
992  "T should be a naked type (no cv qualifiers, or refereces) in get_default_ref<T>()"
993  );
994 
995  static_assert(
996  std::is_same_v<std::decay_t<T>, std::decay_t<DefaultRef>>,
997  "The second argument (the 'default') in get_default_ref<T>() must have the same type as T."
998  );
999 
1000  static_assert(
1001  not std::is_rvalue_reference_v<decltype(default_ref)>,
1002  "get_default_ref() cannot be called with an rvalue (would return a dangling reference)."
1003  );
1004 
1005  if(const std::decay_t<T>* p = try_as<T>(any_v); static_cast<bool>(p))
1006  return *p;
1007  else
1008  return std::forward<DefaultRef>(default_ref);
1009 }
1010 
1039 template <class T, class H, class C, class DefaultVal>
1040 T get_default_val(const AnyValue<H, C>& any_v, DefaultVal&& default_val)
1041 {
1042  static_assert(
1043  std::is_same_v<T, std::decay_t<T>>,
1044  "T should be a naked type (no cv qualifiers, or refereces) in get_default_val<T>()"
1045  );
1046 
1047  static_assert(
1048  std::is_constructible_v<std::decay_t<T>, DefaultVal>,
1049  "Cannot construct return value of get_default_val() with given argument for the default value (the second arguments)."
1050  );
1051 
1052  static_assert(
1053  std::is_constructible_v<std::decay_t<T>, const std::decay_t<T>>,
1054  "Cannot construct return value of get_default_val() with the value contained in AnyValue (const reference)."
1055  );
1056 
1057  if(const T* p = try_as<T>(any_v); static_cast<bool>(p))
1058  return *p;
1059  else
1060  return static_cast<T>(std::forward<DefaultVal>(default_val));
1061 }
1062 
1064 
1065 
1066 } /* namespace te */
1067 
1068 #endif /* ANY_NODE_H */
To exact_cast(const AnyValue< H, C > *any_v)
Access the contained object.
Definition: AnyNode.h:820
friend bool operator!=(const T &left, const AnyValue &right)
Query whether the contained object in right is not of type T or not equal to left.
Definition: AnyNode.h:302
friend bool operator!=(const AnyValue &left, const T &right)
Query whether the contained object in left is not of type T or not equal to right.
Definition: AnyNode.h:311
const std::size_t hash
The hash code obtained by invoking an instance of HashFn on the contained object. ...
Definition: AnyNode.h:453
const T * try_as(const AnyValue< H, C > &any_v)
Get a pointer to the contained object of type T. If the contained object is not an instance of type T...
Definition: AnyNode.h:891
friend bool operator==(const AnyValue &left, const T &right)
Query whether the contained object in left is of type T and equal to right.
Definition: AnyNode.h:284
friend bool operator==(const AnyValue &left, const AnyValue &right)
Query whether the contained objects in left and right are of the same equality-comparable type...
Definition: AnyNode.h:330
friend bool compare(const AnyValue &left, const T &right, Comp comp)
Query whether the contained object in left is of type T and subsequently whether the contained object...
Definition: AnyNode.h:401
CopyConstructionError(const std::type_info &ti)
Construct a CopyConstructionError exception object.
Definition: AnyNode.h:136
friend bool operator==(const T &left, const AnyValue &right)
Query whether the contained object in right is of type T and equal to left.
Definition: AnyNode.h:293
This class is an implementation detail and is not part of the public interface of AnyValue...
Definition: AnyNode.h:79
To polymorphic_cast(const AnyValue< H, C > &any_v)
Access the contained object through a reference to dynamic type To.
Definition: AnyNode.h:708
friend bool compare(const AnyValue &left, const AnyValue &right, Compare comp)
Query whether the contained objects in left and right are of the same type, and subsequently whether ...
Definition: AnyNode.h:363
Definition: AnyNode.h:53
Definition: ValueHolder.h:13
T get_default_val(const AnyValue< H, C > &any_v, DefaultVal &&default_val)
Get a copy of the contained value in any_v of type T.
Definition: AnyNode.h:1040
T what(T... args)
Base type of NoCopyConstructorError. Thrown when attempting to make copies of an AnyValue instance th...
Definition: AnyNode.h:128
Exception thrown when attempting to make copies of an AnyValue instance that contains an instance of ...
Definition: AnyNode.h:164
Primary classes and utility functions for AnySet.
Definition: SetOperations.h:21
virtual const std::type_info & typeinfo() const =0
Get a reference to a std::type_info object that indicates the type of the contained object...
Definition: AnyNode.h:66
T addressof(T... args)
Definition: AnyList.h:18
T move(T... args)
To polymorphic_cast(const AnyValue< H, C > *any_v)
Access the contained object through a pointer to dynamic type To.
Definition: AnyNode.h:755
friend bool operator!=(const AnyValue &left, const AnyValue &right)
Query whether the contained objects in left and right are of different types, or whether the containe...
Definition: AnyNode.h:346
const std::type_info & typeinfo
Definition: AnyNode.h:153
const std::type_info & typeinfo() const final override
Get a reference to a std::type_info object that indicates the type of the contained object...
Definition: AnyNode.h:552
To unsafe_cast(const AnyValue< H, C > &any_v)
Access the contained object without dynamic type checking.
Definition: AnyNode.h:857
friend std::ostream & operator<<(std::ostream &os, const AnyValue &any_v)
Write the contained object to the given std::ostream using the stream insertion << operator...
Definition: AnyNode.h:418
AnySet is an associative container that contains a set of unique objects of any constructible type...
Definition: AnySet.h:104
friend bool compare(const T &left, const AnyValue &right, Comp comp)
Query whether the contained object in right is of type T and subsequently whether the contained objec...
Definition: AnyNode.h:380
Definition: AnyNode.h:93
const T & as(const AnyValue< H, C > &self)
Get a reference to the contained object of type T. If the contained object is not an instance of type...
Definition: AnyNode.h:929
Definition: AnyNode.h:32
const std::decay_t< T > & get_default_ref(const AnyValue< H, C > &any_v, DefaultRef &&default_ref)
Get the contained value in any_v through a reference to const T.
Definition: AnyNode.h:988
To exact_cast(const AnyValue< H, C > &any_v)
Access the contained object.
Definition: AnyNode.h:791