Skip to content

Commit 41f054e

Browse files
authored
Merge pull request #25 from rsl-org/variant/make_structural
[variant] Make structural type and some testing
2 parents 408680d + 0146842 commit 41f054e

3 files changed

Lines changed: 109 additions & 25 deletions

File tree

include/rsl/variant

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,12 @@ protected:
244244
friend struct variant_size<variant_base>;
245245

246246
constexpr void reset() {
247-
if (discriminator != npos) {
247+
if (_impl_discriminator != npos) {
248248
_visit_impl::visit_at<void>(
249-
discriminator,
249+
_impl_discriminator,
250250
[](auto&& member) { std::destroy_at(std::addressof(member)); },
251251
*this);
252-
discriminator = npos;
252+
_impl_discriminator = npos;
253253
}
254254
}
255255

@@ -280,7 +280,7 @@ protected:
280280
std::construct_at(&lhs, idx, std::forward<T>(rhs_alternative));
281281
},
282282
std::forward<V>(rhs));
283-
lhs.discriminator = index_type(rhs_index);
283+
lhs._impl_discriminator = index_type(rhs_index);
284284
}
285285

286286
public:
@@ -292,13 +292,11 @@ public:
292292
using index_type = std::conditional_t<(alternatives.count >= 255), unsigned short, unsigned char>;
293293
static constexpr auto npos = index_type(-1ULL);
294294

295-
protected:
296295
union {
297-
Storage storage;
296+
Storage _impl_storage;
298297
};
299-
index_type discriminator = npos;
298+
index_type _impl_discriminator = npos;
300299

