Skip to content

Commit

Permalink
fix: correctly encapsulate the indirection types
Browse files Browse the repository at this point in the history
  • Loading branch information
lichray committed Jan 25, 2017
1 parent b4754ed commit 435689a
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 21 deletions.
66 changes: 45 additions & 21 deletions include/stdex/oneof.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,33 @@ struct variant_internal<T[]>
using element_type = T;
};

template <typename T>
struct variant_unwrap_internal
{
using type = T;
};

template <typename T>
struct variant_unwrap_internal<indirection<T>>
{
using type = T;
};

template <typename T>
struct variant_unwrap_internal<indirection<T> const>
{
using type = T const;
};

template <typename T>
using variant_internal_t = typename variant_internal<T>::type;

template <typename T>
using variant_element_t = typename variant_internal<T>::element_type;

template <typename T>
using variant_unwrap_internal_t = typename variant_unwrap_internal<T>::type;

template <bool union_default, bool trivial_dtor, typename... T>
union variant_storage_rep;

Expand Down Expand Up @@ -401,23 +422,33 @@ struct variant_storage<T>
};

template <typename X, typename... Ts>
decltype(auto) rget(variant_storage<Ts...>& v)
auto uget(variant_storage<Ts...>& v) -> X&
{
constexpr int i = directing_v<X, Ts...>;
constexpr int i = directing_v<X, variant_unwrap_internal_t<Ts>...>;
return v.rget(index_c<i>);
}

template <typename X, typename... Ts>
decltype(auto) rget(variant_storage<Ts...> const& v)
auto uget(variant_storage<Ts...> const& v) -> X const&
{
constexpr int i = directing_v<X, Ts...>;
constexpr int i = directing_v<X, variant_unwrap_internal_t<Ts>...>;
return v.rget(index_c<i>);
}

template <int I, typename S>
decltype(auto) uget(S&& s)
{
using btype = std::remove_reference_t<decltype(s.rget(index_c<I>))>;
using cv_etype = variant_unwrap_internal_t<btype>;
using rtype = std::conditional_t<is_lvalue_reference_v<S>, cv_etype&,
cv_etype&&>;
return static_cast<rtype>(static_cast<cv_etype&>(s.rget(index_c<I>)));
}

template <typename S, typename A>
decltype(auto) get_like(S&& s, A const&)
{
return detail::rget<A>(std::forward<S>(s));
return detail::uget<A>(std::forward<S>(s));
}

template <typename R, int Low, int High, int Mid = (Low + High) / 2,
Expand All @@ -443,18 +474,11 @@ struct _rvisit_at<R, Low, High, Mid, enable_if_t<(Low > High)>>
template <typename R, int Mid>
struct _rvisit_at<R, Mid, Mid, Mid>
{
template <typename Raw, typename F,
enable_if_t<is_lvalue_reference_v<Raw>, int> = 0>
static decltype(auto) apply(int n, F&& f, Raw&& tp)
{
return std::forward<F>(f)(tp.rget(index_c<Mid>));
}

template <typename Raw, typename F,
enable_if_t<not is_lvalue_reference_v<Raw>, int> = 0>
template <typename Raw, typename F>
static decltype(auto) apply(int n, F&& f, Raw&& tp)
{
return std::forward<F>(f)(std::move(tp.rget(index_c<Mid>)));
return std::forward<F>(f)(
detail::uget<Mid>(std::forward<Raw>(tp)));
}
};

Expand Down Expand Up @@ -784,7 +808,7 @@ struct oneof
if (v.which() != w.which())
return false;
else
return v.match([&](auto&& x) {
return v.match<bool>([&](auto&& x) {
return x == detail::get_like(w.rep_.data, x);
});
}
Expand All @@ -794,7 +818,7 @@ struct oneof
if (v.which() != w.which())
return true;
else
return v.match([&](auto&& x) {
return v.match<bool>([&](auto&& x) {
return x != detail::get_like(w.rep_.data, x);
});
}
Expand All @@ -806,7 +830,7 @@ struct oneof
else if (v.which() > w.which())
return false;
else
return v.match([&](auto&& x) {
return v.match<bool>([&](auto&& x) {
return x < detail::get_like(w.rep_.data, x);
});
}
Expand All @@ -818,7 +842,7 @@ struct oneof
else if (v.which() > w.which())
return false;
else
return v.match([&](auto&& x) {
return v.match<bool>([&](auto&& x) {
return x <= detail::get_like(w.rep_.data, x);
});
}
Expand All @@ -830,7 +854,7 @@ struct oneof
else if (v.which() < w.which())
return false;
else
return v.match([&](auto&& x) {
return v.match<bool>([&](auto&& x) {
return x > detail::get_like(w.rep_.data, x);
});
}
Expand All @@ -842,7 +866,7 @@ struct oneof
else if (v.which() < w.which())
return false;
else
return v.match([&](auto&& x) {
return v.match<bool>([&](auto&& x) {
return x >= detail::get_like(w.rep_.data, x);
});
}
Expand Down
61 changes: 61 additions & 0 deletions tests/test_large.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "doctest.h"

#include <stdex/oneof.h>

#include <array>
#include <string>

TEST_CASE("large object")
{
using arr_t = std::array<char, 100>;

arr_t a = { 'a', 'k', 'b', '4', '8', '\0' };
stdex::oneof<int, arr_t> s;

REQUIRE_FALSE(s.is<arr_t>());

s = a;

REQUIRE(s.is<arr_t>());
REQUIRE(s.get<arr_t>().data() == std::string("akb48"));

REQUIRE(s == s);
REQUIRE_FALSE(s != s);
REQUIRE_FALSE(s < s);
REQUIRE_FALSE(s > s);
REQUIRE(s <= s);
REQUIRE(s >= s);

auto p = s.maybe<arr_t>();

REQUIRE(p);
REQUIRE(*p == a);

s.match(
[](auto&& a) {
static_assert(stdex::is_same_v<decltype(a), arr_t&>, "");
},
[](int) {});

std::move(s).match(
[](auto&& a) {
static_assert(stdex::is_same_v<decltype(a), arr_t&&>, "");
},
[](int) {});

decltype(s) const sc{};

sc.match(
[](auto&& a) {
static_assert(stdex::is_same_v<decltype(a), arr_t const&>,
"");
},
[](int) {});

std::move(sc).match(
[](auto&& a) {
static_assert(stdex::is_same_v<decltype(a), arr_t const&&>,
"");
},
[](int) {});
}

0 comments on commit 435689a

Please sign in to comment.