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  const 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 {
316  return iterable_type::Sequence(this, std::move(value));
317  }
318 
323  const TypeInfo* dereferencedType() const { return _etype; }
324 
325 private:
326  friend class iterable_type::Iterator;
327 
328  const TypeInfo* _etype;
329  const Accessor _accessor;
330 };
331 
332 namespace iterable_type {
333 
334 inline Iterator::Iterator(const IterableType* type, Value v) : _type(type) {
335  _value = std::move(v);
336  _cur = std::get<0>(_type->_accessor)(_value); // begin()
337 }
338 
340  if ( _cur.has_value() )
341  _cur = std::get<1>(_type->_accessor)(*_cur); // next()
342 
343  return *this;
344 }
345 
346 inline const Iterator Iterator::operator++(int) {
347  auto x = *this;
348 
349  if ( _cur.has_value() )
350  _cur = std::get<1>(_type->_accessor)(*_cur); // next()
351 
352  return x;
353 }
354 
355 inline Value Iterator::operator*() const {
356  if ( ! _cur.has_value() )
357  throw InvalidValue("type info iterator invalid");
358 
359  return Value(std::get<2>(_type->_accessor)(*_cur), _type->_etype, _value); // deref()
360 }
361 
362 } // namespace iterable_type
363 
365 class ValueLessType {};
366 
372 
373 } // namespace detail
374 
376 
378 class Address : public detail::AtomicType<hilti::rt::Address> {};
379 
381 class Any : public detail::ValueLessType {};
382 
384 class Bool : public detail::AtomicType<bool> {};
385 
387 class Bytes : public detail::AtomicType<hilti::rt::Bytes> {};
388 
390 class BytesIterator : public detail::AtomicType<hilti::rt::bytes::Iterator> {};
391 
392 namespace enum_ {
393 
395 struct Label {
402  Label(std::string name, int64_t value) : name(std::move(name)), value(value) {}
403 
404  const std::string name;
405  const int64_t value;
406 };
407 
408 } // namespace enum_
409 
411 class Enum {
412 public:
418  Enum(std::vector<enum_::Label> labels) : _labels(std::move(labels)) {}
419 
421  const auto& labels() const { return _labels; }
422 
428  enum_::Label get(const Value& v) const {
429  auto n = *static_cast<const int64_t*>(v.pointer());
430 
431  for ( const auto& l : _labels ) {
432  if ( n == l.value )
433  return l;
434  }
435 
436  return enum_::Label(fmt("<unknown-%" PRId64 ">", n), n);
437  }
438 
439 private:
440  const std::vector<enum_::Label> _labels;
441 };
442 
443 
445 class Error : public detail::AtomicType<hilti::rt::result::Error> {};
446 
448 class Exception : public detail::AtomicType<hilti::rt::Exception> {};
449 
456 
458 class Interval : public detail::AtomicType<hilti::rt::Interval> {};
459 
461 class Library : public detail::ValueLessType {};
462 
463 class Map;
464 
465 namespace map {
466 
468 class Iterator {
469 public:
476  Iterator(const Map* type, Value v);
477 
482  Iterator() {}
483 
485  Iterator& operator++();
486 
488  const Iterator operator++(int);
489 
496  std::pair<Value, Value> operator*() const;
497 
507  bool operator==(const Iterator& other) const {
508  // This is good enough just for comparing against end().
509  return _cur.has_value() == other._cur.has_value();
510  }
511 
513  bool operator!=(const Iterator& other) const { return ! (*this == other); }
514 
515 private:
516  const Map* _type = nullptr;
517  Value _value;
518  std::optional<hilti::rt::any> _cur;
519 };
520 
525 class Sequence {
526 public:
533  Sequence(const Map* type, Value v) : _begin(type, std::move(v)) {}
534 
536  Iterator begin() const { return _begin; }
537 
539  Iterator end() const { return Iterator(); }
540 
541 private:
542  Iterator _begin;
543 };
544 } // namespace map
545 
547 class Map {
548 public:
553  using Accessor = std::tuple<std::optional<hilti::rt::any> (*)(const Value&), // begin()
554  std::optional<hilti::rt::any> (*)(const hilti::rt::any&), // next()
555  std::pair<const void*, const void*> (*)(const hilti::rt::any&)>; // deref()
556 
565  Map(const TypeInfo* ktype, const TypeInfo* vtype, Accessor accessor)
566  : _ktype(ktype), _vtype(vtype), _accessor(std::move(accessor)) {}
567 
569  map::Sequence iterate(const Value& value) const { return map::Sequence(this, std::move(value)); }
570 
575  const TypeInfo* keyType() const { return _ktype; }
576 
580  const TypeInfo* valueType() const { return _vtype; }
581 
582  template<typename K, typename V>
583  using iterator_pair =
584  std::pair<typename hilti::rt::Map<K, V>::const_iterator, typename hilti::rt::Map<K, V>::const_iterator>;
585 
586  template<typename K, typename V>
587  static Accessor accessor() {
588  return std::make_tuple(
589  [](const Value& v_) -> std::optional<hilti::rt::any> { // begin()
590  auto v = static_cast<const hilti::rt::Map<K, V>*>(v_.pointer());
591  if ( v->cbegin() != v->cend() )
592  return std::make_pair(v->cbegin(), v->cend());
593  else
594  return std::nullopt;
595  },
596  [](const hilti::rt::any& i_) -> std::optional<hilti::rt::any> { // next()
597  auto i = hilti::rt::any_cast<iterator_pair<K, V>>(i_);
598  auto n = std::make_pair(++i.first, i.second);
599  if ( n.first != n.second )
600  return std::move(n);
601  else
602  return std::nullopt;
603  },
604  [](const hilti::rt::any& i_) -> std::pair<const void*, const void*> { // deref()
605  auto i = hilti::rt::any_cast<iterator_pair<K, V>>(i_);
606  return std::make_pair(&(*i.first).first, &(*i.first).second);
607  });
608  }
609 
610 private:
611  friend class map::Iterator;
612 
613  const TypeInfo* _ktype;
614  const TypeInfo* _vtype;
615  Accessor _accessor;
616 };
617 
618 namespace map {
619 
620 inline Iterator::Iterator(const Map* type, Value v) : _type(type) {
621  _value = std::move(v);
622  _cur = std::get<0>(_type->_accessor)(_value); // begin()
623 }
624 
626  if ( _cur.has_value() )
627  _cur = std::get<1>(_type->_accessor)(*_cur); // next()
628 
629  return *this;
630 }
631 
632 inline const Iterator Iterator::operator++(int) {
633  auto x = *this;
634 
635  if ( _cur.has_value() )
636  _cur = std::get<1>(_type->_accessor)(*_cur); // next()
637 
638  return x;
639 }
640 
641 inline std::pair<Value, Value> Iterator::operator*() const {
642  if ( ! _cur.has_value() )
643  throw InvalidValue("type info iterator invalid");
644 
645  auto x = std::get<2>(_type->_accessor)(*_cur);
646  return std::make_pair(Value(x.first, _type->_ktype, _value), Value(x.second, _type->_vtype, _value));
647 }
648 
649 } // namespace map
650 
652 class MapIterator {
653 public:
658  using Accessor = std::pair<const void*, const void*> (*)(const Value& v);
659 
667  MapIterator(const TypeInfo* ktype, const TypeInfo* vtype, Accessor accessor)
668  : _ktype(ktype), _vtype(vtype), _accessor(accessor) {}
669 
673  std::pair<Value, Value> value(const Value& v) const {
674  auto x = _accessor(v);
675  return std::make_pair(Value(x.first, _ktype, v), Value(x.second, _vtype, v));
676  }
677 
682  const TypeInfo* keyType() const { return _ktype; }
683 
687  const TypeInfo* valueType() const { return _vtype; }
688 
689  template<typename K, typename V>
690  static auto accessor() { // deref()
691  return [](const Value& v) -> std::pair<const void*, const void*> {
692  using iterator_type = const hilti::rt::map::Iterator<K, V>;
693  const auto& x = **static_cast<iterator_type*>(v.pointer());
694  return std::make_pair(&x.first, &x.second);
695  };
696  }
697 
698 private:
699  const TypeInfo* _ktype;
700  const TypeInfo* _vtype;
701  const Accessor _accessor;
702 };
703 
705 class Network : public detail::AtomicType<hilti::rt::Network> {};
706 
709 public:
711 
712  template<typename T>
713  static auto accessor() { // deref()
714  return [](const Value& v) -> const void* {
715  auto x = static_cast<const std::optional<T>*>(v.pointer());
716  return x->has_value() ? &*x : nullptr;
717  };
718  }
719 };
720 
722 class Port : public detail::AtomicType<hilti::rt::Port> {};
723 
725 class Real : public detail::AtomicType<double> {};
726 
728 class RegExp : public detail::AtomicType<hilti::rt::RegExp> {};
729 
732 public:
734 
735  template<typename T>
736  static auto accessor() { // deref()
737  return [](const Value& v) -> const void* {
738  auto x = static_cast<const hilti::rt::Result<T>*>(v.pointer());
739  return x->hasValue() ? &*x : nullptr;
740  };
741  }
742 
743  // TODO: Cannot get to the error currently.
744 };
745 
747 class Set : public detail::IterableType {
748 public:
750 
751  template<typename T>
752  using iterator_pair =
753  std::pair<typename hilti::rt::Set<T>::const_iterator, typename hilti::rt::Set<T>::const_iterator>;
754 
755  template<typename T>
756  static Accessor accessor() {
757  return std::make_tuple(
758  [](const Value& v_) -> std::optional<hilti::rt::any> {
759  auto v = static_cast<const hilti::rt::Set<T>*>(v_.pointer());
760  if ( v->begin() != v->end() )
761  return std::make_pair(v->begin(), v->end());
762  else
763  return std::nullopt;
764  },
765  [](const hilti::rt::any& i_) -> std::optional<hilti::rt::any> {
766  auto i = hilti::rt::any_cast<iterator_pair<T>>(i_);
767  auto n = std::make_pair(++i.first, i.second);
768  if ( n.first != n.second )
769  return std::move(n);
770  else
771  return std::nullopt;
772  },
773  [](const hilti::rt::any& i_) -> const void* {
774  auto i = hilti::rt::any_cast<iterator_pair<T>>(i_);
775  return &*i.first;
776  });
777  }
778 };
779 
782 public:
784 
785  template<typename T>
786  static auto accessor() { // deref()
787  return [](const Value& v) -> const void* {
788  return &**static_cast<const hilti::rt::set::Iterator<T>*>(v.pointer());
789  };
790  }
791 };
792 
794 template<typename Width>
795 class SignedInteger : public detail::AtomicType<Width> {};
796 
798 class Stream : public detail::AtomicType<hilti::rt::Stream> {};
799 
801 class StreamIterator : public detail::AtomicType<hilti::rt::stream::SafeConstIterator> {};
802 
804 class StreamView : public detail::AtomicType<hilti::rt::stream::View> {};
805 
807 class String : public detail::AtomicType<std::string> {};
808 
811 public:
813 
814  template<typename T>
815  static auto accessor() { // deref()
816  return [](const Value& v) -> const void* {
817  return static_cast<const hilti::rt::StrongReference<T>*>(v.pointer())->get();
818  };
819  }
820 };
821 
822 
823 class Struct;
824 
825 namespace struct_ {
826 
828 struct Field {
833  using Accessor = const void* (*)(const Value& v);
834 
843  Field(const char* name, const TypeInfo* type, std::ptrdiff_t offset, bool internal,
844  Accessor accessor = accessor_default)
845  : name(name), type(type), offset(offset), accessor(std::move(accessor)), internal(internal) {}
846 
848  static const void* accessor_default(const Value& v) { return v.pointer(); }
849 
851  template<typename T>
853  return [](const Value& v) -> const void* {
854  auto x = static_cast<const std::optional<T>*>(v.pointer());
855  if ( x->has_value() ) {
856  auto& o = *x;
857  return &*o;
858  }
859  else
860  return nullptr;
861  };
862  }
863 
864  bool isInternal() const { return internal; }
865 
866  const std::string name;
867  const TypeInfo* type ;
868 
869 private:
870  friend class type_info::Struct;
871 
872  // Internal wrapper around accessor that's used from ``Struct``.
873  Value value(const Value& v) const { return Value(accessor(v), type, v); }
874 
875  const std::ptrdiff_t offset;
876  const Accessor accessor;
877  const bool internal;
878 };
879 
880 }; // namespace struct_
881 
883 class Struct {
884 public:
890  Struct(std::vector<struct_::Field> fields) : _fields(std::move(fields)) {}
891 
898  auto fields(bool include_internal = false) const {
899  std::vector<std::reference_wrapper<const struct_::Field>> fields;
900  std::copy_if(_fields.begin(), _fields.end(), std::back_inserter(fields),
901  [=](const struct_::Field& f) { return include_internal || ! f.isInternal(); });
902  return fields;
903  }
904 
914  auto iterate(const Value& v, bool include_internal = false) const {
915  std::vector<std::pair<const struct_::Field&, Value>> values;
916 
917  for ( const auto& f : fields(include_internal) ) {
918  auto x = Value(static_cast<const char*>(v.pointer()) + f.get().offset, f.get().type, v);
919  values.emplace_back(f.get(), f.get().value(x));
920  }
921 
922  return values;
923  }
924 
925 private:
926  const std::vector<struct_::Field> _fields;
927 };
928 
930 class Time : public detail::AtomicType<hilti::rt::Time> {};
931 
932 class Tuple;
933 
934 namespace tuple {
935 
937 class Element {
938 public:
946  Element(const char* name, const TypeInfo* type, std::ptrdiff_t offset) : name(name), type(type), offset(offset) {}
947 
948  const std::string name;
949  const TypeInfo* type;
951 private:
952  friend class type_info::Tuple;
953 
954  const std::ptrdiff_t offset;
955 };
956 
957 }; // namespace tuple
958 
960 class Tuple {
961 public:
967  Tuple(std::vector<tuple::Element> elements) : _elements(std::move(elements)) {}
968 
970  const auto& elements() const { return _elements; }
971 
980  auto iterate(const Value& v) const {
981  std::vector<std::pair<const tuple::Element&, Value>> values;
982 
983  for ( const auto& f : _elements )
984  values.emplace_back(f, Value(static_cast<const char*>(v.pointer()) + f.offset, f.type, v));
985 
986  return values;
987  }
988 
989 private:
990  const std::vector<tuple::Element> _elements;
991 };
992 
993 namespace union_ {
994 
996 struct Field {
1003  Field(const char* name, const TypeInfo* type) : name(name), type(type) {}
1004 
1005  const std::string name;
1006  const TypeInfo* type;
1007 };
1008 
1009 }; // namespace union_
1010 
1012 class Union {
1013 public:
1018  using Accessor = std::size_t (*)(const Value& v);
1019  const size_t npos = std::variant_npos;
1020 
1027  Union(std::vector<union_::Field> fields, Accessor accessor)
1028  : _fields(std::move(fields)), _accessor(std::move(accessor)) {}
1029 
1031  const auto& fields() const { return _fields; }
1032 
1037  Value value(const Value& v) const {
1038  if ( auto idx = _accessor(v); idx > 0 )
1039  return Value(v.pointer(), _fields[idx - 1].type, v);
1040  else
1041  return Value();
1042  }
1043 
1044  template<typename T>
1045  static auto accessor() {
1046  return [](const Value& v) -> std::size_t { return static_cast<const T*>(v.pointer())->index(); };
1047  }
1048 
1049 private:
1050  const std::vector<union_::Field> _fields;
1051  const Accessor _accessor;
1052 };
1053 
1055 template<typename Width>
1056 class UnsignedInteger : public detail::AtomicType<Width> {};
1057 
1060 public:
1062 
1063  template<typename T>
1064  static auto accessor() { // deref()
1065  return [](const Value& v) -> const void* {
1066  return static_cast<const hilti::rt::ValueReference<T>*>(v.pointer())->get();
1067  };
1068  }
1069 };
1070 
1073 public:
1075 
1076  template<typename T, typename Allocator>
1077  using iterator_pair = std::pair<typename hilti::rt::Vector<T, Allocator>::const_iterator,
1079 
1080  template<typename T, typename Allocator = std::allocator<T>>
1081  static Accessor accessor() {
1082  return std::make_tuple(
1083  [](const Value& v_) -> std::optional<hilti::rt::any> { // begin()
1084  auto v = static_cast<const hilti::rt::Vector<T, Allocator>*>(v_.pointer());
1085  if ( v->begin() != v->end() )
1086  return std::make_pair(v->begin(), v->end());
1087  else
1088  return std::nullopt;
1089  },
1090  [](const hilti::rt::any& i_) -> std::optional<hilti::rt::any> { // next()
1091  auto i = hilti::rt::any_cast<iterator_pair<T, Allocator>>(i_);
1092  auto n = std::make_pair(++i.first, i.second);
1093  if ( n.first != n.second )
1094  return std::move(n);
1095  else
1096  return std::nullopt;
1097  },
1098  [](const hilti::rt::any& i_) -> const void* { // deref()
1099  auto i = hilti::rt::any_cast<iterator_pair<T, Allocator>>(i_);
1100  return &*i.first;
1101  });
1102  }
1103 };
1104 
1107 public:
1109 
1110  template<typename T, typename Allocator = std::allocator<T>>
1111  static auto accessor() { // deref()
1112  return [](const Value& v) -> const void* {
1113  return &**static_cast<const hilti::rt::vector::Iterator<T, Allocator>*>(v.pointer());
1114  };
1115  }
1116 };
1117 
1119 class Void : public detail::ValueLessType {};
1120 
1123 public:
1125 
1126  template<typename T>
1127  static auto accessor() { // deref()
1128  return [](const Value& v) -> const void* {
1129  return static_cast<const hilti::rt::WeakReference<T>*>(v.pointer())->get();
1130  };
1131  }
1132 };
1133 
1134 } // namespace type_info
1135 
1136 } // namespace hilti::rt
1137 
1138 namespace hilti::rt {
1139 
1146 struct TypeInfo {
1147  std::optional<const char*> id;
1148  const char* display;
1150  enum Tag {
1151  Undefined,
1152  Address,
1153  Any,
1154  Bool,
1155  Bytes,
1156  BytesIterator,
1157  Enum,
1158  Error,
1159  Exception,
1160  Function,
1161  Interval,
1162  Library,
1163  Map,
1164  MapIterator,
1165  Network,
1166  Optional,
1167  Port,
1168  Real,
1169  RegExp,
1170  Result,
1171  Set,
1172  SetIterator,
1173  SignedInteger_int8,
1174  SignedInteger_int16,
1175  SignedInteger_int32,
1176  SignedInteger_int64,
1177  Stream,
1178  StreamIterator,
1179  StreamView,
1180  String,
1182  Struct,
1183  Time,
1184  Tuple,
1185  Union,
1186  UnsignedInteger_uint8,
1187  UnsignedInteger_uint16,
1188  UnsignedInteger_uint32,
1189  UnsignedInteger_uint64,
1191  Vector,
1192  VectorIterator,
1193  Void,
1195  };
1196 
1197  // Actual storage for the held type.
1198  std::unique_ptr<char, void (*)(char*)> _storage = {nullptr, [](char*) {}};
1199 
1200  Tag tag = Tag::Undefined;
1201  union {
1202  type_info::Address* address;
1203  type_info::Any* any;
1204  type_info::Bool* bool_;
1205  type_info::Bytes* bytes;
1206  type_info::BytesIterator* bytes_iterator;
1207  type_info::Enum* enum_;
1208  type_info::Error* error;
1209  type_info::Exception* exception;
1210  type_info::Function* function;
1211  type_info::Interval* interval;
1212  type_info::Library* library;
1213  type_info::Map* map;
1214  type_info::MapIterator* map_iterator;
1215  type_info::Network* network;
1216  type_info::Optional* optional;
1217  type_info::Port* port;
1218  type_info::Real* real;
1219  type_info::RegExp* regexp;
1220  type_info::Result* result;
1221  type_info::Set* set;
1222  type_info::SetIterator* set_iterator;
1223  type_info::SignedInteger<int8_t>* signed_integer_int8;
1224  type_info::SignedInteger<int16_t>* signed_integer_int16;
1225  type_info::SignedInteger<int32_t>* signed_integer_int32;
1226  type_info::SignedInteger<int64_t>* signed_integer_int64;
1227  type_info::Stream* stream;
1228  type_info::StreamIterator* stream_iterator;
1229  type_info::StreamView* stream_view;
1230  type_info::String* string;
1231  type_info::StrongReference* strong_reference;
1232  type_info::Struct* struct_;
1233  type_info::Time* time;
1234  type_info::Tuple* tuple;
1235  type_info::Union* union_;
1236  type_info::UnsignedInteger<uint8_t>* unsigned_integer_uint8;
1237  type_info::UnsignedInteger<uint16_t>* unsigned_integer_uint16;
1238  type_info::UnsignedInteger<uint32_t>* unsigned_integer_uint32;
1239  type_info::UnsignedInteger<uint64_t>* unsigned_integer_uint64;
1240  type_info::ValueReference* value_reference;
1241  type_info::Vector* vector;
1242  type_info::VectorIterator* vector_iterator;
1243  type_info::Void* void_;
1244  type_info::WeakReference* weak_reference;
1245  };
1246 
1247  TypeInfo() = default;
1248 
1249  template<typename Type>
1250  TypeInfo(std::optional<const char*> _id, const char* _display, Type* value)
1251  : id(std::move(_id)),
1252  display(_display),
1253  _storage(reinterpret_cast<char*>(value), [](char* p) { delete reinterpret_cast<Type*>(p); }) {
1254  if constexpr ( std::is_same_v<Type, type_info::Address> ) {
1255  tag = Address;
1256  address = value;
1257  }
1258  else if constexpr ( std::is_same_v<Type, type_info::Any> ) {
1259  tag = Any;
1260  any = value;
1261  }
1262  else if constexpr ( std::is_same_v<Type, type_info::Bool> ) {
1263  tag = Bool;
1264  bool_ = value;
1265  }
1266  else if constexpr ( std::is_same_v<Type, type_info::Bytes> ) {
1267  tag = Bytes;
1268  bytes = value;
1269  }
1270  else if constexpr ( std::is_same_v<Type, type_info::BytesIterator> ) {
1271  tag = BytesIterator;
1272  bytes_iterator = value;
1273  }
1274  else if constexpr ( std::is_same_v<Type, type_info::Enum> ) {
1275  tag = Enum;
1276  enum_ = value;
1277  }
1278  else if constexpr ( std::is_same_v<Type, type_info::Error> ) {
1279  tag = Error;
1280  error = value;
1281  }
1282  else if constexpr ( std::is_same_v<Type, type_info::Exception> ) {
1283  tag = Exception;
1284  exception = value;
1285  }
1286  else if constexpr ( std::is_same_v<Type, type_info::Function> ) {
1287  tag = Function;
1288  function = value;
1289  }
1290  else if constexpr ( std::is_same_v<Type, type_info::Interval> ) {
1291  tag = Interval;
1292  interval = value;
1293  }
1294  else if constexpr ( std::is_same_v<Type, type_info::Library> ) {
1295  tag = Library;
1296  library = value;
1297  }
1298  else if constexpr ( std::is_same_v<Type, type_info::Map> ) {
1299  tag = Map;
1300  map = value;
1301  }
1302  else if constexpr ( std::is_same_v<Type, type_info::MapIterator> ) {
1303  tag = MapIterator;
1304  map_iterator = value;
1305  }
1306  else if constexpr ( std::is_same_v<Type, type_info::Network> ) {
1307  tag = Network;
1308  network = value;
1309  }
1310  else if constexpr ( std::is_same_v<Type, type_info::Optional> ) {
1311  tag = Optional;
1312  optional = value;
1313  }
1314  else if constexpr ( std::is_same_v<Type, type_info::Port> ) {
1315  tag = Port;
1316  port = value;
1317  }
1318  else if constexpr ( std::is_same_v<Type, type_info::Real> ) {
1319  tag = Real;
1320  real = value;
1321  }
1322  else if constexpr ( std::is_same_v<Type, type_info::RegExp> ) {
1323  tag = RegExp;
1324  regexp = value;
1325  }
1326  else if constexpr ( std::is_same_v<Type, type_info::Result> ) {
1327  tag = Result;
1328  result = value;
1329  }
1330  else if constexpr ( std::is_same_v<Type, type_info::Set> ) {
1331  tag = Set;
1332  set = value;
1333  }
1334  else if constexpr ( std::is_same_v<Type, type_info::SetIterator> ) {
1335  tag = SetIterator;
1336  set_iterator = value;
1337  }
1338  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int8_t>> ) {
1339  tag = SignedInteger_int8;
1340  signed_integer_int8 = value;
1341  }
1342  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int16_t>> ) {
1343  tag = SignedInteger_int16;
1344  signed_integer_int16 = value;
1345  }
1346  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int32_t>> ) {
1347  tag = SignedInteger_int32;
1348  signed_integer_int32 = value;
1349  }
1350  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int64_t>> ) {
1351  tag = SignedInteger_int64;
1352  signed_integer_int64 = value;
1353  }
1354  else if constexpr ( std::is_same_v<Type, type_info::Stream> ) {
1355  tag = Stream;
1356  stream = value;
1357  }
1358  else if constexpr ( std::is_same_v<Type, type_info::StreamIterator> ) {
1359  tag = StreamIterator;
1360  stream_iterator = value;
1361  }
1362  else if constexpr ( std::is_same_v<Type, type_info::StreamView> ) {
1363  tag = StreamView;
1364  stream_view = value;
1365  }
1366  else if constexpr ( std::is_same_v<Type, type_info::String> ) {
1367  tag = String;
1368  string = value;
1369  }
1370  else if constexpr ( std::is_same_v<Type, type_info::StrongReference> ) {
1371  tag = StrongReference;
1372  strong_reference = value;
1373  }
1374  else if constexpr ( std::is_same_v<Type, type_info::Struct> ) {
1375  tag = Struct;
1376  struct_ = value;
1377  }
1378  else if constexpr ( std::is_same_v<Type, type_info::Time> ) {
1379  tag = Time;
1380  time = value;
1381  }
1382  else if constexpr ( std::is_same_v<Type, type_info::Tuple> ) {
1383  tag = Tuple;
1384  tuple = value;
1385  }
1386  else if constexpr ( std::is_same_v<Type, type_info::Union> ) {
1387  tag = Union;
1388  union_ = value;
1389  }
1390  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint8_t>> ) {
1391  tag = UnsignedInteger_uint8;
1392  unsigned_integer_uint8 = value;
1393  }
1394  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint16_t>> ) {
1395  tag = UnsignedInteger_uint16;
1396  unsigned_integer_uint16 = value;
1397  }
1398  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint32_t>> ) {
1399  tag = UnsignedInteger_uint32;
1400  unsigned_integer_uint32 = value;
1401  }
1402  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint64_t>> ) {
1403  tag = UnsignedInteger_uint64;
1404  unsigned_integer_uint64 = value;
1405  }
1406  else if constexpr ( std::is_same_v<Type, type_info::ValueReference> ) {
1407  tag = ValueReference;
1408  value_reference = value;
1409  }
1410  else if constexpr ( std::is_same_v<Type, type_info::Vector> ) {
1411  tag = Vector;
1412  vector = value;
1413  }
1414  else if constexpr ( std::is_same_v<Type, type_info::VectorIterator> ) {
1415  tag = VectorIterator;
1416  vector_iterator = value;
1417  }
1418  else if constexpr ( std::is_same_v<Type, type_info::Void> ) {
1419  tag = Void;
1420  void_ = value;
1421  }
1422  else if constexpr ( std::is_same_v<Type, type_info::WeakReference> ) {
1423  tag = WeakReference;
1424  weak_reference = value;
1425  }
1426  else {
1427  throw RuntimeError("unhandled type");
1428  }
1429  }
1430 };
1431 
1432 namespace type_info {
1433 
1434 namespace value {
1444 template<typename Type>
1445 const Type* auxType(const type_info::Value& v) {
1446  const auto& type = v.type();
1447 
1448  if constexpr ( std::is_same_v<Type, type_info::Address> ) {
1449  assert(type.tag == TypeInfo::Address);
1450  return type.address;
1451  }
1452  else if constexpr ( std::is_same_v<Type, type_info::Any> ) {
1453  assert(type.tag == TypeInfo::Any);
1454  return type.any;
1455  }
1456  else if constexpr ( std::is_same_v<Type, type_info::Bool> ) {
1457  assert(type.tag == TypeInfo::Bool);
1458  return type.bool_;
1459  }
1460  else if constexpr ( std::is_same_v<Type, type_info::Bytes> ) {
1461  assert(type.tag == TypeInfo::Bytes);
1462  return type.bytes;
1463  }
1464  else if constexpr ( std::is_same_v<Type, type_info::BytesIterator> ) {
1465  assert(type.tag == TypeInfo::BytesIterator);
1466  return type.bytes_iterator;
1467  }
1468  else if constexpr ( std::is_same_v<Type, type_info::Enum> ) {
1469  assert(type.tag == TypeInfo::Enum);
1470  return type.enum_;
1471  }
1472  else if constexpr ( std::is_same_v<Type, type_info::Error> ) {
1473  assert(type.tag == TypeInfo::Error);
1474  return type.error;
1475  }
1476  else if constexpr ( std::is_same_v<Type, type_info::Exception> ) {
1477  assert(type.tag == TypeInfo::Exception);
1478  return type.exception;
1479  }
1480  else if constexpr ( std::is_same_v<Type, type_info::Function> ) {
1481  assert(type.tag == TypeInfo::Function);
1482  return type.function;
1483  }
1484  else if constexpr ( std::is_same_v<Type, type_info::Interval> ) {
1485  assert(type.tag == TypeInfo::Interval);
1486  return type.interval;
1487  }
1488  else if constexpr ( std::is_same_v<Type, type_info::Library> ) {
1489  assert(type.tag == TypeInfo::Library);
1490  return type.library;
1491  }
1492  else if constexpr ( std::is_same_v<Type, type_info::Map> ) {
1493  assert(type.tag == TypeInfo::Map);
1494  return type.map;
1495  }
1496  else if constexpr ( std::is_same_v<Type, type_info::MapIterator> ) {
1497  assert(type.tag == TypeInfo::MapIterator);
1498  return type.map_iterator;
1499  }
1500  else if constexpr ( std::is_same_v<Type, type_info::Network> ) {
1501  assert(type.tag == TypeInfo::Network);
1502  return type.network;
1503  }
1504  else if constexpr ( std::is_same_v<Type, type_info::Optional> ) {
1505  assert(type.tag == TypeInfo::Optional);
1506  return type.optional;
1507  }
1508  else if constexpr ( std::is_same_v<Type, type_info::Port> ) {
1509  assert(type.tag == TypeInfo::Port);
1510  return type.port;
1511  }
1512  else if constexpr ( std::is_same_v<Type, type_info::Real> ) {
1513  assert(type.tag == TypeInfo::Real);
1514  return type.real;
1515  }
1516  else if constexpr ( std::is_same_v<Type, type_info::RegExp> ) {
1517  assert(type.tag == TypeInfo::RegExp);
1518  return type.regexp;
1519  }
1520  else if constexpr ( std::is_same_v<Type, type_info::Result> ) {
1521  assert(type.tag == TypeInfo::Result);
1522  return type.result;
1523  }
1524  else if constexpr ( std::is_same_v<Type, type_info::Set> ) {
1525  assert(type.tag == TypeInfo::Set);
1526  return type.set;
1527  }
1528  else if constexpr ( std::is_same_v<Type, type_info::SetIterator> ) {
1529  assert(type.tag == TypeInfo::SetIterator);
1530  return type.set_iterator;
1531  }
1532  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int8_t>> ) {
1533  assert(type.tag == TypeInfo::SignedInteger_int8);
1534  return type.signed_integer_int8;
1535  }
1536  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int16_t>> ) {
1537  assert(type.tag == TypeInfo::SignedInteger_int16);
1538  return type.signed_integer_int16;
1539  }
1540  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int32_t>> ) {
1541  assert(type.tag == TypeInfo::SignedInteger_int32);
1542  return type.signed_integer_int32;
1543  }
1544  else if constexpr ( std::is_same_v<Type, type_info::SignedInteger<int64_t>> ) {
1545  assert(type.tag == TypeInfo::SignedInteger_int64);
1546  return type.signed_integer_int64;
1547  }
1548  else if constexpr ( std::is_same_v<Type, type_info::Stream> ) {
1549  assert(type.tag == TypeInfo::Stream);
1550  return type.stream;
1551  }
1552  else if constexpr ( std::is_same_v<Type, type_info::StreamIterator> ) {
1553  assert(type.tag == TypeInfo::StreamIterator);
1554  return type.stream_iterator;
1555  }
1556  else if constexpr ( std::is_same_v<Type, type_info::StreamView> ) {
1557  assert(type.tag == TypeInfo::StreamView);
1558  return type.stream_view;
1559  }
1560  else if constexpr ( std::is_same_v<Type, type_info::String> ) {
1561  assert(type.tag == TypeInfo::String);
1562  return type.string;
1563  }
1564  else if constexpr ( std::is_same_v<Type, type_info::StrongReference> ) {
1565  assert(type.tag == TypeInfo::StrongReference);
1566  return type.strong_reference;
1567  }
1568  else if constexpr ( std::is_same_v<Type, type_info::Struct> ) {
1569  assert(type.tag == TypeInfo::Struct);
1570  return type.struct_;
1571  }
1572  else if constexpr ( std::is_same_v<Type, type_info::Time> ) {
1573  assert(type.tag == TypeInfo::Time);
1574  return type.time;
1575  }
1576  else if constexpr ( std::is_same_v<Type, type_info::Tuple> ) {
1577  assert(type.tag == TypeInfo::Tuple);
1578  return type.tuple;
1579  }
1580  else if constexpr ( std::is_same_v<Type, type_info::Union> ) {
1581  assert(type.tag == TypeInfo::Union);
1582  return type.union_;
1583  }
1584  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint8_t>> ) {
1585  assert(type.tag == TypeInfo::UnsignedInteger_uint8);
1586  return type.unsigned_integer_uint8;
1587  }
1588  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint16_t>> ) {
1589  assert(type.tag == TypeInfo::UnsignedInteger_uint16);
1590  return type.unsigned_integer_uint16;
1591  }
1592  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint32_t>> ) {
1593  assert(type.tag == TypeInfo::UnsignedInteger_uint32);
1594  return type.unsigned_integer_uint32;
1595  }
1596  else if constexpr ( std::is_same_v<Type, type_info::UnsignedInteger<uint64_t>> ) {
1597  assert(type.tag == TypeInfo::UnsignedInteger_uint64);
1598  return type.unsigned_integer_uint64;
1599  }
1600  else if constexpr ( std::is_same_v<Type, type_info::ValueReference> ) {
1601  assert(type.tag == TypeInfo::ValueReference);
1602  return type.value_reference;
1603  }
1604  else if constexpr ( std::is_same_v<Type, type_info::Vector> ) {
1605  assert(type.tag == TypeInfo::Vector);
1606  return type.vector;
1607  }
1608  else if constexpr ( std::is_same_v<Type, type_info::VectorIterator> ) {
1609  assert(type.tag == TypeInfo::VectorIterator);
1610  return type.vector_iterator;
1611  }
1612  else if constexpr ( std::is_same_v<Type, type_info::Void> ) {
1613  assert(type.tag == TypeInfo::Void);
1614  return type.void_;
1615  }
1616  else if constexpr ( std::is_same_v<Type, type_info::WeakReference> ) {
1617  assert(type.tag == TypeInfo::WeakReference);
1618  return type.weak_reference;
1619  }
1620  else {
1621  throw RuntimeError("unhandled type");
1622  }
1623 }
1624 } // namespace value
1625 
1626 
1627 // Forward declare static built-in type information objects.
1628 extern TypeInfo address;
1629 extern TypeInfo any;
1630 extern TypeInfo bool_;
1631 extern TypeInfo bytes_iterator;
1632 extern TypeInfo bytes;
1633 extern TypeInfo bytes;
1634 extern TypeInfo error;
1635 extern TypeInfo int16;
1636 extern TypeInfo int32;
1637 extern TypeInfo int64;
1638 extern TypeInfo int8;
1639 extern TypeInfo interval;
1640 extern TypeInfo library;
1641 extern TypeInfo network;
1642 extern TypeInfo port;
1643 extern TypeInfo real;
1644 extern TypeInfo regexp;
1645 extern TypeInfo stream_iterator;
1646 extern TypeInfo stream_view;
1647 extern TypeInfo stream;
1648 extern TypeInfo string;
1649 extern TypeInfo string;
1650 extern TypeInfo time;
1651 extern TypeInfo uint16;
1652 extern TypeInfo uint32;
1653 extern TypeInfo uint64;
1654 extern TypeInfo uint8;
1655 extern TypeInfo void_;
1656 
1657 } // namespace type_info
1658 
1659 } // namespace hilti::rt
Definition: type-info.h:445
MapIterator(const TypeInfo *ktype, const TypeInfo *vtype, Accessor accessor)
Definition: type-info.h:667
Enum(std::vector< enum_::Label > labels)
Definition: type-info.h:418
std::size_t(*)(const Value &v) Accessor
Definition: type-info.h:1018
Definition: network.h:20
Definition: type-info.h:384
Definition: type-info.h:731
Definition: type-info.h:705
Definition: type-info.h:448
Element(const char *name, const TypeInfo *type, std::ptrdiff_t offset)
Definition: type-info.h:946
const TypeInfo * valueType() const
Definition: type-info.h:186
Definition: type-info.h:960
const TypeInfo * type
Definition: type-info.h:1006
Definition: type-info.h:461
Definition: type-info.h:937
const char * display
Definition: type-info.h:1148
Definition: reference.h:652
bool operator!=(const Iterator &other) const
Definition: type-info.h:243
Definition: reference.h:489
Definition: type-info.h:722
Struct(std::vector< struct_::Field > fields)
Definition: type-info.h:890
Definition: type-info.h:996
Definition: type-info.h:1122
Iterator end() const
Definition: type-info.h:269
const TypeInfo * keyType() const
Definition: type-info.h:682
Definition: port.h:22
Definition: type-info.h:747
Sequence(const Map *type, Value v)
Definition: type-info.h:533
Definition: type-info.h:930
auto iterate(const Value &v, bool include_internal=false) const
Definition: type-info.h:914
Value value(const Value &v) const
Definition: type-info.h:1037
const TypeInfo * keyType() const
Definition: type-info.h:575
Definition: interval.h:22
std::pair< const void *, const void * >(*)(const Value &v) Accessor
Definition: type-info.h:658
Definition: any.h:7
Definition: type-info.h:798
Definition: vector.h:162
const TypeInfo & type() const
Definition: type-info.h:128
std::optional< const char * > id
Definition: type-info.h:1147
Definition: optional.h:79
Value operator*() const
Definition: type-info.h:355
Definition: regexp.h:117
Union(std::vector< union_::Field > fields, Accessor accessor)
Definition: type-info.h:1027
Iterator begin() const
Definition: type-info.h:536
const TypeInfo * type
Definition: type-info.h:949
Definition: type-info.h:525
Definition: type-info.h:652
Value(const void *ptr, const TypeInfo *ti, const value::Parent &parent)
Definition: type-info.h:91
Definition: bytes.h:155
Definition: set.h:108
Definition: type-info.h:43
map::Sequence iterate(const Value &value) const
Definition: type-info.h:569
Tuple(std::vector< tuple::Element > elements)
Definition: type-info.h:967
const auto & labels() const
Definition: type-info.h:421
const TypeInfo * valueType() const
Definition: type-info.h:580
const void *(*)(const Value &v) Accessor
Definition: type-info.h:833
Definition: function.h:44
Label(std::string name, int64_t value)
Definition: type-info.h:402
Parent()
Definition: type-info.h:50
Definition: type-info.h:1072
const std::string name
Definition: type-info.h:404
Definition: type-info.h:1012
Definition: type-info.h:458
Field(const char *name, const TypeInfo *type, std::ptrdiff_t offset, bool internal, Accessor accessor=accessor_default)
Definition: type-info.h:843
Definition: type-info.h:728
Definition: type-info.h:804
std::pair< Value, Value > operator*() const
Definition: type-info.h:641
Iterator & operator++()
Definition: type-info.h:625
static const void * accessor_default(const Value &v)
Definition: type-info.h:848
Definition: type-info.h:387
bool hasValue() const
Definition: result.h:148
Iterator()
Definition: type-info.h:482
const std::string name
Definition: type-info.h:948
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:781
Definition: type-info.h:725
Definition: type.h:159
Definition: map.h:31
Definition: reference.h:340
auto fields(bool include_internal=false) const
Definition: type-info.h:898
Definition: type-info.h:395
Definition: library.h:61
DereferenceableType(const TypeInfo *vtype, Accessor accessor)
Definition: type-info.h:176
Definition: map.h:36
Definition: stream.h:1407
Definition: type-info.h:1059
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:1031
static Accessor accessor_optional()
Definition: type-info.h:852
Iterator & operator++()
Definition: type-info.h:339
Definition: type-info.h:795
Definition: reference.h:47
Definition: type-info.h:381
Definition: union.h:62
Definition: type-info.h:1106
Map(const TypeInfo *ktype, const TypeInfo *vtype, Accessor accessor)
Definition: type-info.h:565
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:555
IterableType(const TypeInfo *etype, Accessor accessor)
Definition: type-info.h:312
Definition: set.h:33
Definition: type-info.h:468
Definition: vector.h:251
Definition: type-info.h:411
Definition: type-info.h:1056
Definition: address.h:24
Definition: vector.h:84
Sequence(const IterableType *type, Value v)
Definition: type-info.h:263
Definition: type-info.h:378
Value(const void *ptr, const TypeInfo *ti, const Value &parent)
Definition: type-info.h:103
const TypeInfo * valueType() const
Definition: type-info.h:687
Definition: exception.h:22
const std::string name
Definition: type-info.h:1005
const void *(*)(const Value &v) Accessor
Definition: type-info.h:168
bool operator==(const Iterator &other) const
Definition: type-info.h:507
Definition: type-info.h:390
Definition: time.h:20
Definition: type-info.h:547
Iterator begin() const
Definition: type-info.h:266
Iterator end() const
Definition: type-info.h:539
Definition: type-info.h:828
bool operator!=(const Iterator &other) const
Definition: type-info.h:513
auto iterate(const Value &v) const
Definition: type-info.h:980
Field(const char *name, const TypeInfo *type)
Definition: type-info.h:1003
Definition: type-info.h:801
const int64_t value
Definition: type-info.h:405
Definition: type-info.h:708
Definition: type-info.h:883
Definition: type-info.h:1146
Definition: type-info.h:455
Definition: type-info.h:152
const void * pointer() const
Definition: type-info.h:119
Definition: type-info.h:810
Value value(const Value &v) const
Definition: type-info.h:181
std::pair< Value, Value > value(const Value &v) const
Definition: type-info.h:673
Definition: result.h:67
const TypeInfo * dereferencedType() const
Definition: type-info.h:323
std::string fmt(const char *fmt, const Args &... args)
Definition: fmt.h:13
const std::string name
Definition: type-info.h:866
Definition: type-info.h:1119
void tie(hilti::rt::StrongReferenceGeneric value)
Definition: type-info.h:53
const auto & elements() const
Definition: type-info.h:970
Definition: type-info.h:807
Definition: bool.h:11