LCOV - code coverage report
Current view: top level - json - storage_ptr.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 68 68
Test Date: 2026-02-25 20:43:10 Functions: 96.8 % 31 30 1

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