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