Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 108 additions & 46 deletions include/rfl/Variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "internal/nth_element_t.hpp"
#include "internal/variant/find_max_size.hpp"
#include "internal/variant/is_alternative_type.hpp"
#include "internal/variant/result_t.hpp"

namespace rfl {

Expand All @@ -24,8 +25,6 @@ class Variant {

static constexpr unsigned long num_bytes_ = max_size_wrapper_.size_;

using LargestType = typename decltype(max_size_wrapper_)::Type;

using DataType = std::array<unsigned char, num_bytes_>;

using IndexType =
Expand All @@ -35,8 +34,11 @@ class Variant {

static constexpr IndexType size_ = sizeof...(AlternativeTypes);

template <class F>
using result_t = internal::variant::result_t<F, AlternativeTypes...>;

template <IndexType _i>
struct Index {};
using Index = std::integral_constant<IndexType, _i>;

public:
Variant() {
Expand Down Expand Up @@ -146,14 +148,17 @@ class Variant {
}

template <class F>
auto visit(F& _f) {
using FirstAlternative = internal::nth_element_t<0, AlternativeTypes...>;
using ResultType = std::remove_cvref_t<
std::invoke_result_t<std::remove_cvref_t<F>, FirstAlternative&>>;
result_t<F> visit(F& _f) {
using ResultType = result_t<F>;
if constexpr (std::is_same_v<ResultType, void>) {
bool visited = false;
do_visit_no_result(_f, &visited,
std::make_integer_sequence<IndexType, size_>());
} else if constexpr (std::is_reference_v<ResultType>) {
std::remove_reference_t<ResultType>* res = nullptr;
do_visit_with_reference(_f, &res,
std::make_integer_sequence<IndexType, size_>());
return *res;
} else {
auto res = std::optional<ResultType>();
do_visit_with_result(_f, &res,
Expand All @@ -163,14 +168,17 @@ class Variant {
}

template <class F>
auto visit(F& _f) const {
using FirstAlternative = internal::nth_element_t<0, AlternativeTypes...>;
using ResultType = std::remove_cvref_t<
std::invoke_result_t<std::remove_cvref_t<F>, FirstAlternative&>>;
result_t<F> visit(F& _f) const {
using ResultType = result_t<F>;
if constexpr (std::is_same_v<ResultType, void>) {
bool visited = false;
do_visit_no_result(_f, &visited,
std::make_integer_sequence<IndexType, size_>());
} else if constexpr (std::is_reference_v<ResultType>) {
std::remove_reference_t<ResultType>* res = nullptr;
do_visit_with_reference(_f, &res,
std::make_integer_sequence<IndexType, size_>());
return *res;
} else {
auto res = std::optional<ResultType>();
do_visit_with_result(_f, &res,
Expand All @@ -180,14 +188,17 @@ class Variant {
}

template <class F>
auto visit(const F& _f) {
using FirstAlternative = internal::nth_element_t<0, AlternativeTypes...>;
using ResultType = std::remove_cvref_t<
std::invoke_result_t<std::remove_cvref_t<F>, FirstAlternative&>>;
result_t<F> visit(const F& _f) {
using ResultType = std::remove_reference_t<result_t<F>>;
if constexpr (std::is_same_v<ResultType, void>) {
bool visited = false;
do_visit_no_result(_f, &visited,
std::make_integer_sequence<IndexType, size_>());
} else if constexpr (std::is_reference_v<ResultType>) {
std::remove_reference_t<ResultType>* res = nullptr;
do_visit_with_reference(_f, &res,
std::make_integer_sequence<IndexType, size_>());
return *res;
} else {
auto res = std::optional<ResultType>();
do_visit_with_result(_f, &res,
Expand All @@ -197,14 +208,17 @@ class Variant {
}

template <class F>
auto visit(const F& _f) const {
using FirstAlternative = internal::nth_element_t<0, AlternativeTypes...>;
using ResultType = std::remove_cvref_t<
std::invoke_result_t<std::remove_cvref_t<F>, FirstAlternative&>>;
result_t<F> visit(const F& _f) const {
using ResultType = result_t<F>;
if constexpr (std::is_same_v<ResultType, void>) {
bool visited = false;
do_visit_no_result(_f, &visited,
std::make_integer_sequence<IndexType, size_>());
} else if constexpr (std::is_reference_v<ResultType>) {
std::remove_reference_t<ResultType>* res = nullptr;
do_visit_with_reference(_f, &res,
std::make_integer_sequence<IndexType, size_>());
return *res;
} else {
auto res = std::optional<ResultType>();
do_visit_with_result(_f, &res,
Expand Down Expand Up @@ -264,32 +278,6 @@ class Variant {
(visit_one(_f, _visited, Index<_is>{}), ...);
}

template <class F, class ResultType, IndexType... _is>
void do_visit_with_result(F& _f, std::optional<ResultType>* _res,
std::integer_sequence<IndexType, _is...>) {
auto visit_one = [this]<IndexType _i>(const F& _f,
std::optional<ResultType>* _res,
Index<_i>) {
if (!*_res && index_ == _i) {
*_res = _f(get_alternative<_i>());
}
};
(visit_one(_f, _res, Index<_is>{}), ...);
}

template <class F, class ResultType, IndexType... _is>
void do_visit_with_result(F& _f, std::optional<ResultType>* _res,
std::integer_sequence<IndexType, _is...>) const {
auto visit_one = [this]<IndexType _i>(const F& _f,
std::optional<ResultType>* _res,
Index<_i>) {
if (!*_res && index_ == _i) {
*_res = _f(get_alternative<_i>());
}
};
(visit_one(_f, _res, Index<_is>{}), ...);
}

template <class F, IndexType... _is>
void do_visit_no_result(const F& _f, bool* _visited,
std::integer_sequence<IndexType, _is...>) {
Expand All @@ -316,6 +304,32 @@ class Variant {
(visit_one(_f, _visited, Index<_is>{}), ...);
}

template <class F, class ResultType, IndexType... _is>
void do_visit_with_result(F& _f, std::optional<ResultType>* _res,
std::integer_sequence<IndexType, _is...>) {
auto visit_one = [this]<IndexType _i>(const F& _f,
std::optional<ResultType>* _res,
Index<_i>) {
if (!*_res && index_ == _i) {
*_res = _f(get_alternative<_i>());
}
};
(visit_one(_f, _res, Index<_is>{}), ...);
}

template <class F, class ResultType, IndexType... _is>
void do_visit_with_result(F& _f, std::optional<ResultType>* _res,
std::integer_sequence<IndexType, _is...>) const {
auto visit_one = [this]<IndexType _i>(const F& _f,
std::optional<ResultType>* _res,
Index<_i>) {
if (!*_res && index_ == _i) {
*_res = _f(get_alternative<_i>());
}
};
(visit_one(_f, _res, Index<_is>{}), ...);
}

template <class F, class ResultType, IndexType... _is>
void do_visit_with_result(const F& _f, std::optional<ResultType>* _res,
std::integer_sequence<IndexType, _is...>) {
Expand All @@ -342,6 +356,54 @@ class Variant {
(visit_one(_f, _res, Index<_is>{}), ...);
}

template <class F, class ResultType, IndexType... _is>
void do_visit_with_reference(F& _f, ResultType** _res,
std::integer_sequence<IndexType, _is...>) {
const auto visit_one = [this]<IndexType _i>(const F& _f, ResultType** _res,
Index<_i>) {
if (!*_res && index_ == _i) {
*_res = &_f(get_alternative<_i>());
}
};
(visit_one(_f, _res, Index<_is>{}), ...);
}

template <class F, class ResultType, IndexType... _is>
void do_visit_with_reference(F& _f, ResultType** _res,
std::integer_sequence<IndexType, _is...>) const {
const auto visit_one = [this]<IndexType _i>(const F& _f, ResultType** _res,
Index<_i>) {
if (!*_res && index_ == _i) {
*_res = &_f(get_alternative<_i>());
}
};
(visit_one(_f, _res, Index<_is>{}), ...);
}

template <class F, class ResultType, IndexType... _is>
void do_visit_with_reference(const F& _f, ResultType** _res,
std::integer_sequence<IndexType, _is...>) {
const auto visit_one = [this]<IndexType _i>(const F& _f, ResultType** _res,
Index<_i>) {
if (!*_res && index_ == _i) {
*_res = &_f(get_alternative<_i>());
}
};
(visit_one(_f, _res, Index<_is>{}), ...);
}

template <class F, class ResultType, IndexType... _is>
void do_visit_with_reference(const F& _f, ResultType** _res,
std::integer_sequence<IndexType, _is...>) const {
const auto visit_one = [this]<IndexType _i>(const F& _f, ResultType** _res,
Index<_i>) {
if (!*_res && index_ == _i) {
*_res = &_f(get_alternative<_i>());
}
};
(visit_one(_f, _res, Index<_is>{}), ...);
}

template <IndexType _i>
auto& get_alternative() noexcept {
using CurrentType = internal::nth_element_t<_i, AlternativeTypes...>;
Expand Down Expand Up @@ -376,7 +438,7 @@ class Variant {
IndexType index_;

/// The underlying data, can be any of the underlying types.
alignas(LargestType) DataType data_;
alignas(AlternativeTypes...) DataType data_;
};

template <class T, class... Types>
Expand Down
16 changes: 16 additions & 0 deletions include/rfl/internal/variant/result_t.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef RFL_INTERNAL_VARIANT_RESULT_T_HPP_
#define RFL_INTERNAL_VARIANT_RESULT_T_HPP_

#include <type_traits>

#include "../nth_element_t.hpp"

namespace rfl::internal::variant {

template <class F, class... AlternativeTypes>
using result_t = std::remove_cv_t<std::invoke_result_t<
std::remove_cvref_t<F>, internal::nth_element_t<0, AlternativeTypes...>&>>;

} // namespace rfl::internal::variant

#endif
63 changes: 41 additions & 22 deletions include/rfl/visit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "internal/StringLiteral.hpp"
#include "internal/VisitTree.hpp"
#include "internal/VisitorWrapper.hpp"
#include "internal/variant/result_t.hpp"

namespace rfl {

Expand All @@ -22,66 +23,84 @@ inline auto visit(const Visitor& _visitor, const Literal<_fields...> _literal,
}

template <class F, class... AlternativeTypes>
inline auto visit(F& _f, Variant<AlternativeTypes...>& _v) {
inline internal::variant::result_t<F, AlternativeTypes...> visit(
F& _f, Variant<AlternativeTypes...>& _v) {
return _v.visit(_f);
}

template <class F, class... AlternativeTypes>
inline auto visit(F& _f, Variant<AlternativeTypes...>&& _v) {
inline internal::variant::result_t<F, AlternativeTypes...> visit(
F& _f, Variant<AlternativeTypes...>&& _v) {
return _v.visit(_f);
}

template <class F, class... AlternativeTypes>
inline auto visit(F& _f, const Variant<AlternativeTypes...>& _v) {
inline internal::variant::result_t<F, AlternativeTypes...> visit(
F& _f, const Variant<AlternativeTypes...>& _v) {
return _v.visit(_f);
}

template <class F, class... AlternativeTypes>
inline auto visit(const F& _f, Variant<AlternativeTypes...>& _v) {
inline internal::variant::result_t<F, AlternativeTypes...> visit(
const F& _f, Variant<AlternativeTypes...>& _v) {
return _v.visit(_f);
}

template <class F, class... AlternativeTypes>
inline auto visit(const F& _f, Variant<AlternativeTypes...>&& _v) {
inline internal::variant::result_t<F, AlternativeTypes...> visit(
const F& _f, Variant<AlternativeTypes...>&& _v) {
return _v.visit(_f);
}

template <class F, class... AlternativeTypes>
inline auto visit(const F& _f, const Variant<AlternativeTypes...>& _v) {
inline internal::variant::result_t<F, AlternativeTypes...> visit(
const F& _f, const Variant<AlternativeTypes...>& _v) {
return _v.visit(_f);
}

template <class F, internal::StringLiteral _discriminator, class... Args>
inline auto visit(F& _f, TaggedUnion<_discriminator, Args...>& _tagged_union) {
template <class F, internal::StringLiteral _discriminator,
class... AlternativeTypes>
inline internal::variant::result_t<F, AlternativeTypes...> visit(
F& _f, TaggedUnion<_discriminator, AlternativeTypes...>& _tagged_union) {
return _tagged_union.variant().visit(_f);
}

template <class F, internal::StringLiteral _discriminator, class... Args>
inline auto visit(F& _f, TaggedUnion<_discriminator, Args...>&& _tagged_union) {
template <class F, internal::StringLiteral _discriminator,
class... AlternativeTypes>
inline internal::variant::result_t<F, AlternativeTypes...> visit(
F& _f, TaggedUnion<_discriminator, AlternativeTypes...>&& _tagged_union) {
return _tagged_union.variant().visit(_f);
}

template <class F, internal::StringLiteral _discriminator, class... Args>
inline auto visit(F& _f,
const TaggedUnion<_discriminator, Args...>& _tagged_union) {
template <class F, internal::StringLiteral _discriminator,
class... AlternativeTypes>
inline internal::variant::result_t<F, AlternativeTypes...> visit(
F& _f,
const TaggedUnion<_discriminator, AlternativeTypes...>& _tagged_union) {
return _tagged_union.variant().visit(_f);
}

template <class F, internal::StringLiteral _discriminator, class... Args>
inline auto visit(const F& _f,
TaggedUnion<_discriminator, Args...>& _tagged_union) {
template <class F, internal::StringLiteral _discriminator,
class... AlternativeTypes>
inline internal::variant::result_t<F, AlternativeTypes...> visit(
const F& _f,
TaggedUnion<_discriminator, AlternativeTypes...>& _tagged_union) {
return _tagged_union.variant().visit(_f);
}

template <class F, internal::StringLiteral _discriminator, class... Args>
inline auto visit(const F& _f,
TaggedUnion<_discriminator, Args...>&& _tagged_union) {
template <class F, internal::StringLiteral _discriminator,
class... AlternativeTypes>
inline internal::variant::result_t<F, AlternativeTypes...> visit(
const F& _f,
TaggedUnion<_discriminator, AlternativeTypes...>&& _tagged_union) {
return _tagged_union.variant().visit(_f);
}

template <class F, internal::StringLiteral _discriminator, class... Args>
inline auto visit(const F& _f,
const TaggedUnion<_discriminator, Args...>& _tagged_union) {
template <class F, internal::StringLiteral _discriminator,
class... AlternativeTypes>
inline internal::variant::result_t<F, AlternativeTypes...> visit(
const F& _f,
const TaggedUnion<_discriminator, AlternativeTypes...>& _tagged_union) {
return _tagged_union.variant().visit(_f);
}

Expand Down
Loading
Loading