LCOV - code coverage report
Current view: top level - json - storage_ptr.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 68 68
Test Date: 2025-12-23 17:38:56 Functions: 96.8 % 31 30

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/boostorg/json
       8              : //
       9              : 
      10              : #ifndef BOOST_JSON_STORAGE_PTR_HPP
      11              : #define BOOST_JSON_STORAGE_PTR_HPP
      12              : 
      13              : #include <boost/container/pmr/polymorphic_allocator.hpp>
      14              : #include <boost/json/detail/config.hpp>
      15              : #include <boost/json/detail/shared_resource.hpp>
      16              : #include <boost/json/detail/default_resource.hpp>
      17              : #include <boost/json/is_deallocate_trivial.hpp>
      18              : #include <new>
      19              : #include <type_traits>
      20              : #include <utility>
      21              : 
      22              : namespace boost {
      23              : namespace json {
      24              : 
      25              : /** A smart pointer to a memory resource.
      26              : 
      27              :     This class is used to hold a pointer to a memory resource. The pointed-to
      28              :     resource is always valid. Depending on the means of construction, the
      29              :     ownership will be either:
      30              : 
      31              :     @li Non-owning, when constructing from a raw pointer to
      32              :     @ref boost::container::pmr::memory_resource or from a
      33              :     @ref boost::container::pmr::polymorphic_allocator. In this case the caller
      34              :     is responsible for ensuring that the lifetime of the memory resource
      35              :     extends until there are no more calls to allocate or deallocate.
      36              : 
      37              :     @li Owning, when constructing using the function @ref make_shared_resource.
      38              :     In this case ownership is shared; the lifetime of the memory resource
      39              :     extends until the last copy of the `storage_ptr` is destroyed.
      40              : 
      41              :     @par Examples
      42              :     These statements create a memory resource on the stack and construct
      43              :     a pointer from it without taking ownership:
      44              : 
      45              :     @code
      46              :     monotonic_resource mr;                  // Create our memory resource on the stack
      47              :     storage_ptr sp( &mr );                  // Construct a non-owning pointer to the resource
      48              :     @endcode
      49              : 
      50              :     This function creates a pointer to a memory resource using shared ownership
      51              :     and returns it. The lifetime of the memory resource extends until the last
      52              :     copy of the pointer is destroyed:
      53              : 
      54              :     @code
      55              :     // Create a counted memory resource and return it
      56              :     storage_ptr make_storage()
      57              :     {
      58              :         return make_shared_resource< monotonic_resource >();
      59              :     }
      60              :     @endcode
      61              : 
      62              :     @par Thread Safety
      63              :     Instances of this type provide the default level of thread safety for all
      64              :     C++ objects. Specifically, it conforms to
      65              :     [16.4.6.10 Data race avoidance](http://eel.is/c++draft/res.on.data.races).
      66              : 
      67              :     @see
      68              :         @ref make_shared_resource,
      69              :         @ref boost::container::pmr::polymorphic_allocator,
      70              :         @ref boost::container::pmr::memory_resource.
      71              : 
      72              : */
      73              : class storage_ptr
      74              : {
      75              : #ifndef BOOST_JSON_DOCS
      76              :     // VFALCO doc toolchain shows this when it shouldn't
      77              :     friend struct detail::shared_resource;
      78              : #endif
      79              :     using shared_resource =
      80              :         detail::shared_resource;
      81              : 
      82              :     using default_resource =
      83              :         detail::default_resource;
      84              : 
      85              :     std::uintptr_t i_;
      86              : 
      87              :     shared_resource*
      88          302 :     get_shared() const noexcept
      89              :     {
      90              :         return static_cast<shared_resource*>(
      91              :             reinterpret_cast<container::pmr::memory_resource*>(
      92          302 :                 i_ & ~3));
      93              :     }
      94              : 
      95              :     void
      96      6352456 :     addref() const noexcept
      97              :     {
      98      6352456 :         if(is_shared())
      99          141 :             get_shared()->refs.fetch_add(
     100              :                 1, std::memory_order_relaxed);
     101      6352456 :     }
     102              : 
     103              :     void
     104     43989306 :     release() const noexcept
     105              :     {
     106     43989306 :         if(is_shared())
     107              :         {
     108          161 :             auto const p = get_shared();
     109          161 :             if(p->refs.fetch_sub(1,
     110          161 :                     std::memory_order_acq_rel) == 1)
     111           20 :                 delete p;
     112              :         }
     113     43989306 :     }
     114              : 
     115              :     template<class T>
     116           20 :     storage_ptr(
     117              :         detail::shared_resource_impl<T>* p) noexcept
     118           20 :         : i_(reinterpret_cast<std::uintptr_t>(
     119           20 :                 static_cast<container::pmr::memory_resource*>(p)) + 1 +
     120              :             (json::is_deallocate_trivial<T>::value ? 2 : 0))
     121              :     {
     122           20 :         BOOST_ASSERT(p);
     123           20 :     }
     124              : 
     125              : public:
     126              :     /** Destructor.
     127              : 
     128              :         If the pointer has shared ownership of the resource, the shared
     129              :         ownership is released. If this is the last owned copy, the memory
     130              :         resource is destroyed.
     131              : 
     132              :         @par Complexity
     133              :         Constant.
     134              : 
     135              :         @par Exception Safety
     136              :         No-throw guarantee.
     137              :     */
     138     41912656 :     ~storage_ptr() noexcept
     139              :     {
     140     41912656 :         release();
     141     41912656 :     }
     142              : 
     143              :     /** Constructors.
     144              : 
     145              :         @li **(1)** constructs a non-owning pointer that refers to the
     146              :         \<\<default_memory_resource,default memory resource\>\>.
     147              : 
     148              :         @li **(2)** constructs a non-owning pointer that points to the memory
     149              :         resource `r`.
     150              : 
     151              :         @li **(3)** constructs a non-owning pointer that points to the same
     152              :         memory resource as `alloc`, obtained by calling `alloc.resource()`.
     153              : 
     154              :         @li **(4)**, **(5)** construct a pointer to the same memory resource as
     155              :         `other`, with the same ownership.
     156              : 
     157              :         After **(4)** and **(5)** if `other` was owning, then the constructed
     158              :         pointer is also owning. In particular, **(4)** transfers ownership to
     159              :         the constructed pointer while **(5)** causes it to share ownership with
     160              :         `other`. Otherwise, and with other overloads the constructed pointer
     161              :         doesn't own its memory resource and the caller is responsible for
     162              :         maintaining the lifetime of the pointed-to
     163              :         @ref boost::container::pmr::memory_resource.
     164              : 
     165              :         After **(4)**, `other` will point to the default memory resource.
     166              : 
     167              :         @par Constraints
     168              :         @code
     169              :         std::is_convertible< T*, boost::container::pmr::memory_resource* >::value == true
     170              :         @endcode
     171              : 
     172              :         @pre
     173              :         @code
     174              :         r != nullptr
     175              :         @endcode
     176              : 
     177              :         @par Complexity
     178              :         Constant.
     179              : 
     180              :         @par Exception Safety
     181              :         No-throw guarantee.
     182              : 
     183              :         @{
     184              :     */
     185     14653293 :     storage_ptr() noexcept
     186     14653293 :         : i_(0)
     187              :     {
     188     14653293 :     }
     189              : 
     190              :     /** Overload
     191              : 
     192              :         @tparam T The type of memory resource.
     193              :         @param r A non-null pointer to the memory resource to use.
     194              :     */
     195              :     template<class T
     196              : #ifndef BOOST_JSON_DOCS
     197              :         , class = typename std::enable_if<
     198              :             std::is_convertible<T*,
     199              :                 container::pmr::memory_resource*>::value>::type
     200              : #endif
     201              :     >
     202        57222 :     storage_ptr(T* r) noexcept
     203        57222 :         : i_(reinterpret_cast<std::uintptr_t>(
     204           18 :                 static_cast<container::pmr::memory_resource *>(r)) +
     205              :             (json::is_deallocate_trivial<T>::value ? 2 : 0))
     206              :     {
     207        57222 :         BOOST_ASSERT(r);
     208        57222 :     }
     209              : 
     210              :     /** Overload
     211              : 
     212              :         @tparam V Any type.
     213              :         @param alloc A @ref boost::container::pmr::polymorphic_allocator to
     214              :         construct from.
     215              :     */
     216              :     template<class V>
     217           10 :     storage_ptr(
     218              :         container::pmr::polymorphic_allocator<V> const& alloc) noexcept
     219           10 :         : i_(reinterpret_cast<std::uintptr_t>(
     220           10 :             alloc.resource()))
     221              :     {
     222           10 :     }
     223              : 
     224              :     /** Overload
     225              : 
     226              :         @param other Another pointer.
     227              :     */
     228     22964880 :     storage_ptr(
     229              :         storage_ptr&& other) noexcept
     230     22964880 :         : i_(detail::exchange(other.i_, 0))
     231              :     {
     232     22964880 :     }
     233              : 
     234              :     /** Overload
     235              : 
     236              :         @param other
     237              :     */
     238      6352455 :     storage_ptr(
     239              :         storage_ptr const& other) noexcept
     240      6352455 :         : i_(other.i_)
     241              :     {
     242      6352455 :         addref();
     243      6352455 :     }
     244              :     /// @}
     245              : 
     246              :     /** Assignment operators.
     247              : 
     248              :         This function assigns a pointer that points to the same memory resource
     249              :         as `other`, with the same ownership:
     250              : 
     251              :         @li If `other` is non-owning, then the assigned-to pointer will be be
     252              :         non-owning.
     253              : 
     254              :         @li If `other` has shared ownership, then **(1)** transfers ownership
     255              :         to the assigned-to pointer, while after **(2)** it shares the ownership
     256              :         with `other`.
     257              : 
     258              :         If the assigned-to pointer previously had shared ownership, it is
     259              :         released before the function returns.
     260              : 
     261              :         After **(1)**, `other` will point to the
     262              :         \<\<default_memory_resource,default memory resource\>\>.
     263              : 
     264              :         @par Complexity
     265              :         Constant.
     266              : 
     267              :         @par Exception Safety
     268              :         No-throw guarantee.
     269              : 
     270              :         @param other Another pointer.
     271              : 
     272              :         @{
     273              :     */
     274              :     storage_ptr&
     275      2076649 :     operator=(
     276              :         storage_ptr&& other) noexcept
     277              :     {
     278      2076649 :         release();
     279      2076649 :         i_ = detail::exchange(other.i_, 0);
     280      2076649 :         return *this;
     281              :     }
     282              : 
     283              :     storage_ptr&
     284            1 :     operator=(
     285              :         storage_ptr const& other) noexcept
     286              :     {
     287            1 :         other.addref();
     288            1 :         release();
     289            1 :         i_ = other.i_;
     290            1 :         return *this;
     291              :     }
     292              :     /// @}
     293              : 
     294              :     /** Check if ownership of the memory resource is shared.
     295              : 
     296              :         This function returns true for memory resources created using @ref
     297              :         make_shared_resource.
     298              :     */
     299              :     bool
     300     50341763 :     is_shared() const noexcept
     301              :     {
     302     50341763 :         return (i_ & 1) != 0;
     303              :     }
     304              : 
     305              :     /** Check if calling `deallocate` on the memory resource has no effect.
     306              : 
     307              :         This function is used to determine if the deallocate function of the
     308              :         pointed to memory resource is trivial. The value of @ref
     309              :         is_deallocate_trivial is evaluated and saved when the memory resource
     310              :         is constructed and the type is known, before the type is erased.
     311              :     */
     312              :     bool
     313            1 :     is_deallocate_trivial() const noexcept
     314              :     {
     315            1 :         return (i_ & 2) != 0;
     316              :     }
     317              : 
     318              :     /** Check if ownership of the memory resource is not shared and deallocate is trivial.
     319              : 
     320              :         This function is used to determine if calls to deallocate can
     321              :         effectively be skipped. Equivalent to `! is_shared() &&
     322              :         is_deallocate_trivial()`.
     323              :     */
     324              :     bool
     325      4323313 :     is_not_shared_and_deallocate_is_trivial() const noexcept
     326              :     {
     327      4323313 :         return (i_ & 3) == 2;
     328              :     }
     329              : 
     330              :     /** Return a pointer to the memory resource.
     331              : 
     332              :         This function returns a pointer to the
     333              :         referenced @ref boost::container::pmr::memory_resource.
     334              : 
     335              :         @par Complexity
     336              :         Constant.
     337              : 
     338              :         @par Exception Safety
     339              :         No-throw guarantee.
     340              :     */
     341              :     container::pmr::memory_resource*
     342       652979 :     get() const noexcept
     343              :     {
     344       652979 :         if(i_ != 0)
     345              :             return reinterpret_cast<
     346       122565 :                 container::pmr::memory_resource*>(i_ & ~3);
     347       530414 :         return default_resource::get();
     348              :     }
     349              : 
     350              :     /** Return a pointer to the memory resource.
     351              : 
     352              :         This function returns a pointer to the referenced @ref
     353              :         boost::container::pmr::memory_resource.
     354              : 
     355              :         @par Complexity
     356              :         Constant.
     357              : 
     358              :         @par Exception Safety
     359              :         No-throw guarantee.
     360              :     */
     361              :     container::pmr::memory_resource*
     362       649491 :     operator->() const noexcept
     363              :     {
     364       649491 :         return get();
     365              :     }
     366              : 
     367              :     /** Return a reference to the memory resource.
     368              : 
     369              :         This function returns a reference to the pointed-to @ref
     370              :         boost::container::pmr::memory_resource.
     371              : 
     372              :         @par Complexity
     373              : 
     374              :         Constant.
     375              : 
     376              :         @par Exception Safety
     377              : 
     378              :         No-throw guarantee.
     379              :     */
     380              :     container::pmr::memory_resource&
     381         3456 :     operator*() const noexcept
     382              :     {
     383         3456 :         return *get();
     384              :     }
     385              : 
     386              :     template<class U, class... Args>
     387              :     friend
     388              :     storage_ptr
     389              :     make_shared_resource(Args&&... args);
     390              : };
     391              : 
     392              : #if defined(_MSC_VER)
     393              : # pragma warning( push )
     394              : # if !defined(__clang__) && _MSC_VER <= 1900
     395              : #  pragma warning( disable : 4702 )
     396              : # endif
     397              : #endif
     398              : 
     399              : /** Return a pointer that owns a new, dynamically allocated memory resource.
     400              : 
     401              :     This function dynamically allocates a new memory resource as if by
     402              :     `operator new` that uses shared ownership. The lifetime of the memory
     403              :     resource will be extended until the last @ref storage_ptr which points to
     404              :     it is destroyed.
     405              : 
     406              :     @par Constraints
     407              :     @code
     408              :     std::is_base_of< boost::container::pmr::memory_resource, U >::value == true
     409              :     @endcode
     410              : 
     411              :     @par Complexity
     412              :     Same as `new U( std::forward<Args>(args)... )`.
     413              : 
     414              :     @par Exception Safety
     415              :     Strong guarantee.
     416              : 
     417              :     @tparam U The type of memory resource to create.
     418              : 
     419              :     @param args Parameters forwarded to the constructor of `U`.
     420              : */
     421              : template<class U, class... Args>
     422              : storage_ptr
     423           21 : make_shared_resource(Args&&... args)
     424              : {
     425              :     // If this generates an error, it means that
     426              :     // `T` is not a memory resource.
     427              :     BOOST_STATIC_ASSERT(
     428              :         std::is_base_of<
     429              :             container::pmr::memory_resource, U>::value);
     430           23 :     return storage_ptr(new
     431              :         detail::shared_resource_impl<U>(
     432           22 :             std::forward<Args>(args)...));
     433              : }
     434              : #if defined(_MSC_VER)
     435              : # pragma warning( pop )
     436              : #endif
     437              : 
     438              : /// Overload
     439              : inline
     440              : bool
     441            5 : operator==(
     442              :     storage_ptr const& lhs,
     443              :     storage_ptr const& rhs) noexcept
     444              : {
     445            5 :     return lhs.get() == rhs.get();
     446              : }
     447              : 
     448              : /// Overload
     449              : inline
     450              : bool
     451              : operator!=(
     452              :     storage_ptr const& lhs,
     453              :     storage_ptr const& rhs) noexcept
     454              : {
     455              :     return lhs.get() != rhs.get();
     456              : }
     457              : 
     458              : } // namespace json
     459              : } // namespace boost
     460              : 
     461              : #endif
        

Generated by: LCOV version 2.1