Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions include/iris/x4/core/detail/parse_alternative.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,26 +106,6 @@ struct pass_non_variant_attribute
}
};

// Unwrap single element sequences
template<class Parser, X4Attribute Attr>
requires traits::is_size_one_sequence_v<Attr>
struct pass_non_variant_attribute<Parser, Attr>
{
using attr_type = typename std::remove_reference_t<
alloy::tuple_element_t<0, Attr>
>;
using pass = pass_parser_attribute<Parser, attr_type>;
using type = typename pass::type;

template<X4Attribute Attr_>
[[nodiscard]] static constexpr type
call(Attr_& attr)
noexcept(noexcept(pass::call(alloy::get<0>(attr))))
{
return pass::call(alloy::get<0>(attr));
}
};

template<class Parser, X4Attribute Attr>
requires (!traits::is_variant_v<Attr>)
struct pass_parser_attribute<Parser, Attr>
Expand Down
36 changes: 11 additions & 25 deletions include/iris/x4/core/detail/parse_into_container.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,35 +87,18 @@ struct parse_into_container_base_impl

// ------------------------------------------------------

// Parser has attribute && it is NOT tuple-like
// Parser has attribute
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, X4Attribute Attr>
requires
has_attribute_v<Parser> &&
(!alloy::is_tuple_like_v<Attr>)
has_attribute_v<Parser>
[[nodiscard]] static constexpr bool
call(
Parser const& parser, It& first, Se const& last,
Context const& ctx, Attr& attr
)
{
// TODO: reduce call stack while keeping maintainability
return parse_into_container_base_impl::call_synthesize(parser, first, last, ctx, attr);
}

// Parser has attribute && it is tuple-like
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, X4Attribute Attr>
requires
has_attribute_v<Parser> &&
alloy::is_tuple_like_v<Attr>
[[nodiscard]] static constexpr bool
call(
Parser const& parser, It& first, Se const& last,
Context const& ctx, Attr& attr
) noexcept(noexcept(parse_into_container_base_impl::call_synthesize(parser, first, last, ctx, alloy::get<0>(attr))))
{
static_assert(traits::has_size_v<Attr, 1>, "Expecting a single element tuple-like");
// TODO: reduce call stack while keeping maintainability
return parse_into_container_base_impl::call_synthesize(parser, first, last, ctx, alloy::get<0>(attr));
return parse_into_container_base_impl::call_synthesize(parser, first, last, ctx, x4::unwrap_single_element_tuple_like(attr));
}

// Parser has no attribute (pass unused)
Expand Down Expand Up @@ -149,7 +132,7 @@ struct parse_into_container_impl<Parser>
It, Se, Context,
typename parser_traits<Parser>::attribute_type
>::actual_type,
traits::container_value_t<Attr>
traits::container_value_t<traits::unwrap_single_element_tuple_like_t<Attr>>
>>
>;

Expand Down Expand Up @@ -205,22 +188,25 @@ template<
parse_into_container(
Parser const& parser, It& first, Se const& last,
Context const& ctx, Attr& attr
) noexcept(noexcept(parse_into_container_impl<Parser>::call(parser, first, last, ctx, attr)))
) // TODO: add noexcept
{
static_assert(
!std::same_as<Attr, unused_type>,
"`unused_type` should not be passed to `parse_into_container`. Use `x4::assume_container(attr)`"
);

if constexpr (traits::is_variant_v<Attr>) {
if constexpr (traits::is_variant_v<traits::unwrap_single_element_tuple_like_t<Attr>>) {
// e.g. `char` when the caller is `+char_`
using attribute_type = parser_traits<Parser>::attribute_type;

// e.g. `std::string` when the attribute_type is `char`
using substitute_type = traits::variant_find_substitute_t<Attr, traits::build_container_t<attribute_type>>;
using substitute_type = traits::variant_find_substitute_t<
traits::unwrap_single_element_tuple_like_t<Attr>,
traits::build_container_t<attribute_type>
>;

// instead of creating a temporary `substitute_type`, append directly into the emplaced alternative
auto& variant_alt = attr.template emplace<substitute_type>();
auto& variant_alt = x4::unwrap_single_element_tuple_like(attr).template emplace<substitute_type>();
return parse_into_container_impl<Parser>::call(parser, first, last, ctx, variant_alt);
} else {
return parse_into_container_impl<Parser>::call(parser, first, last, ctx, attr);
Expand Down
30 changes: 7 additions & 23 deletions include/iris/x4/core/detail/parse_sequence.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,6 @@ struct pass_sequence_attribute_unused
}
};

template<class Attr>
struct pass_sequence_attribute_size_one_view
{
using type = alloy::tuple_element_t<0, Attr>;

[[nodiscard]] static constexpr type
call(Attr& attribute)
noexcept(noexcept(alloy::get<0>(attribute)))
{
return alloy::get<0>(attribute);
}
};

template<class Attr>
struct pass_through_sequence_attribute
{
Expand All @@ -76,11 +63,8 @@ struct pass_through_sequence_attribute
};

template<class Parser, class Attr>
struct pass_sequence_attribute : std::conditional_t<
traits::is_size_one_view_v<Attr>,
pass_sequence_attribute_size_one_view<Attr>,
pass_through_sequence_attribute<Attr>
>
struct pass_sequence_attribute
: pass_through_sequence_attribute<Attr>
{};

template<class LParser, class RParser, class Attr>
Expand Down Expand Up @@ -126,21 +110,21 @@ struct partition_attribute

using view = alloy::tuple_ref_t<Attr>;
using splitted = alloy::tuple_split_t<view, l_size, r_size>;
using l_part = alloy::tuple_element_t<0, splitted>;
using r_part = alloy::tuple_element_t<1, splitted>;
using l_part = traits::unwrap_single_element_tuple_like_t<alloy::tuple_element_t<0, splitted>>;
using r_part = traits::unwrap_single_element_tuple_like_t<alloy::tuple_element_t<1, splitted>>;
using l_pass = pass_sequence_attribute<LParser, l_part>;
using r_pass = pass_sequence_attribute<RParser, r_part>;

[[nodiscard]] static constexpr l_part left(Attr& s)
// TODO: noexcept
{
return alloy::get<0>(alloy::tuple_split<l_size, r_size>(alloy::tuple_ref(s)));
return x4::unwrap_single_element_tuple_like(alloy::get<0>(alloy::tuple_split<l_size, r_size>(alloy::tuple_ref(s))));
}

[[nodiscard]] static constexpr r_part right(Attr& s)
// TODO: noexcept
{
return alloy::get<1>(alloy::tuple_split<l_size, r_size>(alloy::tuple_ref(s)));
return x4::unwrap_single_element_tuple_like(alloy::get<1>(alloy::tuple_split<l_size, r_size>(alloy::tuple_ref(s))));
}
};

