882f644031eeb28f348a794e50fb2d48483d20e9
[libcds.git] / cds / opt / hash.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_OPT_HASH_H
4 #define __CDS_OPT_HASH_H
5
6 #include <tuple>
7 #include <functional>
8 #include <cds/opt/options.h>
9
10 namespace cds { namespace opt {
11
12     /// [type-option] Option setter for a hash function
13     /**
14         This option setter specifies hash functor used in unordered containers.
15
16         The default value  of template argument \p Functor is \p cds::opt::v::hash
17         that is synonym for <tt>std::hash</tt> implementation of standard library.
18     */
19     template <typename Functor>
20     struct hash {
21         //@cond
22         template <typename Base> struct pack: public Base
23         {
24             typedef Functor hash;
25         };
26         //@endcond
27     };
28
29     namespace v {
30         //@cond
31         using std::hash;
32
33         /// Metafunction selecting default hash implementation
34         /**
35             The metafunction selects appropriate hash functor implementation.
36             If \p Hash is not equal to opt::none, then result of metafunction is \p Hash.
37             Otherwise, the result is <tt> std::hash<Q> </tt>.
38
39             Note that default hash function like <tt> std::hash<Q> </tt>
40             is generally not suitable for complex type \p Q and its derivatives.
41             You should manually provide particular hash functor for such types.
42         */
43         template <typename Hash>
44         struct hash_selector
45         {
46             typedef Hash    type;   ///< resulting implementation of hash functor
47         };
48
49         template <>
50         struct hash_selector<opt::none>
51         {
52             struct type {
53                 template <typename Q>
54                 size_t operator()( Q const& key ) const
55                 {
56                     return std::hash<Q>()( key );
57                 }
58             };
59         };
60         //@endcond
61     }   // namespace v
62
63     //@cond
64     namespace details {
65         template <class> struct hash_list;
66         template <typename... Functors>
67         struct hash_list< std::tuple<Functors...> >
68         {
69             static size_t const size = sizeof...(Functors);
70             typedef size_t values[size];
71             typedef std::tuple<Functors...> hash_tuple_type;
72
73             hash_tuple_type hash_tuple;
74
75             hash_list()
76             {}
77
78             hash_list( hash_tuple_type const& t)
79                 : hash_tuple( t )
80             {}
81             hash_list( hash_tuple_type&& t)
82                 : hash_tuple( std::forward<hash_tuple_type>(t) )
83             {}
84
85             template <size_t I, typename T>
86             typename std::enable_if< (I == sizeof...(Functors)) >::type apply( size_t * dest, T const& v ) const
87             {}
88
89             template <size_t I, typename T>
90             typename std::enable_if< (I < sizeof...(Functors)) >::type apply( size_t * dest, T const& v ) const
91             {
92                 dest[I] = std::get<I>( hash_tuple )( v );
93                 apply<I+1>( dest, v );
94             }
95
96             template <typename T>
97             void operator()( size_t * dest, T const& v ) const
98             {
99                 apply<0>( dest, v );
100             }
101         };
102     } // namespace details
103     //@endcond
104
105     /// Declare tuple for hash functors \p Functors
106     template <typename... Functors>
107     using hash_tuple = details::hash_list< std::tuple< Functors... >>;
108
109     //@cond
110     // At least, two functors must be provided. Single functor is not supported
111     template <typename Functor> struct hash< std::tuple<Functor> >;
112     //@endcond
113
114     /// Multi-functor hash option setter - specialization for std::tuple
115     template <typename... Functors>
116     struct hash< std::tuple<Functors...> >
117     {
118         //@cond
119         template <typename Base> struct pack: public Base
120         {
121             typedef details::hash_list< std::tuple<Functors...> >  hash;
122         };
123         //@endcond
124     };
125
126
127     //@cond
128     namespace details {
129
130         template <class HashList, typename WrappedType, typename Wrapper>
131         struct hash_list_wrapper {
132             typedef HashList                            hash_list;
133             typedef WrappedType                         wrapped_type;
134             typedef Wrapper                             wrapper_type;
135
136             typedef typename hash_list::hash_tuple_type hash_tuple_type;
137             static size_t const size = hash_list::size;
138
139             hash_list   m_wrappedList;
140
141             hash_list_wrapper()
142             {}
143             hash_list_wrapper( hash_tuple_type const& t)
144                 : m_wrappedList( t )
145             {}
146             hash_list_wrapper( hash_tuple_type&& t)
147                 : m_wrappedList( std::forward<hash_tuple_type>(t) )
148             {}
149
150             void operator()( size_t * dest, wrapped_type const& what ) const
151             {
152                 m_wrappedList( dest, wrapper_type()( what ));
153             }
154
155             template <typename Q>
156             void operator()( size_t * dest, Q const& what) const
157             {
158                 m_wrappedList( dest, what );
159             }
160         };
161
162     } // namespace details
163     //@endcond
164
165 }} // namespace cds::opt
166
167 #endif // #ifndef __CDS_OPT_HASH_H