diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad2f74254..12116f7f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -194,7 +194,6 @@ jobs: libs/function_types \ libs/functional \ libs/fusion \ - libs/integer \ libs/io \ libs/mp11 \ libs/mpl \ @@ -203,11 +202,9 @@ jobs: libs/static_assert \ libs/throw_exception \ libs/tuple \ - libs/type_index \ libs/type_traits \ libs/typeof \ - libs/utility \ - libs/variant + libs/utility - name: Build upstream Boost libraries (Ubuntu) if: matrix.os.name == 'ubuntu' && steps.cache-boost.outputs.cache-hit != 'true' diff --git a/CMakeLists.txt b/CMakeLists.txt index bc6c06d0f..d15c82a8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,26 +80,6 @@ list(APPEND iris_x4_boost_deps functional) list(APPEND iris_x4_boost_deps function) list(APPEND iris_x4_boost_deps bind) -# Everything required by `variant` (manually confirmed) -list(APPEND iris_x4_boost_deps variant) -list(APPEND iris_x4_boost_deps integer) -list(APPEND iris_x4_boost_deps type_index) -list(APPEND iris_x4_boost_deps assert) -list(APPEND iris_x4_boost_deps config) -list(APPEND iris_x4_boost_deps container_hash) -list(APPEND iris_x4_boost_deps core) -list(APPEND iris_x4_boost_deps detail) -list(APPEND iris_x4_boost_deps mpl) -list(APPEND iris_x4_boost_deps preprocessor) -list(APPEND iris_x4_boost_deps static_assert) -list(APPEND iris_x4_boost_deps throw_exception) -list(APPEND iris_x4_boost_deps type_traits) -list(APPEND iris_x4_boost_deps utility) -list(APPEND iris_x4_boost_deps describe) -list(APPEND iris_x4_boost_deps mp11) -list(APPEND iris_x4_boost_deps predef) -list(APPEND iris_x4_boost_deps io) - # Everything required by `preprocessor` (manually confirmed) list(APPEND iris_x4_boost_deps preprocessor) diff --git a/README.md b/README.md index 91ee2dc6a..f6baf801b 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,9 @@ git submodule update --init --depth 1 --recursive -- \ tools/build tools/boost_install libs/assert libs/bind libs/config \ libs/container_hash libs/core libs/describe libs/detail \ libs/function libs/function_types libs/functional libs/fusion \ - libs/integer libs/io libs/mp11 libs/mpl libs/predef libs/preprocessor \ - libs/static_assert libs/throw_exception libs/tuple libs/type_index \ - libs/type_traits libs/typeof libs/utility libs/variant + libs/io libs/mp11 libs/mpl libs/predef libs/preprocessor \ + libs/static_assert libs/throw_exception libs/tuple \ + libs/type_traits libs/typeof libs/utility # Linux ./bootstrap.sh diff --git a/include/iris/x4/core/detail/parse_into_container.hpp b/include/iris/x4/core/detail/parse_into_container.hpp index 8b8e084ae..7a2c3b4d8 100644 --- a/include/iris/x4/core/detail/parse_into_container.hpp +++ b/include/iris/x4/core/detail/parse_into_container.hpp @@ -22,8 +22,6 @@ #include #include -#include // TODO: remove Boost.Variant usage - #include #include #include diff --git a/include/iris/x4/debug/print_attribute.hpp b/include/iris/x4/debug/print_attribute.hpp index 10978c1bd..b81774fcc 100644 --- a/include/iris/x4/debug/print_attribute.hpp +++ b/include/iris/x4/debug/print_attribute.hpp @@ -14,10 +14,9 @@ #include #include -#include +#include -#include -#include // TODO: remove this +#include #ifdef IRIS_X4_UNICODE # include @@ -57,9 +56,9 @@ struct print_fusion_sequence // print elements in a variant template -struct print_visitor : boost::static_visitor<> +struct print_visitor { - print_visitor(Out& out) + explicit print_visitor(Out& out) : out(out) {} @@ -144,7 +143,7 @@ struct print_attribute_debug // for variant types static void call(Out& out, CategorizedAttr auto const& val) { - boost::apply_visitor(detail::print_visitor(out), val); + iris::visit(detail::print_visitor{out}, val); } static void call(Out& out, CategorizedAttr auto const& val) diff --git a/include/iris/x4/operator/alternative.hpp b/include/iris/x4/operator/alternative.hpp index 6f70dd6e0..84a1a323a 100644 --- a/include/iris/x4/operator/alternative.hpp +++ b/include/iris/x4/operator/alternative.hpp @@ -19,7 +19,7 @@ #include #include -#include // TODO: remove this +#include #include #include @@ -31,7 +31,7 @@ namespace iris::x4 { template struct alternative : binary_parser> { - using attribute_type = traits::attribute_of_binary::type; + using attribute_type = traits::attribute_of_binary::type; using binary_parser::binary_parser; diff --git a/include/iris/x4/traits/variant_traits.hpp b/include/iris/x4/traits/variant_traits.hpp index d5484e92d..4c452e827 100644 --- a/include/iris/x4/traits/variant_traits.hpp +++ b/include/iris/x4/traits/variant_traits.hpp @@ -14,120 +14,113 @@ #include -#include // TODO: remove this - -#include // TODO: remove this -#include // TODO: remove this -#include // TODO: remove this -#include // TODO: remove this -#include // TODO: remove this +#include #include namespace iris::x4::traits { -// TODO: define a legit concept for determining variant-like types - template struct is_variant : std::false_type {}; template constexpr bool is_variant_v = is_variant::value; -// By declaring a nested struct named `adapted_variant_tag` in -// your class, you tell X4 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 -// `::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, -// specialize the is_variant trait. -template - requires requires { - typename T::adapted_variant_tag; - } -struct is_variant : std::true_type -{}; +// `std::variant` is not supported, as it does can't handle recursive types -template -struct is_variant> - : std::true_type -{}; +template +struct is_variant> : std::true_type {}; + + +namespace detail { +template +struct variant_find_substitute_impl; -template -struct variant_find_substitute +template +struct variant_find_substitute_impl { - // Get the type from the Variant that can be a substitute for T. - // If none is found, just return T - - using variant_type = Variant; - using types = typename variant_type::types; - using end = typename boost::mpl::end::type; - - using iter_1 = typename boost::mpl::find::type; - - using iter = typename boost::mpl::eval_if< - std::is_same, - boost::mpl::find_if>, - std::type_identity - >::type; - - using type = typename boost::mpl::eval_if< - std::is_same, - std::type_identity, - boost::mpl::deref - >::type; + using type = Attr; }; -template -using variant_find_substitute_t = typename variant_find_substitute::type; - -template -struct variant_find_substitute +template +struct variant_find_substitute_impl { - using type = Variant; + using type = std::conditional_t< + is_substitute_v>, + + // TODO + // Given some type `T`, when both `T` and `recursive_wrapper` is seen + // during attribute resolution, X4 should ideally materialize the latter + // because: + // - It means that the user has supplied at least one explicit type + // (possibly a rule attribute type) that is `recursive_wrapper`, + // - Constructing `T` and then moving it to `recursive_wrapper` + // involves copying from stack to heap. + // + // This is to-do because the above optimization is currently not + // implementable in a straightforward way. We need to add + // `unwrap_recursive(attr)` to every places where any parser attempts + // to modify the content. + iris::unwrap_recursive_t, + + typename variant_find_substitute_impl::type + >; }; +} // detail -namespace detail { -template -struct variant_has_substitute_impl -{ - // Find a type from the Variant that can be a substitute for T. - // return true_ if one is found, else false_ +template +struct variant_find_substitute; - using variant_type = Variant; - using types = typename variant_type::types; - using end = typename boost::mpl::end::type; - using iter_1 = typename boost::mpl::find::type; +template +using variant_find_substitute_t = typename variant_find_substitute::type; - using iter = typename boost::mpl::eval_if< - std::is_same, - boost::mpl::find_if>, - std::type_identity - >::type; +template +struct variant_find_substitute +{ + using type = Attr; +}; - using type = std::bool_constant>; +// Recursively find the first type from the variant that can be a substitute for `Attr`. +// If none is found, returns `Attr`. +template + requires (!std::same_as, Attr>) +struct variant_find_substitute, Attr> +{ + using type = typename detail::variant_find_substitute_impl::type; }; -} // detail template -struct variant_has_substitute - : detail::variant_has_substitute_impl::type -{}; +struct variant_has_substitute; template constexpr bool variant_has_substitute_v = variant_has_substitute::value; template -struct variant_has_substitute : std::true_type {}; +struct variant_has_substitute + : std::true_type +{}; template -struct variant_has_substitute : std::true_type {}; +struct variant_has_substitute + : std::true_type +{}; + +template +struct variant_has_substitute + : std::true_type +{}; + +// Recursively find the first type from the variant that can be a substitute for `T`. +// Returns boolean value whether it was found. +template + requires (!std::same_as, Attr>) +struct variant_has_substitute, Attr> + : std::disjunction...> +{}; } // iris::x4::traits diff --git a/modules/iris b/modules/iris index a9359a6eb..7670a27a5 160000 --- a/modules/iris +++ b/modules/iris @@ -1 +1 @@ -Subproject commit a9359a6ebd84a27a3e44abfa243ddabdc04bcb6d +Subproject commit 7670a27a52fa98e2d726fae1a425bd94806d42ab diff --git a/test/x4/alternative.cpp b/test/x4/alternative.cpp index 38a16f4d7..be45739c0 100644 --- a/test/x4/alternative.cpp +++ b/test/x4/alternative.cpp @@ -2,6 +2,7 @@ Copyright (c) 2001-2015 Joel de Guzman Copyright (c) 2001-2011 Hartmut Kaiser 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) @@ -23,12 +24,12 @@ #include #include +#include + #include #include #include -#include - #include #include @@ -76,47 +77,47 @@ TEST_CASE("alternative") } { - using attr_type = boost::variant; + using attr_type = iris::rvariant; { attr_type v; REQUIRE(parse("12345", int_ | char_, v)); - CHECK(boost::get(v) == 12345); + CHECK(iris::get(v) == 12345); } { attr_type v; REQUIRE(parse("12345", lit("rock") | int_ | char_, v)); - CHECK(boost::get(v) == 12345); + CHECK(iris::get(v) == 12345); } { attr_type v; REQUIRE(parse("rock", lit("rock") | int_ | char_, v)); - CHECK(v.which() == 0); + CHECK(v.index() == 0); } { attr_type v; REQUIRE(parse("x", lit("rock") | int_ | char_, v)); - CHECK(boost::get(v) == 'x'); + CHECK(iris::get(v) == 'x'); } } { // Make sure that we are using the actual supplied attribute types // from the variant and not the expected type. - using attr_type = boost::variant; + using attr_type = iris::rvariant; { attr_type v; REQUIRE(parse("12345", int_ | +char_, v)); - CHECK(boost::get(v) == 12345); + CHECK(iris::get(v) == 12345); } { attr_type v; REQUIRE(parse("abc", int_ | +char_, v)); - CHECK(boost::get(v) == "abc"); + CHECK(iris::get(v) == "abc"); } { attr_type v; REQUIRE(parse("12345", +char_ | int_, v)); - CHECK(boost::get(v) == "12345"); + CHECK(iris::get(v) == "12345"); } } @@ -201,7 +202,7 @@ TEST_CASE("alternative") { //compile test only (bug_march_10_2011_8_35_am) - using value_type = boost::variant; + using value_type = iris::rvariant; using x4::rule; @@ -211,7 +212,7 @@ TEST_CASE("alternative") { using x4::rule; - using d_line = boost::variant; + using d_line = iris::rvariant; rule ignore; rule include; @@ -223,14 +224,14 @@ TEST_CASE("alternative") // single-element fusion vector tests { - boost::fusion::vector> fv; + boost::fusion::vector> fv; REQUIRE(parse("12345", int_ | +char_, fv)); - CHECK(boost::get(boost::fusion::at_c<0>(fv)) == 12345); + CHECK(iris::get(boost::fusion::at_c<0>(fv)) == 12345); } { - boost::fusion::vector> fvi; + boost::fusion::vector> fvi; REQUIRE(parse("12345", int_ | int_, fvi)); - CHECK(boost::get(boost::fusion::at_c<0>(fvi)) == 12345); + CHECK(iris::get(boost::fusion::at_c<0>(fvi)) == 12345); } // alternative over single element sequences as part of another sequence @@ -240,11 +241,11 @@ TEST_CASE("alternative") constexpr auto keys = key1 | key2; constexpr auto pair = keys >> lit("=") >> +char_; - boost::fusion::deque, std::string> attr_; + boost::fusion::deque, std::string> attr_; REQUIRE(parse("long=ABC", pair, attr_)); - CHECK(boost::get(&boost::fusion::front(attr_)) != nullptr); - CHECK(boost::get(&boost::fusion::front(attr_)) == nullptr); + CHECK(iris::get_if(&boost::fusion::front(attr_)) != nullptr); + CHECK(iris::get_if(&boost::fusion::front(attr_)) == nullptr); } { @@ -271,7 +272,7 @@ TEST_CASE("alternative") { // regressing test for #603 struct X {}; - std::vector> v; + std::vector> v; REQUIRE(parse("xx42x9y", *(int_ | +char_('x') | 'y' >> attr(X{})), v)); CHECK(v.size() == 5); } @@ -288,21 +289,21 @@ TEST_CASE("alternative") struct X {}; struct Y {}; struct Z {}; - boost::variant v; - boost::variant x{X{}}; - v = x; // boost::variant supports that convertion + iris::rvariant v; + iris::rvariant x{X{}}; + v = x; // iris::rvariant supports that convertion auto const p = 'x' >> attr(x) | 'z' >> attr(Z{}); REQUIRE(parse("z", p, v)); - CHECK(boost::get(&v) != nullptr); + CHECK(iris::get_if(&v) != nullptr); REQUIRE(parse("x", p, v)); - CHECK(boost::get(&v) != nullptr); + CHECK(iris::get_if(&v) != nullptr); } { // regression test for #679 - using Qaz = std::vector>; - using Foo = std::vector>; - using Bar = std::vector>; + using Qaz = std::vector>; + using Foo = std::vector>; + using Bar = std::vector>; Bar x; CHECK(parse("abaabb", +('a' >> attr(Foo{}) | 'b' >> attr(int{})), x)); } diff --git a/test/x4/raw.cpp b/test/x4/raw.cpp index 8c74f4339..99e7ee28a 100644 --- a/test/x4/raw.cpp +++ b/test/x4/raw.cpp @@ -1,6 +1,7 @@ /*============================================================================= 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) @@ -19,8 +20,9 @@ #include #include +#include + #include -#include #include #include @@ -97,10 +99,10 @@ TEST_CASE("raw") { using range = std::ranges::subrange; - boost::variant attr; + iris::rvariant attr; REQUIRE(parse("test", (int_ | raw[*char_]), attr)); - auto const& rng = boost::get(attr); + auto const& rng = iris::get(attr); CHECK(std::string(rng.begin(), rng.end()) == "test"); } diff --git a/test/x4/rule3.cpp b/test/x4/rule3.cpp index f154e4849..2d24792e0 100644 --- a/test/x4/rule3.cpp +++ b/test/x4/rule3.cpp @@ -1,6 +1,7 @@ /*============================================================================= Copyright (c) 2001-2012 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) @@ -18,11 +19,12 @@ #include #include +#include +#include + #include #include -#include - #include #include #include @@ -47,10 +49,17 @@ IRIS_X4_DEFINE(b) namespace check_recursive { -using node_t = boost::make_recursive_variant< +struct node_array; + +using node_t = iris::rvariant< int, - std::vector ->::type; + iris::recursive_wrapper +>; + +struct node_array : std::vector +{ + using std::vector::vector; +}; x4::rule const grammar; @@ -63,6 +72,7 @@ IRIS_X4_DEFINE(grammar) namespace check_recursive_scoped { using check_recursive::node_t; +using check_recursive::node_array; x4::rule const intvec; auto const grammar = intvec = '[' >> intvec % ',' >> ']' | x4::int_; @@ -147,12 +157,12 @@ TEST_CASE("rule3") using namespace check_recursive; node_t v; REQUIRE(parse("[4,2]", grammar, v)); - CHECK((node_t{std::vector{{4}, {2}}} == v)); + CHECK((node_t{node_array{{4}, {2}}} == v)); } { using namespace check_recursive_scoped; node_t v; REQUIRE(parse("[4,2]", grammar, v)); - CHECK((node_t{std::vector{{4}, {2}}} == v)); + CHECK((node_t{node_array{{4}, {2}}} == v)); } } diff --git a/test/x4/rule4.cpp b/test/x4/rule4.cpp index bbe119261..8c65f9ce0 100644 --- a/test/x4/rule4.cpp +++ b/test/x4/rule4.cpp @@ -1,6 +1,7 @@ /*============================================================================= Copyright (c) 2001-2015 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) @@ -15,11 +16,11 @@ #include #include +#include + #include #include -#include - #include #include #include @@ -153,12 +154,12 @@ TEST_CASE("rule4") } { - using v_type = boost::variant; + using v_type = iris::rvariant; auto r1 = rule{} = int_; v_type v; REQUIRE(parse("1", r1, v)); - REQUIRE(v.which() == 1); - CHECK(boost::get(v) == 1); + REQUIRE(v.index() == 1); + CHECK(iris::get(v) == 1); using ov_type = std::optional; auto r2 = rule{} = int_; diff --git a/test/x4/sequence.cpp b/test/x4/sequence.cpp index ba65c6c18..60ac50f69 100644 --- a/test/x4/sequence.cpp +++ b/test/x4/sequence.cpp @@ -1,6 +1,7 @@ /*============================================================================= Copyright (c) 2001-2015 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) @@ -25,6 +26,8 @@ #include #include +#include + #include #include #include @@ -388,7 +391,7 @@ TEST_CASE("sequence") } { - using Attr = boost::variant; + using Attr = iris::rvariant; constexpr auto term = rule("term") = int_ | float_; constexpr auto expr = rule("expr") = term | ('(' > term > ')'); Attr var;