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