301-
public:
302300
// default constructor, only if alternative #0 is default constructible
303301
constexpr variant_base() //
304302
noexcept(is_nothrow_default_constructible_type(alternatives.types[0])) // [variant.ctor]/5
@@ -364,11 +362,11 @@ public:
364362
template <std::size_t Idx, typename... Args>
365363
constexpr explicit variant_base(std::in_place_index_t<Idx>, Args&&... args) //
366364
noexcept(is_nothrow_constructible_type(alternatives.types[Idx], {^^Args...}))
367-
: discriminator(Idx) {
365+
: _impl_discriminator(Idx) {
368366
// Primary constructor
369367

370-
std::construct_at(&storage, '\0');
371-
std::construct_at(alternatives.template get_addr<Idx>(storage), std::forward<Args>(args)...);
368+
std::construct_at(&_impl_storage, '\0');
369+
std::construct_at(alternatives.template get_addr<Idx>(_impl_storage), std::forward<Args>(args)...);
372370
}
373371

374372
template <std::size_t Idx, typename U, typename... Args>
@@ -377,11 +375,11 @@ public:
377375
Args&&... args) //
378376
noexcept(std::is_nothrow_constructible_v< //
379377
typename[:alternatives.types[Idx]:], std::initializer_list<U>&, Args...>)
380-
: discriminator(Idx) {
378+
: _impl_discriminator(Idx) {
381379
// Primary constructor
382380

383-
std::construct_at(&storage, '\0');
384-
std::construct_at(alternatives.template get_addr<Idx>(storage),
381+
std::construct_at(&_impl_storage, '\0');
382+
std::construct_at(alternatives.template get_addr<Idx>(_impl_storage),
385383
init_list,
386384
std::forward<Args>(args)...);
387385
}
@@ -429,11 +427,11 @@ public:
429427
= default;
430428
constexpr ~variant_base() { reset(); }
431429
[[nodiscard]] constexpr bool valueless_by_exception() const noexcept {
432-
return discriminator == npos;
430+
return _impl_discriminator == npos;
433431
}
434432
[[nodiscard]] constexpr std::size_t index() const noexcept {
435-
if (discriminator != npos) {
436-
return discriminator;
433+
if (_impl_discriminator != npos) {
434+
return _impl_discriminator;
437435
}
438436
return variant_npos;
439437
}
@@ -443,8 +441,8 @@ public:
443441
static_assert(Idx < alternatives.count, "Alternative index out of bounds");
444442

445443
reset();
446-
std::construct_at(alternatives.template get_addr<Idx>(storage), std::forward<Args>(args)...);
447-
discriminator = Idx;
444+
std::construct_at(alternatives.template get_addr<Idx>(_impl_storage), std::forward<Args>(args)...);
445+
_impl_discriminator = Idx;
448446
}
449447

450448
template <typename T, typename... Args>
@@ -456,7 +454,7 @@ public:
456454
template <std::size_t Idx, typename Self>
457455
constexpr decltype(auto) get_alt(this Self&& self) {
458456
static_assert(Idx < alternatives.count, "Alternative index out of bounds");
459-
return alternatives.template get<Idx>(std::forward<Self>(self).storage);
457+
return alternatives.template get<Idx>(std::forward<Self>(self)._impl_storage);
460458
}
461459

462460
template <std::size_t Idx, typename Self>
@@ -929,10 +927,10 @@ public:
929927

930928
using tags = E;
931929

932-
storage_type* operator->() { return &this->storage; }
933-
storage_type const* operator->() const { return &this->storage; }
934-
storage_type* operator*() { return &this->storage; }
935-
storage_type const* operator*() const { return &this->storage; }
930+
storage_type* operator->() { return &this->_impl_storage; }
931+
storage_type const* operator->() const { return &this->_impl_storage; }
932+
storage_type* operator*() { return &this->_impl_storage; }
933+
storage_type const* operator*() const { return &this->_impl_storage; }
936934

937935
explicit(false) operator E() const { return _tagged_variant_impl::transitions<E>[this->index()]; }
938936

test/variant/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
target_sources(rsl-util-test PRIVATE
22
lifetime.cpp
33
special_members.cpp
4-
swap.cpp)
4+
swap.cpp
5+
template.cpp
6+
)
57

68
add_subdirectory(variant.assign)
79
add_subdirectory(variant.bad.access)

test/variant/template.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#include <string>
2+
#include <gtest/gtest.h>
3+
#include <common/assertions.h>
4+
5+
#include <rsl/variant>
6+
#include <rsl/string_view>
7+
8+
template <typename valueType, auto... Indices>
9+
consteval std::array<valueType, sizeof...(Indices)> construct_array(
10+
std::integer_sequence<valueType, Indices...>) {
11+
return {(static_cast<valueType>(Indices))...};
12+
};
13+
14+
enum class Options : uint8_t {
15+
option1,
16+
option2,
17+
};
18+
using variant_options = rsl::variant<int, rsl::string_view, Options>;
19+
template <variant_options... Args>
20+
struct WhoKnows {
21+
static constexpr size_t number_of_args = sizeof...(Args);
22+
23+
template <typename T>
24+
static constexpr bool has = (rsl::holds_alternative<T>(Args) || ...);
25+
26+
template <typename T>
27+
static constexpr bool hasOne = (static_cast<int>(rsl::holds_alternative<T>(Args)) + ...) == 1;
28+
29+
template <typename T>
30+
constexpr T get() {
31+
static_assert(hasOne<T>);
32+
template for (constexpr auto index :
33+
construct_array(std::integer_sequence<int, 0, number_of_args - 1>())) {
34+
if constexpr (rsl::holds_alternative<T>(Args...[index])) {
35+
return rsl::get<T>(Args...[index]);
36+
}
37+
}
38+
return rsl::get<T>(Args...[0]);
39+
}
40+
};
41+
42+
TEST(Variant, MultipleParameters) {
43+
{
44+
WhoKnows<variant_options(42), variant_options(43)> obj;
45+
ASSERT_TRUE([:type_of(^^obj):] ::has<int>);
46+
ASSERT_FALSE([:type_of(^^obj):] ::hasOne<int>);
47+
}
48+
49+
{
50+
WhoKnows<variant_options(42), variant_options(Options::option1)> obj;
51+
ASSERT_TRUE([:type_of(^^obj):] ::has<int>);
52+
ASSERT_TRUE([:type_of(^^obj):] ::hasOne<int>);
53+
ASSERT_EQ(obj.get<int>(), 42);
54+
ASSERT_NE(obj.get<int>(), 1);
55+
}
56+
57+
{
58+
WhoKnows<variant_options(Options::option1)> obj;
59+
ASSERT_FALSE([:type_of(^^obj):] ::has<int>);
60+
ASSERT_TRUE([:type_of(^^obj):] ::has<Options>);
61+
62+
ASSERT_FALSE([:type_of(^^obj):] ::hasOne<int>);
63+
ASSERT_TRUE([:type_of(^^obj):] ::hasOne<Options>);
64+
65+
ASSERT_EQ(obj.get<Options>(), Options::option1);
66+
ASSERT_NE(obj.get<Options>(), Options::option2);
67+
}
68+
69+
{
70+
WhoKnows<variant_options(Options::option1),
71+
variant_options(std::define_static_string("Hello world"))>
72+
obj;
73+
74+
ASSERT_FALSE([:type_of(^^obj):] ::has<int>);
75+
ASSERT_TRUE([:type_of(^^obj):] ::has<Options>);
76+
ASSERT_TRUE([:type_of(^^obj):] ::has<rsl::string_view>);
77+
78+
ASSERT_FALSE([:type_of(^^obj):] ::hasOne<int>);
79+
ASSERT_TRUE([:type_of(^^obj):] ::hasOne<Options>);
80+
ASSERT_TRUE([:type_of(^^obj):] ::hasOne<rsl::string_view>);
81+
82+
ASSERT_EQ(obj.get<rsl::string_view>(), "Hello world");
83+
}
84+
}

0 commit comments

Comments
 (0)