]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/inline_variant.h
update ceph source to reef 18.2.0
[ceph.git] / ceph / src / common / inline_variant.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:4; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=4 smarttab
3 /*
4 * Copied from:
5 * https://github.com/exclipy/inline_variant_visitor/blob/master/inline_variant.hpp
6 */
7
8 #ifndef INLINE_VARIANT_H
9 #define INLINE_VARIANT_H
10
11 #include <boost/function_types/function_arity.hpp>
12 #include <boost/fusion/algorithm/transformation/transform.hpp>
13 #include <boost/mpl/contains.hpp>
14 #include <boost/mpl/map.hpp>
15 #include <boost/mpl/vector.hpp>
16 #include <boost/mpl/range_c.hpp>
17 #include <boost/noncopyable.hpp>
18
19 #include "function_signature.h"
20
21 namespace detail {
22
23 // A metafunction class for getting the argument type from a unary function or functor type
24 struct function_arg_extractor
25 {
26 // Function is either a function type like void(int const&), or a functor - eg. a class with void operator(int)
27 // Sets type to the argument type with the constness and referenceness stripped (eg. int)
28 template <typename Function>
29 struct apply
30 {
31 private:
32 typedef typename boost::remove_const< typename boost::remove_reference<Function>::type >::type bare_type;
33 typedef typename signature_of<bare_type>::type normalized_function_type;
34 typedef typename boost::function_types::function_arity<normalized_function_type>::type arity;
35 typedef typename boost::function_types::parameter_types<normalized_function_type>::type parameter_types;
36 typedef typename boost::function_types::result_type<normalized_function_type>::type result_type;
37
38 BOOST_STATIC_ASSERT_MSG((arity::value == 1), "make_visitor called with a non-unary function");
39
40 typedef typename boost::mpl::front<parameter_types>::type parameter_type;
41 public:
42 typedef typename boost::remove_const< typename boost::remove_reference<parameter_type>::type >::type type;
43 };
44 };
45
46 struct make_pair
47 {
48 template <typename AType, typename Ind>
49 struct apply {
50 typedef boost::mpl::pair<AType, Ind> type;
51 };
52 };
53
54 // A metafunction class that asserts the second argument is in Allowed, and returns void
55 template<typename Allowed>
56 struct check_in
57 {
58 template <typename Type1, typename Type2>
59 struct apply
60 {
61 private:
62 BOOST_STATIC_ASSERT_MSG((boost::mpl::contains<Allowed, typename boost::mpl::first<Type2>::type>::value),
63 "make_visitor called with spurious handler functions");
64 public:
65 typedef void type;
66 };
67 };
68
69 template <typename Seq>
70 struct as_map
71 {
72 private:
73 struct insert_helper {
74 template <typename M, typename P>
75 struct apply
76 {
77 typedef typename boost::mpl::insert<
78 M,
79 P>::type type;
80 };
81 };
82 public:
83 typedef typename boost::mpl::fold<Seq, boost::mpl::map0<>, insert_helper>::type type;
84 };
85
86 // A functor template suitable for passing into apply_visitor. The constructor accepts the list of handler functions,
87 // which are then exposed through a set of operator()s
88 template <typename Result, typename Variant, typename... Functions>
89 struct generic_visitor : boost::static_visitor<Result>, boost::noncopyable
90 {
91 private:
92 typedef generic_visitor<Result, Variant, Functions...> type;
93
94 // Compute the function_map type
95 typedef boost::mpl::vector<Functions...> function_types;
96 typedef typename boost::mpl::transform<function_types, function_arg_extractor>::type arg_types;
97 typedef typename boost::mpl::transform<
98 arg_types,
99 boost::mpl::range_c<int, 0, boost::mpl::size<arg_types>::value>,
100 make_pair
101 >::type pair_list;
102 typedef typename as_map<pair_list>::type fmap;
103
104 // Check that the argument types are unique
105 BOOST_STATIC_ASSERT_MSG((boost::mpl::size<fmap>::value == boost::mpl::size<arg_types>::value),
106 "make_visitor called with non-unique argument types for handler functions");
107
108 // Check that there aren't any argument types not in the variant types
109 typedef typename boost::mpl::fold<fmap, void, check_in<typename Variant::types> >::type dummy;
110
111 boost::fusion::vector<Functions...> fvec;
112
113
114 template <typename T>
115 Result apply_helper(const T& object, boost::mpl::true_) const {
116 typedef typename boost::mpl::at<fmap, T>::type Ind;
117 return boost::fusion::at<Ind>(fvec)(object);
118 }
119
120 template <typename T>
121 Result apply_helper(const T& object, boost::mpl::false_) const {
122 return Result();
123 }
124
125 BOOST_MOVABLE_BUT_NOT_COPYABLE(generic_visitor)
126
127 public:
128 generic_visitor(BOOST_RV_REF(type) other)
129 :
130 fvec(boost::move(other.fvec))
131 {
132 }
133 generic_visitor(Functions&&... functions)
134 :
135 fvec(std::forward<Functions>(functions)...)
136 {
137 }
138
139 template <typename T>
140 Result operator()(const T& object) const {
141 typedef typename boost::mpl::has_key<fmap, T>::type correct_key;
142 BOOST_STATIC_ASSERT_MSG(correct_key::value,
143 "make_visitor called without specifying handlers for all required types");
144 return apply_helper(object, correct_key());
145 }
146 };
147
148 // A metafunction class for getting the return type of a function
149 struct function_return_extractor
150 {
151 template <typename Function>
152 struct apply : boost::function_types::result_type<typename signature_of<Function>::type>
153 {
154 };
155 };
156
157 // A metafunction class that asserts the two arguments are the same and returns the first one
158 struct check_same
159 {
160 template <typename Type1, typename Type2>
161 struct apply
162 {
163 private:
164 BOOST_STATIC_ASSERT_MSG((boost::is_same<Type1, Type2>::value),
165 "make_visitor called with functions of differing return types");
166 public:
167 typedef Type1 type;
168 };
169 };
170
171 // A metafunction for getting the required generic_visitor type for the set of Functions
172 template <typename Variant, typename... Functions>
173 struct get_generic_visitor
174 {
175 private:
176 typedef boost::mpl::vector<Functions...> function_types;
177 typedef typename boost::mpl::transform<
178 function_types,
179 boost::remove_const< boost::remove_reference<boost::mpl::_1> >
180 >::type bare_function_types;
181 typedef typename boost::mpl::transform<bare_function_types, function_return_extractor>::type return_types;
182
183 public:
184 // Set result_type to the return type of the first function
185 typedef typename boost::mpl::front<return_types>::type result_type;
186 typedef generic_visitor<result_type, Variant, Functions...> type;
187
188 private:
189 // Assert that every return type is the same as the first one
190 typedef typename boost::mpl::fold<return_types, result_type, check_same>::type dummy;
191 };
192
193 // Accepts a set of functions and returns an object suitable for apply_visitor
194 template <typename Variant, typename... Functions>
195 auto make_visitor(BOOST_RV_REF(Functions)... functions)
196 -> typename detail::get_generic_visitor<Variant, Functions...>::type
197 {
198 return typename detail::get_generic_visitor<Variant, Functions...>::type(boost::forward<Functions>(functions)...);
199 }
200
201 }
202
203 template <typename Variant, typename... Functions>
204 auto match(Variant const& variant, BOOST_RV_REF(Functions)... functions)
205 -> typename detail::get_generic_visitor<Variant, Functions...>::result_type
206 {
207 return boost::apply_visitor(detail::make_visitor<Variant>(
208 boost::forward<Functions>(functions)...), variant);
209 }
210
211 #endif