Kiwano Engine  v1.2.x
Any.h
1 // Copyright (c) 2016-2018 Kiwano - Nomango
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 // THE SOFTWARE.
20 
21 #pragma once
22 #include <typeinfo>
23 #include <type_traits>
24 #include <exception>
25 
26 namespace kiwano
27 {
28 
31 class Any
32 {
33 public:
34  Any()
35  : storage_{}
36  {
37  }
38 
39  template <typename _Ty, typename _Decayed = typename std::decay<_Ty>::type,
40  typename std::enable_if<std::is_copy_constructible<_Decayed>::value, int>::type = 0>
41  Any(_Ty&& val)
42  : storage_{}
43  {
44  Emplace<_Decayed>(std::forward<_Ty>(val));
45  }
46 
47  template <typename _Ty, typename... _Args>
48  Any(_Args&&... args)
49  : storage_{}
50  {
51  using _Decayed = typename std::decay<_Ty>::type;
52 
53  Clear();
54  EmplaceDecayed<_Decayed>(std::forward<_Args>(args)...);
55  }
56 
57  Any(const Any& rhs)
58  : storage_{}
59  {
60  CopyFrom(rhs);
61  }
62 
63  Any(Any&& rhs) noexcept
64  : storage_{}
65  {
66  MoveFrome(std::move(rhs));
67  }
68 
69  ~Any()
70  {
71  Clear();
72  }
73 
76  inline const std::type_info& GetType() const noexcept
77  {
78  const std::type_info* const info = GetTypeinfo();
79  if (info)
80  {
81  return *info;
82  }
83  return typeid(void);
84  }
85 
88  inline bool HasValue() const noexcept
89  {
90  return GetTypeinfo() != nullptr;
91  }
92 
95  template <typename _Ty, typename... _Args>
96  void Emplace(_Args&&... args)
97  {
98  using _Decayed = typename std::decay<_Ty>::type;
99 
100  Clear();
101  EmplaceDecayed<_Decayed>(std::forward<_Args>(args)...);
102  }
103 
106  void Swap(Any& rhs) noexcept
107  {
108  Any old = std::move(rhs);
109  rhs = std::move(*this);
110  *this = std::move(old);
111  }
112 
115  inline void Clear() noexcept
116  {
117  Tidy();
118  }
119 
122  template <typename _Ty>
123  _Ty* CastPtr() noexcept
124  {
125  return const_cast<_Ty*>(const_cast<const Any*>(this)->CastPtr<_Ty>());
126  }
127 
130  template <typename _Ty>
131  const _Ty* CastPtr() const noexcept
132  {
133  static_assert(!std::is_void<_Ty>::value, "oc::Any cannot contain void");
134 
135  const std::type_info* const info = GetTypeinfo();
136  if (info && (*info == typeid(std::decay<_Ty>::type)))
137  {
138  if (HasSmallType())
139  {
140  return static_cast<const _Ty*>(GetSmallData());
141  }
142  else
143  {
144  return static_cast<const _Ty*>(GetBigData());
145  }
146  }
147  return nullptr;
148  }
149 
153  template <typename _Ty>
154  _Ty Cast()
155  {
156  using _Decayed = typename std::decay<_Ty>::type;
157 
158  const auto ptr = CastPtr<_Decayed>();
159  if (!ptr)
160  {
161  throw std::bad_cast();
162  }
163  return static_cast<_Ty>(*ptr);
164  }
165 
169  template <typename _Ty>
170  _Ty Cast() const
171  {
172  using _Decayed = typename std::decay<_Ty>::type;
173 
174  const auto ptr = CastPtr<_Decayed>();
175  if (!ptr)
176  {
177  throw std::bad_cast();
178  }
179  return static_cast<_Ty>(*ptr);
180  }
181 
182  Any& operator=(const Any& rhs)
183  {
184  *this = Any(rhs);
185  return (*this);
186  }
187 
188  Any& operator=(Any&& rhs) noexcept
189  {
190  Clear();
191  MoveFrome(std::move(rhs));
192  return (*this);
193  }
194 
195 private:
196  const std::type_info*& GetTypeinfo()
197  {
198  return storage_.small_.info_;
199  }
200 
201  const std::type_info* GetTypeinfo() const
202  {
203  return storage_.small_.info_;
204  }
205 
206  template <typename _Decayed, typename... _Args>
207  inline void EmplaceDecayed(_Args&&... args)
208  {
209  Store<_Decayed>(IsSmallSize<_Decayed>{}, std::forward<_Args>(args)...);
210  }
211 
212  template <typename _Decayed, typename... _Args>
213  void Store(std::true_type, _Args&&... args)
214  {
215  storage_.is_small_ = true;
216  GetTypeinfo() = &typeid(_Decayed);
217  GetSmallRTTI() = SmallStorageRTTI::make<_Decayed>();
218 
219  ::new (GetSmallData()) _Decayed(std::forward<_Args>(args)...);
220  }
221 
222  template <typename _Decayed, typename... _Args>
223  void Store(std::false_type, _Args&&... args)
224  {
225  storage_.is_small_ = false;
226  GetTypeinfo() = &typeid(_Decayed);
227  GetBigRTTI() = BigStorageRTTI::make<_Decayed>();
228 
229  GetBigData() = ::new _Decayed(std::forward<_Args>(args)...);
230  }
231 
232  void Tidy() noexcept
233  {
234  if (HasValue())
235  {
236  if (HasSmallType())
237  {
238  GetSmallRTTI().destroy(GetSmallData());
239  }
240  else
241  {
242  GetBigRTTI().destroy(GetBigData());
243  GetBigData() = nullptr;
244  }
245  GetTypeinfo() = nullptr;
246  }
247  }
248 
249  void CopyFrom(const Any& rhs)
250  {
251  if (rhs.HasValue())
252  {
253  GetTypeinfo() = rhs.GetTypeinfo();
254  storage_.is_small_ = rhs.storage_.is_small_;
255 
256  if (rhs.HasSmallType())
257  {
258  GetSmallRTTI() = rhs.GetSmallRTTI();
259  GetSmallRTTI().copy(GetSmallData(), rhs.GetSmallData());
260  }
261  else
262  {
263  GetBigRTTI() = rhs.GetBigRTTI();
264  GetBigData() = GetBigRTTI().copy(rhs.GetBigData());
265  }
266  }
267  }
268 
269  void MoveFrome(Any&& rhs) noexcept
270  {
271  if (rhs.HasValue())
272  {
273  GetTypeinfo() = rhs.GetTypeinfo();
274  storage_.is_small_ = rhs.storage_.is_small_;
275 
276  if (rhs.HasSmallType())
277  {
278  GetSmallRTTI() = rhs.GetSmallRTTI();
279  GetSmallRTTI().move(GetSmallData(), rhs.GetSmallData());
280  }
281  else
282  {
283  GetBigRTTI() = rhs.GetBigRTTI();
284  GetBigData() = rhs.GetBigData();
285  rhs.GetTypeinfo() = nullptr;
286  }
287  }
288  }
289 
290  inline void* GetSmallData()
291  {
292  return storage_.small_.buffer_;
293  }
294 
295  inline const void* GetSmallData() const
296  {
297  return storage_.small_.buffer_;
298  }
299 
300  inline void*& GetBigData()
301  {
302  return storage_.big_.ptr_;
303  }
304 
305  inline void* GetBigData() const
306  {
307  return storage_.big_.ptr_;
308  }
309 
310  inline bool HasSmallType() const
311  {
312  return storage_.is_small_;
313  }
314 
315 private:
316  static const auto ANY_SMALL_SPACE_SIZE = 8U;
317 
318  template <typename _Ty>
319  struct IsSmallSize : public std::bool_constant<sizeof(_Ty) <= ANY_SMALL_SPACE_SIZE>
320  {
321  };
322 
323  struct BigStorageRTTI
324  {
325  using DestroyFunc = void(void*);
326  using CopyFunc = void*(const void*);
327 
328  BigStorageRTTI()
329  {
330  destroy = nullptr;
331  copy = nullptr;
332  }
333 
334  template <typename _Ty>
335  static inline BigStorageRTTI make()
336  {
337  BigStorageRTTI rtti;
338  rtti.destroy = &BigStorageRTTI::Destroy<_Ty>;
339  rtti.copy = &BigStorageRTTI::Copy<_Ty>;
340  return rtti;
341  }
342 
343  template <typename _Ty>
344  static void Destroy(void* const ptr) noexcept
345  {
346  ::delete static_cast<_Ty*>(ptr);
347  }
348 
349  template <typename _Ty>
350  static void* Copy(const void* const ptr) noexcept
351  {
352  return ::new _Ty(*static_cast<const _Ty*>(ptr));
353  }
354 
355  DestroyFunc* destroy;
356  CopyFunc* copy;
357  };
358 
359  struct SmallStorageRTTI
360  {
361  using DestroyFunc = void(void*);
362  using CopyFunc = void*(void*, const void*);
363  using MoveFunc = void*(void*, void*);
364 
365  SmallStorageRTTI()
366  {
367  destroy = nullptr;
368  copy = nullptr;
369  move = nullptr;
370  }
371 
372  template <typename _Ty>
373  static inline SmallStorageRTTI make()
374  {
375  SmallStorageRTTI rtti;
376  rtti.destroy = &SmallStorageRTTI::Destroy<_Ty>;
377  rtti.copy = &SmallStorageRTTI::Copy<_Ty>;
378  rtti.move = &SmallStorageRTTI::Move<_Ty>;
379  return rtti;
380  }
381 
382  template <typename _Ty>
383  static void Destroy(void* const ptr) noexcept
384  {
385  if (ptr)
386  {
387  _Ty& obj = *(static_cast<_Ty* const>(ptr));
388  obj.~_Ty();
389  }
390  }
391 
392  template <typename _Ty>
393  static void* Copy(void* const target, const void* const ptr) noexcept
394  {
395  return ::new (static_cast<_Ty*>(target)) _Ty(*static_cast<const _Ty*>(ptr));
396  }
397 
398  template <typename _Ty>
399  static void* Move(void* const target, void* const ptr) noexcept
400  {
401  return ::new (static_cast<_Ty*>(target)) _Ty(std::move(*static_cast<_Ty*>(ptr)));
402  }
403 
404  DestroyFunc* destroy;
405  CopyFunc* copy;
406  MoveFunc* move;
407  };
408 
409 private:
410  inline SmallStorageRTTI& GetSmallRTTI()
411  {
412  return storage_.small_.rtti_;
413  }
414 
415  inline const SmallStorageRTTI& GetSmallRTTI() const
416  {
417  return storage_.small_.rtti_;
418  }
419 
420  inline BigStorageRTTI& GetBigRTTI()
421  {
422  return storage_.big_.rtti_;
423  }
424 
425  inline const BigStorageRTTI& GetBigRTTI() const
426  {
427  return storage_.big_.rtti_;
428  }
429 
430 private:
431  struct SmallStorage
432  {
433  const std::type_info* info_;
434  SmallStorageRTTI rtti_;
435  char buffer_[ANY_SMALL_SPACE_SIZE];
436  };
437 
438  struct BigStorage
439  {
440  const std::type_info* info_;
441  BigStorageRTTI rtti_;
442  void* ptr_;
443  };
444 
445  struct Storage
446  {
447  bool is_small_;
448  union
449  {
450  SmallStorage small_;
451  BigStorage big_;
452  };
453 
454  Storage()
455  : is_small_(false)
456  , small_()
457  {
458  } // fix error C2280 for VisualStudio 2015
459  };
460 
461  Storage storage_;
462 };
463 
464 } // namespace kiwano
const std::type_info & GetType() const noexcept
获取含有对象类型
Definition: Any.h:76
可储存单个任意对象的容器
Definition: Any.h:31
void Emplace(_Args &&...args)
从参数构造对象
Definition: Any.h:96
_Ty Cast() const
转换为指定类型
Definition: Any.h:170
void Swap(Any &rhs) noexcept
交换容器
Definition: Any.h:106
Definition: Actor.cpp:26
const _Ty * CastPtr() const noexcept
转换为指定类型的指针
Definition: Any.h:131
void Clear() noexcept
销毁所含对象
Definition: Any.h:115
_Ty Cast()
转换为指定类型
Definition: Any.h:154
bool HasValue() const noexcept
是否含有对象
Definition: Any.h:88
_Ty * CastPtr() noexcept
转换为指定类型的指针
Definition: Any.h:123