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