diff --git a/include/boost/parser/detail/text/detail/all_t.hpp b/include/boost/parser/detail/text/detail/all_t.hpp new file mode 100644 index 00000000..c4c7cab0 --- /dev/null +++ b/include/boost/parser/detail/text/detail/all_t.hpp @@ -0,0 +1,122 @@ +// Copyright (C) 2024 T. Zachary Laine +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_PARSER_DETAIL_TEXT_DETAIL_ALL_T_HPP +#define BOOST_PARSER_DETAIL_TEXT_DETAIL_ALL_T_HPP + +#include +#include +#include + +#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS +#include +#endif + + +namespace boost::parser::detail::text::detail { + + template + using iterator_ = decltype(text::detail::begin(std::declval())); + template + using sentinel_ = decltype(text::detail::end(std::declval())); + + template + constexpr bool range_ = + is_detected_v && is_detected_v; + + template + using has_insert_ = decltype(std::declval().insert( + std::declval().begin(), *std::declval().begin())); + + template + constexpr bool container_ = is_detected_v; + + template + constexpr bool view = range_ && !container_; + + template< + typename R, + typename Enable = std::enable_if_t && std::is_object_v>> + struct ref_view : stl_interfaces::view_interface> + { + template< + typename T, + typename Enable2 = std::enable_if_t< + !std:: + is_same_v, remove_cv_ref_t> && + std::is_convertible_v>> + constexpr ref_view(T && t) : + r_(std::addressof(static_cast((T &&) t))) + {} + constexpr R & base() const { return *r_; } + constexpr iterator_ begin() const + { + return text::detail::begin(*r_); + } + constexpr sentinel_ end() const { return text::detail::end(*r_); } + + private: + R * r_; + }; + + template + ref_view(R &) -> ref_view; + + template + struct owning_view : stl_interfaces::view_interface> + { + owning_view() = default; + constexpr owning_view(R && t) : r_(std::move(t)) {} + + owning_view(owning_view &&) = default; + owning_view & operator=(owning_view &&) = default; + + constexpr R & base() & noexcept { return r_; } + constexpr const R & base() const & noexcept { return r_; } + constexpr R && base() && noexcept { return std::move(r_); } + constexpr const R && base() const && noexcept { return std::move(r_); } + + constexpr iterator_ begin() { return text::detail::begin(r_); } + constexpr sentinel_ end() { return text::detail::end(r_); } + + constexpr auto begin() const { return text::detail::begin(r_); } + constexpr auto end() const { return text::detail::end(r_); } + + private: + R r_ = R(); + }; + + template + using can_ref_view_expr = decltype(ref_view(std::declval())); + template + constexpr bool can_ref_view = is_detected_v; + + struct all_impl + { + template>> + [[nodiscard]] constexpr auto operator()(R && r) const + { + if constexpr (view>) + return (R &&) r; + else if constexpr (can_ref_view) + return ref_view((R &&) r); + else + return owning_view((R &&) r); + } + }; + + constexpr all_impl all; + +#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS + template + using all_t = std::views::all_t; +#else + template + using all_t = decltype(all(std::declval())); +#endif + +} + +#endif diff --git a/include/boost/parser/detail/text/transcode_view.hpp b/include/boost/parser/detail/text/transcode_view.hpp index debf191d..b304df58 100644 --- a/include/boost/parser/detail/text/transcode_view.hpp +++ b/include/boost/parser/detail/text/transcode_view.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -386,11 +387,11 @@ namespace boost::parser::detail { namespace text { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template - char8_view(R &&) -> char8_view>; + char8_view(R &&) -> char8_view>; template - char16_view(R &&) -> char16_view>; + char16_view(R &&) -> char16_view>; template - char32_view(R &&) -> char32_view>; + char32_view(R &&) -> char32_view>; #endif #endif @@ -481,10 +482,8 @@ namespace boost::parser::detail { namespace text { constexpr auto end() const { return code_units().end(); } }; -#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template - unpacking_view(R &&) -> unpacking_view>; -#endif + unpacking_view(R &&) -> unpacking_view>; // clang-format on #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS @@ -675,13 +674,13 @@ namespace boost::parser::detail { namespace text { {} }; -#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS +#if !BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD template - utf8_view(R &&) -> utf8_view>; + utf8_view(R &&) -> utf8_view>; template - utf16_view(R &&) -> utf16_view>; + utf16_view(R &&) -> utf16_view>; template - utf32_view(R &&) -> utf32_view>; + utf32_view(R &&) -> utf32_view>; #endif #endif diff --git a/include/boost/parser/replace.hpp b/include/boost/parser/replace.hpp index c39b2768..4ccca6f5 100644 --- a/include/boost/parser/replace.hpp +++ b/include/boost/parser/replace.hpp @@ -386,7 +386,6 @@ namespace boost::parser { }; // deduction guides -#if BOOST_PARSER_USE_CONCEPTS template< typename V, typename ReplacementV, @@ -401,8 +400,8 @@ namespace boost::parser { ReplacementV &&, trace) -> replace_view< - std::views::all_t, - std::views::all_t, + detail::text::detail::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, @@ -421,8 +420,8 @@ namespace boost::parser { parser_interface, ReplacementV &&) -> replace_view< - std::views::all_t, - std::views::all_t, + detail::text::detail::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, @@ -440,8 +439,8 @@ namespace boost::parser { ReplacementV &&, trace) -> replace_view< - std::views::all_t, - std::views::all_t, + detail::text::detail::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, @@ -458,50 +457,12 @@ namespace boost::parser { parser_interface, ReplacementV &&) -> replace_view< - std::views::all_t, - std::views::all_t, + detail::text::detail::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, parser_interface>>; -#else - template< - typename V, - typename ReplacementV, - typename Parser, - typename GlobalState, - typename ErrorHandler> - replace_view( - V &&, - parser_interface, - ReplacementV &&, - trace) - -> replace_view< - V, - ReplacementV, - Parser, - GlobalState, - ErrorHandler, - parser_interface>>; - - template< - typename V, - typename ReplacementV, - typename Parser, - typename GlobalState, - typename ErrorHandler> - replace_view( - V &&, - parser_interface, - ReplacementV &&) - -> replace_view< - V, - ReplacementV, - Parser, - GlobalState, - ErrorHandler, - parser_interface>>; -#endif namespace detail { template< diff --git a/include/boost/parser/search.hpp b/include/boost/parser/search.hpp index 5b769a3b..5e3f9142 100644 --- a/include/boost/parser/search.hpp +++ b/include/boost/parser/search.hpp @@ -426,7 +426,6 @@ namespace boost::parser { }; // deduction guides -#if BOOST_PARSER_USE_CONCEPTS template< typename V, typename Parser, @@ -439,7 +438,7 @@ namespace boost::parser { parser_interface, trace) -> search_all_view< - std::views::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, @@ -456,7 +455,7 @@ namespace boost::parser { parser_interface, parser_interface) -> search_all_view< - std::views::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, @@ -470,7 +469,7 @@ namespace boost::parser { search_all_view( V &&, parser_interface, trace) -> search_all_view< - std::views::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, @@ -483,39 +482,11 @@ namespace boost::parser { typename ErrorHandler> search_all_view(V &&, parser_interface) -> search_all_view< - std::views::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, parser_interface>>; -#else - template< - typename V, - typename Parser, - typename GlobalState, - typename ErrorHandler> - search_all_view( - V &&, parser_interface, trace) - -> search_all_view< - V, - Parser, - GlobalState, - ErrorHandler, - parser_interface>>; - - template< - typename V, - typename Parser, - typename GlobalState, - typename ErrorHandler> - search_all_view(V &&, parser_interface) - -> search_all_view< - V, - Parser, - GlobalState, - ErrorHandler, - parser_interface>>; -#endif namespace detail { template< diff --git a/include/boost/parser/split.hpp b/include/boost/parser/split.hpp index 91caa668..92d17103 100644 --- a/include/boost/parser/split.hpp +++ b/include/boost/parser/split.hpp @@ -153,7 +153,6 @@ namespace boost::parser { }; // deduction guides -#if BOOST_PARSER_USE_CONCEPTS template< typename V, typename Parser, @@ -166,7 +165,7 @@ namespace boost::parser { parser_interface, trace) -> split_view< - std::views::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, @@ -183,7 +182,7 @@ namespace boost::parser { parser_interface, parser_interface) -> split_view< - std::views::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, @@ -197,7 +196,7 @@ namespace boost::parser { split_view( V &&, parser_interface, trace) -> split_view< - std::views::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, @@ -210,39 +209,11 @@ namespace boost::parser { typename ErrorHandler> split_view(V &&, parser_interface) -> split_view< - std::views::all_t, + detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, parser_interface>>; -#else - template< - typename V, - typename Parser, - typename GlobalState, - typename ErrorHandler> - split_view( - V &&, parser_interface, trace) - -> split_view< - V, - Parser, - GlobalState, - ErrorHandler, - parser_interface>>; - - template< - typename V, - typename Parser, - typename GlobalState, - typename ErrorHandler> - split_view(V &&, parser_interface) - -> split_view< - V, - Parser, - GlobalState, - ErrorHandler, - parser_interface>>; -#endif namespace detail { template< diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6530c79e..cf284b58 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -46,6 +46,7 @@ macro(add_test_executable name) add_test(NAME ${name} COMMAND ${name} --gtest_catch_exceptions=1) endmacro() +add_test_executable(all_t) add_test_executable(search) add_test_executable(split) add_test_executable(replace) diff --git a/test/all_t.cpp b/test/all_t.cpp new file mode 100644 index 00000000..98bf888d --- /dev/null +++ b/test/all_t.cpp @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2024 T. Zachary Laine + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include +#include + +#include + + +using namespace boost::parser::detail::text; + +TEST(all_t, basic) +{ + std::string str; + std::string const const_str; + + { + auto && result = detail::all( + BOOST_PARSER_SUBRANGE(const_str.begin(), const_str.end())); + static_assert(std::is_same_v< + decltype(result), + BOOST_PARSER_SUBRANGE &&>); + } + { + auto && result = detail::all(str); + static_assert( + std::is_same_v &&>); + } + { + auto && result = detail::all(const_str); + static_assert(std::is_same_v< + decltype(result), + detail::ref_view &&>); + } + { + auto && result = detail::all(std::string{}); + static_assert(std::is_same_v< + decltype(result), + detail::owning_view &&>); + } + + static_assert( + std::is_same_v< + detail::all_t>, + BOOST_PARSER_SUBRANGE>); + + static_assert(std::is_same_v< + detail::all_t, + detail::ref_view>); + + static_assert(std::is_same_v< + detail::all_t, + detail::ref_view>); + + static_assert(std::is_same_v< + detail::all_t, + detail::owning_view>); +}