Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion include/iris/x4/core/detail/parse_alternative.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ template<class Parser, X4Attribute Attr>
struct pass_parser_attribute
{
using attribute_type = parser_traits<Parser>::attribute_type;
using substitute_type = traits::variant_find_substitute_t<Attr, attribute_type>;
using substitute_type = traits::variant_find_holdable_type_t<Attr, attribute_type>;

using type = std::conditional_t<
std::same_as<Attr, substitute_type>,
Expand Down
9 changes: 5 additions & 4 deletions include/iris/x4/core/detail/parse_into_container.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <iris/x4/core/container_appender.hpp>

#include <iris/x4/traits/container_traits.hpp>
#include <iris/x4/traits/substitution.hpp>
#include <iris/x4/traits/can_hold.hpp>

#include <iris/alloy/tuple.hpp>

Expand All @@ -28,7 +28,7 @@ namespace iris::x4::detail {

template<class Parser, class Container>
struct parser_accepts_container
: traits::is_substitute<typename parser_traits<Parser>::attribute_type, Container>
: traits::can_hold<typename parser_traits<Parser>::attribute_type, Container>
{};

template<class Parser, class Container>
Expand Down Expand Up @@ -140,11 +140,12 @@ template<class Parser>
requires Parser::handles_container
struct parse_into_container_impl<Parser>
{
// TODO: decompose pass_attribute_as_is to make more logic clear
template<std::forward_iterator It, std::sentinel_for<It> Se, class Context, X4Attribute Attr>
static constexpr bool pass_attibute_as_is = std::disjunction_v<
parser_accepts_container<Parser, Attr>,

std::negation<traits::is_substitute< // parser attribute is substitute for container value?
std::negation<traits::can_hold<
typename traits::pseudo_attribute<
It, Se, Context,
typename parser_traits<Parser>::attribute_type
Expand Down Expand Up @@ -217,7 +218,7 @@ parse_into_container(
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_holdable_type_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>();
Expand Down
5 changes: 3 additions & 2 deletions include/iris/x4/core/detail/parse_sequence.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <iris/x4/traits/attribute_category.hpp>
#include <iris/x4/traits/container_traits.hpp>
#include <iris/x4/traits/tuple_traits.hpp>
#include <iris/x4/traits/substitution.hpp>
#include <iris/x4/traits/can_hold.hpp>

#include <iris/alloy/tuple.hpp>
#include <iris/alloy/utility.hpp>
Expand Down Expand Up @@ -281,8 +281,9 @@ parse_sequence(Parser const& parser, It& first, Se const& last, Context const& c
template<class Left, class Right>
struct parse_into_container_impl<sequence<Left, Right>>
{
// TODO: investigate what is_container_substitute means
template<X4Attribute Attr>
static constexpr bool is_container_substitute = traits::is_substitute_v<
static constexpr bool is_container_substitute = traits::can_hold_v<
typename sequence<Left, Right>::attribute_type,
traits::container_value_t<Attr>
>;
Expand Down
30 changes: 8 additions & 22 deletions include/iris/x4/core/move_to.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,49 +153,35 @@ move_to(Source&& src, Dest& dest)
}

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 std::is_assignable_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 tuple-like that the variant
// *can* directly hold.
static_assert(std::is_assignable_v<Dest&, Source>);
// e.g. Dest is `iris::rvariant<int>` and Source is `int`
// e.g. Dest is `iris::rvariant<alloy::tuple<int>>` and Source is `alloy::tuple<int>`
dest = std::forward<Source>(src);
}

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 (!std::is_assignable_v<Dest&, Source&&>) && 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");

// 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>>,
std::is_assignable_v<Dest&, decltype(std::forward_like<Source>(alloy::get<0>(std::forward<Source>(src))))>,
"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)));
}
// forward_like is *required*, since when Source is `alloy::tuple<int&>` `alloy::get<0>(std::forward<Source>(src))` returns `int&` whereas we want `int&&` instead

template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::variant_attr> Dest>
requires (!traits::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);
// e.g. Dest is `iris::rvariant<int>` and Source is `alloy::tuple<int>`
dest = std::forward_like<Source>(alloy::get<0>(std::forward<Source>(src)));
}

template<traits::NonUnusedAttr Source, traits::CategorizedAttr<traits::optional_attr> Dest>
Expand Down
103 changes: 103 additions & 0 deletions include/iris/x4/traits/can_hold.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#ifndef IRIS_X4_TRAITS_CAN_HOLD_HPP
#define IRIS_X4_TRAITS_CAN_HOLD_HPP

/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
Copyright (c) 2026 The Iris Project Contributors

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 <iris/x4/traits/container_traits.hpp>
#include <iris/x4/traits/tuple_traits.hpp>

#include <iris/x4/core/attribute.hpp>

#include <iris/alloy/traits.hpp>

#include <optional>
#include <type_traits>

namespace iris::x4::traits {

template<class T, class U>
struct can_hold;

template<class T, class U>
constexpr bool can_hold_v = can_hold<T, U>::value;

template<class T>
struct is_variant;

namespace detail {

template<class TTuple, class UTuple, class IndexSeq = std::make_index_sequence<alloy::tuple_size_v<TTuple>>>
struct is_all_substitute_for_tuple_impl {};

template<class TTuple, class UTuple, std::size_t... Is>
struct is_all_substitute_for_tuple_impl<TTuple, UTuple, std::index_sequence<Is...>>
: std::conjunction<can_hold<alloy::tuple_element_t<Is, TTuple>, alloy::tuple_element_t<Is, UTuple>>...> {};

template<class TTuple, class UTuple>
struct is_all_substitute_for_tuple : std::false_type {};

template<class TTuple, class UTuple>
requires is_same_size_sequence_v<TTuple, UTuple>
struct is_all_substitute_for_tuple<TTuple, UTuple> : is_all_substitute_for_tuple_impl<TTuple, UTuple> {};

template<class T, class U>
struct value_type_can_hold
: can_hold<container_value_t<T>, container_value_t<U>>
{};

} // detail

template<class T, class U>
struct can_hold
: std::is_same<T, U>
{};

template<class T, class U>
requires
alloy::is_tuple_like_v<T> &&
alloy::is_tuple_like_v<U>
struct can_hold<T, U>
: detail::is_all_substitute_for_tuple<T, U>
{};

template<class T, class U>
requires
is_container_v<std::remove_const<T>> &&
is_container_v<std::remove_const<U>>
struct can_hold<T, U>
: detail::value_type_can_hold<T, U>
{};

template<class T, class U>
requires is_variant<T>::value && X4UnusedAttribute<U>
struct can_hold<T, U>
: std::false_type
{};

template<class T, class U>
requires (!is_variant<T>::value) && X4UnusedAttribute<U>
struct can_hold<T, U>
: std::false_type
{};

template<class T, class U>
requires is_variant<T>::value && (!X4UnusedAttribute<U>)
struct can_hold<T, U>
: std::is_assignable<T&, U>
{};

template<class T, class U>
struct can_hold<std::optional<T>, std::optional<U>>
: can_hold<T, U>
{};

} // iris::x4::traits

#endif
118 changes: 0 additions & 118 deletions include/iris/x4/traits/substitution.hpp

This file was deleted.

Loading
Loading