Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:02:30

0001 // Copyright Ruslan Arutyunyan, 2019-2021.
0002 // Copyright Antony Polukhin, 2021-2023.
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See
0005 // accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 // Contributed by Ruslan Arutyunyan
0009 
0010 #ifndef BOOST_ANYS_BASIC_ANY_HPP_INCLUDED
0011 #define BOOST_ANYS_BASIC_ANY_HPP_INCLUDED
0012 
0013 #include <boost/config.hpp>
0014 #ifdef BOOST_HAS_PRAGMA_ONCE
0015 # pragma once
0016 #endif
0017 
0018 /// \file boost/any/basic_any.hpp
0019 /// \brief \copybrief boost::anys::basic_any
0020 
0021 #include <boost/any/bad_any_cast.hpp>
0022 #include <boost/any/fwd.hpp>
0023 #include <boost/assert.hpp>
0024 #include <boost/type_index.hpp>
0025 #include <boost/throw_exception.hpp>
0026 
0027 #include <memory>  // for std::addressof
0028 #include <type_traits>
0029 
0030 
0031 namespace boost {
0032 
0033 namespace anys {
0034 
0035     /// \brief A class with customizable Small Object Optimization whose
0036     /// instances can hold instances of any type that satisfies
0037     /// \forcedlink{ValueType} requirements. Use boost::any instead if not sure.
0038     ///
0039     /// boost::anys::basic_any is the drop-in replacement for boost::any
0040     /// that provides control over Small Object Optimization via
0041     /// `OptimizeForSize` and `OptimizeForAlignment` template parameters.
0042     ///
0043     /// There are certain applications that require boost::any
0044     /// functionality, do know the typical/maximal size of the stored object and
0045     /// wish to avoid dynamic memory allocation overhead. For the convenience
0046     /// such applications may create a typedef for boost::anys::basic_any
0047     /// with the `OptimizeForSize` and `OptimizeForAlignment` template
0048     /// parameters set to typical/maximal size and alignment of types
0049     /// respectively. Memory allocation would be avoided for storing nothrow
0050     /// move constructible types with size and alignment less than or
0051     /// equal to the `OptimizeForSize` and `OptimizeForAlignment` values.
0052     ///
0053     /// Otherwise just use boost::any.
0054     template <std::size_t OptimizeForSize, std::size_t OptimizeForAlignment>
0055     class basic_any
0056     {
0057         static_assert(OptimizeForSize > 0 && OptimizeForAlignment > 0, "Size and Align shall be positive values");
0058         static_assert(OptimizeForSize >= OptimizeForAlignment, "Size shall non less than Align");
0059         static_assert((OptimizeForAlignment & (OptimizeForAlignment - 1)) == 0, "Align shall be a power of 2");
0060         static_assert(OptimizeForSize % OptimizeForAlignment == 0, "Size shall be multiple of alignment");
0061     private:
0062         /// @cond
0063         enum operation
0064         {
0065             Destroy,
0066             Move,
0067             Copy,
0068             AnyCast,
0069             UnsafeCast,
0070             Typeinfo
0071         };
0072 
0073         template <typename ValueType>
0074         static void* small_manager(operation op, basic_any& left, const basic_any* right, const boost::typeindex::type_info* info)
0075         {
0076             switch (op)
0077             {
0078                 case Destroy:
0079                     BOOST_ASSERT(!left.empty());
0080                     reinterpret_cast<ValueType*>(&left.content.small_value)->~ValueType();
0081                     break;
0082                 case Move: {
0083                     BOOST_ASSERT(left.empty());
0084                     BOOST_ASSERT(right);
0085                     BOOST_ASSERT(!right->empty());
0086                     BOOST_ASSERT(right->type() == boost::typeindex::type_id<ValueType>());
0087                     ValueType* value = reinterpret_cast<ValueType*>(&const_cast<basic_any*>(right)->content.small_value);
0088                     new (&left.content.small_value) ValueType(std::move(*value));
0089                     left.man = right->man;
0090                     reinterpret_cast<ValueType const*>(&right->content.small_value)->~ValueType();
0091                     const_cast<basic_any*>(right)->man = 0;
0092 
0093                     };
0094                     break;
0095 
0096                 case Copy:
0097                     BOOST_ASSERT(left.empty());
0098                     BOOST_ASSERT(right);
0099                     BOOST_ASSERT(!right->empty());
0100                     BOOST_ASSERT(right->type() == boost::typeindex::type_id<ValueType>());
0101                     new (&left.content.small_value) ValueType(*reinterpret_cast<const ValueType*>(&right->content.small_value));
0102                     left.man = right->man;
0103                     break;
0104                 case AnyCast:
0105                     BOOST_ASSERT(info);
0106                     BOOST_ASSERT(!left.empty());
0107                     return boost::typeindex::type_id<ValueType>() == *info ?
0108                             reinterpret_cast<typename std::remove_cv<ValueType>::type *>(&left.content.small_value) : 0;
0109                 case UnsafeCast:
0110                     BOOST_ASSERT(!left.empty());
0111                     return reinterpret_cast<typename std::remove_cv<ValueType>::type *>(&left.content.small_value);
0112                 case Typeinfo:
0113                     return const_cast<void*>(static_cast<const void*>(&boost::typeindex::type_id<ValueType>().type_info()));
0114             }
0115 
0116             return 0;
0117         }
0118 
0119         template <typename ValueType>
0120         static void* large_manager(operation op, basic_any& left, const basic_any* right, const boost::typeindex::type_info* info)
0121         {
0122             switch (op)
0123             {
0124                 case Destroy:
0125                     BOOST_ASSERT(!left.empty());
0126                     delete static_cast<ValueType*>(left.content.large_value);
0127                     break;
0128                 case Move:
0129                     BOOST_ASSERT(left.empty());
0130                     BOOST_ASSERT(right);
0131                     BOOST_ASSERT(!right->empty());
0132                     BOOST_ASSERT(right->type() == boost::typeindex::type_id<ValueType>());
0133                     left.content.large_value = right->content.large_value;
0134                     left.man = right->man;
0135                     const_cast<basic_any*>(right)->content.large_value = 0;
0136                     const_cast<basic_any*>(right)->man = 0;
0137                     break;
0138                 case Copy:
0139                     BOOST_ASSERT(left.empty());
0140                     BOOST_ASSERT(right);
0141                     BOOST_ASSERT(!right->empty());
0142                     BOOST_ASSERT(right->type() == boost::typeindex::type_id<ValueType>());
0143                     left.content.large_value = new ValueType(*static_cast<const ValueType*>(right->content.large_value));
0144                     left.man = right->man;
0145                     break;
0146                 case AnyCast:
0147                     BOOST_ASSERT(info);
0148                     BOOST_ASSERT(!left.empty());
0149                     return boost::typeindex::type_id<ValueType>() == *info ?
0150                             static_cast<typename std::remove_cv<ValueType>::type *>(left.content.large_value) : 0;
0151                 case UnsafeCast:
0152                     BOOST_ASSERT(!left.empty());
0153                     return reinterpret_cast<typename std::remove_cv<ValueType>::type *>(left.content.large_value);
0154                 case Typeinfo:
0155                     return const_cast<void*>(static_cast<const void*>(&boost::typeindex::type_id<ValueType>().type_info()));
0156             }
0157 
0158             return 0;
0159         }
0160 
0161         template <typename ValueType>
0162         struct is_small_object : std::integral_constant<bool, sizeof(ValueType) <= OptimizeForSize &&
0163             alignof(ValueType) <= OptimizeForAlignment &&
0164             std::is_nothrow_move_constructible<ValueType>::value>
0165         {};
0166 
0167         template <typename ValueType>
0168         static void create(basic_any& any, const ValueType& value, std::true_type)
0169         {
0170             typedef typename std::decay<const ValueType>::type DecayedType;
0171 
0172             any.man = &small_manager<DecayedType>;
0173             new (&any.content.small_value) ValueType(value);
0174         }
0175 
0176         template <typename ValueType>
0177         static void create(basic_any& any, const ValueType& value, std::false_type)
0178         {
0179             typedef typename std::decay<const ValueType>::type DecayedType;
0180 
0181             any.man = &large_manager<DecayedType>;
0182             any.content.large_value = new DecayedType(value);
0183         }
0184 
0185         template <typename ValueType>
0186         static void create(basic_any& any, ValueType&& value, std::true_type)
0187         {
0188             typedef typename std::decay<const ValueType>::type DecayedType;
0189             any.man = &small_manager<DecayedType>;
0190             new (&any.content.small_value) DecayedType(std::forward<ValueType>(value));
0191         }
0192 
0193         template <typename ValueType>
0194         static void create(basic_any& any, ValueType&& value, std::false_type)
0195         {
0196             typedef typename std::decay<const ValueType>::type DecayedType;
0197             any.man = &large_manager<DecayedType>;
0198             any.content.large_value = new DecayedType(std::forward<ValueType>(value));
0199         }
0200         /// @endcond
0201 
0202     public: // non-type template parameters accessors
0203             static constexpr std::size_t buffer_size = OptimizeForSize;
0204             static constexpr std::size_t buffer_align = OptimizeForAlignment;
0205 
0206     public: // structors
0207 
0208         /// \post this->empty() is true.
0209         constexpr basic_any() noexcept
0210             : man(0), content()
0211         {
0212         }
0213 
0214         /// Makes a copy of `value`, so
0215         /// that the initial content of the new instance is equivalent
0216         /// in both type and value to `value`.
0217         ///
0218         /// Does not dynamically allocate if `ValueType` is nothrow
0219         /// move constructible and `sizeof(value) <= OptimizeForSize` and
0220         /// `alignof(value) <= OptimizeForAlignment`.
0221         ///
0222         /// \throws std::bad_alloc or any exceptions arising from the copy
0223         /// constructor of the contained type.
0224         template<typename ValueType>
0225         basic_any(const ValueType & value)
0226             : man(0), content()
0227         {
0228             static_assert(
0229                 !std::is_same<ValueType, boost::any>::value,
0230                 "boost::anys::basic_any shall not be constructed from boost::any"
0231             );
0232             static_assert(
0233                 !anys::detail::is_basic_any<ValueType>::value,
0234                 "boost::anys::basic_any<A, B> shall not be constructed from boost::anys::basic_any<C, D>"
0235             );
0236             create(*this, value, is_small_object<ValueType>());
0237         }
0238 
0239         /// Copy constructor that copies content of
0240         /// `other` into new instance, so that any content
0241         /// is equivalent in both type and value to the content of
0242         /// `other`, or empty if `other` is empty.
0243         ///
0244         /// \throws May fail with a `std::bad_alloc`
0245         /// exception or any exceptions arising from the copy
0246         /// constructor of the contained type.
0247         basic_any(const basic_any & other)
0248           : man(0), content()
0249         {
0250             if (other.man)
0251             {
0252                 other.man(Copy, *this, &other, 0);
0253             }
0254         }
0255 
0256         /// Move constructor that moves content of
0257         /// `other` into new instance and leaves `other` empty.
0258         ///
0259         /// \post other->empty() is true
0260         /// \throws Nothing.
0261         basic_any(basic_any&& other) noexcept
0262           : man(0), content()
0263         {
0264             if (other.man)
0265             {
0266                 other.man(Move, *this, &other, 0);
0267             }
0268         }
0269 
0270         /// Forwards `value`, so
0271         /// that the initial content of the new instance is equivalent
0272         /// in both type and value to `value` before the forward.
0273         ///
0274         /// Does not dynamically allocate if `ValueType` is nothrow
0275         /// move constructible and `sizeof(value) <= OptimizeForSize` and
0276         /// `alignof(value) <= OptimizeForAlignment`.
0277         ///
0278         /// \throws std::bad_alloc or any exceptions arising from the move or
0279         /// copy constructor of the contained type.
0280         template<typename ValueType>
0281         basic_any(ValueType&& value
0282             , typename std::enable_if<!std::is_same<basic_any&, ValueType>::value >::type* = 0 // disable if value has type `basic_any&`
0283             , typename std::enable_if<!std::is_const<ValueType>::value >::type* = 0) // disable if value has type `const ValueType&&`
0284           : man(0), content()
0285         {
0286             typedef typename std::decay<ValueType>::type DecayedType;
0287             static_assert(
0288                 !std::is_same<DecayedType, boost::any>::value,
0289                 "boost::anys::basic_any shall not be constructed from boost::any"
0290             );
0291             static_assert(
0292                 !anys::detail::is_basic_any<DecayedType>::value,
0293                 "boost::anys::basic_any<A, B> shall not be constructed from boost::anys::basic_any<C, D>"
0294             );
0295             create(*this, static_cast<ValueType&&>(value), is_small_object<DecayedType>());
0296         }
0297 
0298         /// Releases any and all resources used in management of instance.
0299         ///
0300         /// \throws Nothing.
0301         ~basic_any() noexcept
0302         {
0303             if (man)
0304             {
0305                 man(Destroy, *this, 0, 0);
0306             }
0307         }
0308 
0309     public: // modifiers
0310 
0311         /// Exchange of the contents of `*this` and `rhs`.
0312         ///
0313         /// \returns `*this`
0314         /// \throws Nothing.
0315         basic_any & swap(basic_any & rhs) noexcept
0316         {
0317             if (this == &rhs)
0318             {
0319                 return *this;
0320             }
0321 
0322             if (man && rhs.man)
0323             {
0324                 basic_any tmp;
0325                 rhs.man(Move, tmp, &rhs, 0);
0326                 man(Move, rhs, this, 0);
0327                 tmp.man(Move, *this, &tmp, 0);
0328             }
0329             else if (man)
0330             {
0331                 man(Move, rhs, this, 0);
0332             }
0333             else if (rhs.man)
0334             {
0335                 rhs.man(Move, *this, &rhs, 0);
0336             }
0337             return *this;
0338         }
0339 
0340         /// Copies content of `rhs` into
0341         /// current instance, discarding previous content, so that the
0342         /// new content is equivalent in both type and value to the
0343         /// content of `rhs`, or empty if `rhs.empty()`.
0344         ///
0345         /// \throws std::bad_alloc
0346         /// or any exceptions arising from the copy constructor of the
0347         /// contained type. Assignment satisfies the strong guarantee
0348         /// of exception safety.
0349         basic_any & operator=(const basic_any& rhs)
0350         {
0351             basic_any(rhs).swap(*this);
0352             return *this;
0353         }
0354 
0355         /// Moves content of `rhs` into
0356         /// current instance, discarding previous content, so that the
0357         /// new content is equivalent in both type and value to the
0358         /// content of `rhs` before move, or empty if
0359         /// `rhs.empty()`.
0360         ///
0361         /// \post `rhs->empty()` is true
0362         /// \throws Nothing.
0363         basic_any & operator=(basic_any&& rhs) noexcept
0364         {
0365             rhs.swap(*this);
0366             basic_any().swap(rhs);
0367             return *this;
0368         }
0369 
0370         /// Forwards `rhs`,
0371         /// discarding previous content, so that the new content of is
0372         /// equivalent in both type and value to
0373         /// `rhs` before forward.
0374         ///
0375         /// Does not dynamically allocate if `ValueType` is nothrow
0376         /// move constructible and `sizeof(value) <= OptimizeForSize` and
0377         /// `alignof(value) <= OptimizeForAlignment`.
0378         ///
0379         /// \throws std::bad_alloc
0380         /// or any exceptions arising from the move or copy constructor of the
0381         /// contained type. Assignment satisfies the strong guarantee
0382         /// of exception safety.
0383         template <class ValueType>
0384         basic_any & operator=(ValueType&& rhs)
0385         {
0386             typedef typename std::decay<ValueType>::type DecayedType;
0387             static_assert(
0388                 !std::is_same<DecayedType, boost::any>::value,
0389                 "boost::any shall not be assigned into boost::anys::basic_any"
0390             );
0391             static_assert(
0392                 !anys::detail::is_basic_any<DecayedType>::value || std::is_same<DecayedType, basic_any>::value,
0393                 "boost::anys::basic_any<A, B> shall not be assigned into boost::anys::basic_any<C, D>"
0394             );
0395             basic_any(std::forward<ValueType>(rhs)).swap(*this);
0396             return *this;
0397         }
0398 
0399     public: // queries
0400 
0401         /// \returns `true` if instance is empty, otherwise `false`.
0402         /// \throws Nothing.
0403         bool empty() const noexcept
0404         {
0405             return !man;
0406         }
0407 
0408         /// \post this->empty() is true
0409         void clear() noexcept
0410         {
0411             basic_any().swap(*this);
0412         }
0413 
0414         /// \returns the `typeid` of the
0415         /// contained value if instance is non-empty, otherwise
0416         /// `typeid(void)`.
0417         ///
0418         /// Useful for querying against types known either at compile time or
0419         /// only at runtime.
0420         const boost::typeindex::type_info& type() const BOOST_NOEXCEPT
0421         {
0422             return man
0423                     ? *static_cast<const boost::typeindex::type_info*>(man(Typeinfo, const_cast<basic_any&>(*this), 0, 0))
0424                     : boost::typeindex::type_id<void>().type_info();
0425         }
0426 
0427     private: // representation
0428         /// @cond
0429         template<typename ValueType, std::size_t Size, std::size_t Alignment>
0430         friend ValueType * any_cast(basic_any<Size, Alignment> *) noexcept;
0431 
0432         template<typename ValueType, std::size_t Size, std::size_t Alignment>
0433         friend ValueType * unsafe_any_cast(basic_any<Size, Alignment> *) noexcept;
0434 
0435         typedef void*(*manager)(operation op, basic_any& left, const basic_any* right, const boost::typeindex::type_info* info);
0436 
0437         manager man;
0438 
0439         union content {
0440             void * large_value;
0441             alignas(OptimizeForAlignment) unsigned char small_value[OptimizeForSize];
0442         } content;
0443         /// @endcond
0444     };
0445 
0446     /// Exchange of the contents of `lhs` and `rhs`.
0447     /// \throws Nothing.
0448     template<std::size_t OptimizeForSize, std::size_t OptimizeForAlignment>
0449     void swap(basic_any<OptimizeForSize, OptimizeForAlignment>& lhs, basic_any<OptimizeForSize, OptimizeForAlignment>& rhs) noexcept
0450     {
0451         lhs.swap(rhs);
0452     }
0453 
0454     /// \returns Pointer to a ValueType stored in `operand`, nullptr if
0455     /// `operand` does not contain specified `ValueType`.
0456     template<typename ValueType, std::size_t Size, std::size_t Alignment>
0457     ValueType * any_cast(basic_any<Size, Alignment> * operand) noexcept
0458     {
0459         return operand->man ?
0460                 static_cast<typename std::remove_cv<ValueType>::type *>(operand->man(basic_any<Size, Alignment>::AnyCast, *operand, 0, &boost::typeindex::type_id<ValueType>().type_info()))
0461                 : 0;
0462     }
0463 
0464     /// \returns Const pointer to a ValueType stored in `operand`, nullptr if
0465     /// `operand` does not contain specified `ValueType`.
0466     template<typename ValueType, std::size_t OptimizeForSize, std::size_t OptimizeForAlignment>
0467     inline const ValueType * any_cast(const basic_any<OptimizeForSize, OptimizeForAlignment> * operand) noexcept
0468     {
0469         return boost::anys::any_cast<ValueType>(const_cast<basic_any<OptimizeForSize, OptimizeForAlignment> *>(operand));
0470     }
0471 
0472     /// \returns ValueType stored in `operand`
0473     /// \throws boost::bad_any_cast if `operand` does not contain
0474     /// specified ValueType.
0475     template<typename ValueType, std::size_t OptimizeForSize, std::size_t OptimizeForAlignment>
0476     ValueType any_cast(basic_any<OptimizeForSize, OptimizeForAlignment> & operand)
0477     {
0478         typedef typename std::remove_reference<ValueType>::type nonref;
0479 
0480         nonref * result = boost::anys::any_cast<nonref>(std::addressof(operand));
0481         if(!result)
0482             boost::throw_exception(bad_any_cast());
0483 
0484         // Attempt to avoid construction of a temporary object in cases when
0485         // `ValueType` is not a reference. Example:
0486         // `static_cast<std::string>(*result);`
0487         // which is equal to `std::string(*result);`
0488         typedef typename std::conditional<
0489             std::is_reference<ValueType>::value,
0490             ValueType,
0491             typename std::add_lvalue_reference<ValueType>::type
0492         >::type ref_type;
0493 
0494 #ifdef BOOST_MSVC
0495 #   pragma warning(push)
0496 #   pragma warning(disable: 4172) // "returning address of local variable or temporary" but *result is not local!
0497 #endif
0498         return static_cast<ref_type>(*result);
0499 #ifdef BOOST_MSVC
0500 #   pragma warning(pop)
0501 #endif
0502     }
0503 
0504     /// \returns `ValueType` stored in `operand`
0505     /// \throws boost::bad_any_cast if `operand` does not contain
0506     /// specified `ValueType`.
0507     template<typename ValueType, std::size_t OptimizeForSize, std::size_t OptimizeForAlignment>
0508     inline ValueType any_cast(const basic_any<OptimizeForSize, OptimizeForAlignment> & operand)
0509     {
0510         typedef typename std::remove_reference<ValueType>::type nonref;
0511         return boost::anys::any_cast<const nonref &>(const_cast<basic_any<OptimizeForSize, OptimizeForAlignment> &>(operand));
0512     }
0513 
0514     /// \returns `ValueType` stored in `operand`, leaving the `operand` empty.
0515     /// \throws boost::bad_any_cast if `operand` does not contain
0516     /// specified `ValueType`.
0517     template<typename ValueType, std::size_t OptimizeForSize, std::size_t OptimizeForAlignment>
0518     inline ValueType any_cast(basic_any<OptimizeForSize, OptimizeForAlignment>&& operand)
0519     {
0520         static_assert(
0521             std::is_rvalue_reference<ValueType&&>::value /*true if ValueType is rvalue or just a value*/
0522             || std::is_const< typename std::remove_reference<ValueType>::type >::value,
0523             "boost::any_cast shall not be used for getting nonconst references to temporary objects"
0524         );
0525         return boost::anys::any_cast<ValueType>(operand);
0526     }
0527 
0528 
0529     /// @cond
0530 
0531     // Note: The "unsafe" versions of any_cast are not part of the
0532     // public interface and may be removed at any time. They are
0533     // required where we know what type is stored in the any and can't
0534     // use typeid() comparison, e.g., when our types may travel across
0535     // different shared libraries.
0536     template<typename ValueType, std::size_t OptimizedForSize, std::size_t OptimizeForAlignment>
0537     inline ValueType * unsafe_any_cast(basic_any<OptimizedForSize, OptimizeForAlignment> * operand) noexcept
0538     {
0539         return static_cast<ValueType*>(operand->man(basic_any<OptimizedForSize, OptimizeForAlignment>::UnsafeCast, *operand, 0, 0));
0540     }
0541 
0542     template<typename ValueType, std::size_t OptimizeForSize, std::size_t OptimizeForAlignment>
0543     inline const ValueType * unsafe_any_cast(const basic_any<OptimizeForSize, OptimizeForAlignment> * operand) noexcept
0544     {
0545         return boost::anys::unsafe_any_cast<ValueType>(const_cast<basic_any<OptimizeForSize, OptimizeForAlignment> *>(operand));
0546     }
0547     /// @endcond
0548 
0549 } // namespace anys
0550 
0551 using boost::anys::any_cast;
0552 using boost::anys::unsafe_any_cast;
0553 
0554 } // namespace boost
0555 
0556 #endif // #ifndef BOOST_ANYS_BASIC_ANY_HPP_INCLUDED