100.00% Lines (3/3) 100.00% Functions (1/1)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com) 3   // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 5   // Distributed under the Boost Software License, Version 1.0. (See accompanying
6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/boostorg/json 8   // Official repository: https://github.com/boostorg/json
9   // 9   //
10   10  
11   #ifndef BOOST_JSON_MONOTONIC_RESOURCE_HPP 11   #ifndef BOOST_JSON_MONOTONIC_RESOURCE_HPP
12   #define BOOST_JSON_MONOTONIC_RESOURCE_HPP 12   #define BOOST_JSON_MONOTONIC_RESOURCE_HPP
13   13  
14   #include <boost/container/pmr/memory_resource.hpp> 14   #include <boost/container/pmr/memory_resource.hpp>
15   #include <boost/json/detail/config.hpp> 15   #include <boost/json/detail/config.hpp>
16   #include <boost/json/storage_ptr.hpp> 16   #include <boost/json/storage_ptr.hpp>
17   #include <cstddef> 17   #include <cstddef>
18   #include <utility> 18   #include <utility>
19   19  
20   namespace boost { 20   namespace boost {
21   namespace json { 21   namespace json {
22   22  
23   #ifdef _MSC_VER 23   #ifdef _MSC_VER
24   #pragma warning(push) 24   #pragma warning(push)
25   #pragma warning(disable: 4251) // class needs to have dll-interface to be used by clients of class 25   #pragma warning(disable: 4251) // class needs to have dll-interface to be used by clients of class
26   #pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class 26   #pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class
27   #endif 27   #endif
28   28  
29   //---------------------------------------------------------- 29   //----------------------------------------------------------
30   30  
31   /** A dynamically allocating resource with a trivial deallocate. 31   /** A dynamically allocating resource with a trivial deallocate.
32   32  
33   This memory resource is a special-purpose resource that releases allocated 33   This memory resource is a special-purpose resource that releases allocated
34   memory only when the resource is destroyed (or when @ref release is 34   memory only when the resource is destroyed (or when @ref release is
35   called). It has a trivial deallocate function; that is, the metafunction 35   called). It has a trivial deallocate function; that is, the metafunction
36   @ref is_deallocate_trivial returns `true`. 36   @ref is_deallocate_trivial returns `true`.
37   37  
38   The resource can be constructed with an initial buffer. If there is no 38   The resource can be constructed with an initial buffer. If there is no
39   initial buffer, or if the buffer is exhausted, subsequent dynamic 39   initial buffer, or if the buffer is exhausted, subsequent dynamic
40   allocations are made from the system heap. The size of buffers obtained in 40   allocations are made from the system heap. The size of buffers obtained in
41   this fashion follow a geometric progression. 41   this fashion follow a geometric progression.
42   42  
43   The purpose of this resource is to optimize the use case for performing 43   The purpose of this resource is to optimize the use case for performing
44   many allocations, followed by deallocating everything at once. This is 44   many allocations, followed by deallocating everything at once. This is
45   precisely the pattern of memory allocation which occurs when parsing: 45   precisely the pattern of memory allocation which occurs when parsing:
46   allocation is performed for each parsed element, and when the the resulting 46   allocation is performed for each parsed element, and when the the resulting
47   @ref value is no longer needed, the entire structure is destroyed. However, 47   @ref value is no longer needed, the entire structure is destroyed. However,
48   it is not suited for modifying the value after parsing is complete; 48   it is not suited for modifying the value after parsing is complete;
49   reallocations waste memory, since the older buffer is not reclaimed until 49   reallocations waste memory, since the older buffer is not reclaimed until
50   the resource is destroyed. 50   the resource is destroyed.
51   51  
52   @par Example 52   @par Example
53   53  
54   This parses a JSON text into a value which uses a local stack buffer, then 54   This parses a JSON text into a value which uses a local stack buffer, then
55   prints the result. 55   prints the result.
56   56  
57   @code 57   @code
58   unsigned char buf[ 4000 ]; 58   unsigned char buf[ 4000 ];
59   monotonic_resource mr( buf ); 59   monotonic_resource mr( buf );
60   60  
61   // Parse the string, using our memory resource 61   // Parse the string, using our memory resource
62   auto const jv = parse( "[1,2,3]", &mr ); 62   auto const jv = parse( "[1,2,3]", &mr );
63   63  
64   // Print the JSON 64   // Print the JSON
65   std::cout << jv; 65   std::cout << jv;
66   @endcode 66   @endcode
67   67  
68   @note The total amount of memory dynamically allocated is monotonically 68   @note The total amount of memory dynamically allocated is monotonically
69   increasing; That is, it never decreases. 69   increasing; That is, it never decreases.
70   70  
71   @par Thread Safety 71   @par Thread Safety
72   Members of the same instance may not be 72   Members of the same instance may not be
73   called concurrently. 73   called concurrently.
74   74  
75   @see 75   @see
76   https://en.wikipedia.org/wiki/Region-based_memory_management 76   https://en.wikipedia.org/wiki/Region-based_memory_management
77   */ 77   */
78   class 78   class
79   BOOST_JSON_DECL 79   BOOST_JSON_DECL
80   BOOST_SYMBOL_VISIBLE 80   BOOST_SYMBOL_VISIBLE
81   monotonic_resource final 81   monotonic_resource final
82   : public container::pmr::memory_resource 82   : public container::pmr::memory_resource
83   { 83   {
84   struct block; 84   struct block;
85   struct block_base 85   struct block_base
86   { 86   {
87   void* p; 87   void* p;
88   std::size_t avail; 88   std::size_t avail;
89   std::size_t size; 89   std::size_t size;
90   block_base* next; 90   block_base* next;
91   }; 91   };
92   92  
93   block_base buffer_; 93   block_base buffer_;
94   block_base* head_ = &buffer_; 94   block_base* head_ = &buffer_;
95   std::size_t next_size_ = 1024; 95   std::size_t next_size_ = 1024;
96   storage_ptr upstream_; 96   storage_ptr upstream_;
97   97  
98   static constexpr std::size_t min_size_ = 1024; 98   static constexpr std::size_t min_size_ = 1024;
99   inline static constexpr std::size_t max_size(); 99   inline static constexpr std::size_t max_size();
100   inline static std::size_t round_pow2( 100   inline static std::size_t round_pow2(
101   std::size_t n) noexcept; 101   std::size_t n) noexcept;
102   inline static std::size_t next_pow2( 102   inline static std::size_t next_pow2(
103   std::size_t n) noexcept; 103   std::size_t n) noexcept;
104   104  
105   public: 105   public:
106   /** Assignment operator. 106   /** Assignment operator.
107   107  
108   Copy assignment operator is deleted. This type is not copyable or 108   Copy assignment operator is deleted. This type is not copyable or
109   movable. 109   movable.
110   */ 110   */
111   monotonic_resource& operator=( 111   monotonic_resource& operator=(
112   monotonic_resource const&) = delete; 112   monotonic_resource const&) = delete;
113   113  
114   /** Destructor. 114   /** Destructor.
115   115  
116   Deallocates all the memory owned by this resource. 116   Deallocates all the memory owned by this resource.
117   117  
118   @par Effects 118   @par Effects
119   @code 119   @code
120   release(); 120   release();
121   @endcode 121   @endcode
122   122  
123   @par Complexity 123   @par Complexity
124   Linear in the number of deallocations performed. 124   Linear in the number of deallocations performed.
125   125  
126   @par Exception Safety 126   @par Exception Safety
127   No-throw guarantee. 127   No-throw guarantee.
128   */ 128   */
129   ~monotonic_resource(); 129   ~monotonic_resource();
130   130  
131   /** Constructors. 131   /** Constructors.
132   132  
133   Construct the resource. 133   Construct the resource.
134   134  
135   @li **(1)** indicates that the first internal dynamic allocation shall 135   @li **(1)** indicates that the first internal dynamic allocation shall
136   be at least `initial_size` bytes. 136   be at least `initial_size` bytes.
137   @li **(2)**--**(5)** indicate that subsequent allocations should use 137   @li **(2)**--**(5)** indicate that subsequent allocations should use
138   the specified caller-owned buffer. When this buffer is exhausted, 138   the specified caller-owned buffer. When this buffer is exhausted,
139   dynamic allocations from the upstream resource are made. 139   dynamic allocations from the upstream resource are made.
140   @li **(6)** copy constructor is deleted. This type is not copyable or 140   @li **(6)** copy constructor is deleted. This type is not copyable or
141   movable. 141   movable.
142   142  
143   None of the constructors performs any dynamic allocations. 143   None of the constructors performs any dynamic allocations.
144   144  
145   @par Complexity 145   @par Complexity
146   Constant. 146   Constant.
147   147  
148   @par Exception Safety 148   @par Exception Safety
149   No-throw guarantee. 149   No-throw guarantee.
150   150  
151   @param initial_size The size of the first internal dynamic allocation. 151   @param initial_size The size of the first internal dynamic allocation.
152   If this is lower than the implementation-defined lower limit, 152   If this is lower than the implementation-defined lower limit,
153   then the lower limit is used instead. 153   then the lower limit is used instead.
154   @param upstream An optional upstream memory resource to use for 154   @param upstream An optional upstream memory resource to use for
155   performing internal dynamic allocations. If this parameter is 155   performing internal dynamic allocations. If this parameter is
156   omitted, the \<\<default_memory_resource,default resource\>\> is 156   omitted, the \<\<default_memory_resource,default resource\>\> is
157   used. 157   used.
158   158  
159   @{ 159   @{
160   */ 160   */
161   explicit 161   explicit
162   monotonic_resource( 162   monotonic_resource(
163   std::size_t initial_size = 1024, 163   std::size_t initial_size = 1024,
164   storage_ptr upstream = {}) noexcept; 164   storage_ptr upstream = {}) noexcept;
165   165  
166   /** Overload 166   /** Overload
167   167  
168   @param buffer The buffer to use. Ownership is not transferred; the 168   @param buffer The buffer to use. Ownership is not transferred; the
169   caller is responsible for ensuring that the lifetime of the 169   caller is responsible for ensuring that the lifetime of the
170   buffer extends until the resource is destroyed. 170   buffer extends until the resource is destroyed.
171   @param size The number of valid bytes pointed to by `buffer`. 171   @param size The number of valid bytes pointed to by `buffer`.
172   @param upstream 172   @param upstream
173   */ 173   */
174   monotonic_resource( 174   monotonic_resource(
175   unsigned char* buffer, 175   unsigned char* buffer,
176   std::size_t size, 176   std::size_t size,
177   storage_ptr upstream = {}) noexcept; 177   storage_ptr upstream = {}) noexcept;
178   178  
179   #if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS) 179   #if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
180   /// Overload 180   /// Overload
181   monotonic_resource( 181   monotonic_resource(
182   std::byte* buffer, 182   std::byte* buffer,
183   std::size_t size, 183   std::size_t size,
184   storage_ptr upstream) noexcept 184   storage_ptr upstream) noexcept
185   : monotonic_resource(reinterpret_cast< 185   : monotonic_resource(reinterpret_cast<
186   unsigned char*>(buffer), size, 186   unsigned char*>(buffer), size,
187   std::move(upstream)) 187   std::move(upstream))
188   { 188   {
189   } 189   }
190   #endif 190   #endif
191   191  
192   /// Overload 192   /// Overload
193   template<std::size_t N> 193   template<std::size_t N>
194   explicit 194   explicit
HITCBC 195   2 monotonic_resource( 195   2 monotonic_resource(
196   unsigned char(&buffer)[N], 196   unsigned char(&buffer)[N],
197   storage_ptr upstream = {}) noexcept 197   storage_ptr upstream = {}) noexcept
198   : monotonic_resource(&buffer[0], 198   : monotonic_resource(&buffer[0],
HITCBC 199   2 N, std::move(upstream)) 199   2 N, std::move(upstream))
200   { 200   {
HITCBC 201   2 } 201   2 }
202   202  
203   #if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS) 203   #if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
204   /// Overload 204   /// Overload
205   template<std::size_t N> 205   template<std::size_t N>
206   explicit 206   explicit
207   monotonic_resource( 207   monotonic_resource(
208   std::byte(&buffer)[N], 208   std::byte(&buffer)[N],
209   storage_ptr upstream = {}) noexcept 209   storage_ptr upstream = {}) noexcept
210   : monotonic_resource(&buffer[0], 210   : monotonic_resource(&buffer[0],
211   N, std::move(upstream)) 211   N, std::move(upstream))
212   { 212   {
213   } 213   }
214   #endif 214   #endif
215   215  
216   #ifndef BOOST_JSON_DOCS 216   #ifndef BOOST_JSON_DOCS
217   // Safety net for accidental buffer overflows 217   // Safety net for accidental buffer overflows
218   template<std::size_t N> 218   template<std::size_t N>
219   monotonic_resource( 219   monotonic_resource(
220   unsigned char(&buffer)[N], 220   unsigned char(&buffer)[N],
221   std::size_t n, 221   std::size_t n,
222   storage_ptr upstream = {}) noexcept 222   storage_ptr upstream = {}) noexcept
223   : monotonic_resource(&buffer[0], 223   : monotonic_resource(&buffer[0],
224   n, std::move(upstream)) 224   n, std::move(upstream))
225   { 225   {
226   // If this goes off, check your parameters 226   // If this goes off, check your parameters
227   // closely, chances are you passed an array 227   // closely, chances are you passed an array
228   // thinking it was a pointer. 228   // thinking it was a pointer.
229   BOOST_ASSERT(n <= N); 229   BOOST_ASSERT(n <= N);
230   } 230   }
231   231  
232   #ifdef __cpp_lib_byte 232   #ifdef __cpp_lib_byte
233   // Safety net for accidental buffer overflows 233   // Safety net for accidental buffer overflows
234   template<std::size_t N> 234   template<std::size_t N>
235   monotonic_resource( 235   monotonic_resource(
236   std::byte(&buffer)[N], 236   std::byte(&buffer)[N],
237   std::size_t n, 237   std::size_t n,
238   storage_ptr upstream = {}) noexcept 238   storage_ptr upstream = {}) noexcept
239   : monotonic_resource(&buffer[0], 239   : monotonic_resource(&buffer[0],
240   n, std::move(upstream)) 240   n, std::move(upstream))
241   { 241   {
242   // If this goes off, check your parameters 242   // If this goes off, check your parameters
243   // closely, chances are you passed an array 243   // closely, chances are you passed an array
244   // thinking it was a pointer. 244   // thinking it was a pointer.
245   BOOST_ASSERT(n <= N); 245   BOOST_ASSERT(n <= N);
246   } 246   }
247   #endif 247   #endif
248   #endif 248   #endif
249   249  
250   /// Overload 250   /// Overload
251   monotonic_resource( 251   monotonic_resource(
252   monotonic_resource const&) = delete; 252   monotonic_resource const&) = delete;
253   /// @} 253   /// @}
254   254  
255   /** Release all allocated memory. 255   /** Release all allocated memory.
256   256  
257   This function deallocates all allocated memory. 257   This function deallocates all allocated memory.
258   If an initial buffer was provided upon construction, 258   If an initial buffer was provided upon construction,
259   then all of the bytes will be available again for 259   then all of the bytes will be available again for
260   allocation. Allocated memory is deallocated even 260   allocation. Allocated memory is deallocated even
261   if deallocate has not been called for some of 261   if deallocate has not been called for some of
262   the allocated blocks. 262   the allocated blocks.
263   263  
264   @par Complexity 264   @par Complexity
265   Linear in the number of deallocations performed. 265   Linear in the number of deallocations performed.
266   266  
267   @par Exception Safety 267   @par Exception Safety
268   No-throw guarantee. 268   No-throw guarantee.
269   */ 269   */
270   void 270   void
271   release() noexcept; 271   release() noexcept;
272   272  
273   protected: 273   protected:
274   #ifndef BOOST_JSON_DOCS 274   #ifndef BOOST_JSON_DOCS
275   void* 275   void*
276   do_allocate( 276   do_allocate(
277   std::size_t n, 277   std::size_t n,
278   std::size_t align) override; 278   std::size_t align) override;
279   279  
280   void 280   void
281   do_deallocate( 281   do_deallocate(
282   void* p, 282   void* p,
283   std::size_t n, 283   std::size_t n,
284   std::size_t align) override; 284   std::size_t align) override;
285   285  
286   bool 286   bool
287   do_is_equal( 287   do_is_equal(
288   memory_resource const& mr) const noexcept override; 288   memory_resource const& mr) const noexcept override;
289   #endif 289   #endif
290   }; 290   };
291   291  
292   #ifdef _MSC_VER 292   #ifdef _MSC_VER
293   #pragma warning(pop) 293   #pragma warning(pop)
294   #endif 294   #endif
295   295  
296   template<> 296   template<>
297   struct is_deallocate_trivial< 297   struct is_deallocate_trivial<
298   monotonic_resource> 298   monotonic_resource>
299   { 299   {
300   static constexpr bool value = true; 300   static constexpr bool value = true;
301   }; 301   };
302   302  
303   } // namespace json 303   } // namespace json
304   } // namespace boost 304   } // namespace boost
305   305  
306   #endif 306   #endif