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

Generated by: LCOV version 2.1