siplasplas
type.hpp
1 #ifndef SIPLASPLAS_REFLECTION_DYNAMIC_TYPE_HPP
2 #define SIPLASPLAS_REFLECTION_DYNAMIC_TYPE_HPP
3 
4 #include <siplasplas/reflection/common/type_info.hpp>
5 #include <siplasplas/allocator/freelist_allocator.hpp>
6 #include <siplasplas/utility/exception.hpp>
7 #include <siplasplas/utility/lexical_cast.hpp>
8 #include <siplasplas/utility/meta.hpp>
9 #include <siplasplas/reflection/dynamic/export.hpp>
10 
11 #include <unordered_map>
12 #include <vector>
13 #include <algorithm>
14 
15 namespace cpp
16 {
17 
18 namespace dynamic_reflection
19 {
20 
21 namespace detail
22 {
23  template<typename T>
25  {
26  static constexpr ctti::unnamed_type_id_t id()
27  {
28  return ctti::unnamed_type_id<T>();
29  }
30  };
31 
32 #define CPP_REFLECTION_CUSTOM_TYPENAME_FOR(type, name) \
33  namespace cpp { namespace detail { \
34  template<> \
35  struct CustomTypeName<type> { \
36  static constexpr ::ctti::unnamed_type_id_t id() \
37  { \
38  return ::ctti::id_from_name(name); \
39  } \
40  }; }}
41 }
42 
43 #define CPP_REFLECTION_FORCE_TYPENAME(type) CPP_REFLECTION_CUSTOM_TYPENAME_FOR(type, #type)
44 
45 class SIPLASPLAS_REFLECTION_DYNAMIC_EXPORT Type
46 {
47 public:
48  Type() = default;
49 
50  void* construct() const
51  {
52  return _behavior->construct();
53  }
54 
55  void* copy_construct( const void* object) const
56  {
57  return _behavior->copy_construct(object);
58  }
59 
60  void* move_construct(void* object) const
61  {
62  return _behavior->move_construct(object);
63  }
64 
65  void copy_assign(void* object, const void* other) const
66  {
67  _behavior->copy_assign(object, other);
68  }
69 
70  void move_assign(void* object, void* other) const
71  {
72  _behavior->move_assign(object, other);
73  }
74 
75  void destroy(void* object) const
76  {
77  _behavior->destroy(object);
78  }
79 
80  std::string toString(void* object) const
81  {
82  return _behavior->toString(object);
83  }
84 
85  void* fromString(const std::string& value) const
86  {
87  return _behavior->fromString(value);
88  }
89 
90  const cpp::TypeInfo& type() const
91  {
92  return _behavior->type();
93  }
94 
95  const cpp::TypeInfo& typeInfo() const
96  {
97  return type();
98  }
99 
100  const ctti::detail::cstring typeName() const
101  {
102  return typeInfo().name();
103  }
104 
105  template<typename T>
106  static void registerType()
107  {
108  getType<T>();
109  }
110 
111  template<typename... Ts>
112  static void registerTypes()
113  {
114  TypeRegistration<meta::list<Ts...>>::apply();
115  }
116 
117  template<typename T>
118  static Type& get()
119  {
120  return getType<T>();
121  }
122 
123  static Type& get(const std::string& typeName)
124  {
125  auto try_get = [](const std::string typeName) -> Type*
126  {
127  auto id = ctti::id_from_name(typeName);
128  auto it = types().find(id);
129 
130  if(it != std::end(types()))
131  return &it->second;
132  else
133  return nullptr;
134  };
135 
136  Type* type = nullptr;
137 
138  if(!(type = try_get(typeName)) &&
139  !(type = try_get("class " + typeName)) &&
140  !(type = try_get("struct " + typeName)))
141  {
142  throw std::runtime_error{"Type '" + typeName + "' not registered"};
143  }
144  else
145  {
146  return *type;
147  }
148  }
149 
150  friend bool operator==(const Type& lhs, const Type& rhs)
151  {
152  return lhs.typeInfo() == rhs.typeInfo();
153  }
154 
155  friend bool operator!=(const Type& lhs, const Type& rhs)
156  {
157  return !(lhs == rhs);
158  }
159 
160  class SIPLASPLAS_REFLECTION_DYNAMIC_EXPORT TypeBehavior
161  {
162  public:
163  virtual ~TypeBehavior() = default;
164 
165  virtual void* construct() = 0;
166  virtual void destroy(void* object) = 0;
167  virtual void* copy_construct(const void* object) = 0;
168  virtual void* move_construct(void* object) = 0;
169  virtual void copy_assign(void* object, const void* other) = 0;
170  virtual void move_assign(void* object, void* other) = 0;
171  virtual std::string toString(void* object) = 0;
172  virtual void* fromString(const std::string& value) = 0;
173  virtual const cpp::TypeInfo& type() const = 0;
174  };
175 
176 private:
177  template<typename Ts, typename = void>
178  class TypeRegistration;
179 
180  template<typename Head, typename... Tail>
181  class TypeRegistration<meta::list<Head, Tail...>, void>
182  {
183  public:
184  static void apply()
185  {
186  Type::registerType<Head>();
187  TypeRegistration<meta::list<Tail...>>::apply();
188  }
189  };
190 
191  template<typename... Ts>
192  class TypeRegistration<meta::list<meta::list<Ts...>>, void> :
193  public TypeRegistration<meta::list<Ts...>>
194  {};
195 
196  template<typename void_>
197  class TypeRegistration<meta::list<>, void_>
198  {
199  public:
200  static void apply()
201  {}
202  };
203 
204  template<typename T>
205  class TypeBehaiorOf: public TypeBehavior
206  {
207  public:
208  TypeBehaiorOf() :
209  _type{cpp::TypeInfo::get<T>()}
210  {
211  _objectsArena.emplace_back(512 * (sizeof(T) + alignof(T)));
212  }
213 
214  void* construct() override
215  {
216  return new(allocate_object()) T();
217  }
218 
219  void* copy_construct(const void* object) override
220  {
221  return new(allocate_object()) T(*reinterpret_cast<const T*>(object));
222  }
223 
224  void* move_construct(void* object) override
225  {
226  return new(allocate_object()) T(std::move(*reinterpret_cast<T*>(object)));
227  }
228 
229  void copy_assign(void* object, const void* other) override
230  {
231  *reinterpret_cast<T*>(object) = *reinterpret_cast<const T*>(other);
232  }
233 
234  void move_assign(void* object, void* other) override
235  {
236  *reinterpret_cast<T*>(object) = std::move(*reinterpret_cast<T*>(other));
237  }
238 
239  void destroy(void* object) override
240  {
241  reinterpret_cast<T*>(object)->~T();
242  deallocate_object(object);
243  }
244 
245  std::string toString(void* object) override
246  {
247  return ToString<T>::apply(*static_cast<T*>(object));
248  }
249 
250  void* fromString(const std::string& value) override
251  {
252  auto object = FromString<T>::apply(value);
253  return copy_construct(&object); // Copy returned object
254  }
255 
256  const cpp::TypeInfo& type() const override
257  {
258  return _type;
259  }
260 
261  private:
262  cpp::TypeInfo _type;
263 
264  template<typename U, typename = void>
265  class ToString
266  {
267  public:
268  static std::string apply(const U& value)
269  {
270  std::ostringstream os;
271 
272  os << "'" << ctti::type_id<U>().name() << "' instance "
273  << "@" << static_cast<const void*>(&value);
274 
275  return os.str();
276  }
277  };
278 
279  template<typename U, typename = void>
280  class FromString
281  {
282  public:
283  static U apply(const std::string& value)
284  {
285  throw std::runtime_error{
286  "lexical_cast not supported for type i'" + cpp::lexical_cast(ctti::type_id<U>().name()) +
287  "', you must overload operator>>"
288  };
289  }
290  };
291 
292  template<typename U>
293  class ToString<U, meta::void_t<decltype(std::declval<std::ostream&>() << std::declval<const U&>())>>
294  {
295  public:
296  static std::string apply(const U& value)
297  {
298  return cpp::lexical_cast(value);
299  }
300  };
301 
302  template<typename U>
303  class FromString<U, meta::void_t<decltype(std::declval<std::istream&>() >> std::declval<U&>())>>
304  {
305  public:
306  static U apply(const std::string& value)
307  {
308  return cpp::lexical_cast<U>(value);
309  }
310  };
311 
312  class StorageBlock
313  {
314  public:
315  StorageBlock(std::size_t bytes) :
316  _block{ new char[bytes]},
317  _bytes{bytes},
318  _freeList{ begin(), end(), sizeof(T), alignof(T) }
319  {}
320 
321  void* begin() const
322  {
323  return _block.get();
324  }
325 
326  void* end() const
327  {
328  return _block.get() + _bytes;
329  }
330 
331  std::size_t bytes() const
332  {
333  return _bytes;
334  }
335 
336  cpp::FreeListAllocator freeList() const
337  {
338  return _freeList;
339  }
340 
341  private:
342  std::unique_ptr<char[]> _block;
343  std::size_t _bytes;
344  cpp::FreeListAllocator _freeList;
345  };
346 
347  std::vector<StorageBlock> _objectsArena;
348 
349  void* allocate_object()
350  {
351  return std::malloc(sizeof(T));
352  }
353 
354  void* allocate(std::vector<StorageBlock>& arena, std::size_t sizeOf, std::size_t alignment, int tries = 1)
355  {
356  void* slot = arena.back().freeList().allocate(sizeOf, alignment);
357 
358  if(slot)
359  return slot;
360  else
361  {
362  if(tries < 10)
363  {
364  // Freelist out of space, allocate new block
365  arena.emplace_back(512*(sizeOf + alignment));
366 
367  // try again
368  return allocate(arena,sizeOf, alignment, tries + 1);
369  }
370  else
371  {
372  cpp::Throw<std::runtime_error>("Cannot allocate more storage for meta-instances");
373  return nullptr;
374  }
375  }
376  }
377 
378  void deallocate_object(void* pointer)
379  {
380  return std::free(pointer);
381  }
382 
383  void deallocate(std::vector<StorageBlock>& arena, void* pointer)
384  {
385  auto blockIt = std::find_if(std::begin(arena), std::end(arena),
386  [pointer](const StorageBlock& block)
387  {
388  return block.freeList().belongs_to_storage(pointer);
389  });
390 
391  if(blockIt != std::end(arena))
392  {
393  blockIt->freeList().deallocate(pointer, sizeof(T));
394  }
395  else
396  {
397  cpp::Throw<std::runtime_error>("Cannot deallocate object @{}", pointer);
398  }
399  }
400  };
401 
402  template<typename T>
403  static Type& getType()
404  {
405  static Type& type{ [&]() -> Type&
406  {
407  return types()[detail::CustomTypeName<T>::id()] = Type{new TypeBehaiorOf<T>()};
408  }()};
409 
410  return type;
411  }
412 
413  Type(TypeBehavior* behavior) :
414  _behavior{behavior}
415  {}
416 
417  std::shared_ptr<TypeBehavior> _behavior;
418 
419  using Types = std::unordered_map<ctti::type_index, Type>;
420 
421  static Types& types();
422 };
423 
424 }
425 }
426 
427 #endif // SIPLASPLAS_REFLECTION_DYNAMIC_TYPE_HPP
Definition: meta.hpp:31
Definition: messaging.hpp:8
Definition: meta.hpp:225
void destroy(T &object)
Invokes the destructor of an object.
Definition: destroy.hpp:16
constexpr auto end(const Sequence &sequence)
Returns an iterator pointing to the end of a sequence.
Definition: algorithm.hpp:86
Definition: type.hpp:45
void construct(void *where, Args &&... args)
constructs an object of type T on the specified address
Definition: destroy.hpp:56
constexpr auto begin(const Sequence &sequence)
Returns an iterator pointing to the beginning of a sequence.
Definition: algorithm.hpp:62
Definition: test_util.hpp:13
Definition: freelist_allocator.hpp:11
Definition: typeinfo.hpp:13
std::string lexical_cast(const T &value)
Returns an string representation of a value.
Definition: lexical_cast.hpp:25