100.00% Lines (11/11) 100.00% Functions (5/5)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/boostorg/url 7   // Official repository: https://github.com/boostorg/url
8   // 8   //
9   9  
10   #ifndef BOOST_URL_GRAMMAR_RECYCLED_HPP 10   #ifndef BOOST_URL_GRAMMAR_RECYCLED_HPP
11   #define BOOST_URL_GRAMMAR_RECYCLED_HPP 11   #define BOOST_URL_GRAMMAR_RECYCLED_HPP
12   12  
13   #include <boost/url/detail/config.hpp> 13   #include <boost/url/detail/config.hpp>
14   #include <boost/url/grammar/detail/recycled.hpp> 14   #include <boost/url/grammar/detail/recycled.hpp>
15   #include <atomic> 15   #include <atomic>
16   #include <cstddef> 16   #include <cstddef>
17   #include <type_traits> 17   #include <type_traits>
18   #include <stddef.h> // ::max_align_t 18   #include <stddef.h> // ::max_align_t
19   19  
20   #if !defined(BOOST_URL_DISABLE_THREADS) 20   #if !defined(BOOST_URL_DISABLE_THREADS)
21   # include <mutex> 21   # include <mutex>
22   #endif 22   #endif
23   23  
24   namespace boost { 24   namespace boost {
25   namespace urls { 25   namespace urls {
26   namespace grammar { 26   namespace grammar {
27   27  
28   /** Provides an aligned storage buffer aligned for T 28   /** Provides an aligned storage buffer aligned for T
29   29  
30   @code 30   @code
31   template<class T> 31   template<class T>
32   struct aligned_storage 32   struct aligned_storage
33   { 33   {
34   /// Return a pointer to the aligned storage area 34   /// Return a pointer to the aligned storage area
35   void* addr() noexcept; 35   void* addr() noexcept;
36   36  
37   /// Return a pointer to the aligned storage area 37   /// Return a pointer to the aligned storage area
38   void const* addr() const noexcept; 38   void const* addr() const noexcept;
39   }; 39   };
40   @endcode 40   @endcode
41   41  
42   */ 42   */
43   template<class T> 43   template<class T>
44   using aligned_storage = 44   using aligned_storage =
45   implementation_defined::aligned_storage_impl< 45   implementation_defined::aligned_storage_impl<
46   implementation_defined::nearest_pow2(sizeof(T), 64), 46   implementation_defined::nearest_pow2(sizeof(T), 64),
47   (alignof(::max_align_t) > alignof(T)) ? 47   (alignof(::max_align_t) > alignof(T)) ?
48   alignof(::max_align_t) : alignof(T)>; 48   alignof(::max_align_t) : alignof(T)>;
49   49  
50   //------------------------------------------------ 50   //------------------------------------------------
51   51  
52   /** A thread-safe collection of instances of T 52   /** A thread-safe collection of instances of T
53   53  
54   Instances of this type may be used to control 54   Instances of this type may be used to control
55   where recycled instances of T come from when 55   where recycled instances of T come from when
56   used with @ref recycled_ptr. 56   used with @ref recycled_ptr.
57   57  
58   @par Example 58   @par Example
59   @code 59   @code
60   static recycled< std::string > bin; 60   static recycled< std::string > bin;
61   61  
62   recycled_ptr< std::string > ps( bin ); 62   recycled_ptr< std::string > ps( bin );
63   63  
64   // Put the string into a known state 64   // Put the string into a known state
65   ps->clear(); 65   ps->clear();
66   @endcode 66   @endcode
67   67  
68   @see 68   @see
69   @ref recycled_ptr. 69   @ref recycled_ptr.
70   */ 70   */
71   template<class T> 71   template<class T>
72   class recycled 72   class recycled
73   { 73   {
74   public: 74   public:
75   /** Destructor 75   /** Destructor
76   76  
77   All recycled instances of T are destroyed. 77   All recycled instances of T are destroyed.
78   Undefined behavior results if there are 78   Undefined behavior results if there are
79   any @ref recycled_ptr which reference 79   any @ref recycled_ptr which reference
80   this recycle bin. 80   this recycle bin.
81   */ 81   */
82   ~recycled(); 82   ~recycled();
83   83  
84   /** Constructor 84   /** Constructor
85   */ 85   */
86   constexpr recycled() = default; 86   constexpr recycled() = default;
87   87  
88   private: 88   private:
89   template<class> 89   template<class>
90   friend class recycled_ptr; 90   friend class recycled_ptr;
91   91  
92   struct U 92   struct U
93   { 93   {
94   T t; 94   T t;
95   U* next = nullptr; 95   U* next = nullptr;
96   96  
97   #if !defined(BOOST_URL_DISABLE_THREADS) 97   #if !defined(BOOST_URL_DISABLE_THREADS)
98   std::atomic< 98   std::atomic<
99   std::size_t> refs; 99   std::size_t> refs;
100   #else 100   #else
101   std::size_t refs; 101   std::size_t refs;
102   #endif 102   #endif
103   103  
104   104  
HITCBC 105   7 U() 105   7 U()
HITCBC 106   7 : refs{1} 106   7 : refs{1}
107   { 107   {
HITCBC 108   7 } 108   7 }
109   }; 109   };
110   110  
111   struct report; 111   struct report;
112   112  
113   U* acquire(); 113   U* acquire();
114   void release(U* u) noexcept; 114   void release(U* u) noexcept;
115   115  
116   U* head_ = nullptr; 116   U* head_ = nullptr;
117   117  
118   #if !defined(BOOST_URL_DISABLE_THREADS) 118   #if !defined(BOOST_URL_DISABLE_THREADS)
119   std::mutex m_; 119   std::mutex m_;
120   #endif 120   #endif
121   }; 121   };
122   122  
123   //------------------------------------------------ 123   //------------------------------------------------
124   124  
125   /** A pointer to a shared instance of T 125   /** A pointer to a shared instance of T
126   126  
127   This is a smart pointer container which can 127   This is a smart pointer container which can
128   acquire shared ownership of an instance of 128   acquire shared ownership of an instance of
129   `T` upon or after construction. The instance 129   `T` upon or after construction. The instance
130   is guaranteed to be in a valid, but unknown 130   is guaranteed to be in a valid, but unknown
131   state. Every recycled pointer references 131   state. Every recycled pointer references
132   a valid recycle bin. 132   a valid recycle bin.
133   133  
134   @par Example 134   @par Example
135   @code 135   @code
136   static recycled< std::string > bin; 136   static recycled< std::string > bin;
137   137  
138   recycled_ptr< std::string > ps( bin ); 138   recycled_ptr< std::string > ps( bin );
139   139  
140   // Put the string into a known state 140   // Put the string into a known state
141   ps->clear(); 141   ps->clear();
142   @endcode 142   @endcode
143   143  
144   @tparam T the type of object to 144   @tparam T the type of object to
145   acquire, which must be 145   acquire, which must be
146   <em>DefaultConstructible</em>. 146   <em>DefaultConstructible</em>.
147   */ 147   */
148   template<class T> 148   template<class T>
149   class recycled_ptr 149   class recycled_ptr
150   { 150   {
151   // T must be default constructible! 151   // T must be default constructible!
152   static_assert( 152   static_assert(
153   std::is_default_constructible<T>::value, 153   std::is_default_constructible<T>::value,
154   "T must be DefaultConstructible"); 154   "T must be DefaultConstructible");
155   155  
156   friend class recycled<T>; 156   friend class recycled<T>;
157   157  
158   using B = recycled<T>; 158   using B = recycled<T>;
159   using U = typename B::U; 159   using U = typename B::U;
160   160  
161   B* bin_ = nullptr; 161   B* bin_ = nullptr;
162   U* p_ = nullptr; 162   U* p_ = nullptr;
163   163  
164   public: 164   public:
165   /** Destructor 165   /** Destructor
166   166  
167   If this is not empty, shared ownership 167   If this is not empty, shared ownership
168   of the pointee is released. If this was 168   of the pointee is released. If this was
169   the last reference, the object is 169   the last reference, the object is
170   returned to the original recycle bin. 170   returned to the original recycle bin.
171   171  
172   @par Effects 172   @par Effects
173   @code 173   @code
174   this->release(); 174   this->release();
175   @endcode 175   @endcode
176   */ 176   */
177   ~recycled_ptr(); 177   ~recycled_ptr();
178   178  
179   /** Constructor 179   /** Constructor
180   180  
181   Upon construction, this acquires 181   Upon construction, this acquires
182   exclusive access to an object of type 182   exclusive access to an object of type
183   `T` which is either recycled from the 183   `T` which is either recycled from the
184   specified bin, or newly allocated. 184   specified bin, or newly allocated.
185   The object is in an unknown but 185   The object is in an unknown but
186   valid state. 186   valid state.
187   187  
188   @par Example 188   @par Example
189   @code 189   @code
190   static recycled< std::string > bin; 190   static recycled< std::string > bin;
191   191  
192   recycled_ptr< std::string > ps( bin ); 192   recycled_ptr< std::string > ps( bin );
193   193  
194   // Put the string into a known state 194   // Put the string into a known state
195   ps->clear(); 195   ps->clear();
196   @endcode 196   @endcode
197   197  
198   @par Postconditions 198   @par Postconditions
199   @code 199   @code
200   &this->bin() == &bin && ! this->empty() 200   &this->bin() == &bin && ! this->empty()
201   @endcode 201   @endcode
202   202  
203   @param bin The recycle bin to use 203   @param bin The recycle bin to use
204   204  
205   @see 205   @see
206   @ref recycled. 206   @ref recycled.
207   */ 207   */
208   explicit 208   explicit
209   recycled_ptr(recycled<T>& bin); 209   recycled_ptr(recycled<T>& bin);
210   210  
211   /** Constructor 211   /** Constructor
212   212  
213   After construction, this is empty and 213   After construction, this is empty and
214   refers to the specified recycle bin. 214   refers to the specified recycle bin.
215   215  
216   @par Example 216   @par Example
217   @code 217   @code
218   static recycled< std::string > bin; 218   static recycled< std::string > bin;
219   219  
220   recycled_ptr< std::string > ps( bin, nullptr ); 220   recycled_ptr< std::string > ps( bin, nullptr );
221   221  
222   // Acquire a string and put it into a known state 222   // Acquire a string and put it into a known state
223   ps->acquire(); 223   ps->acquire();
224   ps->clear(); 224   ps->clear();
225   @endcode 225   @endcode
226   226  
227   @par Postconditions 227   @par Postconditions
228   @code 228   @code
229   &this->bin() == &bin && this->empty() 229   &this->bin() == &bin && this->empty()
230   @endcode 230   @endcode
231   231  
232   @par Exception Safety 232   @par Exception Safety
233   Throws nothing. 233   Throws nothing.
234   234  
235   @param bin The recycle bin to use 235   @param bin The recycle bin to use
236   236  
237   @see 237   @see
238   @ref acquire, 238   @ref acquire,
239   @ref recycled, 239   @ref recycled,
240   @ref release. 240   @ref release.
241   */ 241   */
242   recycled_ptr( 242   recycled_ptr(
243   recycled<T>& bin, 243   recycled<T>& bin,
244   std::nullptr_t) noexcept; 244   std::nullptr_t) noexcept;
245   245  
246   /** Constructor 246   /** Constructor
247   247  
248   Upon construction, this acquires 248   Upon construction, this acquires
249   exclusive access to an object of type 249   exclusive access to an object of type
250   `T` which is either recycled from a 250   `T` which is either recycled from a
251   global recycle bin, or newly allocated. 251   global recycle bin, or newly allocated.
252   The object is in an unknown but 252   The object is in an unknown but
253   valid state. 253   valid state.
254   254  
255   @par Example 255   @par Example
256   @code 256   @code
257   recycled_ptr< std::string > ps; 257   recycled_ptr< std::string > ps;
258   258  
259   // Put the string into a known state 259   // Put the string into a known state
260   ps->clear(); 260   ps->clear();
261   @endcode 261   @endcode
262   262  
263   @par Postconditions 263   @par Postconditions
264   @code 264   @code
265   &this->bin() != nullptr && ! this->empty() 265   &this->bin() != nullptr && ! this->empty()
266   @endcode 266   @endcode
267   267  
268   @see 268   @see
269   @ref recycled. 269   @ref recycled.
270   */ 270   */
271   recycled_ptr(); 271   recycled_ptr();
272   272  
273   /** Constructor 273   /** Constructor
274   274  
275   After construction, this is empty 275   After construction, this is empty
276   and refers to a global recycle bin. 276   and refers to a global recycle bin.
277   277  
278   @par Example 278   @par Example
279   @code 279   @code
280   recycled_ptr< std::string > ps( nullptr ); 280   recycled_ptr< std::string > ps( nullptr );
281   281  
282   // Acquire a string and put it into a known state 282   // Acquire a string and put it into a known state
283   ps->acquire(); 283   ps->acquire();
284   ps->clear(); 284   ps->clear();
285   @endcode 285   @endcode
286   286  
287   @par Postconditions 287   @par Postconditions
288   @code 288   @code
289   &this->bin() != nullptr && this->empty() 289   &this->bin() != nullptr && this->empty()
290   @endcode 290   @endcode
291   291  
292   @par Exception Safety 292   @par Exception Safety
293   Throws nothing. 293   Throws nothing.
294   294  
295   @see 295   @see
296   @ref acquire, 296   @ref acquire,
297   @ref recycled, 297   @ref recycled,
298   @ref release. 298   @ref release.
299   */ 299   */
300   recycled_ptr( 300   recycled_ptr(
301   std::nullptr_t) noexcept; 301   std::nullptr_t) noexcept;
302   302  
303   /** Constructor 303   /** Constructor
304   304  
305   If `other` references an object, the 305   If `other` references an object, the
306   newly constructed pointer acquires 306   newly constructed pointer acquires
307   shared ownership. Otherwise this is 307   shared ownership. Otherwise this is
308   empty. The new pointer references 308   empty. The new pointer references
309   the same recycle bin as `other`. 309   the same recycle bin as `other`.
310   310  
311   @par Postconditions 311   @par Postconditions
312   @code 312   @code
313   &this->bin() == &other->bin() && this->get() == other.get() 313   &this->bin() == &other->bin() && this->get() == other.get()
314   @endcode 314   @endcode
315   315  
316   @par Exception Safety 316   @par Exception Safety
317   Throws nothing. 317   Throws nothing.
318   318  
319   @param other The pointer to copy 319   @param other The pointer to copy
320   */ 320   */
321   recycled_ptr( 321   recycled_ptr(
322   recycled_ptr const& other) noexcept; 322   recycled_ptr const& other) noexcept;
323   323  
324   /** Constructor 324   /** Constructor
325   325  
326   If `other` references an object, 326   If `other` references an object,
327   ownership is transferred including 327   ownership is transferred including
328   a reference to the recycle bin. After 328   a reference to the recycle bin. After
329   the move, the moved-from object is empty. 329   the move, the moved-from object is empty.
330   330  
331   @par Postconditions 331   @par Postconditions
332   @code 332   @code
333   &this->bin() == &other->bin() && ! this->empty() && other.empty() 333   &this->bin() == &other->bin() && ! this->empty() && other.empty()
334   @endcode 334   @endcode
335   335  
336   @par Exception Safety 336   @par Exception Safety
337   Throws nothing. 337   Throws nothing.
338   338  
339   @param other The pointer to move from 339   @param other The pointer to move from
340   */ 340   */
341   recycled_ptr( 341   recycled_ptr(
342   recycled_ptr&& other) noexcept; 342   recycled_ptr&& other) noexcept;
343   343  
344   /** Assignment 344   /** Assignment
345   345  
346   If `other` references an object, 346   If `other` references an object,
347   ownership is transferred including 347   ownership is transferred including
348   a reference to the recycle bin. After 348   a reference to the recycle bin. After
349   the move, the moved-from object is empty. 349   the move, the moved-from object is empty.
350   350  
351   @par Effects 351   @par Effects
352   @code 352   @code
353   this->release() 353   this->release()
354   @endcode 354   @endcode
355   355  
356   @par Postconditions 356   @par Postconditions
357   @code 357   @code
358   &this->bin() == &other->bin() 358   &this->bin() == &other->bin()
359   @endcode 359   @endcode
360   360  
361   @par Exception Safety 361   @par Exception Safety
362   Throws nothing. 362   Throws nothing.
363   363  
364   @param other The pointer to move from 364   @param other The pointer to move from
365   @return `*this` 365   @return `*this`
366   */ 366   */
367   recycled_ptr& 367   recycled_ptr&
368   operator=( 368   operator=(
369   recycled_ptr&& other) noexcept; 369   recycled_ptr&& other) noexcept;
370   370  
371   /** Assignment 371   /** Assignment
372   372  
373   If `other` references an object, 373   If `other` references an object,
374   this acquires shared ownership and 374   this acquires shared ownership and
375   references the same recycle bin as 375   references the same recycle bin as
376   `other`. The previous object if any 376   `other`. The previous object if any
377   is released. 377   is released.
378   378  
379   @par Effects 379   @par Effects
380   @code 380   @code
381   this->release() 381   this->release()
382   @endcode 382   @endcode
383   383  
384   @par Postconditions 384   @par Postconditions
385   @code 385   @code
386   &this->bin() == &other->bin() && this->get() == other.get() 386   &this->bin() == &other->bin() && this->get() == other.get()
387   @endcode 387   @endcode
388   388  
389   @par Exception Safety 389   @par Exception Safety
390   Throws nothing. 390   Throws nothing.
391   391  
392   @param other The pointer to copy from 392   @param other The pointer to copy from
393   @return `*this` 393   @return `*this`
394   */ 394   */
395   recycled_ptr& 395   recycled_ptr&
396   operator=( 396   operator=(
397   recycled_ptr const& other) noexcept; 397   recycled_ptr const& other) noexcept;
398   398  
399   /** Return true if this does not reference an object 399   /** Return true if this does not reference an object
400   400  
401   @par Exception Safety 401   @par Exception Safety
402   Throws nothing. 402   Throws nothing.
403   403  
404   @return `p_ == nullptr` 404   @return `p_ == nullptr`
405   */ 405   */
406   bool 406   bool
407   empty() const noexcept 407   empty() const noexcept
408   { 408   {
409   return p_ == nullptr; 409   return p_ == nullptr;
410   } 410   }
411   411  
412   /** Return true if this references an object 412   /** Return true if this references an object
413   413  
414   @par Effects 414   @par Effects
415   @code 415   @code
416   return ! this->empty(); 416   return ! this->empty();
417   @endcode 417   @endcode
418   418  
419   @par Exception Safety 419   @par Exception Safety
420   Throws nothing. 420   Throws nothing.
421   421  
422   @return `!this->empty()` 422   @return `!this->empty()`
423   */ 423   */
424   explicit 424   explicit
HITCBC 425   42 operator bool() const noexcept 425   42 operator bool() const noexcept
426   { 426   {
HITCBC 427   42 return p_ != nullptr; 427   42 return p_ != nullptr;
428   } 428   }
429   429  
430   /** Return the referenced recycle bin 430   /** Return the referenced recycle bin
431   431  
432   @par Exception Safety 432   @par Exception Safety
433   Throws nothing. 433   Throws nothing.
434   434  
435   @return A reference to the recycle bin 435   @return A reference to the recycle bin
436   */ 436   */
437   recycled<T>& 437   recycled<T>&
438   bin() const noexcept 438   bin() const noexcept
439   { 439   {
440   return *bin_; 440   return *bin_;
441   } 441   }
442   442  
443   /** Return the referenced object 443   /** Return the referenced object
444   444  
445   If this is empty, `nullptr` is returned. 445   If this is empty, `nullptr` is returned.
446   446  
447   @par Exception Safety 447   @par Exception Safety
448   Throws nothing. 448   Throws nothing.
449   449  
450   @return A pointer to the object 450   @return A pointer to the object
451   */ 451   */
HITCBC 452   53 T* get() const noexcept 452   53 T* get() const noexcept
453   { 453   {
HITCBC 454   53 return p_ ? &p_->t : nullptr; 454   53 return p_ ? &p_->t : nullptr;
455   } 455   }
456   456  
457   /** Return the referenced object 457   /** Return the referenced object
458   458  
459   If this is empty, `nullptr` is returned. 459   If this is empty, `nullptr` is returned.
460   460  
461   @par Exception Safety 461   @par Exception Safety
462   Throws nothing. 462   Throws nothing.
463   463  
464   @return A pointer to the object 464   @return A pointer to the object
465   */ 465   */
HITCBC 466   50 T* operator->() const noexcept 466   50 T* operator->() const noexcept
467   { 467   {
HITCBC 468   50 return get(); 468   50 return get();
469   } 469   }
470   470  
471   /** Return the referenced object 471   /** Return the referenced object
472   472  
473   @par Preconditions 473   @par Preconditions
474   @code 474   @code
475   not this->empty() 475   not this->empty()
476   @endcode 476   @endcode
477   477  
478   @return A reference to the object 478   @return A reference to the object
479   */ 479   */
HITCBC 480   1 T& operator*() const noexcept 480   1 T& operator*() const noexcept
481   { 481   {
HITCBC 482   1 return *get(); 482   1 return *get();
483   } 483   }
484   484  
485   /** Return the referenced object 485   /** Return the referenced object
486   486  
487   If this references an object, it is 487   If this references an object, it is
488   returned. Otherwise, exclusive ownership 488   returned. Otherwise, exclusive ownership
489   of a new object of type `T` is acquired 489   of a new object of type `T` is acquired
490   and returned. 490   and returned.
491   491  
492   @par Postconditions 492   @par Postconditions
493   @code 493   @code
494   not this->empty() 494   not this->empty()
495   @endcode 495   @endcode
496   496  
497   @return A reference to the object 497   @return A reference to the object
498   */ 498   */
499   T& acquire(); 499   T& acquire();
500   500  
501   /** Release the referenced object 501   /** Release the referenced object
502   502  
503   If this references an object, it is 503   If this references an object, it is
504   released to the referenced recycle bin. 504   released to the referenced recycle bin.
505   The pointer continues to reference 505   The pointer continues to reference
506   the same recycle bin. 506   the same recycle bin.
507   507  
508   @par Postconditions 508   @par Postconditions
509   @code 509   @code
510   this->empty() 510   this->empty()
511   @endcode 511   @endcode
512   512  
513   @par Exception Safety 513   @par Exception Safety
514   Throws nothing. 514   Throws nothing.
515   */ 515   */
516   void release() noexcept; 516   void release() noexcept;
517   }; 517   };
518   518  
519   } // grammar 519   } // grammar
520   } // urls 520   } // urls
521   } // boost 521   } // boost
522   522  
523   #include <boost/url/grammar/impl/recycled.hpp> 523   #include <boost/url/grammar/impl/recycled.hpp>
524   524  
525   #endif 525   #endif