forked from qdrvm/kagome
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvariant_builder.hpp
98 lines (86 loc) · 2.81 KB
/
variant_builder.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
* Copyright Quadrivium LLC
* All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <functional>
#include <type_traits>
#include <vector>
#include <boost/mpl/at.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/int.hpp>
#include <boost/variant.hpp>
namespace kagome::common {
/// Impl details for boost::variant initialization by type index at runtime
namespace dynamic_variant {
/**
* Initializes variant with default constructed object of some type
* @tparam Concrete - a type to construct and assign to variant
* @tparam Variant - type of variant variable
* @param v - variant to intiialize
*/
template <typename Concrete, typename Variant>
void init_variant(Variant &v) {
v = Concrete{};
}
/// Prepares initializers for each type of variant
template <typename Variant>
struct functors_vector_builder {
std::vector<std::function<void(Variant &)>> *vec;
template <typename Element>
void operator()(Element) {
vec->push_back(&init_variant<Element, Variant>);
}
};
template <typename>
struct is_boost_variant : std::false_type {};
/**
* Compile time checker that the type is boost::variant.
*
* Usage example:
* ```
* using MyVariant = boost::variant<int, std::string>;
* ...
* static_assert(is_boost_variant<MyVariant>::value);
* ```
*
* @tparam Ts types held inside boost::variant
*/
template <typename... Ts>
struct is_boost_variant<boost::variant<Ts...>> : std::true_type {};
} // namespace dynamic_variant
/**
* Constructs a value inside boost::variant by type index from variant's
* definition at runtime.
*
* Allows operating with variants as easy as converting an int to enum value
* but with more complex types than in enums.
*
* No need to explicitly specify types below, compiler infers them from
* constructor
* @tparam Variant type defenition of boost::variant
* @tparam Types types held inside Variant
*/
template <typename Variant, typename Types = typename Variant::types>
class VariantBuilder {
Variant &v_;
std::vector<std::function<void(Variant &)>> funcs_;
public:
/// @param v boost::variant variable to initialize
explicit VariantBuilder(Variant &v) : v_(v) {
static_assert(dynamic_variant::is_boost_variant<Variant>::value);
dynamic_variant::functors_vector_builder<Variant> builder = {&funcs_};
boost::mpl::for_each<Types>(builder);
}
/**
* Initializes the referenced variant with default constructed instance of
* object of type at \param index within \tparam Variant::types
*
* @param index index of type
*/
void init(size_t index) {
funcs_[index](v_);
}
};
} // namespace kagome::common