Kiwano Engine v1.3.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
26namespace kiwano
27{
28
31class Any
32{
33public:
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
195private:
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
315private:
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
409private:
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
430private:
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
可储存单个任意对象的容器
Definition: Any.h:32
_Ty Cast()
转换为指定类型
Definition: Any.h:154
const _Ty * CastPtr() const noexcept
转换为指定类型的指针
Definition: Any.h:131
const std::type_info & GetType() const noexcept
获取含有对象类型
Definition: Any.h:76
bool HasValue() const noexcept
是否含有对象
Definition: Any.h:88
_Ty Cast() const
转换为指定类型
Definition: Any.h:170
void Swap(Any &rhs) noexcept
交换容器
Definition: Any.h:106
void Emplace(_Args &&... args)
从参数构造对象
Definition: Any.h:96
void Clear() noexcept
销毁所含对象
Definition: Any.h:115
_Ty * CastPtr() noexcept
转换为指定类型的指针
Definition: Any.h:123