mirror of
https://github.com/boostorg/spirit.git
synced 2026-01-19 04:42:11 +00:00
Use concepts for attribute category overload resolution (#812)
* Use concepts for attribute category overload resolution
`x3::traits::move_to`: Dump tag dispatching and use concepts for
overload resolution. This drastically improves compilation speed and
prints significantly concise errors on ill-formed programs, thanks to
the reduced nesting level on the entire control flow of X3. Also
partially (but not yet completely) improves #346 due to reduced MPL usage.
`x3::detail::parse_into_container`: Ditto.
`support/traits/optional_traits.hpp`:
`BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL`: new macro.
Default to `boost::optional` unless above macro is defined as `0`. Implements
`std::optional` handling regardless of the value; fixes #270.
Note that most test suites are intentionally not defining above macro as `1`
(yet) to make sure the change does not break existing codes.
`x3::optional`: Ideally this should've split into a separate PR, but the
new attribute category handling requires the overhaul on this.
`core/proxy.hpp`: Removed. `x3::optional` was the only derived parser
which used this feature for years. We shouldn't support any overly
generic 'core' features whose extandable use case is unknown even to the
core components.
`extract_int`, etc.: Adjusted to properly "move" the local attribute
variable before passing it to `x3::traits::move_to`.
`char_parser`: Ditto, but this constructs temporary value instead of
applying `std::as_const`. Const references are costly for primitive type
like `Char` thus prvalue should be constructed here.
tests: No semantic changes intended. All changes exists solely for
adapting to the new attribute category handling (implementation details.)
* Fix incorrect `noexcept` specification
* Compensate for potential GCC bug on constraint satisfaction
It turns out that GCC 14 does not like the form below, resulting
in silently defining the flipped value (!) without raising any sort of
hard/soft errors in well-formed code.
```
struct S : std::bool_constant<requires(...) { ... }> {};
```
* Use the correct path to retrieve action cache
<638ed79f9d/restore (ensuring-proper-restores-and-save-happen-across-the-actions)>
> It is very important to use the same key and path that were used by either actions/cache or actions/cache/save while saving the cache.
This commit is contained in:
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@@ -228,6 +228,7 @@ jobs:
|
||||
key: ${{ steps.env-info.outputs.BOOST_RELEASE_VERSION_NAME }}-${{ matrix.os.name }}-${{ matrix.os.version }}-${{ matrix.compiler.toolset }}-${{ matrix.compiler.version }}-${{ matrix.cpp_version.name }}-${{ matrix.build_type.name }}
|
||||
path: |
|
||||
${{ steps.env-info.outputs.BOOST_ROOT }}
|
||||
!${{ steps.env-info.outputs.BOOST_ROOT }}/.git
|
||||
|
||||
- name: Clone upstream Boost libraries
|
||||
if: steps.cache-boost.outputs.cache-hit != 'true'
|
||||
|
||||
@@ -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)
|
||||
@@ -12,6 +13,8 @@
|
||||
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
|
||||
#include <boost/spirit/home/x3/support/no_case.hpp>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -28,7 +31,7 @@ namespace boost { namespace spirit { namespace x3
|
||||
x3::skip_over(first, last, context);
|
||||
if (first != last && this->derived().test(*first, context))
|
||||
{
|
||||
x3::traits::move_to(*first, attr);
|
||||
x3::traits::move_to(std::iter_value_t<Iterator>{*first}, attr);
|
||||
++first;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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,8 +8,6 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM)
|
||||
#define BOOST_SPIRIT_X3_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/pseudo_attribute.hpp>
|
||||
@@ -16,14 +15,23 @@
|
||||
#include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
#include <boost/spirit/home/x3/core/parser.hpp>
|
||||
|
||||
#include <boost/fusion/include/at_key.hpp>
|
||||
#include <boost/fusion/include/front.hpp>
|
||||
#include <boost/fusion/include/back.hpp>
|
||||
#include <boost/variant/apply_visitor.hpp>
|
||||
#include <iterator> // for std::make_move_iterator
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
// TODO: remove Boost.Variant usage
|
||||
#include <boost/variant/variant.hpp>
|
||||
#include <boost/variant/apply_visitor.hpp>
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
|
||||
#include <ranges>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost::spirit::x3::detail
|
||||
{
|
||||
template <typename Attribute, typename Value>
|
||||
struct saver_visitor;
|
||||
@@ -33,277 +41,265 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
struct save_to_assoc_attr
|
||||
{
|
||||
template <typename Value, typename Attribute>
|
||||
static void call(const Key, Value& value, Attribute& attr)
|
||||
static constexpr void call(Key const&, Value&& value, Attribute& attr)
|
||||
noexcept(noexcept(traits::move_to(std::move(value), fusion::at_key<Key>(attr))))
|
||||
{
|
||||
traits::move_to(value, fusion::at_key<Key>(attr));
|
||||
static_assert(std::is_rvalue_reference_v<Value&&>);
|
||||
traits::move_to(std::move(value), fusion::at_key<Key>(attr));
|
||||
}
|
||||
};
|
||||
|
||||
// save to associative fusion container where Key
|
||||
// is variant over possible keys
|
||||
template <typename ...T>
|
||||
struct save_to_assoc_attr<variant<T...> >
|
||||
template <typename... Ts>
|
||||
struct save_to_assoc_attr<variant<Ts...>>
|
||||
{
|
||||
typedef variant<T...> variant_t;
|
||||
|
||||
template <typename Value, typename Attribute>
|
||||
static void call(const variant_t key, Value& value, Attribute& attr)
|
||||
static constexpr void call(variant<Ts...> const& key, Value&& value, Attribute& attr)
|
||||
{
|
||||
apply_visitor(saver_visitor<Attribute, Value>(attr, value), key);
|
||||
static_assert(std::is_rvalue_reference_v<Value&&>);
|
||||
boost::apply_visitor(saver_visitor<Attribute, Value>(attr, std::move(value)), key);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Attribute, typename Value>
|
||||
struct saver_visitor : boost::static_visitor<void>
|
||||
{
|
||||
saver_visitor(Attribute& attr, Value& value)
|
||||
: attr(attr), value(value) {};
|
||||
constexpr saver_visitor(Attribute& attr, Value&& value) noexcept
|
||||
: attr(attr)
|
||||
, value(std::move(value))
|
||||
{};
|
||||
|
||||
Attribute& attr;
|
||||
Value& value;
|
||||
Value&& value;
|
||||
|
||||
template <typename Key>
|
||||
void operator()(Key) const
|
||||
constexpr void operator()(Key const& key) const
|
||||
noexcept(noexcept(save_to_assoc_attr<Key>::call(key, std::move(value), attr)))
|
||||
{
|
||||
save_to_assoc_attr<Key>::call(Key(), value,attr);
|
||||
save_to_assoc_attr<Key>::call(key, std::move(value), attr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Parser, typename Container, typename Context>
|
||||
struct parser_accepts_container
|
||||
: traits::is_substitute<
|
||||
typename traits::attribute_of<Parser, Context>::type
|
||||
, Container
|
||||
>
|
||||
: traits::is_substitute<traits::attribute_of_t<Parser, Context>, Container>
|
||||
{};
|
||||
|
||||
template <typename Parser, typename Container, typename Context>
|
||||
constexpr bool parser_accepts_container_v = parser_accepts_container<Parser, Container, Context>::value;
|
||||
|
||||
template <typename Parser>
|
||||
struct parse_into_container_base_impl
|
||||
{
|
||||
private:
|
||||
|
||||
// Parser has attribute (synthesize; Attribute is a container)
|
||||
template <typename Iterator, typename Context
|
||||
, typename RContext, typename Attribute>
|
||||
static bool call_synthesize_x(
|
||||
Parser const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
|
||||
requires (!parser_accepts_container_v<Parser, Attribute, Context>)
|
||||
[[nodiscard]] static constexpr bool
|
||||
call_synthesize(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
) // never noexcept (requires container insertion)
|
||||
{
|
||||
// synthesized attribute needs to be value initialized
|
||||
using value_type = typename traits::container_value<Attribute>::type;
|
||||
value_type val{};
|
||||
using value_type = traits::container_value_t<Attribute>;
|
||||
value_type val; // default-initialize
|
||||
|
||||
static_assert(Parsable<Parser, It, Se, Context, RContext, value_type>);
|
||||
if (!parser.parse(first, last, context, rcontext, val))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// push the parsed value into our attribute
|
||||
traits::push_back(attr, static_cast<value_type&&>(val));
|
||||
traits::push_back(attr, std::move(val));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parser has attribute (synthesize; Attribute is a container)
|
||||
template <typename Iterator, typename Context
|
||||
, typename RContext, typename Attribute>
|
||||
static bool call_synthesize_x(
|
||||
Parser const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
|
||||
requires parser_accepts_container_v<Parser, Attribute, Context>
|
||||
[[nodiscard]] static constexpr bool
|
||||
call_synthesize(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
) noexcept(is_nothrow_parsable_v<Parser, It, Se, Context, RContext, Attribute>)
|
||||
{
|
||||
static_assert(Parsable<Parser, It, Se, Context, RContext, Attribute>);
|
||||
return parser.parse(first, last, context, rcontext, attr);
|
||||
}
|
||||
|
||||
// Parser has attribute (synthesize; Attribute is a container)
|
||||
template <typename Iterator, typename Context
|
||||
, typename RContext, typename Attribute>
|
||||
static bool call_synthesize(
|
||||
Parser const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr)
|
||||
// Parser has attribute && it is NOT fusion sequence
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
|
||||
requires
|
||||
traits::has_attribute_v<Parser, Context> &&
|
||||
(!fusion::traits::is_sequence<Attribute>::value)
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
)
|
||||
{
|
||||
typedef
|
||||
parser_accepts_container<Parser, Attribute, Context>
|
||||
parser_accepts_container;
|
||||
|
||||
return call_synthesize_x(parser, first, last, context, rcontext, attr
|
||||
, parser_accepts_container());
|
||||
// TODO: reduce call stack while keeping maintainability
|
||||
return parse_into_container_base_impl::call_synthesize(parser, first, last, context, rcontext, attr);
|
||||
}
|
||||
|
||||
// Parser has attribute (synthesize; Attribute is a single element fusion sequence)
|
||||
template <typename Iterator, typename Context
|
||||
, typename RContext, typename Attribute>
|
||||
static bool call_synthesize_into_fusion_seq(Parser const& parser
|
||||
, Iterator& first, Iterator const& last, Context const& context
|
||||
, RContext& rcontext, Attribute& attr, mpl::false_ /* is_associative */)
|
||||
// Parser has attribute && it is fusion sequence (NOT associative)
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
|
||||
requires
|
||||
traits::has_attribute_v<Parser, Context> &&
|
||||
fusion::traits::is_sequence<Attribute>::value &&
|
||||
(!fusion::traits::is_associative<Attribute>::value)
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
) noexcept(noexcept(parse_into_container_base_impl::call_synthesize(parser, first, last, context, rcontext, fusion::front(attr))))
|
||||
{
|
||||
static_assert(traits::has_size<Attribute, 1>::value,
|
||||
"Expecting a single element fusion sequence");
|
||||
return call_synthesize(parser, first, last, context, rcontext,
|
||||
fusion::front(attr));
|
||||
static_assert(traits::has_size_v<Attribute, 1>, "Expecting a single element fusion sequence");
|
||||
// TODO: reduce call stack while keeping maintainability
|
||||
return parse_into_container_base_impl::call_synthesize(parser, first, last, context, rcontext, fusion::front(attr));
|
||||
}
|
||||
|
||||
// Parser has attribute (synthesize; Attribute is fusion map sequence)
|
||||
template <typename Iterator, typename Context, typename RContext, typename Attribute>
|
||||
static bool call_synthesize_into_fusion_seq(
|
||||
Parser const& parser
|
||||
, Iterator& first, Iterator const& last, Context const& context
|
||||
, RContext& rcontext, Attribute& attr, mpl::true_ /*is_associative*/)
|
||||
// Parser has attribute && it is fusion sequence (associative)
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
|
||||
requires
|
||||
traits::has_attribute_v<Parser, Context> &&
|
||||
fusion::traits::is_sequence<Attribute>::value &&
|
||||
fusion::traits::is_associative<Attribute>::value
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
) // never noexcept (requires container insertion)
|
||||
{
|
||||
using attribute_type = typename traits::attribute_of<Parser, Context>::type;
|
||||
static_assert(traits::has_size<attribute_type, 2>::value,
|
||||
"To parse directly into fusion map parser must produce 2 element attr");
|
||||
using attribute_type = traits::attribute_of_t<Parser, Context>;
|
||||
static_assert(traits::has_size_v<attribute_type, 2>, "To parse directly into fusion map, parser must produce 2 element attr");
|
||||
|
||||
// use type of first element of attribute as key
|
||||
using key = typename std::remove_reference<
|
||||
typename fusion::result_of::front<attribute_type>::type>::type;
|
||||
|
||||
attribute_type attr_;
|
||||
attribute_type attr_; // default-initialize
|
||||
static_assert(Parsable<Parser, It, Se, Context, RContext, attribute_type>);
|
||||
if (!parser.parse(first, last, context, rcontext, attr_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
save_to_assoc_attr<key>::call(fusion::front(attr_), fusion::back(attr_), attr);
|
||||
// Use the type of first element of attribute as key
|
||||
using key = std::remove_reference_t<
|
||||
typename fusion::result_of::front<attribute_type>::type
|
||||
>;
|
||||
|
||||
save_to_assoc_attr<key>::call(std::move(fusion::front(attr_)), std::move(fusion::back(attr_)), attr);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Context, typename RContext, typename Attribute>
|
||||
static bool call_synthesize_dispatch_by_seq(Parser const& parser
|
||||
, Iterator& first, Iterator const& last, Context const& context
|
||||
, RContext& rcontext, Attribute& attr, mpl::true_ /*is_sequence*/)
|
||||
{
|
||||
return call_synthesize_into_fusion_seq(
|
||||
parser, first, last, context, rcontext, attr
|
||||
, fusion::traits::is_associative<Attribute>());
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Context, typename RContext, typename Attribute>
|
||||
static bool call_synthesize_dispatch_by_seq(Parser const& parser
|
||||
, Iterator& first, Iterator const& last, Context const& context
|
||||
, RContext& rcontext, Attribute& attr, mpl::false_ /*is_sequence*/)
|
||||
{
|
||||
return call_synthesize(parser, first, last, context, rcontext, attr);
|
||||
}
|
||||
|
||||
// Parser has attribute (synthesize)
|
||||
template <typename Iterator, typename Context, typename RContext, typename Attribute>
|
||||
static bool call(Parser const& parser
|
||||
, Iterator& first, Iterator const& last, Context const& context
|
||||
, RContext& rcontext, Attribute& attr, mpl::true_)
|
||||
{
|
||||
return call_synthesize_dispatch_by_seq(parser, first, last, context, rcontext, attr
|
||||
, fusion::traits::is_sequence<Attribute>());
|
||||
}
|
||||
|
||||
// Parser has no attribute (pass unused)
|
||||
template <typename Iterator, typename Context, typename RContext, typename Attribute>
|
||||
static bool call(
|
||||
Parser const& parser
|
||||
, Iterator& first, Iterator const& last, Context const& context
|
||||
, RContext& rcontext, Attribute& /* attr */, mpl::false_)
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
|
||||
requires (!traits::has_attribute_v<Parser, Context>)
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& /* attr */
|
||||
) noexcept(is_nothrow_parsable_v<Parser, It, Se, Context, RContext, unused_type>)
|
||||
{
|
||||
static_assert(Parsable<Parser, It, Se, Context, RContext, unused_type>);
|
||||
return parser.parse(first, last, context, rcontext, unused);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
template <typename Iterator, typename Context, typename RContext, typename Attribute>
|
||||
static bool call(Parser const& parser
|
||||
, Iterator& first, Iterator const& last, Context const& context
|
||||
, RContext& rcontext, Attribute& attr)
|
||||
{
|
||||
return call(parser, first, last, context, rcontext, attr
|
||||
, mpl::bool_<traits::has_attribute<Parser, Context>::value>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Parser, typename Context, typename RContext, typename Enable = void>
|
||||
struct parse_into_container_impl : parse_into_container_base_impl<Parser> {};
|
||||
|
||||
template <typename Parser, typename Iterator, typename Container, typename Context>
|
||||
struct parser_attr_is_substitute_for_container_value
|
||||
: traits::is_substitute<
|
||||
typename traits::pseudo_attribute<
|
||||
Context
|
||||
, typename traits::attribute_of<Parser, Context>::type
|
||||
, Iterator
|
||||
>::type
|
||||
, typename traits::container_value<Container>::type
|
||||
>
|
||||
{};
|
||||
|
||||
template <typename Parser, typename Context, typename RContext>
|
||||
struct parse_into_container_impl<Parser, Context, RContext,
|
||||
typename enable_if<traits::handles_container<Parser, Context>>::type>
|
||||
requires traits::handles_container_v<Parser, Context>
|
||||
struct parse_into_container_impl<Parser, Context, RContext>
|
||||
{
|
||||
template <typename Iterator, typename Attribute>
|
||||
static bool call(
|
||||
Parser const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
|
||||
static constexpr bool pass_attibute_as_is = std::disjunction_v<
|
||||
parser_accepts_container<Parser, Attribute, Context>,
|
||||
|
||||
std::negation<traits::is_substitute< // parser attribute is substitute for container value?
|
||||
traits::pseudo_attribute_t<
|
||||
Context,
|
||||
traits::attribute_of_t<Parser, Context>,
|
||||
It, Se
|
||||
>,
|
||||
traits::container_value_t<Attribute>
|
||||
>>
|
||||
>;
|
||||
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
|
||||
requires (!pass_attibute_as_is<It, Se, Attribute>)
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
) noexcept(noexcept(parse_into_container_base_impl<Parser>::call(
|
||||
parser, first, last, context, rcontext, attr
|
||||
)))
|
||||
{
|
||||
return parse_into_container_base_impl<Parser>::call(
|
||||
parser, first, last, context, rcontext, attr);
|
||||
parser, first, last, context, rcontext, attr
|
||||
);
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static bool call(
|
||||
Parser const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, unused_type attr, mpl::true_)
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se>
|
||||
requires pass_attibute_as_is<It, Se, unused_type>
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, unused_type
|
||||
) noexcept(is_nothrow_parsable_v<Parser, It, Se, Context, RContext, unused_type>)
|
||||
{
|
||||
return parser.parse(first, last, context, rcontext, attr);
|
||||
static_assert(Parsable<Parser, It, Se, Context, RContext, unused_type>);
|
||||
return parser.parse(first, last, context, rcontext, unused);
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Attribute>
|
||||
static bool call(
|
||||
Parser const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
|
||||
requires pass_attibute_as_is<It, Se, Attribute>
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
) // never noexcept (requires container insertion)
|
||||
{
|
||||
static_assert(Parsable<Parser, It, Se, Context, RContext, Attribute>);
|
||||
if (traits::is_empty(attr))
|
||||
{
|
||||
return parser.parse(first, last, context, rcontext, attr);
|
||||
Attribute rest;
|
||||
bool r = parser.parse(first, last, context, rcontext, rest);
|
||||
if (r)
|
||||
traits::append(attr, std::make_move_iterator(rest.begin()),
|
||||
std::make_move_iterator(rest.end()));
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Attribute>
|
||||
static bool call(Parser const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr)
|
||||
Attribute rest; // default-initialize
|
||||
if (!parser.parse(first, last, context, rcontext, rest))
|
||||
{
|
||||
typedef parser_accepts_container<
|
||||
Parser, Attribute, Context>
|
||||
parser_accepts_container;
|
||||
|
||||
typedef parser_attr_is_substitute_for_container_value<
|
||||
Parser, Iterator, Attribute, Context>
|
||||
parser_attr_is_substitute_for_container_value;
|
||||
|
||||
typedef mpl::or_<
|
||||
parser_accepts_container
|
||||
, mpl::not_<parser_attr_is_substitute_for_container_value>>
|
||||
pass_attibute_as_is;
|
||||
|
||||
return call(parser, first, last, context, rcontext, attr,
|
||||
pass_attibute_as_is());
|
||||
return false;
|
||||
}
|
||||
traits::append(
|
||||
attr,
|
||||
std::make_move_iterator(std::ranges::begin(rest)),
|
||||
std::make_move_iterator(std::ranges::end(rest))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Parser, typename Iterator, typename Context
|
||||
, typename RContext, typename Attribute>
|
||||
bool parse_into_container(
|
||||
Parser const& parser
|
||||
, Iterator& first, Iterator const& last, Context const& context
|
||||
, RContext& rcontext, Attribute& attr)
|
||||
template <
|
||||
typename Parser, std::forward_iterator It, std::sentinel_for<It> Se,
|
||||
typename Context, typename RContext, typename Attribute
|
||||
>
|
||||
[[nodiscard]] constexpr bool
|
||||
parse_into_container(
|
||||
Parser const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
) noexcept(noexcept(parse_into_container_impl<Parser, Context, RContext>::call(
|
||||
parser, first, last, context, rcontext, attr
|
||||
)))
|
||||
{
|
||||
return parse_into_container_impl<Parser, Context, RContext>::call(
|
||||
parser, first, last, context, rcontext, attr);
|
||||
parser, first, last, context, rcontext, attr
|
||||
);
|
||||
}
|
||||
|
||||
}}}}
|
||||
} // boost::spirit::x3::detail
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace boost::spirit::x3
|
||||
Attribute& attr
|
||||
)
|
||||
{
|
||||
static_assert(Parsable<Parser, It, Se, unused_type, unused_type, Attribute>);
|
||||
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, unused_type, unused_type, Attribute>);
|
||||
return as_parser(std::forward<Parser>(p)).parse(first, last, unused, unused, attr);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace boost::spirit::x3
|
||||
auto failure_ctx = x3::make_context<expectation_failure_tag>(expect_failure);
|
||||
using Context = decltype(failure_ctx);
|
||||
|
||||
static_assert(Parsable<Parser, It, Se, Context, unused_type, Attribute>);
|
||||
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
|
||||
|
||||
It first = std::ranges::begin(range);
|
||||
Se last = std::ranges::end(range);
|
||||
@@ -128,7 +128,7 @@ namespace boost::spirit::x3
|
||||
auto failure_ctx = x3::make_context<expectation_failure_tag>(res.expect_failure);
|
||||
using Context = decltype(failure_ctx);
|
||||
|
||||
static_assert(Parsable<Parser, It, Se, Context, unused_type, Attribute>);
|
||||
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
|
||||
|
||||
It first = std::ranges::begin(range);
|
||||
Se last = std::ranges::end(range);
|
||||
@@ -198,7 +198,7 @@ namespace boost::spirit::x3
|
||||
{
|
||||
auto skipper_ctx = x3::make_context<skipper_tag>(as_parser(std::forward<Skipper>(s)));
|
||||
using Context = decltype(skipper_ctx);
|
||||
static_assert(Parsable<Parser, It, Se, Context, unused_type, Attribute>);
|
||||
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
|
||||
|
||||
bool const ok = as_parser(std::forward<Parser>(p)).parse(first, last, skipper_ctx, unused, attr);
|
||||
if (post_skip == skip_flag::post_skip)
|
||||
@@ -290,7 +290,7 @@ namespace boost::spirit::x3
|
||||
auto ctx = x3::make_context<expectation_failure_tag>(expect_failure, skipper_ctx);
|
||||
|
||||
using Context = decltype(ctx);
|
||||
static_assert(Parsable<Parser, It, Se, Context, unused_type, Attribute>);
|
||||
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
|
||||
|
||||
It first = std::ranges::begin(range);
|
||||
Se last = std::ranges::end(range);
|
||||
@@ -332,7 +332,7 @@ namespace boost::spirit::x3
|
||||
auto ctx = x3::make_context<expectation_failure_tag>(res.expect_failure, skipper_ctx);
|
||||
|
||||
using Context = decltype(ctx);
|
||||
static_assert(Parsable<Parser, It, Se, Context, unused_type, Attribute>);
|
||||
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
|
||||
|
||||
It first = std::ranges::begin(range);
|
||||
Se last = std::ranges::end(range);
|
||||
|
||||
@@ -363,8 +363,17 @@ namespace boost::spirit::x3
|
||||
typename RContext,
|
||||
typename Attribute
|
||||
>
|
||||
struct is_parsable : std::bool_constant<
|
||||
requires(std::remove_cvref_t<as_parser_t<Parser>> const& p) // mutable parser use case is currently unknown
|
||||
struct is_parsable
|
||||
{
|
||||
static_assert(X3Subject<Parser>);
|
||||
static_assert(!std::is_reference_v<It>);
|
||||
static_assert(std::forward_iterator<It>);
|
||||
static_assert(std::sentinel_for<Se, It>);
|
||||
static_assert(!std::is_reference_v<Context>);
|
||||
static_assert(!std::is_reference_v<RContext>);
|
||||
static_assert(!std::is_reference_v<Attribute>);
|
||||
|
||||
static constexpr bool value = requires(Parser const& p) // mutable parser use case is currently unknown
|
||||
{
|
||||
{
|
||||
p.parse(
|
||||
@@ -375,15 +384,7 @@ namespace boost::spirit::x3
|
||||
std::declval<Attribute&>() // attr
|
||||
)
|
||||
} -> std::convertible_to<bool>;
|
||||
}
|
||||
> {
|
||||
static_assert(X3Subject<Parser>);
|
||||
static_assert(!std::is_reference_v<It>);
|
||||
static_assert(std::forward_iterator<It>);
|
||||
static_assert(std::sentinel_for<Se, It>);
|
||||
static_assert(!std::is_reference_v<Context>);
|
||||
static_assert(!std::is_reference_v<RContext>);
|
||||
static_assert(!std::is_reference_v<Attribute>);
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Parser, typename It, typename Se, typename Context, typename RContext, typename Attribute>
|
||||
@@ -402,8 +403,17 @@ namespace boost::spirit::x3
|
||||
typename RContext,
|
||||
typename Attribute
|
||||
>
|
||||
struct is_nothrow_parsable : std::bool_constant<
|
||||
requires(std::remove_cvref_t<as_parser_t<Parser>> const& p) // mutable parser use case is currently unknown
|
||||
struct is_nothrow_parsable
|
||||
{
|
||||
static_assert(X3Subject<Parser>);
|
||||
static_assert(!std::is_reference_v<It>);
|
||||
static_assert(std::forward_iterator<It>);
|
||||
static_assert(std::sentinel_for<Se, It>);
|
||||
static_assert(!std::is_reference_v<Context>);
|
||||
static_assert(!std::is_reference_v<RContext>);
|
||||
static_assert(!std::is_reference_v<Attribute>);
|
||||
|
||||
static constexpr bool value = requires(Parser const& p) // mutable parser use case is currently unknown
|
||||
{
|
||||
{
|
||||
p.parse(
|
||||
@@ -414,8 +424,8 @@ namespace boost::spirit::x3
|
||||
std::declval<Attribute&>() // attr
|
||||
)
|
||||
} noexcept -> std::convertible_to<bool>;
|
||||
}
|
||||
> {};
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Parser, typename It, typename Se, typename Context, typename RContext, typename Attribute>
|
||||
constexpr bool is_nothrow_parsable_v = is_nothrow_parsable<Parser, It, Se, Context, RContext, Attribute>::value;
|
||||
@@ -439,7 +449,7 @@ namespace boost::spirit::x3
|
||||
template <typename Parser, class It, class Se>
|
||||
concept X3Parser =
|
||||
X3Subject<Parser> &&
|
||||
is_parsable_v<Parser, It, Se, unused_type, unused_type, unused_type>;
|
||||
is_parsable_v<as_parser_plain_t<Parser>, It, Se, unused_type, unused_type, unused_type>;
|
||||
|
||||
|
||||
// The runtime type info that can be obtained via `x3::what(p)`.
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2017 wanghan02
|
||||
Copyright (c) 2024 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_PROXY_FEBRUARY_1_2013_0211PM)
|
||||
#define BOOST_SPIRIT_X3_PROXY_FEBRUARY_1_2013_0211PM
|
||||
|
||||
#include <boost/spirit/home/x3/support/expectation.hpp>
|
||||
#include <boost/spirit/home/x3/core/parser.hpp>
|
||||
#include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3
|
||||
{
|
||||
template <typename Subject, typename Derived>
|
||||
struct proxy : unary_parser<Subject, Derived>
|
||||
{
|
||||
static bool const is_pass_through_unary = true;
|
||||
|
||||
constexpr proxy(Subject const& subject)
|
||||
: unary_parser<Subject, Derived>(subject) {}
|
||||
|
||||
// Overload this when appropriate. The proxy parser will pick up
|
||||
// the most derived overload.
|
||||
template <typename Iterator, typename Context
|
||||
, typename RuleContext, typename Attribute, typename Category>
|
||||
bool parse_subject(Iterator& first, Iterator const& last
|
||||
, Context const& context, RuleContext& rcontext, Attribute& attr, Category) const
|
||||
{
|
||||
this->subject.parse(first, last, context, rcontext, attr);
|
||||
return !has_expectation_failure(context);
|
||||
}
|
||||
|
||||
// Main entry point.
|
||||
template <typename Iterator, typename Context
|
||||
, typename RuleContext, typename Attribute>
|
||||
bool parse(Iterator& first, Iterator const& last
|
||||
, Context const& context, RuleContext& rcontext, Attribute& attr) const
|
||||
{
|
||||
return this->derived().parse_subject(first, last, context, rcontext, attr
|
||||
, typename traits::attribute_category<Attribute>::type());
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <boost/spirit/home/x3/support/traits/transform_attribute.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
@@ -19,18 +20,25 @@ namespace boost::spirit::x3
|
||||
namespace detail
|
||||
{
|
||||
struct parser_id;
|
||||
}
|
||||
} // detail
|
||||
|
||||
template <typename Exposed, typename Transformed>
|
||||
requires std::is_assignable_v<Exposed&, Transformed&&>
|
||||
struct default_transform_attribute
|
||||
{
|
||||
typedef Transformed type;
|
||||
using type = Transformed;
|
||||
|
||||
static Transformed pre(Exposed&) { return Transformed(); }
|
||||
|
||||
static void post(Exposed& val, Transformed&& attribute)
|
||||
static constexpr Transformed pre(Exposed&)
|
||||
noexcept(std::is_nothrow_default_constructible_v<Transformed>)
|
||||
{
|
||||
traits::move_to(std::forward<Transformed>(attribute), val);
|
||||
return Transformed{};
|
||||
}
|
||||
|
||||
template <typename TransformedT>
|
||||
static constexpr void post(Exposed& val, TransformedT&& attribute)
|
||||
noexcept(noexcept(traits::move_to(std::forward<TransformedT>(attribute), val)))
|
||||
{
|
||||
traits::move_to(std::forward<TransformedT>(attribute), val);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -38,13 +46,14 @@ namespace boost::spirit::x3
|
||||
template <typename Attribute>
|
||||
struct default_transform_attribute<Attribute, Attribute>
|
||||
{
|
||||
typedef Attribute& type;
|
||||
static Attribute& pre(Attribute& val) { return val; }
|
||||
static void post(Attribute&, Attribute const&) {}
|
||||
using type = Attribute&;
|
||||
static constexpr Attribute& pre(Attribute& val) noexcept { return val; }
|
||||
static constexpr void post(Attribute&, Attribute const&) noexcept {}
|
||||
};
|
||||
|
||||
// main specialization for x3
|
||||
template <typename Exposed, typename Transformed, typename Enable = void>
|
||||
requires std::is_assignable_v<Exposed&, Transformed&&>
|
||||
struct transform_attribute
|
||||
: default_transform_attribute<Exposed, Transformed> {};
|
||||
|
||||
@@ -52,9 +61,9 @@ namespace boost::spirit::x3
|
||||
template <>
|
||||
struct transform_attribute<unused_type, unused_type>
|
||||
{
|
||||
typedef unused_type type;
|
||||
static unused_type pre(unused_type) { return unused; }
|
||||
static void post(unused_type, unused_type) {}
|
||||
using type = unused_type;
|
||||
static constexpr unused_type pre(unused_type) noexcept { return unused; }
|
||||
static constexpr void post(unused_type, unused_type) noexcept {}
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -76,18 +85,19 @@ namespace boost::spirit::x3
|
||||
template <typename Attribute>
|
||||
struct transform_attribute<Attribute const, unused_type>
|
||||
: transform_attribute<unused_type, unused_type> {};
|
||||
|
||||
} // boost::spirit::x3
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
template <typename Exposed, typename Transformed>
|
||||
requires std::is_assignable_v<Exposed&, Transformed&&>
|
||||
struct transform_attribute<Exposed, Transformed, x3::detail::parser_id>
|
||||
: x3::transform_attribute<Exposed, Transformed>
|
||||
{
|
||||
static_assert(!std::is_reference<Exposed>::value,
|
||||
"Exposed cannot be a reference type");
|
||||
static_assert(!std::is_reference<Transformed>::value,
|
||||
"Transformed cannot be a reference type");
|
||||
static_assert(!std::is_reference_v<Exposed>, "Exposed cannot be a reference type");
|
||||
static_assert(!std::is_reference_v<Transformed>, "Transformed cannot be a reference type");
|
||||
};
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -14,42 +15,42 @@
|
||||
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/variant_has_substitute.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/variant_find_substitute.hpp>
|
||||
#include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
|
||||
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/spirit/home/x3/core/parser.hpp>
|
||||
#include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
|
||||
|
||||
#include <boost/fusion/include/front.hpp>
|
||||
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3
|
||||
namespace boost::spirit::x3
|
||||
{
|
||||
template <typename Left, typename Right>
|
||||
struct alternative;
|
||||
}}}
|
||||
} // boost::spirit::x3
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
namespace boost::spirit::x3::detail
|
||||
{
|
||||
struct pass_variant_unused
|
||||
{
|
||||
typedef unused_type type;
|
||||
using type = unused_type;
|
||||
|
||||
template <typename T>
|
||||
static unused_type
|
||||
call(T&)
|
||||
[[nodiscard]] static constexpr unused_type
|
||||
call(T&) noexcept
|
||||
{
|
||||
return unused_type();
|
||||
return unused_type{};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Attribute>
|
||||
struct pass_variant_used
|
||||
{
|
||||
typedef Attribute& type;
|
||||
using type = Attribute&;
|
||||
|
||||
static Attribute&
|
||||
call(Attribute& v)
|
||||
[[nodiscard]] static constexpr Attribute&
|
||||
call(Attribute& v) noexcept
|
||||
{
|
||||
return v;
|
||||
}
|
||||
@@ -58,56 +59,44 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
template <>
|
||||
struct pass_variant_used<unused_type> : pass_variant_unused {};
|
||||
|
||||
template <typename Parser, typename Attribute, typename Context
|
||||
, typename Enable = void>
|
||||
template <typename Parser, typename Attribute, typename Context, typename Enable = void>
|
||||
struct pass_parser_attribute
|
||||
{
|
||||
typedef typename
|
||||
traits::attribute_of<Parser, Context>::type
|
||||
attribute_type;
|
||||
typedef typename
|
||||
traits::variant_find_substitute<Attribute, attribute_type>::type
|
||||
substitute_type;
|
||||
using attribute_type = traits::attribute_of_t<Parser, Context>;
|
||||
using substitute_type = traits::variant_find_substitute_t<Attribute, attribute_type>;
|
||||
|
||||
typedef typename
|
||||
mpl::if_<
|
||||
is_same<Attribute, substitute_type>
|
||||
, Attribute&
|
||||
, substitute_type
|
||||
>::type
|
||||
type;
|
||||
using type = std::conditional_t<
|
||||
std::is_same_v<Attribute, substitute_type>,
|
||||
Attribute&,
|
||||
substitute_type
|
||||
>;
|
||||
|
||||
template <typename Attribute_>
|
||||
static Attribute_&
|
||||
call(Attribute_& attribute, mpl::true_)
|
||||
requires std::is_same_v<Attribute_, std::remove_reference_t<type>>
|
||||
[[nodiscard]] static constexpr Attribute_&
|
||||
call(Attribute_& attribute) noexcept
|
||||
{
|
||||
return attribute;
|
||||
}
|
||||
|
||||
template <typename Attribute_>
|
||||
static type
|
||||
call(Attribute_&, mpl::false_)
|
||||
requires (!std::is_same_v<Attribute_, std::remove_reference_t<type>>)
|
||||
[[nodiscard]] static type
|
||||
call(Attribute_&)
|
||||
noexcept(std::is_nothrow_default_constructible_v<type>)
|
||||
{
|
||||
return type();
|
||||
}
|
||||
|
||||
template <typename Attribute_>
|
||||
static type
|
||||
call(Attribute_& attribute)
|
||||
{
|
||||
return call(attribute, is_same<Attribute_, typename remove_reference<type>::type>());
|
||||
return type{};
|
||||
}
|
||||
};
|
||||
|
||||
// Pass non-variant attributes as-is
|
||||
template <typename Parser, typename Attribute, typename Context
|
||||
, typename Enable = void>
|
||||
template <typename Parser, typename Attribute, typename Context, typename Enable = void>
|
||||
struct pass_non_variant_attribute
|
||||
{
|
||||
typedef Attribute& type;
|
||||
using type = Attribute&;
|
||||
|
||||
static Attribute&
|
||||
call(Attribute& attribute)
|
||||
[[nodiscard]] constexpr static Attribute&
|
||||
call(Attribute& attribute) noexcept
|
||||
{
|
||||
return attribute;
|
||||
}
|
||||
@@ -115,80 +104,110 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
|
||||
// Unwrap single element sequences
|
||||
template <typename Parser, typename Attribute, typename Context>
|
||||
struct pass_non_variant_attribute<Parser, Attribute, Context,
|
||||
typename enable_if<traits::is_size_one_sequence<Attribute>>::type>
|
||||
requires traits::is_size_one_sequence_v<Attribute>
|
||||
struct pass_non_variant_attribute<Parser, Attribute, Context>
|
||||
{
|
||||
typedef typename remove_reference<
|
||||
typename fusion::result_of::front<Attribute>::type>::type
|
||||
attr_type;
|
||||
|
||||
typedef pass_parser_attribute<Parser, attr_type, Context> pass;
|
||||
typedef typename pass::type type;
|
||||
using attr_type = typename std::remove_reference_t<
|
||||
typename fusion::result_of::front<Attribute>::type
|
||||
>;
|
||||
using pass = pass_parser_attribute<Parser, attr_type, Context>;
|
||||
using type = typename pass::type;
|
||||
|
||||
template <typename Attribute_>
|
||||
static type
|
||||
[[nodiscard]] static constexpr type
|
||||
call(Attribute_& attr)
|
||||
noexcept(noexcept(pass::call(fusion::front(attr))))
|
||||
{
|
||||
return pass::call(fusion::front(attr));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Parser, typename Attribute, typename Context>
|
||||
struct pass_parser_attribute<Parser, Attribute, Context,
|
||||
typename enable_if_c<(!traits::is_variant<Attribute>::value)>::type>
|
||||
requires (!traits::is_variant_v<Attribute>)
|
||||
struct pass_parser_attribute<Parser, Attribute, Context>
|
||||
: pass_non_variant_attribute<Parser, Attribute, Context>
|
||||
{};
|
||||
|
||||
template <typename Parser, typename Context>
|
||||
struct pass_parser_attribute<Parser, unused_type, Context>
|
||||
: pass_variant_unused {};
|
||||
: pass_variant_unused
|
||||
{};
|
||||
|
||||
template <typename Parser, typename Attribute, typename Context>
|
||||
struct pass_variant_attribute :
|
||||
mpl::if_c<traits::has_attribute<Parser, Context>::value
|
||||
, pass_parser_attribute<Parser, Attribute, Context>
|
||||
, pass_variant_unused>::type
|
||||
{
|
||||
};
|
||||
struct pass_variant_attribute
|
||||
: std::conditional_t<
|
||||
traits::has_attribute_v<Parser, Context>,
|
||||
pass_parser_attribute<Parser, Attribute, Context>,
|
||||
pass_variant_unused
|
||||
>
|
||||
{};
|
||||
|
||||
template <typename L, typename R, typename Attribute, typename Context>
|
||||
struct pass_variant_attribute<alternative<L, R>, Attribute, Context> :
|
||||
mpl::if_c<traits::has_attribute<alternative<L, R>, Context>::value
|
||||
, pass_variant_used<Attribute>
|
||||
, pass_variant_unused>::type
|
||||
{
|
||||
};
|
||||
struct pass_variant_attribute<alternative<L, R>, Attribute, Context>
|
||||
: std::conditional_t<
|
||||
traits::has_attribute_v<alternative<L, R>, Context>,
|
||||
pass_variant_used<Attribute>,
|
||||
pass_variant_unused
|
||||
>
|
||||
{};
|
||||
|
||||
template <bool Condition>
|
||||
struct move_if
|
||||
{
|
||||
template<typename T1, typename T2>
|
||||
static void call(T1& /* attr_ */, T2& /* attr */) {}
|
||||
};
|
||||
template <typename Parser, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Attribute>
|
||||
using parse_alternative_pseudo_t = traits::pseudo_attribute<
|
||||
Context, typename pass_variant_attribute<Parser, Attribute, Context>::type, It, Se
|
||||
>;
|
||||
|
||||
template <>
|
||||
struct move_if<true>
|
||||
template <typename Parser, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Attribute>
|
||||
constexpr bool is_reference_pseudo_type = std::is_reference_v<typename parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::type>;
|
||||
|
||||
template <typename Parser, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
|
||||
requires is_reference_pseudo_type<Parser, It, Se, Context, Attribute>
|
||||
[[nodiscard]] constexpr bool
|
||||
parse_alternative(
|
||||
Parser const& p, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attribute
|
||||
) noexcept(
|
||||
noexcept(parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::call(
|
||||
first, last, pass_variant_attribute<Parser, Attribute, Context>::call(attribute)
|
||||
)) &&
|
||||
is_nothrow_parsable_v<
|
||||
Parser, It, Se, Context, RContext,
|
||||
std::remove_reference_t<typename parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::type>
|
||||
>
|
||||
)
|
||||
{
|
||||
template<typename T1, typename T2>
|
||||
static void call(T1& attr_, T2& attribute)
|
||||
{
|
||||
traits::move_to(attr_, attribute);
|
||||
using pass = pass_variant_attribute<Parser, Attribute, Context>;
|
||||
using pseudo = traits::pseudo_attribute<Context, typename pass::type, It, Se>;
|
||||
typename pseudo::type attr_ = pseudo::call(first, last, pass::call(attribute));
|
||||
return p.parse(first, last, context, rcontext, attr_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Parser, typename Iterator, typename Context
|
||||
, typename RContext, typename Attribute>
|
||||
bool parse_alternative(Parser const& p, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attribute)
|
||||
template <typename Parser, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
|
||||
requires (!is_reference_pseudo_type<Parser, It, Se, Context, Attribute>)
|
||||
[[nodiscard]] constexpr bool
|
||||
parse_alternative(
|
||||
Parser const& p, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attribute
|
||||
) noexcept(
|
||||
noexcept(parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::call(
|
||||
first, last, pass_variant_attribute<Parser, Attribute, Context>::call(attribute)
|
||||
)) &&
|
||||
is_nothrow_parsable_v<
|
||||
Parser, It, Se, Context, RContext,
|
||||
std::remove_reference_t<typename parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::type>
|
||||
> &&
|
||||
noexcept(traits::move_to(
|
||||
std::declval<typename parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::type&&>(),
|
||||
attribute
|
||||
))
|
||||
)
|
||||
{
|
||||
using pass = detail::pass_variant_attribute<Parser, Attribute, Context>;
|
||||
using pseudo = traits::pseudo_attribute<Context, typename pass::type, Iterator>;
|
||||
|
||||
using pass = pass_variant_attribute<Parser, Attribute, Context>;
|
||||
using pseudo = traits::pseudo_attribute<Context, typename pass::type, It, Se>;
|
||||
typename pseudo::type attr_ = pseudo::call(first, last, pass::call(attribute));
|
||||
|
||||
if (p.parse(first, last, context, rcontext, attr_))
|
||||
{
|
||||
move_if<!std::is_reference<decltype(attr_)>::value>::call(attr_, attribute);
|
||||
traits::move_to(std::move(attr_), attribute);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -197,14 +216,14 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
template <typename Subject>
|
||||
struct alternative_helper : unary_parser<Subject, alternative_helper<Subject>>
|
||||
{
|
||||
static bool const is_pass_through_unary = true;
|
||||
static constexpr bool is_pass_through_unary = true;
|
||||
|
||||
using unary_parser<Subject, alternative_helper<Subject>>::unary_parser;
|
||||
|
||||
template <typename Iterator, typename Context
|
||||
, typename RContext, typename Attribute>
|
||||
bool parse(Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr) const
|
||||
template <typename Iterator, typename Context, typename RContext, typename Attribute>
|
||||
[[nodiscard]] constexpr bool parse(
|
||||
Iterator& first, Iterator const& last, Context const& context, RContext& rcontext, Attribute& attr
|
||||
) const noexcept(noexcept(detail::parse_alternative(this->subject, first, last, context, rcontext, attr)))
|
||||
{
|
||||
return detail::parse_alternative(this->subject, first, last, context, rcontext, attr);
|
||||
}
|
||||
@@ -213,39 +232,34 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
template <typename Left, typename Right, typename Context, typename RContext>
|
||||
struct parse_into_container_impl<alternative<Left, Right>, Context, RContext>
|
||||
{
|
||||
typedef alternative<Left, Right> parser_type;
|
||||
using parser_type = alternative<Left, Right>;
|
||||
|
||||
template <typename Iterator, typename Attribute>
|
||||
static bool call(
|
||||
parser_type const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attribute, mpl::false_)
|
||||
{
|
||||
return detail::parse_into_container(parser.left, first, last, context, rcontext, attribute)
|
||||
|| detail::parse_into_container(parser.right, first, last, context, rcontext, attribute);
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Attribute>
|
||||
static bool call(
|
||||
parser_type const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attribute, mpl::true_)
|
||||
requires traits::is_variant_v<traits::container_value_t<Attribute>>
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
parser_type const& parser,
|
||||
Iterator& first, Iterator const& last, Context const& context, RContext& rcontext, Attribute& attribute
|
||||
)
|
||||
{
|
||||
return detail::parse_into_container(alternative_helper<Left>{parser.left}, first, last, context, rcontext, attribute)
|
||||
|| detail::parse_into_container(alternative_helper<Right>{parser.right}, first, last, context, rcontext, attribute);
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Attribute>
|
||||
static bool call(
|
||||
parser_type const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attribute)
|
||||
requires (!traits::is_variant_v<traits::container_value_t<Attribute>>)
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
parser_type const& parser,
|
||||
Iterator& first, Iterator const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attribute
|
||||
)
|
||||
{
|
||||
return call(parser, first, last, context, rcontext, attribute,
|
||||
typename traits::is_variant<typename traits::container_value<Attribute>::type>::type{});
|
||||
return detail::parse_into_container(parser.left, first, last, context, rcontext, attribute)
|
||||
|| detail::parse_into_container(parser.right, first, last, context, rcontext, attribute);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
} // boost::spirit::x3::detail
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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)
|
||||
@@ -25,18 +26,15 @@
|
||||
|
||||
#include <boost/mpl/if.hpp>
|
||||
|
||||
#include <boost/type_traits/add_reference.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <iterator>
|
||||
|
||||
#include <iterator> // for std::make_move_iterator
|
||||
|
||||
namespace boost { namespace spirit { namespace x3
|
||||
namespace boost::spirit::x3
|
||||
{
|
||||
template <typename Left, typename Right>
|
||||
struct sequence;
|
||||
}}}
|
||||
} // boost::spirit::x3
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
namespace boost::spirit::x3::detail
|
||||
{
|
||||
template <typename Parser, typename Context, typename Enable = void>
|
||||
struct sequence_size
|
||||
@@ -358,62 +356,62 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
template <typename Left, typename Right, typename Context, typename RContext>
|
||||
struct parse_into_container_impl<sequence<Left, Right>, Context, RContext>
|
||||
{
|
||||
typedef sequence<Left, Right> parser_type;
|
||||
using parser_type = sequence<Left, Right>;
|
||||
|
||||
template <typename Iterator, typename Attribute>
|
||||
static bool call(
|
||||
parser_type const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
|
||||
template <typename Attribute>
|
||||
static constexpr bool is_container_substitute = traits::is_substitute_v<
|
||||
traits::attribute_of_t<parser_type, Context>,
|
||||
traits::container_value_t<Attribute>
|
||||
>;
|
||||
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
|
||||
requires is_container_substitute<Attribute>
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
parser_type const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
) noexcept(noexcept(parse_into_container_base_impl<parser_type>::call(
|
||||
parser, first, last, context, rcontext, attr
|
||||
)))
|
||||
{
|
||||
return parse_into_container_base_impl<parser_type>::call(
|
||||
parser, first, last, context, rcontext, attr
|
||||
);
|
||||
}
|
||||
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
|
||||
requires (!is_container_substitute<Attribute>)
|
||||
[[nodiscard]] static constexpr bool
|
||||
call(
|
||||
parser_type const& parser, It& first, Se const& last,
|
||||
Context const& context, RContext& rcontext, Attribute& attr
|
||||
) // never noexcept (requires container insertion)
|
||||
{
|
||||
// inform user what went wrong if we jumped here in attempt to
|
||||
// parse incompatible sequence into fusion::map
|
||||
static_assert(!is_same< typename traits::attribute_category<Attribute>::type,
|
||||
traits::associative_attribute>::value,
|
||||
static_assert(
|
||||
!std::is_same_v<traits::attribute_category_t<Attribute>, traits::associative_attribute>,
|
||||
"To parse directly into fusion::map sequence must produce tuple attribute "
|
||||
"where type of first element is existing key in fusion::map and second element "
|
||||
"is value to be stored under that key");
|
||||
"is value to be stored under that key"
|
||||
);
|
||||
|
||||
Attribute attr_{};
|
||||
if (!parse_sequence(parser
|
||||
, first, last, context, rcontext, attr_, traits::container_attribute()))
|
||||
if (!detail::parse_sequence(
|
||||
parser, first, last, context, rcontext, attr_, traits::container_attribute()
|
||||
))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
traits::append(attr, std::make_move_iterator(traits::begin(attr_)),
|
||||
std::make_move_iterator(traits::end(attr_)));
|
||||
traits::append(
|
||||
attr,
|
||||
std::make_move_iterator(traits::begin(attr_)),
|
||||
std::make_move_iterator(traits::end(attr_))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Attribute>
|
||||
static bool call(
|
||||
parser_type const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
|
||||
{
|
||||
return parse_into_container_base_impl<parser_type>::call(
|
||||
parser, first, last, context, rcontext, attr);
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Attribute>
|
||||
static bool call(
|
||||
parser_type const& parser
|
||||
, Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr)
|
||||
{
|
||||
typedef typename
|
||||
traits::attribute_of<parser_type, Context>::type
|
||||
attribute_type;
|
||||
|
||||
typedef typename
|
||||
traits::container_value<Attribute>::type
|
||||
value_type;
|
||||
|
||||
return call(parser, first, last, context, rcontext, attr
|
||||
, typename traits::is_substitute<attribute_type, value_type>::type());
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
} // boost::spirit::x3::detail
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2001-2011 Hartmut Kaiser
|
||||
Copyright (c) 2017 wanghan02
|
||||
Copyright (c) 2024 Nana Sakisaka
|
||||
Copyright (c) 2024-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,7 +10,7 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_OPTIONAL_MARCH_23_2007_1117PM)
|
||||
#define BOOST_SPIRIT_X3_OPTIONAL_MARCH_23_2007_1117PM
|
||||
|
||||
#include <boost/spirit/home/x3/core/proxy.hpp>
|
||||
#include <boost/spirit/home/x3/core/parser.hpp>
|
||||
#include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
|
||||
#include <boost/spirit/home/x3/support/expectation.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
|
||||
@@ -18,72 +18,101 @@
|
||||
#include <boost/spirit/home/x3/support/traits/optional_traits.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost::spirit::x3
|
||||
{
|
||||
template <typename Subject>
|
||||
struct optional : proxy<Subject, optional<Subject>>
|
||||
struct optional : unary_parser<Subject, optional<Subject>>
|
||||
{
|
||||
typedef proxy<Subject, optional<Subject>> base_type;
|
||||
static bool const is_pass_through_unary = false;
|
||||
static bool const handles_container = true;
|
||||
using base_type = unary_parser<Subject, optional<Subject>>;
|
||||
static constexpr bool is_pass_through_unary = false;
|
||||
static constexpr bool handles_container = true;
|
||||
|
||||
constexpr optional(Subject const& subject)
|
||||
: base_type(subject) {}
|
||||
template <typename SubjectT>
|
||||
requires std::is_constructible_v<Subject, SubjectT>
|
||||
constexpr optional(SubjectT&& subject)
|
||||
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT>)
|
||||
: base_type(std::forward<SubjectT>(subject))
|
||||
{}
|
||||
|
||||
using base_type::parse_subject;
|
||||
|
||||
// Attribute is a container
|
||||
template <typename Iterator, typename Context
|
||||
, typename RContext, typename Attribute>
|
||||
bool parse_subject(Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr
|
||||
, traits::container_attribute) const
|
||||
// catch-all overload
|
||||
template <
|
||||
std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext,
|
||||
typename Attribute // unconstrained
|
||||
>
|
||||
[[nodiscard]] constexpr bool
|
||||
parse(
|
||||
It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr
|
||||
) const
|
||||
noexcept(is_nothrow_parsable_v<Subject, It, Se, Context, RContext, Attribute>)
|
||||
{
|
||||
detail::parse_into_container(
|
||||
this->subject, first, last, context, rcontext, attr);
|
||||
return !has_expectation_failure(context);
|
||||
static_assert(Parsable<Subject, It, Se, Context, RContext, Attribute>);
|
||||
|
||||
// discard [[nodiscard]]
|
||||
(void)this->subject.parse(first, last, context, rcontext, attr);
|
||||
return !x3::has_expectation_failure(context);
|
||||
}
|
||||
|
||||
// Attribute is an optional
|
||||
template <typename Iterator, typename Context
|
||||
, typename RContext, typename Attribute>
|
||||
bool parse_subject(Iterator& first, Iterator const& last
|
||||
, Context const& context, RContext& rcontext, Attribute& attr
|
||||
, traits::optional_attribute) const
|
||||
// container attribute
|
||||
template <
|
||||
std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext,
|
||||
traits::CategorizedAttr<traits::container_attribute> Attribute
|
||||
>
|
||||
[[nodiscard]] constexpr bool
|
||||
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
|
||||
noexcept(noexcept(detail::parse_into_container(this->subject, first, last, context, rcontext, attr)))
|
||||
{
|
||||
typedef typename
|
||||
x3::traits::optional_value<Attribute>::type
|
||||
value_type;
|
||||
// discard [[nodiscard]]
|
||||
(void)detail::parse_into_container(this->subject, first, last, context, rcontext, attr);
|
||||
return !x3::has_expectation_failure(context);
|
||||
}
|
||||
|
||||
// create a local value
|
||||
value_type val{};
|
||||
// optional attribute
|
||||
template <
|
||||
std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext,
|
||||
traits::CategorizedAttr<traits::optional_attribute> Attribute
|
||||
>
|
||||
[[nodiscard]] constexpr bool
|
||||
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
|
||||
noexcept(
|
||||
std::is_nothrow_default_constructible_v<x3::traits::optional_value_t<Attribute>> &&
|
||||
is_nothrow_parsable_v<Subject, It, Se, Context, RContext, x3::traits::optional_value_t<Attribute>> &&
|
||||
noexcept(x3::traits::move_to(std::declval<x3::traits::optional_value_t<Attribute>&&>(), attr))
|
||||
)
|
||||
{
|
||||
using value_type = x3::traits::optional_value_t<Attribute>;
|
||||
value_type val; // default-initialize
|
||||
|
||||
static_assert(Parsable<Subject, It, Se, Context, RContext, value_type>);
|
||||
if (this->subject.parse(first, last, context, rcontext, val))
|
||||
{
|
||||
// assign the parsed value into our attribute
|
||||
x3::traits::move_to(val, attr);
|
||||
|
||||
} else {
|
||||
return !has_expectation_failure(context);
|
||||
}
|
||||
x3::traits::move_to(std::move(val), attr);
|
||||
return true;
|
||||
}
|
||||
|
||||
return !x3::has_expectation_failure(context);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Subject>
|
||||
constexpr optional<typename extension::as_parser<Subject>::value_type>
|
||||
operator-(Subject const& subject)
|
||||
template <X3Subject Subject>
|
||||
[[nodiscard]] constexpr optional<as_parser_plain_t<Subject>>
|
||||
operator-(Subject&& subject)
|
||||
noexcept(is_parser_nothrow_constructible_v<optional<as_parser_plain_t<Subject>>, Subject>)
|
||||
{
|
||||
return { as_parser(subject) };
|
||||
return { as_parser(std::forward<Subject>(subject)) };
|
||||
}
|
||||
}}}
|
||||
} // boost::spirit::x3
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
template <typename Subject, typename Context>
|
||||
struct attribute_of<x3::optional<Subject>, Context>
|
||||
: build_optional<
|
||||
typename attribute_of<Subject, Context>::type> {};
|
||||
}}}}
|
||||
: build_optional<attribute_of_t<Subject, Context>>
|
||||
{};
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
Copyright (c) 2011 Jan Frederick Eick
|
||||
Copyright (c) 2011 Christopher Jefferson
|
||||
Copyright (c) 2006 Stephen Nutt
|
||||
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)
|
||||
@@ -342,7 +343,7 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
|
||||
if (count + leading_zeros >= MinDigits)
|
||||
{
|
||||
traits::move_to(val, attr);
|
||||
traits::move_to(std::move(val), attr);
|
||||
first = it;
|
||||
return true;
|
||||
}
|
||||
@@ -444,7 +445,7 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
{
|
||||
if (count == 0) // must have at least one digit
|
||||
return false;
|
||||
traits::move_to(val, attr);
|
||||
traits::move_to(std::move(val), attr);
|
||||
first = it;
|
||||
return true;
|
||||
}
|
||||
@@ -458,7 +459,7 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
|
||||
, SPIRIT_NUMERIC_INNER_LOOP, _)
|
||||
}
|
||||
|
||||
traits::move_to(val, attr);
|
||||
traits::move_to(std::move(val), attr);
|
||||
first = it;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2011 Jan Frederick Eick
|
||||
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)
|
||||
@@ -77,7 +78,7 @@ namespace boost { namespace spirit { namespace x3
|
||||
T attr;
|
||||
if (call(first, last, attr))
|
||||
{
|
||||
traits::move_to(attr, attr_);
|
||||
traits::move_to(std::move(attr), attr_);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -131,7 +132,7 @@ namespace boost { namespace spirit { namespace x3
|
||||
T attr;
|
||||
if (call(first, last, attr))
|
||||
{
|
||||
traits::move_to(attr, attr_);
|
||||
traits::move_to(std::move(attr), attr_);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 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)
|
||||
@@ -8,22 +8,22 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_ATTRIBUTE_CATEGORY_JAN_4_2012_1150AM)
|
||||
#define BOOST_SPIRIT_X3_ATTRIBUTE_CATEGORY_JAN_4_2012_1150AM
|
||||
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/mpl/logical.hpp>
|
||||
#include <boost/mpl/eval_if.hpp>
|
||||
#include <boost/fusion/include/is_sequence.hpp>
|
||||
#include <boost/fusion/support/category_of.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/is_variant.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/is_range.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/optional_traits.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3
|
||||
#include <boost/fusion/include/is_sequence.hpp>
|
||||
#include <boost/fusion/support/category_of.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost::spirit::x3
|
||||
{
|
||||
struct unused_type;
|
||||
}}}
|
||||
} // boost::spirit::x3
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
struct unused_attribute {};
|
||||
struct plain_attribute {};
|
||||
@@ -36,60 +36,89 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct attribute_category
|
||||
: mpl::identity<plain_attribute> {};
|
||||
{
|
||||
using type = plain_attribute;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category<T const> : attribute_category<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category<T&> : attribute_category<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category<T const&> : attribute_category<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category<T&&> : attribute_category<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category<T const&&> : attribute_category<T> {};
|
||||
|
||||
template <typename T>
|
||||
using attribute_category_t = typename attribute_category<T>::type;
|
||||
|
||||
template <>
|
||||
struct attribute_category<unused_type>
|
||||
: mpl::identity<unused_attribute> {};
|
||||
{
|
||||
using type = unused_attribute;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct attribute_category<unused_type const>
|
||||
: mpl::identity<unused_attribute> {};
|
||||
template <typename T, typename AttributeCategoryTag>
|
||||
concept CategorizedAttr = std::is_same_v<typename attribute_category<T>::type, AttributeCategoryTag>;
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category< T
|
||||
, typename enable_if<
|
||||
typename mpl::eval_if<
|
||||
fusion::traits::is_sequence<T>
|
||||
, fusion::traits::is_associative<T>
|
||||
, mpl::false_
|
||||
>::type >::type >
|
||||
: mpl::identity<associative_attribute> {};
|
||||
concept NonUnusedAttr = !CategorizedAttr<T, unused_attribute>;
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category< T
|
||||
, typename enable_if<
|
||||
mpl::and_<
|
||||
fusion::traits::is_sequence<T>
|
||||
, mpl::not_<fusion::traits::is_associative<T> >
|
||||
> >::type >
|
||||
: mpl::identity<tuple_attribute> {};
|
||||
requires
|
||||
fusion::traits::is_sequence<T>::value &&
|
||||
fusion::traits::is_associative<T>::value
|
||||
struct attribute_category<T>
|
||||
{
|
||||
using type = associative_attribute;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category<T,
|
||||
typename enable_if<traits::is_variant<T>>::type>
|
||||
: mpl::identity<variant_attribute> {};
|
||||
requires
|
||||
fusion::traits::is_sequence<T>::value &&
|
||||
(!fusion::traits::is_associative<T>::value)
|
||||
struct attribute_category<T>
|
||||
{
|
||||
using type = tuple_attribute;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category<T,
|
||||
typename enable_if<traits::is_optional<T>>::type>
|
||||
: mpl::identity<optional_attribute> {};
|
||||
requires is_variant_v<T>
|
||||
struct attribute_category<T>
|
||||
{
|
||||
using type = variant_attribute;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category<T,
|
||||
typename enable_if<traits::is_range<T>>::type>
|
||||
: mpl::identity<range_attribute> {};
|
||||
requires is_optional_v<T>
|
||||
struct attribute_category<T>
|
||||
{
|
||||
using type = optional_attribute;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct attribute_category< T
|
||||
, typename enable_if<
|
||||
mpl::and_<
|
||||
traits::is_container<T>
|
||||
, mpl::not_<fusion::traits::is_sequence<T> >
|
||||
, mpl::not_<traits::is_range<T> >
|
||||
> >::type >
|
||||
: mpl::identity<container_attribute> {};
|
||||
requires is_range_v<T>
|
||||
struct attribute_category<T>
|
||||
{
|
||||
using type = range_attribute;
|
||||
};
|
||||
|
||||
}}}}
|
||||
template <typename T>
|
||||
requires
|
||||
(!traits::is_range_v<T>) &&
|
||||
traits::is_container_v<T> &&
|
||||
(!fusion::traits::is_sequence<T>::value)
|
||||
struct attribute_category<T>
|
||||
{
|
||||
using type = container_attribute;
|
||||
};
|
||||
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2013 Agustin Berge
|
||||
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)
|
||||
@@ -9,11 +9,9 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_ATTRIBUTE_OF_JAN_7_2012_0914AM)
|
||||
#define BOOST_SPIRIT_X3_ATTRIBUTE_OF_JAN_7_2012_0914AM
|
||||
|
||||
#include <boost/spirit/home/x3/support/utility/sfinae.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Get the attribute type of a component. By default, this gets the
|
||||
@@ -24,31 +22,37 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
template <typename Component, typename Context, typename Enable = void>
|
||||
struct attribute_of;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Component, typename Context, typename Enable = void>
|
||||
struct default_attribute_of;
|
||||
using attribute_of_t = typename attribute_of<Component, Context>::type;
|
||||
|
||||
template <typename Component, typename Context>
|
||||
struct default_attribute_of<Component, Context,
|
||||
typename disable_if_substitution_failure<
|
||||
typename Component::attribute_type>::type>
|
||||
: mpl::identity<typename Component::attribute_type> {};
|
||||
|
||||
template <typename Component, typename Context>
|
||||
struct default_attribute_of<Component, Context,
|
||||
typename disable_if_substitution_failure<
|
||||
typename Component::template attribute<Context>::type>::type>
|
||||
: Component::template attribute<Context> {};
|
||||
|
||||
template <typename Component, typename Context>
|
||||
struct default_attribute_of<Component, Context,
|
||||
typename enable_if_c<Component::is_pass_through_unary>::type>
|
||||
: attribute_of<typename Component::subject_type, Context>{};
|
||||
requires requires {
|
||||
typename Component::attribute_type;
|
||||
}
|
||||
struct attribute_of<Component, Context>
|
||||
{
|
||||
using type = typename Component::attribute_type;
|
||||
};
|
||||
|
||||
template <typename Component, typename Context, typename Enable>
|
||||
struct attribute_of : detail::default_attribute_of<Component, Context> {};
|
||||
}}}}
|
||||
template <typename Component, typename Context>
|
||||
requires requires {
|
||||
typename Component::template attribute<Context>::type;
|
||||
}
|
||||
struct attribute_of<Component, Context>
|
||||
{
|
||||
using type = typename Component::template attribute<Context>::type;
|
||||
};
|
||||
|
||||
template <typename Component, typename Context>
|
||||
requires Component::is_pass_through_unary
|
||||
struct attribute_of<Component, Context>
|
||||
{
|
||||
static_assert(requires {
|
||||
typename Component::subject_type;
|
||||
});
|
||||
using type = typename attribute_of<typename Component::subject_type, Context>::type;
|
||||
};
|
||||
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 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)
|
||||
@@ -8,19 +8,20 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_ATTRIBUTE_TYPE_JAN_5_2012_0358PM)
|
||||
#define BOOST_SPIRIT_X3_ATTRIBUTE_TYPE_JAN_5_2012_0358PM
|
||||
|
||||
#include <boost/mpl/identity.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Retrieve the attribute type to use from the given type
|
||||
//
|
||||
// Retrieve the attribute type to use from the given type.
|
||||
// This is needed to extract the correct attribute type from proxy classes
|
||||
// as utilized in FUSION_ADAPT_ADT et. al.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// as utilized in `FUSION_ADAPT_ADT` et. al.
|
||||
template <typename Attribute, typename Enable = void>
|
||||
struct attribute_type : mpl::identity<Attribute> {};
|
||||
struct attribute_type
|
||||
{
|
||||
using type = Attribute;
|
||||
};
|
||||
|
||||
}}}}
|
||||
template <typename Attribute>
|
||||
using attribute_type_t = typename attribute_type<Attribute>::type;
|
||||
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2001-2011 Hartmut Kaiser
|
||||
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)
|
||||
@@ -12,49 +12,55 @@
|
||||
#include <boost/fusion/support/category_of.hpp>
|
||||
#include <boost/spirit/home/x3/support/unused.hpp>
|
||||
#include <boost/fusion/include/deque.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/type_traits/make_void.hpp>
|
||||
|
||||
#include <ranges>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// This file contains some container utils for stl containers.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, typename Enabler = void>
|
||||
struct is_container_impl : mpl::false_ {};
|
||||
|
||||
template <typename T>
|
||||
struct is_container_impl<T, void_t<
|
||||
typename T::value_type, typename T::iterator,
|
||||
typename T::size_type, typename T::reference> > : mpl::true_ {};
|
||||
|
||||
template <typename T, typename Enabler = void>
|
||||
struct is_associative_impl : mpl::false_ {};
|
||||
struct is_container : std::false_type {};
|
||||
|
||||
// TODO: fully replace this trait using std::ranges
|
||||
template <typename T>
|
||||
struct is_associative_impl<T, void_t<typename T::key_type>>
|
||||
: mpl::true_ {};
|
||||
requires
|
||||
//std::ranges::range<T> && // TODO: this breaks `fusion::vector<>`; test case in omit.cpp.
|
||||
requires {
|
||||
typename T::value_type;
|
||||
typename T::iterator;
|
||||
typename T::size_type;
|
||||
typename T::reference;
|
||||
}
|
||||
struct is_container<T> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
using is_container = typename detail::is_container_impl<T>::type;
|
||||
constexpr bool is_container_v = is_container<T>::value;
|
||||
|
||||
template <typename T>
|
||||
using is_associative = typename detail::is_associative_impl<T>::type;
|
||||
concept ContainerAttr = is_container_v<std::remove_cvref_t<T>>;
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct is_associative : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
requires requires {
|
||||
typename T::key_type;
|
||||
}
|
||||
struct is_associative<T> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_associative_v = is_associative<T>::value;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
struct remove_value_const : mpl::identity<T> {};
|
||||
struct remove_value_const : std::type_identity<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct remove_value_const<T const> : remove_value_const<T> {};
|
||||
@@ -62,9 +68,9 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
template <typename F, typename S>
|
||||
struct remove_value_const<std::pair<F, S>>
|
||||
{
|
||||
typedef typename remove_value_const<F>::type first_type;
|
||||
typedef typename remove_value_const<S>::type second_type;
|
||||
typedef std::pair<first_type, second_type> type;
|
||||
using first_type = typename remove_value_const<F>::type;
|
||||
using second_type = typename remove_value_const<S>::type;
|
||||
using type = std::pair<first_type, second_type>;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,6 +80,9 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
: detail::remove_value_const<typename Container::value_type>
|
||||
{};
|
||||
|
||||
template <typename Container>
|
||||
using container_value_t = typename container_value<Container>::type;
|
||||
|
||||
template <typename Container>
|
||||
struct container_value<Container const> : container_value<Container> {};
|
||||
|
||||
@@ -82,32 +91,36 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
// saved to container, we simply return whole fusion::map as is
|
||||
// so that check can be done in traits::is_substitute specialisation
|
||||
template <typename T>
|
||||
struct container_value<T
|
||||
, typename enable_if<typename mpl::eval_if <
|
||||
fusion::traits::is_sequence<T>
|
||||
, fusion::traits::is_associative<T>
|
||||
, mpl::false_ >::type >::type>
|
||||
: mpl::identity<T> {};
|
||||
struct container_value<
|
||||
T,
|
||||
std::enable_if_t<
|
||||
std::conditional_t<
|
||||
fusion::traits::is_sequence<T>::value,
|
||||
fusion::traits::is_associative<T>,
|
||||
std::false_type
|
||||
>::type::value
|
||||
>
|
||||
> : std::type_identity<T> {};
|
||||
|
||||
template <>
|
||||
struct container_value<unused_type> : mpl::identity<unused_type> {};
|
||||
struct container_value<unused_type> : std::type_identity<unused_type> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Container, typename Enable = void>
|
||||
struct container_iterator
|
||||
: mpl::identity<typename Container::iterator> {};
|
||||
: std::type_identity<typename Container::iterator> {};
|
||||
|
||||
template <typename Container>
|
||||
struct container_iterator<Container const>
|
||||
: mpl::identity<typename Container::const_iterator> {};
|
||||
: std::type_identity<typename Container::const_iterator> {};
|
||||
|
||||
template <>
|
||||
struct container_iterator<unused_type>
|
||||
: mpl::identity<unused_type const*> {};
|
||||
: std::type_identity<unused_type const*> {};
|
||||
|
||||
template <>
|
||||
struct container_iterator<unused_type const>
|
||||
: mpl::identity<unused_type const*> {};
|
||||
: std::type_identity<unused_type const*> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Container, typename T>
|
||||
@@ -156,13 +169,13 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
{
|
||||
private:
|
||||
template <typename Iterator>
|
||||
static void insert(Container& c, Iterator first, Iterator last, mpl::false_)
|
||||
static void insert(Container& c, Iterator first, Iterator last, std::false_type)
|
||||
{
|
||||
c.insert(c.end(), first, last);
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static void insert(Container& c, Iterator first, Iterator last, mpl::true_)
|
||||
static void insert(Container& c, Iterator first, Iterator last, std::true_type)
|
||||
{
|
||||
c.insert(first, last);
|
||||
}
|
||||
@@ -190,23 +203,26 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Container, typename Enable = void>
|
||||
struct is_empty_container
|
||||
{
|
||||
static bool call(Container const& c)
|
||||
{
|
||||
return c.empty();
|
||||
}
|
||||
};
|
||||
struct is_empty_container;
|
||||
|
||||
template <typename Container>
|
||||
inline bool is_empty(Container const& c)
|
||||
[[nodiscard]] constexpr bool is_empty(unused_type) noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <ContainerAttr Container>
|
||||
[[nodiscard]] constexpr bool is_empty(Container const& c) noexcept
|
||||
{
|
||||
return is_empty_container<Container>::call(c);
|
||||
}
|
||||
|
||||
inline bool is_empty(unused_type)
|
||||
template <ContainerAttr Container>
|
||||
requires requires {
|
||||
std::ranges::empty(std::declval<Container const&>());
|
||||
}
|
||||
[[nodiscard]] constexpr bool is_empty(Container const& c) noexcept
|
||||
{
|
||||
return true;
|
||||
return std::ranges::empty(c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -324,17 +340,17 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct build_container : mpl::identity<std::vector<T>> {};
|
||||
struct build_container : std::type_identity<std::vector<T>> {};
|
||||
|
||||
template <typename T>
|
||||
struct build_container<boost::fusion::deque<T> > : build_container<T> {};
|
||||
|
||||
template <>
|
||||
struct build_container<unused_type> : mpl::identity<unused_type> {};
|
||||
struct build_container<unused_type> : std::type_identity<unused_type> {};
|
||||
|
||||
template <>
|
||||
struct build_container<char> : mpl::identity<std::string> {};
|
||||
struct build_container<char> : std::type_identity<std::string> {};
|
||||
|
||||
}}}}
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2011 Hartmut Kaiser
|
||||
Copyright (c) 2013 Agustin Berge
|
||||
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,20 +9,21 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_HANDLES_CONTAINER_DEC_18_2010_0920AM)
|
||||
#define BOOST_SPIRIT_X3_HANDLES_CONTAINER_DEC_18_2010_0920AM
|
||||
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Whether a component handles container attributes intrinsically
|
||||
// (or whether container attributes need to be split up separately).
|
||||
// By default, this gets the Component's handles_container nested value.
|
||||
// Components may specialize this if such a handles_container is not
|
||||
// readily available (e.g. expensive to compute at compile time).
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Component, typename Context, typename Enable = void>
|
||||
struct handles_container : mpl::bool_<Component::handles_container> {};
|
||||
struct handles_container : std::bool_constant<Component::handles_container> {};
|
||||
|
||||
}}}}
|
||||
template <typename Component, typename Context>
|
||||
constexpr bool handles_container_v = handles_container<Component, Context>::value;
|
||||
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2013 Agustin Berge
|
||||
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)
|
||||
@@ -10,50 +10,54 @@
|
||||
#define BOOST_SPIRIT_X3_HAS_ATTRIBUTE_JUN_6_2012_1714PM
|
||||
|
||||
#include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
|
||||
#include <boost/spirit/home/x3/support/utility/sfinae.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/mpl/not.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost::spirit::x3
|
||||
{
|
||||
struct unused_type;
|
||||
}}}
|
||||
} // boost::spirit::x3
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TODO: make these 'Component' depend on the concept.
|
||||
// It is currently hard to implement due to circular dependency.
|
||||
|
||||
// Whether a component has an attribute. By default, this compares the
|
||||
// component attribute against unused_type. If the component provides a
|
||||
// nested constant expression has_attribute as a hint, that value is used
|
||||
// instead. Components may specialize this.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Component, typename Context, typename Enable = void>
|
||||
struct has_attribute;
|
||||
|
||||
namespace detail
|
||||
struct has_attribute
|
||||
{
|
||||
template <typename Component, typename Context, typename Enable = void>
|
||||
struct default_has_attribute
|
||||
: mpl::not_<is_same<unused_type,
|
||||
typename attribute_of<Component, Context>::type>> {};
|
||||
static_assert(requires {
|
||||
typename attribute_of<Component, Context>::type;
|
||||
});
|
||||
static constexpr bool value = !std::is_same_v<attribute_of_t<Component, Context>, unused_type>;
|
||||
};
|
||||
|
||||
template <typename Component, typename Context>
|
||||
struct default_has_attribute<Component, Context,
|
||||
typename disable_if_substitution_failure<
|
||||
mpl::bool_<Component::has_attribute>>::type>
|
||||
: mpl::bool_<Component::has_attribute> {};
|
||||
constexpr bool has_attribute_v = has_attribute<Component, Context>::value;
|
||||
|
||||
template <typename Component, typename Context>
|
||||
struct default_has_attribute<Component, Context,
|
||||
typename enable_if_c<Component::is_pass_through_unary>::type>
|
||||
: has_attribute<typename Component::subject_type, Context> {};
|
||||
requires requires {
|
||||
{ Component::has_attribute } -> std::same_as<bool>;
|
||||
}
|
||||
struct has_attribute<Component, Context>
|
||||
: std::bool_constant<Component::has_attribute>
|
||||
{};
|
||||
|
||||
template <typename Component, typename Context, typename Enable>
|
||||
struct has_attribute : detail::default_has_attribute<Component, Context> {};
|
||||
template <typename Component, typename Context>
|
||||
requires Component::is_pass_through_unary
|
||||
struct has_attribute<Component, Context>
|
||||
{
|
||||
static_assert(requires {
|
||||
typename Component::subject_type;
|
||||
});
|
||||
static constexpr bool value = has_attribute_v<typename Component::subject_type, Context>;
|
||||
};
|
||||
|
||||
}}}}
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2014 Agustin Berge
|
||||
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,26 +9,19 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_IS_PARSER_MAY_20_2013_0235PM)
|
||||
#define BOOST_SPIRIT_X3_IS_PARSER_MAY_20_2013_0235PM
|
||||
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/spirit/home/x3/core/parser.hpp>
|
||||
#include <boost/spirit/home/x3/support/utility/sfinae.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// is_parser<T>: metafunction that evaluates to mpl::true_ if a type T
|
||||
// can be used as a parser, mpl::false_ otherwise
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// is_parser<T>: metafunction that evaluates to `std::true_type` if `T`
|
||||
// models `X3Subject`, `std::false_type` otherwise
|
||||
template <typename T, typename Enable = void>
|
||||
struct is_parser
|
||||
: mpl::false_
|
||||
struct [[deprecated("Use the concept `x3::X3Subject`")]]
|
||||
is_parser : std::bool_constant<X3Subject<T>>
|
||||
{};
|
||||
|
||||
template <typename T>
|
||||
struct is_parser<T, typename disable_if_substitution_failure<
|
||||
typename extension::as_parser<T>::type>::type>
|
||||
: mpl::true_
|
||||
{};
|
||||
}}}}
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 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)
|
||||
@@ -9,6 +9,8 @@
|
||||
#define BOOST_SPIRIT_X3_IS_SUBSTITUTE_JAN_9_2012_1049PM
|
||||
|
||||
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/tuple_traits.hpp>
|
||||
#include <boost/spirit/home/x3/support/traits/optional_traits.hpp>
|
||||
#include <boost/fusion/include/is_sequence.hpp>
|
||||
#include <boost/fusion/include/map.hpp>
|
||||
#include <boost/fusion/include/value_at_key.hpp>
|
||||
@@ -20,140 +22,148 @@
|
||||
#include <boost/mpl/size.hpp>
|
||||
#include <boost/mpl/logical.hpp>
|
||||
#include <boost/mpl/at.hpp>
|
||||
#include <boost/mpl/count_if.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Find out if T can be a (strong) substitute for Attribute
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T, typename Attribute, typename Enable = void>
|
||||
struct is_substitute;
|
||||
|
||||
template <typename T, typename Attribute>
|
||||
constexpr bool is_substitute_v = is_substitute<T, Attribute>::value;
|
||||
|
||||
template <typename Variant, typename Attribute>
|
||||
struct variant_has_substitute;
|
||||
|
||||
// TODO: reduce MPL usage
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, typename Attribute>
|
||||
struct value_type_is_substitute
|
||||
: is_substitute<
|
||||
typename container_value<T>::type
|
||||
, typename container_value<Attribute>::type>
|
||||
: is_substitute<container_value_t<T>, container_value_t<Attribute>>
|
||||
{};
|
||||
|
||||
template <typename T, typename Attribute, typename Enable = void>
|
||||
struct is_substitute_impl : mpl::false_ {};
|
||||
struct is_substitute_impl : std::false_type {};
|
||||
|
||||
template <typename T, typename Attribute>
|
||||
struct is_substitute_impl<T, Attribute,
|
||||
typename enable_if<
|
||||
mpl::and_<
|
||||
requires std::conjunction_v<
|
||||
fusion::traits::is_sequence<T>,
|
||||
fusion::traits::is_sequence<Attribute>,
|
||||
mpl::equal<T, Attribute, is_substitute<mpl::_1, mpl::_2>>
|
||||
fusion::traits::is_sequence<Attribute>
|
||||
>
|
||||
>::type>
|
||||
: mpl::true_ {};
|
||||
struct is_substitute_impl<T, Attribute>
|
||||
: mpl::equal<T, Attribute, is_substitute<mpl::_1, mpl::_2>>
|
||||
{};
|
||||
|
||||
template <typename T, typename Attribute>
|
||||
struct is_substitute_impl<T, Attribute,
|
||||
typename enable_if<
|
||||
mpl::and_<
|
||||
is_container<T>,
|
||||
is_container<Attribute>,
|
||||
value_type_is_substitute<T, Attribute>
|
||||
>
|
||||
>::type>
|
||||
: mpl::true_ {};
|
||||
requires
|
||||
is_container_v<T> &&
|
||||
is_container_v<Attribute>
|
||||
struct is_substitute_impl<T, Attribute>
|
||||
: value_type_is_substitute<T, Attribute>
|
||||
{};
|
||||
|
||||
template <typename T, typename Attribute>
|
||||
struct is_substitute_impl<T, Attribute,
|
||||
typename enable_if<
|
||||
is_variant<Attribute>
|
||||
>::type>
|
||||
requires is_variant_v<Attribute>
|
||||
struct is_substitute_impl<T, Attribute>
|
||||
: variant_has_substitute<Attribute, T>
|
||||
{};
|
||||
}
|
||||
|
||||
template <typename T, typename Attribute, typename Enable /*= void*/>
|
||||
template <typename T, typename Attribute, typename Enable>
|
||||
struct is_substitute
|
||||
: mpl::or_<
|
||||
is_same<T, Attribute>,
|
||||
detail::is_substitute_impl<T, Attribute>> {};
|
||||
: std::disjunction<
|
||||
std::is_same<T, Attribute>,
|
||||
detail::is_substitute_impl<T, Attribute>
|
||||
>
|
||||
{};
|
||||
|
||||
// for reference T
|
||||
template <typename T, typename Attribute, typename Enable>
|
||||
struct is_substitute<T&, Attribute, Enable>
|
||||
: is_substitute<T, Attribute, Enable> {};
|
||||
template <typename T, typename Attribute>
|
||||
struct is_substitute<T&, Attribute>
|
||||
: is_substitute<T, Attribute>
|
||||
{};
|
||||
|
||||
// for reference Attribute
|
||||
template <typename T, typename Attribute, typename Enable>
|
||||
struct is_substitute<T, Attribute&, Enable>
|
||||
: is_substitute<T, Attribute, Enable> {};
|
||||
template <typename T, typename Attribute>
|
||||
struct is_substitute<T, Attribute&>
|
||||
: is_substitute<T, Attribute>
|
||||
{};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Key, typename Value, typename Map>
|
||||
struct has_fusion_kv_in_map : std::false_type {};
|
||||
|
||||
template <typename Key, typename Value, typename Map>
|
||||
requires fusion::result_of::has_key<Map, Key>::value
|
||||
struct has_fusion_kv_in_map<Key, Value, Map> : is_substitute<
|
||||
typename fusion::result_of::value_at_key<Map, Key>::type,
|
||||
Value
|
||||
> {};
|
||||
} // detail
|
||||
|
||||
// 2 element mpl tuple is compatible with fusion::map if:
|
||||
// - it's first element type is existing key in map
|
||||
// - it second element type is compatible to type stored at the key in map
|
||||
template <typename T, typename Attribute>
|
||||
struct is_substitute<T, Attribute
|
||||
, typename enable_if<
|
||||
typename mpl::eval_if<
|
||||
mpl::and_<fusion::traits::is_sequence<T>
|
||||
, fusion::traits::is_sequence<Attribute>>
|
||||
, mpl::and_<traits::has_size<T, 2>
|
||||
, fusion::traits::is_associative<Attribute>>
|
||||
, mpl::false_>::type>::type>
|
||||
|
||||
requires std::conjunction_v<
|
||||
fusion::traits::is_sequence<T>,
|
||||
fusion::traits::is_sequence<Attribute>,
|
||||
traits::has_size<T, 2>,
|
||||
fusion::traits::is_associative<Attribute>
|
||||
>
|
||||
struct is_substitute<T, Attribute>
|
||||
{
|
||||
// checking that "p_key >> p_value" parser can
|
||||
// Checking that "p_key >> p_value" parser can
|
||||
// store it's result in fusion::map attribute
|
||||
typedef typename mpl::at_c<T, 0>::type p_key;
|
||||
typedef typename mpl::at_c<T, 1>::type p_value;
|
||||
using p_key = typename mpl::at_c<T, 0>::type;
|
||||
using p_value = typename mpl::at_c<T, 1>::type;
|
||||
|
||||
// for simple p_key type we just check that
|
||||
// For simple `p_key` type we just check that
|
||||
// such key can be found in attr and that value under that key
|
||||
// matches p_value
|
||||
template <typename Key, typename Value, typename Map>
|
||||
struct has_kv_in_map
|
||||
: mpl::eval_if<
|
||||
fusion::result_of::has_key<Map, Key>
|
||||
, mpl::apply<
|
||||
is_substitute<
|
||||
fusion::result_of::value_at_key<mpl::_1, Key>
|
||||
, Value>
|
||||
, Map>
|
||||
, mpl::false_>
|
||||
{};
|
||||
// matches `p_value`.
|
||||
|
||||
// if p_key is variant over multiple types (as a result of
|
||||
// "(key1|key2|key3) >> p_value" parser) check that all
|
||||
// keys are found in fusion::map attribute and that values
|
||||
// under these keys match p_value
|
||||
// Otherwise, if p_key is variant over multiple types (as a result of
|
||||
// "(key1|key2|key3) >> p_value" parser), check that all
|
||||
// keys are found in `fusion::map` attribute and that values
|
||||
// under these keys match `p_value`.
|
||||
template <typename Variant>
|
||||
struct variant_kv
|
||||
: mpl::equal_to<
|
||||
mpl::size< typename Variant::types>
|
||||
, mpl::size< mpl::filter_view<typename Variant::types
|
||||
, has_kv_in_map<mpl::_1, p_value, Attribute>>>
|
||||
mpl::size<typename Variant::types>,
|
||||
mpl::size<
|
||||
mpl::filter_view<
|
||||
typename Variant::types,
|
||||
detail::has_fusion_kv_in_map<mpl::_1, p_value, Attribute>
|
||||
>
|
||||
>
|
||||
>
|
||||
{};
|
||||
|
||||
typedef typename
|
||||
mpl::eval_if<
|
||||
is_variant<p_key>
|
||||
, variant_kv<p_key>
|
||||
, has_kv_in_map<p_key, p_value, Attribute>
|
||||
>::type
|
||||
type;
|
||||
static constexpr bool value = std::conditional_t<
|
||||
is_variant_v<p_key>,
|
||||
variant_kv<p_key>,
|
||||
detail::has_fusion_kv_in_map<p_key, p_value, Attribute>
|
||||
>::value;
|
||||
};
|
||||
|
||||
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
|
||||
template <typename T, typename Attribute>
|
||||
struct is_substitute<optional<T>, optional<Attribute>>
|
||||
: is_substitute<T, Attribute> {};
|
||||
}}}}
|
||||
struct [[deprecated("Use std::optional")]] is_substitute<boost::optional<T>, boost::optional<Attribute>>
|
||||
: is_substitute<T, Attribute>
|
||||
{};
|
||||
#endif
|
||||
|
||||
template <typename T, typename Attribute>
|
||||
struct is_substitute<std::optional<T>, std::optional<Attribute>>
|
||||
: is_substitute<T, Attribute>
|
||||
{};
|
||||
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 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)
|
||||
@@ -8,34 +8,40 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_IS_VARIANT_JAN_10_2012_0823AM)
|
||||
#define BOOST_SPIRIT_X3_IS_VARIANT_JAN_10_2012_0823AM
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/variant/variant_fwd.hpp> // TODO: remove this
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// By declaring a nested struct in your class/struct, you tell
|
||||
// spirit that it is regarded as a variant type. The minimum
|
||||
// required interface for such a variant is that it has constructors
|
||||
// for various types supported by your variant and a typedef 'types'
|
||||
// which is an mpl sequence of the contained types.
|
||||
// TODO: define a legit concept for determining variant-like types
|
||||
|
||||
template <typename T, typename Enabled = void>
|
||||
struct is_variant : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_variant_v = is_variant<T>::value;
|
||||
|
||||
// By declaring a nested struct named `adapted_variant_tag` in
|
||||
// your class, you tell spirit that it is regarded as a variant type.
|
||||
// The minimum required interface for such a variant is that it has
|
||||
// constructors for various types supported by your variant and a
|
||||
// typedef 'types' which is an mpl sequence of the contained types.
|
||||
// Note (2025): The above spec is obsolete and will change in the near future.
|
||||
//
|
||||
// This is an intrusive interface. For a non-intrusive interface,
|
||||
// use the is_variant trait.
|
||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(adapted_variant_tag)
|
||||
// specialize the is_variant trait.
|
||||
template <typename T>
|
||||
requires requires {
|
||||
typename T::adapted_variant_tag;
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct is_variant
|
||||
: detail::has_adapted_variant_tag<T>
|
||||
struct is_variant<T> : std::true_type
|
||||
{};
|
||||
|
||||
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
||||
struct is_variant<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
|
||||
: mpl::true_
|
||||
: std::true_type
|
||||
{};
|
||||
}}}}
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2013 Agustin Berge
|
||||
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)
|
||||
@@ -17,212 +17,259 @@
|
||||
#include <boost/fusion/include/is_sequence.hpp>
|
||||
#include <boost/fusion/include/front.hpp>
|
||||
#include <boost/fusion/include/move.hpp>
|
||||
#include <boost/fusion/include/copy.hpp>
|
||||
#include <boost/fusion/include/is_sequence.hpp>
|
||||
|
||||
#ifndef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
|
||||
# include <boost/range/iterator_range_core.hpp> // deprecated
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
template <typename Source, typename Dest>
|
||||
inline void move_to(Source&& src, Dest& dest);
|
||||
// Identical types ---------------------------------------
|
||||
//
|
||||
// Note that these overloads must be strictly "more constrained"
|
||||
// than any of the other overloads.
|
||||
//
|
||||
// Such resolution should be possible even without an extra
|
||||
// constraint that checks `std::is_same_v<Source, Dest>`, thanks to
|
||||
// the ordinary overload resolution rules of C++.
|
||||
|
||||
template <typename T>
|
||||
inline void move_to(T& src, T& dest);
|
||||
|
||||
template <typename T>
|
||||
inline void move_to(T const& src, T& dest);
|
||||
|
||||
template <typename T>
|
||||
inline void move_to(T&& src, T& dest);
|
||||
|
||||
template <typename Iterator, typename Dest>
|
||||
inline void move_to(Iterator first, Iterator last, Dest& dest);
|
||||
|
||||
template <typename Dest>
|
||||
inline void move_to(unused_type, Dest&) {}
|
||||
|
||||
template <typename Source>
|
||||
inline void move_to(Source&, unused_type) {}
|
||||
|
||||
inline void move_to(unused_type, unused_type) {}
|
||||
|
||||
template <typename Iterator>
|
||||
inline void
|
||||
move_to(Iterator, Iterator, unused_type) {}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to(Source&, Dest&, unused_attribute) {}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to_plain(Source& src, Dest& dest, mpl::false_) // src is not a single-element tuple
|
||||
requires (!CategorizedAttr<T, unused_attribute>)
|
||||
constexpr void move_to(T const&& src, T& dest)
|
||||
noexcept(std::is_nothrow_assignable_v<T&, T const&&>)
|
||||
{
|
||||
dest = std::move(src);
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to_plain(Source& src, Dest& dest, mpl::true_) // src is a single-element tuple
|
||||
{
|
||||
dest = std::move(fusion::front(src));
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to(Source& src, Dest& dest, plain_attribute)
|
||||
{
|
||||
typename mpl::and_<
|
||||
fusion::traits::is_sequence<Source>,
|
||||
is_size_one_sequence<Source> >
|
||||
is_single_element_sequence;
|
||||
|
||||
move_to_plain(src, dest, is_single_element_sequence);
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline typename enable_if<is_container<Source>>::type
|
||||
move_to(Source& src, Dest& dest, container_attribute)
|
||||
{
|
||||
traits::move_to(src.begin(), src.end(), dest);
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline typename enable_if<
|
||||
mpl::and_<
|
||||
is_same_size_sequence<Dest, Source>,
|
||||
mpl::not_<is_size_one_sequence<Dest> > >
|
||||
>::type
|
||||
move_to(Source& src, Dest& dest, tuple_attribute)
|
||||
{
|
||||
fusion::move(std::move(src), dest);
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline typename enable_if<
|
||||
is_size_one_sequence<Dest>
|
||||
>::type
|
||||
move_to(Source& src, Dest& dest, tuple_attribute)
|
||||
{
|
||||
traits::move_to(src, fusion::front(dest));
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to(Source& src, Dest& dest, variant_attribute, mpl::false_)
|
||||
{
|
||||
dest = std::move(src);
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to_variant_from_single_element_sequence(Source& src, Dest& dest, mpl::false_)
|
||||
{
|
||||
// dest is a variant, src is a single element fusion sequence that the variant
|
||||
// cannot directly hold. We'll try to unwrap the single element fusion sequence.
|
||||
|
||||
// Make sure that the Dest variant can really hold Source
|
||||
static_assert(variant_has_substitute<Dest, typename fusion::result_of::front<Source>::type>::value,
|
||||
"Error! The destination variant (Dest) cannot hold the source type (Source)");
|
||||
|
||||
dest = std::move(fusion::front(src));
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to_variant_from_single_element_sequence(Source& src, Dest& dest, mpl::true_)
|
||||
{
|
||||
// dest is a variant, src is a single element fusion sequence that the variant
|
||||
// *can* directly hold.
|
||||
dest = std::move(src);
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to(Source& src, Dest& dest, variant_attribute, mpl::true_)
|
||||
{
|
||||
move_to_variant_from_single_element_sequence(src, dest, variant_has_substitute<Dest, Source>());
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to(Source& src, Dest& dest, variant_attribute tag)
|
||||
{
|
||||
move_to(src, dest, tag, is_size_one_sequence<Source>());
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void
|
||||
move_to(Source& src, Dest& dest, optional_attribute)
|
||||
{
|
||||
dest = std::move(src);
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline void
|
||||
move_to(Iterator, Iterator, unused_type, unused_attribute) {}
|
||||
|
||||
template <typename Iterator, typename Dest>
|
||||
inline void
|
||||
move_to(Iterator first, Iterator last, Dest& dest, container_attribute)
|
||||
{
|
||||
if (is_empty(dest))
|
||||
dest = Dest(first, last);
|
||||
else
|
||||
append(dest, first, last);
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Dest>
|
||||
inline typename enable_if<
|
||||
is_size_one_sequence<Dest>
|
||||
>::type
|
||||
move_to(Iterator first, Iterator last, Dest& dest, tuple_attribute)
|
||||
{
|
||||
traits::move_to(first, last, fusion::front(dest));
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline void
|
||||
move_to(Iterator first, Iterator last, boost::iterator_range<Iterator>& rng, range_attribute)
|
||||
{
|
||||
rng = {first, last};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
inline void move_to(Source&& src, Dest& dest)
|
||||
{
|
||||
detail::move_to(src, dest, typename attribute_category<Dest>::type());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void move_to(T& src, T& dest)
|
||||
requires (!CategorizedAttr<T, unused_attribute>)
|
||||
constexpr void move_to(T&& src, T& dest)
|
||||
noexcept(std::is_nothrow_assignable_v<T&, T&&>)
|
||||
{
|
||||
BOOST_ASSERT(boost::addressof(src) != boost::addressof(dest));
|
||||
dest = std::move(src);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void move_to(T const& src, T& dest)
|
||||
requires (!CategorizedAttr<T, unused_attribute>)
|
||||
constexpr void move_to(T const& src, T& dest)
|
||||
noexcept(std::is_nothrow_copy_assignable_v<T>)
|
||||
{
|
||||
BOOST_ASSERT(boost::addressof(src) != boost::addressof(dest));
|
||||
dest = src;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void move_to(T&& src, T& dest)
|
||||
requires (!CategorizedAttr<T, unused_attribute>)
|
||||
constexpr void move_to(T&, T&) noexcept
|
||||
{
|
||||
BOOST_ASSERT(boost::addressof(src) != boost::addressof(dest));
|
||||
dest = std::move(src);
|
||||
static_assert(
|
||||
!std::is_const_v<T>,
|
||||
"`x3::move_to(T const&, T const&)` is not allowed"
|
||||
);
|
||||
|
||||
static_assert(
|
||||
false,
|
||||
"lvalue reference detected on the `src` argument of `x3::move_to`. "
|
||||
"The caller is definitely lacking `std::move` or `std::forward`. If you "
|
||||
"intend to *copy* the mutable value, apply `x3::move_to(std::as_const(attr_), attr)`."
|
||||
);
|
||||
// Banned: possible, but bug-prone.
|
||||
// dest = std::move(src);
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Dest>
|
||||
inline void move_to(Iterator first, Iterator last, Dest& dest)
|
||||
// unused_type -------------------------------------------
|
||||
template <typename Source, typename Dest>
|
||||
requires
|
||||
CategorizedAttr<Source, unused_attribute> ||
|
||||
CategorizedAttr<Dest, unused_attribute>
|
||||
constexpr void move_to(Source&&, Dest&) noexcept
|
||||
{
|
||||
// $$$ Use std::move_iterator when iterator is not a const-iterator $$$
|
||||
detail::move_to(first, last, dest, typename attribute_category<Dest>::type());
|
||||
}
|
||||
}}}}
|
||||
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Dest>
|
||||
requires
|
||||
std::is_same_v<std::remove_const_t<Dest>, unused_type>
|
||||
constexpr void
|
||||
move_to(It, Se, Dest&) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
// Category specific --------------------------------------
|
||||
|
||||
template <NonUnusedAttr Source, CategorizedAttr<plain_attribute> Dest>
|
||||
requires is_size_one_sequence_v<Source>
|
||||
constexpr void
|
||||
move_to(Source&& src, Dest& dest)
|
||||
noexcept(noexcept(dest = std::forward_like<Source>(fusion::front(std::forward<Source>(src)))))
|
||||
{
|
||||
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
|
||||
dest = std::forward_like<Source>(fusion::front(std::forward<Source>(src)));
|
||||
}
|
||||
|
||||
template <NonUnusedAttr Source, CategorizedAttr<plain_attribute> Dest>
|
||||
requires (!is_size_one_sequence_v<Source>)
|
||||
constexpr void
|
||||
move_to(Source&& src, Dest& dest)
|
||||
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
|
||||
{
|
||||
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
|
||||
static_assert(std::is_assignable_v<Dest&, Source&&>);
|
||||
dest = std::forward<Source>(src);
|
||||
}
|
||||
|
||||
template <NonUnusedAttr Source, CategorizedAttr<tuple_attribute> Dest>
|
||||
requires
|
||||
is_same_size_sequence_v<Dest, Source> &&
|
||||
(!is_size_one_sequence_v<Dest>)
|
||||
constexpr void
|
||||
move_to(Source&& src, Dest& dest)
|
||||
noexcept(
|
||||
std::is_rvalue_reference_v<Source&&> ?
|
||||
noexcept(fusion::move(std::move(src), dest)) :
|
||||
noexcept(fusion::copy(src, dest))
|
||||
)
|
||||
{
|
||||
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
|
||||
|
||||
if constexpr (std::is_rvalue_reference_v<Source&&>)
|
||||
{
|
||||
fusion::move(std::move(src), dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
fusion::copy(src, dest);
|
||||
}
|
||||
}
|
||||
|
||||
template <NonUnusedAttr Source, CategorizedAttr<variant_attribute> Dest>
|
||||
requires is_size_one_sequence_v<Source> && variant_has_substitute_v<Dest, Source>
|
||||
constexpr void
|
||||
move_to(Source&& src, Dest& dest)
|
||||
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
|
||||
{
|
||||
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
|
||||
|
||||
// dest is a variant, src is a single element fusion sequence that the variant
|
||||
// *can* directly hold.
|
||||
dest = std::forward<Source>(src);
|
||||
}
|
||||
|
||||
template <NonUnusedAttr Source, CategorizedAttr<variant_attribute> Dest>
|
||||
requires is_size_one_sequence_v<Source> && (!variant_has_substitute_v<Dest, Source>)
|
||||
constexpr void
|
||||
move_to(Source&& src, Dest& dest)
|
||||
noexcept(noexcept(dest = std::forward_like<Source>(fusion::front(std::forward<Source>(src)))))
|
||||
{
|
||||
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
|
||||
|
||||
// dest is a variant, src is a single element fusion sequence that the variant
|
||||
// cannot directly hold. We'll try to unwrap the single element fusion sequence.
|
||||
|
||||
// Make sure that the Dest variant can really hold Source
|
||||
static_assert(
|
||||
variant_has_substitute_v<Dest, typename fusion::result_of::front<Source>::type>,
|
||||
"Error! The destination variant (Dest) cannot hold the source type (Source)"
|
||||
);
|
||||
|
||||
dest = std::forward_like<Source>(fusion::front(std::forward<Source>(src)));
|
||||
}
|
||||
|
||||
template <NonUnusedAttr Source, CategorizedAttr<variant_attribute> Dest>
|
||||
requires (!is_size_one_sequence_v<Source>)
|
||||
constexpr void
|
||||
move_to(Source&& src, Dest& dest)
|
||||
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
|
||||
{
|
||||
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
|
||||
dest = std::forward<Source>(src);
|
||||
}
|
||||
|
||||
template <NonUnusedAttr Source, CategorizedAttr<optional_attribute> Dest>
|
||||
constexpr void
|
||||
move_to(Source&& src, Dest& dest)
|
||||
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
|
||||
{
|
||||
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
|
||||
dest = std::forward<Source>(src);
|
||||
}
|
||||
|
||||
// Containers -------------------------------------------------
|
||||
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, CategorizedAttr<container_attribute> Dest>
|
||||
constexpr void
|
||||
move_to(It first, Se last, Dest& dest)
|
||||
// never noexcept, requires container insertion
|
||||
{
|
||||
if (traits::is_empty(dest))
|
||||
{
|
||||
dest = Dest(first, last);
|
||||
}
|
||||
else
|
||||
{
|
||||
traits::append(dest, first, last);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
|
||||
template <std::forward_iterator It>
|
||||
constexpr void
|
||||
move_to(It first, It last, boost::iterator_range<It>& rng)
|
||||
{
|
||||
rng = {first, last};
|
||||
}
|
||||
#endif
|
||||
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, std::ranges::subrange_kind Kind>
|
||||
constexpr void
|
||||
move_to(It first, Se last, std::ranges::subrange<It, Se, Kind>& rng)
|
||||
{
|
||||
rng = std::ranges::subrange<It, Se, Kind>(std::move(first), std::move(last));
|
||||
}
|
||||
|
||||
template <std::forward_iterator It, std::sentinel_for<It> Se, CategorizedAttr<tuple_attribute> Dest>
|
||||
requires is_size_one_sequence_v<Dest>
|
||||
constexpr void
|
||||
move_to(It first, Se last, Dest& dest)
|
||||
noexcept(noexcept(traits::move_to(first, last, fusion::front(dest))))
|
||||
{
|
||||
traits::move_to(first, last, fusion::front(dest));
|
||||
}
|
||||
|
||||
template <ContainerAttr Source, CategorizedAttr<container_attribute> Dest>
|
||||
constexpr void
|
||||
move_to(Source&& src, Dest& dest)
|
||||
// TODO: noexcept
|
||||
{
|
||||
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
|
||||
|
||||
if constexpr (std::is_rvalue_reference_v<Source&&>)
|
||||
{
|
||||
traits::move_to(std::make_move_iterator(std::ranges::begin(src)), std::make_move_iterator(std::ranges::end(src)), dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
traits::move_to(std::ranges::begin(src), std::ranges::end(src), dest);
|
||||
}
|
||||
}
|
||||
|
||||
// Size-one fusion tuple forwarding
|
||||
template <NonUnusedAttr Source, CategorizedAttr<tuple_attribute> Dest>
|
||||
requires is_size_one_sequence_v<Dest>
|
||||
constexpr void
|
||||
move_to(Source&& src, Dest& dest)
|
||||
noexcept(noexcept(traits::move_to(std::forward<Source>(src), fusion::front(dest))))
|
||||
{
|
||||
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
|
||||
|
||||
traits::move_to(std::forward<Source>(src), fusion::front(dest));
|
||||
}
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2001-2011 Hartmut Kaiser
|
||||
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)
|
||||
@@ -10,65 +10,87 @@
|
||||
#define BOOST_SPIRIT_X3_OPTIONAL_TRAITS_FEBRUARY_06_2007_1001AM
|
||||
|
||||
#include <boost/spirit/home/x3/support/unused.hpp>
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
#ifndef BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
|
||||
# define BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL 1
|
||||
#endif
|
||||
|
||||
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
|
||||
# include <boost/optional/optional.hpp>
|
||||
#endif
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T, typename Enable = void>
|
||||
struct is_optional
|
||||
: mpl::false_
|
||||
{};
|
||||
struct is_optional : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_optional<boost::optional<T>>
|
||||
: mpl::true_
|
||||
{};
|
||||
constexpr bool is_optional_v = is_optional<T>::value;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// build_optional
|
||||
//
|
||||
// Build a boost::optional from T. Return unused_type if T is unused_type.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
|
||||
template <typename T>
|
||||
struct [[deprecated("Use std::optional")]] is_optional<boost::optional<T>> : std::true_type {};
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct is_optional<std::optional<T>> : std::true_type {};
|
||||
|
||||
// Build a optional type from T. Return unused_type if T is unused_type.
|
||||
template <typename T>
|
||||
struct build_optional
|
||||
{
|
||||
typedef boost::optional<T> type;
|
||||
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
|
||||
using type [[deprecated("Use std::optional")]] = boost::optional<T>;
|
||||
#else
|
||||
using type = std::optional<T>;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct build_optional<boost::optional<T> >
|
||||
using build_optional_t = typename build_optional<T>::type;
|
||||
|
||||
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
|
||||
template <typename T>
|
||||
struct [[deprecated("Use std::optional")]] build_optional<boost::optional<T>>
|
||||
{
|
||||
typedef boost::optional<T> type;
|
||||
using type = boost::optional<T>;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct build_optional<std::optional<T>>
|
||||
{
|
||||
using type = std::optional<T>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct build_optional<unused_type>
|
||||
{
|
||||
typedef unused_type type;
|
||||
using type = unused_type;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// optional_value
|
||||
//
|
||||
// Get the optional's value_type. Handles unused_type as well.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct optional_value : mpl::identity<T> {};
|
||||
struct optional_value { using type = typename T::value_type; };
|
||||
|
||||
template <typename T>
|
||||
struct optional_value<boost::optional<T> >
|
||||
: mpl::identity<T> {};
|
||||
using optional_value_t = typename optional_value<T>::type;
|
||||
|
||||
template <>
|
||||
struct optional_value<unused_type>
|
||||
: mpl::identity<unused_type> {};
|
||||
{
|
||||
using type = unused_type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct optional_value<unused_type const>
|
||||
: mpl::identity<unused_type> {};
|
||||
{
|
||||
using type = unused_type;
|
||||
};
|
||||
|
||||
}}}}
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2019 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,28 +8,29 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_PSEUDO_ATTRIBUTE_OF_MAY_15_2019_1012PM)
|
||||
#define BOOST_SPIRIT_X3_PSEUDO_ATTRIBUTE_OF_MAY_15_2019_1012PM
|
||||
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Pseudo attributes are placeholders for parsers that can only know
|
||||
// its actual attribute at parse time. This trait customization point
|
||||
// provides a mechanism to convert the trait to the actual trait at
|
||||
// parse time.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Context, typename Attribute, typename Iterator
|
||||
, typename Enable = void>
|
||||
template <typename Context, typename Attribute, std::forward_iterator It, std::sentinel_for<It> Se = It, typename Enable = void>
|
||||
struct pseudo_attribute
|
||||
{
|
||||
using attribute_type = Attribute;
|
||||
using type = Attribute;
|
||||
|
||||
static type&& call(Iterator&, Iterator const&, attribute_type&& attribute)
|
||||
[[nodiscard]] static constexpr type&& call(It&, Se const&, Attribute&& attribute) noexcept
|
||||
{
|
||||
return std::forward<type>(attribute);
|
||||
return static_cast<type&&>(attribute);
|
||||
}
|
||||
};
|
||||
}}}}
|
||||
|
||||
template <typename Context, typename Attribute, std::forward_iterator It, std::sentinel_for<It> Se>
|
||||
using pseudo_attribute_t = typename pseudo_attribute<Context, Attribute, It, Se>::type;
|
||||
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 Joel de Guzman
|
||||
Copyright (c) 2001-2012 Hartmut Kaiser
|
||||
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)
|
||||
@@ -9,9 +9,7 @@
|
||||
#if !defined(BOOST_SPIRIT_X3_ATTRIBUTE_TRANSFORM_JAN_8_2012_0721PM)
|
||||
#define BOOST_SPIRIT_X3_ATTRIBUTE_TRANSFORM_JAN_8_2012_0721PM
|
||||
|
||||
#include <boost/mpl/identity.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// transform_attribute
|
||||
@@ -24,6 +22,12 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
template <typename Exposed, typename Transformed, typename Tag
|
||||
, typename Enable = void>
|
||||
struct transform_attribute;
|
||||
}}}}
|
||||
|
||||
template <typename Exposed, typename Transformed, typename Tag>
|
||||
concept Transformable = requires {
|
||||
typename transform_attribute<Exposed, Transformed, Tag>::type;
|
||||
};
|
||||
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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)
|
||||
@@ -10,48 +11,69 @@
|
||||
#include <boost/fusion/include/is_sequence.hpp>
|
||||
#include <boost/fusion/include/is_view.hpp>
|
||||
#include <boost/fusion/include/size.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
// Note that these metafunctions MUST be explicitly derived from `std::bool_constant`,
|
||||
// because they are used for tag dispatch in some locations.
|
||||
// Beware that `std::conjunction` / `std::disjunction` is not guaranteed to derive
|
||||
// from `std::bool_constant`.
|
||||
|
||||
template <typename A, typename B>
|
||||
struct has_same_size
|
||||
: mpl::bool_<(
|
||||
fusion::result_of::size<A>::value ==
|
||||
fusion::result_of::size<B>::value
|
||||
)>
|
||||
: std::bool_constant<
|
||||
fusion::result_of::size<std::remove_cvref_t<A>>::value ==
|
||||
fusion::result_of::size<std::remove_cvref_t<B>>::value
|
||||
>
|
||||
{};
|
||||
|
||||
template <typename A, typename B>
|
||||
constexpr bool has_same_size_v = has_same_size<A, B>::value;
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct has_size
|
||||
: mpl::bool_<(fusion::result_of::size<T>::value == N)>
|
||||
: std::bool_constant<fusion::result_of::size<std::remove_cvref_t<T>>::value == N>
|
||||
{};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
constexpr bool has_size_v = has_size<T, N>::value;
|
||||
|
||||
template <typename A, typename B>
|
||||
struct is_same_size_sequence
|
||||
: mpl::and_<
|
||||
fusion::traits::is_sequence<A>
|
||||
, fusion::traits::is_sequence<B>
|
||||
, has_same_size<A, B>
|
||||
>
|
||||
: std::bool_constant<std::conjunction_v<
|
||||
fusion::traits::is_sequence<std::remove_cvref_t<A>>,
|
||||
fusion::traits::is_sequence<std::remove_cvref_t<B>>,
|
||||
has_same_size<A, B>
|
||||
>>
|
||||
{};
|
||||
|
||||
template <typename A, typename B>
|
||||
constexpr bool is_same_size_sequence_v = is_same_size_sequence<A, B>::value;
|
||||
|
||||
template <typename Seq>
|
||||
struct is_size_one_sequence
|
||||
: mpl::and_<
|
||||
fusion::traits::is_sequence<Seq>
|
||||
, has_size<Seq, 1>
|
||||
>
|
||||
: std::bool_constant<std::conjunction_v<
|
||||
fusion::traits::is_sequence<std::remove_cvref_t<Seq>>,
|
||||
has_size<Seq, 1>
|
||||
>>
|
||||
{};
|
||||
|
||||
template <typename Seq>
|
||||
constexpr bool is_size_one_sequence_v = is_size_one_sequence<Seq>::value;
|
||||
|
||||
template <typename View>
|
||||
struct is_size_one_view
|
||||
: mpl::and_<
|
||||
fusion::traits::is_view<View>
|
||||
, has_size<View, 1>
|
||||
>
|
||||
: std::bool_constant<std::conjunction_v<
|
||||
fusion::traits::is_view<std::remove_cvref_t<View>>,
|
||||
has_size<View, 1>
|
||||
>>
|
||||
{};
|
||||
}}}}
|
||||
|
||||
template <typename View>
|
||||
constexpr bool is_size_one_view_v = is_size_one_view<View>::value;
|
||||
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 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)
|
||||
@@ -9,9 +9,9 @@
|
||||
#define BOOST_SPIRIT_X3_VARIANT_FIND_SUBSTITUTE_APR_18_2014_930AM
|
||||
|
||||
#include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
|
||||
#include <boost/mpl/find.hpp>
|
||||
#include <boost/mpl/find.hpp> // TODO: remove this
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
template <typename Variant, typename T>
|
||||
struct variant_find_substitute
|
||||
@@ -19,33 +19,34 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
// Get the type from the Variant that can be a substitute for T.
|
||||
// If none is found, just return T
|
||||
|
||||
typedef Variant variant_type;
|
||||
typedef typename variant_type::types types;
|
||||
typedef typename mpl::end<types>::type end;
|
||||
using variant_type = Variant;
|
||||
using types = typename variant_type::types;
|
||||
using end = typename mpl::end<types>::type;
|
||||
|
||||
typedef typename mpl::find<types, T>::type iter_1;
|
||||
using iter_1 = typename mpl::find<types, T>::type;
|
||||
|
||||
typedef typename
|
||||
mpl::eval_if<
|
||||
is_same<iter_1, end>,
|
||||
using iter = typename mpl::eval_if<
|
||||
std::is_same<iter_1, end>,
|
||||
mpl::find_if<types, traits::is_substitute<T, mpl::_1> >,
|
||||
mpl::identity<iter_1>
|
||||
>::type
|
||||
iter;
|
||||
std::type_identity<iter_1>
|
||||
>::type;
|
||||
|
||||
typedef typename
|
||||
mpl::eval_if<
|
||||
is_same<iter, end>,
|
||||
mpl::identity<T>,
|
||||
using type = typename mpl::eval_if<
|
||||
std::is_same<iter, end>,
|
||||
std::type_identity<T>,
|
||||
mpl::deref<iter>
|
||||
>::type
|
||||
type;
|
||||
>::type;
|
||||
};
|
||||
|
||||
template <typename Variant, typename T>
|
||||
using variant_find_substitute_t = typename variant_find_substitute<Variant, T>::type;
|
||||
|
||||
template <typename Variant>
|
||||
struct variant_find_substitute<Variant, Variant>
|
||||
: mpl::identity<Variant> {};
|
||||
{
|
||||
using type = Variant;
|
||||
};
|
||||
|
||||
}}}}
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2014 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)
|
||||
@@ -9,9 +9,13 @@
|
||||
#define BOOST_SPIRIT_X3_VARIANT_HAS_SUBSTITUTE_APR_18_2014_925AM
|
||||
|
||||
#include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
|
||||
#include <boost/mpl/find.hpp>
|
||||
#include <boost/mpl/find.hpp> // TODO: remove this
|
||||
|
||||
namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost::spirit::x3::traits
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename Variant, typename T>
|
||||
struct variant_has_substitute_impl
|
||||
@@ -19,33 +23,35 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
|
||||
// Find a type from the Variant that can be a substitute for T.
|
||||
// return true_ if one is found, else false_
|
||||
|
||||
typedef Variant variant_type;
|
||||
typedef typename variant_type::types types;
|
||||
typedef typename mpl::end<types>::type end;
|
||||
using variant_type = Variant;
|
||||
using types = typename variant_type::types;
|
||||
using end = typename mpl::end<types>::type;
|
||||
using iter_1 = typename mpl::find<types, T>::type;
|
||||
|
||||
typedef typename mpl::find<types, T>::type iter_1;
|
||||
|
||||
typedef typename
|
||||
mpl::eval_if<
|
||||
is_same<iter_1, end>,
|
||||
using iter = typename mpl::eval_if<
|
||||
std::is_same<iter_1, end>,
|
||||
mpl::find_if<types, traits::is_substitute<T, mpl::_1>>,
|
||||
mpl::identity<iter_1>
|
||||
>::type
|
||||
iter;
|
||||
std::type_identity<iter_1>
|
||||
>::type;
|
||||
|
||||
typedef mpl::not_<is_same<iter, end>> type;
|
||||
using type = std::bool_constant<!std::is_same_v<iter, end>>;
|
||||
};
|
||||
} // detail
|
||||
|
||||
template <typename Variant, typename T>
|
||||
struct variant_has_substitute
|
||||
: variant_has_substitute_impl<Variant, T>::type {};
|
||||
: detail::variant_has_substitute_impl<Variant, T>::type
|
||||
{};
|
||||
|
||||
template <typename Variant, typename T>
|
||||
constexpr bool variant_has_substitute_v = variant_has_substitute<Variant, T>::value;
|
||||
|
||||
template <typename T>
|
||||
struct variant_has_substitute<unused_type, T> : mpl::true_ {};
|
||||
struct variant_has_substitute<unused_type, T> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct variant_has_substitute<unused_type const, T> : mpl::true_ {};
|
||||
struct variant_has_substitute<unused_type const, T> : std::true_type {};
|
||||
|
||||
}}}}
|
||||
} // boost::spirit::x3::traits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2017-2021 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)
|
||||
=============================================================================*/
|
||||
|
||||
#include <boost/spirit/home/x3.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
=============================================================================*/
|
||||
#include "test.hpp"
|
||||
|
||||
#include <boost/spirit/home/x3.hpp>
|
||||
#include <boost/fusion/include/std_pair.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "test.hpp"
|
||||
|
||||
using boost::spirit::x3::rule;
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2001-2012 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)
|
||||
=============================================================================*/
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
#include <boost/spirit/home/x3.hpp>
|
||||
#include <boost/fusion/include/adapt_struct.hpp>
|
||||
#include <boost/fusion/include/std_pair.hpp>
|
||||
@@ -14,7 +17,6 @@
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include "test.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// bogus https://developercommunity.visualstudio.com/t/buggy-warning-c4709/471956
|
||||
@@ -34,9 +36,10 @@ struct f
|
||||
};
|
||||
|
||||
|
||||
struct stationary : boost::noncopyable
|
||||
struct stationary
|
||||
{
|
||||
explicit stationary(int i) : val{i} {}
|
||||
stationary(stationary const&) = delete;
|
||||
stationary& operator=(int i) { val = i; return *this; }
|
||||
|
||||
int val;
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
=============================================================================*/
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
#include <boost/spirit/home/x3.hpp>
|
||||
#include <boost/fusion/include/vector.hpp>
|
||||
#include <boost/fusion/include/at.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include "test.hpp"
|
||||
|
||||
namespace x3 = boost::spirit::x3;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user