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-03-05 09:04:27 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/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 HIT         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.3