Spicy
type-info.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <memory>
6 #include <optional>
7 #include <string>
8 #include <tuple>
9 #include <utility>
10 #include <variant>
11 #include <vector>
12 
13 #include <hilti/rt/exception.h>
14 #include <hilti/rt/fmt.h>
15 #include <hilti/rt/types/address.h>
16 #include <hilti/rt/types/bool.h>
17 #include <hilti/rt/types/bytes.h>
18 #include <hilti/rt/types/map.h>
19 #include <hilti/rt/types/network.h>
20 #include <hilti/rt/types/port.h>
21 #include <hilti/rt/types/reference.h>
22 #include <hilti/rt/types/set.h>
23 #include <hilti/rt/types/stream.h>
24 #include <hilti/rt/types/vector.h>
25 
26 namespace hilti::rt {
27 
28 struct TypeInfo;
29 
30 namespace type_info {
31 
32 class Value;
33 
34 namespace value {
35 
43 class Parent {
44 public:
46  template<typename T>
47  Parent(const StrongReference<T>& value) : _handle(std::make_shared<bool>()), _value(value) {}
48 
50  Parent() : _handle(std::make_shared<bool>()) {}
51 
53  void tie(hilti::rt::StrongReferenceGeneric value) { _value = std::move(value); }
54 
55 private:
56  friend class type_info::Value;
57 
58  std::weak_ptr<bool> handle() const {
59  if ( ! _value )
60  throw InvalidValue("type-info traversal not tied to value");
61 
62  return _handle;
63  }
64 
65  std::shared_ptr<bool> _handle;
66  std::optional<hilti::rt::StrongReferenceGeneric> _value;
67 };
68 
69 } // namespace value
70 
82 class Value {
83 public:
91  Value(const void* ptr, const TypeInfo* ti, const value::Parent& parent)
92  : _ptr(ptr), _ti(ti), _parent_handle(parent.handle()) {
93  check();
94  }
95 
103  Value(const void* ptr, const TypeInfo* ti, const Value& parent)
104  : _ptr(ptr), _ti(ti), _parent_handle(parent._parent_handle) {
105  check();
106  }
107 
111  Value() = default;
112 
119  const void* pointer() const {
120  if ( ! _ptr )
121  throw InvalidValue("value not set");
122 
123  check();
124  return _ptr;
125  }
126 
128  const TypeInfo& type() const { return *_ti; }
129 
131  operator bool() const { return _ptr != nullptr; }
132 
133 private:
134  // Throws if parent has expired.
135  void check() const {
136  if ( _parent_handle.expired() )
137  throw InvalidValue("type info value expired");
138  }
139 
140  const void* _ptr;
141  const TypeInfo* _ti;
142  std::weak_ptr<bool> _parent_handle;
143 };
144 
145 namespace detail {
146 
151 template<typename T>
152 class AtomicType {
153 public:
155  const T& get(const Value& v) const { return *static_cast<const T*>(v.pointer()); }
156 };
157 
163 public:
168  using Accessor = const void* (*)(const Value& v);
169 
176  DereferenceableType(const TypeInfo* vtype, Accessor accessor) : _vtype(vtype), _accessor(accessor) {}
177 
181  Value value(const Value& v) const { return Value(_accessor(v), _vtype, v); }
182 
186  const TypeInfo* valueType() const { return _vtype; }
187 
188 private:
189  const TypeInfo* _vtype;
190  const Accessor _accessor;
191 };
192 
193 class IterableType;
194 
195 namespace iterable_type {
196 
198 class Iterator {
199 public:
206  Iterator(const IterableType* type, Value v);
207 
212  Iterator() {}
213 
215  Iterator& operator++();
216 
218  Iterator operator++(int);
219 
226  Value operator*() const;
227 
237  bool operator==(const Iterator& other) const {
238  // This is good enough just for comparing against end().
239  return _cur.has_value() == other._cur.has_value();
240  }
241 
243  bool operator!=(const Iterator& other) const { return ! (*this == other); }
244 
245 private:
246  const IterableType* _type = nullptr;
247  Value _value;
248  std::optional<hilti::rt::any> _cur;
249 };
250 
255 class Sequence {
256 public:
263  Sequence(const IterableType* type, Value v) : _begin(type, std::move(v)) {}
264 
266  Iterator begin() const { return _begin; }
267 
269  Iterator end() const { return Iterator(); }
270 
271 private:
272  Iterator _begin;
273 };
274 
275 } // namespace iterable_type
276 
282 public:
301  using Accessor = std::tuple<std::optional<hilti::rt::any> (*)(const Value&), // begin()
302  std::optional<hilti::rt::any> (*)(const hilti::rt::any&), // next()
303  const void* (*)(const hilti::rt::any&)>; // deref()
304 
312  IterableType(const TypeInfo* etype, Accessor accessor) : _etype(etype), _accessor(std::move(accessor)) {}
313 
315  iterable_type::Sequence iterate(const Value& value) const { return iterable_type::Sequence(this, value); }
316 
321  const TypeInfo* dereferencedType() const { return _etype; }
322 
323 private:
324  friend class iterable_type::Iterator;
325 
326  const TypeInfo* _etype;
327  const Accessor _accessor;
328 };
329 
330 namespace iterable_type {
331 
332 inline Iterator::Iterator(const IterableType* type, Value v) : _type(type) {
333  _value = std::move(v);
334  _cur = std::get<0>(_type->_accessor)(_value); // begin()
335 }
336 
338  if ( _cur.has_value() )
339  _cur = std::get<1>(_type->_accessor)(*_cur); // next()
340 
341  return *this;
342 }
343 
345  auto x = *this;
346 
347  if ( _cur.has_value() )
348  _cur = std::get<1>(_type->_accessor)(*_cur); // next()
349 
350  return x;
351 }
352 
353 inline Value Iterator::operator*() const {
354  if ( ! _cur.has_value() )
355  throw InvalidValue("type info iterator invalid");
356 
357  return Value(std::get<2>(_type->_accessor)(*_cur), _type->_etype, _value); // deref()
358 }
359 
360 } // namespace iterable_type
361 
363 class ValueLessType {};
364 
370 
371 } // namespace detail
372 
374 
376 class Address : public detail::AtomicType<hilti::rt::Address> {};
377 
379 class Any : public detail::ValueLessType {};
380 
382 class Bool : public detail::AtomicType<bool> {};
383 
385 class Bytes : public detail::AtomicType<hilti::rt::Bytes> {};
386 
388 class BytesIterator : public detail::AtomicType<hilti::rt::bytes::Iterator> {};
389 
390 namespace enum_ {
391 
393 struct Label {
400  Label(std::string name, int64_t value) : name(std::move(name)), value(value) {}
401 
402  const std::string name;
403  const int64_t value;
404 };
405 
406 } // namespace enum_
407 
409 class Enum {
410 public:
416  Enum(std::vector<enum_::Label> labels) : _labels(std::move(labels)) {}
417 
419  const auto& labels() const { return _labels; }
420 
426  enum_::Label get(const Value& v) const {
427  auto n = *static_cast<const int64_t*>(v.pointer());
428 
429  for ( const auto& l : _labels ) {
430  if ( n == l.value )
431  return l;
432  }
433 
434  return enum_::Label(fmt("<unknown-%" PRId64 ">", n), n);
435  }
436 
437 private:
438  const std::vector<enum_::Label> _labels;
439 };
440 
441 
443 class Error : public detail::AtomicType<hilti::rt::result::Error> {};
444 
446 class Exception : public detail::AtomicType<hilti::rt::Exception> {};
447 
454 
456 class Interval : public detail::AtomicType<hilti::rt::Interval> {};
457 
459 class Library : public detail::ValueLessType {};
460 
461 class Map;
462 
463 namespace map {
464 
466 class Iterator {
467 public:
474  Iterator(const Map* type, Value v);
475 
480  Iterator() {}
481 
483  Iterator& operator++();
484 
486  Iterator operator++(int);
487 
494  std::pair<Value, Value> operator*() const;
495 
505  bool operator==(const Iterator& other) const {
506  // This is good enough just for comparing against end().
507  return _cur.has_value() == other._cur.has_value();
508  }
509 
511  bool operator!=(const Iterator& other) const { return ! (*this == other); }
512 
513 private:
514  const Map* _type = nullptr;
515  Value _value;
516  std::optional<hilti::rt::any> _cur;
517 };
518 
523 class Sequence {
524 public:
531  Sequence(const Map* type, Value v) : _begin(type, std::move(v)) {}
532 
534  Iterator begin() const { return _begin; }
535 
537  Iterator end() const { return Iterator(); }
538 
539 private:
540  Iterator _begin;
541 };
542 } // namespace map
543 
545 class Map {
546 public:
551  using Accessor = std::tuple<std::optional<hilti::rt::any> (*)(const Value&), // begin()
552  std::optional<hilti::rt::any> (*)(const hilti::rt::any&), // next()
553  std::pair<const void*, const void*> (*)(const hilti::rt::any&)>; // deref()
554 
563  Map(const TypeInfo* ktype, const TypeInfo* vtype, Accessor accessor)
564  : _ktype(ktype), _vtype(vtype), _accessor(std::move(accessor)) {}
565 
567  map::Sequence iterate(const Value& value) const { return map::Sequence(this, value); }
568 
573  const TypeInfo* keyType() const { return _ktype; }
574 
578  const TypeInfo* valueType() const { return _vtype; }
579 
580  template<typename K, typename V>
581  using iterator_pair =
582  std::pair<typename hilti::rt::Map<K, V>::const_iterator, typename hilti::rt::Map<K, V>::const_iterator>;
583 
584  template<typename K, typename V>
585  static Accessor accessor() {
586  return std::make_tuple(
587  [](const Value& v_) -> std::optional<hilti::rt::any> { // begin()
588  auto v = static_cast<const hilti::rt::Map<K, V>*>(v_.pointer());
589  if ( v->cbegin() != v->cend() )
590  return std::make_pair(v->cbegin(), v->cend());
591  else
592  return std::nullopt;
593  },
594  [](const hilti::rt::any& i_) -> std::optional<hilti::rt::any> { // next()
595  auto i = hilti::rt::any_cast<iterator_pair<K, V>>(i_);
596  auto n = std::make_pair(++i.first, i.second);
597  if ( n.first != n.second )
598  return std::move(n);
599  else
600  return std::nullopt;
601  },
602  [](const hilti::rt::any& i_) -> std::pair<const void*, const void*> { // deref()
603  auto i = hilti::rt::any_cast<iterator_pair<K, V>>(i_);
604  return std::make_pair(&(*i.first).first, &(*i.first).second);
605  });
606  }
607 
608 private:
609  friend class map::Iterator;
610 
611  const TypeInfo* _ktype;
612  const TypeInfo* _vtype;
613  Accessor _accessor;
614 };
615 
616 namespace map {
617 
618 inline Iterator::Iterator(const Map* type, Value v) : _type(type) {
619  _value = std::move(v);
620  _cur = std::get<0>(_type->_accessor)(_value); // begin()
621 }
622 
624  if ( _cur.has_value() )
625  _cur = std::get<1>(_type->_accessor)(*_cur); // next()
626 
627  return *this;
628 }
629 
631  auto x = *this;
632 
633  if ( _cur.has_value() )
634  _cur = std::get<1>(_type->_accessor)(*_cur); // next()
635 
636  return x;
637 }
638 
639 inline std::pair<Value, Value> Iterator::operator*() const {
640  if ( ! _cur.has_value() )
641  throw InvalidValue("type info iterator invalid");
642 
643  auto x = std::get<2>(_type->_accessor)(*_cur);
644  return std::make_pair(Value(x.first, _type->_ktype, _value), Value(x.second, _type->_vtype, _value));
645 }
646 
647 } // namespace map
648 
650 class MapIterator {
651 public:
656  using Accessor = std::pair<const void*, const void*> (*)(const Value& v);
657 
665  MapIterator(const TypeInfo* ktype, const TypeInfo* vtype, Accessor accessor)
666  : _ktype(ktype), _vtype(vtype), _accessor(accessor) {}
667 
671  std::pair<Value, Value> value(const Value& v) const {
672  auto x = _accessor(v);
673  return std::make_pair(Value(x.first, _ktype, v), Value(x.second, _vtype, v));
674  }
675 
680  const TypeInfo* keyType() const { return _ktype; }
681 
685  const TypeInfo* valueType() const { return _vtype; }
686 
687  template<typename K, typename V>
688  static auto accessor() { // deref()
689  return [](const Value& v) -> std::pair<const void*, const void*> {
690  using iterator_type = const hilti::rt::map::Iterator<K, V>;
691  const auto& x = **static_cast<iterator_type*>(v.pointer());
692  return std::make_pair(&x.first, &x.second);
693  };
694  }
695 
696 private:
697  const TypeInfo* _ktype;
698  const TypeInfo* _vtype;
699  const Accessor _accessor;
700 };
701 
703 class Network : public detail::AtomicType<hilti::rt::Network> {};
704 
707 public:
709 
710  template<typename T>
711  static auto accessor() { // deref()
712  return [](const Value& v) -> const void* {
713  auto x = static_cast<const std::optional<T>*>(v.pointer());
714  return x->has_value() ? &*x : nullptr;
715  };
716  }
717 };
718 
720 class Port : public detail::AtomicType<hilti::rt::Port> {};
721 
723 class Real : public detail::AtomicType<double> {};
724 
726 class RegExp : public detail::AtomicType<hilti::rt::RegExp> {};
727 
730 public:
732 
733  template<typename T>
734  static auto accessor() { // deref()
735  return [](const Value& v) -> const void* {
736  auto x = static_cast<const hilti::rt::Result<T>*>(v.pointer());
737  return x->hasValue() ? &*x : nullptr;
738  };
739  }
740 
741  // TODO: Cannot get to the error currently.
742 };
743 
745 class Set : public detail::IterableType {
746 public:
748 
749  template<typename T>
750  using iterator_pair =
751  std::pair<typename hilti::rt::Set<T>::const_iterator, typename hilti::rt::Set<T>::const_iterator>;
752 
753  template<typename T>
754  static Accessor accessor() {
755  return std::make_tuple(
756  [](const Value& v_) -> std::optional<hilti::rt::any> {
757  auto v = static_cast<const hilti::rt::Set<T>*>(v_.pointer());
758  if ( v->begin() != v->end() )
759  return std::make_pair(v->begin(), v->end());
760  else
761  return std::nullopt;
762  },
763  [](const hilti::rt::any& i_) -> std::optional<hilti::rt::any> {
764  auto i = hilti::rt::any_cast<iterator_pair<T>>(i_);
765  auto n = std::make_pair(++i.first, i.second);
766  if ( n.first != n.second )
767  return std::move(n);
768  else
769  return std::nullopt;
770  },
771  [](const hilti::rt::any& i_) -> const void* {
772  auto i = hilti::rt::any_cast<iterator_pair<T>>(i_);
773  return &*i.first;
774  });
775  }
776 };
777 
780 public:
782 
783  template<typename T>
784  static auto accessor() { // deref()
785  return [](const Value& v) -> const void* {
786  return &**static_cast<const hilti::rt::set::Iterator<T>*>(v.pointer());
787  };
788  }
789 };
790 
792 template<typename Width>
793 class SignedInteger : public detail::AtomicType<Width> {};
794 
796 class Stream : public detail::AtomicType<hilti::rt::Stream> {};
797 
799 class StreamIterator : public detail::AtomicType<hilti::rt::stream::SafeConstIterator> {};
800 
802 class StreamView : public detail::AtomicType<hilti::rt::stream::View> {};
803 
805 class String : public detail::AtomicType<std::string> {};
806 
809 public:
811 
812  template<typename T>
813  static auto accessor() { // deref()
814  return [](const Value& v) -> const void* {
815  return static_cast<const hilti::rt::StrongReference<T>*>(v.pointer())->get();
816  };
817  }
818 };
819 
820 
821 class Struct;
822 
823 namespace struct_ {
824 
826 struct Field {
831  using Accessor = const void* (*)(const Value& v);
832 
841  Field(const char* name, const TypeInfo* type, std::ptrdiff_t offset, bool internal,
842  Accessor accessor = accessor_default)
843  : name(name), type(type), offset(offset), accessor(accessor), internal(internal) {}
844 
846  static const void* accessor_default(const Value& v) { return v.pointer(); }
847 
849  template<typename T>
851  return [](const Value& v) -> const void* {
852  auto x = static_cast<const std::optional<T>*>(v.pointer());
853  if ( x->has_value() ) {
854  auto& o = *x;
855  return &*o;
856  }
857  else
858  return nullptr;
859  };
860  }
861 
862  bool isInternal() const { return internal; }
863 
864  const std::string name;
865  const TypeInfo* type ;
866 
867 private:
868  friend class type_info::Struct;
869 
870  // Internal wrapper around accessor that's used from ``Struct``.
871  Value value(const Value& v) const { return Value(accessor(v), type, v); }
872 
873  const std::ptrdiff_t offset;
874  const Accessor accessor;
875  const bool internal;
876 };
877 
878 }; // namespace struct_
879 
881 class Struct {
882 public:
888  Struct(std::vector<struct_::Field> fields) : _fields(std::move(fields)) {}
889 
896  auto fields(bool include_internal = false) const {
897  std::vector<std::reference_wrapper<const struct_::Field>> fields;
898  std::copy_if(_fields.begin(), _fields.end(), std::back_inserter(fields),
899  [=](const struct_::Field& f) { return include_internal || ! f.isInternal(); });
900  return fields;
901  }
902 
912  auto iterate(const Value& v, bool include_internal = false) const {
913  std::vector<std::pair<const struct_::Field&, Value>> values;
914 
915  for ( const auto& f : fields(include_internal) ) {
916  auto x = Value(static_cast<const char*>(v.pointer()) + f.get().offset, f.get().type, v);
917  values.emplace_back(f.get(), f.get().value(x));
918  }
919 
920  return values;
921  }
922 
923 private:
924  const std::vector<struct_::Field> _fields;
925 };
926 
928 class Time : public detail::AtomicType<hilti::rt::Time> {};
929 
930 class Tuple;
931 
932 namespace tuple {
933 
935 class Element {
936 public:
944  Element(const char* name, const TypeInfo* type, std::ptrdiff_t offset) : name(name), type(type), offset(offset) {}
945 
946  const std::string name;
947  const TypeInfo* type;
949 private:
950  friend class type_info::Tuple;
951 
952  const std::ptrdiff_t offset;
953 };
954 
955 }; // namespace tuple
956 
958 class Tuple {
959 public:
965  Tuple(std::vector<tuple::Element> elements) : _elements(std::move(elements)) {}
966 
968  const auto& elements() const { return _elements; }
969 
978  auto iterate(const Value& v) const {
979  std::vector<std::pair<const tuple::Element&, Value>> values;
980 
981  for ( const auto& f : _elements )
982  values.emplace_back(f, Value(static_cast<const char*>(v.pointer()) + f.offset, f.type, v));
983 
984  return values;
985  }
986 
987 private:
988  const std::vector<tuple::Element> _elements;
989 };
990 
991 namespace union_ {
992 
994 struct Field {
1001  Field(const char* name, const TypeInfo* type) : name(name), type(type) {}
1002 
1003  const std::string name;
1004  const TypeInfo* type;
1005 };
1006 
1007 }; // namespace union_
1008 
1010 class Union {
1011 public:
1016  using Accessor = std::size_t (*)(const Value& v);
1017  const size_t npos = std::variant_npos;
1018 
1025  Union(std::vector<union_::Field> fields, Accessor accessor) : _fields(std::move(fields)), _accessor(accessor) {}
1026 
1028  const auto& fields() const { return _fields; }
1029 
1034  Value value(const Value& v) const {
1035  if ( auto idx = _accessor(v); idx > 0 )
1036  return Value(v.pointer(), _fields[idx - 1].type, v);
1037  else
1038  return Value();
1039  }
1040 
1041  template<typename T>
1042  static auto accessor() {
1043  return [](const Value& v) -> std::size_t { return static_cast<const T*>(v.pointer())->index(); };
1044  }
1045 
1046 private:
1047  const std::vector<union_::Field> _fields;
1048  const Accessor _accessor;
1049 };
1050 
1052 template<typename Width>
1053 class UnsignedInteger : public detail::AtomicType<Width> {};
1054 
1057 public:
1059 
1060  template<typename T>
1061  static auto accessor() { // deref()
1062  return [](const Value& v) -> const void* {
1063  return static_cast<const hilti::rt::ValueReference<T>*>(v.pointer())->get();
1064  };
1065  }
1066 };
1067 
1070 public:
1072 
1073  template<typename T, typename Allocator>
1074  using iterator_pair = std::pair<typename hilti::rt::Vector<T, Allocator>::const_iterator,
1076 
1077  template<typename T, typename Allocator = std::allocator<T>>
1078  static Accessor accessor() {
1079  return std::make_tuple(
1080  [](const Value& v_) -> std::optional<hilti::rt::any> { // begin()
1081  auto v = static_cast<const hilti::rt::Vector<T, Allocator>*>(v_.pointer());
1082  if ( v->begin() != v->end() )
1083  return std::make_pair(v->begin(), v->end());
1084  else
1085  return std::nullopt;
1086  },
1087  [](const hilti::rt::any& i_) -> std::optional<hilti::rt::any> { // next()
1088  auto i = hilti::rt::any_cast<iterator_pair<T, Allocator>>(i_);
1089  auto n = std::make_pair(++i.first, i.second);
1090  if ( n.first != n.second )
1091  return std::move(n);
1092  else
1093  return std::nullopt;
1094  },
1095  [](const hilti::rt::any& i_) -> const void* { // deref()
1096  auto i = hilti::rt::any_cast<iterator_pair<T, Allocator>>(i_);
1097  return &*i.first;
1098  });
1099  }
1100 };
1101 
1104 public:
1106 
1107  template<typename T, typename Allocator = std::allocator<T>>
1108  static auto accessor() { // deref()
1109  return [](const Value& v) -> const void* {
1110  return &**static_cast<const hilti::rt::vector::Iterator<T, Allocator>*>(v.pointer());
1111  };
1112  }
1113 };
1114 
1116 class Void : public detail::ValueLessType {};
1117 
1120 public:
1122 
1123  template<typename T>
1124  static auto accessor() { // deref()
1125  return [](const Value& v) -> const void* {
1126  return static_cast<const hilti::rt::WeakReference<T>*>(v.pointer())->get();
1127  };
1128  }
1129 };
1130 
1131 } // namespace type_info
1132 
1133 } // namespace hilti::rt
1134 
1135 namespace hilti::rt {
1136 
1143 struct TypeInfo {
1144  std::optional<const char*> id;
1145  const char* display;
1147  enum Tag {
1148  Undefined,
1149  Address,
1150  Any,
1151  Bool,
1152  Bytes,
1153  BytesIterator,
1154  Enum,
1155  Error,
1156  Exception,
1157  Function,
1158  Interval,
1159  Library,
1160  Map,
1161  MapIterator,
1162  Network,
1163  Optional,
1164  Port,
1165  Real,
1166  RegExp,
1167  Result,
1168  Set,
1169  SetIterator,
1170  SignedInteger_int8,
1171  SignedInteger_int16,
1172  SignedInteger_int32,
1173  SignedInteger_int64,
1174  Stream,
1175  StreamIterator,
1176  StreamView,
1177  String,
1179  Struct,
1180  Time,
1181  Tuple,
1182  Union,
1183  UnsignedInteger_uint8,
1184  UnsignedInteger_uint16,
1185  UnsignedInteger_uint32,
1186  UnsignedInteger_uint64,
1188  Vector,
1189  VectorIterator,
1190  Void,
1192  };
1193 
1194  // Actual storage for the held type.
1195  std::unique_ptr<const char, void (*)(const char*)> _storage = {nullptr, [](const char*) {}};
1196 
1197  Tag tag = Tag::Undefined;
1198  union {
1199  type_info::Address* address;
1200  type_info::Any* any;
1201  type_info::Bool* bool_;
1202  type_info::Bytes* bytes;
1203  type_info::BytesIterator* bytes_iterator;
1204  type_info::Enum* enum_;
1205  type_info::Error* error;
1206  type_info::Exception* exception;
1207  type_info::Function* function;
1208  type_info::Interval* interval;
1209  type_info::Library* library;
1210  type_info::Map* map;
1211  type_info::MapIterator* map_iterator;
1212  type_info::Network* network;
1213  type_info::Optional* optional;
1214  type_info::Port* port;
1215  type_info::Real* real;
1216  type_info::RegExp* regexp;
1217  type_info::Result* result;
1218  type_info::Set* set;
1219  type_info::SetIterator* set_iterator;
1220  type_info::SignedInteger<int8_t>* signed_integer_int8;
1221  type_info::SignedInteger<int16_t>* signed_integer_int16;
1222  type_info::SignedInteger<int32_t>* signed_integer_int32;
1223  type_info::SignedInteger<int64_t>* signed_integer_int64;
1224  type_info::Stream* stream;
1225  type_info::StreamIterator* stream_iterator;
1226  type_info::StreamView* stream_view;
1227  type_info::String* string;
1228  type_info::StrongReference* strong_reference;
1229  type_info::Struct* struct_;
1230  type_info::Time* time;
1231  type_info::Tuple* tuple;
1232  type_info::Union* union_;
1233  type_info::UnsignedInteger<uint8_t>* unsigned_integer_uint8;
1234  type_info::UnsignedInteger<uint16_t>* unsigned_integer_uint16;
1235  type_info::UnsignedInteger<uint32_t>* unsigned_integer_uint32;
1236  type_info::UnsignedInteger<uint64_t>* unsigned_integer_uint64;
1237  type_info::ValueReference* value_reference;
1238  type_info::Vector* vector;
1239  type_info::VectorIterator* vector_iterator;
1240  type_info::Void* void_;
1241  type_info::WeakReference* weak_reference;
1242  };
1243 
1244  TypeInfo() = default;
1245 
1246  template<typename Type>
1247  TypeInfo(std::optional<const char*> _id, const char* _display, Type* value)
1248  : id(_id), display(_display), _storage(reinterpret_cast<const char*>(value), [](const char* p) {
1249  delete reinterpret_cast<const Type*>(p);
1250  }) {
1251  if constexpr ( std::is_same_v<Type, type_info::Address> ) {
1252  tag = Address;
1253  address = value;
1254  }
1255  else if constexpr ( std::is_same_v<Type, type_info::Any> ) {
1256  tag = Any;
1257  any = value;
1258  }
1259  else if constexpr ( std::is_same_v<Type, type_info::Bool> ) {
1260  tag = Bool;
1261  bool_ = value;
1262  }
1263  else if constexpr ( std::is_same_v<Type, type_info::Bytes> ) {
1264  tag = Bytes;
1265  bytes = value;
1266  }
1267  else if constexpr ( std::is_same_v<Type, type_info::BytesIterator> ) {
1268  tag = BytesIterator;
1269  bytes_iterator = value;
1270  }
1271  else if constexpr ( std::is_same_v<Type, type_info::Enum> ) {
1272  tag = Enum;
1273  enum_ = value;
1274  }
1275  else if constexpr ( std::is_same_v<Type, type_info::Error> ) {
1276  tag = Error;
1277  error = value;
1278  }
1279  else if constexpr ( std::is_same_v<Type, type_info::Exception> ) {
1280  tag = Exception;
1281  exception = value;
1282  }
1283  else if constexpr ( std::is_same_v<Type, type_info::Function> ) {
1284  tag = Function;
1285  function = value;
1286  }
1287  else if constexpr ( std::is_same_v<Type, type_info::Interval> ) {
1288  tag = Interval;
1289  interval = value;
1290  }
1291  else if constexpr ( std::is_same_v<Type, type_info::Library> ) {
1292  tag = Library;
1293  library = value;
1294  }
1295  else if constexpr ( std::is_same_v<Type, type_info::Map> ) {
1296  tag = Map;
1297  map = value;
1298  }
1299  else if constexpr ( std::is_same_v<Type, type_info::MapIterator> ) {
1300  tag = MapIterator;
1301  map_iterator = value;
1302  }
1303  else if constexpr ( std::is_same_v<Type, type_info::Network> ) {
1304  tag = Network;
1305  network = value;
1306  }
1307  else if constexpr ( std::is_same_v<Type, type_info::Optional> ) {
1308  tag = Optional;
1309  optional = value;
1310  }
1311  else if constexpr ( std::is_same_v<Type, type_info::Port> ) {
1312  tag = Port;
1313  port = value;
1314  }
1315  else if constexpr ( std::is_same_v<Type, type_info::Real> ) {
1316  tag = Real;
1317  real = value;
1318  }
1319  else if constexpr ( std::is_same_v<Type, type_info::RegExp> ) {
1320  tag = RegExp;
1321  regexp = value;
1322  }
1323  else if constexpr ( std::is_same_v<Type, type_info::Result> ) {
1324  tag = Result;
1325  result = value;
1326  }
1327  else if constexpr ( std::is_same_v<Type, type_info::Set> ) {
1328  tag = Set;
1329  set = value;
1330  }
1331  else if constexpr ( std::is_same_v<Type, type_info::SetIterator> ) {
1332  tag = SetIterator;
1333  set_iterator = value;
1334  }
1335  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int8_t>> ) {
1336  tag = SignedInteger_int8;
1337  signed_integer_int8 = value;
1338  }
1339  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int16_t>> ) {
1340  tag = SignedInteger_int16;
1341  signed_integer_int16 = value;
1342  }
1343  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int32_t>> ) {
1344  tag = SignedInteger_int32;
1345  signed_integer_int32 = value;
1346  }
1347  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int64_t>> ) {
1348  tag = SignedInteger_int64;
1349  signed_integer_int64 = value;
1350  }
1351  else if constexpr ( std::is_same_v<Type, type_info::Stream> ) {
1352  tag = Stream;
1353  stream = value;
1354  }
1355  else if constexpr ( std::is_same_v<Type, type_info::StreamIterator> ) {
1356  tag = StreamIterator;
1357  stream_iterator = value;
1358  }
1359  else if constexpr ( std::is_same_v<Type, type_info::StreamView> ) {
1360  tag = StreamView;
1361  stream_view = value;
1362  }
1363  else if constexpr ( std::is_same_v<Type, type_info::String> ) {
1364  tag = String;
1365  string = value;
1366  }
1367  else if constexpr ( std::is_same_v<Type, type_info::StrongReference> ) {
1368  tag = StrongReference;
1369  strong_reference = value;
1370  }
1371  else if constexpr ( std::is_same_v<Type, type_info::Struct> ) {
1372  tag = Struct;
1373  struct_ = value;
1374  }
1375  else if constexpr ( std::is_same_v<Type, type_info::Time> ) {
1376  tag = Time;
1377  time = value;
1378  }
1379  else if constexpr ( std::is_same_v<Type, type_info::Tuple> ) {
1380  tag = Tuple;
1381  tuple = value;
1382  }
1383  else if constexpr ( std::is_same_v<Type, type_info::Union> ) {
1384  tag = Union;
1385  union_ = value;
1386  }
1387  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint8_t>> ) {
1388  tag = UnsignedInteger_uint8;
1389  unsigned_integer_uint8 = value;
1390  }
1391  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint16_t>> ) {
1392  tag = UnsignedInteger_uint16;
1393  unsigned_integer_uint16 = value;
1394  }
1395  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint32_t>> ) {
1396  tag = UnsignedInteger_uint32;
1397  unsigned_integer_uint32 = value;
1398  }
1399  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint64_t>> ) {
1400  tag = UnsignedInteger_uint64;
1401  unsigned_integer_uint64 = value;
1402  }
1403  else if constexpr ( std::is_same_v<Type, type_info::ValueReference> ) {
1404  tag = ValueReference;
1405  value_reference = value;
1406  }
1407  else if constexpr ( std::is_same_v<Type, type_info::Vector> ) {
1408  tag = Vector;
1409  vector = value;
1410  }
1411  else if constexpr ( std::is_same_v<Type, type_info::VectorIterator> ) {
1412  tag = VectorIterator;
1413  vector_iterator = value;
1414  }
1415  else if constexpr ( std::is_same_v<Type, type_info::Void> ) {
1416  tag = Void;
1417  void_ = value;
1418  }
1419  else if constexpr ( std::is_same_v<Type, type_info::WeakReference> ) {
1420  tag = WeakReference;
1421  weak_reference = value;
1422  }
1423  else {
1424  throw RuntimeError("unhandled type");
1425  }
1426  }
1427 };
1428 
1429 namespace type_info {
1430 
1431 namespace value {
1441 template<typename Type>
1442 const Type* auxType(const type_info::Value& v) {
1443  const auto& type = v.type();
1444 
1445  if constexpr ( std::is_same_v<Type, type_info::Address> ) {
1446  assert(type.tag == TypeInfo::Address);
1447  return type.address;
1448  }
1449  else if constexpr ( std::is_same_v<Type, type_info::Any> ) {
1450  assert(type.tag == TypeInfo::Any);
1451  return type.any;
1452  }
1453  else if constexpr ( std::is_same_v<Type, type_info::Bool> ) {
1454  assert(type.tag == TypeInfo::Bool);
1455  return type.bool_;
1456  }
1457  else if constexpr ( std::is_same_v<Type, type_info::Bytes> ) {
1458  assert(type.tag == TypeInfo::Bytes);
1459  return type.bytes;
1460  }
1461  else if constexpr ( std::is_same_v<Type, type_info::BytesIterator> ) {
1462  assert(type.tag == TypeInfo::BytesIterator);
1463  return type.bytes_iterator;
1464  }
1465  else if constexpr ( std::is_same_v<Type, type_info::Enum> ) {
1466  assert(type.tag == TypeInfo::Enum);
1467  return type.enum_;
1468  }
1469  else if constexpr ( std::is_same_v<Type, type_info::Error> ) {
1470  assert(type.tag == TypeInfo::Error);
1471  return type.error;
1472  }
1473  else if constexpr ( std::is_same_v<Type, type_info::Exception> ) {
1474  assert(type.tag == TypeInfo::Exception);
1475  return type.exception;
1476  }
1477  else if constexpr ( std::is_same_v<Type, type_info::Function> ) {
1478  assert(type.tag == TypeInfo::Function);
1479  return type.function;
1480  }
1481  else if constexpr ( std::is_same_v<Type, type_info::Interval> ) {
1482  assert(type.tag == TypeInfo::Interval);
1483  return type.interval;
1484  }
1485  else if constexpr ( std::is_same_v<Type, type_info::Library> ) {
1486  assert(type.tag == TypeInfo::Library);
1487  return type.library;
1488  }
1489  else if constexpr ( std::is_same_v<Type, type_info::Map> ) {
1490  assert(type.tag == TypeInfo::Map);
1491  return type.map;
1492  }
1493  else if constexpr ( std::is_same_v<Type, type_info::MapIterator> ) {
1494  assert(type.tag == TypeInfo::MapIterator);
1495  return type.map_iterator;
1496  }
1497  else if constexpr ( std::is_same_v<Type, type_info::Network> ) {
1498  assert(type.tag == TypeInfo::Network);
1499  return type.network;
1500  }
1501  else if constexpr ( std::is_same_v<Type, type_info::Optional> ) {
1502  assert(type.tag == TypeInfo::Optional);
1503  return type.optional;
1504  }
1505  else if constexpr ( std::is_same_v<Type, type_info::Port> ) {
1506  assert(type.tag == TypeInfo::Port);
1507  return type.port;
1508  }
1509  else if constexpr ( std::is_same_v<Type, type_info::Real> ) {
1510  assert(type.tag == TypeInfo::Real);
1511  return type.real;
1512  }
1513  else if constexpr ( std::is_same_v<Type, type_info::RegExp> ) {
1514  assert(type.tag == TypeInfo::RegExp);
1515  return type.regexp;
1516  }
1517  else if constexpr ( std::is_same_v<Type, type_info::Result> ) {
1518  assert(type.tag == TypeInfo::Result);
1519  return type.result;
1520  }
1521  else if constexpr ( std::is_same_v<Type, type_info::Set> ) {
1522  assert(type.tag == TypeInfo::Set);
1523  return type.set;
1524  }
1525  else if constexpr ( std::is_same_v<Type, type_info::SetIterator> ) {
1526  assert(type.tag == TypeInfo::SetIterator);
1527  return type.set_iterator;
1528  }
1529  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int8_t>> ) {
1530  assert(type.tag == TypeInfo::SignedInteger_int8);
1531  return type.signed_integer_int8;
1532  }
1533  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int16_t>> ) {
1534  assert(type.tag == TypeInfo::SignedInteger_int16);
1535  return type.signed_integer_int16;
1536  }
1537  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int32_t>> ) {
1538  assert(type.tag == TypeInfo::SignedInteger_int32);
1539  return type.signed_integer_int32;
1540  }
1541  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int64_t>> ) {
1542  assert(type.tag == TypeInfo::SignedInteger_int64);
1543  return type.signed_integer_int64;
1544  }
1545  else if constexpr ( std::is_same_v<Type, type_info::Stream> ) {
1546  assert(type.tag == TypeInfo::Stream);
1547  return type.stream;
1548  }
1549  else if constexpr ( std::is_same_v<Type, type_info::StreamIterator> ) {
1550  assert(type.tag == TypeInfo::StreamIterator);
1551  return type.stream_iterator;
1552  }
1553  else if constexpr ( std::is_same_v<Type, type_info::StreamView> ) {
1554  assert(type.tag == TypeInfo::StreamView);
1555  return type.stream_view;
1556  }
1557  else if constexpr ( std::is_same_v<Type, type_info::String> ) {
1558  assert(type.tag == TypeInfo::String);
1559  return type.string;
1560  }
1561  else if constexpr ( std::is_same_v<Type, type_info::StrongReference> ) {
1562  assert(type.tag == TypeInfo::StrongReference);
1563  return type.strong_reference;
1564  }
1565  else if constexpr ( std::is_same_v<Type, type_info::Struct> ) {
1566  assert(type.tag == TypeInfo::Struct);
1567  return type.struct_;
1568  }
1569  else if constexpr ( std::is_same_v<Type, type_info::Time> ) {
1570  assert(type.tag == TypeInfo::Time);
1571  return type.time;
1572  }
1573  else if constexpr ( std::is_same_v<Type, type_info::Tuple> ) {
1574  assert(type.tag == TypeInfo::Tuple);
1575  return type.tuple;
1576  }
1577  else if constexpr ( std::is_same_v<Type, type_info::Union> ) {
1578  assert(type.tag == TypeInfo::Union);
1579  return type.union_;
1580  }
1581  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint8_t>> ) {
1582  assert(type.tag == TypeInfo::UnsignedInteger_uint8);
1583  return type.unsigned_integer_uint8;
1584  }
1585  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint16_t>> ) {
1586  assert(type.tag == TypeInfo::UnsignedInteger_uint16);
1587  return type.unsigned_integer_uint16;
1588  }
1589  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint32_t>> ) {
1590  assert(type.tag == TypeInfo::UnsignedInteger_uint32);
1591  return type.unsigned_integer_uint32;
1592  }
1593  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint64_t>> ) {
1594  assert(type.tag == TypeInfo::UnsignedInteger_uint64);
1595  return type.unsigned_integer_uint64;
1596  }
1597  else if constexpr ( std::is_same_v<Type, type_info::ValueReference> ) {
1598  assert(type.tag == TypeInfo::ValueReference);
1599  return type.value_reference;
1600  }
1601  else if constexpr ( std::is_same_v<Type, type_info::Vector> ) {
1602  assert(type.tag == TypeInfo::Vector);
1603  return type.vector;
1604  }
1605  else if constexpr ( std::is_same_v<Type, type_info::VectorIterator> ) {
1606  assert(type.tag == TypeInfo::VectorIterator);
1607  return type.vector_iterator;
1608  }
1609  else if constexpr ( std::is_same_v<Type, type_info::Void> ) {
1610  assert(type.tag == TypeInfo::Void);
1611  return type.void_;
1612  }
1613  else if constexpr ( std::is_same_v<Type, type_info::WeakReference> ) {
1614  assert(type.tag == TypeInfo::WeakReference);
1615  return type.weak_reference;
1616  }
1617  else {
1618  throw RuntimeError("unhandled type");
1619  }
1620 }
1621 } // namespace value
1622 
1623 
1624 // Forward declare static built-in type information objects.
1625 extern TypeInfo address;
1626 extern TypeInfo any;
1627 extern TypeInfo bool_;
1628 extern TypeInfo bytes_iterator;
1629 extern TypeInfo bytes;
1630 
1631 extern TypeInfo error;
1632 extern TypeInfo int16;
1633 extern TypeInfo int32;
1634 extern TypeInfo int64;
1635 extern TypeInfo int8;
1636 extern TypeInfo interval;
1637 extern TypeInfo library;
1638 extern TypeInfo network;
1639 extern TypeInfo port;
1640 extern TypeInfo real;
1641 extern TypeInfo regexp;
1642 extern TypeInfo stream_iterator;
1643 extern TypeInfo stream_view;
1644 extern TypeInfo stream;
1645 extern TypeInfo string;
1646 
1647 extern TypeInfo time;
1648 extern TypeInfo uint16;
1649 extern TypeInfo uint32;
1650 extern TypeInfo uint64;
1651 extern TypeInfo uint8;
1652 extern TypeInfo void_;
1653 
1654 } // namespace type_info
1655 
1656 } // namespace hilti::rt
Definition: type-info.h:443
MapIterator(const TypeInfo *ktype, const TypeInfo *vtype, Accessor accessor)
Definition: type-info.h:665
Enum(std::vector< enum_::Label > labels)
Definition: type-info.h:416
std::size_t(*)(const Value &v) Accessor
Definition: type-info.h:1016
Definition: network.h:20
Definition: type-info.h:382
Definition: type-info.h:729
Definition: type-info.h:703
Definition: type-info.h:446
Element(const char *name, const TypeInfo *type, std::ptrdiff_t offset)
Definition: type-info.h:944
const TypeInfo * valueType() const
Definition: type-info.h:186
Definition: type-info.h:958
const TypeInfo * type
Definition: type-info.h:1004
Definition: type-info.h:459
Definition: type-info.h:935
const char * display
Definition: type-info.h:1145
Definition: reference.h:663
bool operator!=(const Iterator &other) const
Definition: type-info.h:243
Definition: reference.h:497
Definition: type-info.h:720
Struct(std::vector< struct_::Field > fields)
Definition: type-info.h:888
Definition: type-info.h:994
Definition: type-info.h:1119
Iterator end() const
Definition: type-info.h:269
const TypeInfo * keyType() const
Definition: type-info.h:680
Definition: port.h:22
Definition: type-info.h:745
Sequence(const Map *type, Value v)
Definition: type-info.h:531
Definition: type-info.h:928
auto iterate(const Value &v, bool include_internal=false) const
Definition: type-info.h:912
Value value(const Value &v) const
Definition: type-info.h:1034
const TypeInfo * keyType() const
Definition: type-info.h:573
Definition: interval.h:22
std::pair< const void *, const void * >(*)(const Value &v) Accessor
Definition: type-info.h:656
Definition: any.h:7
Definition: type-info.h:796
Definition: vector.h:167
const TypeInfo & type() const
Definition: type-info.h:128
std::optional< const char * > id
Definition: type-info.h:1144
Definition: optional.h:79
Value operator*() const
Definition: type-info.h:353
Definition: regexp.h:125
Union(std::vector< union_::Field > fields, Accessor accessor)
Definition: type-info.h:1025
Iterator begin() const
Definition: type-info.h:534
const TypeInfo * type
Definition: type-info.h:947
Definition: type-info.h:523
Definition: type-info.h:650
Value(const void *ptr, const TypeInfo *ti, const value::Parent &parent)
Definition: type-info.h:91
Definition: bytes.h:157
Definition: set.h:108
Definition: type-info.h:43
map::Sequence iterate(const Value &value) const
Definition: type-info.h:567
Tuple(std::vector< tuple::Element > elements)
Definition: type-info.h:965
const auto & labels() const
Definition: type-info.h:419
const TypeInfo * valueType() const
Definition: type-info.h:578
const void *(*)(const Value &v) Accessor
Definition: type-info.h:831
Definition: function.h:44
Label(std::string name, int64_t value)
Definition: type-info.h:400
Parent()
Definition: type-info.h:50
Definition: type-info.h:1069
const std::string name
Definition: type-info.h:402
Definition: type-info.h:1010
Definition: type-info.h:456
Field(const char *name, const TypeInfo *type, std::ptrdiff_t offset, bool internal, Accessor accessor=accessor_default)
Definition: type-info.h:841
Definition: type-info.h:726
Definition: type-info.h:802
std::pair< Value, Value > operator*() const
Definition: type-info.h:639
Iterator & operator++()
Definition: type-info.h:623
static const void * accessor_default(const Value &v)
Definition: type-info.h:846
Definition: type-info.h:385
bool hasValue() const
Definition: result.h:152
Iterator()
Definition: type-info.h:480
const std::string name
Definition: type-info.h:946
std::tuple< std::optional< hilti::rt::any >(*)(const Value &), std::optional< hilti::rt::any >(*)(const hilti::rt::any &), const void *(*)(const hilti::rt::any &)> Accessor
Definition: type-info.h:303
Definition: type-info.h:779
Definition: type-info.h:723
Definition: type.h:160
Definition: map.h:32
Definition: reference.h:345
auto fields(bool include_internal=false) const
Definition: type-info.h:896
Definition: type-info.h:393
Definition: library.h:59
DereferenceableType(const TypeInfo *vtype, Accessor accessor)
Definition: type-info.h:176
Definition: map.h:37
Definition: stream.h:1408
Definition: type-info.h:1056
iterable_type::Sequence iterate(const Value &value) const
Definition: type-info.h:315
Definition: type-info.h:82
bool operator==(const Iterator &other) const
Definition: type-info.h:237
const auto & fields() const
Definition: type-info.h:1028
static Accessor accessor_optional()
Definition: type-info.h:850
Iterator & operator++()
Definition: type-info.h:337
Definition: type-info.h:793
Definition: reference.h:47
Definition: type-info.h:379
Definition: union.h:62
Definition: type-info.h:1103
Map(const TypeInfo *ktype, const TypeInfo *vtype, Accessor accessor)
Definition: type-info.h:563
Parent(const StrongReference< T > &value)
Definition: type-info.h:47
std::tuple< std::optional< hilti::rt::any >(*)(const Value &), std::optional< hilti::rt::any >(*)(const hilti::rt::any &), std::pair< const void *, const void * >(*)(const hilti::rt::any &)> Accessor
Definition: type-info.h:553
IterableType(const TypeInfo *etype, Accessor accessor)
Definition: type-info.h:312
Definition: set.h:33
Definition: type-info.h:466
Definition: vector.h:256
Definition: type-info.h:409
Definition: type-info.h:1053
Definition: address.h:25
Definition: vector.h:89
Sequence(const IterableType *type, Value v)
Definition: type-info.h:263
Definition: type-info.h:376
Value(const void *ptr, const TypeInfo *ti, const Value &parent)
Definition: type-info.h:103
const TypeInfo * valueType() const
Definition: type-info.h:685
Definition: exception.h:22
const std::string name
Definition: type-info.h:1003
const void *(*)(const Value &v) Accessor
Definition: type-info.h:168
bool operator==(const Iterator &other) const
Definition: type-info.h:505
Definition: type-info.h:388
Definition: time.h:20
Definition: type-info.h:545
Iterator begin() const
Definition: type-info.h:266
Iterator end() const
Definition: type-info.h:537
Definition: type-info.h:826
bool operator!=(const Iterator &other) const
Definition: type-info.h:511
auto iterate(const Value &v) const
Definition: type-info.h:978
Field(const char *name, const TypeInfo *type)
Definition: type-info.h:1001
Definition: type-info.h:799
const int64_t value
Definition: type-info.h:403
Definition: type-info.h:706
Definition: type-info.h:881
Definition: type-info.h:1143
Definition: type-info.h:453
Definition: type-info.h:152
const void * pointer() const
Definition: type-info.h:119
Definition: type-info.h:808
Value value(const Value &v) const
Definition: type-info.h:181
std::pair< Value, Value > value(const Value &v) const
Definition: type-info.h:671
Definition: result.h:67
const TypeInfo * dereferencedType() const
Definition: type-info.h:321
std::string fmt(const char *fmt, const Args &... args)
Definition: fmt.h:13
const std::string name
Definition: type-info.h:864
Definition: type-info.h:1116
void tie(hilti::rt::StrongReferenceGeneric value)
Definition: type-info.h:53
const auto & elements() const
Definition: type-info.h:968
Definition: type-info.h:805
Definition: bool.h:11