diff --git a/sprout/tuple.hpp b/sprout/tuple.hpp new file mode 100644 index 00000000..5bb157b4 --- /dev/null +++ b/sprout/tuple.hpp @@ -0,0 +1,8 @@ +#ifndef SPROUT_TUPLE_HPP +#define SPROUT_TUPLE_HPP + +#include +#include +#include + +#endif // #ifndef SPROUT_TUPLE_HPP diff --git a/sprout/tuple/tuple.hpp b/sprout/tuple/tuple.hpp new file mode 100644 index 00000000..4c7d6517 --- /dev/null +++ b/sprout/tuple/tuple.hpp @@ -0,0 +1,405 @@ +#ifndef SPROUT_TUPLE_TUPLE_HPP +#define SPROUT_TUPLE_TUPLE_HPP + +#include +#include +#include +#include +#include +#include + +namespace sprout { + namespace tuples { + namespace detail { + template + class head_base; + template + class head_base + : public Head + { + public: + static SPROUT_CONSTEXPR Head& head(head_base& t) SPROUT_NOEXCEPT { + return t; + } + static SPROUT_CONSTEXPR Head const& head(head_base const& t) SPROUT_NOEXCEPT { + return t; + } + public: + SPROUT_CONSTEXPR head_base() + : Head() + {} + SPROUT_CONSTEXPR head_base(Head const& v) + : Head(v) + {} + template + SPROUT_CONSTEXPR head_base(UHead&& v) + : Head(sprout::forward(v)) + {} + }; + template + class head_base { + public: + static SPROUT_CONSTEXPR Head& head(head_base& t) SPROUT_NOEXCEPT { + return t.head_; + } + static SPROUT_CONSTEXPR Head const& head(head_base const& t) SPROUT_NOEXCEPT { + return t.head_; + } + private: + Head head_; + public: + SPROUT_CONSTEXPR head_base() + : head_() + {} + SPROUT_CONSTEXPR head_base(Head const& v) + : head_(v) + {} + template + SPROUT_CONSTEXPR head_base(UHead&& v) + : head_(sprout::forward(v)) + {} + }; + + template + class tuple_impl; + template + class tuple_impl { + public: + template + friend class sprout::tuples::detail::tuple_impl; + protected: + void swap(tuple_impl&) SPROUT_NOEXCEPT {} + public: + tuple_impl() = default; + }; + template + class tuple_impl + : public sprout::tuples::detail::tuple_impl + , private sprout::tuples::detail::head_base::value> + { + public: + template + friend class sprout::tuples::detail::tuple_impl; + public: + typedef sprout::tuples::detail::tuple_impl inherited_type; + typedef sprout::tuples::detail::head_base::value> base_type; + public: + static SPROUT_CONSTEXPR Head& head(tuple_impl& t) SPROUT_NOEXCEPT { + return base_type::head(t); + } + static SPROUT_CONSTEXPR const Head& head(tuple_impl const& t) SPROUT_NOEXCEPT { + return base_type::head(t); + } + static SPROUT_CONSTEXPR inherited_type& tail(tuple_impl& t) SPROUT_NOEXCEPT { + return t; + } + static SPROUT_CONSTEXPR inherited_type const& tail(tuple_impl const& t) SPROUT_NOEXCEPT { + return t; + } + protected: + void swap(tuple_impl& t) SPROUT_NOEXCEPT_EXPR( + SPROUT_NOEXCEPT_EXPR(swap(std::declval(), std::declval())) + && SPROUT_NOEXCEPT_EXPR(tail(t).swap(tail(t))) + ) + { + using std::swap; + swap(head(*this), head(t)); + inherited_type::swap(tail(t)); + } + public: + SPROUT_CONSTEXPR tuple_impl() + : inherited_type() + , base_type() + {} + SPROUT_CONSTEXPR explicit tuple_impl(const Head& h, Tail const&... tail) + : inherited_type(tail...) + , base_type(h) + {} + template::type> + SPROUT_CONSTEXPR explicit tuple_impl(UHead&& h, UTail&&... tail) + : inherited_type(sprout::forward(tail)...) + , base_type(sprout::forward(h)) + {} + SPROUT_CONSTEXPR tuple_impl(tuple_impl const&) = default; + SPROUT_CONSTEXPR tuple_impl(tuple_impl&& t) + SPROUT_NOEXCEPT_EXPR(std::is_nothrow_move_constructible::value && std::is_nothrow_move_constructible::value) + : inherited_type(std::move(tail(t))) + , base_type(sprout::forward(head(t))) + {} + template + SPROUT_CONSTEXPR tuple_impl(tuple_impl const& t) + : inherited_type(sprout::tuples::detail::tuple_impl::tail(t)) + , base_type(sprout::tuples::detail::tuple_impl::head(t)) + {} + template + SPROUT_CONSTEXPR tuple_impl(tuple_impl&& t) + : inherited_type(std::move(sprout::tuples::detail::tuple_impl::tail(t))) + , base_type(sprout::forward(sprout::tuples::detail::tuple_impl::head(t))) + {} + tuple_impl& operator=(tuple_impl const& t) { + head(*this) = head(t); + tail(*this) = tail(t); + return *this; + } + tuple_impl& operator=(tuple_impl&& t) + SPROUT_NOEXCEPT_EXPR(std::is_nothrow_move_assignable::value && std::is_nothrow_move_assignable::value) + { + head(*this) = sprout::forward(head(t)); + tail(*this) = std::move(tail(t)); + return *this; + } + template + tuple_impl& operator=(sprout::tuples::detail::tuple_impl const& t) { + head(*this) = sprout::tuples::detail::tuple_impl::head(t); + tail(*this) = sprout::tuples::detail::tuple_impl::tail(t); + return *this; + } + template + tuple_impl& operator=(sprout::tuples::detail::tuple_impl&& t) { + head(*this) = sprout::forward(sprout::tuples::detail::tuple_impl::head(t)); + tail(*this) = std::move(sprout::tuples::detail::tuple_impl::tail(t)); + return *this; + } + }; + } // namespace detail + + // + // tuple + // + template + class tuple + : public sprout::tuples::detail::tuple_impl<0, Types...> + { + public: + typedef sprout::tuples::detail::tuple_impl<0, Types...> inherited_type; + public: + // tuple construction + SPROUT_CONSTEXPR tuple() + : inherited_type() + {} + SPROUT_CONSTEXPR explicit tuple(Types const&... elements) + : inherited_type(elements...) + {} + template::type> + SPROUT_CONSTEXPR explicit tuple(UTypes&&... elements) + : inherited_type(sprout::forward(elements)...) + {} + SPROUT_CONSTEXPR tuple(tuple const &) = default; + SPROUT_CONSTEXPR tuple(tuple&&) = default; + template::type> + SPROUT_CONSTEXPR tuple(sprout::tuples::tuple const& t) + : inherited_type(static_cast const&>(t)) + {} + template::type> + SPROUT_CONSTEXPR tuple(sprout::tuples::tuple&& t) + : inherited_type(static_cast&&>(t)) + {} + // tuple assignment + tuple& operator=(const tuple& rhs) { + static_cast(*this) = rhs; + return *this; + } + tuple& operator=(tuple&& rhs) SPROUT_NOEXCEPT_EXPR(std::is_nothrow_move_assignable::value) { + static_cast(*this) = std::move(rhs); + return *this; + } + template::type> + tuple& operator=(sprout::tuples::tuple const& rhs) { + static_cast(*this) = rhs; + return *this; + } + template::type> + tuple& operator=(sprout::tuples::tuple&& rhs) { + static_cast(*this) = std::move(rhs); + return *this; + } + // tuple swap + void swap(tuple& other) SPROUT_NOEXCEPT_EXPR(SPROUT_NOEXCEPT_EXPR(other.swap(other))) { + inherited_type::swap(other); + } + }; + template<> + class tuple<> { + public: + // tuple swap + void swap(tuple&) SPROUT_NOEXCEPT {} + }; + + // + // ignore_t + // + struct ignore_t { + template + ignore_t const& operator=(T const&) const { + return *this; + } + }; + // + // ignore + // + static SPROUT_CONSTEXPR ignore_t ignore{}; + + // + // make_tuple + // + template + SPROUT_CONSTEXPR inline sprout::tuples::tuple::type...> make_tuple(Types&&... args) { + return sprout::tuples::tuple::type...>(sprout::forward(args)...); + } + // + // forward_as_tuple + // + template + SPROUT_CONSTEXPR inline sprout::tuples::tuple forward_as_tuple(Types&&... args) SPROUT_NOEXCEPT { + return sprout::tuples::tuple(sprout::forward(args)...); + } + // + // tie + // + template + inline sprout::tuples::tuple tie(Types&... args) SPROUT_NOEXCEPT { + return sprout::tuples::tuple(args...); + } + + // + // tuple_size + // + template + struct tuple_size; + template + struct tuple_size + : public sprout::tuples::tuple_size + {}; + template + struct tuple_size + : public sprout::tuples::tuple_size + {}; + template + struct tuple_size + : public sprout::tuples::tuple_size + {}; + template + struct tuple_size > + : public std::integral_constant + {}; + + // + // tuple_element + // + template + struct tuple_element; + template + struct tuple_element { + public: + typedef typename std::add_const::type>::type type; + }; + template + struct tuple_element { + public: + typedef typename std::add_volatile::type>::type type; + }; + template + struct tuple_element { + public: + typedef typename std::add_cv::type>::type type; + }; + namespace detail { + template + struct tuple_element_impl; + template + struct tuple_element_impl<0, sprout::tuples::tuple > { + public: + typedef Head type; + }; + template + struct tuple_element_impl > + : public sprout::tuples::tuple_element > + {}; + } // namespace detail + template + struct tuple_element > + : public sprout::tuples::detail::tuple_element_impl > + {}; + + // + // get + // + namespace detail { + template + SPROUT_CONSTEXPR typename std::add_lvalue_reference::type get_helper( + sprout::tuples::detail::tuple_impl& t + ) SPROUT_NOEXCEPT + { + return sprout::tuples::detail::tuple_impl::head(t); + } + template + SPROUT_CONSTEXPR typename std::add_lvalue_reference::type>::type get_helper( + sprout::tuples::detail::tuple_impl const& t + ) SPROUT_NOEXCEPT + { + return sprout::tuples::detail::tuple_impl::head(t); + } + } // namespace detail + template + SPROUT_CONSTEXPR typename sprout::tuples::tuple_element >::type& get( + tuple& t + ) SPROUT_NOEXCEPT + { + return sprout::tuples::detail::get_helper(t); + } + template + SPROUT_CONSTEXPR typename sprout::tuples::tuple_element >::type&& get( + tuple&& t + ) SPROUT_NOEXCEPT + { + return sprout::forward >::type&&>( + sprout::tuples::get(t) + ); + } + template + SPROUT_CONSTEXPR typename sprout::tuples::tuple_element >::type const& get( + tuple const& t + ) SPROUT_NOEXCEPT + { + return sprout::tuples::detail::get_helper(t); + } + + // + // swap + // + template + inline void swap(tuple& lhs, tuple& rhs) SPROUT_NOEXCEPT_EXPR(SPROUT_NOEXCEPT_EXPR(lhs.swap(rhs))) { + lhs.swap(rhs); + } + } // namespace tuples + + using sprout::tuples::tuple; + using sprout::tuples::ignore; + using sprout::tuples::make_tuple; + using sprout::tuples::forward_as_tuple; + using sprout::tuples::tie; + using sprout::tuples::tuple_size; + using sprout::tuples::tuple_element; + using sprout::tuples::get; + using sprout::tuples::swap; +} // namespace sprout + +namespace std { + // + // tuple_size + // + template + struct tuple_size > + : public sprout::tuples::tuple_size > + {}; + + // + // tuple_element + // + template + struct tuple_element > + : public sprout::tuples::tuple_element > + {}; +} // namespace std + +#endif // #ifndef SPROUT_TUPLE_TUPLE_HPP diff --git a/sprout/tuple/tuple_comparison.hpp b/sprout/tuple/tuple_comparison.hpp new file mode 100644 index 00000000..bbc97351 --- /dev/null +++ b/sprout/tuple/tuple_comparison.hpp @@ -0,0 +1,115 @@ +#ifndef SPROUT_TUPLE_TUPLE_COMPARISON_HPP +#define SPROUT_TUPLE_TUPLE_COMPARISON_HPP + +#include +#include +#include + +namespace sprout { + namespace tuples { + // + // operator== + // operator< + // operator!= + // operator> + // operator>= + // operator<= + // + namespace detail { + template + struct tuple_compare; + template + struct tuple_compare<0, I, I, T, U> { + public: + static SPROUT_CONSTEXPR bool eq(T const&, U const&) { + return true; + } + static SPROUT_CONSTEXPR bool less(T const&, U const&) { + return false; + } + }; + template + struct tuple_compare<0, I, J, T, U> { + public: + static SPROUT_CONSTEXPR bool eq(T const& t, U const& u) { + return (sprout::tuples::get(t) == sprout::tuples::get(u) + && sprout::tuples::detail::tuple_compare<0, I + 1, J, T, U>::eq(t, u)) + ; + } + static SPROUT_CONSTEXPR bool less(T const& t, U const& u) { + return (sprout::tuples::get(t) < sprout::tuples::get(u)) + || (!(sprout::tuples::get(u) < sprout::tuples::get(t)) + && sprout::tuples::detail::tuple_compare<0, I + 1, J, T, U>::less(t, u) + ) + ; + } + }; + } // namespace detail + template + bool SPROUT_CONSTEXPR inline operator==( + sprout::tuples::tuple const& lhs, + sprout::tuples::tuple const& rhs + ) + { + typedef sprout::tuples::tuple T; + typedef sprout::tuples::tuple U; + return sprout::tuples::detail::tuple_compare< + sprout::tuples::tuple_size::value - sprout::tuples::tuple_size::value, + 0, + sprout::tuples::tuple_size::value, + T, + U + >::eq(lhs, rhs); + } + template + bool SPROUT_CONSTEXPR inline operator<( + sprout::tuples::tuple const& lhs, + sprout::tuples::tuple const& rhs + ) + { + typedef sprout::tuples::tuple T; + typedef sprout::tuples::tuple U; + return sprout::tuples::detail::tuple_compare< + sprout::tuples::tuple_size::value - sprout::tuples::tuple_size::value, + 0, + sprout::tuples::tuple_size::value, + T, + U + >::less(lhs, rhs); + } + template + bool SPROUT_CONSTEXPR inline operator!=( + sprout::tuples::tuple const& lhs, + sprout::tuples::tuple const& rhs + ) + { + return !(lhs == rhs); + } + template + bool SPROUT_CONSTEXPR inline operator>( + sprout::tuples::tuple const& lhs, + sprout::tuples::tuple const& rhs + ) + { + return rhs < lhs; + } + template + bool SPROUT_CONSTEXPR inline operator<=( + sprout::tuples::tuple const& lhs, + sprout::tuples::tuple const& rhs + ) + { + return !(rhs < lhs); + } + template + bool SPROUT_CONSTEXPR inline operator>=( + sprout::tuples::tuple const& lhs, + sprout::tuples::tuple const& rhs + ) + { + return !(lhs < rhs); + } + } // namespace tuples +} // namespace sprout + +#endif // #ifndef SPROUT_TUPLE_TUPLE_COMPARISON_HPP