Added copyright and license
[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         /// Wrapper for hp::ThreadGC class
91         /**
92             @headerfile cds/gc/hp.h
93             This class performs automatically attaching/detaching Hazard Pointer GC
94             for the current thread.
95         */
96         class thread_gc: public thread_gc_impl
97         {
98             //@cond
99             bool    m_bPersistent;
100             //@endcond
101         public:
102
103             /// Constructor
104             /**
105                 The constructor attaches the current thread to the Hazard Pointer GC
106                 if it is not yet attached.
107                 The \p bPersistent parameter specifies attachment persistence:
108                 - \p true - the class destructor will not detach the thread from Hazard Pointer GC.
109                 - \p false (default) - the class destructor will detach the thread from Hazard Pointer GC.
110             */
111             thread_gc(
112                 bool    bPersistent = false
113             ) ;     //inline in hp_impl.h
114
115             /// Destructor
116             /**
117                 If the object has been created in persistent mode, the destructor does nothing.
118                 Otherwise it detaches the current thread from Hazard Pointer GC.
119             */
120             ~thread_gc() ;  // inline in hp_impl.h
121
122         public: // for internal use only!!!
123             //@cond
124             static cds::gc::hp::details::hp_guard& alloc_guard(); // inline in hp_impl.h
125             static void free_guard( cds::gc::hp::details::hp_guard& g ); // inline in hp_impl.h
126             //@endcond
127         };
128
129         /// Hazard Pointer guard
130         /**
131             @headerfile cds/gc/hp.h
132
133             A guard is the hazard pointer.
134             Additionally, the \p %Guard class manages allocation and deallocation of the hazard pointer
135
136             A \p %Guard object is not copy- and move-constructible
137             and not copy- and move-assignable.
138         */
139         class Guard : public hp::guard
140         {
141             //@cond
142             typedef hp::guard base_class;
143             //@endcond
144
145         public:
146             /// Default ctor
147             Guard()
148             {}
149
150             //@cond
151             Guard( Guard const& ) = delete;
152             Guard( Guard&& s ) = delete;
153             Guard& operator=(Guard const&) = delete;
154             Guard& operator=(Guard&&) = delete;
155             //@endcond
156
157             /// Protects a pointer of type \p atomic<T*>
158             /**
159                 Return the value of \p toGuard
160
161                 The function tries to load \p toGuard and to store it
162                 to the HP slot repeatedly until the guard's value equals \p toGuard
163             */
164             template <typename T>
165             T protect( atomics::atomic<T> const& toGuard )
166             {
167                 T pCur = toGuard.load(atomics::memory_order_acquire);
168                 T pRet;
169                 do {
170                     pRet = assign( pCur );
171                     pCur = toGuard.load(atomics::memory_order_acquire);
172                 } while ( pRet != pCur );
173                 return pCur;
174             }
175
176             /// Protects a converted pointer of type \p atomic<T*>
177             /**
178                 Return the value of \p toGuard
179
180                 The function tries to load \p toGuard and to store result of \p f functor
181                 to the HP slot repeatedly until the guard's value equals \p toGuard.
182
183                 The function is useful for intrusive containers when \p toGuard is a node pointer
184                 that should be converted to a pointer to the value before protecting.
185                 The parameter \p f of type Func is a functor that makes this conversion:
186                 \code
187                     struct functor {
188                         value_type * operator()( T * p );
189                     };
190                 \endcode
191                 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
192             */
193             template <typename T, class Func>
194             T protect( atomics::atomic<T> const& toGuard, Func f )
195             {
196                 T pCur = toGuard.load(atomics::memory_order_acquire);
197                 T pRet;
198                 do {
199                     pRet = pCur;
200                     assign( f( pCur ) );
201                     pCur = toGuard.load(atomics::memory_order_acquire);
202                 } while ( pRet != pCur );
203                 return pCur;
204             }
205
206             /// Store \p p to the guard
207             /**
208                 The function equals to a simple assignment the value \p p to guard, no loop is performed.
209                 Can be used for a pointer that cannot be changed concurrently
210             */
211             template <typename T>
212             T * assign( T * p );    // inline in hp_impl.h
213
214             //@cond
215             std::nullptr_t assign( std::nullptr_t )
216             {
217                 return base_class::operator =(nullptr);
218             }
219             //@endcond
220
221             /// Copy from \p src guard to \p this guard
222             void copy( Guard const& src )
223             {
224                 assign( src.get_native() );
225             }
226
227             /// Store marked pointer \p p to the guard
228             /**
229                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
230                 Can be used for a marked pointer that cannot be changed concurrently.
231             */
232             template <typename T, int BITMASK>
233             T * assign( cds::details::marked_ptr<T, BITMASK> p )
234             {
235                 return base_class::operator =( p.ptr() );
236             }
237
238             /// Clear value of the guard
239             void clear()
240             {
241                 assign( nullptr );
242             }
243
244             /// Get the value currently protected
245             template <typename T>
246             T * get() const
247             {
248                 return reinterpret_cast<T *>( get_native() );
249             }
250
251             /// Get native hazard pointer stored
252             guarded_pointer get_native() const
253             {
254                 return base_class::get();
255             }
256         };
257
258         /// Array of Hazard Pointer guards
259         /**
260             @headerfile cds/gc/hp.h
261             The class is intended for allocating an array of hazard pointer guards.
262             Template parameter \p Count defines the size of the array.
263
264             A \p %GuardArray object is not copy- and move-constructible
265             and not copy- and move-assignable.
266         */
267         template <size_t Count>
268         class GuardArray : public hp::array<Count>
269         {
270             //@cond
271             typedef hp::array<Count> base_class;
272             //@endcond
273         public:
274             /// Rebind array for other size \p Count2
275             template <size_t Count2>
276             struct rebind {
277                 typedef GuardArray<Count2>  other   ;   ///< rebinding result
278             };
279
280         public:
281             /// Default ctor
282             GuardArray()
283             {}
284
285             //@cond
286             GuardArray( GuardArray const& ) = delete;
287             GuardArray( GuardArray&& ) = delete;
288             GuardArray& operator=(GuardArray const&) = delete;
289             GuardArray& operator=(GuardArray&&) = delete;
290             //@endcond
291
292             /// Protects a pointer of type \p atomic<T*>
293             /**
294                 Return the value of \p toGuard
295
296                 The function tries to load \p toGuard and to store it
297                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
298             */
299             template <typename T>
300             T protect( size_t nIndex, atomics::atomic<T> const& toGuard )
301             {
302                 T pRet;
303                 do {
304                     pRet = assign( nIndex, toGuard.load(atomics::memory_order_acquire) );
305                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
306
307                 return pRet;
308             }
309
310             /// Protects a pointer of type \p atomic<T*>
311             /**
312                 Return the value of \p toGuard
313
314                 The function tries to load \p toGuard and to store it
315                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
316
317                 The function is useful for intrusive containers when \p toGuard is a node pointer
318                 that should be converted to a pointer to the value type before guarding.
319                 The parameter \p f of type Func is a functor that makes this conversion:
320                 \code
321                     struct functor {
322                         value_type * operator()( T * p );
323                     };
324                 \endcode
325                 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
326             */
327             template <typename T, class Func>
328             T protect( size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
329             {
330                 T pRet;
331                 do {
332                     assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_acquire) ));
333                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
334
335                 return pRet;
336             }
337
338             /// Store \p to the slot \p nIndex
339             /**
340                 The function equals to a simple assignment, no loop is performed.
341             */
342             template <typename T>
343             T * assign( size_t nIndex, T * p ); // inline in hp_impl.h
344
345             /// Store marked pointer \p p to the guard
346             /**
347                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
348                 Can be used for a marked pointer that cannot be changed concurrently.
349             */
350             template <typename T, int BITMASK>
351             T * assign( size_t nIndex, cds::details::marked_ptr<T, BITMASK> p )
352             {
353                 return assign( nIndex, p.ptr() );
354             }
355
356             /// Copy guarded value from \p src guard to slot at index \p nIndex
357             void copy( size_t nIndex, Guard const& src )
358             {
359                 assign( nIndex, src.get_native() );
360             }
361
362             /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
363             void copy( size_t nDestIndex, size_t nSrcIndex )
364             {
365                 assign( nDestIndex, get_native( nSrcIndex ));
366             }
367
368             /// Clear value of the slot \p nIndex
369             void clear( size_t nIndex )
370             {
371                 base_class::clear( nIndex );
372             }
373
374             /// Get current value of slot \p nIndex
375             template <typename T>
376             T * get( size_t nIndex ) const
377             {
378                 return reinterpret_cast<T *>( get_native( nIndex ) );
379             }
380
381             /// Get native hazard pointer stored
382             guarded_pointer get_native( size_t nIndex ) const
383             {
384                 return base_class::operator[](nIndex).get();
385             }
386
387             /// Capacity of the guard array
388             static CDS_CONSTEXPR size_t capacity()
389             {
390                 return Count;
391             }
392         };
393
394         /// Guarded pointer
395         /**
396             A guarded pointer is a pair of a pointer and GC's guard.
397             Usually, it is used for returning a pointer to the item from an lock-free container.
398             The guard prevents the pointer to be early disposed (freed) by GC.
399             After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time.
400
401             Template arguments:
402             - \p GuardedType - a type which the guard stores
403             - \p ValueType - a value type
404             - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
405
406             For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
407             In such case the \p %guarded_ptr is:
408             @code
409             typedef cds::gc::HP::guarded_ptr< foo > intrusive_guarded_ptr;
410             @endcode
411
412             For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
413             For example:
414             @code
415             struct foo {
416                 int const   key;
417                 std::string value;
418             };
419
420             struct value_accessor {
421                 std::string* operator()( foo* pFoo ) const
422                 {
423                     return &(pFoo->value);
424                 }
425             };
426
427             // Guarded ptr
428             typedef cds::gc::HP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
429             @endcode
430
431             You don't need use this class directly.
432             All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
433         */
434         template <typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
435         class guarded_ptr
436         {
437             //@cond
438             struct trivial_cast {
439                 ValueType * operator()( GuardedType * p ) const
440                 {
441                     return p;
442                 }
443             };
444             //@endcond
445
446         public:
447             typedef GuardedType guarded_type; ///< Guarded type
448             typedef ValueType   value_type;   ///< Value type
449
450             /// Functor for casting \p guarded_type to \p value_type
451             typedef typename std::conditional< std::is_same<Cast, void>::value, trivial_cast, Cast >::type value_cast;
452
453             //@cond
454             typedef cds::gc::hp::details::hp_guard native_guard;
455             //@endcond
456
457         private:
458             //@cond
459             native_guard *  m_pGuard;
460             //@endcond
461
462         public:
463             /// Creates empty guarded pointer
464             guarded_ptr() CDS_NOEXCEPT
465                 : m_pGuard(nullptr)
466             {
467                 alloc_guard();
468             }
469
470             //@cond
471             /// Initializes guarded pointer with \p p
472             explicit guarded_ptr( guarded_type * p ) CDS_NOEXCEPT
473                 : m_pGuard( nullptr )
474             {
475                 reset(p);
476             }
477             explicit guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
478                 : m_pGuard( nullptr )
479             {}
480             //@endcond
481
482             /// Move ctor
483             guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
484                 : m_pGuard( gp.m_pGuard )
485             {
486                 gp.m_pGuard = nullptr;
487             }
488
489             /// The guarded pointer is not copy-constructible
490             guarded_ptr( guarded_ptr const& gp ) = delete;
491
492             /// Clears the guarded pointer
493             /**
494                 \ref release is called if guarded pointer is not \ref empty
495             */
496             ~guarded_ptr() CDS_NOEXCEPT
497             {
498                 free_guard();
499             }
500
501             /// Move-assignment operator
502             guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
503             {
504                 // Hazard Pointer array is organized as a stack
505                 if ( m_pGuard && m_pGuard > gp.m_pGuard ) {
506                     m_pGuard->set( gp.m_pGuard->get(atomics::memory_order_relaxed) );
507                     gp.free_guard();
508                 }
509                 else {
510                     free_guard();
511                     m_pGuard = gp.m_pGuard;
512                     gp.m_pGuard = nullptr;
513                 }
514                 return *this;
515             }
516
517             /// The guarded pointer is not copy-assignable
518             guarded_ptr& operator=(guarded_ptr const& gp) = delete;
519
520             /// Returns a pointer to guarded value
521             value_type * operator ->() const CDS_NOEXCEPT
522             {
523                 assert( !empty() );
524                 return value_cast()( reinterpret_cast<guarded_type *>(m_pGuard->get()));
525             }
526
527             /// Returns a reference to guarded value
528             value_type& operator *() CDS_NOEXCEPT
529             {
530                 assert( !empty());
531                 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
532             }
533
534             /// Returns const reference to guarded value
535             value_type const& operator *() const CDS_NOEXCEPT
536             {
537                 assert( !empty() );
538                 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
539             }
540
541             /// Checks if the guarded pointer is \p nullptr
542             bool empty() const CDS_NOEXCEPT
543             {
544                 return !m_pGuard || m_pGuard->get( atomics::memory_order_relaxed ) == nullptr;
545             }
546
547             /// \p bool operator returns <tt>!empty()</tt>
548             explicit operator bool() const CDS_NOEXCEPT
549             {
550                 return !empty();
551             }
552
553             /// Clears guarded pointer
554             /**
555                 If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
556                 Dereferncing the guarded pointer after \p release() is dangerous.
557             */
558             void release() CDS_NOEXCEPT
559             {
560                 free_guard();
561             }
562
563             //@cond
564             // For internal use only!!!
565             native_guard& guard() CDS_NOEXCEPT
566             {
567                 alloc_guard();
568                 assert( m_pGuard );
569                 return *m_pGuard;
570             }
571
572             void reset(guarded_type * p) CDS_NOEXCEPT
573             {
574                 alloc_guard();
575                 assert( m_pGuard );
576                 m_pGuard->set(p);
577             }
578             //@endcond
579
580         private:
581             //@cond
582             void alloc_guard()
583             {
584                 if ( !m_pGuard )
585                     m_pGuard = &thread_gc::alloc_guard();
586             }
587
588             void free_guard()
589             {
590                 if ( m_pGuard ) {
591                     thread_gc::free_guard( *m_pGuard );
592                     m_pGuard = nullptr;
593                 }
594             }
595             //@endcond
596         };
597
598     public:
599         /// \p scan() type
600         enum class scan_type {
601             classic = hp::classic,    ///< classic scan as described in Michael's papers
602             inplace = hp::inplace     ///< inplace scan without allocation
603         };
604         /// Initializes %HP singleton
605         /**
606             The constructor initializes GC singleton with passed parameters.
607             If GC instance is not exist then the function creates the instance.
608             Otherwise it does nothing.
609
610             The Michael's %HP reclamation schema depends of three parameters:
611             - \p nHazardPtrCount - hazard pointer count per thread. Usually it is small number (up to 10) depending from
612                 the data structure algorithms. By default, if \p nHazardPtrCount = 0, the function
613                 uses maximum of the hazard pointer count for CDS library.
614             - \p nMaxThreadCount - max count of thread with using Hazard Pointer GC in your application. Default is 100.
615             - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
616                 <tt> nHazardPtrCount * nMaxThreadCount </tt>. Default is <tt>2 * nHazardPtrCount * nMaxThreadCount </tt>.
617         */
618         HP(
619             size_t nHazardPtrCount = 0,     ///< Hazard pointer count per thread
620             size_t nMaxThreadCount = 0,     ///< Max count of simultaneous working thread in your application
621             size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
622             scan_type nScanType = scan_type::inplace   ///< Scan type (see \p scan_type enum)
623         )
624         {
625             hp::GarbageCollector::Construct(
626                 nHazardPtrCount,
627                 nMaxThreadCount,
628                 nMaxRetiredPtrCount,
629                 static_cast<hp::scan_type>(nScanType)
630             );
631         }
632
633         /// Terminates GC singleton
634         /**
635             The destructor destroys %HP global object. After calling of this function you may \b NOT
636             use CDS data structures based on \p %cds::gc::HP.
637             Usually, %HP object is destroyed at the end of your \p main().
638         */
639         ~HP()
640         {
641             hp::GarbageCollector::Destruct( true );
642         }
643
644         /// Checks if count of hazard pointer is no less than \p nCountNeeded
645         /**
646             If \p bRaiseException is \p true (that is the default), the function raises
647             an \p std::overflow_error exception "Too few hazard pointers"
648             if \p nCountNeeded is more than the count of hazard pointer per thread.
649         */
650         static bool check_available_guards( size_t nCountNeeded, bool bRaiseException = true )
651         {
652             if ( hp::GarbageCollector::instance().getHazardPointerCount() < nCountNeeded ) {
653                 if ( bRaiseException )
654                     throw std::overflow_error( "Too few hazard pointers" );
655                 return false;
656             }
657             return true;
658         }
659
660         /// Returns max Hazard Pointer count
661         static size_t max_hazard_count()
662         {
663             return hp::GarbageCollector::instance().getHazardPointerCount();
664         }
665
666         /// Returns max count of thread
667         static size_t max_thread_count()
668         {
669             return hp::GarbageCollector::instance().getMaxThreadCount();
670         }
671
672         /// Returns capacity of retired pointer array
673         static size_t retired_array_capacity()
674         {
675             return hp::GarbageCollector::instance().getMaxRetiredPtrCount();
676         }
677
678         /// Retire pointer \p p with function \p pFunc
679         /**
680             The function places pointer \p p to array of pointers ready for removing.
681             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
682             Deleting the pointer is the function \p pFunc call.
683         */
684         template <typename T>
685         static void retire( T * p, void (* pFunc)(T *) );   // inline in hp_impl.h
686
687         /// Retire pointer \p p with functor of type \p Disposer
688         /**
689             The function places pointer \p p to array of pointers ready for removing.
690             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
691
692             Deleting the pointer is an invocation of some object of type \p Disposer; the interface of \p Disposer is:
693             \code
694             template <typename T>
695             struct disposer {
696                 void operator()( T * p )    ;   // disposing operator
697             };
698             \endcode
699             Since the functor call can happen at any time after \p retire call, additional restrictions are imposed to \p Disposer type:
700             - it should be stateless functor
701             - it should be default-constructible
702             - the result of functor call with argument \p p should not depend on where the functor will be called.
703
704             \par Examples:
705             Operator \p delete functor:
706             \code
707             template <typename T>
708             struct disposer {
709                 void operator ()( T * p ) {
710                     delete p;
711                 }
712             };
713
714             // How to call GC::retire method
715             int * p = new int;
716
717             // ... use p in lock-free manner
718
719             cds::gc::HP::retire<disposer>( p ) ;   // place p to retired pointer array of HP GC
720             \endcode
721
722             Functor based on \p std::allocator :
723             \code
724             template <typename ALLOC = std::allocator<int> >
725             struct disposer {
726                 template <typename T>
727                 void operator()( T * p ) {
728                     typedef typename ALLOC::templare rebind<T>::other   alloc_t;
729                     alloc_t a;
730                     a.destroy( p );
731                     a.deallocate( p, 1 );
732                 }
733             };
734             \endcode
735         */
736         template <class Disposer, typename T>
737         static void retire( T * p );   // inline in hp_impl.h
738
739         /// Get current scan strategy
740         static scan_type getScanType()
741         {
742             return static_cast<scan_type>( hp::GarbageCollector::instance().getScanType());
743         }
744
745         /// Set current scan strategy
746         static void setScanType(
747             scan_type nScanType     ///< new scan strategy
748         )
749         {
750             hp::GarbageCollector::instance().setScanType( static_cast<hp::scan_type>(nScanType) );
751         }
752
753         /// Checks if Hazard Pointer GC is constructed and may be used
754         static bool isUsed()
755         {
756             return hp::GarbageCollector::isUsed();
757         }
758
759         /// Forced GC cycle call for current thread
760         /**
761             Usually, this function should not be called directly.
762         */
763         static void scan()  ;   // inline in hp_impl.h
764
765         /// Synonym for \ref scan()
766         static void force_dispose()
767         {
768             scan();
769         }
770     };
771 }}  // namespace cds::gc
772
773 #endif  // #ifndef CDSLIB_GC_IMPL_HP_DECL_H