Skip to content

Commit

Permalink
tagged rework
Browse files Browse the repository at this point in the history
  • Loading branch information
CaseyCarter committed Jul 1, 2017
1 parent 05911a9 commit e7c51dd
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 152 deletions.
264 changes: 133 additions & 131 deletions include/stl2/detail/tagged.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// cmcstl2 - A concept-enabled C++ standard library
//
// Copyright Casey Carter 2015
// Copyright Casey Carter 2015, 2017
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
Expand All @@ -25,195 +25,199 @@
// Tagged tuple-like types [taggedtup]
//
STL2_OPEN_NAMESPACE {
template <class T>
struct __tag_properties {};
template <class Spec, class Arg>
struct __tag_properties<Spec(Arg)> {
using specifier = Spec;
using type = Arg;
};
template <class T>
using __tag_spec = typename __tag_properties<T>::specifier;

template <class T>
using __tag_elem = meta::_t<__tag_properties<T>>;

template <class Derived, std::size_t I>
class tag_specifier_base;
namespace __tagged {
template <class T>
struct properties {};
template <class Spec, class Arg>
struct properties<Spec(Arg)> {
using specifier = Spec;
using type = Arg;
};
template <class T>
using specifier = typename properties<T>::specifier;

template <class T>
using element = meta::_t<properties<T>>;

template <class Untagged, std::size_t I, class Next>
struct specifier_link : Next {
using Next::Next;
specifier_link() = default;
constexpr specifier_link(Untagged&& that)
noexcept(std::is_nothrow_move_constructible<Untagged>::value)
requires MoveConstructible<Untagged>
: Next(std::move(that))
{}
constexpr specifier_link(const Untagged& that)
noexcept(std::is_nothrow_copy_constructible<Untagged>::value)
requires CopyConstructible<Untagged>
: Next(that)
{}
protected:
~specifier_link() = default;

constexpr auto&& get() & {
Untagged& self = *this;
return detail::adl_get<I>(self);
}
constexpr auto&& get() const& {
const Untagged& self = *this;
return detail::adl_get<I>(self);
}
constexpr auto&& get() && {
Untagged& self = *this;
return detail::adl_get<I>(std::move(self));
}
constexpr auto&& get() const&& {
const Untagged& self = *this;
return detail::adl_get<I>(std::move(self));
}
};

template <class T, class D, std::size_t I>
requires
DerivedFrom<
typename T::template tagged_getter<tag_specifier_base<D, I>>,
tag_specifier_base<D, I>>
using __tag_specifier_getter =
typename T::template tagged_getter<tag_specifier_base<D, I>>;
template <class Untagged, std::size_t, class...>
struct chain {
using type = Untagged;
};
template <class Untagged, std::size_t I, class First, class... Rest>
struct chain<Untagged, I, First, Rest...>
{
using type = typename First::template tagged_getter<
specifier_link<Untagged, I, meta::_t<chain<Untagged, I + 1, Rest...>>>>;
};
} // namespace __tagged

template <class T>
concept bool TagSpecifier =
requires {
typename __tag_specifier_getter<T, std::tuple<int>, 0>;
};
DerivedFrom<typename T::template tagged_getter<
__tagged::specifier_link<std::tuple<int>, 0, std::tuple<int>>>,
std::tuple<int>>;

template <class T>
concept bool TaggedType =
requires {
typename __tag_spec<T>;
requires TagSpecifier<__tag_spec<T>>;
typename __tagged::specifier<T>;
requires TagSpecifier<__tagged::specifier<T>>;
};

template <class Base, TagSpecifier...Tags>
requires sizeof...(Tags) <= tuple_size<Base>::value
struct tagged;

class __getters {
template <class Base, TagSpecifier...Tags>
requires sizeof...(Tags) <= tuple_size<Base>::value
friend struct tagged;

template <class Type, class Indices, TagSpecifier...Tags>
class collect_;

template <class Type, std::size_t...Is, TagSpecifier...Tags>
requires sizeof...(Is) == sizeof...(Tags)
class collect_<Type, std::index_sequence<Is...>, Tags...>
: public __tag_specifier_getter<Tags, Type, Is>... {
protected:
~collect_() = default;
};

template <class Type, TagSpecifier...Tags>
using collect = collect_<Type, std::index_sequence_for<Tags...>, Tags...>;
};

// tagged
///////////////////////////////////////////////////////////////////////////
// tagged [taggedtup.tagged]
// Not to spec:
// * constexpr per P0579
// * Implements https://github.com/ericniebler/stl2/issues/172
// * Implements https://github.com/ericniebler/stl2/issues/363
// * Implements https://github.com/ericniebler/stl2/issues/364
// * Implements https://github.com/ericniebler/stl2/issues/418
//
template <class Base, TagSpecifier...Tags>
requires sizeof...(Tags) <= tuple_size<Base>::value
struct tagged
: Base, __getters::collect<tagged<Base, Tags...>, Tags...>
: meta::_t<__tagged::chain<Base, 0, Tags...>>
{
using Base::Base;
private:
using base_t = meta::_t<__tagged::chain<Base, 0, Tags...>>;
public:
tagged() = default;
using base_t::base_t;

constexpr tagged(Base&& that)
noexcept(std::is_nothrow_move_constructible<Base>::value)
requires MoveConstructible<Base>
: base_t(std::move(that))
{}
constexpr tagged(const Base& that)
noexcept(std::is_nothrow_copy_constructible<Base>::value)
requires CopyConstructible<Base>
: base_t(that)
{}

// Not to spec: constexpr per P0579
template <class Other>
requires Constructible<Base, Other>
constexpr tagged(tagged<Other, Tags...>&& that)
noexcept(is_nothrow_constructible<Base, Other&&>::value)
: Base(static_cast<Other&&>(that)) {}
noexcept(std::is_nothrow_constructible<Base, Other&&>::value)
: base_t(static_cast<Other&&>(that)) {}

// Not to spec: constexpr per P0579
template <class Other>
requires Constructible<Base, const Other&>
constexpr tagged(tagged<Other, Tags...> const& that)
noexcept(is_nothrow_constructible<Base, const Other&>::value)
: Base(static_cast<const Other&>(that)) {}
constexpr tagged(const tagged<Other, Tags...>& that)
noexcept(std::is_nothrow_constructible<Base, const Other&>::value)
: base_t(static_cast<const Other&>(that)) {}

// Not to spec: constexpr per P0579
template <class Other>
requires Assignable<Base&, Other>
constexpr tagged& operator=(tagged<Other, Tags...>&& that)
noexcept(is_nothrow_assignable<Base&, Other&&>::value)
noexcept(std::is_nothrow_assignable<Base&, Other&&>::value)
{
static_cast<Base&>(*this) = static_cast<Other&&>(that);
return *this;
}

// Not to spec: constexpr per P0579
template <class Other>
requires Assignable<Base&, const Other&>
constexpr tagged& operator=(const tagged<Other, Tags...>& that)
noexcept(is_nothrow_assignable<Base&, const Other&>::value)
noexcept(std::is_nothrow_assignable<Base&, const Other&>::value)
{
static_cast<Base&>(*this) = static_cast<const Other&>(that);
return *this;
}

// Not to spec: constexpr per P0579
template <class U>
requires !Same<decay_t<U>, tagged> && Assignable<Base&, U>
constexpr tagged& operator=(U&& u) &
noexcept(is_nothrow_assignable<Base&, U&&>::value)
noexcept(std::is_nothrow_assignable<Base&, U&&>::value)
{
static_cast<Base&>(*this) = __stl2::forward<U>(u);
static_cast<Base&>(*this) = std::forward<U>(u);
return *this;
}

// Not to spec: constexpr per P0579
constexpr void swap(tagged& that)
noexcept(is_nothrow_swappable_v<Base&, Base&>)
requires Swappable<Base>
{
__stl2::swap(static_cast<Base&>(*this), static_cast<Base&>(that));
}

// Not to spec: constexpr per P0579
friend constexpr void swap(tagged& a, tagged& b)
noexcept(noexcept(a.swap(b)))
requires Swappable<Base>
{
a.swap(b);
}

// Not to spec: Extension
constexpr Base& base() & { return *this; }
constexpr const Base& base() const& { return *this; }
constexpr Base&& base() && { return __stl2::move(*this); }
constexpr const Base&& base() const&& { return __stl2::move(*this); }
};

template <class Derived, std::size_t I>
class tag_specifier_base {
protected:
~tag_specifier_base() = default;

constexpr auto&& get() & {
using __stl2::get;
return get<I>(derived().base());
}
constexpr auto&& get() const& {
using __stl2::get;
return get<I>(derived().base());
}
constexpr auto&& get() && {
using __stl2::get;
return get<I>(__stl2::move(derived()).base());
}
constexpr auto&& get() const&& {
using __stl2::get;
return get<I>(__stl2::move(derived()).base());
}
private:
constexpr Derived& derived() noexcept {
static_assert(models::DerivedFrom<Derived, tag_specifier_base>);
return static_cast<Derived&>(*this);
}
constexpr const Derived& derived() const noexcept {
static_assert(models::DerivedFrom<Derived, tag_specifier_base>);
return static_cast<const Derived&>(*this);
}
};

#define STL2_DEFINE_GETTER(name) \
struct name { \
template <class Base> \
struct tagged_getter : Base { \
constexpr decltype(auto) name() & { \
return Base::get(); \
} \
constexpr decltype(auto) name() const& { \
return Base::get(); \
} \
constexpr decltype(auto) name() && { \
return __stl2::move(*this).Base::get(); \
} \
/* Not to spec: Extension */ \
constexpr decltype(auto) name() const&& { \
return __stl2::move(*this).Base::get(); \
} \
protected: \
~tagged_getter() = default; \
}; \
#define STL2_DEFINE_GETTER(name) \
struct name { \
template <class Next> \
struct tagged_getter : Next { \
using Next::Next; \
tagged_getter() = default; \
tagged_getter(const tagged_getter&) = default; \
tagged_getter(tagged_getter&&) = default; \
tagged_getter& operator=(tagged_getter&&) = default; \
tagged_getter& operator=(const tagged_getter&) = default; \
\
constexpr decltype(auto) name() & \
noexcept(noexcept(std::declval<Next&>().get())) \
{ \
return Next::get(); \
} \
constexpr decltype(auto) name() const& \
noexcept(noexcept(std::declval<const Next&>().get())) \
{ \
return Next::get(); \
} \
constexpr decltype(auto) name() && \
noexcept(noexcept(std::declval<Next>().get())) \
{ \
return std::move(*this).Next::get(); \
} \
constexpr decltype(auto) name() const&& \
noexcept(noexcept(std::declval<const Next>().get())) \
{ \
return std::move(*this).Next::get(); \
} \
protected: \
~tagged_getter() = default; \
}; \
};

// tag specifiers [algorithm.general]
Expand All @@ -232,8 +236,6 @@ STL2_OPEN_NAMESPACE {
STL2_DEFINE_GETTER(count) // Extension
}

#undef STL2_DEFINE_GETTER

template <class T, class Base, class...Tags>
constexpr std::size_t tuple_find<T, tagged<Base, Tags...>> =
tuple_find<T, Base>;
Expand Down
15 changes: 15 additions & 0 deletions include/stl2/detail/tuple_like.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ STL2_OPEN_NAMESPACE {
requires !Same<U, __uncvref<U>>
constexpr std::size_t tuple_find<T, U> =
tuple_find<T, __uncvref<U>>;

namespace detail {
namespace adl {
using std::get;

template <std::size_t I, class T>
constexpr auto adl_get(T&& t)
noexcept(noexcept(get<I>(static_cast<T&&>(t))))
-> decltype(get<I>(static_cast<T&&>(t)))
{
return get<I>(static_cast<T&&>(t));
}
} // namespace adl
using adl::adl_get;
} // namespace detail
} STL2_CLOSE_NAMESPACE

#endif
2 changes: 1 addition & 1 deletion include/stl2/tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ STL2_OPEN_NAMESPACE {
// tagged_tuple
template <TaggedType...Types>
using tagged_tuple =
tagged<tuple<__tag_elem<Types>...>, __tag_spec<Types>...>;
tagged<tuple<__tagged::element<Types>...>, __tagged::specifier<Types>...>;

// make_tagged_tuple
template <TagSpecifier...Tags, class...Types>
Expand Down
4 changes: 2 additions & 2 deletions include/stl2/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ STL2_OPEN_NAMESPACE {
// tagged_pair
template <TaggedType F, TaggedType S>
using tagged_pair =
tagged<pair<__tag_elem<F>, __tag_elem<S>>,
__tag_spec<F>, __tag_spec<S>>;
tagged<pair<__tagged::element<F>, __tagged::element<S>>,
__tagged::specifier<F>, __tagged::specifier<S>>;

// make_tagged_pair
template <TagSpecifier Tag1, TagSpecifier Tag2, class T1, class T2>
Expand Down
2 changes: 1 addition & 1 deletion include/stl2/variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ STL2_OPEN_NAMESPACE {

template <TaggedType...Ts>
using tagged_variant =
tagged<variant<__tag_elem<Ts>...>, __tag_spec<Ts>...>;
tagged<variant<__tagged::element<Ts>...>, __tagged::specifier<Ts>...>;

template <class T, __variant::Variant V>
constexpr std::size_t tuple_find<T, V> =
Expand Down
Loading

0 comments on commit e7c51dd

Please sign in to comment.