1 /* Copyright 2003-2019 Joaquin M Lopez Munoz.
2  * Distributed under the Boost Software License, Version 1.0.
3  * (See accompanying file LICENSE_1_0.txt or copy at
4  * http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * See http://www.boost.org/libs/multi_index for library home page.
7  */
8 
9 #ifndef BOOST_MULTI_INDEX_KEY_HPP
10 #define BOOST_MULTI_INDEX_KEY_HPP
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
17 #include <boost/multi_index/composite_key.hpp>
18 #include <boost/multi_index/global_fun.hpp>
19 #include <boost/multi_index/member.hpp>
20 #include <boost/multi_index/mem_fun.hpp>
21 
22 #if __cplusplus>=201703L||\
23     defined(BOOST_MSVC)&&defined(__cpp_nontype_template_parameter_auto)
24 
25 #define BOOST_MULTI_INDEX_KEY_SUPPORTED
26 
27 #include <boost/multi_index/detail/is_function.hpp>
28 #include <boost/preprocessor/facilities/empty.hpp>
29 #include <type_traits>
30 
31 namespace boost{
32 
33 namespace multi_index{
34 
35 /* C++17 terse key specification syntax */
36 
37 namespace detail{
38 
39 template<typename T,T,typename=void>
40 struct typed_key_impl;
41 
42 template<typename Class,typename Type,Type Class::*PtrToMember>
43 struct typed_key_impl<
44   Type Class::*,PtrToMember,
45   typename std::enable_if<!is_function<Type>::value>::type
46 >
47 {
48   using value_type=Class;
49   using type=member<Class,Type,PtrToMember>;
50 };
51 
52 #define BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL(qualifier,extractor)            \
53 template<                                                                    \
54   typename Class,typename Type,Type (Class::*PtrToMemberFunction)()qualifier \
55 >                                                                            \
56 struct typed_key_impl<Type (Class::*)()qualifier,PtrToMemberFunction>        \
57 {                                                                            \
58   using value_type=Class;                                                    \
59   using type=extractor<Class,Type,PtrToMemberFunction>;                      \
60 };
61 
62 BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL(                ,mem_fun)
63 BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL(const           ,const_mem_fun)
64 BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL(volatile        ,volatile_mem_fun)
65 BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL(const volatile  ,cv_mem_fun)
66 BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL(&               ,ref_mem_fun)
67 BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL(const&          ,cref_mem_fun)
68 BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL(volatile&       ,vref_mem_fun)
69 BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL(const volatile& ,cvref_mem_fun)
70 
71 #undef BOOST_MULTI_INDEX_KEY_TYPED_KEY_IMPL
72 
73 template<class Value,typename Type,Type (*PtrToFunction)(Value)>
74 struct typed_key_impl<Type (*)(Value),PtrToFunction>
75 {
76   using value_type=Value;
77   using type=global_fun<Value,Type,PtrToFunction>;
78 };
79 
80 template<typename T>
81 struct remove_noexcept{using type=T;};
82 
83 #define BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(qualifier) \
84 template<typename R,typename C,typename... Args>                \
85 struct remove_noexcept<R(C::*)(Args...)qualifier noexcept>      \
86   {using type=R(C::*)(Args...)qualifier;};                      \
87                                                                 \
88 template<typename R,typename C,typename... Args>                \
89 struct remove_noexcept<R(C::*)(Args...,...)qualifier noexcept>  \
90   {using type=R(C::*)(Args...,...)qualifier;};
91 
92 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(BOOST_PP_EMPTY())
93                                              /* VS warns without dummy arg */
94 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(const)
95 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(volatile)
96 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(const volatile)
97 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(&)
98 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(const&)
99 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(volatile&)
100 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(const volatile&)
101 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(&&)
102 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(const&&)
103 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(volatile&&)
104 BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT(const volatile&&)
105 
106 #undef BOOST_MULTI_INDEX_KEY_REMOVE_MEMFUN_NOEXCEPT
107 
108 template<typename R,typename... Args>
109 struct remove_noexcept<R(*)(Args...)noexcept>{using type=R(*)(Args...);};
110 template<typename R,typename... Args>
111 struct remove_noexcept<R(*)(Args...,...)noexcept>
112   {using type=R(*)(Args...,...);};
113 
114 template<typename T>
115 using remove_noexcept_t=typename remove_noexcept<T>::type;
116 
117 template<auto... Keys>
118 struct key_impl;
119 
120 template<auto Key>
121 struct key_impl<Key>:typed_key_impl<remove_noexcept_t<decltype(Key)>,Key>{};
122 
123 template<typename... Ts>
124 struct least_generic;
125 
126 template<typename T0,typename... Ts>
127 struct least_generic<T0,Ts...>
128 {
129   using type=T0;
130 };
131 
132 template<typename T0,typename T1,typename... Ts>
133 struct least_generic<T0,T1,Ts...>
134 {
135   static_assert(
136     std::is_convertible<const T0&,const T1&>::value||
137     std::is_convertible<const T1&,const T0&>::value,
138     "one type should be convertible to the other");
139 
140   using type=typename least_generic<
141     typename std::conditional<
142       std::is_convertible<const T0&,const T1&>::value,T0,T1
143     >::type,
144     Ts...
145   >::type;
146 };
147 
148 template<auto Key0,auto... Keys>
149 struct key_impl<Key0,Keys...>
150 {
151   using value_type=typename least_generic<
152     typename std::decay<typename key_impl<Key0>::value_type>::type,
153     typename std::decay<typename key_impl<Keys>::value_type>::type...
154   >::type;
155   using type=composite_key<
156     value_type,
157     typename key_impl<Key0>::type,
158     typename key_impl<Keys>::type...
159   >;
160 };
161 
162 template<typename=composite_key<void,void>>
163 struct composite_key_size;
164 
165 template<typename... Args>
166 struct composite_key_size<composite_key<Args...>>
167 {
168   static constexpr auto value=sizeof...(Args)-1;
169 };
170 
171 template<auto... Keys>
172 struct limited_size_key_impl
173 {
174   static_assert(
175     sizeof...(Keys)<=composite_key_size<>::value,
176     "specified number of keys must meet the limits of "
177     "boost::multi_index::composite_key");
178   using type=typename key_impl<Keys...>::type;
179 };
180 
181 } /* namespace multi_index::detail */
182 
183 template<auto... Keys>
184 using key=typename detail::limited_size_key_impl<Keys...>::type;
185 
186 } /* namespace multi_index */
187 
188 } /* namespace boost */
189 
190 #endif
191 #endif
192