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