halcheck 1.0
Loading...
Searching...
No Matches
any.hpp
1#ifndef HALCHECK_LIB_ANY_HPP
2#define HALCHECK_LIB_ANY_HPP
3
11#include <halcheck/lib/type_traits.hpp>
12#include <halcheck/lib/typeinfo.hpp>
13#include <halcheck/lib/variant.hpp>
14
15#include <exception>
16#include <initializer_list>
17#include <memory>
18#include <utility>
19
20namespace halcheck { namespace lib {
21
22class any;
23
24template<typename T, HALCHECK_REQUIRE(!std::is_void<T>())>
25T *any_cast(any *operand) noexcept;
26
27template<typename T, HALCHECK_REQUIRE(!std::is_void<T>())>
28const T *any_cast(const any *operand) noexcept;
29
35class any {
36public:
37 constexpr any() noexcept = default;
38
39 any(const any &other) : _type(other._type), _impl(other.has_value() ? other._impl->clone() : nullptr) {}
40
41 any(any &&other) noexcept(false) : _type(other._type), _impl(other.has_value() ? other._impl->move() : nullptr) {}
42
43 template<
44 typename T,
47 any(T &&value) // NOLINT: implicit conversion
48 : any(lib::in_place_type_t<lib::decay_t<T>>(), std::forward<T>(value)) {}
49
50 template<
51 typename T,
52 typename... Args,
55 explicit any(lib::in_place_type_t<T>, Args &&...args)
56 : _type(lib::type_id::of<T>()), _impl(new derived<T>(std::forward<Args>(args)...)) {}
57
58 template<
59 typename T,
60 typename U,
61 typename... Args,
64 explicit any(lib::in_place_type_t<T>, std::initializer_list<U> il, Args &&...args)
65 : _type(lib::type_id::of<T>()), _impl(new derived<T>(il, std::forward<Args>(args)...)) {}
66
67 ~any() = default;
68
69 any &operator=(const any &rhs) {
70 any(rhs).swap(*this);
71 return *this;
72 }
73
74 any &operator=(any &&rhs) noexcept {
75 swap(rhs);
76 return *this;
77 }
78
79 template<
80 typename T,
83 any &operator=(T &&rhs) noexcept {
84 any(std::forward<T>(rhs)).swap(*this);
85 return *this;
86 }
87
88 template<
89 typename T,
90 typename... Args,
93 T &emplace(Args &&...args) {
94 _impl.reset(new derived<T>(std::forward<Args>(args)...));
95 }
96
97 template<
98 typename T,
99 typename U,
100 typename... Args,
103 T &emplace(std::initializer_list<U> il, Args &&...args) {
104 _impl.reset(new derived<T>(il, std::forward<Args>(args)...));
105 }
106
107 void reset() noexcept {
108 _type = lib::type_id::of<void>();
109 _impl.reset();
110 }
111
112 void swap(any &other) noexcept {
113 using std::swap;
114 swap(_type, other._type);
115 swap(_impl, other._impl);
116 }
117
118 bool has_value() const noexcept { return bool(_impl); }
119
120 const lib::type_id &type() const { return _type; }
121
122private:
123 template<typename T, HALCHECK_REQUIRE_(!std::is_void<T>())>
124 friend const T *any_cast(const any *operand) noexcept;
125
126 template<typename T, HALCHECK_REQUIRE_(!std::is_void<T>())>
127 friend T *any_cast(any *operand) noexcept;
128
129 friend void swap(any &lhs, any &rhs) noexcept { lhs.swap(rhs); }
130
131 struct base {
132 virtual ~base() = 0;
133 virtual const void *data() const = 0;
134 virtual void *data() = 0;
135 virtual std::unique_ptr<base> move() = 0;
136 virtual std::unique_ptr<base> clone() const = 0;
137 };
138
139 template<typename T>
140 struct derived : base {
141 template<typename... Args>
142 explicit derived(Args &&...args) : value(std::forward<Args>(args)...) {}
143
144 const void *data() const override { return std::addressof(value); }
145
146 void *data() override { return std::addressof(value); }
147
148 std::unique_ptr<base> move() override { return new derived<T>(std::move(value)); }
149
150 std::unique_ptr<base> clone() const override { return new derived<T>(value); }
151
152 T value;
153 };
154
155 lib::type_id _type;
157};
158
166 const char *what() const noexcept override { return "halcheck::lib::bad_any_cast"; }
167};
168
175template<typename T, HALCHECK_REQUIRE(std::is_constructible<T, const lib::remove_cv_t<lib::remove_reference_t<T>> &>())>
176T any_cast(const any &operand) {
177 if (auto output = lib::any_cast<lib::remove_cv_t<lib::remove_reference_t<T>>>(&operand))
178 return static_cast<T>(*output);
179 else
180 throw lib::bad_any_cast();
181}
182
189template<typename T, HALCHECK_REQUIRE(std::is_constructible<T, lib::remove_cv_t<lib::remove_reference_t<T>> &>())>
190T any_cast(any &operand) {
191 if (auto output = lib::any_cast<lib::remove_cv_t<lib::remove_reference_t<T>>>(&operand))
192 return static_cast<T>(*output);
193 else
194 throw lib::bad_any_cast();
195}
196
203template<typename T, HALCHECK_REQUIRE(std::is_constructible<T, lib::remove_cv_t<lib::remove_reference_t<T>>>())>
204T any_cast(any &&operand) {
205 if (auto output = lib::any_cast<lib::remove_cv_t<lib::remove_reference_t<T>>>(&operand))
206 return static_cast<T>(std::move(*output));
207 else
208 throw lib::bad_any_cast();
209}
210
217template<typename T, HALCHECK_REQUIRE_(!std::is_void<T>())>
218const T *any_cast(const any *operand) noexcept {
219 if (operand && operand->type() == lib::type_id::of<T>())
220 return reinterpret_cast<const T *>(operand->_impl->data());
221 else
222 return nullptr;
223}
224
231template<typename T, HALCHECK_REQUIRE_(!std::is_void<T>())>
232T *any_cast(any *operand) noexcept {
233 if (operand && operand->type() == lib::type_id::of<T>())
234 return reinterpret_cast<T *>(operand->_impl->data());
235 else
236 return nullptr;
237}
238
245template<typename T, typename... Args>
246any make_any(Args &&...args) {
247 return any(lib::in_place_type_t<T>(), std::forward<Args>(args)...);
248}
249
250}} // namespace halcheck::lib
251
252#endif
T addressof(T... args)
T any_cast(T... args)
An implemenetation of std::any.
Definition any.hpp:35
T forward(T... args)
T any_cast(any &operand)
An implementation of std::any_cast.
Definition any.hpp:190
T any_cast(any &&operand)
An implementation of std::any_cast.
Definition any.hpp:204
T any_cast(const any &operand)
An implementation of std::any_cast.
Definition any.hpp:176
any make_any(Args &&...args)
An implementation of std::make_any.
Definition any.hpp:246
T * any_cast(any *operand) noexcept
An implementation of std::any_cast.
Definition any.hpp:232
const T * any_cast(const any *operand) noexcept
An implementation of std::any_cast.
Definition any.hpp:218
typename std::decay< T >::type decay_t
An implementation of std::decay_t.
Definition type_traits.hpp:101
typename std::remove_cv< T >::type remove_cv_t
An implementation of std::remove_cv_t.
Definition type_traits.hpp:109
typename std::remove_reference< T >::type remove_reference_t
An implementation of std::remove_reference_t.
Definition type_traits.hpp:175
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
T reset(T... args)
An implementation of std::bad_any_cast.
Definition any.hpp:165
Determines if a type is a specialization of a template class.
Definition type_traits.hpp:437
static type_id of()
Gets the unique type identifier associated with the given type.
Definition typeinfo.hpp:86
A runtime type identifier that does not require RTTI.
Definition typeinfo.hpp:65
T swap(T... args)