Menu

[8ba648]: / variant.hpp  Maximize  Restore  History

Download this file

190 lines (156 with data), 4.9 kB

  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
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#ifndef CHILON_VARIANT_HPP
#define CHILON_VARIANT_HPP
#include <chilon/meta/at.hpp>
#include <chilon/meta/index_of.hpp>
#include <chilon/meta/max.hpp>
#include <chilon/meta/return.hpp>
#include <chilon/singleton.hpp>
#include <boost/ptr_container/ptr_array.hpp>
#include <utility>
#include <assert.h>
namespace chilon {
/**
* A simple variant which can store one of any of the types in T that
* stores all data on the stack.
* Currently destructors are never called, so types with non-trivial
* destructors are not supported, but this can be fixed when more of the
* c++0x type_traits are complete.
* \tparam T pack of valid types the variant may store.
*/
template <class... T>
struct variant {
enum { n_elements = sizeof...(T) };
enum { max_size = meta::max<sizeof(T)...>::value };
typedef typename meta::head<T...>::type head_type;
template <class V>
variant& operator=(V const& rhs) {
int const new_index = meta::index_of<V, T...>::value;
static_assert(
new_index < n_elements, "type does not exist in variant");
type_index_ = new_index;
cast<V>() = rhs;
return *this;
}
/**
* Change variant to represent a default constructed V
*/
template <class V>
V& construct_default() {
int const new_index = meta::index_of<V, T...>::value;
static_assert(
new_index < n_elements, "type does not exist in variant");
type_index_ = new_index;
return *new (data_) V;
}
/**
* Unsafe access to type at index I.
*/
template <int I>
typename meta::at<I, T...>::type& at() {
static_assert(I < n_elements, "index too high");
#ifndef NDEBUG
assert(type_index_ == I);
#endif
return cast<typename meta::at<I, T...>::type>();
}
/**
* Unsafe const access to type at index I.
*/
template <int I>
typename meta::at<I, T...>::type const& at() const {
static_assert(I < n_elements, "type not found in variant");
#ifndef NDEBUG
assert(type_index_ == I);
#endif
return cast<typename meta::at<I, T...>::type>();
}
template <class Y>
Y& at() {
return at<meta::index_of<Y, T...>::value>();
}
int const type_index() const { return type_index_; }
private:
// unsafe casts
template <class Y>
Y const& cast() const {
return (*reinterpret_cast<Y const *>(data_));
}
template <class Y>
Y& cast() {
return (*reinterpret_cast<Y *>(data_));
}
public:
// default constructor constructs the first element in the tuple
variant() : type_index_(0) {
new (data_) head_type;
}
private:
char data_[max_size];
int type_index_;
};
namespace detail {
template <class T, class F>
struct variant_apply_helper {};
template <class T, class F>
struct variant_apply_lookup_table {
struct apply {
virtual auto operator()(T const& v, F const& f) -> decltype(f(v.template at<0>())) =0;
};
boost::ptr_array<apply, T::n_elements> appliers_;
template <int I>
struct apply_idx : apply {
virtual auto operator()(T const& v, F const& f)
CHILON_RETURN(f(v.template at<I>()))
};
template <int I, int L>
struct create_applier {
static void exec(decltype(appliers_)& appliers) {
appliers.replace(I, new apply_idx<I>());
create_applier<I + 1, L>::exec(appliers);
}
};
template <int I>
struct create_applier<I, I> {
static void exec(decltype(appliers_)& appliers) {}
};
variant_apply_lookup_table() {
create_applier<0, T::n_elements>::exec(appliers_);
}
};
template <class... T, class F>
struct variant_apply_helper< variant<T...>, F > {
typedef variant<T...> type;
inline static auto exec(type const& v, F const& f) -> decltype(f(v.template at<0>())) {
chilon::singleton<
variant_apply_lookup_table<type, F>
>::instance().appliers_[v.type_index()](v, f);
}
};
}
template <class F, class T>
inline auto variant_apply(T const& v, F const& f)
CHILON_RETURN(detail::variant_apply_helper<T, F>::exec(v, f))
template <class T, class... Y>
inline T& variant_as(variant<Y...>& v) {
return v.template at<T>();
}
template <class T, class... Y>
inline T& variant_as(variant<Y...> const& v) {
return v.template at<T>();
}
template <class T>
inline auto variant_as(T&& v) CHILON_RETURN(std::forward<T>(v))
/**
* call construct_default on a variant
*/
template <class T, class... Y>
inline void construct_default(variant<Y...>& v) {
v.template construct_default<T>();
}
/**
* construct_default on non-variant does nothing
*/
template <class T>
inline void construct_default(T&& v) {}
}
#endif
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.