Keyple Util C++ Library 2.3.0.5-SNAPSHOT
Reference Terminal Reader API for C++
Any.h
Go to the documentation of this file.
1//
2// Implementation of N4562 std::experimental::any (merged into C++17) for C++11 compilers.
3//
4// See also:
5// + http://en.cppreference.com/w/cpp/any
6// + http://en.cppreference.com/w/cpp/experimental/any
7// + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any
8// + https://cplusplus.github.io/LWG/lwg-active.html#2509
9//
10//
11// Copyright (c) 2016 Denilson das Mercês Amorim
12//
13// Distributed under the Boost Software License, Version 1.0. (See accompanying
14// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
15//
16#ifndef LINB_ANY_HPP
17#define LINB_ANY_HPP
18#pragma once
19#include <typeinfo>
20#include <type_traits>
21#include <stdexcept>
22#include <utility>
23
24
25#if defined(PARTICLE)
26#if !defined(__cpp_exceptions) && !defined(ANY_IMPL_NO_EXCEPTIONS) && !defined(ANY_IMPL_EXCEPTIONS)
27# define ANY_IMPL_NO_EXCEPTIONS
28# endif
29#else
30// you can opt-out of exceptions by definining ANY_IMPL_NO_EXCEPTIONS,
31// but you must ensure not to cast badly when passing an `any' object to any_cast<T>(any)
32#endif
33
34#if defined(PARTICLE)
35#if !defined(__cpp_rtti) && !defined(ANY_IMPL_NO_RTTI) && !defined(ANY_IMPL_RTTI)
36# define ANY_IMPL_NO_RTTI
37# endif
38#else
39// you can opt-out of RTTI by defining ANY_IMPL_NO_RTTI,
40// in order to disable functions working with the typeid of a type
41#endif
42
43
44namespace keyple {
45namespace core {
46namespace util {
47namespace cpp {
48
49class bad_any_cast : public std::bad_cast
50{
51public:
52 const char* what() const noexcept override
53 {
54 return "bad any cast";
55 }
56};
57
58class any final
59{
60public:
62 any() :
63 vtable(nullptr)
64 {
65 }
66
68 any(const any& rhs) :
69 vtable(rhs.vtable)
70 {
71 if(!rhs.empty())
72 {
73 rhs.vtable->copy(rhs.storage, this->storage);
74 }
75 }
76
79 any(any&& rhs) noexcept :
80 vtable(rhs.vtable)
81 {
82 if(!rhs.empty())
83 {
84 rhs.vtable->move(rhs.storage, this->storage);
85 rhs.vtable = nullptr;
86 }
87 }
88
91 {
92 this->clear();
93 }
94
99 template<typename ValueType, typename = typename std::enable_if<!std::is_same<typename std::decay<ValueType>::type, any>::value>::type>
100 any(ValueType&& value)
101 {
102 static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
103 "T shall satisfy the CopyConstructible requirements.");
104 this->construct(std::forward<ValueType>(value));
105 }
106
108 any& operator=(const any& rhs)
109 {
110 any(rhs).swap(*this);
111 return *this;
112 }
113
118 any& operator=(any&& rhs) noexcept
119 {
120 any(std::move(rhs)).swap(*this);
121 return *this;
122 }
123
128 template<typename ValueType, typename = typename std::enable_if<!std::is_same<typename std::decay<ValueType>::type, any>::value>::type>
129 any& operator=(ValueType&& value)
130 {
131 static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
132 "T shall satisfy the CopyConstructible requirements.");
133 any(std::forward<ValueType>(value)).swap(*this);
134 return *this;
135 }
136
138 void clear() noexcept
139 {
140 if(!empty())
141 {
142 this->vtable->destroy(storage);
143 this->vtable = nullptr;
144 }
145 }
146
148 bool empty() const noexcept
149 {
150 return this->vtable == nullptr;
151 }
152
153#ifndef ANY_IMPL_NO_RTTI
155 const std::type_info& type() const noexcept
156 {
157 return empty()? typeid(void) : this->vtable->type();
158 }
159#endif
160
162 void swap(any& rhs) noexcept
163 {
164 if(this->vtable != rhs.vtable)
165 {
166 any tmp(std::move(rhs));
167
168 // move from *this to rhs.
169 rhs.vtable = this->vtable;
170 if(this->vtable != nullptr)
171 {
172 this->vtable->move(this->storage, rhs.storage);
173 //this->vtable = nullptr; -- unneeded, see below
174 }
175
176 // move from tmp (previously rhs) to *this.
177 this->vtable = tmp.vtable;
178 if(tmp.vtable != nullptr)
179 {
180 tmp.vtable->move(tmp.storage, this->storage);
181 tmp.vtable = nullptr;
182 }
183 }
184 else // same types
185 {
186 if(this->vtable != nullptr)
187 this->vtable->swap(this->storage, rhs.storage);
188 }
189 }
190
191private: // Storage and Virtual Method Table
192
193 union storage_union
194 {
195 using stack_storage_t = typename std::aligned_storage<2 * sizeof(void*), std::alignment_of<void*>::value>::type;
196
197 void* dynamic;
198 stack_storage_t stack; // 2 words for e.g. shared_ptr
199 };
200
202 struct vtable_type
203 {
204 // Note: The caller is responssible for doing .vtable = nullptr after destructful operations
205 // such as destroy() and/or move().
206
207#ifndef ANY_IMPL_NO_RTTI
209 const std::type_info& (*type)() noexcept;
210#endif
211
214 void(*destroy)(storage_union&) noexcept;
215
218 void(*copy)(const storage_union& src, storage_union& dest);
219
222 void(*move)(storage_union& src, storage_union& dest) noexcept;
223
225 void(*swap)(storage_union& lhs, storage_union& rhs) noexcept;
226 };
227
229 template<typename T>
230 struct vtable_dynamic
231 {
232#ifndef ANY_IMPL_NO_RTTI
233 static const std::type_info& type() noexcept
234 {
235 return typeid(T);
236 }
237#endif
238
239 static void destroy(storage_union& storage) noexcept
240 {
241 //assert(reinterpret_cast<T*>(storage.dynamic));
242 delete reinterpret_cast<T*>(storage.dynamic);
243 }
244
245 static void copy(const storage_union& src, storage_union& dest)
246 {
247 dest.dynamic = new T(*reinterpret_cast<const T*>(src.dynamic));
248 }
249
250 static void move(storage_union& src, storage_union& dest) noexcept
251 {
252 dest.dynamic = src.dynamic;
253 src.dynamic = nullptr;
254 }
255
256 static void swap(storage_union& lhs, storage_union& rhs) noexcept
257 {
258 // just exchage the storage pointers.
259 std::swap(lhs.dynamic, rhs.dynamic);
260 }
261 };
262
264 template<typename T>
265 struct vtable_stack
266 {
267#ifndef ANY_IMPL_NO_RTTI
268 static const std::type_info& type() noexcept
269 {
270 return typeid(T);
271 }
272#endif
273
274 static void destroy(storage_union& storage) noexcept
275 {
276 reinterpret_cast<T*>(&storage.stack)->~T();
277 }
278
279 static void copy(const storage_union& src, storage_union& dest)
280 {
281 new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
282 }
283
284 static void move(storage_union& src, storage_union& dest) noexcept
285 {
286 // one of the conditions for using vtable_stack is a nothrow move constructor,
287 // so this move constructor will never throw a exception.
288 new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
289 destroy(src);
290 }
291
292 static void swap(storage_union& lhs, storage_union& rhs) noexcept
293 {
294 storage_union tmp_storage;
295 move(rhs, tmp_storage);
296 move(lhs, rhs);
297 move(tmp_storage, lhs);
298 }
299 };
300
302 template<typename T>
303 struct requires_allocation :
304 std::integral_constant<bool,
305 !(std::is_nothrow_move_constructible<T>::value // N4562 §6.3/3 [any.class]
306 && sizeof(T) <= sizeof(storage_union::stack)
307 && std::alignment_of<T>::value <= std::alignment_of<storage_union::stack_storage_t>::value)>
308 {};
309
311 template<typename T>
312 static vtable_type* vtable_for_type()
313 {
314 using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
315 static vtable_type table = {
316#ifndef ANY_IMPL_NO_RTTI
317 VTableType::type,
318#endif
319 VTableType::destroy,
320 VTableType::copy, VTableType::move,
321 VTableType::swap,
322 };
323 return &table;
324 }
325
326protected:
327 template<typename T>
328 friend const T* any_cast(const any* operand) noexcept;
329 template<typename T>
330 friend T* any_cast(any* operand) noexcept;
331
332#ifndef ANY_IMPL_NO_RTTI
334 bool is_typed(const std::type_info& t) const
335 {
336 return is_same(this->type(), t);
337 }
338#endif
339
340#ifndef ANY_IMPL_NO_RTTI
347 static bool is_same(const std::type_info& a, const std::type_info& b)
348 {
349#ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE
350 return &a == &b;
351#else
352 return a == b;
353#endif
354 }
355#endif
356
358 template<typename T>
359 const T* cast() const noexcept
360 {
361 return requires_allocation<typename std::decay<T>::type>::value?
362 reinterpret_cast<const T*>(storage.dynamic) :
363 reinterpret_cast<const T*>(&storage.stack);
364 }
365
367 template<typename T>
368 T* cast() noexcept
369 {
370 return requires_allocation<typename std::decay<T>::type>::value?
371 reinterpret_cast<T*>(storage.dynamic) :
372 reinterpret_cast<T*>(&storage.stack);
373 }
374
375private:
376 storage_union storage = { 0 }; // on offset(0) so no padding for align
377 vtable_type* vtable;
378
379 template<typename ValueType, typename T>
380 typename std::enable_if<requires_allocation<T>::value>::type
381 do_construct(ValueType&& value)
382 {
383 storage.dynamic = new T(std::forward<ValueType>(value));
384 }
385
386 template<typename ValueType, typename T>
387 typename std::enable_if<!requires_allocation<T>::value>::type
388 do_construct(ValueType&& value)
389 {
390 new (&storage.stack) T(std::forward<ValueType>(value));
391 }
392
395 template<typename ValueType>
396 void construct(ValueType&& value)
397 {
398 using T = typename std::decay<ValueType>::type;
399
400 this->vtable = vtable_for_type<T>();
401
402 do_construct<ValueType,T>(std::forward<ValueType>(value));
403 }
404};
405
406
407
408namespace detail
409{
410 template<typename ValueType>
411 inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p, std::true_type)
412 {
413 return std::move(*p);
414 }
415
416 template<typename ValueType>
417 inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p, std::false_type)
418 {
419 return *p;
420 }
421}
422
424template<typename ValueType>
425inline ValueType any_cast(const any& operand)
426{
427 auto p = any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(&operand);
428#ifndef ANY_IMPL_NO_EXCEPTIONS
429 if(p == nullptr) throw bad_any_cast();
430#endif
431 return *p;
432}
433
435template<typename ValueType>
436inline ValueType any_cast(any& operand)
437{
438 auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
439#ifndef ANY_IMPL_NO_EXCEPTIONS
440 if(p == nullptr) throw bad_any_cast();
441#endif
442 return *p;
443}
444
450template<typename ValueType>
451inline ValueType any_cast(any&& operand)
452{
453 using can_move = std::integral_constant<bool,
454 std::is_move_constructible<ValueType>::value
455 && !std::is_lvalue_reference<ValueType>::value>;
456
457 auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
458#ifndef ANY_IMPL_NO_EXCEPTIONS
459 if(p == nullptr) throw bad_any_cast();
460#endif
461 return detail::any_cast_move_if_true<ValueType>(p, can_move());
462}
463
466template<typename ValueType>
467inline const ValueType* any_cast(const any* operand) noexcept
468{
469 using T = typename std::decay<ValueType>::type;
470
471#ifndef ANY_IMPL_NO_RTTI
472 if (operand && operand->is_typed(typeid(T)))
473#else
474 if (operand && operand->vtable == any::vtable_for_type<T>())
475#endif
476 return operand->cast<ValueType>();
477 else
478 return nullptr;
479}
480
483template<typename ValueType>
484inline ValueType* any_cast(any* operand) noexcept
485{
486 using T = typename std::decay<ValueType>::type;
487
488#ifndef ANY_IMPL_NO_RTTI
489 if (operand && operand->is_typed(typeid(T)))
490#else
491 if (operand && operand->vtable == any::vtable_for_type<T>())
492#endif
493 return operand->cast<ValueType>();
494 else
495 return nullptr;
496}
497
498}
499}
500}
501}
502
503namespace std
504{
506 {
507 lhs.swap(rhs);
508 }
509}
510
511#endif
bool empty() const noexcept
Returns true if *this has no contained object, otherwise false.
Definition: Any.h:148
any & operator=(any &&rhs) noexcept
Definition: Any.h:118
any & operator=(ValueType &&value)
Definition: Any.h:129
void clear() noexcept
If not empty, destroys the contained object.
Definition: Any.h:138
void swap(any &rhs) noexcept
Exchange the states of *this and rhs.
Definition: Any.h:162
const std::type_info & type() const noexcept
If *this has a contained object of type T, typeid(T); otherwise typeid(void).
Definition: Any.h:155
any(const any &rhs)
Constructs an object of type any with an equivalent state as other.
Definition: Any.h:68
any(any &&rhs) noexcept
Definition: Any.h:79
any & operator=(const any &rhs)
Has the same effect as any(rhs).swap(*this). No effects if an exception is thrown.
Definition: Any.h:108
friend const T * any_cast(const any *operand) noexcept
Definition: Any.h:467
any(ValueType &&value)
Definition: Any.h:100
any()
Constructs an object of type any with an empty state.
Definition: Any.h:62
~any()
Same effect as this->clear().
Definition: Any.h:90
const char * what() const noexcept override
Definition: Any.h:52
ValueType any_cast_move_if_true(typename std::remove_reference< ValueType >::type *p, std::false_type)
Definition: Any.h:417
Definition: Any.h:504
void swap(keyple::core::util::cpp::any &lhs, keyple::core::util::cpp::any &rhs) noexcept
Definition: Any.h:505