Expand Down Expand Up @@ -284,7 +268,7 @@ struct parse_into_container_impl<sequence<Left, Right>>
template<X4Attribute Attr>
static constexpr bool is_container_substitute = traits::is_substitute_v<
typename sequence<Left, Right>::attribute_type,
traits::container_value_t<Attr>
traits::container_value_t<traits::unwrap_single_element_tuple_like_t<Attr>>
>;

template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, X4Attribute Attr>
Expand Down
84 changes: 37 additions & 47 deletions include/iris/x4/core/move_to.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,7 @@ constexpr void move_to(It const&, Se const&, unused_type const&&) = delete; // t
// Category specific --------------------------------------

template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::plain_attr> Dest>
requires traits::is_size_one_sequence_v<Source>
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(noexcept(dest = std::forward_like<Source>(alloy::get<0>(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");
// TODO: preliminarily invoke static_assert to check if the assignment is valid
dest = std::forward_like<Source>(alloy::get<0>(std::forward<Source>(src)));
}

template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::plain_attr> Dest>
requires (!traits::is_size_one_sequence_v<Source>)
requires (!traits::is_single_element_tuple_like_v<Dest>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
Expand All @@ -139,8 +128,8 @@ move_to(Source&& src, Dest& dest)

template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::tuple_attr> Dest>
requires
traits::is_same_size_sequence_v<Dest, Source> &&
(!traits::is_size_one_sequence_v<Dest>)
traits::is_same_size_tuple_like_v<Dest, std::remove_cvref_t<Source>> &&
(!traits::is_single_element_tuple_like_v<Dest>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(noexcept(alloy::tuple_assign(std::forward<Source>(src), dest)))
Expand All @@ -152,43 +141,40 @@ move_to(Source&& src, Dest& dest)
alloy::tuple_assign(std::forward<Source>(src), dest);
}

// Source is single element tuple-like and Dest is variant which *can* holds Source directly
template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::variant_attr> Dest>
requires traits::is_size_one_sequence_v<Source> && traits::variant_has_substitute_v<Dest, Source>
requires
(!traits::is_single_element_tuple_like_v<Dest>) &&
traits::is_single_element_tuple_like_v<std::remove_cvref_t<Source>> &&
traits::variant_has_substitute_v<Dest, std::remove_cvref_t<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 tuple-like that the variant
// *can* directly hold.
static_assert(std::is_assignable_v<Dest&, Source>);
dest = std::forward<Source>(src);
}

// Source is single element tuple-like and Dest is variant which *can not* holds Source directly
template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::variant_attr> Dest>
requires traits::is_size_one_sequence_v<Source> && (!traits::variant_has_substitute_v<Dest, Source>)
requires
(!traits::is_single_element_tuple_like_v<Dest>) &&
traits::is_single_element_tuple_like_v<std::remove_cvref_t<Source>> &&
(!traits::variant_has_substitute_v<Dest, std::remove_cvref_t<Source>>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(noexcept(dest = std::forward_like<Source>(alloy::get<0>(std::forward<Source>(src)))))
move_to(Source&& src, Dest& dest) // TODO: add noexcept
{
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 tuple-like that the variant
// cannot directly hold. We'll try to unwrap the single element tuple-like.

// Make sure that the Dest variant can really hold Source
static_assert(
traits::variant_has_substitute_v<Dest, alloy::tuple_element_t<0, Source>>,
"Error! The destination variant (Dest) cannot hold the source type (Source)"
);

// TODO: preliminarily invoke static_assert to check if the assignment is valid
dest = std::forward_like<Source>(alloy::get<0>(std::forward<Source>(src)));
}

// Source is *NOT* single element tuple-like and Dest is variant
template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::variant_attr> Dest>
requires (!traits::is_size_one_sequence_v<Source>)
requires
(!traits::is_single_element_tuple_like_v<Dest>) &&
(!traits::is_single_element_tuple_like_v<std::remove_cvref_t<Source>>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
Expand All @@ -199,6 +185,7 @@ move_to(Source&& src, Dest& dest)
}

template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::optional_attr> Dest>
requires (!traits::is_single_element_tuple_like_v<Dest>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
Expand All @@ -214,6 +201,7 @@ template<class ContainerAttr>
struct container_appender;

template<std::forward_iterator It, std::sentinel_for<It> Se, traits::CategorizedAttr<traits::container_attr> Dest>
requires (!traits::is_single_element_tuple_like_v<Dest>)
constexpr void
move_to(It first, Se last, Dest& dest)
// never noexcept, requires container insertion
Expand Down Expand Up @@ -243,21 +231,13 @@ 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, traits::CategorizedAttr<traits::tuple_attr> Dest>
requires traits::is_size_one_sequence_v<Dest>
constexpr void
move_to(It first, Se last, Dest& dest)
noexcept(noexcept(x4::move_to(first, last, alloy::get<0>(dest))))
{
x4::move_to(first, last, alloy::get<0>(dest));
}

// Move non-container `src` into container `dest`.
// e.g. Source=std::string_view, Dest=std::string (used in `attr_parser`)
template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::container_attr> Dest>
requires
(!traits::X4Container<Source>) &&
(!std::same_as<std::remove_const_t<Dest>, unused_container_type>)
(!std::same_as<std::remove_const_t<Dest>, unused_container_type>) &&
(!traits::is_single_element_tuple_like_v<Dest>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
Expand All @@ -272,6 +252,7 @@ move_to(Source&& src, Dest& dest)
}

template<traits::X4Container Source, traits::CategorizedAttr<traits::container_attr> Dest>
requires (!traits::is_single_element_tuple_like_v<Dest>)
constexpr void
move_to(Source&& src, Dest& dest)
// TODO: noexcept
Expand All @@ -285,12 +266,21 @@ move_to(Source&& src, Dest& dest)
}
}

// Size-one tuple-like forwarding
template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::tuple_attr> Dest>
requires traits::is_size_one_sequence_v<Dest>
// single element tuple-like forwarding

template<std::forward_iterator It, std::sentinel_for<It> Se, traits::NonUnusedAttr Dest>
requires traits::is_single_element_tuple_like_v<Dest>
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(noexcept(x4::move_to(std::forward<Source>(src), alloy::get<0>(dest))))
move_to(It first, Se last, Dest& dest)
noexcept(noexcept(x4::move_to(first, last, alloy::get<0>(dest))))
{
x4::move_to(first, last, alloy::get<0>(dest));
}

template<traits::NonUnusedAttr Source, traits::NonUnusedAttr Dest>
requires traits::is_single_element_tuple_like_v<Dest>
constexpr void
move_to(Source&& src, Dest& dest) // TODO: add noexcept
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");

Expand Down
2 changes: 1 addition & 1 deletion include/iris/x4/operator/alternative.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace iris::x4 {
template<class Left, class Right>
struct alternative : binary_parser<Left, Right, alternative<Left, Right>>
{
using attribute_type = traits::attribute_of_binary<iris::rvariant, alternative, Left, Right>::type;
using attribute_type = traits::attribute_of_binary<iris::rvariant, Left, Right>::type;

using binary_parser<Left, Right, alternative>::binary_parser;

Expand Down
2 changes: 1 addition & 1 deletion include/iris/x4/operator/sequence.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace iris::x4 {
template<class Left, class Right>
struct sequence : binary_parser<Left, Right, sequence<Left, Right>>
{
using attribute_type = traits::attribute_of_binary<alloy::tuple, x4::sequence, Left, Right>::type;
using attribute_type = traits::attribute_of_binary<alloy::tuple, Left, Right>::type;

static constexpr std::size_t sequence_size =
parser_traits<Left>::sequence_size + parser_traits<Right>::sequence_size;
Expand Down
Loading
Loading