Fix compiler warnings for padding option
[libcds.git] / cds / opt / options.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_OPT_OPTIONS_H
4 #define __CDS_OPT_OPTIONS_H
5
6 /*
7     Framework to define template options
8
9     Editions:
10         2011.01.23 khizmax  Created
11 */
12
13 #include <cds/details/aligned_type.h>
14 #include <cds/user_setup/allocator.h>
15 #include <cds/user_setup/cache_line.h>
16 #include <cds/cxx11_atomic.h>
17 #include <stdlib.h> // rand, srand
18
19 namespace cds {
20
21 /// Framework to define template options
22 /**
23     There are two kind of options:
24     - \p type-option - option that determines a data type. The template argument \p Type of the option is a type.
25     - \p value-option - option that determines a value. The template argument \p Value of the option is a value.
26 */
27 namespace opt {
28
29     /// Predefined options value (generally, for the options that determine the data types)
30     namespace v {}
31
32     /// Type indicates that an option is not specified and the default one should be used
33     struct none
34     {
35         //@cond
36         template <class Base> struct pack: public Base
37         {};
38         //@endcond
39     };
40
41     /// Metafunction for selecting default option value
42     /**
43         Template parameters:
44         - \p Option - option value
45         - \p Default - default option value
46         - \p Value - option value if \p Option is not opt::none
47
48         If \p Option is opt::none, the metafunction result is \p Default, otherwise
49         the result is \p Value.
50
51         Examples:
52         \code
53         // default_spin is cds::lock::Spin
54         typedef typename cds::opt::select_default< cds::opt::none, cds::lock::Spin >::type  default_spin;
55
56         // spin_32bit is cds::lock::Spin32
57         typedef typename cds::opt::select_default< cds::lock::Spin32, cds::lock::Spin >::type  spin_32bit;
58         \endcode
59     */
60     template <typename Option, typename Default, typename Value = Option>
61     struct select_default
62     {
63         typedef Value type ;   ///< metafunction result
64     };
65     //@cond
66     template <typename Default>
67     struct select_default< none, Default >
68     {
69         typedef Default type;
70     };
71     //@endcond
72
73     /// Metafunction to select option value
74     /**
75         This metafunction is intended for extracting the value of the \p Option option.
76         For example,
77         \code
78         #include <cds/opt/options.h>
79         #include <type_traits> // only for testing purpose (static_assert)
80
81         struct tag_a;
82
83         // Define option
84         typedef cds::opt::tag< tag_a >  tag_option;
85
86         // What is the value of the tag_option?
87         // How we can extract tag_a from tag_option?
88         // Here is a solution:
89         typedef cds::opt::value< tag_option >::tag  tag_option_value;
90
91         // tag_option_value is the same as tag_a
92         static_assert( std::is_same< tag_option_value, tag_a >::value, "Error: tag_option_value != tag_a" );
93
94         \endcode
95     */
96     template <typename Option>
97     struct value: public Option::template pack<none>
98     {};
99
100
101     /// [type-option] Option setter specifies a tag
102     /**
103         Suppose, you have a struct
104         \code
105         struct Feature
106         {  .... };
107         \endcode
108         and you want that your class \p X would be derived from several \p Feature:
109         \code
110             class X: public Feature, public Feature
111             { .... };
112         \endcode
113
114         How can you distinguish one \p Feature from another?
115         You may use a tag option:
116         \code
117             template <typename Tag>
118             struct Feature
119             { .... };
120
121             class tag_a;
122             class tag_b;
123             class X: public Feature< tag_a >, public Feature< tag_b >
124             { .... };
125         \endcode
126         Now you can distinguish one \p Feature from another:
127         \code
128             X x;
129             Feature<tag_a>& fa = static_cast< Feature<tag_a> >( x );
130             Feature<tag_b>& fb = static_cast< Feature<tag_b> >( x );
131         \endcode
132
133         \p tag option setter allows you to do things like this for an option-centric approach:
134         \code
135         template <typename ...Options>
136         struct Feature
137         { .... };
138
139         class tag_a;
140         class tag_b;
141         class X: public Feature< tag<tag_a> >, public Feature< tag<tag_b> >
142         { .... };
143         \endcode
144
145         This option setter is widely used in cds::intrusive containers to distinguish
146         between different intrusive part of container's node.
147
148         An incomplete type can serve as a \p Tag.
149     */
150     template <typename Tag>
151     struct tag {
152         //@cond
153         template<class Base> struct pack: public Base
154         {
155             typedef Tag tag;
156         };
157         //@endcond
158     };
159
160     /// [type-option] Option setter specifies lock class
161     /**
162         Specification of the \p Type class is:
163         \code
164         struct Lock {
165             void lock();
166             void unlock();
167         };
168         \endcode
169     */
170     template <typename Type>
171     struct lock_type {
172         //@cond
173         template<class Base> struct pack: public Base
174         {
175             typedef Type lock_type;
176         };
177         //@endcond
178     };
179
180     /// [type-option] Back-off strategy option setter
181     /**
182         Back-off strategy used in some algorithm.
183         See cds::backoff namespace for back-off explanation and supported interface.
184     */
185     template <typename Type>
186     struct back_off {
187         //@cond
188         template <class Base> struct pack: public Base
189         {
190             typedef Type back_off;
191         };
192         //@endcond
193     };
194
195     /// [type-option] Option setter for garbage collecting schema used
196     /**
197         Possible values of \p GC template parameter are:
198         - cds::gc::HP - Hazard Pointer garbage collector
199         - cds::gc::HRC - Gidenstam's garbage collector
200         - cds::gc::PTB - Pass-the-Buck garbage collector
201         - cds::gc::none::GC - No garbage collector (not supported for some containers)
202     */
203     template <typename GC>
204     struct gc {
205         //@cond
206         template <class Base> struct pack: public Base
207         {
208             typedef GC gc;
209         };
210         //@endcond
211     };
212
213     /// [type-option] Option setter for an allocator
214     /**
215         \p Type is allocator with \p std::allocator interface. Default is value of macro CDS_DEFAULT_ALLOCATOR
216         that, in turn, is \p std::allocator.
217
218         The \p libcds containers actively use rebinding to convert an allocator of one type to another. Thus,
219         you may specify any valid type as std::allocator's template parameter.
220
221         See also opt::node_allocator
222     */
223     template <typename Type>
224     struct allocator {
225         //@cond
226         template <typename Base> struct pack: public Base
227         {
228             typedef Type allocator;
229         };
230         //@endcond
231     };
232
233     /// [type-option] Option setter for node allocator
234     /**
235         \p Type is allocator with \p std::allocator interface. Default is value of macro CDS_DEFAULT_ALLOCATOR
236         that, in turn, is \p std::allocator.
237
238         Many node-base containers require an allocator for maintaining data (container's node) and for internal use.
239         Sometimes, this types of allocator should be different for performance reason.
240         For example, we should like to allocate the node from a pool of preallocated nodes.
241         Such pool can be seen as the node allocator.
242
243         Usually, if a container supports \p opt::allocator and \p %opt::node_allocator options
244         and \p opt::node_allocator is not specified the \p %opt::allocator option is used for maintaining the nodes.
245
246         The \p libcds containers actively use rebinding to convert an allocator of one type to another. Thus,
247         you may specify any valid type as std::allocator's template parameter.
248     */
249     template <typename Type>
250     struct node_allocator {
251         //@cond
252             template <typename Base> struct pack: public Base
253             {
254                 typedef Type node_allocator;
255             };
256         //@endcond
257     };
258
259     /// [type-option] Option setter for item counting
260     /**
261         Some data structure (for example, queues) has additional feature for item counting.
262         This option allows to set up appropriate item counting policy for that data structure.
263
264         Predefined option \p Type:
265         - atomicity::empty_item_counter - no item counting performed. It is default policy for many
266             containers
267         - atomicity::item_counter - the class that provides atomically item counting
268         - opt::v::sequential_item_counter - simple non-atomic item counter. This item counter is not intended for
269             concurrent containers and may be used only if it is explicitly noted.
270
271         You may provide other implementation of atomicity::item_counter interface for your needs.
272
273         Note, the item counting in lock-free containers cannot be exact; for example, if
274         item counter for a container returns zero it is not mean that the container is empty.
275         Thus, item counter may be used for statistical purposes only.
276     */
277     template <typename Type>
278     struct item_counter {
279         //@cond
280         template <typename Base> struct pack: public Base
281         {
282             typedef Type item_counter;
283         };
284         //@endcond
285     };
286
287     namespace v {
288         /// Sequential non-atomic item counter
289         /**
290             This type of item counter is not intended for concurrent containers
291             and may be used only if it is explicitly noted.
292         */
293         class sequential_item_counter
294         {
295         public:
296             typedef size_t counter_type    ;  ///< Counter type
297         protected:
298             counter_type  m_nCounter ;      ///< Counter
299
300         public:
301             sequential_item_counter()
302                 : m_nCounter(0)
303             {}
304
305             /// Returns current value of the counter
306             counter_type    value() const
307             {
308                 return m_nCounter;
309             }
310
311             /// Same as \ref value() with relaxed memory ordering
312             operator counter_type() const
313             {
314                 return value();
315             }
316
317             /// Increments the counter. Semantics: postincrement
318             counter_type inc()
319             {
320                 return m_nCounter++;
321             }
322
323             /// Decrements the counter. Semantics: postdecrement
324             counter_type dec()
325             {
326                 return m_nCounter--;
327             }
328
329             /// Preincrement
330             counter_type operator ++()
331             {
332                 return inc() + 1;
333             }
334             /// Postincrement
335             counter_type operator ++(int)
336             {
337                 return inc();
338             }
339
340             /// Predecrement
341             counter_type operator --()
342             {
343                 return dec() - 1;
344             }
345             /// Postdecrement
346             counter_type operator --(int)
347             {
348                 return dec();
349             }
350
351             /// Resets count to 0
352             void reset()
353             {
354                 m_nCounter = 0;
355             }
356         };
357     } // namespace v
358
359     /// Special alignment constants for \ref cds::opt::alignment option
360     enum special_alignment {
361         no_special_alignment = 0,   ///< no special alignment
362         cache_line_alignment = 1    ///< use cache line size defined in cds/user_setup/cache_line.h
363     };
364
365     /// [value-option] Alignment option setter
366     /**
367         Alignment for some internal data of containers. May be useful to solve false sharing problem.
368         \p Value defines desired alignment and it may be power of two integer or predefined values from
369         \ref special_alignment enum.
370     */
371     template <unsigned int Value>
372     struct alignment {
373         //@cond
374         template <typename Base> struct pack: public Base
375         {
376             enum { alignment = Value };
377         };
378         //@endcond
379     };
380
381     //@cond
382     namespace details {
383         template <typename Type, unsigned int Alignment>
384         struct alignment_setter {
385             typedef typename cds::details::aligned_type< Type, Alignment >::type  type;
386         };
387
388         template <typename Type>
389         struct alignment_setter<Type, no_special_alignment> {
390             typedef Type type;
391         };
392
393         template <typename Type>
394         struct alignment_setter<Type, cache_line_alignment> {
395             typedef typename cds::details::aligned_type< Type, c_nCacheLineSize >::type  type;
396         };
397
398     } // namespace details
399     //@endcond
400
401     /// Special padding constants for \p cds::opt::padding option
402     enum special_padding {
403         no_special_padding = 0,   ///< no special padding
404         cache_line_padding = 1,   ///< use cache line size defined in cds/user_setup/cache_line.h
405
406         /// Apply padding only for tiny data of size less than required padding
407         /**
408             The flag means that if your data size is less than the casheline size, the padding is applyed.
409             Otherwise no padding will be applyed.
410
411             This flag is applyed for padding value:
412             \code
413             cds::opt::padding< cds::opt::cache_line_padding | cds::opt::padding_tiny_data_only >;
414             cds::opt::padding< 256 | cds::opt::padding_tiny_data_only >;
415             \endcode
416         */
417         padding_tiny_data_only = 0x80000000,
418
419         //@cond
420         padding_flags = padding_tiny_data_only
421         //@endcond
422     };
423
424     /// [value-option] Padding option setter
425     /**
426         The padding for the internal data of some containers. May be useful to solve false sharing problem.
427         \p Value defines desired padding and it may be power of two integer or predefined values from
428         \p special_padding enum.
429     */
430     template <unsigned int Value>
431     struct padding {
432         //@cond
433         template <typename Base> struct pack: public Base
434         {
435             enum { padding = Value };
436         };
437         //@endcond
438     };
439
440     //@cond
441     namespace details {
442         enum padding_vs_datasize {
443             padding_datasize_less,
444             padding_datasize_equal,
445             padding_datasize_greater
446         };
447
448         template < typename T, unsigned int Padding, bool NoPadding, padding_vs_datasize Relation, bool TinyOnly >
449         struct apply_padding_helper;
450
451         template <typename T, padding_vs_datasize Relation, bool TinyOnly >
452         struct apply_padding_helper < T, 0, true, Relation, TinyOnly >
453         {
454             struct type {
455                 T   data;
456             };
457         };
458
459         template <typename T, unsigned int Padding, bool TinyOnly >
460         struct apply_padding_helper < T, Padding, false, padding_datasize_equal, TinyOnly >
461         {
462             struct type {
463                 T   data;
464             };
465         };
466
467         template <typename T, unsigned int Padding, bool TinyOnly >
468         struct apply_padding_helper < T, Padding, false, padding_datasize_less, TinyOnly >
469         {
470             struct type {
471                 T data;
472                 uint8_t pad_[Padding - sizeof( T )];
473             };
474         };
475
476         template <typename T, unsigned int Padding >
477         struct apply_padding_helper < T, Padding, false, padding_datasize_greater, false >
478         {
479             struct type {
480                 T data;
481                 uint8_t pad_[Padding - sizeof( T ) % Padding];
482             };
483         };
484
485         template <typename T, unsigned int Padding >
486         struct apply_padding_helper < T, Padding, false, padding_datasize_greater, true >
487         {
488             struct type {
489                 T data;
490             };
491         };
492
493         template <typename T, unsigned int Padding >
494         struct apply_padding
495         {
496         private:
497             enum { padding = Padding & ~padding_flags };
498
499         public:
500             static CDS_CONSTEXPR const size_t c_nPadding = 
501                 static_cast<unsigned int>(padding) == static_cast<unsigned int>(cache_line_padding) ? cds::c_nCacheLineSize : 
502                 static_cast<unsigned int>(padding) == static_cast<unsigned int>(no_special_padding) ? 0 : padding;
503
504             static_assert( (c_nPadding & (c_nPadding - 1)) == 0, "Padding must be a power-of-two number" );
505
506             typedef typename apply_padding_helper< T,
507                 c_nPadding,
508                 c_nPadding == 0,
509                 sizeof( T ) < c_nPadding ? padding_datasize_less : sizeof( T ) == c_nPadding ? padding_datasize_equal : padding_datasize_greater,
510                 (Padding & padding_tiny_data_only) != 0 
511             >::type type;
512         };
513
514     } // namespace details
515     //@endcond
516
517
518     /// [type-option] Generic option setter for statisitcs
519     /**
520         This option sets a type to gather statistics.
521         The option is generic - no predefined type(s) is provided.
522         The particular \p Type of statistics depends on internal structure of the object.
523     */
524     template <typename Type>
525     struct stat {
526         //@cond
527         template <typename Base> struct pack: public Base
528         {
529             typedef Type stat;
530         };
531         //@endcond
532     };
533
534     /// [type-option] Option setter for C++ memory model
535     /**
536         The <b>cds</b> library supports following memory ordering constraints for atomic operations in container implementation:
537         - v::relaxed_ordering - relaxed C++ memory model. This mode supports full set of memory ordering constraints:
538             \p memory_order_relaxed, \p memory_order_acquire, \p memory_order_release and so on.
539         - v::sequential_consistent - sequentially consistent C++ memory model (default memory ordering for C++). In
540             this mode any memory ordering constraint maps to \p memory_order_seq_cst.
541
542         The \p Type template parameter can be v::relaxed_ordering or v::sequential_consistent.
543
544         You may mix different memory ordering options for different containers: one declare as sequentially consistent,
545         another declare as relaxed.
546         Usually, v::relaxed_ordering is the default memory ordering for <b>cds</b> containers.
547     */
548     template <typename Type>
549     struct memory_model {
550         //@cond
551         template <typename Base> struct pack: public Base
552         {
553             typedef Type memory_model;
554         };
555         //@endcond
556     };
557
558     namespace v {
559         /// Relaxed memory ordering model
560         /**
561             In this memory model the memory constraints are defined according to C++ Memory Model specification.
562
563             See opt::memory_model for explanations
564         */
565         struct relaxed_ordering {
566             //@cond
567
568             // For new C++11 (cds-1.1.0)
569             static const atomics::memory_order memory_order_relaxed    = atomics::memory_order_relaxed;
570             static const atomics::memory_order memory_order_consume    = atomics::memory_order_consume;
571             static const atomics::memory_order memory_order_acquire    = atomics::memory_order_acquire;
572             static const atomics::memory_order memory_order_release    = atomics::memory_order_release;
573             static const atomics::memory_order memory_order_acq_rel    = atomics::memory_order_acq_rel;
574             static const atomics::memory_order memory_order_seq_cst    = atomics::memory_order_seq_cst;
575             //@endcond
576         };
577
578         /// Sequential consistent memory ordering model
579         /**
580             In this memory model any memory constraint is equivalent to \p memory_order_seq_cst.
581
582             See opt::memory_model for explanations
583         */
584         struct sequential_consistent {
585             //@cond
586
587             // For new C++11 (cds-1.1.0)
588             static const atomics::memory_order memory_order_relaxed    = atomics::memory_order_seq_cst;
589             static const atomics::memory_order memory_order_consume    = atomics::memory_order_seq_cst;
590             static const atomics::memory_order memory_order_acquire    = atomics::memory_order_seq_cst;
591             static const atomics::memory_order memory_order_release    = atomics::memory_order_seq_cst;
592             static const atomics::memory_order memory_order_acq_rel    = atomics::memory_order_seq_cst;
593             static const atomics::memory_order memory_order_seq_cst    = atomics::memory_order_seq_cst;
594             //@endcond
595         };
596     } // namespace v
597
598     /// [type-option] Base type traits option setter
599     /**
600         This option setter is intended generally for internal use for type rebinding.
601     */
602     template <typename Type>
603     struct type_traits {
604         //@cond
605         template <typename Base> struct pack: public Base
606         {
607             typedef Type type_traits;
608         };
609         //@endcond
610     };
611
612     /// Resizing policy option
613     /**
614         This option specifies the resizing policy that decides when to resize a container.
615         Used in some containers, for example, in container::StripedHashSet, intrusive::StripedHashSet.
616
617         The real resizing policy specified by \p Type does strongly depend on a container
618         that supports this option, see container documentation about possibly \p Type values.
619     */
620     template <typename Type>
621     struct resizing_policy {
622         //@cond
623         template <typename Base> struct pack: public Base
624         {
625             typedef Type resizing_policy;
626         };
627         //@endcond
628     };
629
630     /// Copy policy option
631     /**
632         The copy policy defines an item copying algorithm which is used, for example, when a container is resized.
633         It is very specific algorithm depending on type of the container.
634     */
635     template <typename Type>
636     struct copy_policy {
637         //@cond
638         template <typename Base> struct pack: public Base
639         {
640             typedef Type copy_policy;
641         };
642         //@endcond
643     };
644
645     /// Swap policy option
646     /**
647         The swap policy specifies an algorithm for swapping two objects.
648         Usually, the default policy is \p std::swap (see opt::v::default_swap_policy):
649
650         @code
651         struct std_swap {
652             template <typename T>
653             void operator ()( T& v1, T& v2 )
654             {
655                 std::swap( v1, v2 );
656             }
657         };
658         @endcode
659     */
660     template <typename Type>
661     struct swap_policy {
662         //@cond
663         template <typename Base> struct pack: public Base
664         {
665             typedef Type swap_policy;
666         };
667         //@endcond
668     };
669
670     namespace v {
671
672         /// Default swap policy (see opt::swap_policy option)
673         /**
674             The default swap policy is wrappr around \p std::swap algorithm.
675         */
676         struct default_swap_policy {
677             /// Performs swapping of \p v1 and \p v2 using \p std::swap algo
678             template <typename T>
679             void operator()( T& v1, T& v2 ) const
680             {
681                 std::swap( v1, v2 );
682             }
683         };
684     } // namespace v
685
686     /// Move policy option
687     /**
688         The move policy specifies an algorithm for moving object content.
689         In trivial case, it can be simple assignment.
690
691         The move interface is:
692         \code
693         template <typename T>
694         struct move_policy {
695             void operator()( T& dest, T& src );
696         };
697         \endcode
698
699         Note that in move algorithm the \p src source argument can be changed too.
700         So you can use move semantics.
701
702         Usually, the default move policy is opt::v::assignment_move_policy
703     */
704     template <typename Type>
705     struct move_policy {
706         //@cond
707         template <typename Base> struct pack: public Base
708         {
709             typedef Type move_policy;
710         };
711         //@endcond
712     };
713
714     namespace v {
715         /// \ref opt::move_policy "Move policy" based on assignment operator
716         struct assignment_move_policy
717         {
718             /// <tt> dest = src </tt>
719             template <typename T>
720             void operator()( T& dest, T const& src ) const
721             {
722                 dest = src;
723             }
724         };
725     } // namespace v
726
727     /// [value-option] Enable sorting
728     /**
729         This option enables (<tt>Enable = true</tt>) or disables (<tt>Enable == false</tt>)
730         sorting of a container.
731     */
732     template <bool Enable>
733     struct sort {
734         //@cond
735         template <typename Base> struct pack: public Base
736         {
737             static bool const sort = Enable;
738         };
739         //@endcond
740     };
741
742     /// [type-option] Concurrent access policy
743     /**
744         This option specifies synchronization strategy for fine-grained lock-based containers.
745         The option has no predefined \p Policy type.
746         For each container that accepts this option the range of available \p Policy types
747         is unique.
748     */
749     template <typename Policy>
750     struct mutex_policy {
751         //@cond
752         template <typename Base> struct pack: public Base
753         {
754             typedef Policy mutex_policy;
755         };
756         //@endcond
757     };
758
759
760     /// [type-option] Random number generator
761     /**
762         The option specifies a random number generator.
763         \p Random can be any STL random number generator producing
764         unsigned integer: \p std::linear_congruential_engine,
765         \p std::mersenne_twister_engine, \p std::subtract_with_carry_engine
766         and so on, or opt::v::c_rand.
767
768     */
769     template <typename Random>
770     struct random_engine {
771         //@cond
772         template <typename Base> struct pack: public Base
773         {
774             typedef Random random_engine;
775         };
776         //@endcond
777     };
778
779     namespace v {
780         /// \p rand() -base random number generator
781         /**
782             This generator returns a pseudorandom integer in the range 0 to \p RAND_MAX (32767).
783         */
784         struct c_rand {
785             typedef unsigned int result_type; ///< Result type
786
787             /// Constructor initializes object calling \p srand()
788             c_rand()
789             {
790                 srand(1);
791             }
792
793             /// Returns next random number calling \p rand()
794             result_type operator()()
795             {
796                 return (result_type) rand();
797             }
798         };
799     } // namespace v
800
801     //@cond
802     // For internal use
803     template <typename Accessor>
804     struct key_accessor {
805         template <typename Base> struct pack: public Base
806         {
807             typedef Accessor key_accessor;
808         };
809     };
810
811     template <typename Traits, typename ReplaceWith, typename WhatReplace = none >
812     struct replace_key_accessor {
813         typedef typename std::conditional<
814             std::is_same< typename Traits::key_accessor, WhatReplace >::value,
815             typename opt::key_accessor< ReplaceWith >::template pack< Traits >,
816             Traits
817         >::type type;
818     };
819     //@endcond
820
821 }}  // namespace cds::opt
822
823 #include <cds/opt/make_options_var.h>
824
825 #endif  // #ifndef __CDS_OPT_OPTIONS_H