2
0
mirror of https://github.com/boostorg/spirit.git synced 2026-01-19 04:42:11 +00:00

Modernize char/string, use X3's own char_encoding

This commit is contained in:
Nana Sakisaka
2025-09-08 10:02:43 +09:00
parent 5fb8252115
commit c28805b591
42 changed files with 2343 additions and 1869 deletions

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -7,62 +8,56 @@
#if !defined(BOOST_SPIRIT_X3_ANY_CHAR_APRIL_16_2006_1051AM)
#define BOOST_SPIRIT_X3_ANY_CHAR_APRIL_16_2006_1051AM
#include <boost/type_traits/extent.hpp>
#include <boost/spirit/home/x3/char/literal_char.hpp>
#include <boost/spirit/home/x3/char/char_set.hpp>
namespace boost { namespace spirit { namespace x3
namespace boost::spirit::x3
{
template <typename Encoding>
struct any_char : char_parser<any_char<Encoding>>
{
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef char_type attribute_type;
static bool const has_attribute = true;
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = char_type;
static constexpr bool has_attribute = true;
template <typename Char, typename Context>
bool test(Char ch_, Context const&) const
template <typename Context>
[[nodiscard]] static constexpr bool test(char_type ch, Context const&) noexcept
{
return encoding::ischar(ch_);
return encoding::ischar(ch);
}
template <typename Char>
constexpr literal_char<Encoding> operator()(Char ch) const
[[nodiscard]] static constexpr literal_char<Encoding> operator()(char_type ch) noexcept
{
return { ch };
}
template <typename Char>
constexpr literal_char<Encoding> operator()(const Char (&ch)[2]) const
[[nodiscard]] static constexpr literal_char<Encoding> operator()(char_type const (&ch)[2]) noexcept
{
return { ch[0] };
}
template <typename Char, std::size_t N>
constexpr char_set<Encoding> operator()(const Char (&ch)[N]) const
template <std::size_t N>
[[nodiscard]] static constexpr char_set<Encoding> operator()(char_type const (&ch)[N]) noexcept
{
return { ch };
}
template <typename Char>
constexpr char_range<Encoding> operator()(Char from, Char to) const
[[nodiscard]] static constexpr char_range<Encoding> operator()(char_type from, char_type to) noexcept
{
return { from, to };
}
template <typename Char>
constexpr char_range<Encoding> operator()(Char (&from)[2], Char (&to)[2]) const
[[nodiscard]] static constexpr char_range<Encoding> operator()(char_type const (&from)[2], char_type const (&to)[2]) noexcept
{
return { static_cast<char_type>(from[0]), static_cast<char_type>(to[0]) };
}
template <typename Char>
char_set<Encoding> operator()(std::basic_string<Char> const& s) const
[[nodiscard]] static char_set<Encoding> operator()(std::basic_string_view<char_type> sv) noexcept
{
return { s };
return { std::move(sv) };
}
};
}}}
} // boost::spirit::x3
#endif

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,84 +9,139 @@
#define BOOST_SPIRIT_X3_CHAR_APRIL_16_2006_1051AM
#include <boost/spirit/home/x3/char/any_char.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/spirit/home/support/char_encoding/iso8859_1.hpp>
#include <boost/spirit/home/support/char_encoding/standard.hpp>
#include <boost/spirit/home/support/char_encoding/standard_wide.hpp>
#include <boost/spirit/home/x3/char/literal_char.hpp>
#include <boost/spirit/home/x3/support/traits/string_traits.hpp>
namespace boost { namespace spirit { namespace x3
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/spirit/home/x3/char_encoding/ascii.hpp> // deprecated
#include <boost/spirit/home/x3/char_encoding/iso8859_1.hpp> // deprecated
#include <boost/spirit/home/x3/char_encoding/standard.hpp>
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
# include <boost/spirit/home/x3/char_encoding/standard_wide.hpp>
#endif
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#endif
#include <type_traits>
namespace boost::spirit::x3
{
namespace standard
{
typedef any_char<char_encoding::standard> char_type;
constexpr auto char_ = char_type{};
inline constexpr any_char<char_encoding::standard> char_{};
constexpr literal_char<char_encoding::standard, unused_type>
lit(char ch)
inline namespace helpers
{
return { ch };
}
[[nodiscard]] constexpr literal_char<char_encoding::standard, unused_type>
lit(char ch) noexcept
{
return { ch };
}
constexpr literal_char<char_encoding::standard, unused_type>
lit(wchar_t ch)
{
return { ch };
}
[[nodiscard]] constexpr literal_char<char_encoding::standard, unused_type>
lit(traits::X3VagueArrayOf2Chars<char> auto const& ch) noexcept
{
return { ch[0] };
}
} // helpers
// If you see "no matching overload" on string literals (e.g. `"foo"`),
// you may need to include `x3/string/literal_string.hpp`.
// If you still see errors after the inclusion, that might be due to
// mixing incompatible string literals. Don't do that.
constexpr void lit(traits::CharIncompatibleWith<char> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<char> auto) = delete; // Mixing incompatible character types is not allowed
}
using standard::char_type;
using standard::char_;
using standard::lit;
inline constexpr auto const& char_ = standard::char_; // TODO: this can't overload other character types
using standard::helpers::lit;
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
namespace standard_wide
{
typedef any_char<char_encoding::standard_wide> char_type;
constexpr auto char_ = char_type{};
inline constexpr any_char<char_encoding::standard_wide> char_{};
constexpr literal_char<char_encoding::standard_wide, unused_type>
lit(wchar_t ch)
inline namespace helpers
{
return { ch };
}
[[nodiscard]] constexpr literal_char<char_encoding::standard_wide, unused_type>
lit(wchar_t ch) noexcept
{
return { ch };
}
[[nodiscard]] constexpr literal_char<char_encoding::standard_wide, unused_type>
lit(traits::X3VagueArrayOf2Chars<wchar_t> auto const& ch) noexcept
{
return { ch[0] };
}
} // helpers
constexpr void lit(traits::CharIncompatibleWith<wchar_t> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<wchar_t> auto) = delete; // Mixing incompatible character types is not allowed
}
using standard_wide::helpers::lit;
#endif
namespace ascii
#ifdef BOOST_SPIRIT_X3_UNICODE
namespace unicode
{
typedef any_char<char_encoding::ascii> char_type;
constexpr auto char_ = char_type{};
inline constexpr any_char<char_encoding::unicode> char_{};
constexpr literal_char<char_encoding::ascii, unused_type>
lit(char ch)
inline namespace helpers
{
return { ch };
}
// TODO: add `char8_t` and `char16_t` overloads
constexpr literal_char<char_encoding::ascii, unused_type>
lit(wchar_t ch)
{
return { ch };
}
[[nodiscard]] constexpr literal_char<char_encoding::unicode, unused_type>
lit(char32_t ch) noexcept
{
return { ch };
}
[[nodiscard]] constexpr literal_char<char_encoding::unicode, unused_type>
lit(traits::X3VagueArrayOf2Chars<char32_t> auto const& ch) noexcept
{
return { ch[0] };
}
} // helpers
constexpr void lit(traits::CharIncompatibleWith<char32_t> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<char32_t> auto) = delete; // Mixing incompatible character types is not allowed
}
namespace iso8859_1
using unicode::helpers::lit;
#endif
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] ascii
{
typedef any_char<char_encoding::iso8859_1> char_type;
constexpr auto char_ = char_type{};
inline constexpr any_char<char_encoding::ascii> char_{};
constexpr literal_char<char_encoding::iso8859_1, unused_type>
lit(char ch)
[[nodiscard]] constexpr literal_char<char_encoding::ascii, unused_type>
lit(char ch) noexcept
{
return { ch };
}
constexpr literal_char<char_encoding::iso8859_1, unused_type>
lit(wchar_t ch)
constexpr void lit(traits::CharIncompatibleWith<char> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<char> auto) = delete; // Mixing incompatible character types is not allowed
}
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] iso8859_1
{
inline constexpr any_char<char_encoding::iso8859_1> char_{};
[[nodiscard]] constexpr literal_char<char_encoding::iso8859_1, unused_type>
lit(char ch) noexcept
{
return { ch };
}
constexpr void lit(traits::CharIncompatibleWith<char> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<char> auto) = delete; // Mixing incompatible character types is not allowed
}
namespace extension
@@ -93,29 +149,23 @@ namespace boost { namespace spirit { namespace x3
template <>
struct as_parser<char>
{
typedef literal_char<
char_encoding::standard, unused_type>
type;
using type = literal_char<char_encoding::standard, unused_type>;
using value_type = type;
typedef type value_type;
static constexpr type call(char ch)
[[nodiscard]] static constexpr type call(char ch) noexcept
{
return { ch };
}
};
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
template <>
struct as_parser<wchar_t>
{
typedef literal_char<
char_encoding::standard_wide, unused_type>
type;
using type = literal_char<char_encoding::standard_wide, unused_type>;
using value_type = type;
typedef type value_type;
static constexpr type call(wchar_t ch)
[[nodiscard]] static constexpr type call(wchar_t ch) noexcept
{
return { ch };
}
@@ -125,37 +175,30 @@ namespace boost { namespace spirit { namespace x3
template <>
struct as_parser<char [2]>
{
typedef literal_char<
char_encoding::standard, unused_type>
type;
using type = literal_char<char_encoding::standard, unused_type>;
using value_type = type;
typedef type value_type;
static constexpr type call(char const ch[])
[[nodiscard]] static constexpr type call(char const ch[]) noexcept
{
return { ch[0] };
}
};
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
template <>
struct as_parser<wchar_t [2]>
{
typedef literal_char<
char_encoding::standard_wide, unused_type>
type;
using type = literal_char<char_encoding::standard_wide, unused_type>;
using value_type = type;
typedef type value_type;
static constexpr type call(wchar_t const ch[] )
[[nodiscard]] static constexpr type call(wchar_t const ch[]) noexcept
{
return { ch[0] };
}
};
#endif
}
}}}
} // boost::spirit::x3
#endif

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,24 +9,27 @@
#define BOOST_SPIRIT_X3_CHAR_CLASS_APRIL_16_2006_1051AM
#include <boost/spirit/home/x3/char/char_parser.hpp>
#include <boost/spirit/home/x3/char/detail/cast_char.hpp>
#include <boost/spirit/home/support/char_encoding/standard.hpp>
#include <boost/spirit/home/support/char_encoding/standard_wide.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/spirit/home/support/char_encoding/iso8859_1.hpp>
#include <boost/spirit/home/x3/char/char_class_tags.hpp>
namespace boost { namespace spirit { namespace x3
#include <boost/spirit/home/x3/char/detail/cast_char.hpp>
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/spirit/home/x3/char_encoding/standard.hpp>
#include <boost/spirit/home/x3/char_encoding/standard_wide.hpp>
#include <boost/spirit/home/x3/char_encoding/ascii.hpp>
#include <boost/spirit/home/x3/char_encoding/iso8859_1.hpp>
namespace boost::spirit::x3
{
///////////////////////////////////////////////////////////////////////////
template <typename Encoding>
struct char_class_base
{
typedef typename Encoding::classify_type char_type;
using char_type = typename Encoding::classify_type;
#define BOOST_SPIRIT_X3_CLASSIFY(name) \
template <typename Char> \
static bool \
is(name##_tag, Char ch) \
[[nodiscard]] static constexpr bool \
is(name##_tag, Char ch) noexcept \
{ \
return Encoding::is##name \
BOOST_PREVENT_MACRO_SUBSTITUTION \
@@ -51,31 +55,29 @@ namespace boost { namespace spirit { namespace x3
};
template <typename Encoding, typename Tag>
struct char_class
: char_parser<char_class<Encoding, Tag>>
struct char_class : char_parser<char_class<Encoding, Tag>>
{
typedef Encoding encoding;
typedef Tag tag;
typedef typename Encoding::char_type char_type;
typedef char_type attribute_type;
static bool const has_attribute = true;
using encoding = Encoding;
using tag = Tag;
using char_type = typename Encoding::char_type;
using attribute_type = char_type;
static constexpr bool has_attribute = true;
template <typename Char, typename Context>
bool test(Char ch, Context const& context) const
[[nodiscard]] constexpr bool test(Char ch, Context const& context) const noexcept
{
return encoding::ischar(ch)
&& char_class_base<Encoding>::is(
get_case_compare<Encoding>(context).get_char_class_tag(tag()), ch);
x3::get_case_compare<Encoding>(context).get_char_class_tag(tag()), ch);
}
};
#define BOOST_SPIRIT_X3_CHAR_CLASS(encoding, name) \
typedef char_class<char_encoding::encoding, name##_tag> name##_type; \
constexpr name##_type name = name##_type(); \
/***/
using name##_type = char_class<char_encoding::encoding, name##_tag>; \
inline constexpr name##_type name{};
#define BOOST_SPIRIT_X3_CHAR_CLASSES(encoding) \
namespace encoding \
#define BOOST_SPIRIT_X3_CHAR_CLASSES(ns_attr, encoding) \
namespace ns_attr encoding \
{ \
BOOST_SPIRIT_X3_CHAR_CLASS(encoding, alnum) \
BOOST_SPIRIT_X3_CHAR_CLASS(encoding, alpha) \
@@ -89,44 +91,46 @@ namespace boost { namespace spirit { namespace x3
BOOST_SPIRIT_X3_CHAR_CLASS(encoding, space) \
BOOST_SPIRIT_X3_CHAR_CLASS(encoding, blank) \
BOOST_SPIRIT_X3_CHAR_CLASS(encoding, upper) \
} \
/***/
}
BOOST_SPIRIT_X3_CHAR_CLASSES(standard)
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
BOOST_SPIRIT_X3_CHAR_CLASSES(standard_wide)
BOOST_SPIRIT_X3_CHAR_CLASSES(, standard)
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
BOOST_SPIRIT_X3_CHAR_CLASSES(, standard_wide)
#endif
BOOST_SPIRIT_X3_CHAR_CLASSES(ascii)
BOOST_SPIRIT_X3_CHAR_CLASSES(iso8859_1)
BOOST_SPIRIT_X3_CHAR_CLASSES([[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]], ascii)
BOOST_SPIRIT_X3_CHAR_CLASSES([[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]], iso8859_1)
#undef BOOST_SPIRIT_X3_CHAR_CLASS
#undef BOOST_SPIRIT_X3_CHAR_CLASSES
using standard::alnum_type;
using standard::alpha_type;
using standard::digit_type;
using standard::xdigit_type;
using standard::cntrl_type;
using standard::graph_type;
using standard::lower_type;
using standard::print_type;
using standard::punct_type;
using standard::space_type;
using standard::blank_type;
using standard::upper_type;
using alnum_type = standard::alnum_type;
using alpha_type = standard::alpha_type;
using digit_type = standard::digit_type;
using xdigit_type = standard::xdigit_type;
using cntrl_type = standard::cntrl_type;
using graph_type = standard::graph_type;
using lower_type = standard::lower_type;
using print_type = standard::print_type;
using punct_type = standard::punct_type;
using space_type = standard::space_type;
using blank_type = standard::blank_type;
using upper_type = standard::upper_type;
using standard::alnum;
using standard::alpha;
using standard::digit;
using standard::xdigit;
using standard::cntrl;
using standard::graph;
using standard::lower;
using standard::print;
using standard::punct;
using standard::space;
using standard::blank;
using standard::upper;
}}}
inline constexpr auto const& alnum = standard::alnum;
inline constexpr auto const& alpha = standard::alpha;
inline constexpr auto const& digit = standard::digit;
inline constexpr auto const& xdigit = standard::xdigit;
inline constexpr auto const& cntrl = standard::cntrl;
inline constexpr auto const& graph = standard::graph;
inline constexpr auto const& lower = standard::lower;
inline constexpr auto const& print = standard::print;
inline constexpr auto const& punct = standard::punct;
inline constexpr auto const& space = standard::space;
inline constexpr auto const& blank = standard::blank;
inline constexpr auto const& upper = standard::upper;
} // boost::spirit::x3
#endif

View File

@@ -15,29 +15,26 @@
#include <iterator>
namespace boost { namespace spirit { namespace x3
namespace boost::spirit::x3
{
///////////////////////////////////////////////////////////////////////////
// The base char_parser
///////////////////////////////////////////////////////////////////////////
template <typename Derived>
struct char_parser : parser<Derived>
{
template <typename Iterator, typename Context, typename Attribute>
bool parse(
Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute& attr) const
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Attribute>
[[nodiscard]] constexpr bool parse(
It& first, Se const& last, Context const& context, unused_type, Attribute& attr
) const // I (saki7) don't think this can ever be noexcept, due to the nature of the operations below
{
x3::skip_over(first, last, context);
if (first != last && this->derived().test(*first, context))
{
x3::traits::move_to(std::iter_value_t<Iterator>{*first}, attr);
x3::traits::move_to(std::iter_value_t<It>{*first}, attr);
++first;
return true;
}
return false;
}
};
}}}
} // boost::spirit::x3
#endif

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,72 +10,73 @@
#include <boost/spirit/home/x3/char/char_parser.hpp>
#include <boost/spirit/home/x3/char/detail/cast_char.hpp>
#include <boost/spirit/home/x3/char/detail/basic_chset.hpp>
#include <boost/spirit/home/x3/support/traits/string_traits.hpp>
#include <boost/spirit/home/x3/support/utility/utf8.hpp>
#include <boost/spirit/home/x3/support/no_case.hpp>
#include <boost/spirit/home/support/char_set/basic_chset.hpp>
#include <boost/type_traits/is_same.hpp>
#include <ranges>
#include <string_view>
#include <type_traits>
namespace boost { namespace spirit { namespace x3
namespace boost::spirit::x3
{
///////////////////////////////////////////////////////////////////////////
// Parser for a character range
///////////////////////////////////////////////////////////////////////////
template <typename Encoding, typename Attribute = typename Encoding::char_type>
struct char_range
: char_parser< char_range<Encoding, Attribute> >
struct char_range : char_parser<char_range<Encoding, Attribute>>
{
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef Attribute attribute_type;
static bool const has_attribute =
!is_same<unused_type, attribute_type>::value;
constexpr char_range(char_type from_, char_type to_)
: from(from_), to(to_) {}
constexpr char_range(char_type from_, char_type to_) noexcept
: from(from_), to(to_)
{}
template <typename Char, typename Context>
bool test(Char ch_, Context const& context) const
requires (std::is_convertible_v<std::remove_cvref_t<Char>, char_type>)
[[nodiscard]] constexpr bool test(Char ch_, Context const& context) const noexcept
{
char_type ch = char_type(ch_); // optimize for token based parsing
return (get_case_compare<encoding>(context)(ch, from) >= 0)
&& (get_case_compare<encoding>(context)(ch , to) <= 0);
char_type ch = static_cast<char_type>(ch_); // optimize for token based parsing
return (x3::get_case_compare<encoding>(context)(ch, from) >= 0)
&& (x3::get_case_compare<encoding>(context)(ch , to) <= 0);
}
char_type from, to;
};
///////////////////////////////////////////////////////////////////////////
// Parser for a character set
///////////////////////////////////////////////////////////////////////////
template <typename Encoding, typename Attribute = typename Encoding::char_type>
struct char_set : char_parser<char_set<Encoding, Attribute>>
{
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef Attribute attribute_type;
static bool const has_attribute =
!is_same<unused_type, attribute_type>::value;
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
template <typename String>
char_set(String const& str)
template<std::ranges::forward_range R>
constexpr char_set(R const& str)
noexcept(detail::cast_char_noexcept<std::ranges::range_value_t<R>, char_type>)
{
using spirit::x3::detail::cast_char;
static_assert(detail::cast_char_viable<std::ranges::range_value_t<R>, char_type>);
auto* definition = traits::get_c_string(str);
auto ch = *definition++;
while (ch)
using detail::cast_char; // ADL introduction
for (auto definition = std::ranges::begin(str); definition != std::ranges::end(str);)
{
auto next = *definition++;
if (next == '-')
auto const ch = *definition;
auto next_definition = std::next(definition);
if (next_definition == std::ranges::end(str))
{
next = *definition++;
if (next == 0)
chset.set(cast_char<char_type>(ch));
break;
}
auto next_ch = *next_definition;
if (next_ch == '-')
{
next_definition = std::next(next_definition);
if (next_definition == std::ranges::end(str))
{
chset.set(cast_char<char_type>(ch));
chset.set('-');
@@ -82,46 +84,47 @@ namespace boost { namespace spirit { namespace x3
}
chset.set(
cast_char<char_type>(ch),
cast_char<char_type>(next)
cast_char<char_type>(*next_definition)
);
}
else
{
chset.set(cast_char<char_type>(ch));
}
ch = next;
definition = next_definition;
}
}
template <typename Char, typename Context>
bool test(Char ch_, Context const& context) const
[[nodiscard]] constexpr bool test(Char ch_, Context const& context) const noexcept
{
return get_case_compare<encoding>(context).in_set(ch_, chset);
return x3::get_case_compare<encoding>(context).in_set(ch_, chset);
}
support::detail::basic_chset<char_type> chset;
detail::basic_chset<char_type> chset;
};
template <typename Encoding, typename Attribute>
struct get_info<char_set<Encoding, Attribute>>
{
typedef std::string result_type;
std::string operator()(char_set<Encoding, Attribute> const& /* p */) const
using result_type = std::string;
[[nodiscard]] constexpr std::string operator()(char_set<Encoding, Attribute> const& /* p */) const
{
return "char-set";
return "char-set"; // TODO: make more user-friendly
}
};
template <typename Encoding, typename Attribute>
struct get_info<char_range<Encoding, Attribute>>
{
typedef std::string result_type;
std::string operator()(char_range<Encoding, Attribute> const& p) const
using result_type = std::string;
[[nodiscard]] constexpr std::string operator()(char_range<Encoding, Attribute> const& p) const
{
return "char_range \"" + to_utf8(Encoding::toucs4(p.from)) + '-' + to_utf8(Encoding::toucs4(p.to))+ '"';
// TODO: make more user-friendly && make the format consistent with above
return "char_range \"" + x3::to_utf8(Encoding::toucs4(p.from)) + '-' + x3::to_utf8(Encoding::toucs4(p.to))+ '"';
}
};
}}}
} // boost::spirit::x3
#endif

View File

@@ -16,7 +16,7 @@
namespace boost::spirit::x3::detail
{
// basic character set implementation using range_run
// basic character set implementation using char_range_run
template <typename CharT>
struct basic_chset
{
@@ -78,7 +78,7 @@ namespace boost::spirit::x3::detail
constexpr basic_chset&
operator|=(basic_chset const& x) noexcept
{
typedef typename range_run<CharT>::const_iterator const_iterator;
typedef typename char_range_run<CharT>::const_iterator const_iterator;
for (const_iterator iter = x.rr.begin(); iter != x.rr.end(); ++iter)
rr.set(*iter);
return *this;
@@ -100,7 +100,7 @@ namespace boost::spirit::x3::detail
constexpr basic_chset&
operator-=(basic_chset const& x) noexcept
{
typedef typename range_run<CharT>::const_iterator const_iterator;
typedef typename char_range_run<CharT>::const_iterator const_iterator;
for (const_iterator iter = x.rr.begin(); iter != x.rr.end(); ++iter)
rr.clear(*iter);
return *this;

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,27 +10,33 @@
#include <boost/spirit/home/x3/char/char_parser.hpp>
#include <boost/spirit/home/x3/support/utility/utf8.hpp>
#include <boost/type_traits/is_same.hpp>
namespace boost { namespace spirit { namespace x3
#include <type_traits>
#include <concepts>
namespace boost::spirit::x3
{
template <typename Encoding, typename Attribute = typename Encoding::char_type>
struct literal_char : char_parser<literal_char<Encoding, Attribute>>
{
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef Attribute attribute_type;
static bool const has_attribute =
!is_same<unused_type, attribute_type>::value;
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
template <typename Char>
constexpr literal_char(Char ch)
: ch(static_cast<char_type>(ch)) {}
requires std::convertible_to<Char, char_type>
constexpr literal_char(Char ch) noexcept
: ch(static_cast<char_type>(ch))
{
static_assert(std::same_as<char_type, Char>, "Mixing incompatible character types is not allowed");
}
template <typename Char, typename Context>
bool test(Char ch_, Context const& context) const
[[nodiscard]] constexpr bool test(Char ch_, Context const& context) const noexcept
{
return get_case_compare<encoding>(context)(ch, char_type(ch_)) == 0;
static_assert(std::same_as<char_type, Char>, "Mixing incompatible character types is not allowed");
return x3::get_case_compare<encoding>(context)(ch, char_type(ch_)) == 0;
}
char_type ch;
@@ -38,12 +45,12 @@ namespace boost { namespace spirit { namespace x3
template <typename Encoding, typename Attribute>
struct get_info<literal_char<Encoding, Attribute>>
{
typedef std::string result_type;
std::string operator()(literal_char<Encoding, Attribute> const& p) const
using result_type = std::string;
[[nodiscard]] std::string operator()(literal_char<Encoding, Attribute> const& p) const
{
return '\'' + to_utf8(Encoding::toucs4(p.ch)) + '\'';
return '\'' + x3::to_utf8(Encoding::toucs4(p.ch)) + '\'';
}
};
}}}
} // boost::spirit::x3
#endif

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,15 +9,12 @@
#define BOOST_SPIRIT_X3_UNICODE_JAN_20_2012_1218AM
#include <boost/spirit/home/x3/char/char_parser.hpp>
#include <boost/spirit/home/x3/char/char.hpp>
#include <boost/spirit/home/x3/char/detail/cast_char.hpp>
#include <boost/spirit/home/support/char_encoding/unicode.hpp>
#include <boost/spirit/home/x3/char_encoding/unicode.hpp>
namespace boost { namespace spirit { namespace x3
namespace boost::spirit::x3
{
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
struct char_tag;
struct alnum_tag;
struct alpha_tag;
@@ -31,9 +29,7 @@ namespace boost { namespace spirit { namespace x3
struct lower_tag;
struct upper_tag;
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
struct letter_tag {};
struct mark_tag {};
struct number_tag {};
@@ -42,9 +38,7 @@ namespace boost { namespace spirit { namespace x3
struct punctuation_tag {};
struct symbol_tag {};
///////////////////////////////////////////////////////////////////////////
// Unicode General Categories
///////////////////////////////////////////////////////////////////////////
// Unicode General Categories
struct uppercase_letter_tag {};
struct lowercase_letter_tag {};
struct titlecase_letter_tag {};
@@ -82,9 +76,7 @@ namespace boost { namespace spirit { namespace x3
struct modifier_symbol_tag {};
struct other_symbol_tag {};
///////////////////////////////////////////////////////////////////////////
// Unicode Derived Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Derived Categories
struct alphabetic_tag {};
struct uppercase_tag {};
struct lowercase_tag {};
@@ -93,9 +85,7 @@ namespace boost { namespace spirit { namespace x3
struct noncharacter_code_point_tag {};
struct default_ignorable_code_point_tag {};
///////////////////////////////////////////////////////////////////////////
// Unicode Scripts
///////////////////////////////////////////////////////////////////////////
// Unicode Scripts
struct adlam_tag {};
struct caucasian_albanian_tag {};
struct ahom_tag {};
@@ -262,11 +252,10 @@ namespace boost { namespace spirit { namespace x3
struct common_tag {};
struct unknown_tag {};
///////////////////////////////////////////////////////////////////////////
struct unicode_char_class_base
{
typedef char_encoding::unicode encoding;
typedef char_encoding::unicode::char_type char_type;
using encoding = char_encoding::unicode;
using char_type = char_encoding::unicode::char_type;
#define BOOST_SPIRIT_X3_BASIC_CLASSIFY(name) \
template <typename Char> \
@@ -291,9 +280,7 @@ namespace boost { namespace spirit { namespace x3
/***/
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
BOOST_SPIRIT_X3_BASIC_CLASSIFY(char)
BOOST_SPIRIT_X3_BASIC_CLASSIFY(alnum)
BOOST_SPIRIT_X3_BASIC_CLASSIFY(alpha)
@@ -308,9 +295,7 @@ namespace boost { namespace spirit { namespace x3
BOOST_SPIRIT_X3_BASIC_CLASSIFY(blank)
BOOST_SPIRIT_X3_BASIC_CLASSIFY(upper)
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
BOOST_SPIRIT_X3_CLASSIFY(letter)
BOOST_SPIRIT_X3_CLASSIFY(mark)
BOOST_SPIRIT_X3_CLASSIFY(number)
@@ -319,9 +304,7 @@ namespace boost { namespace spirit { namespace x3
BOOST_SPIRIT_X3_CLASSIFY(punctuation)
BOOST_SPIRIT_X3_CLASSIFY(symbol)
///////////////////////////////////////////////////////////////////////////
// Unicode General Categories
///////////////////////////////////////////////////////////////////////////
// Unicode General Categories
BOOST_SPIRIT_X3_CLASSIFY(uppercase_letter)
BOOST_SPIRIT_X3_CLASSIFY(lowercase_letter)
BOOST_SPIRIT_X3_CLASSIFY(titlecase_letter)
@@ -359,9 +342,7 @@ namespace boost { namespace spirit { namespace x3
BOOST_SPIRIT_X3_CLASSIFY(modifier_symbol)
BOOST_SPIRIT_X3_CLASSIFY(other_symbol)
///////////////////////////////////////////////////////////////////////////
// Unicode Derived Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Derived Categories
BOOST_SPIRIT_X3_CLASSIFY(alphabetic)
BOOST_SPIRIT_X3_CLASSIFY(uppercase)
BOOST_SPIRIT_X3_CLASSIFY(lowercase)
@@ -370,9 +351,7 @@ namespace boost { namespace spirit { namespace x3
BOOST_SPIRIT_X3_CLASSIFY(noncharacter_code_point)
BOOST_SPIRIT_X3_CLASSIFY(default_ignorable_code_point)
///////////////////////////////////////////////////////////////////////////
// Unicode Scripts
///////////////////////////////////////////////////////////////////////////
// Unicode Scripts
BOOST_SPIRIT_X3_CLASSIFY(adlam)
BOOST_SPIRIT_X3_CLASSIFY(caucasian_albanian)
BOOST_SPIRIT_X3_CLASSIFY(ahom)
@@ -545,34 +524,28 @@ namespace boost { namespace spirit { namespace x3
template <typename Tag>
struct unicode_char_class
: char_parser<unicode_char_class<Tag>>
: char_parser<unicode_char_class<Tag>>
{
typedef char_encoding::unicode encoding;
typedef Tag tag;
typedef typename encoding::char_type char_type;
typedef char_type attribute_type;
static bool const has_attribute = true;
using encoding = char_encoding::unicode;
using tag = Tag;
using char_type = typename encoding::char_type;
using attribute_type = char_type;
static constexpr bool has_attribute = true;
template <typename Char, typename Context>
bool test(Char ch, Context const&) const
[[nodiscard]] constexpr bool test(Char ch, Context const&) const noexcept
{
return encoding::ischar(ch) && unicode_char_class_base::is(tag(), ch);
return encoding::ischar(ch) && unicode_char_class_base::is(tag{}, ch);
}
};
#define BOOST_SPIRIT_X3_CHAR_CLASS(name) \
typedef unicode_char_class<name##_tag> name##_type; \
constexpr name##_type name = name##_type(); \
/***/
using name##_type = unicode_char_class<name##_tag>; \
inline constexpr name##_type name{};
namespace unicode
{
typedef any_char<char_encoding::unicode> char_type;
constexpr auto char_ = char_type{};
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
BOOST_SPIRIT_X3_CHAR_CLASS(alnum)
BOOST_SPIRIT_X3_CHAR_CLASS(alpha)
BOOST_SPIRIT_X3_CHAR_CLASS(digit)
@@ -586,9 +559,7 @@ namespace boost { namespace spirit { namespace x3
BOOST_SPIRIT_X3_CHAR_CLASS(blank)
BOOST_SPIRIT_X3_CHAR_CLASS(upper)
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
BOOST_SPIRIT_X3_CHAR_CLASS(letter)
BOOST_SPIRIT_X3_CHAR_CLASS(mark)
BOOST_SPIRIT_X3_CHAR_CLASS(number)
@@ -597,9 +568,7 @@ namespace boost { namespace spirit { namespace x3
BOOST_SPIRIT_X3_CHAR_CLASS(punctuation)
BOOST_SPIRIT_X3_CHAR_CLASS(symbol)
///////////////////////////////////////////////////////////////////////////
// Unicode General Categories
///////////////////////////////////////////////////////////////////////////
// Unicode General Categories
BOOST_SPIRIT_X3_CHAR_CLASS(uppercase_letter)
BOOST_SPIRIT_X3_CHAR_CLASS(lowercase_letter)
BOOST_SPIRIT_X3_CHAR_CLASS(titlecase_letter)
@@ -637,9 +606,7 @@ namespace boost { namespace spirit { namespace x3
BOOST_SPIRIT_X3_CHAR_CLASS(modifier_symbol)
BOOST_SPIRIT_X3_CHAR_CLASS(other_symbol)
///////////////////////////////////////////////////////////////////////////
// Unicode Derived Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Derived Categories
BOOST_SPIRIT_X3_CHAR_CLASS(alphabetic)
BOOST_SPIRIT_X3_CHAR_CLASS(uppercase)
BOOST_SPIRIT_X3_CHAR_CLASS(lowercase)
@@ -648,9 +615,7 @@ namespace boost { namespace spirit { namespace x3
BOOST_SPIRIT_X3_CHAR_CLASS(noncharacter_code_point)
BOOST_SPIRIT_X3_CHAR_CLASS(default_ignorable_code_point)
///////////////////////////////////////////////////////////////////////////
// Unicode Scripts
///////////////////////////////////////////////////////////////////////////
// Unicode Scripts
BOOST_SPIRIT_X3_CHAR_CLASS(adlam)
BOOST_SPIRIT_X3_CHAR_CLASS(caucasian_albanian)
BOOST_SPIRIT_X3_CHAR_CLASS(ahom)
@@ -820,6 +785,6 @@ namespace boost { namespace spirit { namespace x3
#undef BOOST_SPIRIT_X3_CHAR_CLASS
}}}
} // boost::spirit::x3
#endif

View File

@@ -0,0 +1,45 @@
/*=============================================================================
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CORE_CONFIG_HPP
#define BOOST_SPIRIT_X3_CORE_CONFIG_HPP
#include <boost/config.hpp>
#include <cstddef>
#if _MSC_VER
# include <CppCoreCheck/Warnings.h>
# pragma warning(default: CPPCORECHECK_LIFETIME_WARNINGS)
#endif
// <https://devblogs.microsoft.com/cppblog/msvc-cpp20-and-the-std-cpp20-switch/#c++20-[[no_unique_address]]>
#if _MSC_VER && _MSC_VER < 1929 // VS 2019 v16.9 or before
# error "Too old MSVC version; we don't support this because it leads to ODR violation regarding the existence of [[(msvc::)no_unique_address]]"
#endif
#if _MSC_VER && __INTELLISENSE__ // Memory Layout view shows wrong layout without this workaround
# define BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS [[msvc::no_unique_address, no_unique_address]]
#elif _MSC_VER // normal MSVC
# define BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
#else // other compilers
# define BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS [[no_unique_address]]
#endif
#ifndef BOOST_SPIRIT_X3_LIFETIMEBOUND
# if defined(__clang__)
# define BOOST_SPIRIT_X3_LIFETIMEBOUND [[clang::lifetimebound]]
# elif defined(_MSC_VER)
# define BOOST_SPIRIT_X3_LIFETIMEBOUND [[msvc::lifetimebound]]
# else
# define BOOST_SPIRIT_X3_LIFETIMEBOUND
# endif
#endif
#endif

View File

@@ -1,6 +1,7 @@
/*=============================================================================
Copyright (c) 2009 Hartmut Kaiser
Copyright (c) 2014 Joel de Guzman
Copyright (c) 2009 Hartmut Kaiser
Copyright (c) 2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -54,7 +55,7 @@ namespace boost { namespace spirit { namespace x3
};
template <typename T, typename Encoding, typename BoolPolicies = bool_policies<T>>
struct literal_bool_parser : parser<bool_parser<T, Encoding, BoolPolicies>>
struct literal_bool_parser : parser<literal_bool_parser<T, Encoding, BoolPolicies>>
{
typedef Encoding encoding;
typedef T attribute_type;
@@ -114,7 +115,7 @@ namespace boost { namespace spirit { namespace x3
constexpr false_type false_ = { false };
}
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
namespace standard_wide
{
typedef bool_parser<bool, char_encoding::standard_wide> bool_type;

View File

@@ -1,6 +1,7 @@
/*=============================================================================
Copyright (c) 2009 Hartmut Kaiser
Copyright (c) 2014 Joel de Guzman
Copyright (c) 2009 Hartmut Kaiser
Copyright (c) 2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -11,19 +12,22 @@
#include <boost/spirit/home/x3/string/detail/string_parse.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
namespace boost { namespace spirit { namespace x3
#include <string_view>
#include <iterator>
namespace boost::spirit::x3
{
///////////////////////////////////////////////////////////////////////////
// Default boolean policies
///////////////////////////////////////////////////////////////////////////
template <typename T = bool>
struct bool_policies
{
template <typename Iterator, typename Attribute, typename CaseCompare>
static bool
parse_true(Iterator& first, Iterator const& last, Attribute& attr_, CaseCompare const& case_compare)
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename CaseCompare>
[[nodiscard]] static constexpr bool
parse_true(It& first, Se const& last, Attribute& attr_, CaseCompare const& case_compare)
noexcept(std::is_nothrow_constructible_v<Attribute, T>)
{
if (detail::string_parse("true", first, last, unused, case_compare))
using namespace std::string_view_literals;
if (detail::string_parse("true"sv, first, last, unused, case_compare))
{
traits::move_to(T(true), attr_); // result is true
return true;
@@ -31,11 +35,13 @@ namespace boost { namespace spirit { namespace x3
return false;
}
template <typename Iterator, typename Attribute, typename CaseCompare>
static bool
parse_false(Iterator& first, Iterator const& last, Attribute& attr_, CaseCompare const& case_compare)
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename CaseCompare>
[[nodiscard]] static constexpr bool
parse_false(It& first, Se const& last, Attribute& attr_, CaseCompare const& case_compare)
noexcept(std::is_nothrow_constructible_v<Attribute, T>)
{
if (detail::string_parse("false", first, last, unused, case_compare))
using namespace std::string_view_literals;
if (detail::string_parse("false"sv, first, last, unused, case_compare))
{
traits::move_to(T(false), attr_); // result is false
return true;
@@ -43,6 +49,6 @@ namespace boost { namespace spirit { namespace x3
return false;
}
};
}}}
} // boost::spirit::x3
#endif

View File

@@ -1,6 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
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)
@@ -11,11 +12,11 @@
#include <boost/spirit/home/x3/string/detail/string_parse.hpp>
#include <boost/spirit/home/x3/support/numeric_utils/extract_int.hpp>
namespace boost { namespace spirit { namespace x3
#include <string_view>
namespace boost::spirit::x3
{
///////////////////////////////////////////////////////////////////////////
// Default (unsigned) real number policies
///////////////////////////////////////////////////////////////////////////
// Default (unsigned) real number policies
template <typename T>
struct ureal_policies
{
@@ -72,24 +73,24 @@ namespace boost { namespace spirit { namespace x3
return extract_int<int, 10, 1, -1>::call(first, last, attr_);
}
///////////////////////////////////////////////////////////////////////
// The parse_nan() and parse_inf() functions get called whenever
// a number to parse does not start with a digit (after having
// successfully parsed an optional sign).
// The parse_nan() and parse_inf() functions get called whenever
// a number to parse does not start with a digit (after having
// successfully parsed an optional sign).
//
// The functions should return true if a Nan or Inf has been found. In
// this case the attr should be set to the matched value (NaN or
// Inf). The optional sign will be automatically applied afterwards.
// The functions should return true if a Nan or Inf has been found. In
// this case the attr should be set to the matched value (NaN or
// Inf). The optional sign will be automatically applied afterwards.
//
// The default implementation below recognizes representations of NaN
// and Inf as mandated by the C99 Standard and as proposed for
// inclusion into the C++0x Standard: nan, nan(...), inf and infinity
// (the matching is performed case-insensitively).
///////////////////////////////////////////////////////////////////////
// The default implementation below recognizes representations of NaN
// and Inf as mandated by the C99 Standard and as proposed for
// inclusion into the C++0x Standard: nan, nan(...), inf and infinity
// (the matching is performed case-insensitively).
template <typename Iterator, typename Attribute>
static bool
parse_nan(Iterator& first, Iterator const& last, Attribute& attr_)
{
using namespace std::string_view_literals;
if (first == last)
return false; // end of input reached
@@ -97,7 +98,7 @@ namespace boost { namespace spirit { namespace x3
return false; // not "nan"
// nan[(...)] ?
if (detail::string_parse("nan", "NAN", first, last, unused))
if (detail::string_parse("nan"sv, "NAN"sv, first, last, unused))
{
if (first != last && *first == '(')
{
@@ -121,6 +122,8 @@ namespace boost { namespace spirit { namespace x3
static bool
parse_inf(Iterator& first, Iterator const& last, Attribute& attr_)
{
using namespace std::string_view_literals;
if (first == last)
return false; // end of input reached
@@ -128,10 +131,10 @@ namespace boost { namespace spirit { namespace x3
return false; // not "inf"
// inf or infinity ?
if (detail::string_parse("inf", "INF", first, last, unused))
if (detail::string_parse("inf"sv, "INF"sv, first, last, unused))
{
// skip allowed 'inity' part of infinity
detail::string_parse("inity", "INITY", first, last, unused);
(void)detail::string_parse("inity"sv, "INITY"sv, first, last, unused);
attr_ = std::numeric_limits<T>::infinity();
return true;
}
@@ -139,9 +142,7 @@ namespace boost { namespace spirit { namespace x3
}
};
///////////////////////////////////////////////////////////////////////////
// Default (signed) real number policies
///////////////////////////////////////////////////////////////////////////
// Default (signed) real number policies
template <typename T>
struct real_policies : ureal_policies<T>
{
@@ -164,6 +165,6 @@ namespace boost { namespace spirit { namespace x3
{
static bool const expect_dot = true;
};
}}}
} // boost::spirit::x3
#endif

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,6 +9,7 @@
#define BOOST_SPIRIT_X3_STRING_FEBRUARY_03_2007_0355PM
#include <boost/spirit/home/x3/string/literal_string.hpp>
#include <boost/spirit/home/x3/string/string.hpp>
#include <boost/spirit/home/x3/string/symbols.hpp>
#endif

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,36 +10,22 @@
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
namespace boost { namespace spirit { namespace x3 { namespace detail
#include <string_view>
#include <iterator>
namespace boost::spirit::x3::detail
{
template <typename Char, typename Iterator, typename Attribute, typename CaseCompareFunc>
inline bool string_parse(
Char const* str
, Iterator& first, Iterator const& last, Attribute& attr, CaseCompareFunc const& compare)
template <typename CharT, typename CharTraitsT, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename CaseCompareFunc>
[[nodiscard]] constexpr bool
string_parse(
std::basic_string_view<CharT, CharTraitsT> const str,
It& first, Se const& last,
Attribute& attr, CaseCompareFunc const& compare
) noexcept(std::is_same_v<std::remove_const_t<Attribute>, unused_type>)
{
Iterator i = first;
Char ch = *str;
for (; !!ch; ++i)
{
if (i == last || (compare(ch, *i) != 0))
return false;
ch = *++str;
}
x3::traits::move_to(first, i, attr);
first = i;
return true;
}
template <typename String, typename Iterator, typename Attribute, typename CaseCompareFunc>
inline bool string_parse(
String const& str
, Iterator& first, Iterator const& last, Attribute& attr, CaseCompareFunc const& compare)
{
Iterator i = first;
typename String::const_iterator stri = str.begin();
typename String::const_iterator str_last = str.end();
It i = first;
auto stri = str.begin();
auto str_last = str.end();
for (; stri != str_last; ++stri, ++i)
if (i == last || (compare(*stri, *i) != 0))
@@ -48,30 +35,29 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
return true;
}
template <typename Char, typename Iterator, typename Attribute>
inline bool string_parse(
Char const* uc_i, Char const* lc_i
, Iterator& first, Iterator const& last, Attribute& attr)
template <typename CharT, typename CharTraitsT, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename CaseCompareFunc>
[[nodiscard]] constexpr bool
string_parse(
std::basic_string<CharT, CharTraitsT> const& str,
It& first, Se const& last,
Attribute& attr, CaseCompareFunc const& compare
) noexcept(std::is_same_v<std::remove_const_t<Attribute>, unused_type>)
{
Iterator i = first;
for (; *uc_i && *lc_i; ++uc_i, ++lc_i, ++i)
if (i == last || ((*uc_i != *i) && (*lc_i != *i)))
return false;
x3::traits::move_to(first, i, attr);
first = i;
return true;
return detail::string_parse(std::basic_string_view{str}, first, last, attr, compare);
}
template <typename String, typename Iterator, typename Attribute>
inline bool string_parse(
String const& ucstr, String const& lcstr
, Iterator& first, Iterator const& last, Attribute& attr)
template <typename CharT, typename CharTraitsT, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
[[nodiscard]] constexpr bool
string_parse(
std::basic_string_view<CharT, CharTraitsT> const ucstr,
std::basic_string_view<CharT, CharTraitsT> const lcstr,
It& first, Se const& last, Attribute& attr
) noexcept(std::is_same_v<std::remove_const_t<Attribute>, unused_type>)
{
typename String::const_iterator uc_i = ucstr.begin();
typename String::const_iterator uc_last = ucstr.end();
typename String::const_iterator lc_i = lcstr.begin();
Iterator i = first;
auto uc_i = ucstr.begin();
auto uc_last = ucstr.end();
auto lc_i = lcstr.begin();
It i = first;
for (; uc_i != uc_last; ++uc_i, ++lc_i, ++i)
if (i == last || ((*uc_i != *i) && (*lc_i != *i)))
@@ -80,6 +66,17 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
first = i;
return true;
}
}}}}
template <typename CharT, typename CharTraitsT, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
[[nodiscard]] constexpr bool
string_parse(
std::basic_string<CharT, CharTraitsT> const& ucstr,
std::basic_string<CharT, CharTraitsT> const& lcstr,
It& first, Se const& last, Attribute& attr
) noexcept(std::is_same_v<std::remove_const_t<Attribute>, unused_type>)
{
return detail::string_parse(std::basic_string_view{ucstr}, std::basic_string_view{lcstr}, first, last, attr);
}
} // boost::spirit::x3::detail
#endif

View File

@@ -1,202 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_X3_TST_MARCH_09_2007_0905AM)
#define BOOST_SPIRIT_X3_TST_MARCH_09_2007_0905AM
#include <boost/call_traits.hpp>
#include <boost/assert.hpp>
#include <string>
namespace boost { namespace spirit { namespace x3 { namespace detail
{
// This file contains low level TST routines, not for
// public consumption.
template <typename Char, typename T>
struct tst_node
{
tst_node(Char id)
: id(id), data(0), lt(0), eq(0), gt(0)
{
}
template <typename Alloc>
static void
destruct_node(tst_node* p, Alloc* alloc)
{
if (p)
{
if (p->data)
alloc->delete_data(p->data);
destruct_node(p->lt, alloc);
destruct_node(p->eq, alloc);
destruct_node(p->gt, alloc);
alloc->delete_node(p);
}
}
template <typename Alloc>
static tst_node*
clone_node(tst_node* p, Alloc* alloc)
{
if (p)
{
tst_node* clone = alloc->new_node(p->id);
if (p->data)
clone->data = alloc->new_data(*p->data);
clone->lt = clone_node(p->lt, alloc);
clone->eq = clone_node(p->eq, alloc);
clone->gt = clone_node(p->gt, alloc);
return clone;
}
return 0;
}
template <typename Iterator, typename CaseCompare>
static T*
find(tst_node* start, Iterator& first, Iterator last, CaseCompare comp)
{
if (first == last)
return 0;
Iterator i = first;
Iterator latest = first;
tst_node* p = start;
T* found = 0;
while (p && i != last)
{
int32_t c = comp(*i,p->id);
if (c == 0)
{
if (p->data)
{
found = p->data;
latest = i;
}
p = p->eq;
i++;
}
else if (c < 0)
{
p = p->lt;
}
else
{
p = p->gt;
}
}
if (found)
first = ++latest; // one past the last matching char
return found;
}
template <typename Iterator, typename Alloc>
static T*
add(
tst_node*& start
, Iterator first
, Iterator last
, typename boost::call_traits<T>::param_type val
, Alloc* alloc)
{
if (first == last)
return 0;
tst_node** pp = &start;
for (;;)
{
auto c = *first;
if (*pp == 0)
*pp = alloc->new_node(c);
tst_node* p = *pp;
if (c == p->id)
{
if (++first == last)
{
if (p->data == 0)
p->data = alloc->new_data(val);
return p->data;
}
pp = &p->eq;
}
else if (c < p->id)
{
pp = &p->lt;
}
else
{
pp = &p->gt;
}
}
}
template <typename Iterator, typename Alloc>
static void
remove(tst_node*& p, Iterator first, Iterator last, Alloc* alloc)
{
if (p == 0 || first == last)
return;
auto c = *first;
if (c == p->id)
{
if (++first == last)
{
if (p->data)
{
alloc->delete_data(p->data);
p->data = 0;
}
}
remove(p->eq, first, last, alloc);
}
else if (c < p->id)
{
remove(p->lt, first, last, alloc);
}
else
{
remove(p->gt, first, last, alloc);
}
if (p->data == 0 && p->lt == 0 && p->eq == 0 && p->gt == 0)
{
alloc->delete_node(p);
p = 0;
}
}
template <typename F>
static void
for_each(tst_node* p, std::basic_string<Char> prefix, F f)
{
if (p)
{
for_each(p->lt, prefix, f);
std::basic_string<Char> s = prefix + p->id;
for_each(p->eq, s, f);
if (p->data)
f(s, *p->data);
for_each(p->gt, prefix, f);
}
}
Char id; // the node's identity character
T* data; // optional data
tst_node* lt; // left pointer
tst_node* eq; // middle pointer
tst_node* gt; // right pointer
};
}}}}
#endif

View File

@@ -0,0 +1,175 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_X3_TST_MARCH_09_2007_0905AM)
#define BOOST_SPIRIT_X3_TST_MARCH_09_2007_0905AM
#include <boost/spirit/home/x3/core/config.hpp>
#include <boost/spirit/home/x3/support/allocator.hpp>
#include <boost/assert.hpp>
#include <iterator>
#include <memory>
#include <string_view>
#include <string>
#include <utility>
namespace boost::spirit::x3::detail
{
// This file contains low level TST routines, not for
// public consumption.
template <typename Char, typename T, typename Alloc = std::allocator<T>>
struct tst_node
{
using allocator_type = Alloc;
using node_allocator_type = std::allocator_traits<Alloc>::template rebind_alloc<tst_node>;
constexpr explicit tst_node(Char id, Alloc const& alloc = {}) noexcept
: alloc(alloc)
, node_alloc(this->alloc)
, id(id)
{
}
constexpr tst_node(tst_node const& rhs)
: alloc(std::allocator_traits<Alloc>::select_on_container_copy_construction(rhs.alloc))
, node_alloc(std::allocator_traits<node_allocator_type>::select_on_container_copy_construction(rhs.node_alloc))
, id(rhs.id)
, data(allocator_ops<tst_node>::template copy_construct<&tst_node::alloc, &tst_node::data>(*this, rhs))
, lt(allocator_ops<tst_node>::template copy_construct<&tst_node::node_alloc, &tst_node::lt>(*this, rhs))
, eq(allocator_ops<tst_node>::template copy_construct<&tst_node::node_alloc, &tst_node::eq>(*this, rhs))
, gt(allocator_ops<tst_node>::template copy_construct<&tst_node::node_alloc, &tst_node::gt>(*this, rhs))
{
}
constexpr tst_node(tst_node&& rhs) noexcept
: alloc(std::move(rhs.alloc))
, node_alloc(std::move(rhs.node_alloc))
, id(std::move(rhs.id))
, data(std::exchange(rhs.data, nullptr))
, lt(std::exchange(rhs.lt, nullptr))
, eq(std::exchange(rhs.eq, nullptr))
, gt(std::exchange(rhs.gt, nullptr))
{
}
constexpr ~tst_node() noexcept
{
allocator_ops<tst_node>::template destroy_deallocate<
&tst_node::alloc, &tst_node::data
>(*this);
allocator_ops<tst_node>::template destroy_deallocate<
&tst_node::node_alloc,
&tst_node::lt, &tst_node::eq, &tst_node::gt
>(*this);
}
constexpr tst_node& operator=(tst_node const& rhs)
{
if (std::addressof(rhs) == this) return *this;
id = rhs.id;
allocator_ops<tst_node>::template copy_assign<
&tst_node::alloc, &tst_node::data
>(*this, rhs);
allocator_ops<tst_node>::template copy_assign<
&tst_node::node_alloc,
&tst_node::lt, &tst_node::eq, &tst_node::gt
>(*this, rhs);
}
constexpr tst_node& operator=(tst_node&& rhs)
noexcept(allocator_ops<tst_node>::template move_assign_noexcept<allocator_type, node_allocator_type>)
{
if (std::addressof(rhs) == this) return *this;
id = std::move(rhs.id);
allocator_ops<tst_node>::template move_assign<
&tst_node::alloc, &tst_node::data
>(*this, std::move(rhs));
allocator_ops<tst_node>::template move_assign<
&tst_node::node_alloc,
&tst_node::lt, &tst_node::eq, &tst_node::gt
>(*this, std::move(rhs));
}
template <std::forward_iterator Iterator, typename CaseCompare>
[[nodiscard]] static constexpr T*
find(tst_node* start, Iterator& first, Iterator last, CaseCompare const& comp) noexcept
{
if (first == last) return nullptr;
Iterator i = first;
Iterator latest = first;
tst_node* p = start;
T* found = nullptr;
while (p && i != last)
{
auto c = comp(*i,p->id);
if (c == 0) {
if (p->data)
{
found = p->data;
latest = i;
}
p = p->eq;
++i;
}
else if (c < 0)
{
p = p->lt;
}
else
{
p = p->gt;
}
}
if (found)
{
first = ++latest; // one past the last matching char
}
return found;
}
template <typename F>
static void
for_each(tst_node* const p, std::basic_string_view<Char> const prefix, F&& f)
{
if (!p) return;
tst_node::for_each(p->lt, prefix, f);
std::basic_string<Char> s = std::basic_string<Char>(prefix) + p->id;
tst_node::for_each(p->eq, s, f);
if (p->data)
{
f(s, *p->data);
}
tst_node::for_each(p->gt, prefix, f);
}
friend struct allocator_ops<tst_node>;
BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS Alloc alloc;
BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS node_allocator_type node_alloc;
Char id; // the node's identity character
T* data = nullptr; // optional data
tst_node* lt = nullptr; // left pointer
tst_node* eq = nullptr; // middle pointer
tst_node* gt = nullptr; // right pointer
};
}
#endif

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -7,276 +8,66 @@
#if !defined(BOOST_SPIRIT_X3_LITERAL_STRING_APR_18_2006_1125PM)
#define BOOST_SPIRIT_X3_LITERAL_STRING_APR_18_2006_1125PM
#include <boost/spirit/home/x3/string/detail/string_parse.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/skip_over.hpp>
#include <boost/spirit/home/x3/string/detail/string_parse.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/spirit/home/x3/support/no_case.hpp>
#include <boost/spirit/home/x3/support/utility/utf8.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/spirit/home/support/char_encoding/standard.hpp>
#include <boost/spirit/home/support/char_encoding/standard_wide.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
namespace boost { namespace spirit { namespace x3
namespace boost::spirit::x3
{
template <typename String, typename Encoding,
typename Attribute = std::basic_string<typename Encoding::char_type>>
template <typename String, typename Encoding, typename Attribute = std::basic_string<typename Encoding::char_type>>
struct literal_string : parser<literal_string<String, Encoding, Attribute>>
{
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef Attribute attribute_type;
static bool const has_attribute =
!is_same<unused_type, attribute_type>::value;
static bool const handles_container = has_attribute;
static_assert(
!std::is_pointer_v<std::decay_t<String>>,
"`literal_string` for raw character pointer/array is banned; it has an undetectable risk of holding a dangling pointer."
);
static_assert(std::is_convertible_v<String, std::basic_string_view<typename String::value_type>>);
constexpr literal_string(typename add_reference< typename add_const<String>::type >::type str)
: str(str)
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
static constexpr bool handles_container = has_attribute;
template<class... Args>
requires std::is_constructible_v<String, Args...>
constexpr literal_string(Args&&... args)
noexcept(std::is_nothrow_constructible_v<String, Args...>)
: str(std::forward<Args>(args)...)
{}
template <typename Iterator, typename Context, typename Attribute_>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute_& attr) const
[[nodiscard]] constexpr bool parse(
Iterator& first, Iterator const& last,
Context const& context, unused_type, Attribute_& attr
) const
{
x3::skip_over(first, last, context);
return detail::string_parse(str, first, last, attr, get_case_compare<encoding>(context));
return detail::string_parse(str, first, last, attr, x3::get_case_compare<encoding>(context));
}
String str;
};
namespace standard
{
constexpr literal_string<char const*, char_encoding::standard>
string(char const* s)
{
return { s };
}
inline literal_string<std::basic_string<char>, char_encoding::standard>
string(std::basic_string<char> const& s)
{
return { s };
}
inline constexpr literal_string<char const*, char_encoding::standard, unused_type>
lit(char const* s)
{
return { s };
}
template <typename Char>
literal_string<std::basic_string<Char>, char_encoding::standard, unused_type>
lit(std::basic_string<Char> const& s)
{
return { s };
}
}
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
namespace standard_wide
{
constexpr literal_string<wchar_t const*, char_encoding::standard_wide>
string(wchar_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<wchar_t>, char_encoding::standard_wide>
string(std::basic_string<wchar_t> const& s)
{
return { s };
}
constexpr literal_string<wchar_t const*, char_encoding::standard_wide, unused_type>
lit(wchar_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<wchar_t>, char_encoding::standard_wide, unused_type>
lit(std::basic_string<wchar_t> const& s)
{
return { s };
}
}
#endif
#if defined(BOOST_SPIRIT_X3_UNICODE)
namespace unicode
{
constexpr literal_string<char32_t const*, char_encoding::unicode>
string(char32_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<char32_t>, char_encoding::unicode>
string(std::basic_string<char32_t> const& s)
{
return { s };
}
constexpr literal_string<char32_t const*, char_encoding::unicode, unused_type>
lit(char32_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<char32_t>, char_encoding::unicode, unused_type>
lit(std::basic_string<char32_t> const& s)
{
return { s };
}
}
#endif
namespace ascii
{
constexpr literal_string<wchar_t const*, char_encoding::ascii>
string(wchar_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<wchar_t>, char_encoding::ascii>
string(std::basic_string<wchar_t> const& s)
{
return { s };
}
constexpr literal_string<char const*, char_encoding::ascii, unused_type>
lit(char const* s)
{
return { s };
}
template <typename Char>
literal_string<std::basic_string<Char>, char_encoding::ascii, unused_type>
lit(std::basic_string<Char> const& s)
{
return { s };
}
}
namespace iso8859_1
{
constexpr literal_string<wchar_t const*, char_encoding::iso8859_1>
string(wchar_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<wchar_t>, char_encoding::iso8859_1>
string(std::basic_string<wchar_t> const& s)
{
return { s };
}
constexpr literal_string<char const*, char_encoding::iso8859_1, unused_type>
lit(char const* s)
{
return { s };
}
template <typename Char>
literal_string<std::basic_string<Char>, char_encoding::iso8859_1, unused_type>
lit(std::basic_string<Char> const& s)
{
return { s };
}
}
using standard::string;
using standard::lit;
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
using standard_wide::string;
using standard_wide::lit;
#endif
namespace extension
{
template <int N>
struct as_parser<char[N]>
{
typedef literal_string<
char const*, char_encoding::standard, unused_type>
type;
typedef type value_type;
static constexpr type call(char const* s)
{
return type(s);
}
};
template <int N>
struct as_parser<char const[N]> : as_parser<char[N]> {};
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
template <int N>
struct as_parser<wchar_t[N]>
{
typedef literal_string<
wchar_t const*, char_encoding::standard_wide, unused_type>
type;
typedef type value_type;
static constexpr type call(wchar_t const* s)
{
return type(s);
}
};
template <int N>
struct as_parser<wchar_t const[N]> : as_parser<wchar_t[N]> {};
#endif
template <>
struct as_parser<char const*>
{
typedef literal_string<
char const*, char_encoding::standard, unused_type>
type;
typedef type value_type;
static constexpr type call(char const* s)
{
return type(s);
}
};
template <typename Char>
struct as_parser< std::basic_string<Char> >
{
typedef literal_string<
Char const*, char_encoding::standard, unused_type>
type;
typedef type value_type;
static type call(std::basic_string<Char> const& s)
{
return type(s.c_str());
}
};
}
template <typename String, typename Encoding, typename Attribute>
struct get_info<literal_string<String, Encoding, Attribute>>
{
typedef std::string result_type;
std::string operator()(literal_string<String, Encoding, Attribute> const& p) const
using result_type = std::string;
[[nodiscard]] constexpr std::string operator()(literal_string<String, Encoding, Attribute> const& p) const
{
return '"' + to_utf8(p.str) + '"';
return '"' + x3::to_utf8(p.str) + '"';
}
};
}}}
} // boost::spirit::x3
#endif

View File

@@ -0,0 +1,298 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_STRING_STRING_HPP
#define BOOST_SPIRIT_X3_STRING_STRING_HPP
#include <boost/spirit/home/x3/string/literal_string.hpp>
#include <boost/spirit/home/x3/char/literal_char.hpp> // required for "c" -> 'c' optimization
#include <boost/spirit/home/x3/support/traits/string_traits.hpp>
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/spirit/home/x3/char_encoding/standard.hpp>
#include <boost/spirit/home/x3/char_encoding/standard_wide.hpp>
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#endif
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
{
namespace standard
{
inline namespace helpers
{
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::standard>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::standard>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::standard, std::basic_string<char>>
string(char ch) noexcept
{
return { ch };
}
// Optimize `literal_string{"c"}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::standard, std::basic_string<char>>
string(traits::X3VagueArrayOf2Chars<char> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::standard, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::standard, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
} // helpers
template <typename T>
requires traits::CharIncompatibleWith<T, char> || traits::StringLikeIncompatibleWith<T, char>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
} // standard
using standard::helpers::string;
using standard::helpers::lit;
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
namespace standard_wide
{
inline namespace helpers
{
template <traits::CppStringLike<wchar_t> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::standard_wide>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::standard_wide>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::standard_wide, std::basic_string<wchar_t>>
string(wchar_t ch) noexcept
{
return { ch };
}
// Optimize `literal_string{L"c"}` into `literal_char{L'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::standard_wide, std::basic_string<wchar_t>>
string(traits::X3VagueArrayOf2Chars<wchar_t> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<wchar_t> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::standard_wide, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::standard_wide, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
} // helpers
template <typename T>
requires traits::CharIncompatibleWith<T, wchar_t> || traits::StringLikeIncompatibleWith<T, wchar_t>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
} // standard_wide
using standard_wide::helpers::string;
using standard_wide::helpers::lit;
#endif
#ifdef BOOST_SPIRIT_X3_UNICODE
namespace unicode
{
inline namespace helpers
{
// TODO: add `char8_t` and `char16_t` overloads
template <traits::CppStringLike<char32_t> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::unicode>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::unicode>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::unicode, std::basic_string<char32_t>>
string(char32_t ch) noexcept
{
return { ch };
}
// Optimize `literal_string{U"c"}` into `literal_char{U'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::unicode, std::basic_string<char32_t>>
string(traits::X3VagueArrayOf2Chars<char32_t> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<char32_t> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::unicode, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::unicode, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
} // helpers
template <typename T>
requires traits::CharIncompatibleWith<T, char32_t> || traits::StringLikeIncompatibleWith<T, char32_t>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
}
using unicode::helpers::string;
using unicode::helpers::lit;
#endif
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] ascii
{
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::ascii>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::ascii>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::ascii, std::basic_string<char>>
string(char ch) noexcept
{
return { ch };
}
// Optimize `literal_string{"c"}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::ascii, std::basic_string<char>>
string(traits::X3VagueArrayOf2Chars<char> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::ascii, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::ascii, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
template <typename T>
requires traits::CharIncompatibleWith<T, char> || traits::StringLikeIncompatibleWith<T, char>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
} // ascii
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] iso8859_1
{
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::iso8859_1>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::iso8859_1>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::iso8859_1, std::basic_string<char>>
string(char ch) noexcept
{
return { ch };
}
// Optimize `literal_string{"c"}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::iso8859_1, std::basic_string<char>>
string(traits::X3VagueArrayOf2Chars<char> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::iso8859_1, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::iso8859_1, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
template <typename T>
requires traits::CharIncompatibleWith<T, char> || traits::StringLikeIncompatibleWith<T, char>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
} // iso8859_1
namespace extension
{
template <traits::CharLike CharT, std::size_t N>
struct as_parser<CharT[N]>
{
using type = literal_string<std::basic_string_view<CharT>, traits::char_encoding_for<CharT>, unused_type>;
using value_type = type;
[[nodiscard]] static constexpr type call(CharT const* s)
{
return type(s);
}
};
template <traits::CharLike CharT, std::size_t N>
struct as_parser<CharT const[N]> : as_parser<CharT[N]> {};
template <traits::CharLike CharT>
struct as_parser<CharT const*>
{
using type = literal_string<std::basic_string_view<CharT>, traits::char_encoding_for<CharT>, unused_type>;
using value_type = type;
[[nodiscard]] static constexpr type call(CharT const* s)
{
return type(std::basic_string_view<CharT>{s});
}
};
template <traits::CharLike CharT>
struct as_parser<std::basic_string<CharT>>
{
using type = literal_string<std::basic_string<CharT>, traits::char_encoding_for<CharT>, unused_type>;
using value_type = type;
template <typename T>
[[nodiscard]] static constexpr type call(T&& str)
noexcept(std::is_nothrow_constructible_v<type, T>)
{
return type(std::forward<T>(str));
}
};
template <traits::CharLike CharT>
struct as_parser<std::basic_string_view<CharT>>
{
using type = literal_string<std::basic_string_view<CharT>, traits::char_encoding_for<CharT>, unused_type>;
using value_type = type;
template <typename T>
[[nodiscard]] static constexpr type call(T&& str)
noexcept(std::is_nothrow_constructible_v<type, T>)
{
return type(std::forward<T>(str));
}
};
} // extension
} // boost::spirit::x3
#endif

View File

@@ -1,6 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2013 Carl Barron
Copyright (c) 2025 Nana Sakisaka
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)
@@ -16,99 +17,154 @@
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/no_case.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/spirit/home/support/char_encoding/iso8859_1.hpp>
#include <boost/spirit/home/support/char_encoding/standard.hpp>
#include <boost/spirit/home/support/char_encoding/standard_wide.hpp>
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/spirit/home/x3/char_encoding/ascii.hpp>
#include <boost/spirit/home/x3/char_encoding/iso8859_1.hpp>
#include <boost/spirit/home/x3/char_encoding/standard.hpp>
#include <boost/spirit/home/x3/char_encoding/standard_wide.hpp>
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#endif
#include <string>
#include <string_view>
#include <ranges>
#include <iterator>
#include <initializer_list>
#include <iterator> // std::begin
#include <memory> // std::shared_ptr
#include <type_traits>
#include <utility>
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4355) // 'this' : used in base member initializer list warning
#endif
namespace boost { namespace spirit { namespace x3
#define BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING(old_api) \
"Use `shared_" old_api "` instead. `" old_api "` has had a " \
"*implicit* trait where the underlying storage is shared via " \
"`std::shared_ptr`. This disallows `constexpr` usage in generic " \
"scenarios where the sharing is not actually needed at all. Even " \
"for non-`constexpr` usage, the old name `" old_api "` does not " \
"represent this trait, so the usage of the old API is strongly " \
"discouraged."
namespace boost::spirit::x3
{
template <
typename Encoding
, typename T = unused_type
, typename Lookup = tst<typename Encoding::char_type, T> >
struct symbols_parser : parser<symbols_parser<Encoding, T, Lookup>>
namespace detail
{
template <typename Derived, bool IsShared, typename Encoding, typename T, typename Lookup>
struct symbols_parser_impl : parser<Derived>
{
typedef typename Encoding::char_type char_type; // the character type
typedef Encoding encoding;
typedef T value_type; // the value associated with each entry
typedef value_type attribute_type;
using char_type = typename Encoding::char_type; // the character type
using encoding = Encoding;
using value_type = T; // the value associated with each entry
using attribute_type = value_type;
static bool const has_attribute =
!std::is_same<unused_type, attribute_type>::value;
static bool const handles_container =
traits::is_container<attribute_type>::value;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
static constexpr bool handles_container = traits::is_container_v<attribute_type>;
symbols_parser(std::string const& name = "symbols")
: add{*this}
, remove{*this}
, lookup(std::make_shared<Lookup>())
, name_(name)
constexpr symbols_parser_impl(std::string_view name = "symbols")
requires(IsShared)
: add{*this}
, remove{*this}
, lookup(std::make_shared<Lookup>())
, name_(name)
{
}
symbols_parser(symbols_parser const& syms)
: add{*this}
, remove{*this}
, lookup(syms.lookup)
, name_(syms.name_)
constexpr symbols_parser_impl(std::string_view name = "symbols")
requires(!IsShared)
: add{*this}
, remove{*this}
, lookup(std::make_unique<Lookup>())
, name_(name)
{
}
template <typename Symbols>
symbols_parser(Symbols const& syms, std::string const& name = "symbols")
: symbols_parser(name)
constexpr symbols_parser_impl(symbols_parser_impl const& syms)
requires(IsShared)
: add{*this}
, remove{*this}
, lookup(syms.lookup)
, name_(syms.name_)
{
for (auto& sym : syms)
add(sym);
}
template <typename Symbols, typename Data>
symbols_parser(Symbols const& syms, Data const& data
, std::string const& name = "symbols")
: symbols_parser(name)
constexpr symbols_parser_impl(symbols_parser_impl const& syms)
requires(!IsShared)
: add{*this}
, remove{*this}
, lookup(std::make_unique<Lookup>(*syms.lookup))
, name_(syms.name_)
{
using std::begin;
auto di = begin(data);
for (auto& sym : syms)
add(sym, *di++);
}
symbols_parser(std::initializer_list<std::pair<char_type const*, T>> syms
, std::string const & name="symbols")
: symbols_parser(name)
constexpr symbols_parser_impl(symbols_parser_impl&&) noexcept = default;
template <std::ranges::forward_range Symbols>
requires std::convertible_to<std::ranges::range_value_t<Symbols>, std::basic_string_view<char_type>>
constexpr symbols_parser_impl(Symbols const& syms, std::string const& name = "symbols")
: symbols_parser_impl(name)
{
for (auto& sym : syms)
for (auto const& sym : syms)
{
this->add(sym);
}
}
template <std::ranges::forward_range Symbols, std::ranges::forward_range Data>
requires
std::convertible_to<std::ranges::range_value_t<Symbols>, std::basic_string_view<char_type>> &&
std::convertible_to<std::ranges::range_value_t<Data>, T>
constexpr symbols_parser_impl(
Symbols const& syms, Data const& data, std::string const& name = "symbols"
)
: symbols_parser_impl(name)
{
auto di = std::ranges::begin(data);
for (auto const& sym : syms)
{
this->add(sym, *di++);
}
}
constexpr symbols_parser_impl(
std::initializer_list<std::pair<char_type const*, T>> syms,
std::string const & name="symbols"
)
: symbols_parser_impl(name)
{
for (auto const& sym : syms)
{
add(sym.first, sym.second);
}
}
symbols_parser(std::initializer_list<char_type const*> syms
, std::string const &name="symbols")
: symbols_parser(name)
constexpr symbols_parser_impl(
std::initializer_list<char_type const*> syms,
std::string const &name="symbols"
)
: symbols_parser_impl(name)
{
for (auto str : syms)
for (auto const& str : syms)
{
add(str);
}
}
symbols_parser&
operator=(symbols_parser const& rhs)
constexpr symbols_parser_impl& operator=(symbols_parser_impl const& rhs)
{
name_ = rhs.name_;
lookup = rhs.lookup;
return *this;
}
void clear()
constexpr symbols_parser_impl& operator=(symbols_parser_impl&&) noexcept = default;
constexpr void clear() noexcept
{
lookup->clear();
}
@@ -116,93 +172,75 @@ namespace boost { namespace spirit { namespace x3
struct adder;
struct remover;
template <typename Str>
adder const&
operator=(Str const& str)
constexpr adder const&
operator=(std::basic_string_view<char_type> const s)
{
lookup->clear();
return add(str);
return this->add(s);
}
template <typename Str>
friend adder const&
operator+=(symbols_parser& sym, Str const& str)
friend constexpr adder const&
operator+=(symbols_parser_impl& sym, std::basic_string_view<char_type> const s)
{
return sym.add(str);
return sym.add(s);
}
template <typename Str>
friend remover const&
operator-=(symbols_parser& sym, Str const& str)
friend constexpr remover const&
operator-=(symbols_parser_impl& sym, std::basic_string_view<char_type> const s)
{
return sym.remove(str);
return sym.remove(s);
}
template <typename F>
void for_each(F f) const
constexpr void for_each(F&& f) const
{
lookup->for_each(f);
lookup->for_each(std::forward<F>(f));
}
template <typename Str>
value_type& at(Str const& str)
template <typename F>
constexpr void for_each(F&& f)
{
return *lookup->add(traits::get_string_begin<char_type>(str)
, traits::get_string_end<char_type>(str), T());
lookup->for_each(std::forward<F>(f));
}
template <typename Iterator>
value_type* prefix_find(Iterator& first, Iterator const& last)
[[nodiscard]] constexpr value_type& at(std::basic_string_view<char_type> const s)
{
return *lookup->add(s.begin(), s.end(), T{});
}
template <std::forward_iterator Iterator>
[[nodiscard]] constexpr value_type* prefix_find(Iterator& first, Iterator const& last) noexcept
{
return lookup->find(first, last, case_compare<Encoding>());
}
template <typename Iterator>
value_type const* prefix_find(Iterator& first, Iterator const& last) const
template <std::forward_iterator Iterator>
[[nodiscard]] constexpr value_type const* prefix_find(Iterator& first, Iterator const& last) const noexcept
{
return lookup->find(first, last, case_compare<Encoding>());
}
template <typename Str>
value_type* find(Str const& str)
[[nodiscard]] constexpr value_type* find(std::basic_string_view<char_type> const s) noexcept
{
return find_impl(traits::get_string_begin<char_type>(str)
, traits::get_string_end<char_type>(str));
return this->find_impl(s.begin(), s.end());
}
template <typename Str>
value_type const* find(Str const& str) const
[[nodiscard]] constexpr value_type const* find(std::basic_string_view<char_type> const s) const noexcept
{
return find_impl(traits::get_string_begin<char_type>(str)
, traits::get_string_end<char_type>(str));
return this->find_impl(s.begin(), s.end());
}
private:
template <typename Iterator>
value_type* find_impl(Iterator begin, Iterator end)
{
value_type* r = lookup->find(begin, end, case_compare<Encoding>());
return begin == end ? r : 0;
}
template <typename Iterator>
value_type const* find_impl(Iterator begin, Iterator end) const
{
value_type const* r = lookup->find(begin, end, case_compare<Encoding>());
return begin == end ? r : 0;
}
public:
template <typename Iterator, typename Context, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute& attr) const
template <std::forward_iterator Iterator, typename Context, typename Attribute>
[[nodiscard]] constexpr bool parse(
Iterator& first, Iterator const& last, Context const& context, unused_type, Attribute& attr
) const noexcept(
noexcept(x3::skip_over(first, last, context)) &&
noexcept(x3::traits::move_to(std::declval<value_type const&>(), attr))
)
{
x3::skip_over(first, last, context);
if (value_type const* val_ptr
= lookup->find(first, last, get_case_compare<Encoding>(context)))
if (value_type const* val_ptr = lookup->find(first, last, x3::get_case_compare<Encoding>(context)))
{
x3::traits::move_to(*val_ptr, attr);
return true;
@@ -210,124 +248,214 @@ namespace boost { namespace spirit { namespace x3
return false;
}
void name(std::string const &str)
constexpr void name(std::string const &str)
{
name_ = str;
}
std::string const &name() const
[[nodiscard]] constexpr std::string const& name() const noexcept
{
return name_;
}
struct adder
struct [[maybe_unused]] adder
{
template <typename Iterator>
adder const&
template <std::forward_iterator Iterator>
[[maybe_unused]] constexpr adder const&
operator()(Iterator first, Iterator last, T const& val) const
{
sym.lookup->add(first, last, val);
return *this;
}
template <typename Str>
adder const&
operator()(Str const& s, T const& val = T()) const
[[maybe_unused]] constexpr adder const&
operator()(std::basic_string_view<char_type> const s, T const& val = T{}) const
{
sym.lookup->add(traits::get_string_begin<char_type>(s)
, traits::get_string_end<char_type>(s), val);
sym.lookup->add(s.begin(), s.end(), val);
return *this;
}
template <typename Str>
adder const&
operator,(Str const& s) const
[[maybe_unused, deprecated("Don't rely on overloaded comma operator. It's the leftover from the black magic in the 2000s.")]]
constexpr adder const&
operator,(std::basic_string_view<char_type> const s) const
{
sym.lookup->add(traits::get_string_begin<char_type>(s)
, traits::get_string_end<char_type>(s), T());
sym.lookup->add(s.begin(), s.end(), T{});
return *this;
}
symbols_parser& sym;
symbols_parser_impl& sym;
};
struct remover
struct [[maybe_unused]] remover
{
template <typename Iterator>
remover const&
template <std::forward_iterator Iterator>
[[maybe_unused]] constexpr remover const&
operator()(Iterator const& first, Iterator const& last) const
{
sym.lookup->remove(first, last);
return *this;
}
template <typename Str>
remover const&
operator()(Str const& s) const
[[maybe_unused]] constexpr remover const&
operator()(std::basic_string_view<char_type> const s) const
{
sym.lookup->remove(traits::get_string_begin<char_type>(s)
, traits::get_string_end<char_type>(s));
sym.lookup->remove(s.begin(), s.end());
return *this;
}
template <typename Str>
remover const&
operator,(Str const& s) const
[[maybe_unused, deprecated("Don't rely on overloaded comma operator. It's the leftover from the black magic in the 2000s.")]]
constexpr remover const&
operator,(std::basic_string_view<char_type> const s) const
{
sym.lookup->remove(traits::get_string_begin<char_type>(s)
, traits::get_string_end<char_type>(s));
sym.lookup->remove(s.begin(), s.end());
return *this;
}
symbols_parser& sym;
symbols_parser_impl& sym;
};
adder add;
remover remove;
std::shared_ptr<Lookup> lookup;
[[maybe_unused]] adder add;
[[maybe_unused]] remover remove;
private:
template <std::forward_iterator Iterator>
[[nodiscard]] constexpr value_type* find_impl(Iterator begin, Iterator end) noexcept
{
value_type* r = lookup->find(begin, end, case_compare<Encoding>());
return begin == end ? r : 0;
}
template <std::forward_iterator Iterator>
[[nodiscard]] constexpr value_type const* find_impl(Iterator begin, Iterator end) const noexcept
{
value_type const* r = lookup->find(begin, end, case_compare<Encoding>());
return begin == end ? r : 0;
}
std::conditional_t<IsShared, std::shared_ptr<Lookup>, std::unique_ptr<Lookup>> lookup;
std::string name_;
};
} // detail
template <typename Encoding, typename T = unused_type, typename Lookup = tst<typename Encoding::char_type, T>>
struct shared_symbols_parser
: detail::symbols_parser_impl<shared_symbols_parser<Encoding, T, Lookup>, true, Encoding, T, Lookup>
{
using base_type = detail::symbols_parser_impl<shared_symbols_parser<Encoding, T, Lookup>, true, Encoding, T, Lookup>;
using base_type::base_type;
using base_type::operator=;
};
template <typename Encoding, typename T = unused_type, typename Lookup = tst<typename Encoding::char_type, T>>
struct [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols_parser"))]]
symbols_parser : shared_symbols_parser<Encoding, T, Lookup>
{
using base_type = shared_symbols_parser<Encoding, T, Lookup>;
using base_type::base_type;
using base_type::operator=;
};
template <typename Encoding, typename T = unused_type, typename Lookup = tst<typename Encoding::char_type, T>>
struct unique_symbols_parser
: detail::symbols_parser_impl<unique_symbols_parser<Encoding, T, Lookup>, false, Encoding, T, Lookup>
{
using base_type = detail::symbols_parser_impl<unique_symbols_parser<Encoding, T, Lookup>, false, Encoding, T, Lookup>;
using base_type::base_type;
using base_type::operator=;
};
template <typename Encoding, typename T, typename Lookup>
struct get_info<symbols_parser<Encoding, T, Lookup>>
struct get_info<shared_symbols_parser<Encoding, T, Lookup>>
{
typedef std::string result_type;
result_type operator()(symbols_parser< Encoding, T
, Lookup
> const& symbols) const
{
return symbols.name();
}
using result_type = std::string const&;
[[nodiscard]] constexpr result_type operator()(shared_symbols_parser<Encoding, T, Lookup> const& symbols) const noexcept
{
return symbols.name();
}
};
template <typename Encoding, typename T, typename Lookup>
struct get_info<unique_symbols_parser<Encoding, T, Lookup>>
{
using result_type = std::string const&;
[[nodiscard]] constexpr result_type operator()(unique_symbols_parser<Encoding, T, Lookup> const& symbols) const noexcept
{
return symbols.name();
}
};
namespace standard
{
template <typename T = unused_type>
using symbols = symbols_parser<char_encoding::standard, T>;
}
using symbols [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols"))]]
= x3::shared_symbols_parser<char_encoding::standard, T>;
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::standard, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::standard, T>;
} // standard
using standard::symbols;
using standard::shared_symbols;
using standard::unique_symbols;
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
namespace standard_wide
{
template <typename T = unused_type>
using symbols = symbols_parser<char_encoding::standard_wide, T>;
}
using symbols [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols"))]]
= x3::shared_symbols_parser<char_encoding::standard_wide, T>;
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::standard_wide, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::standard_wide, T>;
} // standard_wide
#endif
namespace ascii
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] ascii
{
template <typename T = unused_type>
using symbols = symbols_parser<char_encoding::ascii, T>;
}
using symbols [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols"))]]
= x3::shared_symbols_parser<char_encoding::ascii, T>;
namespace iso8859_1
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::ascii, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::ascii, T>;
} // ascii
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] iso8859_1
{
template <typename T = unused_type>
using symbols = symbols_parser<char_encoding::iso8859_1, T>;
}
using symbols [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols"))]]
= x3::shared_symbols_parser<char_encoding::iso8859_1, T>;
}}}
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::iso8859_1, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::iso8859_1, T>;
} // iso8859_1
#ifdef BOOST_SPIRIT_X3_UNICODE
namespace unicode {
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::unicode, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::unicode, T>;
} // unicode
#endif
} // boost::spirit::x3
#undef BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING
#if defined(BOOST_MSVC)
# pragma warning(pop)

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -7,129 +8,208 @@
#if !defined(BOOST_SPIRIT_X3_TST_JUNE_03_2007_1031AM)
#define BOOST_SPIRIT_X3_TST_JUNE_03_2007_1031AM
#include <boost/spirit/home/x3/string/detail/tst.hpp>
#include <boost/spirit/home/x3/core/config.hpp>
#include <boost/spirit/home/x3/string/detail/tst_node.hpp>
#include <boost/spirit/home/x3/support/allocator.hpp>
#include <boost/assert.hpp>
#include <iterator>
#include <memory>
#include <string>
#include <type_traits>
namespace boost { namespace spirit { namespace x3
namespace boost::spirit::x3
{
struct tst_pass_through
{
template <typename Char>
Char operator()(Char ch) const
[[nodiscard]] constexpr Char operator()(Char ch) const noexcept
{
return ch;
}
};
template <typename Char, typename T>
template <typename Char, typename T, typename Alloc = std::allocator<T>>
struct tst
{
typedef Char char_type; // the character type
typedef T value_type; // the value associated with each entry
typedef detail::tst_node<Char, T> node;
using char_type = Char; // the character type
using value_type = T; // the value associated with each entry
using allocator_type = Alloc;
using node = detail::tst_node<Char, T>;
using node_allocator_type = std::allocator_traits<Alloc>::template rebind_alloc<node>;
tst()
: root(0)
constexpr tst() noexcept(std::is_nothrow_default_constructible_v<Alloc>) = default;
constexpr explicit tst(Alloc const& alloc) noexcept
: alloc_(alloc)
, node_alloc_(alloc_)
{}
constexpr ~tst() noexcept
{
detail::allocator_ops<tst>::template destroy_deallocate<&tst::node_alloc_, &tst::root_>(*this);
}
constexpr tst(tst const& other)
: alloc_(std::allocator_traits<Alloc>::select_on_container_copy_construction(other.alloc_))
, node_alloc_(std::allocator_traits<node_allocator_type>::select_on_container_copy_construction(other.node_alloc_))
, root_(detail::allocator_ops<tst>::template copy_construct<&tst::node_alloc_, &tst::root_>(*this, other))
{
}
~tst()
constexpr tst(tst&& other) noexcept
: alloc_(std::move(other.alloc_))
, node_alloc_(std::move(other.node_alloc_))
, root_(std::exchange(other.root_, nullptr))
{
clear();
}
tst(tst const& rhs)
: root(0)
constexpr tst& operator=(tst const& other)
{
copy(rhs);
}
tst& operator=(tst const& rhs)
{
return assign(rhs);
}
template <typename Iterator, typename CaseCompare>
T* find(Iterator& first, Iterator last, CaseCompare caseCompare) const
{
return node::find(root, first, last, caseCompare);
}
/*template <typename Iterator>
T* find(Iterator& first, Iterator last) const
{
return find(first, last, case_compare<tst_pass_through());
}*/
template <typename Iterator>
T* add(
Iterator first
, Iterator last
, typename boost::call_traits<T>::param_type val)
{
return node::add(root, first, last, val, this);
}
template <typename Iterator>
void remove(Iterator first, Iterator last)
{
node::remove(root, first, last, this);
}
void clear()
{
node::destruct_node(root, this);
root = 0;
}
template <typename F>
void for_each(F f) const
{
node::for_each(root, std::basic_string<Char>(), f);
}
private:
friend struct detail::tst_node<Char, T>;
void copy(tst const& rhs)
{
root = node::clone_node(rhs.root, this);
}
tst& assign(tst const& rhs)
{
if (this != &rhs)
{
clear();
copy(rhs);
}
if (this == std::addressof(other)) return *this;
detail::allocator_ops<tst>::template copy_assign<&tst::node_alloc_, &tst::root_>(*this, other);
detail::allocator_ops<tst>::template copy_assign<&tst::alloc_>(*this, other);
return *this;
}
node* root;
node* new_node(Char id)
constexpr tst& operator=(tst&& other)
noexcept(detail::allocator_ops<tst>::template move_assign_noexcept<allocator_type, node_allocator_type>)
{
return new node(id);
if (this == std::addressof(other)) return *this;
detail::allocator_ops<tst>::template move_assign<&tst::node_alloc_, &tst::root_>(*this, std::move(other));
detail::allocator_ops<tst>::template move_assign<&tst::alloc_>(*this, std::move(other));
return *this;
}
T* new_data(typename boost::call_traits<T>::param_type val)
template <std::forward_iterator Iterator, typename CaseCompare>
[[nodiscard]] constexpr T* find(Iterator& first, Iterator last, CaseCompare caseCompare) const noexcept
{
return new T(val);
return node::find(root_, first, last, caseCompare);
}
void delete_node(node* p)
template <std::forward_iterator Iterator, typename Val>
constexpr T* add(Iterator first, Iterator last, Val&& val)
{
delete p;
if (first == last) return nullptr;
if (!root_)
{
root_ = std::allocator_traits<node_allocator_type>::allocate(node_alloc_, 1);
std::allocator_traits<node_allocator_type>::construct(node_alloc_, root_, *first, alloc_);
}
return this->add(root_, first, last, std::forward<Val>(val));
}
void delete_data(T* p)
template <std::forward_iterator Iterator>
constexpr void remove(Iterator first, Iterator last) noexcept
{
delete p;
this->remove(root_, first, last);
}
constexpr void clear() noexcept
{
if (!root_) return;
std::allocator_traits<node_allocator_type>::destroy(node_alloc_, root_);
std::allocator_traits<node_allocator_type>::deallocate(node_alloc_, root_, 1);
root_ = nullptr;
}
template <typename F>
constexpr void for_each(F&& f) const
{
node::for_each(root_, {}, std::forward<F>(f));
}
friend struct detail::allocator_ops<tst>;
private:
template <std::forward_iterator Iterator, typename Val>
[[nodiscard]] constexpr T*
add(node* root, Iterator first, Iterator last, Val&& val)
{
BOOST_ASSERT(root != nullptr);
BOOST_ASSERT(first != last);
node** pp = &root;
auto c = *first;
while (true)
{
node* const p = *pp;
if (c == p->id)
{
if (++first == last)
{
if (!p->data)
{
p->data = std::allocator_traits<Alloc>::allocate(alloc_, 1);
std::allocator_traits<Alloc>::construct(alloc_, p->data, std::forward<Val>(val));
}
return p->data;
}
pp = &p->eq;
c = *first;
}
else if (c < p->id)
{
pp = &p->lt;
}
else
{
pp = &p->gt;
}
if (!*pp)
{
*pp = std::allocator_traits<node_allocator_type>::allocate(node_alloc_, 1);
std::allocator_traits<node_allocator_type>::construct(node_alloc_, *pp, c);
}
}
}
template <std::forward_iterator Iterator>
constexpr void
remove(node*& p, Iterator first, Iterator last) noexcept
{
if (!p || first == last) return;
auto c = *first;
if (c == p->id)
{
if (++first == last)
{
if (p->data)
{
std::allocator_traits<Alloc>::destroy(alloc_, p->data);
std::allocator_traits<Alloc>::deallocate(alloc_, p->data, 1);
p->data = nullptr;
}
}
this->remove(p->eq, first, last);
}
else if (c < p->id)
{
this->remove(p->lt, first, last);
}
else
{
this->remove(p->gt, first, last);
}
if (!p->data && !p->lt && !p->eq && !p->gt)
{
std::allocator_traits<node_allocator_type>::destroy(node_alloc_, p);
std::allocator_traits<node_allocator_type>::deallocate(node_alloc_, p, 1);
p = nullptr;
}
}
BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS Alloc alloc_;
BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS node_allocator_type node_alloc_;
node* root_ = nullptr;
};
}}}
}
#endif

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -7,9 +8,10 @@
#if !defined(BOOST_SPIRIT_X3_TST_MAP_JUNE_03_2007_1143AM)
#define BOOST_SPIRIT_X3_TST_MAP_JUNE_03_2007_1143AM
#include <boost/spirit/home/x3/string/detail/tst.hpp>
#include <boost/spirit/home/x3/string/tst.hpp>
#include <unordered_map>
#include <boost/pool/object_pool.hpp>
#include <boost/call_traits.hpp>
namespace boost { namespace spirit { namespace x3
{

View File

@@ -0,0 +1,251 @@
/*=============================================================================
Copyright (c) 2025 Nana Sakisaka
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_X3_SUPPORT_ALLOCATOR_HPP)
#define BOOST_SPIRIT_X3_SUPPORT_ALLOCATOR_HPP
#include <boost/assert.hpp>
#include <memory>
#include <type_traits>
namespace boost::spirit::x3::detail {
template <typename Klass>
struct allocator_ops
{
template <typename... Allocs>
static constexpr bool move_assign_noexcept = std::conjunction_v<
std::disjunction<
typename std::allocator_traits<Allocs>::propagate_on_container_move_assignment,
typename std::allocator_traits<Allocs>::is_always_equal
>...
>;
template <auto AllocMem, auto Mem>
[[nodiscard]] static constexpr auto copy_construct(Klass& self, Klass const& other)
-> std::remove_reference_t<decltype(self.*Mem)>
{
if (!(other.*Mem)) return nullptr;
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
auto& alloc = self.*AllocMem;
auto* data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, *(other.*Mem));
return data;
}
template <auto AllocMem, auto... Mems>
static constexpr void destroy_deallocate(Klass& self) noexcept
{
static_assert(sizeof...(Mems) > 0);
(allocator_ops::destroy_deallocate_impl<AllocMem, Mems>(self), ...);
}
template <auto AllocMem, auto... Mems>
static constexpr void copy_assign(Klass& self, Klass const& other)
{
BOOST_ASSERT(std::addressof(self) != std::addressof(other));
(allocator_ops::copy_assign_impl<AllocMem, Mems>(self, other), ...);
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
constexpr bool pocca = std::allocator_traits<Alloc>::propagate_on_container_copy_assignment::value;
if constexpr (pocca)
{
self.*AllocMem = other.*AllocMem;
}
}
template <auto AllocMem, auto... Mems>
static constexpr void move_assign(Klass& self, Klass&& other)
noexcept(move_assign_noexcept<decltype(self.*AllocMem)>)
{
BOOST_ASSERT(std::addressof(self) != std::addressof(other));
(allocator_ops::move_assign_impl<AllocMem, Mems>(self, std::move(other)), ...);
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
constexpr bool pocca = std::allocator_traits<Alloc>::propagate_on_container_move_assignment::value;
if constexpr (pocca)
{
self.*AllocMem = std::move(other.*AllocMem);
}
}
private:
template <auto AllocMem, auto Mem>
static constexpr void destroy_deallocate_impl(Klass& self) noexcept
{
auto& data = self.*Mem;
if (!data) return;
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
auto& alloc = self.*AllocMem;
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
}
template <auto AllocMem, auto Mem>
static constexpr void copy_assign_impl(Klass& self, Klass const& other)
{
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
constexpr bool pocca = std::allocator_traits<Alloc>::propagate_on_container_copy_assignment::value;
auto& data = self.*Mem;
auto& alloc = self.*AllocMem;
auto const& other_data = other.*Mem;
auto const& other_alloc = other.*AllocMem;
if (other_data)
{
if constexpr (std::allocator_traits<Alloc>::is_always_equal::value)
{
if (data)
{
*data = *other_data;
return;
}
if constexpr (pocca)
{
data = std::allocator_traits<Alloc>::allocate(other_alloc, 1);
std::allocator_traits<Alloc>::construct(other_alloc, data, *other_data);
}
else
{
data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, *other_data);
}
return;
}
else if (alloc == other_alloc)
{
if (data)
{
*data = *other_data;
return;
}
if constexpr (pocca)
{
data = std::allocator_traits<Alloc>::allocate(other_alloc, 1);
std::allocator_traits<Alloc>::construct(other_alloc, data, *other_data);
}
else
{
data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, *other_data);
}
return;
}
else
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
data = nullptr;
}
if constexpr (pocca)
{
data = std::allocator_traits<Alloc>::allocate(other_alloc, 1);
std::allocator_traits<Alloc>::construct(other_alloc, data, *other_data);
}
else
{
data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, *other_data);
}
return;
}
}
else // !other_data
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
data = nullptr;
}
return;
}
}
template <auto AllocMem, auto Mem>
static constexpr void move_assign_impl(Klass& self, Klass&& other)
noexcept(move_assign_noexcept<std::remove_reference_t<decltype(self.*AllocMem)>>)
{
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
constexpr bool pocma = std::allocator_traits<Alloc>::propagate_on_container_move_assignment::value;
auto& data = self.*Mem;
auto& alloc = self.*AllocMem;
auto& other_data = other.*Mem;
auto& other_alloc = other.*AllocMem;
if (other_data)
{
if constexpr (std::allocator_traits<Alloc>::is_always_equal::value)
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
}
data = std::exchange(other_data, nullptr);
return;
}
else if (alloc == other_alloc)
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
}
data = std::exchange(other_data, nullptr);
return;
}
else
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
}
if constexpr (pocma)
{
data = std::allocator_traits<Alloc>::allocate(other_alloc, 1);
std::allocator_traits<Alloc>::construct(other_alloc, data, std::move(*other_data));
}
else
{
data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, std::move(*other_data));
}
std::allocator_traits<Alloc>::destroy(other_alloc, other_data);
std::allocator_traits<Alloc>::deallocate(other_alloc, other_data, 1);
return;
}
}
else // !other_data
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
data = nullptr;
}
return;
}
}
};
} // boost::spirit::x3::detail
#endif

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -11,7 +12,9 @@
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/char/char_class_tags.hpp>
namespace boost { namespace spirit { namespace x3
#include <cstdint>
namespace boost::spirit::x3
{
struct no_case_tag {};
@@ -19,19 +22,20 @@ namespace boost { namespace spirit { namespace x3
struct case_compare
{
template <typename Char, typename CharSet>
bool in_set(Char ch, CharSet const& set)
[[nodiscard]] constexpr bool in_set(Char ch, CharSet const& set) noexcept
{
static_assert(noexcept(set.test(ch)));
return set.test(ch);
}
template <typename Char>
int32_t operator()(Char lc, Char rc) const
[[nodiscard]] constexpr std::int32_t operator()(Char lc, Char rc) const noexcept
{
return lc - rc;
}
template <typename CharClassTag>
CharClassTag get_char_class_tag(CharClassTag tag) const
[[nodiscard]] constexpr CharClassTag get_char_class_tag(CharClassTag tag) const noexcept
{
return tag;
}
@@ -41,17 +45,18 @@ namespace boost { namespace spirit { namespace x3
struct no_case_compare
{
template <typename Char, typename CharSet>
bool in_set(Char ch_, CharSet const& set)
[[nodiscard]] bool in_set(Char ch_, CharSet const& set) noexcept // TODO: constexpr
{
using char_type = typename Encoding::classify_type;
auto ch = char_type(ch_);
static_assert(noexcept(set.test(ch)));
return set.test(ch)
|| set.test(Encoding::islower(ch)
? Encoding::toupper(ch) : Encoding::tolower(ch));
}
template <typename Char>
int32_t operator()(Char lc_, Char const rc_) const
[[nodiscard]] std::int32_t operator()(Char lc_, Char const rc_) const noexcept // TODO: constexpr
{
using char_type = typename Encoding::classify_type;
auto lc = char_type(lc_);
@@ -61,43 +66,45 @@ namespace boost { namespace spirit { namespace x3
}
template <typename CharClassTag>
CharClassTag get_char_class_tag(CharClassTag tag) const
[[nodiscard]] constexpr CharClassTag get_char_class_tag(CharClassTag tag) const noexcept
{
return tag;
}
alpha_tag get_char_class_tag(lower_tag ) const
[[nodiscard]] constexpr alpha_tag get_char_class_tag(lower_tag) const noexcept
{
return {};
}
alpha_tag get_char_class_tag(upper_tag ) const
[[nodiscard]] constexpr alpha_tag get_char_class_tag(upper_tag) const noexcept
{
return {};
}
};
template <typename Encoding>
case_compare<Encoding> get_case_compare_impl(unused_type const&)
namespace detail
{
return {};
}
template <typename Encoding>
[[nodiscard]] constexpr case_compare<Encoding> get_case_compare_impl(unused_type const&) noexcept
{
return {};
}
template <typename Encoding>
no_case_compare<Encoding> get_case_compare_impl(no_case_tag const&)
{
return {};
}
template <typename Encoding>
[[nodiscard]] constexpr no_case_compare<Encoding> get_case_compare_impl(no_case_tag const&) noexcept
{
return {};
}
} // detail
template <typename Encoding, typename Context>
inline decltype(auto) get_case_compare(Context const& context)
[[nodiscard]] constexpr decltype(auto) get_case_compare(Context const& context) noexcept
{
return get_case_compare_impl<Encoding>(x3::get<no_case_tag>(context));
return detail::get_case_compare_impl<Encoding>(x3::get<no_case_tag>(context));
}
auto const no_case_compare_ = no_case_tag{};
auto const no_case_compare_ = no_case_tag{}; // TODO: this should be private
}}}
} // boost::spirit::x3
#endif

View File

@@ -16,7 +16,7 @@
#include <boost/spirit/home/x3/support/traits/attribute_type.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/traits/numeric_traits.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/spirit/home/x3/support/traits/char_encoding_traits.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/iteration/local.hpp>
@@ -123,7 +123,7 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
{
return (Radix <= 10 || (ch >= '0' && ch <= '9'))
? ch - '0'
: char_encoding::ascii::tolower(ch) - 'a' + 10;
: traits::char_encoding_traits<Char>::encoding_type::tolower(ch) - 'a' + 10;
}
};

View File

@@ -0,0 +1,62 @@
/*=============================================================================
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_SUPPORT_TRAITS_CHAR_ENCODING_TRAITS_HPP
#define BOOST_SPIRIT_X3_SUPPORT_TRAITS_CHAR_ENCODING_TRAITS_HPP
#include <boost/spirit/home/x3/char/char.hpp>
#include <boost/spirit/home/x3/char/literal_char.hpp>
#include <boost/spirit/home/x3/string/literal_string.hpp>
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#endif
namespace boost::spirit::x3::traits
{
namespace detail
{
template <typename Encoding>
struct char_encoding_traits_impl
{
using encoding_type = Encoding;
template <class... Args>
[[nodiscard]] static constexpr auto lit(Args&&... args)
noexcept(noexcept(Encoding::lit(std::forward<Args>(args)...)))
{
return Encoding::lit(std::forward<Args>(args)...);
}
template <class... Args>
[[nodiscard]] static constexpr auto string(Args&&... args)
noexcept(noexcept(Encoding::string(std::forward<Args>(args)...)))
{
return Encoding::string(std::forward<Args>(args)...);
}
};
} // detail
template <traits::CharLike CharT>
struct char_encoding_traits;
template <>
struct char_encoding_traits<char> : detail::char_encoding_traits_impl<char_encoding::standard> {};
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
template <>
struct char_encoding_traits<wchar_t> : detail::char_encoding_traits_impl<char_encoding::standard_wide> {};
#endif
#ifdef BOOST_SPIRIT_X3_UNICODE
template <>
struct char_encoding_traits<char32_t> : detail::char_encoding_traits_impl<char_encoding::unicode> {};
#endif
} // boost::spirit::x3::traits
#endif

View File

@@ -1,6 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,16 +10,16 @@
#define BOOST_SPIRIT_X3_PRINT_ATTRIBUTE_JANUARY_20_2013_0814AM
#include <boost/variant.hpp>
#include <boost/optional/optional.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
#include <boost/spirit/home/x3/support/traits/is_variant.hpp>
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/support/char_encoding/unicode.hpp>
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#endif
namespace boost { namespace spirit { namespace x3 { namespace traits
namespace boost::spirit::x3::traits
{
template <typename Out, typename T>
void print_attribute(Out& out, T const& val);
@@ -165,6 +166,6 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
{
print_attribute_debug<Out, T>::call(out, val);
}
}}}}
} // boost::spirit::x3::traits
#endif

View File

@@ -1,7 +1,8 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2010 Bryce Lelbach
Copyright (c) 2010 Bryce Lelbach
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,146 +10,113 @@
#if !defined(BOOST_SPIRIT_X3_STRING_TRAITS_OCTOBER_2008_1252PM)
#define BOOST_SPIRIT_X3_STRING_TRAITS_OCTOBER_2008_1252PM
#if defined(BOOST_SPIRIT_UNICODE) && !defined(BOOST_SPIRIT_X3_UNICODE)
# error "`BOOST_SPIRIT_UNICODE` has no effect on X3. #define `BOOST_SPIRIT_X3_UNICODE`"
#endif
#if defined(BOOST_SPIRIT_X3_NO_STANDARD_WIDE) && !defined(BOOST_SPIRIT_X3_NO_STANDARD_WIDE)
# error "`BOOST_SPIRIT_X3_NO_STANDARD_WIDE` has no effect on X3. #define `BOOST_SPIRIT_X3_NO_STANDARD_WIDE`"
#endif
#include <string>
#include <boost/mpl/bool.hpp>
#include <string_view>
#include <type_traits>
#include <concepts>
namespace boost { namespace spirit { namespace x3 { namespace traits
namespace boost::spirit::x3::char_encoding
{
///////////////////////////////////////////////////////////////////////////
// Get the C string from a string
///////////////////////////////////////////////////////////////////////////
template <typename String>
struct extract_c_string;
struct standard;
template <typename String>
struct extract_c_string
{
template <typename T>
static T const* call (T* str)
{
return (T const*)str;
}
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
struct standard_wide;
#endif
template <typename T>
static T const* call (T const* str)
{
return str;
}
};
#ifdef BOOST_SPIRIT_X3_UNICODE
struct unicode;
#endif
} // boost::spirit::x3::char_encoding
// Forwarder that strips const
namespace boost::spirit::x3::traits
{
template <typename T>
struct extract_c_string<T const>
{
static decltype(auto) call(T const str)
{
return extract_c_string<T>::call(str);
}
};
concept CharLike =
std::same_as<std::remove_cvref_t<T>, char> ||
std::same_as<std::remove_cvref_t<T>, wchar_t> ||
std::same_as<std::remove_cvref_t<T>, char8_t> ||
std::same_as<std::remove_cvref_t<T>, char16_t> ||
std::same_as<std::remove_cvref_t<T>, char32_t>;
// Forwarder that strips references
template <typename T>
struct extract_c_string<T&>
{
static decltype(auto) call(T& str)
{
return extract_c_string<T>::call(str);
}
};
// Spirit has historically converted "c" to 'c'.
//
// While we think it's still useful to retain the conversion,
// we need to avoid further conversion to `std::basic_string_view`,
// which leads to performance overhead. This trait enables
// detection of such arrays.
//
// Note that the status quo introduces ambiguity in determining
// {'c', '\0'} and {'c', 'd'}, but we're not aware of any practical
// usage of non-null-terminated character array in the context of
// DSL on parser combinator.
//
// However, if compelling use cases emerge, we may revise these
// semantics. Versioned as `X3` for forward compatibility.
template <typename T, typename CharT>
concept X3VagueArrayOf2Chars =
std::same_as<std::remove_all_extents_t<std::remove_cvref_t<T>>, CharT> &&
std::is_bounded_array_v<std::remove_cvref_t<T>> &&
std::extent_v<std::remove_cvref_t<T>> == 2;
// Forwarder that strips const references
template <typename T>
struct extract_c_string<T const&>
{
static decltype(auto) call(T const& str)
{
return extract_c_string<T>::call(str);
}
};
// Main utility to guide `char_`, `lit` and `string` to be
// resolved into either `x3::literal_char` or `x3::literal_string`.
//
// This may also be used in other codes which require the same
// semantics.
template <typename T, typename CharT>
concept CppStringLike =
// This avoids converting `CharT[2]` to `std::basic_string_view`.
(!X3VagueArrayOf2Chars<T, CharT>) &&
// All other types that are *naturally* convertible to `std::basic_string_view`.
std::convertible_to<std::decay_t<T>, std::basic_string_view<CharT>>;
template <typename T, typename Traits, typename Allocator>
struct extract_c_string<std::basic_string<T, Traits, Allocator> >
{
typedef std::basic_string<T, Traits, Allocator> string;
// Mixing incompatible character types is semantically wrong.
// Don't do that. It may even lead to security vulnerabilities.
template <typename T, typename ExpectedCharT>
concept CharIncompatibleWith =
CharLike<T> &&
!std::same_as<std::remove_cvref_t<T>, ExpectedCharT>;
static T const* call (string const& str)
{
return str.c_str();
}
};
// Mixing incompatible character types is semantically wrong.
// Don't do that. It may even lead to security vulnerabilities.
template <typename T, typename ExpectedCharT>
concept StringLikeIncompatibleWith =
CharLike<std::remove_const_t<std::remove_pointer_t<std::decay_t<T>>>> &&
!std::convertible_to<T, std::basic_string_view<ExpectedCharT>>;
template <typename T>
decltype(auto) get_c_string(T* str)
{
return extract_c_string<T*>::call(str);
}
namespace detail {
template <CharLike CharT> struct char_encoding_for_impl;
template <> struct char_encoding_for_impl<char> { using type = char_encoding::standard; };
template <typename T>
decltype(auto) get_c_string(T const* str)
{
return extract_c_string<T const*>::call(str);
}
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
template <> struct char_encoding_for_impl<wchar_t> { using type = char_encoding::standard_wide; };
#endif
template <typename String>
decltype(auto) get_c_string(String& str)
{
return extract_c_string<String>::call(str);
}
#ifdef BOOST_SPIRIT_X3_UNICODE
template <> struct char_encoding_for_impl<char8_t> { using type = char_encoding::unicode; };
template <> struct char_encoding_for_impl<char16_t> { using type = char_encoding::unicode; };
template <> struct char_encoding_for_impl<char32_t> { using type = char_encoding::unicode; };
#endif
} // detail
template <typename String>
decltype(auto) get_c_string(String const& str)
{
return extract_c_string<String>::call(str);
}
template <class T>
using maybe_owning_string = std::conditional_t<
std::is_pointer_v<std::decay_t<T>>,
std::basic_string_view<std::remove_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
std::remove_cvref_t<T>
>;
///////////////////////////////////////////////////////////////////////////
// Get the begin/end iterators from a string
///////////////////////////////////////////////////////////////////////////
template <CharLike CharT>
using char_encoding_for = typename detail::char_encoding_for_impl<CharT>::type;
// Implementation for C-style strings.
template <typename T>
inline T const* get_string_begin(T const* str) { return str; }
template <typename T>
inline T* get_string_begin(T* str) { return str; }
template <typename T>
inline T const* get_string_end(T const* str)
{
T const* last = str;
while (*last)
last++;
return last;
}
template <typename T>
inline T* get_string_end(T* str)
{
T* last = str;
while (*last)
last++;
return last;
}
// Implementation for containers (includes basic_string).
template <typename T, typename Str>
inline typename Str::const_iterator get_string_begin(Str const& str)
{ return str.begin(); }
template <typename T, typename Str>
inline typename Str::iterator
get_string_begin(Str& str)
{ return str.begin(); }
template <typename T, typename Str>
inline typename Str::const_iterator get_string_end(Str const& str)
{ return str.end(); }
template <typename T, typename Str>
inline typename Str::iterator
get_string_end(Str& str)
{ return str.end(); }
}}}}
} // boost::spirit::x3::traits
#endif

View File

@@ -1,6 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2023 Nikita Kniazev
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,121 +10,165 @@
#define BOOST_SPIRIT_X3_UC_TYPES_NOVEMBER_23_2008_0840PM
#include <boost/config.hpp>
#include <ranges>
#include <type_traits>
#include <string>
#include <string_view>
namespace boost { namespace spirit { namespace x3
#include <cassert>
namespace boost::spirit::x3
{
typedef char32_t ucs4_char;
typedef char utf8_char;
typedef std::basic_string<ucs4_char> ucs4_string;
typedef std::basic_string<utf8_char> utf8_string;
using ucs4_char = char32_t;
using utf8_char = char;
using ucs4_string = std::basic_string<ucs4_char>;
using utf8_string = std::basic_string<utf8_char>;
namespace detail {
inline void utf8_put_encode(utf8_string& out, ucs4_char x)
{
// https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf D90
if (BOOST_UNLIKELY(x > 0x10FFFFul || (0xD7FFul < x && x < 0xE000ul)))
x = 0xFFFDul;
namespace detail {
constexpr void utf8_put_encode(utf8_string& out, ucs4_char x) noexcept
{
// https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf D90
if (x > 0x10FFFFul || (0xD7FFul < x && x < 0xE000ul)) [[unlikely]]
x = 0xFFFDul;
// Table 3-6. UTF-8 Bit Distribution
if (x < 0x80ul) {
out.push_back(static_cast<unsigned char>(x));
}
else if (x < 0x800ul) {
out.push_back(static_cast<unsigned char>(0xC0ul + (x >> 6)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
else if (x < 0x10000ul) {
out.push_back(static_cast<unsigned char>(0xE0ul + (x >> 12)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 6) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
else {
out.push_back(static_cast<unsigned char>(0xF0ul + (x >> 18)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 12) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 6) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
// Table 3-6. UTF-8 Bit Distribution
if (x < 0x80ul) {
out.push_back(static_cast<unsigned char>(x));
}
else if (x < 0x800ul) {
out.push_back(static_cast<unsigned char>(0xC0ul + (x >> 6)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
else if (x < 0x10000ul) {
out.push_back(static_cast<unsigned char>(0xE0ul + (x >> 12)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 6) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
else {
out.push_back(static_cast<unsigned char>(0xF0ul + (x >> 18)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 12) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 6) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
}
}
}
template <typename Char>
inline utf8_string to_utf8(Char value)
[[nodiscard]] constexpr utf8_string to_utf8(Char value)
{
utf8_string result;
typedef typename std::make_unsigned<Char>::type UChar;
using UChar = std::make_unsigned_t<Char>;
detail::utf8_put_encode(result, static_cast<UChar>(value));
return result;
}
template <typename Char>
inline utf8_string to_utf8(Char const* str)
[[nodiscard]] constexpr utf8_string to_utf8(Char const* str)
{
utf8_string result;
typedef typename std::make_unsigned<Char>::type UChar;
using UChar = typename std::make_unsigned<Char>::type;
while (*str)
{
detail::utf8_put_encode(result, static_cast<UChar>(*str++));
}
return result;
}
template <typename Char, typename Traits, typename Allocator>
inline utf8_string
to_utf8(std::basic_string<Char, Traits, Allocator> const& str)
template <typename Char, typename Traits>
[[nodiscard]] constexpr utf8_string
to_utf8(std::basic_string_view<Char, Traits> const str)
{
utf8_string result;
typedef typename std::make_unsigned<Char>::type UChar;
using UChar = typename std::make_unsigned<Char>::type;
for (Char ch : str)
{
detail::utf8_put_encode(result, static_cast<UChar>(ch));
}
return result;
}
template <typename Char, typename Traits>
[[nodiscard]] constexpr utf8_string
to_utf8(std::basic_string<Char, Traits> const& str)
{
utf8_string result;
using UChar = typename std::make_unsigned<Char>::type;
for (Char ch : str)
{
detail::utf8_put_encode(result, static_cast<UChar>(ch));
}
return result;
}
// Assume wchar_t content is UTF-16 on MSVC, or mingw/wineg++ with -fshort-wchar
#if defined(_MSC_VER) || defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2
inline utf8_string to_utf8(wchar_t value)
[[nodiscard]] constexpr utf8_string to_utf8(wchar_t value)
{
utf8_string result;
detail::utf8_put_encode(result, static_cast<std::make_unsigned<wchar_t>::type>(value));
detail::utf8_put_encode(result, static_cast<std::make_unsigned_t<wchar_t>>(value));
return result;
}
namespace detail {
inline ucs4_char decode_utf16(wchar_t const*& s)
template <std::forward_iterator It>
requires std::is_same_v<std::remove_const_t<std::iter_value_t<It>>, wchar_t>
[[nodiscard]] constexpr ucs4_char decode_utf16(It& s) noexcept
{
typedef std::make_unsigned<wchar_t>::type uwchar_t;
using uwchar_t = std::make_unsigned<wchar_t>::type;
uwchar_t x(*s);
if (x < 0xD800ul || x > 0xDFFFul)
{
return x;
}
// expected high-surrogate
if (BOOST_UNLIKELY((x >> 10) != 0b110110ul))
if ((x >> 10) != 0b110110ul) [[unlikely]]
{
return 0xFFFDul;
}
uwchar_t y(*++s);
// expected low-surrogate
if (BOOST_UNLIKELY((y >> 10) != 0b110111ul))
if ((y >> 10) != 0b110111ul) [[unlikely]]
{
return 0xFFFDul;
}
return ((x & 0x3FFul) << 10) + (y & 0x3FFul) + 0x10000ul;
}
}
inline utf8_string to_utf8(wchar_t const* str)
template <typename Traits>
[[nodiscard]] constexpr utf8_string
to_utf8(std::basic_string_view<wchar_t, Traits> const str)
{
utf8_string result;
for (ucs4_char c; (c = detail::decode_utf16(str)) != ucs4_char(); ++str)
detail::utf8_put_encode(result, c);
for (auto it = str.begin(); it != str.end(); ++it)
{
detail::utf8_put_encode(result, detail::decode_utf16(it));
}
return result;
}
template <typename Traits, typename Allocator>
inline utf8_string
to_utf8(std::basic_string<wchar_t, Traits, Allocator> const& str)
[[nodiscard]] constexpr utf8_string to_utf8(wchar_t const* str)
{
return to_utf8(str.c_str());
return x3::to_utf8(std::basic_string_view(str));
}
template <typename Traits>
[[nodiscard]] constexpr utf8_string
to_utf8(std::basic_string<wchar_t, Traits> const& str)
{
utf8_string result;
for (auto it = str.begin(); it != str.end(); ++it)
{
detail::utf8_put_encode(result, detail::decode_utf16(it));
}
return result;
}
#endif
}}}
} // boost::spirit::x3
#endif

View File

@@ -91,8 +91,7 @@ run extract_int.cpp ;
run int1.cpp ;
run kleene.cpp ;
run lexeme.cpp ;
run lit1.cpp ;
run lit2.cpp ;
run lit.cpp ;
run list.cpp ;
run matches.cpp ;
run no_case.cpp ;

View File

@@ -1,11 +1,38 @@
/*=============================================================================
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2011 Bryce Lelbach
Copyright (c) 2011 Bryce Lelbach
Copyright (c) 2025 Nana Sakisaka
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 "bool.hpp"
#include "test.hpp"
#include <boost/spirit/home/x3.hpp>
#include <string_view>
#include <iterator>
struct backwards_bool_policies : boost::spirit::x3::bool_policies<>
{
// we want to interpret a 'true' spelled backwards as 'false'
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename CaseCompare>
[[nodiscard]] static constexpr bool
parse_false(
It& first, Se const& last, Attribute& attr, CaseCompare const& case_compare
)
{
using namespace std::string_view_literals;
namespace x3 = boost::spirit::x3;
if (x3::detail::string_parse("eurt"sv, first, last, x3::unused, case_compare))
{
x3::traits::move_to(false, attr); // result is false
return true;
}
return false;
}
};
int main()
{
@@ -27,61 +54,65 @@ int main()
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(true_);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(false_);
BOOST_TEST(test("true", true_));
BOOST_TEST(!test("true", false_));
BOOST_TEST(test("false", false_));
BOOST_TEST(!test("false", true_));
}
{
using boost::spirit::x3::true_;
using boost::spirit::x3::false_;
using boost::spirit::x3::no_case;
BOOST_TEST(test("True", no_case[bool_]));
BOOST_TEST(test("False", no_case[bool_]));
BOOST_TEST(test("True", no_case[true_]));
BOOST_TEST(test("False", no_case[false_]));
}
{
bool b = false;
BOOST_TEST(test_attr("true", bool_, b) && b);
BOOST_TEST(test_attr("false", bool_, b) && !b);
BOOST_TEST(!test_attr("fasle", bool_, b));
}
{
typedef boost::spirit::x3::bool_parser<bool, boost::spirit::char_encoding::standard, backwards_bool_policies>
backwards_bool_type;
using backwards_bool_type = boost::spirit::x3::bool_parser<bool, boost::spirit::x3::char_encoding::standard, backwards_bool_policies>;
constexpr backwards_bool_type backwards_bool{};
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(backwards_bool);
BOOST_TEST(test("true", backwards_bool));
BOOST_TEST(test("eurt", backwards_bool));
BOOST_TEST(!test("false", backwards_bool));
BOOST_TEST(!test("fasle", backwards_bool));
bool b = false;
BOOST_TEST(test_attr("true", backwards_bool, b) && b);
BOOST_TEST(test_attr("eurt", backwards_bool, b) && !b);
BOOST_TEST(!test_attr("false", backwards_bool, b));
BOOST_TEST(!test_attr("fasle", backwards_bool, b));
}
{
typedef boost::spirit::x3::bool_parser<test_bool_type, boost::spirit::char_encoding::standard>
bool_test_type;
struct test_bool_type
{
test_bool_type(bool b = false) : b(b) {} // provide conversion
bool b;
};
using bool_test_type = boost::spirit::x3::bool_parser<test_bool_type, boost::spirit::x3::char_encoding::standard>;
constexpr bool_test_type test_bool{};
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(test_bool);
BOOST_TEST(test("true", test_bool));
BOOST_TEST(test("false", test_bool));
BOOST_TEST(!test("fasle", test_bool));
test_bool_type b = false;
BOOST_TEST(test_attr("true", test_bool, b) && b.b);
BOOST_TEST(test_attr("false", test_bool, b) && !b.b);

View File

@@ -1,40 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2011 Bryce Lelbach
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_TEST_QI_BOOL)
#define BOOST_SPIRIT_TEST_QI_BOOL
#include <boost/spirit/home/x3.hpp>
#include "test.hpp"
///////////////////////////////////////////////////////////////////////////////
struct backwards_bool_policies : boost::spirit::x3::bool_policies<>
{
// we want to interpret a 'true' spelled backwards as 'false'
template <typename Iterator, typename Attribute, typename CaseCompare>
static bool
parse_false(Iterator& first, Iterator const& last, Attribute& attr, CaseCompare const& case_compare)
{
namespace spirit = boost::spirit;
namespace x3 = boost::spirit::x3;
if (x3::detail::string_parse("eurt", first, last, x3::unused, case_compare))
{
x3::traits::move_to(false, attr); // result is false
return true;
}
return false;
}
};
///////////////////////////////////////////////////////////////////////////////
struct test_bool_type
{
test_bool_type(bool b = false) : b(b) {} // provide conversion
bool b;
};
#endif

View File

@@ -1,31 +1,32 @@
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2019 Christian Mazakas
Copyright (c) 2019 Christian Mazakas
Copyright (c) 2025 Nana Sakisaka
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)
=============================================================================*/
#define BOOST_SPIRIT_UNICODE
#define BOOST_SPIRIT_X3_UNICODE
#include <boost/spirit/home/x3.hpp>
#include <boost/utility/string_view.hpp>
#include <string>
#include <string_view>
#include <iostream>
#include <vector>
#include <algorithm>
#include "test.hpp"
int
main()
int main()
{
using spirit_test::test;
{
using namespace boost::spirit::x3::ascii;
using namespace boost::spirit::x3::standard;
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(char_);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(char_('x'));
@@ -69,7 +70,7 @@ main()
}
{
using namespace boost::spirit::x3::ascii;
using namespace boost::spirit::x3::standard;
BOOST_TEST(test(" x", 'x', space));
BOOST_TEST(test(L" x", L'x', space));
@@ -125,11 +126,11 @@ main()
auto const sub_delims = char_(U"!$&'()*+,;=");
auto const delims =
std::vector<boost::u32string_view>{U"!", U"$", U"&", U"'", U"(", U")", U"*", U"+",
std::vector<std::u32string_view>{U"!", U"$", U"&", U"'", U"(", U")", U"*", U"+",
U",", U";", U"="};
auto const matched_all_sub_delims =
std::all_of(delims.begin(), delims.end(), [&](auto const delim) -> bool {
std::ranges::all_of(delims, [&](auto const delim) -> bool {
return test(delim, sub_delims);
});
@@ -143,18 +144,18 @@ main()
auto const chars = char_(U"\u0024\u00a2\u0939\u20ac\U00010348");
auto const test_strings =
std::vector<boost::u32string_view>{U"\u0024", U"\u00a2", U"\u0939", U"\u20ac",
std::vector<std::u32string_view>{U"\u0024", U"\u00a2", U"\u0939", U"\u20ac",
U"\U00010348"};
auto const bad_test_strings = std::vector<boost::u32string_view>{U"a", U"B", U"c", U"\u0409"};
auto const bad_test_strings = std::vector<std::u32string_view>{U"a", U"B", U"c", U"\u0409"};
auto const all_matched =
std::all_of(test_strings.begin(), test_strings.end(), [&](auto const test_str) -> bool {
std::ranges::all_of(test_strings, [&](auto const test_str) -> bool {
return test(test_str, chars);
});
auto const none_matched =
std::all_of(bad_test_strings.begin(), bad_test_strings.end(), [&](auto const bad_test_str) -> bool {
std::ranges::all_of(bad_test_strings, [&](auto const bad_test_str) -> bool {
return !test(bad_test_str, chars);
});
@@ -164,50 +165,38 @@ main()
{ // single char strings!
namespace ascii = boost::spirit::x3::ascii;
namespace wide = boost::spirit::x3::standard_wide;
namespace standard = boost::spirit::x3::standard;
namespace wide = boost::spirit::x3::standard_wide;
BOOST_TEST(test("x", "x"));
BOOST_TEST(test(L"x", L"x"));
BOOST_TEST(test("x", ascii::char_("x")));
BOOST_TEST(test("x", standard::char_("x")));
BOOST_TEST(test(L"x", wide::char_(L"x")));
BOOST_TEST(test("x", ascii::char_("a", "z")));
BOOST_TEST(test("x", standard::char_("a", "z")));
BOOST_TEST(test(L"x", wide::char_(L"a", L"z")));
}
{
// chsets
namespace ascii = boost::spirit::x3::ascii;
namespace standard = boost::spirit::x3::standard;
namespace wide = boost::spirit::x3::standard_wide;
BOOST_TEST(test("x", ascii::char_("a-z")));
BOOST_TEST(!test("1", ascii::char_("a-z")));
BOOST_TEST(test("1", ascii::char_("a-z0-9")));
BOOST_TEST(test("x", standard::char_("a-z")));
BOOST_TEST(!test("1", standard::char_("a-z")));
BOOST_TEST(test("1", standard::char_("a-z0-9")));
BOOST_TEST(test("x", wide::char_(L"a-z")));
BOOST_TEST(!test("1", wide::char_(L"a-z")));
BOOST_TEST(test("1", wide::char_(L"a-z0-9")));
std::string set = "a-z0-9";
BOOST_TEST(test("x", ascii::char_(set)));
BOOST_TEST(test("x", standard::char_(set)));
#ifdef SPIRIT_NO_COMPILE_CHECK
test("", ascii::char_(L"a-z0-9"));
#endif
}
{
namespace ascii = boost::spirit::x3::ascii;
char const* input = "\x80";
// ascii > 7 bits (this should fail, not assert!)
BOOST_TEST(!test(input, ascii::char_));
BOOST_TEST(!test(input, ascii::char_('a')));
BOOST_TEST(!test(input, ascii::alnum));
BOOST_TEST(!test(input, ascii::char_("a-z")));
BOOST_TEST(!test(input, ascii::char_('0', '9')));
}
return boost::report_errors();
}

View File

@@ -1,21 +1,23 @@
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
Copyright (c) 2001-2010 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
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)
=============================================================================*/
#define BOOST_SPIRIT_UNICODE
#define BOOST_SPIRIT_X3_UNICODE
#include <boost/spirit/home/x3.hpp>
#include <boost/type_traits/is_same.hpp>
#include <iostream>
#include "test.hpp"
int
main()
#include <boost/spirit/home/x3.hpp>
#include <type_traits>
#include <iostream>
int main()
{
using spirit_test::test;
using spirit_test::test_failure;
@@ -23,113 +25,6 @@ main()
using boost::spirit::x3::unused_type;
{
using namespace boost::spirit::x3::ascii;
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(alnum);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(alpha);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(digit);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(xdigit);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(cntrl);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(graph);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(lower);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(print);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(punct);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(space);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(blank);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(upper);
BOOST_TEST(test("1", alnum));
BOOST_TEST(!test(" ", alnum));
BOOST_TEST(!test("1", alpha));
BOOST_TEST(test("x", alpha));
BOOST_TEST(test(" ", blank));
BOOST_TEST(!test("x", blank));
BOOST_TEST(test("1", digit));
BOOST_TEST(!test("x", digit));
BOOST_TEST(test("a", lower));
BOOST_TEST(!test("A", lower));
BOOST_TEST(test("!", punct));
BOOST_TEST(!test("x", punct));
BOOST_TEST(test(" ", space));
BOOST_TEST(test("\n", space));
BOOST_TEST(test("\r", space));
BOOST_TEST(test("\t", space));
BOOST_TEST(test("A", upper));
BOOST_TEST(!test("a", upper));
BOOST_TEST(test("A", xdigit));
BOOST_TEST(test("0", xdigit));
BOOST_TEST(test("f", xdigit));
BOOST_TEST(!test("g", xdigit));
}
{
using namespace boost::spirit::x3::ascii;
BOOST_TEST(!test("1", ~alnum));
BOOST_TEST(test(" ", ~alnum));
BOOST_TEST(test("1", ~alpha));
BOOST_TEST(!test("x", ~alpha));
BOOST_TEST(!test(" ", ~blank));
BOOST_TEST(test("x", ~blank));
BOOST_TEST(!test("1", ~digit));
BOOST_TEST(test("x", ~digit));
BOOST_TEST(!test("a", ~lower));
BOOST_TEST(test("A", ~lower));
BOOST_TEST(!test("!", ~punct));
BOOST_TEST(test("x", ~punct));
BOOST_TEST(!test(" ", ~space));
BOOST_TEST(!test("\n", ~space));
BOOST_TEST(!test("\r", ~space));
BOOST_TEST(!test("\t", ~space));
BOOST_TEST(!test("A", ~upper));
BOOST_TEST(test("a", ~upper));
BOOST_TEST(!test("A", ~xdigit));
BOOST_TEST(!test("0", ~xdigit));
BOOST_TEST(!test("f", ~xdigit));
BOOST_TEST(test("g", ~xdigit));
}
{
using namespace boost::spirit::x3::iso8859_1;
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(alnum);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(alpha);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(digit);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(xdigit);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(cntrl);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(graph);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(lower);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(print);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(punct);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(space);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(blank);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(upper);
BOOST_TEST(test("1", alnum));
BOOST_TEST(!test(" ", alnum));
BOOST_TEST(!test("1", alpha));
BOOST_TEST(test("x", alpha));
BOOST_TEST(test(" ", blank));
BOOST_TEST(!test("x", blank));
BOOST_TEST(test("1", digit));
BOOST_TEST(!test("x", digit));
BOOST_TEST(test("a", lower));
BOOST_TEST(!test("A", lower));
BOOST_TEST(test("!", punct));
BOOST_TEST(!test("x", punct));
BOOST_TEST(test(" ", space));
BOOST_TEST(test("\n", space));
BOOST_TEST(test("\r", space));
BOOST_TEST(test("\t", space));
BOOST_TEST(test("A", upper));
BOOST_TEST(!test("a", upper));
BOOST_TEST(test("A", xdigit));
BOOST_TEST(test("0", xdigit));
BOOST_TEST(test("f", xdigit));
BOOST_TEST(!test("g", xdigit));
// test extended ASCII characters
BOOST_TEST(test("\xE9", alpha));
BOOST_TEST(test("\xE9", lower));
BOOST_TEST(!test("\xE9", upper));
}
{
using namespace boost::spirit::x3::standard;
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(alnum);
@@ -221,42 +116,42 @@ main()
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(space);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(blank);
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(upper);
BOOST_TEST(test(L"1", alnum));
BOOST_TEST(!test(L" ", alnum));
BOOST_TEST(!test(L"1", alpha));
BOOST_TEST(test(L"x", alpha));
BOOST_TEST(test(L" ", blank));
BOOST_TEST(!test(L"x", blank));
BOOST_TEST(test(L"1", digit));
BOOST_TEST(!test(L"x", digit));
BOOST_TEST(test(L"a", lower));
BOOST_TEST(!test(L"A", lower));
BOOST_TEST(test(L"!", punct));
BOOST_TEST(!test(L"x", punct));
BOOST_TEST(test(L" ", space));
BOOST_TEST(test(L"\n", space));
BOOST_TEST(test(L"\r", space));
BOOST_TEST(test(L"\t", space));
BOOST_TEST(test(L"A", upper));
BOOST_TEST(!test(L"a", upper));
BOOST_TEST(test(L"A", xdigit));
BOOST_TEST(test(L"0", xdigit));
BOOST_TEST(test(L"f", xdigit));
BOOST_TEST(!test(L"g", xdigit));
BOOST_TEST(test(U"1", alnum));
BOOST_TEST(!test(U" ", alnum));
BOOST_TEST(!test(U"1", alpha));
BOOST_TEST(test(U"x", alpha));
BOOST_TEST(test(U" ", blank));
BOOST_TEST(!test(U"x", blank));
BOOST_TEST(test(U"1", digit));
BOOST_TEST(!test(U"x", digit));
BOOST_TEST(test(U"a", lower));
BOOST_TEST(!test(U"A", lower));
BOOST_TEST(test(U"!", punct));
BOOST_TEST(!test(U"x", punct));
BOOST_TEST(test(U" ", space));
BOOST_TEST(test(U"\n", space));
BOOST_TEST(test(U"\r", space));
BOOST_TEST(test(U"\t", space));
BOOST_TEST(test(U"A", upper));
BOOST_TEST(!test(U"a", upper));
BOOST_TEST(test(U"A", xdigit));
BOOST_TEST(test(U"0", xdigit));
BOOST_TEST(test(U"f", xdigit));
BOOST_TEST(!test(U"g", xdigit));
BOOST_TEST(test(L"A", alphabetic));
BOOST_TEST(test(L"9", decimal_number));
BOOST_TEST(test(L"\u2800", braille));
BOOST_TEST(!test(L" ", braille));
BOOST_TEST(test(L" ", ~braille));
// $$$ TODO $$$ Add more unicode tests
BOOST_TEST(test(U"A", alphabetic));
BOOST_TEST(test(U"9", decimal_number));
BOOST_TEST(test(U"\u2800", braille));
BOOST_TEST(!test(U" ", braille));
BOOST_TEST(test(U" ", ~braille));
// TODO: Add more unicode tests
}
{ // test invalid unicode literals
using namespace boost::spirit::x3::unicode;
auto const invalid_unicode = char32_t{0x7FFFFFFF};
auto const input = boost::u32string_view(&invalid_unicode, 1);
auto const input = std::u32string_view(&invalid_unicode, 1);
BOOST_TEST(test_failure(input, char_));
@@ -268,16 +163,11 @@ main()
}
{ // test attribute extraction
using boost::spirit::x3::traits::attribute_of;
using boost::spirit::x3::iso8859_1::alpha;
using boost::spirit::x3::iso8859_1::alpha_type;
using boost::spirit::x3::traits::attribute_of_t;
using boost::spirit::x3::standard::alpha;
using boost::spirit::x3::standard::alpha_type;
static_assert(
boost::is_same<
attribute_of<alpha_type, unused_type>::type
, unsigned char>::value
, "Wrong attribute type!"
);
static_assert(std::is_same_v<attribute_of_t<alpha_type, unused_type>, char>);
int attr = 0;
BOOST_TEST(test_attr("a", alpha, attr));
@@ -285,15 +175,15 @@ main()
}
{ // test attribute extraction
using boost::spirit::x3::iso8859_1::alpha;
using boost::spirit::x3::iso8859_1::space;
using boost::spirit::x3::standard::alpha;
using boost::spirit::x3::standard::space;
char attr = 0;
BOOST_TEST(test_attr(" a", alpha, attr, space));
BOOST_TEST(attr == 'a');
}
{ // test action
using namespace boost::spirit::x3::ascii;
using namespace boost::spirit::x3::standard;
using boost::spirit::x3::_attr;
char ch;
auto f = [&](auto& ctx){ ch = _attr(ctx); };

View File

@@ -1,54 +1,164 @@
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
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)
=============================================================================*/
#undef BOOST_SPIRIT_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_UNICODE
# define BOOST_SPIRIT_UNICODE
#endif
#ifndef BOOST_SPIRIT_X3_UNICODE
# define BOOST_SPIRIT_X3_UNICODE
#endif
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/vector.hpp>
#include <string>
#include "test.hpp"
int
main()
int main()
{
namespace x3 = boost::spirit::x3;
using spirit_test::test;
using spirit_test::test_attr;
using boost::spirit::x3::lit;
using boost::spirit::x3::char_;
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(lit("x"));
// standard
{
(void)x3::lit('f'); // deprecated
(void)x3::lit("f"); // deprecated
(void)x3::lit("foo"); // deprecated
(void)x3::standard::lit('f');
(void)x3::standard::lit("f");
(void)x3::standard::lit("foo");
(void)x3::char_('f'); // deprecated
(void)x3::char_("f"); // deprecated
(void)x3::char_("foo"); // deprecated
(void)x3::standard::char_('f');
(void)x3::standard::char_("f");
(void)x3::standard::char_("foo");
(void)x3::string('f'); // deprecated
(void)x3::string("f"); // deprecated
(void)x3::string("foo"); // deprecated
(void)x3::standard::string('f');
(void)x3::standard::string("f");
(void)x3::standard::string("foo");
}
// standard_wide
{
(void)x3::lit(L'f'); // deprecated
(void)x3::lit(L"f"); // deprecated
(void)x3::lit(L"foo"); // deprecated
(void)x3::standard_wide::lit(L'f');
(void)x3::standard_wide::lit(L"f");
(void)x3::standard_wide::lit(L"foo");
(void)x3::standard_wide::char_(L'f');
(void)x3::standard_wide::char_(L"f");
(void)x3::standard_wide::char_(L"foo");
(void)x3::string(L'f'); // deprecated
(void)x3::string(L"f"); // deprecated
(void)x3::string(L"foo"); // deprecated
(void)x3::standard_wide::string(L'f');
(void)x3::standard_wide::string(L"f");
(void)x3::standard_wide::string(L"foo");
}
// unicode
{
(void)x3::unicode::lit(U'f');
(void)x3::unicode::lit(U"f");
(void)x3::unicode::lit(U"foo");
(void)x3::unicode::char_(U'f');
(void)x3::unicode::char_(U"f");
(void)x3::unicode::char_(U"foo");
(void)x3::unicode::string(U'f');
(void)x3::unicode::string(U"f");
(void)x3::unicode::string(U"foo");
}
{
std::string attr;
auto p = char_ >> lit("\n");
auto p = x3::standard::char_ >> x3::standard::lit("\n");
BOOST_TEST(test_attr("A\n", p, attr));
BOOST_TEST(attr == "A");
}
{
using namespace boost::spirit::x3::ascii;
std::string attr;
auto p = char_ >> lit("\n");
BOOST_TEST(test_attr("A\n", p, attr));
BOOST_TEST(attr == "A");
}
{
using namespace boost::spirit::x3::iso8859_1;
std::string attr;
auto p = char_ >> lit("\n");
BOOST_TEST(test_attr("É\n", p, attr));
BOOST_TEST(attr == "É");
}
{
using namespace boost::spirit::x3::standard_wide;
std::wstring attr;
auto p = char_ >> lit("\n");
BOOST_TEST(test_attr(l"É\n", p, attr));
BOOST_TEST(attr == "A");
auto p = x3::standard_wide::char_ >> x3::standard_wide::lit(L"\n");
BOOST_TEST(test_attr(L"É\n", p, attr));
BOOST_TEST(attr == L"É");
}
// -------------------------------------------------
{
BOOST_TEST((test("kimpo", x3::standard::lit("kimpo"))));
std::basic_string<char> s("kimpo");
std::basic_string<wchar_t> ws(L"kimpo");
BOOST_TEST((test("kimpo", x3::standard::lit(s))));
BOOST_TEST((test(L"kimpo", x3::standard_wide::lit(ws))));
}
{
std::basic_string<char> s("kimpo");
BOOST_TEST((test("kimpo", x3::standard::lit(s))));
std::basic_string<wchar_t> ws(L"kimpo");
BOOST_TEST((test(L"kimpo", x3::standard_wide::lit(ws))));
}
// -------------------------------------------------
{
BOOST_TEST((test("kimpo", "kimpo")));
BOOST_TEST((test("kimpo", x3::standard::string("kimpo"))));
BOOST_TEST((test("x", x3::standard::string("x"))));
BOOST_TEST((test(L"x", x3::standard_wide::string(L"x"))));
std::basic_string<char> s("kimpo");
std::basic_string<wchar_t> ws(L"kimpo");
BOOST_TEST((test("kimpo", s)));
BOOST_TEST((test(L"kimpo", ws)));
BOOST_TEST((test("kimpo", x3::standard::string(s))));
BOOST_TEST((test(L"kimpo", x3::standard_wide::string(ws))));
}
{
BOOST_TEST((test(L"kimpo", L"kimpo")));
BOOST_TEST((test(L"kimpo", x3::standard_wide::string(L"kimpo"))));
BOOST_TEST((test(L"x", x3::standard_wide::string(L"x"))));
}
{
std::basic_string<char> s("kimpo");
BOOST_TEST((test("kimpo", x3::standard::string(s))));
std::basic_string<wchar_t> ws(L"kimpo");
BOOST_TEST((test(L"kimpo", x3::standard_wide::string(ws))));
}
{
// single-element fusion vector tests
boost::fusion::vector<std::string> s;
BOOST_TEST(test_attr("kimpo", x3::standard::string("kimpo"), s));
BOOST_TEST(boost::fusion::at_c<0>(s) == "kimpo");
}
return boost::report_errors();
}

View File

@@ -1,89 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
http://spirit.sourceforge.net/
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/spirit/home/x3.hpp>
#include <boost/fusion/include/vector.hpp>
#include <string>
#include "test.hpp"
int
main()
{
using spirit_test::test;
using spirit_test::test_attr;
using boost::spirit::x3::string;
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(string("x"));
{
BOOST_TEST((test("kimpo", "kimpo")));
BOOST_TEST((test("kimpo", string("kimpo"))));
BOOST_TEST((test("x", string("x"))));
BOOST_TEST((test(L"x", string(L"x"))));
std::basic_string<char> s("kimpo");
std::basic_string<wchar_t> ws(L"kimpo");
BOOST_TEST((test("kimpo", s)));
BOOST_TEST((test(L"kimpo", ws)));
BOOST_TEST((test("kimpo", string(s))));
BOOST_TEST((test(L"kimpo", string(ws))));
}
{
BOOST_TEST((test(L"kimpo", L"kimpo")));
BOOST_TEST((test(L"kimpo", string(L"kimpo"))));
BOOST_TEST((test(L"x", string(L"x"))));
}
{
std::basic_string<char> s("kimpo");
BOOST_TEST((test("kimpo", string(s))));
std::basic_string<wchar_t> ws(L"kimpo");
BOOST_TEST((test(L"kimpo", string(ws))));
}
{
using namespace boost::spirit::x3::ascii;
BOOST_TEST((test(" kimpo", string("kimpo"), space)));
BOOST_TEST((test(L" kimpo", string(L"kimpo"), space)));
BOOST_TEST((test(" x", string("x"), space)));
}
{
using namespace boost::spirit::x3::ascii;
BOOST_TEST((test(" kimpo", string("kimpo"), space)));
BOOST_TEST((test(L" kimpo", string(L"kimpo"), space)));
BOOST_TEST((test(" x", string("x"), space)));
}
{
using namespace boost::spirit::x3::ascii;
std::string s;
BOOST_TEST((test_attr("kimpo", string("kimpo"), s)));
BOOST_TEST(s == "kimpo");
s.clear();
BOOST_TEST((test_attr("kimpo", string("kim") >> string("po"), s)));
BOOST_TEST(s == "kimpo");
s.clear();
BOOST_TEST((test_attr(L"kimpo", string(L"kimpo"), s)));
BOOST_TEST(s == "kimpo");
s.clear();
BOOST_TEST((test_attr("x", string("x"), s)));
BOOST_TEST(s == "x");
}
{ // single-element fusion vector tests
boost::fusion::vector<std::string> s;
BOOST_TEST(test_attr("kimpo", string("kimpo"), s));
BOOST_TEST(boost::fusion::at_c<0>(s) == "kimpo");
}
return boost::report_errors();
}

View File

@@ -1,51 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
http://spirit.sourceforge.net/
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/spirit/home/x3.hpp>
#include <iostream>
#include "test.hpp"
int
main()
{
using spirit_test::test;
using spirit_test::test_attr;
using boost::spirit::x3::lit;
{
BOOST_TEST((test("kimpo", lit("kimpo"))));
std::basic_string<char> s("kimpo");
std::basic_string<wchar_t> ws(L"kimpo");
BOOST_TEST((test("kimpo", lit(s))));
BOOST_TEST((test(L"kimpo", lit(ws))));
}
{
std::basic_string<char> s("kimpo");
BOOST_TEST((test("kimpo", lit(s))));
std::basic_string<wchar_t> ws(L"kimpo");
BOOST_TEST((test(L"kimpo", lit(ws))));
}
{
using namespace boost::spirit::x3::ascii;
BOOST_TEST((test(" kimpo", lit("kimpo"), space)));
BOOST_TEST((test(L" kimpo", lit(L"kimpo"), space)));
}
{
using namespace boost::spirit::x3::iso8859_1;
BOOST_TEST((test(" kimpo", lit("kimpo"), space)));
BOOST_TEST((test(L" kimpo", lit(L"kimpo"), space)));
}
return boost::report_errors();
}

View File

@@ -1,6 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
http://spirit.sourceforge.net/
Copyright (c) 2025 Nana Sakisaka
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)
@@ -11,8 +11,7 @@
#include <iostream>
#include "test.hpp"
int
main()
int main()
{
using spirit_test::test;
using spirit_test::test_attr;
@@ -21,7 +20,7 @@ main()
BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(no_case['x']);
{
using namespace boost::spirit::x3::ascii;
using namespace boost::spirit::x3::standard;
BOOST_TEST(test("x", no_case[char_]));
BOOST_TEST(test("X", no_case[char_('x')]));
BOOST_TEST(test("X", no_case[char_('X')]));
@@ -35,7 +34,7 @@ main()
BOOST_TEST(!test("z", no_case[char_('a', 'y')]));
}
{
using namespace boost::spirit::x3::ascii;
using namespace boost::spirit::x3::standard;
BOOST_TEST(test("X", no_case['x']));
BOOST_TEST(test("X", no_case['X']));
BOOST_TEST(test("x", no_case['X']));
@@ -45,24 +44,13 @@ main()
}
{
using namespace boost::spirit::x3::iso8859_1;
using namespace boost::spirit::x3::standard;
BOOST_TEST(test("X", no_case[char_("a-z")]));
BOOST_TEST(!test("1", no_case[char_("a-z")]));
}
{ // test extended ASCII characters
using namespace boost::spirit::x3::iso8859_1;
BOOST_TEST(test("\xC1", no_case[char_('\xE1')]));
BOOST_TEST(test("\xC9", no_case[char_("\xE5-\xEF")]));
BOOST_TEST(!test("\xFF", no_case[char_("\xE5-\xEF")]));
BOOST_TEST(test("\xC1\xE1", no_case[lit("\xE1\xC1")]));
BOOST_TEST(test("\xE1\xE1", no_case[no_case[lit("\xE1\xC1")]]));
}
{
using namespace boost::spirit::x3::ascii;
using namespace boost::spirit::x3::standard;
BOOST_TEST(test("Bochi Bochi", no_case[lit("bochi bochi")]));
BOOST_TEST(test("BOCHI BOCHI", no_case[lit("bochi bochi")]));
BOOST_TEST(!test("Vavoo", no_case[lit("bochi bochi")]));
@@ -70,40 +58,12 @@ main()
{
// should work!
using namespace boost::spirit::x3::ascii;
using namespace boost::spirit::x3::standard;
BOOST_TEST(test("x", no_case[no_case[char_]]));
BOOST_TEST(test("x", no_case[no_case[char_('x')]]));
BOOST_TEST(test("yabadabadoo", no_case[no_case[lit("Yabadabadoo")]]));
}
{
using namespace boost::spirit::x3::ascii;
BOOST_TEST(test("X", no_case[alnum]));
BOOST_TEST(test("6", no_case[alnum]));
BOOST_TEST(!test(":", no_case[alnum]));
BOOST_TEST(test("X", no_case[lower]));
BOOST_TEST(test("x", no_case[lower]));
BOOST_TEST(test("X", no_case[upper]));
BOOST_TEST(test("x", no_case[upper]));
BOOST_TEST(!test(":", no_case[lower]));
BOOST_TEST(!test(":", no_case[upper]));
}
{
using namespace boost::spirit::x3::iso8859_1;
BOOST_TEST(test("X", no_case[alnum]));
BOOST_TEST(test("6", no_case[alnum]));
BOOST_TEST(!test(":", no_case[alnum]));
BOOST_TEST(test("X", no_case[lower]));
BOOST_TEST(test("x", no_case[lower]));
BOOST_TEST(test("X", no_case[upper]));
BOOST_TEST(test("x", no_case[upper]));
BOOST_TEST(!test(":", no_case[lower]));
BOOST_TEST(!test(":", no_case[upper]));
}
{
using namespace boost::spirit::x3::standard;
BOOST_TEST(test("X", no_case[alnum]));

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -21,16 +22,15 @@ private:
char str[2];
};
int
main()
int main()
{
using spirit_test::test;
using spirit_test::test_attr;
using boost::spirit::x3::symbols;
using boost::spirit::x3::shared_symbols;
using boost::spirit::x3::no_case;
{ // basics
symbols<int> sym;
shared_symbols<int> sym;
sym.add
("Joel")
@@ -52,7 +52,7 @@ main()
BOOST_TEST((!test("XXX", sym)));
// test copy
symbols<int> sym2;
shared_symbols<int> sym2;
sym2 = sym;
BOOST_TEST((test("Joel", sym2)));
BOOST_TEST((test("Ruby", sym2)));
@@ -75,7 +75,7 @@ main()
}
{ // comma syntax
symbols<int> sym;
shared_symbols<int> sym;
sym += "Joel", "Ruby", "Tenji", "Tutit", "Kim", "Joey";
BOOST_TEST((test("Joel", sym)));
@@ -93,9 +93,9 @@ main()
}
{ // no-case handling
using namespace boost::spirit::x3::ascii;
using namespace boost::spirit::x3::standard;
symbols<int> sym;
shared_symbols<int> sym;
// NOTE: make sure all entries are in lower-case!!!
sym = "joel", "ruby", "tenji", "tutit", "kim", "joey";
@@ -118,7 +118,7 @@ main()
}
{ // attributes
symbols<int> sym;
shared_symbols<int> sym;
sym.add
("Joel", 1)
@@ -154,7 +154,7 @@ main()
{ // actions
using boost::spirit::x3::_attr;
symbols<int> sym;
shared_symbols<int> sym;
sym.add
("Joel", 1)
("Ruby", 2)

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,34 +10,17 @@
#include <iostream>
#include "test.hpp"
// Custom string type with a C-style string conversion.
struct custom_string_c
{
custom_string_c(char c) { str[0] = c; str[1] = '\0'; }
operator char*() { return str; }
operator char const*() const { return str; }
private:
char str[2];
};
std::string get_str(char const* str)
{
return std::string(str);
}
int
main()
int main()
{
using spirit_test::test;
using spirit_test::test_attr;
using boost::spirit::x3::symbols;
using boost::spirit::x3::shared_symbols;
using boost::spirit::x3::rule;
{ // construction from symbol array
char const* syms[] = {"Joel","Ruby","Tenji","Tutit","Kim","Joey"};
symbols<int> sym(syms);
{
// construction from symbol array
char const* syms[] = {"Joel", "Ruby", "Tenji", "Tutit", "Kim", "Joey"};
shared_symbols<int> sym(syms);
BOOST_TEST((test("Joel", sym)));
BOOST_TEST((test("Ruby", sym)));
@@ -47,11 +31,12 @@ main()
BOOST_TEST((!test("XXX", sym)));
}
{ // construction from 2 arrays
{
// construction from 2 arrays
char const* syms[] = {"Joel","Ruby","Tenji","Tutit","Kim","Joey"};
int data[] = {1,2,3,4,5,6};
symbols<int> sym(syms, data);
char const* syms[] = {"Joel", "Ruby", "Tenji", "Tutit", "Kim", "Joey"};
int data[] = {1, 2, 3, 4, 5, 6};
shared_symbols<int> sym(syms, data);
int i;
BOOST_TEST((test_attr("Joel", sym, i)));
@@ -69,8 +54,9 @@ main()
BOOST_TEST((!test_attr("XXX", sym, i)));
}
{ // allow std::string and other string types
symbols<> sym;
{
// allow std::string and other string types
shared_symbols<> sym;
// const and non-const std::string
std::string a("abc");
@@ -88,19 +74,12 @@ main()
sym = arr;
BOOST_TEST((test("a", sym)));
BOOST_TEST((!test("b", sym)));
// const and non-const custom string type
custom_string_c c('x');
custom_string_c const cc('y');
sym = c, cc;
BOOST_TEST((test("x", sym)));
BOOST_TEST((test("y", sym)));
BOOST_TEST((!test("z", sym)));
}
{ // find
{
// find
symbols<int> sym;
shared_symbols<int> sym;
sym.add("a", 1)("b", 2);
BOOST_TEST(!sym.find("c"));
@@ -116,7 +95,7 @@ main()
BOOST_TEST(sym.find("b") && *sym.find("b") == 2);
BOOST_TEST(sym.find("c") && *sym.find("c") == 0);
symbols<int> const_sym(sym);
shared_symbols<int> const_sym(sym);
BOOST_TEST(const_sym.find("a") && *const_sym.find("a") == 1);
BOOST_TEST(const_sym.find("b") && *const_sym.find("b") == 2);
@@ -132,20 +111,22 @@ main()
BOOST_TEST(!sym.prefix_find(first, last) && first == str2);
}
{ // name
symbols <int> sym,sym2;
{
// name
shared_symbols<int> sym,sym2;
sym.name("test");
BOOST_TEST(sym.name()=="test");
sym2 = sym;
BOOST_TEST(sym2.name()=="test");
symbols <int> sym3(sym);
shared_symbols<int> sym3(sym);
BOOST_TEST(sym3.name()=="test");
}
{ // Substrings
{
// Substrings
symbols<int> sym;
shared_symbols<int> sym;
BOOST_TEST(sym.at("foo") == 0);
sym.at("foo") = 1;
BOOST_TEST(sym.at("foo") == 1);
@@ -175,23 +156,22 @@ main()
}
{
// remove bug
std::string s;
symbols<double> vars;
shared_symbols<double> vars;
vars.add("l1", 12.0);
vars.add("l2", 0.0);
vars.remove("l2");
vars.find("l1");
(void)vars.find("l1");
double* d = vars.find("l1");
BOOST_TEST(d != 0);
BOOST_TEST(d != nullptr);
}
{ // test for proto problem with rvalue references (10-11-2011)
symbols<int> sym;
sym += get_str("Joel");
sym += get_str("Ruby");
{
// test for proto problem with rvalue references (10-11-2011)
shared_symbols<int> sym;
sym += std::string("Joel");
sym += std::string("Ruby");
BOOST_TEST((test("Joel", sym)));
BOOST_TEST((test("Ruby", sym)));

View File

@@ -1,30 +1,33 @@
/*=============================================================================
Copyright (c) 2013 Carl Barron
Copyright (c) 2015 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
=============================================================================*/
#define BOOST_SPIRIT_X3_DEBUG
#define BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL 0
#include "test.hpp"
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/support/char_encoding/unicode.hpp>
#include <boost/fusion/include/at.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/mpl/int.hpp>
#include <boost/optional.hpp>
#include <optional>
#include <iostream>
#include <numeric>
#include <vector>
#include "test.hpp"
struct roman
{
boost::optional<int> a;
boost::optional<int> b;
boost::optional<int> c;
std::optional<int> a;
std::optional<int> b;
std::optional<int> c;
};
BOOST_FUSION_ADAPT_STRUCT(roman,
@@ -33,30 +36,29 @@ BOOST_FUSION_ADAPT_STRUCT(roman,
int eval(roman const & c)
{
return c.a.get_value_or(0) + c.b.get_value_or(0) + c.c.get_value_or(0);
return c.a.value_or(0) + c.b.value_or(0) + c.c.value_or(0);
}
int
main()
int main()
{
using spirit_test::test;
using spirit_test::test_attr;
using boost::spirit::x3::symbols;
using boost::spirit::x3::shared_symbols;
{ // construction from initializer-list
symbols<int> const ones =
shared_symbols<int> const ones =
{
{"I", 1}, {"II", 2}, {"III", 3}, {"IV", 4},
{"V", 5}, {"VI", 6}, {"VII", 7}, {"VIII", 8},
{"IX", 9}
};
symbols<int> const tens =
shared_symbols<int> const tens =
{
{"X", 10}, {"XX", 20}, {"XXX", 30}, {"XL", 40},
{"L", 50}, {"LX", 60}, {"LXX", 70}, {"LXXX", 80},
{"XC", 90}
};
symbols<int> const hundreds
shared_symbols<int> const hundreds
{
{"C", 100}, {"CC", 200}, {"CCC", 300}, {"CD", 400},
{"D", 500}, {"DC", 600}, {"DCC", 700}, {"DCCC", 800},
@@ -71,13 +73,13 @@ main()
}
{ // construction from initializer-list without attribute
symbols<> foo = {"a1", "a2", "a3"};
shared_symbols<> foo = {"a1", "a2", "a3"};
BOOST_TEST((test("a3", foo)));
}
{ // assignment from initializer-list
symbols<> foo;
shared_symbols<> foo;
foo = {"a1", "a2", "a3"};
BOOST_TEST((test("a3", foo)));
@@ -85,7 +87,7 @@ main()
{ // unicode | construction from initializer-list
using namespace boost::spirit;
x3::symbols_parser<char_encoding::unicode, int> foo = {{U"a1", 1}, {U"a2", 2}, {U"a3", 3}};
x3::shared_symbols_parser<char_encoding::unicode, int> foo = {{U"a1", 1}, {U"a2", 2}, {U"a3", 3}};
int r;
BOOST_TEST((test_attr(U"a3", foo, r)));

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2013 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -10,13 +11,16 @@
#include <boost/spirit/home/x3/core/parse.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/utility/string_view.hpp>
#include <string_view>
#include <iostream>
namespace spirit_test
{
template <typename Char, typename Parser>
bool test(Char const* in, Parser const& p, bool full_match = true)
[[nodiscard]] bool test(
Char const* in, Parser const& p, bool full_match = true
)
{
Char const* last = in;
while (*last)
@@ -25,9 +29,11 @@ namespace spirit_test
&& (!full_match || (in == last));
}
template <typename Char, typename Parser>
bool test(boost::basic_string_view<Char, std::char_traits<Char>> in,
Parser const& p, bool full_match = true)
template <typename Char, typename CharTraits, typename Parser>
[[nodiscard]] bool test(
std::basic_string_view<Char, CharTraits> in,
Parser const& p, bool full_match = true
)
{
auto const last = in.end();
auto pos = in.begin();
@@ -36,8 +42,10 @@ namespace spirit_test
}
template <typename Char, typename Parser, typename Skipper>
bool test(Char const* in, Parser const& p
, Skipper const& s, bool full_match = true)
[[nodiscard]] bool test(
Char const* in, Parser const& p,
Skipper const& s, bool full_match = true
)
{
Char const* last = in;
while (*last)
@@ -47,7 +55,7 @@ namespace spirit_test
}
template <typename Char, typename Parser>
bool test_failure(Char const* in, Parser const& p)
[[nodiscard]] bool test_failure(Char const* in, Parser const& p)
{
Char const * const start = in;
Char const* last = in;
@@ -57,17 +65,20 @@ namespace spirit_test
return !boost::spirit::x3::parse(in, last, p) && (in == start);
}
template <typename Char, typename Parser>
bool test_failure(boost::basic_string_view<Char, std::char_traits<Char>> const in,
Parser const& p)
template <typename Char, typename CharTraits, typename Parser>
[[nodiscard]] bool test_failure(
std::basic_string_view<Char, CharTraits> const in, Parser const& p
)
{
auto pos = in.begin();
return !boost::spirit::x3::parse(pos, in.end(), p) && (pos == in.begin());
}
template <typename Char, typename Parser, typename Attr>
bool test_attr(Char const* in, Parser const& p
, Attr& attr, bool full_match = true)
[[nodiscard]] bool test_attr(
Char const* in, Parser const& p,
Attr& attr, bool full_match = true
)
{
Char const* last = in;
while (*last)
@@ -77,8 +88,10 @@ namespace spirit_test
}
template <typename Char, typename Parser, typename Attr, typename Skipper>
bool test_attr(Char const* in, Parser const& p
, Attr& attr, Skipper const& s, bool full_match = true)
[[nodiscard]] bool test_attr(
Char const* in, Parser const& p,
Attr& attr, Skipper const& s, bool full_match = true
)
{
Char const* last = in;
while (*last)
@@ -88,8 +101,10 @@ namespace spirit_test
}
template <typename Char, typename Parser>
bool binary_test(Char const* in, std::size_t size, Parser const& p,
bool full_match = true)
[[nodiscard]] bool binary_test(
Char const* in, std::size_t size, Parser const& p,
bool full_match = true
)
{
Char const* last = in + size;
return boost::spirit::x3::parse(in, last, p)
@@ -97,8 +112,10 @@ namespace spirit_test
}
template <typename Char, typename Parser, typename Skipper>
bool binary_test(Char const* in, std::size_t size, Parser const& p,
Skipper const& s, bool full_match = true)
[[nodiscard]] bool binary_test(
Char const* in, std::size_t size, Parser const& p,
Skipper const& s, bool full_match = true
)
{
Char const* last = in + size;
return boost::spirit::x3::phrase_parse(in, last, p, s)
@@ -106,8 +123,10 @@ namespace spirit_test
}
template <typename Char, typename Parser, typename Attr>
bool binary_test_attr(Char const* in, std::size_t size, Parser const& p,
Attr& attr, bool full_match = true)
[[nodiscard]] bool binary_test_attr(
Char const* in, std::size_t size, Parser const& p,
Attr& attr, bool full_match = true
)
{
Char const* last = in + size;
return boost::spirit::x3::parse(in, last, p, attr)
@@ -115,20 +134,21 @@ namespace spirit_test
}
template <typename Char, typename Parser, typename Attr, typename Skipper>
bool binary_test_attr(Char const* in, std::size_t size, Parser const& p,
Attr& attr, Skipper const& s, bool full_match = true)
[[nodiscard]] bool binary_test_attr(
Char const* in, std::size_t size, Parser const& p,
Attr& attr, Skipper const& s, bool full_match = true
)
{
Char const* last = in + size;
return boost::spirit::x3::phrase_parse(in, last, p, s, attr)
&& (!full_match || (in == last));
}
template <typename... T>
constexpr bool always_true(T&&...) { return true; }
[[nodiscard]] constexpr bool always_true(T&&...) { return true; }
template <typename Parser>
constexpr bool test_ctors(Parser const& p)
[[nodiscard]] constexpr bool test_ctors(Parser const& p)
{
return always_true(
static_cast<Parser>(static_cast<Parser&&>( // test move ctor

View File

@@ -1,5 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,7 +9,6 @@
#include <boost/phoenix.hpp>
#include <boost/unordered_map.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/cstdint.hpp>
#include <boost/foreach.hpp>
#include <boost/array.hpp>
#include <boost/scoped_array.hpp>
@@ -22,10 +22,12 @@
#include <string>
#include <map>
#include <cstdint>
// We place the data here. Each line comprises various fields
typedef std::vector<std::string> ucd_line;
typedef std::vector<ucd_line> ucd_vector;
typedef std::vector<ucd_line>::iterator ucd_iterator;
using ucd_line = std::vector<std::string>;
using ucd_vector = std::vector<ucd_line>;
using ucd_iterator = std::vector<ucd_line>::iterator;
// spirit and phoenix using declarations
using boost::spirit::qi::parse;
@@ -40,9 +42,9 @@ using boost::phoenix::push_back;
using boost::phoenix::ref;
// basic unsigned types
using boost::uint8_t;
using boost::uint16_t;
using boost::uint32_t;
using std::uint8_t;
using std::uint16_t;
using std::uint32_t;
enum code_action
{
@@ -535,15 +537,16 @@ void print_head(Out& out)
out
<< "/*=============================================================================\n"
<< " Copyright (c) 2001-2011 Joel de Guzman\n"
<< " Copyright (c) 2025 Nana Sakisaka\n"
<< "\n"
<< " Distributed under the Boost Software License, Version 1.0. (See accompanying\n"
<< " file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n"
<< "\n"
<< " AUTOGENERATED. DO NOT EDIT!!!\n"
<< "==============================================================================*/\n"
<< "#include <boost/cstdint.hpp>\n"
<< "#include <cstdint>\n"
<< "\n"
<< "namespace boost { namespace spirit { namespace ucd { namespace detail\n"
<< "namespace boost::spirit::x3::unicode::detail\n"
<< "{"
;
}
@@ -553,7 +556,7 @@ void print_tail(Out& out)
{
out
<< "\n"
<< "}}}} // namespace boost::spirit::unicode::detail\n"
<< "} // boost::spirit::x3::unicode::detail\n"
;
}
@@ -561,10 +564,10 @@ char const* get_int_type_name(int size)
{
switch (size)
{
case 1: return "::boost::uint8_t";
case 2: return "::boost::uint16_t";
case 4: return "::boost::uint32_t";
case 5: return "::boost::uint64_t";
case 1: return "std::uint8_t";
case 2: return "std::uint16_t";
case 4: return "std::uint32_t";
case 5: return "std::uint64_t";
default: BOOST_ASSERT(false); return 0; // invalid size
};
}
@@ -588,7 +591,7 @@ void print_file(Out& out, Builder& builder, int field_width, char const* name)
out
<< "\n"
<< " static const ::boost::uint8_t " << name << "_stage1[] = {\n"
<< " inline constexpr std::uint8_t " << name << "_stage1[] = {\n"
<< "\n"
;
@@ -600,7 +603,7 @@ void print_file(Out& out, Builder& builder, int field_width, char const* name)
<< " };"
<< "\n"
<< "\n"
<< " static const " << int_name << ' ' << name << "_stage2[] = {"
<< " inline constexpr " << int_name << ' ' << name << "_stage2[] = {"
;
int block_n = 0;
@@ -621,9 +624,9 @@ void print_file(Out& out, Builder& builder, int field_width, char const* name)
out
<< "\n"
<< " inline " << int_name << ' ' << name << "_lookup(::boost::uint32_t ch)\n"
<< " [[nodiscard]] constexpr " << int_name << ' ' << name << "_lookup(std::uint32_t ch) noexcept\n"
<< " {\n"
<< " ::boost::uint32_t block_offset = " << name << "_stage1[ch / " << block_size << "] * " << block_size << ";\n"
<< " std::uint32_t block_offset = " << name << "_stage1[ch / " << block_size << "] * " << block_size << ";\n"
<< " return " << name << "_stage2[block_offset + ch % " << block_size << "];\n"
<< " }\n"
;
@@ -666,6 +669,4 @@ int main()
builder.collect("UnicodeData.txt", 12, assign_code_value);
print_file(out, builder, 6, "uppercase");
}
return 0;
}