any.hpp
Go to the documentation of this file.
00001 //
00002 // Implementation of N4562 std::experimental::any (merged into C++17) for C++11 compilers.
00003 //
00004 // See also:
00005 //   + http://en.cppreference.com/w/cpp/any
00006 //   + http://en.cppreference.com/w/cpp/experimental/any
00007 //   + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any
00008 //   + https://cplusplus.github.io/LWG/lwg-active.html#2509
00009 //
00010 //
00011 // Copyright (c) 2016 Denilson das Merc�s Amorim
00012 //
00013 // Distributed under the Boost Software License, Version 1.0. (See accompanying
00014 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
00015 //
00016 #ifndef LINB_ANY_HPP
00017 #define LINB_ANY_HPP
00018 #pragma once
00019 #include <typeinfo>
00020 #include <type_traits>
00021 #include <stdexcept>
00022 
00023 namespace linb
00024 {
00025 class bad_any_cast : public std::bad_cast
00026 {
00027   public:
00028     const char* what() const noexcept override
00029     {
00030         return "bad any cast";
00031     }
00032 };
00033 
00034 class any final
00035 {
00036   public:
00038     any() : vtable(nullptr)
00039     {
00040     }
00041 
00043     any(const any& rhs) : vtable(rhs.vtable)
00044     {
00045         if (!rhs.empty())
00046         {
00047             rhs.vtable->copy(rhs.storage, this->storage);
00048         }
00049     }
00050 
00053     any(any&& rhs) noexcept : vtable(rhs.vtable)
00054     {
00055         if (!rhs.empty())
00056         {
00057             rhs.vtable->move(rhs.storage, this->storage);
00058             rhs.vtable = nullptr;
00059         }
00060     }
00061 
00063     ~any()
00064     {
00065         this->clear();
00066     }
00067 
00072     template <typename ValueType, typename = typename std::enable_if<!std::is_same<
00073                                       typename std::decay<ValueType>::type, any>::value>::type>
00074     any(ValueType&& value)
00075     {
00076         static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
00077                       "T shall satisfy the CopyConstructible requirements.");
00078         this->construct(std::forward<ValueType>(value));
00079     }
00080 
00082     any& operator=(const any& rhs)
00083     {
00084         any(rhs).swap(*this);
00085         return *this;
00086     }
00087 
00092     any& operator=(any&& rhs) noexcept
00093     {
00094         any(std::move(rhs)).swap(*this);
00095         return *this;
00096     }
00097 
00102     template <typename ValueType, typename = typename std::enable_if<!std::is_same<
00103                                       typename std::decay<ValueType>::type, any>::value>::type>
00104     any& operator=(ValueType&& value)
00105     {
00106         static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
00107                       "T shall satisfy the CopyConstructible requirements.");
00108         any(std::forward<ValueType>(value)).swap(*this);
00109         return *this;
00110     }
00111 
00113     void clear() noexcept
00114     {
00115         if (!empty())
00116         {
00117             this->vtable->destroy(storage);
00118             this->vtable = nullptr;
00119         }
00120     }
00121 
00123     bool empty() const noexcept
00124     {
00125         return this->vtable == nullptr;
00126     }
00127 
00129     const std::type_info& type() const noexcept
00130     {
00131         return empty() ? typeid(void) : this->vtable->type();
00132     }
00133 
00135     void swap(any& rhs) noexcept
00136     {
00137         if (this->vtable != rhs.vtable)
00138         {
00139             any tmp(std::move(rhs));
00140 
00141             // move from *this to rhs.
00142             rhs.vtable = this->vtable;
00143             if (this->vtable != nullptr)
00144             {
00145                 this->vtable->move(this->storage, rhs.storage);
00146                 //this->vtable = nullptr; -- uneeded, see below
00147             }
00148 
00149             // move from tmp (previously rhs) to *this.
00150             this->vtable = tmp.vtable;
00151             if (tmp.vtable != nullptr)
00152             {
00153                 tmp.vtable->move(tmp.storage, this->storage);
00154                 tmp.vtable = nullptr;
00155             }
00156         }
00157         else   // same types
00158         {
00159             if (this->vtable != nullptr)
00160                 this->vtable->swap(this->storage, rhs.storage);
00161         }
00162     }
00163 
00164   private:   // Storage and Virtual Method Table
00165     union storage_union
00166     {
00167         using stack_storage_t =
00168             typename std::aligned_storage<2 * sizeof(void*), std::alignment_of<void*>::value>::type;
00169 
00170         void* dynamic;
00171         stack_storage_t stack;   // 2 words for e.g. shared_ptr
00172     };
00173 
00175     struct vtable_type
00176     {
00177         // Note: The caller is responssible for doing .vtable = nullptr after destructful operations
00178         // such as destroy() and/or move().
00179 
00181         const std::type_info& (*type)() noexcept;
00182 
00185         void (*destroy)(storage_union&) noexcept;
00186 
00189         void (*copy)(const storage_union& src, storage_union& dest);
00190 
00193         void (*move)(storage_union& src, storage_union& dest) noexcept;
00194 
00196         void (*swap)(storage_union& lhs, storage_union& rhs) noexcept;
00197     };
00198 
00200     template <typename T>
00201     struct vtable_dynamic
00202     {
00203         static const std::type_info& type() noexcept
00204         {
00205             return typeid(T);
00206         }
00207 
00208         static void destroy(storage_union& storage) noexcept
00209         {
00210             //assert(reinterpret_cast<T*>(storage.dynamic));
00211             delete reinterpret_cast<T*>(storage.dynamic);
00212         }
00213 
00214         static void copy(const storage_union& src, storage_union& dest)
00215         {
00216             dest.dynamic = new T(*reinterpret_cast<const T*>(src.dynamic));
00217         }
00218 
00219         static void move(storage_union& src, storage_union& dest) noexcept
00220         {
00221             dest.dynamic = src.dynamic;
00222             src.dynamic = nullptr;
00223         }
00224 
00225         static void swap(storage_union& lhs, storage_union& rhs) noexcept
00226         {
00227             // just exchage the storage pointers.
00228             std::swap(lhs.dynamic, rhs.dynamic);
00229         }
00230     };
00231 
00233     template <typename T>
00234     struct vtable_stack
00235     {
00236         static const std::type_info& type() noexcept
00237         {
00238             return typeid(T);
00239         }
00240 
00241         static void destroy(storage_union& storage) noexcept
00242         {
00243             reinterpret_cast<T*>(&storage.stack)->~T();
00244         }
00245 
00246         static void copy(const storage_union& src, storage_union& dest)
00247         {
00248             new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
00249         }
00250 
00251         static void move(storage_union& src, storage_union& dest) noexcept
00252         {
00253             // one of the conditions for using vtable_stack is a nothrow move constructor,
00254             // so this move constructor will never throw a exception.
00255             new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
00256             destroy(src);
00257         }
00258 
00259         static void swap(storage_union& lhs, storage_union& rhs) noexcept
00260         {
00261             storage_union tmp_storage;
00262             move(rhs, tmp_storage);
00263             move(lhs, rhs);
00264             move(tmp_storage, lhs);
00265         }
00266     };
00267 
00269     template <typename T>
00270     struct requires_allocation
00271       : std::integral_constant<
00272             bool,
00273             !(std::is_nothrow_move_constructible<T>::value   // N4562 �6.3/3 [any.class]
00274               && sizeof(T) <= sizeof(storage_union::stack) &&
00275               std::alignment_of<T>::value <=
00276                   std::alignment_of<storage_union::stack_storage_t>::value)>
00277     {
00278     };
00279 
00281     template <typename T>
00282     static vtable_type* vtable_for_type()
00283     {
00284         using VTableType = typename std::conditional<requires_allocation<T>::value,
00285                                                      vtable_dynamic<T>, vtable_stack<T>>::type;
00286         static vtable_type table = {
00287             VTableType::type, VTableType::destroy, VTableType::copy,
00288             VTableType::move, VTableType::swap,
00289         };
00290         return &table;
00291     }
00292 
00293   protected:
00294     template <typename T>
00295     friend const T* any_cast(const any* operand) noexcept;
00296     template <typename T>
00297     friend T* any_cast(any* operand) noexcept;
00298 
00300     bool is_typed(const std::type_info& t) const
00301     {
00302         return is_same(this->type(), t);
00303     }
00304 
00311     static bool is_same(const std::type_info& a, const std::type_info& b)
00312     {
00313 #ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE
00314         return &a == &b;
00315 #else
00316         return a == b;
00317 #endif
00318     }
00319 
00321     template <typename T>
00322     const T* cast() const noexcept
00323     {
00324         return requires_allocation<typename std::decay<T>::type>::value ?
00325                    reinterpret_cast<const T*>(storage.dynamic) :
00326                    reinterpret_cast<const T*>(&storage.stack);
00327     }
00328 
00330     template <typename T>
00331     T* cast() noexcept
00332     {
00333         return requires_allocation<typename std::decay<T>::type>::value ?
00334                    reinterpret_cast<T*>(storage.dynamic) :
00335                    reinterpret_cast<T*>(&storage.stack);
00336     }
00337 
00338   private:
00339     storage_union storage;   // on offset(0) so no padding for align
00340     vtable_type* vtable;
00341 
00342     template <typename ValueType, typename T>
00343     typename std::enable_if<requires_allocation<T>::value>::type do_construct(ValueType&& value)
00344     {
00345         storage.dynamic = new T(std::forward<ValueType>(value));
00346     }
00347 
00348     template <typename ValueType, typename T>
00349     typename std::enable_if<!requires_allocation<T>::value>::type do_construct(ValueType&& value)
00350     {
00351         new (&storage.stack) T(std::forward<ValueType>(value));
00352     }
00353 
00356     template <typename ValueType>
00357     void construct(ValueType&& value)
00358     {
00359         using T = typename std::decay<ValueType>::type;
00360 
00361         this->vtable = vtable_for_type<T>();
00362 
00363         do_construct<ValueType, T>(std::forward<ValueType>(value));
00364     }
00365 };
00366 
00367 namespace detail
00368 {
00369 template <typename ValueType>
00370 inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p,
00371                                        std::true_type)
00372 {
00373     return std::move(*p);
00374 }
00375 
00376 template <typename ValueType>
00377 inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p,
00378                                        std::false_type)
00379 {
00380     return *p;
00381 }
00382 }
00383 
00385 template <typename ValueType>
00386 inline ValueType any_cast(const any& operand)
00387 {
00388     auto p =
00389         any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(
00390             &operand);
00391     if (p == nullptr)
00392         throw bad_any_cast();
00393     return *p;
00394 }
00395 
00397 template <typename ValueType>
00398 inline ValueType any_cast(any& operand)
00399 {
00400     auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
00401     if (p == nullptr)
00402         throw bad_any_cast();
00403     return *p;
00404 }
00405 
00415 template <typename ValueType>
00416 inline ValueType any_cast(any&& operand)
00417 {
00418 #ifdef ANY_IMPL_ANY_CAST_MOVEABLE
00419     // https://cplusplus.github.io/LWG/lwg-active.html#2509
00420     using can_move = std::integral_constant<bool, std::is_move_constructible<ValueType>::value &&
00421                                                       !std::is_lvalue_reference<ValueType>::value>;
00422 #else
00423     using can_move = std::false_type;
00424 #endif
00425 
00426     auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
00427     if (p == nullptr)
00428         throw bad_any_cast();
00429     return detail::any_cast_move_if_true<ValueType>(p, can_move());
00430 }
00431 
00434 template <typename T>
00435 inline const T* any_cast(const any* operand) noexcept
00436 {
00437     if (operand == nullptr || !operand->is_typed(typeid(T)))
00438         return nullptr;
00439     else
00440         return operand->cast<T>();
00441 }
00442 
00445 template <typename T>
00446 inline T* any_cast(any* operand) noexcept
00447 {
00448     if (operand == nullptr || !operand->is_typed(typeid(T)))
00449         return nullptr;
00450     else
00451         return operand->cast<T>();
00452 }
00453 }
00454 
00455 namespace std
00456 {
00457 inline void swap(linb::any& lhs, linb::any& rhs) noexcept
00458 {
00459     lhs.swap(rhs);
00460 }
00461 }
00462 
00463 #endif


behaviortree_cpp
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Sat Feb 2 2019 03:50:09