From f01382e3e57192721f565ac3a8533a2021e80a1c Mon Sep 17 00:00:00 2001 From: bolero-MURAKAMI Date: Wed, 19 Dec 2012 23:06:08 +0900 Subject: [PATCH] support polymorphic visitor (variant) --- sprout/string.hpp | 1 + sprout/string/float_to_string.hpp | 20 ++++++-- sprout/string/shrink.hpp | 16 ++++++ sprout/string/stretch.hpp | 25 +++++++++ sprout/string/string.hpp | 11 ++-- sprout/type_traits/has_xxx.hpp | 28 ++++++++++ sprout/variant/apply_visitor.hpp | 42 ++++++++++++++- sprout/variant/variant.hpp | 85 +++++++++++++++++++++++++------ 8 files changed, 204 insertions(+), 24 deletions(-) create mode 100644 sprout/string/stretch.hpp diff --git a/sprout/string.hpp b/sprout/string.hpp index 6a9eb4f1..e2d49c74 100644 --- a/sprout/string.hpp +++ b/sprout/string.hpp @@ -16,5 +16,6 @@ #include #include #include +#include #endif // #ifndef SPROUT_STRING_HPP diff --git a/sprout/string/float_to_string.hpp b/sprout/string/float_to_string.hpp index cb75a06b..510a5231 100644 --- a/sprout/string/float_to_string.hpp +++ b/sprout/string/float_to_string.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -32,14 +33,15 @@ namespace sprout { namespace detail { template inline SPROUT_CONSTEXPR sprout::basic_string::value> - float_to_string(FloatType val, bool negative, int digits, sprout::index_tuple) { + float_to_string_impl(FloatType val, bool negative, int digits, int v, sprout::index_tuple) { return negative ? sprout::basic_string::value>{ { static_cast('-'), (Indexes < digits ? sprout::detail::int_to_char(sprout::detail::float_digit_at(val, digits - 1 - Indexes)) : Indexes == digits ? static_cast('.') - : Indexes < digits + 1 + sprout::detail::decimal_places_length ? sprout::detail::int_to_char(sprout::detail::float_digit_at(val, digits - Indexes)) + : Indexes < digits + 1 + sprout::detail::decimal_places_length + ? sprout::detail::int_to_char(sprout::detail::int_digit_at(v, digits + sprout::detail::decimal_places_length - Indexes)) : Elem() )... }, @@ -49,7 +51,8 @@ namespace sprout { { (Indexes < digits ? sprout::detail::int_to_char(sprout::detail::float_digit_at(val, digits - 1 - Indexes)) : Indexes == digits ? static_cast('.') - : Indexes < digits + 1 + sprout::detail::decimal_places_length ? sprout::detail::int_to_char(sprout::detail::float_digit_at(val, digits - Indexes)) + : Indexes < digits + 1 + sprout::detail::decimal_places_length + ? sprout::detail::int_to_char(sprout::detail::int_digit_at(v, digits + sprout::detail::decimal_places_length - Indexes)) : Elem() )... }, @@ -57,6 +60,14 @@ namespace sprout { } ; } + template + inline SPROUT_CONSTEXPR sprout::basic_string::value> + float_to_string(FloatType val, bool negative, int digits) { + return sprout::detail::float_to_string_impl( + val, negative, digits, static_cast((val - sprout::floor(val)) * sprout::detail::int_pow(sprout::detail::decimal_places_length)), + sprout::index_range<0, sprout::printed_float_digits::value - 1>::make() + ); + } } // namespace detail // @@ -71,8 +82,7 @@ namespace sprout { return sprout::detail::float_to_string( sprout::detail::float_round_at(val < 0 ? -val : val, sprout::detail::decimal_places_length), val < 0, - sprout::detail::float_digits(val), - sprout::index_range<0, sprout::printed_float_digits::value - 1>::make() + sprout::detail::float_digits(val) ); } diff --git a/sprout/string/shrink.hpp b/sprout/string/shrink.hpp index 7d30767e..370a179a 100644 --- a/sprout/string/shrink.hpp +++ b/sprout/string/shrink.hpp @@ -58,6 +58,22 @@ namespace sprout { shrink(sprout::basic_string const& s) { return sprout::shrink_string(s); } + template + inline SPROUT_CONSTEXPR sprout::basic_string + shrink(sprout::basic_string const& s) { + return sprout::shrink(s); + } + + template + inline SPROUT_CONSTEXPR sprout::shrink_string + shrink(T const(& arr)[N]) { + return sprout::shrink(sprout::to_string(arr)); + } + template + inline SPROUT_CONSTEXPR sprout::basic_string + shrink(T const(& arr)[N]) { + return sprout::shrink(sprout::to_string(arr)); + } } // namespace sprout #endif // #ifndef SPROUT_STRING_SHRINK_HPP diff --git a/sprout/string/stretch.hpp b/sprout/string/stretch.hpp new file mode 100644 index 00000000..c3c1cce3 --- /dev/null +++ b/sprout/string/stretch.hpp @@ -0,0 +1,25 @@ +#ifndef SPROUT_STRING_STRETCH_HPP +#define SPROUT_STRING_STRETCH_HPP + +#include +#include +#include + +namespace sprout { + // + // stretch + // + template + inline SPROUT_CONSTEXPR sprout::basic_string + stretch(sprout::basic_string const& s) { + return s; + } + + template + inline SPROUT_CONSTEXPR sprout::basic_string + stretch(T const(& arr)[N]) { + return sprout::stretch(sprout::to_string(arr)); + } +} // namespace sprout + +#endif // #ifndef SPROUT_STRING_STRETCH_HPP diff --git a/sprout/string/string.hpp b/sprout/string/string.hpp index a9d66ea9..d4448226 100644 --- a/sprout/string/string.hpp +++ b/sprout/string/string.hpp @@ -861,9 +861,6 @@ namespace sprout { }; } // namespace detail - // - // to_string - // namespace detail { template inline SPROUT_CONSTEXPR sprout::basic_string @@ -880,6 +877,14 @@ namespace sprout { return to_string_impl_1(arr, sprout::char_traits::length(arr), sprout::index_tuple()); } } // namespace detail + // + // to_string + // + template + inline SPROUT_CONSTEXPR sprout::basic_string + to_string(sprout::basic_string const& s) { + return s; + } template inline SPROUT_CONSTEXPR sprout::basic_string to_string(T const(& arr)[N]) { diff --git a/sprout/type_traits/has_xxx.hpp b/sprout/type_traits/has_xxx.hpp index c30d9e60..9fdd2e0d 100644 --- a/sprout/type_traits/has_xxx.hpp +++ b/sprout/type_traits/has_xxx.hpp @@ -61,4 +61,32 @@ #define SPROUT_HAS_XXX_VALUE_DEF_LAZY(VALUE) \ SPROUT_HAS_XXX_VALUE_DEF(SPROUT_PP_CAT(has_, VALUE), VALUE) +// +// SPROUT_HAS_XXX_TEMPLATE_DEF +// SPROUT_HAS_XXX_TEMPLATE_DEF_LAZY +// +#if defined(_MSC_VER) +#define SPROUT_HAS_XXX_TEMPLATE_DEF(NAME, TEMPLATE) \ + template class = T::template TEMPLATE> \ + std::true_type SPROUT_PP_CAT(SPROUT_PP_CAT(SPROUT_PP_CAT(sprout_has_xxx_impl_check_type_, TEMPLATE), NAME), __LINE__)(int); \ + template \ + std::false_type SPROUT_PP_CAT(SPROUT_PP_CAT(SPROUT_PP_CAT(sprout_has_xxx_impl_check_type_, TEMPLATE), NAME), __LINE__)(long); \ + template(0))> \ + struct NAME \ + : public Base_ \ + {} +#else +#define SPROUT_HAS_XXX_TEMPLATE_DEF(NAME, TEMPLATE) \ + template class = T::template TEMPLATE> \ + std::true_type SPROUT_PP_CAT(SPROUT_PP_CAT(SPROUT_PP_CAT(sprout_has_xxx_impl_check_type_, TEMPLATE), NAME), __LINE__)(int); \ + template \ + std::false_type SPROUT_PP_CAT(SPROUT_PP_CAT(SPROUT_PP_CAT(sprout_has_xxx_impl_check_type_, TEMPLATE), NAME), __LINE__)(long); \ + template \ + struct NAME \ + : public decltype(SPROUT_PP_CAT(SPROUT_PP_CAT(SPROUT_PP_CAT(sprout_has_xxx_impl_check_type_, TEMPLATE), NAME), __LINE__)(0)) \ + {} +#endif +#define SPROUT_HAS_XXX_TEMPLATE_DEF_LAZY(TEMPLATE) \ + SPROUT_HAS_XXX_TEMPLATE_DEF(SPROUT_PP_CAT(has_, TEMPLATE), TEMPLATE) + #endif // #ifndef SPROUT_TYPE_TRAITS_HAS_XXX_HPP diff --git a/sprout/variant/apply_visitor.hpp b/sprout/variant/apply_visitor.hpp index 4e247d04..205a5ed7 100644 --- a/sprout/variant/apply_visitor.hpp +++ b/sprout/variant/apply_visitor.hpp @@ -1,12 +1,52 @@ #ifndef SPROUT_VARIANT_APPLY_VISITOR_HPP #define SPROUT_VARIANT_APPLY_VISITOR_HPP +#include #include #include +#include namespace sprout { + // + // has_visitor_result + // + SPROUT_HAS_XXX_TEMPLATE_DEF_LAZY(visitor_result); + + namespace detail { + template + struct visitor_result_impl; + template + struct visitor_result_impl< + Visitor, Visitable, + typename std::enable_if::value>::type + > + : public Visitable::template visitor_result + {}; + template + struct visitor_result_impl< + Visitor, Visitable, + typename std::enable_if::value>::type + > { + public: + typedef typename Visitor::result_type type; + }; + } // namespace detail + // + // visitor_result + // template - inline SPROUT_CONSTEXPR typename std::decay::type::result_type + struct visitor_result + : public sprout::detail::visitor_result_impl + {}; + + // + // apply_visitor + // + template + inline SPROUT_CONSTEXPR typename sprout::visitor_result< + typename std::remove_reference::type, + typename std::remove_reference::type + >::type apply_visitor(Visitor&& visitor, Visitable&& visitable) { return sprout::forward(visitable).apply_visitor(sprout::forward(visitor)); } diff --git a/sprout/variant/variant.hpp b/sprout/variant/variant.hpp index 7969fecc..1ce6c193 100644 --- a/sprout/variant/variant.hpp +++ b/sprout/variant/variant.hpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include namespace sprout { template @@ -72,6 +74,52 @@ namespace sprout { typedef typename impl_type::uncvref_tuple_type uncvref_tuple_type; public: typedef typename impl_type::tuple_type tuple_type; + private: + template + struct visitor_result_impl_1; + template + struct visitor_result_impl_1 > { + public: + typedef typename std::decay< + typename std::common_type< + decltype((std::declval())(sprout::tuples::get(std::declval())))... + >::type + >::type type; + }; + template + struct visitor_result_impl; + template + struct visitor_result_impl< + Visitor, Tuple, + typename std::enable_if >::value>::type + > + : public visitor_result_impl_1::value>::type> + {}; + template + struct visitor_result_impl< + Visitor, Tuple, + typename std::enable_if >::value>::type + > { + public: + typedef typename sprout::weak_result_type::result_type type; + }; + public: + template + struct visitor_result + : public visitor_result_impl + {}; + template + struct visitor_result + : public visitor_result_impl + {}; + template + struct visitor_result + : public visitor_result_impl + {}; + template + struct visitor_result + : public visitor_result_impl + {}; private: template static SPROUT_CONSTEXPR typename std::enable_if< @@ -124,21 +172,24 @@ namespace sprout { : output(os, t, which) ; } - template + template static SPROUT_CONSTEXPR typename std::enable_if< - I == sizeof...(Types), - typename std::decay::type::result_type - >::type visit(Tuple&& t, Visitor&& v, int which) { - return typename std::decay::type::result_type(); - } - template - static SPROUT_CONSTEXPR typename std::enable_if< - I != sizeof...(Types), - typename std::decay::type::result_type + I == sizeof...(Types) - 1, + Result >::type visit(Tuple&& t, Visitor&& v, int which) { return I == which ? sprout::forward(v)(sprout::tuples::get(sprout::forward(t))) - : visit(sprout::forward(t), sprout::forward(v), which) + : throw std::domain_error("variant<>: bad visit") + ; + } + template + static SPROUT_CONSTEXPR typename std::enable_if< + I != sizeof...(Types) - 1, + Result + >::type visit(Tuple&& t, Visitor&& v, int which) { + return I == which + ? sprout::forward(v)(sprout::tuples::get(sprout::forward(t))) + : visit(sprout::forward(t), sprout::forward(v), which) ; } private: @@ -249,12 +300,16 @@ namespace sprout { } // visitation support template - SPROUT_CONSTEXPR typename std::decay::type::result_type apply_visitor(Visitor&& visitor) const { - return visit<0>(tuple_, sprout::forward(visitor), which_); + SPROUT_CONSTEXPR typename visitor_result::type, variant const>::type + apply_visitor(Visitor&& visitor) const { + typedef typename visitor_result::type, variant const>::type result_type; + return visit(tuple_, sprout::forward(visitor), which_); } template - typename std::decay::type::result_type apply_visitor(Visitor&& visitor) { - return visit<0>(tuple_, sprout::forward(visitor), which_); + typename visitor_result::type, variant>::type + apply_visitor(Visitor&& visitor) { + typedef typename visitor_result::type, variant>::type result_type; + return visit(tuple_, sprout::forward(visitor), which_); } };