1 /* Copyright 2003-2013 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_DETAIL_VARTEMPL_SUPPORT_HPP
10 #define BOOST_MULTI_INDEX_DETAIL_VARTEMPL_SUPPORT_HPP
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 /* Utilities for emulation of variadic template functions. Variadic packs are
17  * replaced by lists of BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS parameters:
18  *
19  *   - typename... Args            --> BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK
20  *   - Args&&... args              --> BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK
21  *   - std::forward<Args>(args)... --> BOOST_MULTI_INDEX_FORWARD_PARAM_PACK
22  *
23  * Forwarding emulated with Boost.Move. A template functions foo_imp
24  * defined in such way accepts *exactly* BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS
25  * arguments: variable number of arguments is emulated by providing a set of
26  * overloads foo forwarding to foo_impl with
27  *
28  *   BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
29  *   BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG (initial extra arg)
30  *
31  * which fill the extra args with boost::multi_index::detail::noarg's.
32  * boost::multi_index::detail::vartempl_placement_new works the opposite
33  * way: it acceps a full a pointer x to Value and a
34  * BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK and forwards to
35  * new(x) Value(args) where args is the argument pack after discarding
36  * noarg's.
37  *
38  * Emulation decays to the real thing when the compiler supports variadic
39  * templates and move semantics natively.
40  */
41 
42 #include <boost/config.hpp>
43 
44 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)||\
45     defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
46 
47 #include <boost/move/core.hpp>
48 #include <boost/move/utility.hpp>
49 #include <boost/preprocessor/arithmetic/add.hpp>
50 #include <boost/preprocessor/arithmetic/sub.hpp>
51 #include <boost/preprocessor/cat.hpp>
52 #include <boost/preprocessor/control/if.hpp>
53 #include <boost/preprocessor/facilities/empty.hpp>
54 #include <boost/preprocessor/facilities/intercept.hpp>
55 #include <boost/preprocessor/logical/and.hpp>
56 #include <boost/preprocessor/punctuation/comma.hpp>
57 #include <boost/preprocessor/punctuation/comma_if.hpp>
58 #include <boost/preprocessor/repetition/enum.hpp>
59 #include <boost/preprocessor/repetition/enum_params.hpp>
60 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
61 #include <boost/preprocessor/seq/elem.hpp>
62 
63 #if !defined(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS)
64 #define BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS 5
65 #endif
66 
67 #define BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK                        \
68 BOOST_PP_ENUM_PARAMS(                                                \
69   BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,typename T)
70 
71 #define BOOST_MULTI_INDEX_VARTEMPL_ARG(z,n,_)                        \
72 BOOST_FWD_REF(BOOST_PP_CAT(T,n)) BOOST_PP_CAT(t,n)
73 
74 #define BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK                        \
75 BOOST_PP_ENUM(                                                       \
76   BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,                             \
77   BOOST_MULTI_INDEX_VARTEMPL_ARG,~)
78 
79 #define BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG(z,n,_)                \
80 boost::forward<BOOST_PP_CAT(T,n)>(BOOST_PP_CAT(t,n))
81 
82 #define BOOST_MULTI_INDEX_FORWARD_PARAM_PACK                         \
83 BOOST_PP_ENUM(                                                       \
84   BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,                             \
85   BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~)
86 
87 namespace boost{namespace multi_index{namespace detail{
88 struct noarg{};
89 }}}
90 
91 /* call vartempl function without args */
92 
93 #define BOOST_MULTI_INDEX_NULL_PARAM_PACK                            \
94 BOOST_PP_ENUM_PARAMS(                                                \
95   BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,                             \
96   boost::multi_index::detail::noarg() BOOST_PP_INTERCEPT)
97 
98 #define BOOST_MULTI_INDEX_TEMPLATE_N(n)                              \
99 template<BOOST_PP_ENUM_PARAMS(n,typename T)>
100 
101 #define BOOST_MULTI_INDEX_TEMPLATE_0(n)
102 
103 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_AUX(z,n,data)        \
104 BOOST_PP_IF(n,                                                       \
105   BOOST_MULTI_INDEX_TEMPLATE_N,                                      \
106   BOOST_MULTI_INDEX_TEMPLATE_0)(n)                                   \
107 BOOST_PP_SEQ_ELEM(0,data) /* ret */                                  \
108 BOOST_PP_SEQ_ELEM(1,data) /* name_from */ (                          \
109   BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_ARG,~))                 \
110 {                                                                    \
111   return BOOST_PP_SEQ_ELEM(2,data) /* name_to */ (                   \
112     BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~)        \
113     BOOST_PP_COMMA_IF(                                               \
114       BOOST_PP_AND(                                                  \
115         n,BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n)))    \
116     BOOST_PP_ENUM_PARAMS(                                            \
117       BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n),         \
118       boost::multi_index::detail::noarg() BOOST_PP_INTERCEPT)        \
119   );                                                                 \
120 }
121 
122 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(                     \
123   ret,name_from,name_to)                                             \
124 BOOST_PP_REPEAT_FROM_TO(                                             \
125   0,BOOST_PP_ADD(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,1),           \
126   BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_AUX,                       \
127   (ret)(name_from)(name_to))
128 
129 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG_AUX(       \
130   z,n,data)                                                          \
131 BOOST_PP_IF(n,                                                       \
132   BOOST_MULTI_INDEX_TEMPLATE_N,                                      \
133   BOOST_MULTI_INDEX_TEMPLATE_0)(n)                                   \
134 BOOST_PP_SEQ_ELEM(0,data) /* ret */                                  \
135 BOOST_PP_SEQ_ELEM(1,data) /* name_from */ (                          \
136   BOOST_PP_SEQ_ELEM(3,data) BOOST_PP_SEQ_ELEM(4,data) /* extra arg */\
137   BOOST_PP_COMMA_IF(n)                                               \
138   BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_ARG,~))                 \
139 {                                                                    \
140   return BOOST_PP_SEQ_ELEM(2,data) /* name_to */ (                   \
141     BOOST_PP_SEQ_ELEM(4,data) /* extra_arg_name */                   \
142     BOOST_PP_COMMA_IF(n)                                             \
143     BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~)        \
144     BOOST_PP_COMMA_IF(                                               \
145       BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n))         \
146     BOOST_PP_ENUM_PARAMS(                                            \
147       BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n),         \
148       boost::multi_index::detail::noarg() BOOST_PP_INTERCEPT)        \
149   );                                                                 \
150 }
151 
152 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(           \
153   ret,name_from,name_to,extra_arg_type,extra_arg_name)               \
154 BOOST_PP_REPEAT_FROM_TO(                                             \
155   0,BOOST_PP_ADD(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,1),           \
156   BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG_AUX,             \
157   (ret)(name_from)(name_to)(extra_arg_type)(extra_arg_name))
158 
159 namespace boost{
160 
161 namespace multi_index{
162 
163 namespace detail{
164 
165 #define BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW_AUX(z,n,name)    \
166 template<                                                            \
167   typename Value                                                     \
168   BOOST_PP_COMMA_IF(n)                                               \
169   BOOST_PP_ENUM_PARAMS(n,typename T)                                 \
170 >                                                                    \
171 Value* name(                                                         \
172   Value* x                                                           \
173   BOOST_PP_COMMA_IF(n)                                               \
174   BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_ARG,~)                  \
175   BOOST_PP_COMMA_IF(                                                 \
176     BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n))           \
177   BOOST_PP_ENUM_PARAMS(                                              \
178     BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n),           \
179     BOOST_FWD_REF(noarg) BOOST_PP_INTERCEPT))                        \
180 {                                                                    \
181   return new(x) Value(                                               \
182     BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~));      \
183 }
184 
185 #define BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW(name)            \
186 BOOST_PP_REPEAT_FROM_TO(                                             \
187   0,BOOST_PP_ADD(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,1),           \
188   BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW_AUX,                   \
189   name)
190 
191 BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW(vartempl_placement_new)
192 
193 #undef BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW_AUX
194 #undef BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW
195 
196 } /* namespace multi_index::detail */
197 
198 } /* namespace multi_index */
199 
200 } /* namespace boost */
201 
202 #else
203 
204 /* native variadic templates support */
205 
206 #include <utility>
207 
208 #define BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK typename... Args
209 #define BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK Args&&... args
210 #define BOOST_MULTI_INDEX_FORWARD_PARAM_PACK  std::forward<Args>(args)...
211 #define BOOST_MULTI_INDEX_NULL_PARAM_PACK
212 
213 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(                     \
214   ret,name_from,name_to)                                             \
215 template<typename... Args> ret name_from(Args&&... args)             \
216 {                                                                    \
217   return name_to(std::forward<Args>(args)...);                       \
218 }
219 
220 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(           \
221   ret,name_from,name_to,extra_arg_type,extra_arg_name)               \
222 template<typename... Args> ret name_from(                            \
223   extra_arg_type extra_arg_name,Args&&... args)                      \
224 {                                                                    \
225   return name_to(extra_arg_name,std::forward<Args>(args)...);        \
226 }
227 
228 namespace boost{
229 
230 namespace multi_index{
231 
232 namespace detail{
233 
234 template<typename Value,typename... Args>
235 Value* vartempl_placement_new(Value*x,Args&&... args)
236 {
237   return new(x) Value(std::forward<Args>(args)...);
238 }
239 
240 } /* namespace multi_index::detail */
241 
242 } /* namespace multi_index */
243 
244 } /* namespace boost */
245 
246 #endif
247 #endif
248