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:20:51 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 container is used to hold a pointer to a memory resource. The
      28              :     pointed-to resource is always valid. Depending on the means of
      29              :     construction, the ownership will be either:
      30              : 
      31              :     @li Non-owning, when constructing from a raw pointer to
      32              :     `boost::container::pmr::memory_resource` or from a
      33              :     `boost::container::pmr::polymorphic_allocator`. In this case the caller is
      34              :     responsible for ensuring that the lifetime of the memory resource extends
      35              :     until there are no more calls to allocate or deallocate.
      36              : 
      37              :     @li Owning, when constructing using the function
      38              :     @ref make_shared_resource. In this case
      39              :     ownership is shared; the lifetime of the memory
      40              :     resource extends until the last copy of the
      41              :     @ref storage_ptr is destroyed.
      42              : 
      43              :     @par Examples
      44              : 
      45              :     These statements create a memory resource on the
      46              :     stack and construct a pointer from it without
      47              :     taking ownership:
      48              :     @code
      49              :     monotonic_resource mr;                  // Create our memory resource on the stack
      50              :     storage_ptr sp( &mr );                  // Construct a non-owning pointer to the resource
      51              :     @endcode
      52              : 
      53              :     This function creates a pointer to a memory
      54              :     resource using shared ownership and returns it.
      55              :     The lifetime of the memory resource extends until
      56              :     the last copy of the pointer is destroyed:
      57              :     @code
      58              :     // Create a counted memory resource and return it
      59              :     storage_ptr make_storage()
      60              :     {
      61              :         return make_shared_resource< monotonic_resource >();
      62              :     }
      63              :     @endcode
      64              : 
      65              :     @par Thread Safety
      66              : 
      67              :     Instances of this type provide the default level of
      68              :     thread safety for all C++ objects. Specifically, it
      69              :     conforms to
      70              :     <a href="http://eel.is/c++draft/res.on.data.races">
      71              :         16.4.6.10 Data race avoidance</a>.
      72              : 
      73              :     @see
      74              :         @ref make_shared_resource,
      75              :         @ref boost::container::pmr::polymorphic_allocator,
      76              :         @ref boost::container::pmr::memory_resource.
      77              : 
      78              : */
      79              : class storage_ptr
      80              : {
      81              : #ifndef BOOST_JSON_DOCS
      82              :     // VFALCO doc toolchain shows this when it shouldn't
      83              :     friend struct detail::shared_resource;
      84              : #endif
      85              :     using shared_resource =
      86              :         detail::shared_resource;
      87              : 
      88              :     using default_resource =
      89              :         detail::default_resource;
      90              : 
      91              :     std::uintptr_t i_;
      92              : 
      93              :     shared_resource*
      94          302 :     get_shared() const noexcept
      95              :     {
      96              :         return static_cast<shared_resource*>(
      97              :             reinterpret_cast<container::pmr::memory_resource*>(
      98          302 :                 i_ & ~3));
      99              :     }
     100              : 
     101              :     void
     102      6352922 :     addref() const noexcept
     103              :     {
     104      6352922 :         if(is_shared())
     105          141 :             get_shared()->refs.fetch_add(
     106              :                 1, std::memory_order_relaxed);
     107      6352922 :     }
     108              : 
     109              :     void
     110     43991462 :     release() const noexcept
     111              :     {
     112     43991462 :         if(is_shared())
     113              :         {
     114          161 :             auto const p = get_shared();
     115          161 :             if(p->refs.fetch_sub(1,
     116          161 :                     std::memory_order_acq_rel) == 1)
     117           20 :                 delete p;
     118              :         }
     119     43991462 :     }
     120              : 
     121              :     template<class T>
     122           20 :     storage_ptr(
     123              :         detail::shared_resource_impl<T>* p) noexcept
     124           20 :         : i_(reinterpret_cast<std::uintptr_t>(
     125           20 :                 static_cast<container::pmr::memory_resource*>(p)) + 1 +
     126              :             (json::is_deallocate_trivial<T>::value ? 2 : 0))
     127              :     {
     128           20 :         BOOST_ASSERT(p);
     129           20 :     }
     130              : 
     131              : public:
     132              :     /** Destructor
     133              : 
     134              :         If the pointer has shared ownership of the
     135              :         resource, the shared ownership is released.
     136              :         If this is the last owned copy, the memory
     137              :         resource is destroyed.
     138              : 
     139              :         @par Complexity
     140              :         Constant.
     141              : 
     142              :         @par Exception Safety
     143              :         No-throw guarantee.
     144              :     */
     145     41914812 :     ~storage_ptr() noexcept
     146              :     {
     147     41914812 :         release();
     148     41914812 :     }
     149              : 
     150              :     /** Constructor
     151              : 
     152              :         This constructs a non-owning pointer that refers
     153              :         to the [default memory resource].
     154              : 
     155              :         @par Complexity
     156              :         Constant.
     157              : 
     158              :         @par Exception Safety
     159              :         No-throw guarantee.
     160              : 
     161              :         [default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
     162              :     */
     163     14653596 :     storage_ptr() noexcept
     164     14653596 :         : i_(0)
     165              :     {
     166     14653596 :     }
     167              : 
     168              :     /** Constructor
     169              : 
     170              :         This constructs a non-owning pointer that points to the memory resource
     171              :         `r`. The caller is responsible for maintaining the lifetime of the
     172              :         pointed-to `boost::container::pmr::memory_resource`.
     173              : 
     174              :         @par Constraints
     175              :         @code
     176              :         std::is_convertible< T*, boost::container::pmr::memory_resource* >::value == true
     177              :         @endcode
     178              : 
     179              :         @par Preconditions
     180              :         @code
     181              :         r != nullptr
     182              :         @endcode
     183              : 
     184              :         @par Exception Safety
     185              :         No-throw guarantee.
     186              : 
     187              :         @param r A pointer to the memory resource to use.
     188              :         This may not be null.
     189              :     */
     190              :     template<class T
     191              : #ifndef BOOST_JSON_DOCS
     192              :         , class = typename std::enable_if<
     193              :             std::is_convertible<T*,
     194              :                 container::pmr::memory_resource*>::value>::type
     195              : #endif
     196              :     >
     197        57222 :     storage_ptr(T* r) noexcept
     198        57222 :         : i_(reinterpret_cast<std::uintptr_t>(
     199           18 :                 static_cast<container::pmr::memory_resource *>(r)) +
     200              :             (json::is_deallocate_trivial<T>::value ? 2 : 0))
     201              :     {
     202        57222 :         BOOST_ASSERT(r);
     203        57222 :     }
     204              : 
     205              :     /** Constructor
     206              : 
     207              :         This constructs a non-owning pointer that points to the same memory
     208              :         resource as `alloc`, obtained by calling `alloc.resource()`. The caller
     209              :         is responsible for maintaining the lifetime of the
     210              :         pointed-to `boost::container::pmr::memory_resource`.
     211              : 
     212              :         @par Constraints
     213              :         @code
     214              :         std::is_convertible< T*, boost::container::pmr::memory_resource* >::value == true
     215              :         @endcode
     216              : 
     217              :         @par Exception Safety
     218              :         No-throw guarantee.
     219              : 
     220              :         @param alloc A `boost::container::pmr::polymorphic_allocator` to
     221              :         construct from.
     222              :     */
     223              :     template<class T>
     224           10 :     storage_ptr(
     225              :         container::pmr::polymorphic_allocator<T> const& alloc) noexcept
     226           10 :         : i_(reinterpret_cast<std::uintptr_t>(
     227           10 :             alloc.resource()))
     228              :     {
     229           10 :     }
     230              : 
     231              :     /** Move constructor
     232              : 
     233              :         This function constructs a pointer that
     234              :         points to the same memory resource as `other`,
     235              :         with the same ownership:
     236              : 
     237              :         @li If `other` is non-owning, then `*this`
     238              :         will be be non-owning.
     239              : 
     240              :         @li If `other` has shared ownership, then
     241              :         ownership will be transferred to `*this`.
     242              : 
     243              :         After construction, `other` will point
     244              :         to the [default memory resource].
     245              : 
     246              :         @par Complexity
     247              :         Constant.
     248              : 
     249              :         @par Exception Safety
     250              :         No-throw guarantee.
     251              : 
     252              :         @param other The pointer to construct from.
     253              : 
     254              :         [default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
     255              :     */
     256     22966351 :     storage_ptr(
     257              :         storage_ptr&& other) noexcept
     258     22966351 :         : i_(detail::exchange(other.i_, 0))
     259              :     {
     260     22966351 :     }
     261              : 
     262              :     /** Copy constructor
     263              : 
     264              :         This function constructs a pointer that
     265              :         points to the same memory resource as `other`,
     266              :         with the same ownership:
     267              : 
     268              :         @li If `other` is non-owning, then `*this`
     269              :         will be be non-owning.
     270              : 
     271              :         @li If `other` has shared ownership, then
     272              :         `*this` will acquire shared ownership.
     273              : 
     274              :         @par Complexity
     275              :         Constant.
     276              : 
     277              :         @par Exception Safety
     278              :         No-throw guarantee.
     279              : 
     280              :         @param other The pointer to construct from.
     281              :     */
     282      6352921 :     storage_ptr(
     283              :         storage_ptr const& other) noexcept
     284      6352921 :         : i_(other.i_)
     285              :     {
     286      6352921 :         addref();
     287      6352921 :     }
     288              : 
     289              :     /** Move assignment
     290              : 
     291              :         This function assigns a pointer that
     292              :         points to the same memory resource as `other`,
     293              :         with the same ownership:
     294              : 
     295              :         @li If `other` is non-owning, then `*this`
     296              :         will be be non-owning.
     297              : 
     298              :         @li If `other` has shared ownership, then
     299              :         ownership will be transferred to `*this`.
     300              : 
     301              :         After assignment, `other` will point
     302              :         to the [default memory resource].
     303              :         If `*this` previously had shared ownership,
     304              :         it is released before the function returns.
     305              : 
     306              :         @par Complexity
     307              :         Constant.
     308              : 
     309              :         @par Exception Safety
     310              :         No-throw guarantee.
     311              : 
     312              :         @param other The storage pointer to move.
     313              : 
     314              :         [default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
     315              :     */
     316              :     storage_ptr&
     317      2076649 :     operator=(
     318              :         storage_ptr&& other) noexcept
     319              :     {
     320      2076649 :         release();
     321      2076649 :         i_ = detail::exchange(other.i_, 0);
     322      2076649 :         return *this;
     323              :     }
     324              : 
     325              :     /** Copy assignment.
     326              : 
     327              :         This function assigns a pointer that
     328              :         points to the same memory resource as `other`,
     329              :         with the same ownership:
     330              : 
     331              :         @li If `other` is non-owning, then `*this`
     332              :         will be be non-owning.
     333              : 
     334              :         @li If `other` has shared ownership, then
     335              :         `*this` will acquire shared ownership.
     336              : 
     337              :         If `*this` previously had shared ownership,
     338              :         it is released before the function returns.
     339              : 
     340              :         @par Complexity
     341              :         Constant.
     342              : 
     343              :         @par Exception Safety
     344              :         No-throw guarantee.
     345              : 
     346              :         @param other The storage pointer to copy.
     347              :     */
     348              :     storage_ptr&
     349            1 :     operator=(
     350              :         storage_ptr const& other) noexcept
     351              :     {
     352            1 :         other.addref();
     353            1 :         release();
     354            1 :         i_ = other.i_;
     355            1 :         return *this;
     356              :     }
     357              : 
     358              :     /** Return `true` if ownership of the memory resource is shared.
     359              : 
     360              :         This function returns true for memory resources
     361              :         created using @ref make_shared_resource.
     362              :     */
     363              :     bool
     364     50344385 :     is_shared() const noexcept
     365              :     {
     366     50344385 :         return (i_ & 1) != 0;
     367              :     }
     368              : 
     369              :     /** Return `true` if calling `deallocate` on the memory resource has no effect.
     370              : 
     371              :         This function is used to determine if the deallocate
     372              :         function of the pointed to memory resource is trivial.
     373              :         The value of @ref is_deallocate_trivial is evaluated
     374              :         and saved when the memory resource is constructed
     375              :         and the type is known, before the type is erased.
     376              :     */
     377              :     bool
     378            1 :     is_deallocate_trivial() const noexcept
     379              :     {
     380            1 :         return (i_ & 2) != 0;
     381              :     }
     382              : 
     383              :     /** Return `true` if ownership of the memory resource is not shared and deallocate is trivial.
     384              : 
     385              :         This function is used to determine if calls to deallocate
     386              :         can effectively be skipped.
     387              : 
     388              :         @par Effects
     389              :         Returns `! this->is_shared() && this->is_deallocate_trivial()`
     390              :     */
     391              :     bool
     392      4323571 :     is_not_shared_and_deallocate_is_trivial() const noexcept
     393              :     {
     394      4323571 :         return (i_ & 3) == 2;
     395              :     }
     396              : 
     397              :     /** Return a pointer to the memory resource.
     398              : 
     399              :         This function returns a pointer to the
     400              :         referenced `boost::container::pmr::memory_resource`.
     401              : 
     402              :         @par Complexity
     403              :         Constant.
     404              : 
     405              :         @par Exception Safety
     406              :         No-throw guarantee.
     407              :     */
     408              :     container::pmr::memory_resource*
     409       653617 :     get() const noexcept
     410              :     {
     411       653617 :         if(i_ != 0)
     412              :             return reinterpret_cast<
     413       122565 :                 container::pmr::memory_resource*>(i_ & ~3);
     414       531052 :         return default_resource::get();
     415              :     }
     416              : 
     417              :     /** Return a pointer to the memory resource.
     418              : 
     419              :         This function returns a pointer to the
     420              :         referenced `boost::container::pmr::memory_resource`.
     421              : 
     422              :         @par Complexity
     423              :         Constant.
     424              : 
     425              :         @par Exception Safety
     426              :         No-throw guarantee.
     427              :     */
     428              :     container::pmr::memory_resource*
     429       649823 :     operator->() const noexcept
     430              :     {
     431       649823 :         return get();
     432              :     }
     433              : 
     434              :     /** Return a reference to the memory resource.
     435              : 
     436              :         This function returns a reference to the
     437              :         pointed-to `boost::container::pmr::memory_resource`.
     438              : 
     439              :         @par Complexity
     440              : 
     441              :         Constant.
     442              : 
     443              :         @par Exception Safety
     444              : 
     445              :         No-throw guarantee.
     446              :     */
     447              :     container::pmr::memory_resource&
     448         3762 :     operator*() const noexcept
     449              :     {
     450         3762 :         return *get();
     451              :     }
     452              : 
     453              :     template<class U, class... Args>
     454              :     friend
     455              :     storage_ptr
     456              :     make_shared_resource(Args&&... args);
     457              : };
     458              : 
     459              : #if defined(_MSC_VER)
     460              : # pragma warning( push )
     461              : # if !defined(__clang__) && _MSC_VER <= 1900
     462              : #  pragma warning( disable : 4702 )
     463              : # endif
     464              : #endif
     465              : /** Return shared ownership of a new, dynamically allocated memory resource.
     466              : 
     467              :     This function dynamically allocates a new memory resource
     468              :     as if by `operator new` that uses shared ownership. The
     469              :     lifetime of the memory resource will be extended until
     470              :     the last @ref storage_ptr which points to it is destroyed.
     471              : 
     472              :     @par Mandates
     473              :     @code
     474              :     std::is_base_of< boost::container::pmr::memory_resource, U >::value == true
     475              :     @endcode
     476              : 
     477              :     @par Complexity
     478              :     Same as `new U( std::forward<Args>(args)... )`.
     479              : 
     480              :     @par Exception Safety
     481              :     Strong guarantee.
     482              : 
     483              :     @tparam U The type of memory resource to create.
     484              : 
     485              :     @param args Parameters forwarded to the constructor of `U`.
     486              : */
     487              : template<class U, class... Args>
     488              : storage_ptr
     489           21 : make_shared_resource(Args&&... args)
     490              : {
     491              :     // If this generates an error, it means that
     492              :     // `T` is not a memory resource.
     493              :     BOOST_STATIC_ASSERT(
     494              :         std::is_base_of<
     495              :             container::pmr::memory_resource, U>::value);
     496           23 :     return storage_ptr(new
     497              :         detail::shared_resource_impl<U>(
     498           22 :             std::forward<Args>(args)...));
     499              : }
     500              : #if defined(_MSC_VER)
     501              : # pragma warning( pop )
     502              : #endif
     503              : 
     504              : /** Return true if two storage pointers point to the same memory resource.
     505              : 
     506              :     This function returns `true` if the
     507              :     `boost::container::pmr::memory_resource` objects pointed to by `lhs` and
     508              :     `rhs` have the same address.
     509              : */
     510              : inline
     511              : bool
     512            5 : operator==(
     513              :     storage_ptr const& lhs,
     514              :     storage_ptr const& rhs) noexcept
     515              : {
     516            5 :     return lhs.get() == rhs.get();
     517              : }
     518              : 
     519              : /** Return true if two storage pointers point to different memory resources.
     520              : 
     521              :     This function returns `true` if the
     522              :     `boost::container::pmr::memory_resource` objects pointed to by `lhs` and
     523              :     `rhs` have different addresses.
     524              : */
     525              : inline
     526              : bool
     527              : operator!=(
     528              :     storage_ptr const& lhs,
     529              :     storage_ptr const& rhs) noexcept
     530              : {
     531              :     return lhs.get() != rhs.get();
     532              : }
     533              : 
     534              : } // namespace json
     535              : } // namespace boost
     536              : 
     537              : #endif
        

Generated by: LCOV version 2.1