2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-19 04:22:13 +00:00

Add all_t, and use it in non-concepts builds.

Fixes #85.
This commit is contained in:
Zach Laine
2024-01-28 01:43:53 -06:00
parent de74eecabe
commit 33edb6c4e8
7 changed files with 211 additions and 123 deletions

View File

@@ -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 <boost/parser/detail/stl_interfaces/view_interface.hpp>
#include <boost/parser/detail/text/detail/begin_end.hpp>
#include <boost/parser/detail/detection.hpp>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
#include <ranges>
#endif
namespace boost::parser::detail::text::detail {
template<typename T>
using iterator_ = decltype(text::detail::begin(std::declval<T &>()));
template<typename Range>
using sentinel_ = decltype(text::detail::end(std::declval<Range>()));
template<typename T>
constexpr bool range_ =
is_detected_v<iterator_, T> && is_detected_v<sentinel_, T>;
template<typename T>
using has_insert_ = decltype(std::declval<T &>().insert(
std::declval<T>().begin(), *std::declval<T>().begin()));
template<typename T>
constexpr bool container_ = is_detected_v<has_insert_, T>;
template<typename R>
constexpr bool view = range_<R> && !container_<R>;
template<
typename R,
typename Enable = std::enable_if_t<range_<R> && std::is_object_v<R>>>
struct ref_view : stl_interfaces::view_interface<ref_view<R>>
{
template<
typename T,
typename Enable2 = std::enable_if_t<
!std::
is_same_v<remove_cv_ref_t<T>, remove_cv_ref_t<ref_view>> &&
std::is_convertible_v<T, R &>>>
constexpr ref_view(T && t) :
r_(std::addressof(static_cast<R &>((T &&) t)))
{}
constexpr R & base() const { return *r_; }
constexpr iterator_<R> begin() const
{
return text::detail::begin(*r_);
}
constexpr sentinel_<R> end() const { return text::detail::end(*r_); }
private:
R * r_;
};
template<typename R>
ref_view(R &) -> ref_view<R>;
template<typename R>
struct owning_view : stl_interfaces::view_interface<owning_view<R>>
{
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_<R> begin() { return text::detail::begin(r_); }
constexpr sentinel_<R> 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<typename T>
using can_ref_view_expr = decltype(ref_view(std::declval<T>()));
template<typename T>
constexpr bool can_ref_view = is_detected_v<can_ref_view_expr, T>;
struct all_impl
{
template<typename R, typename Enable = std::enable_if_t<range_<R>>>
[[nodiscard]] constexpr auto operator()(R && r) const
{
if constexpr (view<remove_cv_ref_t<R>>)
return (R &&) r;
else if constexpr (can_ref_view<R>)
return ref_view((R &&) r);
else
return owning_view((R &&) r);
}
};
constexpr all_impl all;
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<typename R>
using all_t = std::views::all_t<R>;
#else
template<typename R>
using all_t = decltype(all(std::declval<R>()));
#endif
}
#endif

View File

@@ -8,6 +8,7 @@
#include <boost/parser/detail/text/transcode_algorithm.hpp>
#include <boost/parser/detail/text/transcode_iterator.hpp>
#include <boost/parser/detail/text/detail/all_t.hpp>
#include <boost/parser/detail/stl_interfaces/view_interface.hpp>
#include <boost/parser/detail/stl_interfaces/view_adaptor.hpp>
@@ -386,11 +387,11 @@ namespace boost::parser::detail { namespace text {
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R>
char8_view(R &&) -> char8_view<std::views::all_t<R>>;
char8_view(R &&) -> char8_view<detail::all_t<R>>;
template<class R>
char16_view(R &&) -> char16_view<std::views::all_t<R>>;
char16_view(R &&) -> char16_view<detail::all_t<R>>;
template<class R>
char32_view(R &&) -> char32_view<std::views::all_t<R>>;
char32_view(R &&) -> char32_view<detail::all_t<R>>;
#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<class R>
unpacking_view(R &&) -> unpacking_view<std::views::all_t<R>>;
#endif
unpacking_view(R &&) -> unpacking_view<detail::all_t<R>>;
// 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<class R>
utf8_view(R &&) -> utf8_view<std::views::all_t<R>>;
utf8_view(R &&) -> utf8_view<detail::all_t<R>>;
template<class R>
utf16_view(R &&) -> utf16_view<std::views::all_t<R>>;
utf16_view(R &&) -> utf16_view<detail::all_t<R>>;
template<class R>
utf32_view(R &&) -> utf32_view<std::views::all_t<R>>;
utf32_view(R &&) -> utf32_view<detail::all_t<R>>;
#endif
#endif

View File

@@ -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<V>,
std::views::all_t<ReplacementV>,
detail::text::detail::all_t<V>,
detail::text::detail::all_t<ReplacementV>,
Parser,
GlobalState,
ErrorHandler,
@@ -421,8 +420,8 @@ namespace boost::parser {
parser_interface<SkipParser>,
ReplacementV &&)
-> replace_view<
std::views::all_t<V>,
std::views::all_t<ReplacementV>,
detail::text::detail::all_t<V>,
detail::text::detail::all_t<ReplacementV>,
Parser,
GlobalState,
ErrorHandler,
@@ -440,8 +439,8 @@ namespace boost::parser {
ReplacementV &&,
trace)
-> replace_view<
std::views::all_t<V>,
std::views::all_t<ReplacementV>,
detail::text::detail::all_t<V>,
detail::text::detail::all_t<ReplacementV>,
Parser,
GlobalState,
ErrorHandler,
@@ -458,50 +457,12 @@ namespace boost::parser {
parser_interface<Parser, GlobalState, ErrorHandler>,
ReplacementV &&)
-> replace_view<
std::views::all_t<V>,
std::views::all_t<ReplacementV>,
detail::text::detail::all_t<V>,
detail::text::detail::all_t<ReplacementV>,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
#else
template<
typename V,
typename ReplacementV,
typename Parser,
typename GlobalState,
typename ErrorHandler>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler>,
ReplacementV &&,
trace)
-> replace_view<
V,
ReplacementV,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
template<
typename V,
typename ReplacementV,
typename Parser,
typename GlobalState,
typename ErrorHandler>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler>,
ReplacementV &&)
-> replace_view<
V,
ReplacementV,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
#endif
namespace detail {
template<

View File

@@ -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<SkipParser>,
trace)
-> search_all_view<
std::views::all_t<V>,
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
@@ -456,7 +455,7 @@ namespace boost::parser {
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>)
-> search_all_view<
std::views::all_t<V>,
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
@@ -470,7 +469,7 @@ namespace boost::parser {
search_all_view(
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
-> search_all_view<
std::views::all_t<V>,
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
@@ -483,39 +482,11 @@ namespace boost::parser {
typename ErrorHandler>
search_all_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
-> search_all_view<
std::views::all_t<V>,
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
#else
template<
typename V,
typename Parser,
typename GlobalState,
typename ErrorHandler>
search_all_view(
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
-> search_all_view<
V,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
template<
typename V,
typename Parser,
typename GlobalState,
typename ErrorHandler>
search_all_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
-> search_all_view<
V,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
#endif
namespace detail {
template<

View File

@@ -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<SkipParser>,
trace)
-> split_view<
std::views::all_t<V>,
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
@@ -183,7 +182,7 @@ namespace boost::parser {
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>)
-> split_view<
std::views::all_t<V>,
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
@@ -197,7 +196,7 @@ namespace boost::parser {
split_view(
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
-> split_view<
std::views::all_t<V>,
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
@@ -210,39 +209,11 @@ namespace boost::parser {
typename ErrorHandler>
split_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
-> split_view<
std::views::all_t<V>,
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
#else
template<
typename V,
typename Parser,
typename GlobalState,
typename ErrorHandler>
split_view(
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
-> split_view<
V,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
template<
typename V,
typename Parser,
typename GlobalState,
typename ErrorHandler>
split_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
-> split_view<
V,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
#endif
namespace detail {
template<

View File

@@ -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)

63
test/all_t.cpp Normal file
View File

@@ -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 <boost/parser/config.hpp>
#include <boost/parser/detail/text/detail/all_t.hpp>
#include <gtest/gtest.h>
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<decltype(const_str.begin())> &&>);
}
{
auto && result = detail::all(str);
static_assert(
std::is_same_v<decltype(result), detail::ref_view<std::string> &&>);
}
{
auto && result = detail::all(const_str);
static_assert(std::is_same_v<
decltype(result),
detail::ref_view<std::string const> &&>);
}
{
auto && result = detail::all(std::string{});
static_assert(std::is_same_v<
decltype(result),
detail::owning_view<std::string> &&>);
}
static_assert(
std::is_same_v<
detail::all_t<BOOST_PARSER_SUBRANGE<decltype(const_str.begin())>>,
BOOST_PARSER_SUBRANGE<decltype(const_str.begin())>>);
static_assert(std::is_same_v<
detail::all_t<std::string &>,
detail::ref_view<std::string>>);
static_assert(std::is_same_v<
detail::all_t<std::string const &>,
detail::ref_view<std::string const>>);
static_assert(std::is_same_v<
detail::all_t<std::string &&>,
detail::owning_view<std::string>>);
}