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 % 74 74
Test Date: 2026-03-05 11:14:12 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                 :     void* p_;
      87                 : 
      88                 :     shared_resource*
      89 HIT         302 :     get_shared() const noexcept
      90                 :     {
      91             302 :         auto const i = reinterpret_cast<std::uintptr_t>(p_);
      92             302 :         auto const c_ptr = reinterpret_cast<unsigned char*>(p_) - (i & 3);
      93                 :         return static_cast<shared_resource*>(
      94             302 :             reinterpret_cast<container::pmr::memory_resource*>(c_ptr));
      95                 :     }
      96                 : 
      97                 :     void
      98         6352730 :     addref() const noexcept
      99                 :     {
     100         6352730 :         if(is_shared())
     101             141 :             get_shared()->refs.fetch_add(
     102                 :                 1, std::memory_order_relaxed);
     103         6352730 :     }
     104                 : 
     105                 :     void
     106        43990763 :     release() const noexcept
     107                 :     {
     108        43990763 :         if(is_shared())
     109                 :         {
     110             161 :             auto const p = get_shared();
     111             161 :             if(p->refs.fetch_sub(1,
     112             161 :                     std::memory_order_acq_rel) == 1)
     113              20 :                 delete p;
     114                 :         }
     115        43990763 :     }
     116                 : 
     117                 :     template<class T>
     118              20 :     storage_ptr(
     119                 :         detail::shared_resource_impl<T>* p) noexcept
     120              20 :         : p_(reinterpret_cast<unsigned char*>(
     121                 :                 static_cast<container::pmr::memory_resource*>(p))
     122              20 :              + 1 + (json::is_deallocate_trivial<T>::value ? 2 : 0))
     123                 :     {
     124              20 :         BOOST_ASSERT(p);
     125              20 :     }
     126                 : 
     127                 : public:
     128                 :     /** Destructor.
     129                 : 
     130                 :         If the pointer has shared ownership of the resource, the shared
     131                 :         ownership is released. If this is the last owned copy, the memory
     132                 :         resource is destroyed.
     133                 : 
     134                 :         @par Complexity
     135                 :         Constant.
     136                 : 
     137                 :         @par Exception Safety
     138                 :         No-throw guarantee.
     139                 :     */
     140        41914113 :     ~storage_ptr() noexcept
     141                 :     {
     142        41914113 :         release();
     143        41914113 :     }
     144                 : 
     145                 :     /** Constructors.
     146                 : 
     147                 :         @li **(1)** constructs a non-owning pointer that refers to the
     148                 :         \<\<default_memory_resource,default memory resource\>\>.
     149                 : 
     150                 :         @li **(2)** constructs a non-owning pointer that points to the memory
     151                 :         resource `r`.
     152                 : 
     153                 :         @li **(3)** constructs a non-owning pointer that points to the same
     154                 :         memory resource as `alloc`, obtained by calling `alloc.resource()`.
     155                 : 
     156                 :         @li **(4)**, **(5)** construct a pointer to the same memory resource as
     157                 :         `other`, with the same ownership.
     158                 : 
     159                 :         After **(4)** and **(5)** if `other` was owning, then the constructed
     160                 :         pointer is also owning. In particular, **(4)** transfers ownership to
     161                 :         the constructed pointer while **(5)** causes it to share ownership with
     162                 :         `other`. Otherwise, and with other overloads the constructed pointer
     163                 :         doesn't own its memory resource and the caller is responsible for
     164                 :         maintaining the lifetime of the pointed-to
     165                 :         @ref boost::container::pmr::memory_resource.
     166                 : 
     167                 :         After **(4)**, `other` will point to the default memory resource.
     168                 : 
     169                 :         @par Constraints
     170                 :         @code
     171                 :         std::is_convertible< T*, boost::container::pmr::memory_resource* >::value == true
     172                 :         @endcode
     173                 : 
     174                 :         @pre
     175                 :         @code
     176                 :         r != nullptr
     177                 :         @endcode
     178                 : 
     179                 :         @par Complexity
     180                 :         Constant.
     181                 : 
     182                 :         @par Exception Safety
     183                 :         No-throw guarantee.
     184                 : 
     185                 :         @{
     186                 :     */
     187        14653478 :     storage_ptr() noexcept
     188        14653478 :         : p_(nullptr)
     189                 :     {
     190        14653478 :     }
     191                 : 
     192                 :     /** Overload
     193                 : 
     194                 :         @tparam T The type of memory resource.
     195                 :         @param r A non-null pointer to the memory resource to use.
     196                 :     */
     197                 :     template<class T
     198                 : #ifndef BOOST_JSON_DOCS
     199                 :         , class = typename std::enable_if<
     200                 :             std::is_convertible<T*,
     201                 :                 container::pmr::memory_resource*>::value>::type
     202                 : #endif
     203                 :     >
     204           57222 :     storage_ptr(T* r) noexcept
     205           57222 :         : p_(reinterpret_cast<unsigned char*>(
     206                 :                 static_cast<container::pmr::memory_resource*>(r))
     207              17 :              + (json::is_deallocate_trivial<T>::value ? 2 : 0))
     208                 :     {
     209           57222 :         BOOST_ASSERT(r);
     210           57222 :     }
     211                 : 
     212                 :     /** Overload
     213                 : 
     214                 :         @tparam V Any type.
     215                 :         @param alloc A @ref boost::container::pmr::polymorphic_allocator to
     216                 :         construct from.
     217                 :     */
     218                 :     template<class V>
     219              10 :     storage_ptr(
     220                 :         container::pmr::polymorphic_allocator<V> const& alloc) noexcept
     221              10 :         : p_(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 :         : p_(detail::exchange(other.p_, nullptr))
     232                 :     {
     233        22965882 :     }
     234                 : 
     235                 :     /** Overload
     236                 : 
     237                 :         @param other
     238                 :     */
     239         6352729 :     storage_ptr(
     240                 :         storage_ptr const& other) noexcept
     241         6352729 :         : p_(other.p_)
     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 :         p_ = detail::exchange(other.p_, nullptr);
     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 :         p_ = other.p_;
     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 :         auto i = reinterpret_cast<std::uintptr_t>(p_);
     304        50343494 :         return (i & 1) != 0;
     305                 :     }
     306                 : 
     307                 :     /** Check if calling `deallocate` on the memory resource has no effect.
     308                 : 
     309                 :         This function is used to determine if the deallocate function of the
     310                 :         pointed to memory resource is trivial. The value of @ref
     311                 :         is_deallocate_trivial is evaluated and saved when the memory resource
     312                 :         is constructed and the type is known, before the type is erased.
     313                 :     */
     314                 :     bool
     315               1 :     is_deallocate_trivial() const noexcept
     316                 :     {
     317               1 :         auto i = reinterpret_cast<std::uintptr_t>(p_);
     318               1 :         return (i & 2) != 0;
     319                 :     }
     320                 : 
     321                 :     /** Check if ownership of the memory resource is not shared and deallocate is trivial.
     322                 : 
     323                 :         This function is used to determine if calls to deallocate can
     324                 :         effectively be skipped. Equivalent to `! is_shared() &&
     325                 :         is_deallocate_trivial()`.
     326                 :     */
     327                 :     bool
     328         4323577 :     is_not_shared_and_deallocate_is_trivial() const noexcept
     329                 :     {
     330         4323577 :         auto i = reinterpret_cast<std::uintptr_t>(p_);
     331         4323577 :         return (i & 3) == 2;
     332                 :     }
     333                 : 
     334                 :     /** Return a pointer to the memory resource.
     335                 : 
     336                 :         This function returns a pointer to the
     337                 :         referenced @ref boost::container::pmr::memory_resource.
     338                 : 
     339                 :         @par Complexity
     340                 :         Constant.
     341                 : 
     342                 :         @par Exception Safety
     343                 :         No-throw guarantee.
     344                 :     */
     345                 :     container::pmr::memory_resource*
     346          653431 :     get() const noexcept
     347                 :     {
     348          653431 :         if(!p_)
     349          530848 :             return default_resource::get();
     350                 : 
     351          122583 :         auto const i = reinterpret_cast<std::uintptr_t>(p_);
     352          122583 :         auto const c_ptr = reinterpret_cast<unsigned char*>(p_) - (i & 3);
     353          122583 :         return reinterpret_cast<container::pmr::memory_resource*>(c_ptr);
     354                 :     }
     355                 : 
     356                 :     /** Return a pointer to the memory resource.
     357                 : 
     358                 :         This function returns a pointer to the referenced @ref
     359                 :         boost::container::pmr::memory_resource.
     360                 : 
     361                 :         @par Complexity
     362                 :         Constant.
     363                 : 
     364                 :         @par Exception Safety
     365                 :         No-throw guarantee.
     366                 :     */
     367                 :     container::pmr::memory_resource*
     368          649785 :     operator->() const noexcept
     369                 :     {
     370          649785 :         return get();
     371                 :     }
     372                 : 
     373                 :     /** Return a reference to the memory resource.
     374                 : 
     375                 :         This function returns a reference to the pointed-to @ref
     376                 :         boost::container::pmr::memory_resource.
     377                 : 
     378                 :         @par Complexity
     379                 : 
     380                 :         Constant.
     381                 : 
     382                 :         @par Exception Safety
     383                 : 
     384                 :         No-throw guarantee.
     385                 :     */
     386                 :     container::pmr::memory_resource&
     387            3614 :     operator*() const noexcept
     388                 :     {
     389            3614 :         return *get();
     390                 :     }
     391                 : 
     392                 :     template<class U, class... Args>
     393                 :     friend
     394                 :     storage_ptr
     395                 :     make_shared_resource(Args&&... args);
     396                 : };
     397                 : 
     398                 : #if defined(_MSC_VER)
     399                 : # pragma warning( push )
     400                 : # if !defined(__clang__) && _MSC_VER <= 1900
     401                 : #  pragma warning( disable : 4702 )
     402                 : # endif
     403                 : #endif
     404                 : 
     405                 : /** Return a pointer that owns a new, dynamically allocated memory resource.
     406                 : 
     407                 :     This function dynamically allocates a new memory resource as if by
     408                 :     `operator new` that uses shared ownership. The lifetime of the memory
     409                 :     resource will be extended until the last @ref storage_ptr which points to
     410                 :     it is destroyed.
     411                 : 
     412                 :     @par Constraints
     413                 :     @code
     414                 :     std::is_base_of< boost::container::pmr::memory_resource, U >::value == true
     415                 :     @endcode
     416                 : 
     417                 :     @par Complexity
     418                 :     Same as `new U( std::forward<Args>(args)... )`.
     419                 : 
     420                 :     @par Exception Safety
     421                 :     Strong guarantee.
     422                 : 
     423                 :     @tparam U The type of memory resource to create.
     424                 : 
     425                 :     @param args Parameters forwarded to the constructor of `U`.
     426                 : */
     427                 : template<class U, class... Args>
     428                 : storage_ptr
     429              21 : make_shared_resource(Args&&... args)
     430                 : {
     431                 :     // If this generates an error, it means that
     432                 :     // `T` is not a memory resource.
     433                 :     BOOST_CORE_STATIC_ASSERT((
     434                 :         std::is_base_of<container::pmr::memory_resource, U>::value));
     435              23 :     return storage_ptr(new
     436                 :         detail::shared_resource_impl<U>(
     437              22 :             std::forward<Args>(args)...));
     438                 : }
     439                 : #if defined(_MSC_VER)
     440                 : # pragma warning( pop )
     441                 : #endif
     442                 : 
     443                 : /// Overload
     444                 : inline
     445                 : bool
     446               5 : operator==(
     447                 :     storage_ptr const& lhs,
     448                 :     storage_ptr const& rhs) noexcept
     449                 : {
     450               5 :     return lhs.get() == rhs.get();
     451                 : }
     452                 : 
     453                 : /// Overload
     454                 : inline
     455                 : bool
     456                 : operator!=(
     457                 :     storage_ptr const& lhs,
     458                 :     storage_ptr const& rhs) noexcept
     459                 : {
     460                 :     return lhs.get() != rhs.get();
     461                 : }
     462                 : 
     463                 : } // namespace json
     464                 : } // namespace boost
     465                 : 
     466                 : #endif
        

Generated by: LCOV version 2.3