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 3 : U()
106 3 : : refs{1}
107 : {
108 3 : }
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 : */
366 : recycled_ptr&
367 : operator=(
368 : recycled_ptr&& other) noexcept;
369 :
370 : /** Assignment
371 :
372 : If `other` references an object,
373 : this acquires shared ownership and
374 : references the same recycle bin as
375 : `other`. The previous object if any
376 : is released.
377 :
378 : @par Effects
379 : @code
380 : this->release()
381 : @endcode
382 :
383 : @par Postconditions
384 : @code
385 : &this->bin() == &other->bin() && this->get() == other.get()
386 : @endcode
387 :
388 : @par Exception Safety
389 : Throws nothing.
390 :
391 : @param other The pointer to copy from
392 : */
393 : recycled_ptr&
394 : operator=(
395 : recycled_ptr const& other) noexcept;
396 :
397 : /** Return true if this does not reference an object
398 :
399 : @par Exception Safety
400 : Throws nothing.
401 : */
402 : bool
403 : empty() const noexcept
404 : {
405 : return p_ == nullptr;
406 : }
407 :
408 : /** Return true if this references an object
409 :
410 : @par Effects
411 : @code
412 : return ! this->empty();
413 : @endcode
414 :
415 : @par Exception Safety
416 : Throws nothing.
417 : */
418 : explicit
419 12 : operator bool() const noexcept
420 : {
421 12 : return p_ != nullptr;
422 : }
423 :
424 : /** Return the referenced recycle bin
425 :
426 : @par Exception Safety
427 : Throws nothing.
428 : */
429 : recycled<T>&
430 : bin() const noexcept
431 : {
432 : return *bin_;
433 : }
434 :
435 : /** Return the referenced object
436 :
437 : If this is empty, `nullptr` is returned.
438 :
439 : @par Exception Safety
440 : Throws nothing.
441 : */
442 30 : T* get() const noexcept
443 : {
444 30 : return &p_->t;
445 : }
446 :
447 : /** Return the referenced object
448 :
449 : If this is empty, `nullptr` is returned.
450 :
451 : @par Exception Safety
452 : Throws nothing.
453 : */
454 30 : T* operator->() const noexcept
455 : {
456 30 : return get();
457 : }
458 :
459 : /** Return the referenced object
460 :
461 : @par Preconditions
462 : @code
463 : not this->empty()
464 : @endcode
465 : */
466 : T& operator*() const noexcept
467 : {
468 : return *get();
469 : }
470 :
471 : /** Return the referenced object
472 :
473 : If this references an object, it is
474 : returned. Otherwise, exclusive ownership
475 : of a new object of type `T` is acquired
476 : and returned.
477 :
478 : @par Postconditions
479 : @code
480 : not this->empty()
481 : @endcode
482 : */
483 : T& acquire();
484 :
485 : /** Release the referenced object
486 :
487 : If this references an object, it is
488 : released to the referenced recycle bin.
489 : The pointer continues to reference
490 : the same recycle bin.
491 :
492 : @par Postconditions
493 : @code
494 : this->empty()
495 : @endcode
496 :
497 : @par Exception Safety
498 : Throws nothing.
499 : */
500 : void release() noexcept;
501 : };
502 :
503 : } // grammar
504 : } // urls
505 : } // boost
506 :
507 : #include <boost/url/grammar/impl/recycled.hpp>
508 :
509 : #endif
|