HP refactoring:
[libcds.git] / cds / gc / impl / hp_decl.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_GC_IMPL_HP_DECL_H
32 #define CDSLIB_GC_IMPL_HP_DECL_H
33
34 #include <stdexcept>    // overflow_error
35 #include <cds/gc/details/hp.h>
36 #include <cds/details/marked_ptr.h>
37
38 namespace cds { namespace gc {
39     /// @defgroup cds_garbage_collector Garbage collectors
40
41     /// Hazard Pointer garbage collector
42     /**  @ingroup cds_garbage_collector
43         @headerfile cds/gc/hp.h
44
45         Implementation of classic Hazard Pointer garbage collector.
46
47         Sources:
48             - [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
49             - [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
50             - [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
51
52         Hazard Pointer garbage collector is a singleton. The main user-level part of Hazard Pointer schema is
53         GC class \p %cds::gc::HP and its nested classes. Before use any HP-related class you must initialize HP garbage collector
54         by contructing \p %cds::gc::HP object in beginning of your \p main().
55         See \ref cds_how_to_use "How to use" section for details how to apply garbage collector.
56     */
57     class HP
58     {
59     public:
60         /// Native guarded pointer type
61         /**
62             @headerfile cds/gc/hp.h
63         */
64         typedef gc::hp::hazard_pointer guarded_pointer;
65
66         /// Atomic reference
67         /**
68             @headerfile cds/gc/hp.h
69         */
70         template <typename T> using atomic_ref = atomics::atomic<T *>;
71
72         /// Atomic marked pointer
73         /**
74             @headerfile cds/gc/hp.h
75         */
76         template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
77
78         /// Atomic type
79         /**
80             @headerfile cds/gc/hp.h
81         */
82         template <typename T> using atomic_type = atomics::atomic<T>;
83
84         /// Thread GC implementation for internal usage
85         /**
86             @headerfile cds/gc/hp.h
87         */
88         typedef hp::ThreadGC   thread_gc_impl;
89
90         /// Exception "Too many Hazard Pointer"
91         typedef hp::GarbageCollector::too_many_hazard_ptr too_many_hazard_ptr_exception;
92
93         /// Wrapper for hp::ThreadGC class
94         /**
95             @headerfile cds/gc/hp.h
96             This class performs automatically attaching/detaching Hazard Pointer GC
97             for the current thread.
98         */
99         class thread_gc: public thread_gc_impl
100         {
101             //@cond
102             bool    m_bPersistent;
103             //@endcond
104         public:
105
106             /// Constructor
107             /**
108                 The constructor attaches the current thread to the Hazard Pointer GC
109                 if it is not yet attached.
110                 The \p bPersistent parameter specifies attachment persistence:
111                 - \p true - the class destructor will not detach the thread from Hazard Pointer GC.
112                 - \p false (default) - the class destructor will detach the thread from Hazard Pointer GC.
113             */
114             thread_gc(
115                 bool    bPersistent = false
116             ) ;     //inline in hp_impl.h
117
118             /// Destructor
119             /**
120                 If the object has been created in persistent mode, the destructor does nothing.
121                 Otherwise it detaches the current thread from Hazard Pointer GC.
122             */
123             ~thread_gc() ;  // inline in hp_impl.h
124
125         public: // for internal use only!!!
126             //@cond
127             static cds::gc::hp::details::hp_guard* alloc_guard(); // inline in hp_impl.h
128             static void free_guard( cds::gc::hp::details::hp_guard* g ); // inline in hp_impl.h
129             //@endcond
130         };
131
132         /// Hazard Pointer guard
133         /**
134             @headerfile cds/gc/hp.h
135
136             A guard is a hazard pointer.
137             Additionally, the \p %Guard class manages allocation and deallocation of the hazard pointer.
138
139             \p %Guard object is movable but not copyable.
140
141             The guard object can be in two states:
142             - unlinked - the guard is not linked with any internal hazard pointer.
143               In this state no operation except \p link() and move assignment is supported.
144             - linked (default) - the guard allocates an internal hazard pointer and fully operable.
145
146             Due to performance reason the implementation does not check state of the guard in runtime.
147
148             @warning Move assignment can transfer the guard in unlinked state, use with care.
149         */
150         class Guard
151         {
152         public:
153             /// Default ctor allocates a guard (hazard pointer) from thread-private storage
154             /**
155                 @warning Can throw \p too_many_hazard_ptr_exception if internal hazard pointer objects are exhausted.
156             */
157             Guard();  // inline in hp_impl.h
158
159             /// Initilalizes an unlinked guard i.e. the guard contains no hazard pointer. Used for move semantics support
160             explicit Guard( std::nullptr_t ) CDS_NOEXCEPT
161                 : m_guard( nullptr )
162             {}
163
164             /// Move ctor - \p src guard becomes unlinked (transfer internal guard ownership)
165             Guard( Guard&& src ) CDS_NOEXCEPT
166                 : m_guard( src.m_guard )
167             {
168                 src.m_guard = nullptr;
169             }
170
171             /// Move assignment: the internal guards are swapped between \p src and \p this
172             /**
173                 @warning \p src will become in unlinked state if \p this was unlinked on entry.
174             */
175             Guard& operator=( Guard&& src ) CDS_NOEXCEPT
176             {
177                 std::swap( m_guard, src.m_guard );
178                 return *this;
179             }
180
181             /// Copy ctor is prohibited - the guard is not copyable
182             Guard( Guard const& ) = delete;
183
184             /// Copy assignment is prohibited
185             Guard& operator=( Guard const& ) = delete;
186
187             /// Frees the internal hazard pointer if the guard is in linked state
188             ~Guard()
189             {
190                 unlink();
191             }
192
193             /// Checks if the guard object linked with any internal hazard pointer
194             bool is_linked() const
195             {
196                 return m_guard != nullptr;
197             }
198
199             /// Links the guard with internal hazard pointer if the guard is in unlinked state
200             /**
201                 @warning Can throw \p too_many_hazard_ptr_exception if internal hazard pointer objects are exhausted.
202             */
203             void link(); // inline in hp_impl.h
204
205             /// Unlinks the guard from internal hazard pointer; the guard becomes in unlinked state
206             void unlink(); // inline in hp_impl.h
207
208             /// Protects a pointer of type \p atomic<T*>
209             /**
210                 Return the value of \p toGuard
211
212                 The function tries to load \p toGuard and to store it
213                 to the HP slot repeatedly until the guard's value equals \p toGuard
214
215                 @warning The guad object should be in linked state, otherwise the result is undefined
216             */
217             template <typename T>
218             T protect( atomics::atomic<T> const& toGuard )
219             {
220                 assert( m_guard != nullptr );
221
222                 T pCur = toGuard.load(atomics::memory_order_acquire);
223                 T pRet;
224                 do {
225                     pRet = assign( pCur );
226                     pCur = toGuard.load(atomics::memory_order_acquire);
227                 } while ( pRet != pCur );
228                 return pCur;
229             }
230
231             /// Protects a converted pointer of type \p atomic<T*>
232             /**
233                 Return the value of \p toGuard
234
235                 The function tries to load \p toGuard and to store result of \p f functor
236                 to the HP slot repeatedly until the guard's value equals \p toGuard.
237
238                 The function is useful for intrusive containers when \p toGuard is a node pointer
239                 that should be converted to a pointer to the value before protecting.
240                 The parameter \p f of type Func is a functor that makes this conversion:
241                 \code
242                     struct functor {
243                         value_type * operator()( T * p );
244                     };
245                 \endcode
246                 Actually, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
247
248                 @warning The guad object should be in linked state, otherwise the result is undefined
249             */
250             template <typename T, class Func>
251             T protect( atomics::atomic<T> const& toGuard, Func f )
252             {
253                 assert( m_guard != nullptr );
254
255                 T pCur = toGuard.load(atomics::memory_order_acquire);
256                 T pRet;
257                 do {
258                     pRet = pCur;
259                     assign( f( pCur ) );
260                     pCur = toGuard.load(atomics::memory_order_acquire);
261                 } while ( pRet != pCur );
262                 return pCur;
263             }
264
265             /// Store \p p to the guard
266             /**
267                 The function equals to a simple assignment the value \p p to guard, no loop is performed.
268                 Can be used for a pointer that cannot be changed concurrently
269
270                 @warning The guad object should be in linked state, otherwise the result is undefined
271             */
272             template <typename T>
273             T * assign( T* p );    // inline in hp_impl.h
274
275             //@cond
276             std::nullptr_t assign( std::nullptr_t )
277             {
278                 assert(m_guard != nullptr );
279                 return *m_guard = nullptr;
280             }
281             //@endcond
282
283             /// Copy a value guarded from \p src guard to \p this guard (valid only in linked state)
284             void copy( Guard const& src )
285             {
286                 assign( src.get_native() );
287             }
288
289             /// Store marked pointer \p p to the guard
290             /**
291                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
292                 Can be used for a marked pointer that cannot be changed concurrently.
293
294                 @warning The guad object should be in linked state, otherwise the result is undefined
295             */
296             template <typename T, int BITMASK>
297             T * assign( cds::details::marked_ptr<T, BITMASK> p )
298             {
299                 return assign( p.ptr());
300             }
301
302             /// Clear value of the guard (valid only in linked state)
303             void clear()
304             {
305                 assign( nullptr );
306             }
307
308             /// Get the value currently protected (valid only in linked state)
309             template <typename T>
310             T * get() const
311             {
312                 return reinterpret_cast<T *>( get_native() );
313             }
314
315             /// Get native hazard pointer stored (valid only in linked state)
316             guarded_pointer get_native() const
317             {
318                 assert( m_guard != nullptr );
319                 return m_guard->get();
320             }
321
322             //@cond
323             hp::details::hp_guard* release()
324             {
325                 hp::details::hp_guard* g = m_guard;
326                 m_guard = nullptr;
327                 return g;
328             }
329             //@endcond
330
331         private:
332             //@cond
333             hp::details::hp_guard* m_guard;
334             //@endcond
335         };
336
337         /// Array of Hazard Pointer guards
338         /**
339             @headerfile cds/gc/hp.h
340             The class is intended for allocating an array of hazard pointer guards.
341             Template parameter \p Count defines the size of the array.
342
343         */
344         template <size_t Count>
345         class GuardArray
346         {
347         public:
348             /// Rebind array for other size \p Count2
349             template <size_t Count2>
350             struct rebind {
351                 typedef GuardArray<Count2>  other;   ///< rebinding result
352             };
353
354             /// Array capacity
355             static CDS_CONSTEXPR const size_t c_nCapacity = Count;
356
357         public:
358             /// Default ctor allocates \p Count hazard pointers
359             GuardArray(); // inline in hp_impl.h
360
361             /// Move ctor is prohibited
362             GuardArray( GuardArray&& ) = delete;
363
364             /// Move assignment is prohibited
365             GuardArray& operator=( GuardArray&& ) = delete;
366
367             /// Copy ctor is prohibited
368             GuardArray( GuardArray const& ) = delete;
369
370             /// Copy assignment is prohibited
371             GuardArray& operator=( GuardArray const& ) = delete;
372
373             /// Frees allocated hazard pointers
374             ~GuardArray(); // inline in hp_impl.h
375
376             /// Protects a pointer of type \p atomic<T*>
377             /**
378                 Return the value of \p toGuard
379
380                 The function tries to load \p toGuard and to store it
381                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
382             */
383             template <typename T>
384             T protect( size_t nIndex, atomics::atomic<T> const& toGuard )
385             {
386                 assert( nIndex < capacity());
387
388                 T pRet;
389                 do {
390                     pRet = assign( nIndex, toGuard.load(atomics::memory_order_acquire) );
391                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
392
393                 return pRet;
394             }
395
396             /// Protects a pointer of type \p atomic<T*>
397             /**
398                 Return the value of \p toGuard
399
400                 The function tries to load \p toGuard and to store it
401                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
402
403                 The function is useful for intrusive containers when \p toGuard is a node pointer
404                 that should be converted to a pointer to the value type before guarding.
405                 The parameter \p f of type Func is a functor that makes this conversion:
406                 \code
407                     struct functor {
408                         value_type * operator()( T * p );
409                     };
410                 \endcode
411                 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
412             */
413             template <typename T, class Func>
414             T protect( size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
415             {
416                 assert( nIndex < capacity() );
417
418                 T pRet;
419                 do {
420                     assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_acquire) ));
421                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
422
423                 return pRet;
424             }
425
426             /// Store \p to the slot \p nIndex
427             /**
428                 The function equals to a simple assignment, no loop is performed.
429             */
430             template <typename T>
431             T * assign( size_t nIndex, T * p ); // inline in hp_impl.h
432
433             /// Store marked pointer \p p to the guard
434             /**
435                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
436                 Can be used for a marked pointer that cannot be changed concurrently.
437             */
438             template <typename T, int BITMASK>
439             T * assign( size_t nIndex, cds::details::marked_ptr<T, BITMASK> p )
440             {
441                 return assign( nIndex, p.ptr() );
442             }
443
444             /// Copy guarded value from \p src guard to slot at index \p nIndex
445             void copy( size_t nIndex, Guard const& src )
446             {
447                 assign( nIndex, src.get_native() );
448             }
449
450             /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
451             void copy( size_t nDestIndex, size_t nSrcIndex )
452             {
453                 assign( nDestIndex, get_native( nSrcIndex ));
454             }
455
456             /// Clear value of the slot \p nIndex
457             void clear( size_t nIndex )
458             {
459                 m_arr.clear( nIndex );
460             }
461
462             /// Get current value of slot \p nIndex
463             template <typename T>
464             T * get( size_t nIndex ) const
465             {
466                 return reinterpret_cast<T *>( get_native( nIndex ) );
467             }
468
469             /// Get native hazard pointer stored
470             guarded_pointer get_native( size_t nIndex ) const
471             {
472                 assert( nIndex < capacity() );
473                 return m_arr[nIndex]->get();
474             }
475
476             //@cond
477             hp::details::hp_guard* release( size_t nIndex ) CDS_NOEXCEPT
478             {
479                 return m_arr.release( nIndex );
480             }
481             //@endcond
482
483             /// Capacity of the guard array
484             static CDS_CONSTEXPR size_t capacity()
485             {
486                 return c_nCapacity;
487             }
488
489         private:
490             //@cond
491             hp::details::hp_array<Count> m_arr;
492             //@endcond
493         };
494
495         /// Guarded pointer
496         /**
497             A guarded pointer is a pair of a pointer and GC's guard.
498             Usually, it is used for returning a pointer to the item from an lock-free container.
499             The guard prevents the pointer to be early disposed (freed) by GC.
500             After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time.
501
502             Template arguments:
503             - \p GuardedType - a type which the guard stores
504             - \p ValueType - a value type
505             - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
506
507             For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
508             In such case the \p %guarded_ptr is:
509             @code
510             typedef cds::gc::HP::guarded_ptr< foo > intrusive_guarded_ptr;
511             @endcode
512
513             For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
514             For example:
515             @code
516             struct foo {
517                 int const   key;
518                 std::string value;
519             };
520
521             struct value_accessor {
522                 std::string* operator()( foo* pFoo ) const
523                 {
524                     return &(pFoo->value);
525                 }
526             };
527
528             // Guarded ptr
529             typedef cds::gc::HP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
530             @endcode
531
532             You don't need use this class directly.
533             All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
534         */
535         template <typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
536         class guarded_ptr
537         {
538             //@cond
539             struct trivial_cast {
540                 ValueType * operator()( GuardedType * p ) const
541                 {
542                     return p;
543                 }
544             };
545
546             template <typename GT, typename VT, typename C> friend class guarded_ptr;
547             //@endcond
548
549         public:
550             typedef GuardedType guarded_type; ///< Guarded type
551             typedef ValueType   value_type;   ///< Value type
552
553             /// Functor for casting \p guarded_type to \p value_type
554             typedef typename std::conditional< std::is_same<Cast, void>::value, trivial_cast, Cast >::type value_cast;
555
556         public:
557             /// Creates empty guarded pointer
558             guarded_ptr() CDS_NOEXCEPT
559                 : m_pGuard(nullptr)
560             {}
561
562             //@cond
563             explicit guarded_ptr( hp::details::hp_guard* g ) CDS_NOEXCEPT
564                 : m_pGuard( g )
565             {}
566
567             /// Initializes guarded pointer with \p p
568             explicit guarded_ptr( guarded_type* p ) CDS_NOEXCEPT
569                 : m_pGuard( nullptr )
570             {
571                 reset(p);
572             }
573             explicit guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
574                 : m_pGuard( nullptr )
575             {}
576             //@endcond
577
578             /// Move ctor
579             guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
580                 : m_pGuard( gp.m_pGuard )
581             {
582                 gp.m_pGuard = nullptr;
583             }
584
585             /// Move ctor
586             template <typename GT, typename VT, typename C>
587             guarded_ptr( guarded_ptr<GT, VT, C>&& gp ) CDS_NOEXCEPT
588                 : m_pGuard( gp.m_pGuard )
589             {
590                 gp.m_pGuard = nullptr;
591             }
592
593             /// Ctor from \p Guard
594             explicit guarded_ptr( Guard&& g ) CDS_NOEXCEPT
595                 : m_pGuard( g.release() )
596             {}
597
598             /// The guarded pointer is not copy-constructible
599             guarded_ptr( guarded_ptr const& gp ) = delete;
600
601             /// Clears the guarded pointer
602             /**
603                 \ref release() is called if guarded pointer is not \ref empty()
604             */
605             ~guarded_ptr() CDS_NOEXCEPT
606             {
607                 release();
608             }
609
610             /// Move-assignment operator
611             guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
612             {
613                 std::swap( m_pGuard, gp.m_pGuard );
614                 return *this;
615             }
616
617             /// Move-assignment from \p Guard
618             guarded_ptr& operator=( Guard&& g ) CDS_NOEXCEPT
619             {
620                 std::swap( m_pGuard, g.m_guard );
621                 return *this;
622             }
623
624             /// The guarded pointer is not copy-assignable
625             guarded_ptr& operator=(guarded_ptr const& gp) = delete;
626
627             /// Returns a pointer to guarded value
628             value_type * operator ->() const CDS_NOEXCEPT
629             {
630                 assert( !empty() );
631                 return value_cast()( reinterpret_cast<guarded_type *>(m_pGuard->get()));
632             }
633
634             /// Returns a reference to guarded value
635             value_type& operator *() CDS_NOEXCEPT
636             {
637                 assert( !empty());
638                 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
639             }
640
641             /// Returns const reference to guarded value
642             value_type const& operator *() const CDS_NOEXCEPT
643             {
644                 assert( !empty() );
645                 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
646             }
647
648             /// Checks if the guarded pointer is \p nullptr
649             bool empty() const CDS_NOEXCEPT
650             {
651                 return !m_pGuard || m_pGuard->get( atomics::memory_order_relaxed ) == nullptr;
652             }
653
654             /// \p bool operator returns <tt>!empty()</tt>
655             explicit operator bool() const CDS_NOEXCEPT
656             {
657                 return !empty();
658             }
659
660             /// Clears guarded pointer
661             /**
662                 If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
663                 Dereferncing the guarded pointer after \p release() is dangerous.
664             */
665             void release() CDS_NOEXCEPT
666             {
667                 free_guard();
668             }
669
670             //@cond
671             // For internal use only!!!
672             void reset(guarded_type * p) CDS_NOEXCEPT
673             {
674                 alloc_guard();
675                 assert( m_pGuard );
676                 m_pGuard->set(p);
677             }
678             //@endcond
679
680         private:
681             //@cond
682             void alloc_guard()
683             {
684                 if ( !m_pGuard )
685                     m_pGuard = thread_gc::alloc_guard();
686             }
687
688             void free_guard()
689             {
690                 if ( m_pGuard ) {
691                     thread_gc::free_guard( m_pGuard );
692                     m_pGuard = nullptr;
693                 }
694             }
695             //@endcond
696
697         private:
698             //@cond
699             hp::details::hp_guard* m_pGuard;
700             //@endcond
701         };
702
703     public:
704         /// \p scan() type
705         enum class scan_type {
706             classic = hp::classic,    ///< classic scan as described in Michael's papers
707             inplace = hp::inplace     ///< inplace scan without allocation
708         };
709         /// Initializes %HP singleton
710         /**
711             The constructor initializes GC singleton with passed parameters.
712             If GC instance is not exist then the function creates the instance.
713             Otherwise it does nothing.
714
715             The Michael's %HP reclamation schema depends of three parameters:
716             - \p nHazardPtrCount - hazard pointer count per thread. Usually it is small number (up to 10) depending from
717                 the data structure algorithms. By default, if \p nHazardPtrCount = 0, the function
718                 uses maximum of the hazard pointer count for CDS library.
719             - \p nMaxThreadCount - max count of thread with using Hazard Pointer GC in your application. Default is 100.
720             - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
721                 <tt> nHazardPtrCount * nMaxThreadCount </tt>. Default is <tt>2 * nHazardPtrCount * nMaxThreadCount </tt>.
722         */
723         HP(
724             size_t nHazardPtrCount = 0,     ///< Hazard pointer count per thread
725             size_t nMaxThreadCount = 0,     ///< Max count of simultaneous working thread in your application
726             size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
727             scan_type nScanType = scan_type::inplace   ///< Scan type (see \p scan_type enum)
728         )
729         {
730             hp::GarbageCollector::Construct(
731                 nHazardPtrCount,
732                 nMaxThreadCount,
733                 nMaxRetiredPtrCount,
734                 static_cast<hp::scan_type>(nScanType)
735             );
736         }
737
738         /// Terminates GC singleton
739         /**
740             The destructor destroys %HP global object. After calling of this function you may \b NOT
741             use CDS data structures based on \p %cds::gc::HP.
742             Usually, %HP object is destroyed at the end of your \p main().
743         */
744         ~HP()
745         {
746             hp::GarbageCollector::Destruct( true );
747         }
748
749         /// Checks if count of hazard pointer is no less than \p nCountNeeded
750         /**
751             If \p bRaiseException is \p true (that is the default), the function raises
752             an \p std::overflow_error exception "Too few hazard pointers"
753             if \p nCountNeeded is more than the count of hazard pointer per thread.
754         */
755         static bool check_available_guards( size_t nCountNeeded, bool bRaiseException = true )
756         {
757             if ( hp::GarbageCollector::instance().getHazardPointerCount() < nCountNeeded ) {
758                 if ( bRaiseException )
759                     throw std::overflow_error( "Too few hazard pointers" );
760                 return false;
761             }
762             return true;
763         }
764
765         /// Returns max Hazard Pointer count
766         static size_t max_hazard_count()
767         {
768             return hp::GarbageCollector::instance().getHazardPointerCount();
769         }
770
771         /// Returns max count of thread
772         static size_t max_thread_count()
773         {
774             return hp::GarbageCollector::instance().getMaxThreadCount();
775         }
776
777         /// Returns capacity of retired pointer array
778         static size_t retired_array_capacity()
779         {
780             return hp::GarbageCollector::instance().getMaxRetiredPtrCount();
781         }
782
783         /// Retire pointer \p p with function \p pFunc
784         /**
785             The function places pointer \p p to array of pointers ready for removing.
786             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
787             Deleting the pointer is the function \p pFunc call.
788         */
789         template <typename T>
790         static void retire( T * p, void (* pFunc)(T *) );   // inline in hp_impl.h
791
792         /// Retire pointer \p p with functor of type \p Disposer
793         /**
794             The function places pointer \p p to array of pointers ready for removing.
795             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
796
797             Deleting the pointer is an invocation of some object of type \p Disposer; the interface of \p Disposer is:
798             \code
799             template <typename T>
800             struct disposer {
801                 void operator()( T * p )    ;   // disposing operator
802             };
803             \endcode
804             Since the functor call can happen at any time after \p retire call, additional restrictions are imposed to \p Disposer type:
805             - it should be stateless functor
806             - it should be default-constructible
807             - the result of functor call with argument \p p should not depend on where the functor will be called.
808
809             \par Examples:
810             Operator \p delete functor:
811             \code
812             template <typename T>
813             struct disposer {
814                 void operator ()( T * p ) {
815                     delete p;
816                 }
817             };
818
819             // How to call GC::retire method
820             int * p = new int;
821
822             // ... use p in lock-free manner
823
824             cds::gc::HP::retire<disposer>( p ) ;   // place p to retired pointer array of HP GC
825             \endcode
826
827             Functor based on \p std::allocator :
828             \code
829             template <typename ALLOC = std::allocator<int> >
830             struct disposer {
831                 template <typename T>
832                 void operator()( T * p ) {
833                     typedef typename ALLOC::templare rebind<T>::other   alloc_t;
834                     alloc_t a;
835                     a.destroy( p );
836                     a.deallocate( p, 1 );
837                 }
838             };
839             \endcode
840         */
841         template <class Disposer, typename T>
842         static void retire( T * p );   // inline in hp_impl.h
843
844         /// Get current scan strategy
845         static scan_type getScanType()
846         {
847             return static_cast<scan_type>( hp::GarbageCollector::instance().getScanType());
848         }
849
850         /// Set current scan strategy
851         static void setScanType(
852             scan_type nScanType     ///< new scan strategy
853         )
854         {
855             hp::GarbageCollector::instance().setScanType( static_cast<hp::scan_type>(nScanType) );
856         }
857
858         /// Checks if Hazard Pointer GC is constructed and may be used
859         static bool isUsed()
860         {
861             return hp::GarbageCollector::isUsed();
862         }
863
864         /// Forced GC cycle call for current thread
865         /**
866             Usually, this function should not be called directly.
867         */
868         static void scan()  ;   // inline in hp_impl.h
869
870         /// Synonym for \ref scan()
871         static void force_dispose()
872         {
873             scan();
874         }
875     };
876 }}  // namespace cds::gc
877
878 #endif  // #ifndef CDSLIB_GC_IMPL_HP_DECL_H