diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12116f7f4..27f38b85c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,27 +23,45 @@ jobs: changes: runs-on: ubuntu-latest outputs: - x4_component: ${{ steps.filter.outputs.changes }} + components: ${{ steps.processed.outputs.result }} steps: - uses: actions/checkout@v5 - uses: dorny/paths-filter@v3 id: filter with: filters: | - x4: - - '.github/workflows/*.yml' - - 'modules/iris' + general: + - '.github/workflows/*.yml' - 'CMakeLists.txt' + - 'modules/iris' + - 'test/CMakeLists.txt' + alloy: + - 'include/iris/alloy/**/*' + - 'test/alloy/**/*' + x4: - 'include/iris/x4.hpp' - 'include/iris/x4/**/*' - - 'test/CMakeLists.txt' - 'test/x4/**/*' + - uses: actions/github-script@v8 + id: processed + env: + CHANGES: ${{ steps.filter.outputs.changes }} + with: + script: | + const changes = JSON.parse(process.env.CHANGES); + console.log('changes: ', changes); + let result = []; + if (changes.includes('general') || changes.includes('alloy')) result.push('alloy'); + if (changes.includes('general') || changes.includes('alloy') || changes.includes('x4')) result.push('x4'); + console.log('result: ', result); + return result; + build: - name: "[${{ matrix.cpp_version.name }}] ${{ matrix.x4_component }} | ${{ matrix.compiler.toolset }}-${{ matrix.compiler.version }} (${{ matrix.build_type.name }}) @ ${{ matrix.os.name }}-${{ matrix.os.version }}" + name: "[${{ matrix.cpp_version.name }}] ${{ matrix.components }} | ${{ matrix.compiler.toolset }}-${{ matrix.compiler.version }} (${{ matrix.build_type.name }}) @ ${{ matrix.os.name }}-${{ matrix.os.version }}" needs: changes - if: ${{ needs.changes.outputs.x4_component != '[]' && needs.changes.outputs.x4_component != '' }} + if: ${{ needs.changes.outputs.components != '[]' && needs.changes.outputs.components != '' }} runs-on: ${{ matrix.os.name }}-${{ matrix.os.version }} @@ -83,7 +101,7 @@ jobs: builder_additional_args: -- "-consoleLoggerParameters:ForceConsoleColor" executable: cl - x4_component: ${{ fromJSON(needs.changes.outputs.x4_component) }} + components: ${{ fromJSON(needs.changes.outputs.components) }} exclude: # Blacklist all invalid combinations of environments @@ -184,26 +202,15 @@ jobs: 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/io \ - libs/mp11 \ libs/mpl \ libs/predef \ libs/preprocessor \ libs/static_assert \ libs/throw_exception \ - libs/tuple \ libs/type_traits \ - libs/typeof \ libs/utility - name: Build upstream Boost libraries (Ubuntu) @@ -271,6 +278,8 @@ jobs: -DCMAKE_CXX_FLAGS="${{ matrix.compiler.cxxflags }}" \ -DCMAKE_CXX_STANDARD=${{ matrix.cpp_version.number }} \ -DCMAKE_BUILD_TYPE=${{ matrix.build_type.name }} \ + -DIRIS_TEST_ALLOY=${{ case(matrix.components == 'alloy' || matrix.components == 'x4', 'ON', 'OFF') }} \ + -DIRIS_TEST_X4=${{ case(matrix.components == 'x4', 'ON', 'OFF') }} \ -S . - name: Build Tests diff --git a/.gitignore b/.gitignore index 7149e71fc..4f84d4746 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ .DS_Store /build*/ + +# ignore preprocessed file +include/iris/alloy/detail/preprocessed/tuple_impl.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 59b14af6f..413d50126 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,64 @@ endif() add_subdirectory("${IRIS_ROOT}") +# ----------------------------------------------------------------- +# Create the alloy target + +if(MSVC) + # This needs to be `OBJECT` target to set correct `/std:` flags on IDE + add_library(iris_alloy OBJECT EXCLUDE_FROM_ALL) + set_target_properties(iris_alloy PROPERTIES LINKER_LANGUAGE CXX) + + target_link_libraries(iris_alloy PUBLIC Iris::Iris) + +else() + add_library(iris_alloy INTERFACE) + target_link_libraries(iris_alloy INTERFACE Iris::Iris) +endif() + +add_library(Iris::Alloy ALIAS iris_alloy) +set_target_properties(iris_alloy PROPERTIES CXX_EXTENSIONS OFF) + +# ----------------------------------------------------------------- +# Configure alloy target + +if(MSVC) + add_custom_command( + OUTPUT ${PROJECT_SOURCE_DIR}/include/iris/alloy/detail/preprocessed/tuple_impl.hpp + COMMAND ${PROJECT_SOURCE_DIR}/scripts/generate_tuple_members.bat + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + DEPENDS ${PROJECT_SOURCE_DIR}/include/iris/alloy/detail/tuple_impl.hpp + VERBATIM + ) +else() + add_custom_command( + OUTPUT ${PROJECT_SOURCE_DIR}/include/iris/alloy/detail/preprocessed/tuple_impl.hpp + COMMAND ${PROJECT_SOURCE_DIR}/scripts/generate_tuple_members.sh + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + DEPENDS ${PROJECT_SOURCE_DIR}/include/iris/alloy/detail/tuple_impl.hpp + VERBATIM + ) +endif() + +file( + GLOB_RECURSE IRIS_ALLOY_HEADERS + ${PROJECT_SOURCE_DIR}/include/iris/alloy/*.hpp + ${PROJECT_SOURCE_DIR}/include/iris/alloy/*.ipp +) + +list(APPEND IRIS_ALLOY_HEADERS ${PROJECT_SOURCE_DIR}/include/iris/alloy/detail/preprocessed/tuple_impl.hpp) + +target_sources( + iris_alloy + PRIVATE FILE_SET HEADERS TYPE HEADERS FILES ${IRIS_ALLOY_HEADERS} +) +source_group( + TREE ${PROJECT_SOURCE_DIR}/include/iris PREFIX iris FILES ${IRIS_ALLOY_HEADERS} +) +target_include_directories( + iris_alloy + INTERFACE ${PROJECT_SOURCE_DIR}/include +) # ----------------------------------------------------------------- # Create the main X4 target @@ -41,14 +99,14 @@ if(MSVC) iris_x4 PRIVATE # "${PROJECT_SOURCE_DIR}/cpp.hint" # TODO - # "${PROJECT_SOURCE_DIR}/iris_x4.natvis" # TODO + "${PROJECT_SOURCE_DIR}/iris_x4.natvis" ) target_link_libraries(iris_x4 PUBLIC Iris::Iris) else() add_library(iris_x4 INTERFACE) - target_link_libraries(iris_x4 INTERFACE Iris::Iris) + target_link_libraries(iris_x4 INTERFACE Iris::Iris Iris::Alloy) endif() add_library(Iris::X4 ALIAS iris_x4) @@ -60,30 +118,6 @@ set_target_properties(iris_x4 PROPERTIES CXX_EXTENSIONS OFF) set(iris_x4_boost_deps "") -# Everything required by `fusion` (manually confirmed) -list(APPEND iris_x4_boost_deps fusion) -list(APPEND iris_x4_boost_deps config) -list(APPEND iris_x4_boost_deps container_hash) -list(APPEND iris_x4_boost_deps describe) -list(APPEND iris_x4_boost_deps mp11) -list(APPEND iris_x4_boost_deps core) -list(APPEND iris_x4_boost_deps assert) -list(APPEND iris_x4_boost_deps static_assert) -list(APPEND iris_x4_boost_deps throw_exception) -list(APPEND iris_x4_boost_deps function_types) -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 type_traits) -list(APPEND iris_x4_boost_deps predef) -list(APPEND iris_x4_boost_deps utility) -list(APPEND iris_x4_boost_deps io) -list(APPEND iris_x4_boost_deps tuple) -list(APPEND iris_x4_boost_deps typeof) -list(APPEND iris_x4_boost_deps functional) -list(APPEND iris_x4_boost_deps function) -list(APPEND iris_x4_boost_deps bind) - # Everything required by `preprocessor` (manually confirmed) list(APPEND iris_x4_boost_deps preprocessor) @@ -94,6 +128,13 @@ list(APPEND iris_x4_boost_deps config) list(APPEND iris_x4_boost_deps static_assert) list(APPEND iris_x4_boost_deps throw_exception) +# Everything required by `mpl` +list(APPEND iris_x4_boost_deps mpl) +list(APPEND iris_x4_boost_deps io) +list(APPEND iris_x4_boost_deps predef) +list(APPEND iris_x4_boost_deps type_traits) +list(APPEND iris_x4_boost_deps utility) + # --------------------------------------------- list(REMOVE_DUPLICATES iris_x4_boost_deps) @@ -114,8 +155,9 @@ endforeach() file( GLOB_RECURSE IRIS_X4_HEADERS - ${PROJECT_SOURCE_DIR}/include/iris/*.hpp - ${PROJECT_SOURCE_DIR}/include/iris/*.ipp + ${PROJECT_SOURCE_DIR}/include/iris/x4/*.hpp + ${PROJECT_SOURCE_DIR}/include/iris/x4/*.ipp + ${PROJECT_SOURCE_DIR}/include/iris/x4.hpp ) target_sources( diff --git a/README.md b/README.md index f6baf801b..0e2e000fa 100644 --- a/README.md +++ b/README.md @@ -45,12 +45,9 @@ Note: Boost dependency is going to be removed entirely in the near future. ```console 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/io libs/mp11 libs/mpl libs/predef libs/preprocessor \ - libs/static_assert libs/throw_exception libs/tuple \ - libs/type_traits libs/typeof libs/utility + tools/build tools/boost_install libs/assert libs/config \ + libs/core libs/io libs/mpl libs/predef libs/preprocessor \ + libs/static_assert libs/throw_exception libs/type_traits libs/utility # Linux ./bootstrap.sh diff --git a/include/iris/alloy/adapt.hpp b/include/iris/alloy/adapt.hpp new file mode 100644 index 000000000..4def5267f --- /dev/null +++ b/include/iris/alloy/adapt.hpp @@ -0,0 +1,29 @@ +#ifndef IRIS_ALLOY_ADAPT_HPP +#define IRIS_ALLOY_ADAPT_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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) +==============================================================================*/ + +namespace iris::alloy { + +namespace detail { + +template +struct non_type_list; + +} // detail + +template +struct adaptor; + +template +using make_getters_list = detail::non_type_list; + +} // iris::alloy + +#endif diff --git a/include/iris/alloy/adapted/std_pair.hpp b/include/iris/alloy/adapted/std_pair.hpp new file mode 100644 index 000000000..7ddef5e34 --- /dev/null +++ b/include/iris/alloy/adapted/std_pair.hpp @@ -0,0 +1,34 @@ +#ifndef IRIS_ALLOY_ADAPTED_STD_PAIR_HPP +#define IRIS_ALLOY_ADAPTED_STD_PAIR_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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 + +namespace iris::alloy { + +namespace detail { + +template +struct non_type_list; + +} // detail + +template +struct adaptor; + +template +struct adaptor> +{ + using getters_list = detail::non_type_list<&std::pair::first, &std::pair::second>; +}; + +} // iris::alloy + +#endif diff --git a/include/iris/alloy/adapted/std_tuple.hpp b/include/iris/alloy/adapted/std_tuple.hpp new file mode 100644 index 000000000..ed8306e30 --- /dev/null +++ b/include/iris/alloy/adapted/std_tuple.hpp @@ -0,0 +1,52 @@ +#ifndef IRIS_ALLOY_ADAPTED_STD_TUPLE_HPP +#define IRIS_ALLOY_ADAPTED_STD_TUPLE_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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 + +#include +#include + +#include + +namespace iris::alloy { + +template +struct adaptor; + +namespace detail { + +template +struct call_std_get +{ + template + static constexpr decltype(auto) operator()(Tuple&& t) + { + return std::get(static_cast(t)); + } +}; + +template +struct make_call_std_get +{ + static constexpr auto value = call_std_get{}; +}; + +} // detail + +template +struct adaptor> +{ + using getters_list = detail::integer_seq_transform_t, detail::make_call_std_get>; +}; + +} // iris::alloy + +#endif diff --git a/include/iris/alloy/detail/deduce.hpp b/include/iris/alloy/detail/deduce.hpp new file mode 100644 index 000000000..141de7976 --- /dev/null +++ b/include/iris/alloy/detail/deduce.hpp @@ -0,0 +1,46 @@ +#ifndef IRIS_ALLOY_DETAIL_DEDUCE_HPP +#define IRIS_ALLOY_DETAIL_DEDUCE_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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 + +namespace iris::alloy::detail { + +template +struct deduce +{ + static_assert(std::conjunction_v, std::is_reference, + std::is_same, std::remove_reference_t>>); +}; + +template +struct deduce +{ + using type = T&; +}; + +template +struct deduce +{ + using type = T; +}; + +template +struct deduce +{ + using type = T; +}; + +template +using deduce_t = typename deduce::type; + +} // iris::alloy::detail + +#endif diff --git a/include/iris/alloy/detail/integer_seq_transform.hpp b/include/iris/alloy/detail/integer_seq_transform.hpp new file mode 100644 index 000000000..caa47bda9 --- /dev/null +++ b/include/iris/alloy/detail/integer_seq_transform.hpp @@ -0,0 +1,32 @@ +#ifndef IRIS_ALLOY_DETAIL_INTEGER_SEQ_TRANSFORM_HPP +#define IRIS_ALLOY_DETAIL_INTEGER_SEQ_TRANSFORM_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + + 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 + +namespace iris::alloy::detail { + +template +struct non_type_list; + +template class F> +struct integer_seq_transform; + +template class F> +struct integer_seq_transform, F> +{ + using type = detail::non_type_list::value...>; +}; + +template class F> +using integer_seq_transform_t = typename integer_seq_transform::type; + +} // iris::alloy::detail + +#endif diff --git a/include/iris/alloy/detail/preprocessed/.clang-format b/include/iris/alloy/detail/preprocessed/.clang-format new file mode 100644 index 000000000..066b8bfac --- /dev/null +++ b/include/iris/alloy/detail/preprocessed/.clang-format @@ -0,0 +1,16 @@ +AccessModifierOffset: -4 +AllowBreakBeforeNoexceptSpecifier: OnlyWithParen +AlwaysBreakTemplateDeclarations : true +ColumnLimit: 160 +FixNamespaceComments: false +IndentWidth: 4 +NamespaceIndentation: None +PointerAlignment: Left +QualifierAlignment: Right +UseTab: Never +AlignEscapedNewlines: DontAlign +BreakBeforeBraces: Mozilla +SpaceAfterTemplateKeyword: false +SpaceBeforeParens: Custom +SpaceBeforeParensOptions: + AfterRequiresInClause: true diff --git a/include/iris/alloy/detail/preprocessed/tuple_impl.hpp.post.in b/include/iris/alloy/detail/preprocessed/tuple_impl.hpp.post.in new file mode 100644 index 000000000..ddd5dae0d --- /dev/null +++ b/include/iris/alloy/detail/preprocessed/tuple_impl.hpp.post.in @@ -0,0 +1,2 @@ + +#endif diff --git a/include/iris/alloy/detail/preprocessed/tuple_impl.hpp.pre.in b/include/iris/alloy/detail/preprocessed/tuple_impl.hpp.pre.in new file mode 100644 index 000000000..36138c5a6 --- /dev/null +++ b/include/iris/alloy/detail/preprocessed/tuple_impl.hpp.pre.in @@ -0,0 +1,23 @@ +#ifndef IRIS_ALLOY_DETAIL_PREPROCESSED_TUPLE_IMPL_HPP +#define IRIS_ALLOY_DETAIL_PREPROCESSED_TUPLE_IMPL_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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 + +#include + +#include + +#include + +#include + +#include + diff --git a/include/iris/alloy/detail/tuple_comparison.hpp b/include/iris/alloy/detail/tuple_comparison.hpp new file mode 100644 index 000000000..d6d561cdd --- /dev/null +++ b/include/iris/alloy/detail/tuple_comparison.hpp @@ -0,0 +1,68 @@ +#ifndef IRIS_ALLOY_DETAIL_TUPLE_COMPARISON_HPP +#define IRIS_ALLOY_DETAIL_TUPLE_COMPARISON_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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 + +#include +#include + +namespace iris::alloy { + +template +class tuple; + +namespace detail { + +namespace equality_operator_poison_barrier { + +bool operator==(auto, auto) = delete; // poison-pill + +template +concept has_equality_operator = requires(T&& x, U&& y) { + { static_cast(x) == static_cast(y) } -> req::boolean_testable; +}; + +template +struct is_nothrow_equality_comparable : std::bool_constant && noexcept(std::declval() == std::declval())> {}; + +} // equality_operator_poison_barrier + +using equality_operator_poison_barrier::has_equality_operator; +using equality_operator_poison_barrier::is_nothrow_equality_comparable; + +template +struct do_tuple_all_elements_have_equality_operator {}; + +template +struct do_tuple_all_elements_have_equality_operator, tuple> + : std::bool_constant<(has_equality_operator && ...)> {}; + +template +inline constexpr bool do_tuple_all_elements_have_equality_operator_v = do_tuple_all_elements_have_equality_operator::value; + +template +concept tuple_all_elements_have_equality_operator = do_tuple_all_elements_have_equality_operator_v; + +template +struct are_tuple_all_elements_nothrow_equality_comparable {}; + +template +struct are_tuple_all_elements_nothrow_equality_comparable, tuple> + : std::conjunction...> {}; + +template +inline constexpr bool are_tuple_all_elements_nothrow_equality_comparable_v = are_tuple_all_elements_nothrow_equality_comparable::value; + +} // detail + +} // iris::alloy + +#endif diff --git a/include/iris/alloy/detail/tuple_impl.hpp b/include/iris/alloy/detail/tuple_impl.hpp new file mode 100644 index 000000000..2abf3a83e --- /dev/null +++ b/include/iris/alloy/detail/tuple_impl.hpp @@ -0,0 +1,521 @@ +#ifndef IRIS_ALLOY_DETAIL_TUPLE_IMPL_HPP +#define IRIS_ALLOY_DETAIL_TUPLE_IMPL_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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) +==============================================================================*/ + +#ifndef IRIS_ALLOY_GENERATE_PREPROCESSED + +#include + +#include + +#include + +#include + +#include + +#include + +#endif + +#include +#include +#include +#include +#include + +namespace iris::alloy { + +template +class tuple; + +template + requires detail::tuple_all_elements_have_equality_operator, tuple> +constexpr bool operator==(tuple const&, tuple const&) + noexcept(detail::are_tuple_all_elements_nothrow_equality_comparable_v, tuple>); + +namespace detail { + +template +class tuple_impl; + +template<> +class tuple_impl<> +{ + template + requires tuple_all_elements_have_equality_operator, tuple> + friend constexpr bool alloy::operator==(tuple const& a, tuple const& b) + noexcept(detail::are_tuple_all_elements_nothrow_equality_comparable_v, tuple>); + +private: + constexpr bool equal_to(tuple_impl const&) const noexcept { return true; } + +public: + tuple_impl() = default; + + tuple_impl(tuple_impl const&) = default; + + tuple_impl(tuple_impl&&) = default; + + constexpr tuple_impl(value_initialize_t) noexcept {} +}; + +#define IRIS_ALLOY_TUPLE_LIMIT 32 + +#define IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_1 T +#define IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_2 U +#define IRIS_ALLOY_DETAIL_FUNCTION_PARAM_1 t +#define IRIS_ALLOY_DETAIL_FUNCTION_PARAM_2 u +#define IRIS_ALLOY_DETAIL_MEMBER_PREFIX _ + +#define IRIS_ALLOY_DETAIL_TEMPLATE_PARAMS(z, n, name) BOOST_PP_COMMA_IF(n) class BOOST_PP_CAT(name, n) +#define IRIS_ALLOY_DETAIL_ARGS(z, n, name) BOOST_PP_COMMA_IF(n) BOOST_PP_CAT(name, n) + +#define IRIS_ALLOY_DETAIL_MEM_DEFS(z, n, data) \ + IRIS_NO_UNIQUE_ADDRESS BOOST_PP_CAT(IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_1, n) BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n); + +#define IRIS_ALLOY_DETAIL_FWD_PARAMS(z, n, data) \ + BOOST_PP_COMMA_IF(n) \ + BOOST_PP_CAT(IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_2, n) && BOOST_PP_CAT(IRIS_ALLOY_DETAIL_FUNCTION_PARAM_2, n) + +#define IRIS_ALLOY_DETAIL_FWD_INITS(z, n, data) \ + BOOST_PP_COMMA_IF(n) \ + BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, \ + n)(static_cast(BOOST_PP_CAT(IRIS_ALLOY_DETAIL_FUNCTION_PARAM_2, n))) + +#define IRIS_ALLOY_DETAIL_INITS(z, n, other) \ + BOOST_PP_COMMA_IF(n) \ + BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n)(other.BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n)) + +#define IRIS_ALLOY_DETAIL_NOTHROW_DEFAULT_CONSTRUCTIBLE(z, n, data) \ + BOOST_PP_COMMA_IF(n) std::is_nothrow_default_constructible + +#define IRIS_ALLOY_DETAIL_NOTHROW_CONSTRUCTIBLE(z, n, suffix) \ + BOOST_PP_COMMA_IF(n) \ + std::is_nothrow_constructible + +#define IRIS_ALLOY_DETAIL_NOTHROW_COPY_ASSIGNABLE(z, n, data) \ + BOOST_PP_COMMA_IF(n) std::is_nothrow_copy_assignable + +#define IRIS_ALLOY_DETAIL_NOTHROW_MOVE_ASSIGNABLE(z, n, data) \ + BOOST_PP_COMMA_IF(n) std::is_nothrow_move_assignable + +#define IRIS_ALLOY_DETAIL_NOTHROW_ASSIGNABLE(z, n, suffix) \ + BOOST_PP_COMMA_IF(n) \ + std::is_nothrow_assignable + +#define IRIS_ALLOY_DETAIL_VALUE_INITS(z, n, data) \ + BOOST_PP_COMMA_IF(n) BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n) {} + +#define IRIS_ALLOY_DETAIL_ASSIGN(z, n, other) \ + BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n) = other.BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n); + +#define IRIS_ALLOY_DETAIL_ASSIGN_ASSIGN(z, n, data) \ + BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n) = \ + static_cast(BOOST_PP_CAT(IRIS_ALLOY_DETAIL_FUNCTION_PARAM_2, n)); + +#define IRIS_ALLOY_DETAIL_ASSIGN_GET(z, n, other) \ + BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n) = alloy::get(static_cast(other)); + +#define IRIS_ALLOY_DETAIL_SWAP(z, n, other) \ + swap(BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n), other.BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n)); + +#define IRIS_ALLOY_DETAIL_SWAPPABLE(z, n, data) BOOST_PP_COMMA_IF(n) std::is_swappable + +#define IRIS_ALLOY_DETAIL_NOTHROW_SWAPPABLE(z, n, data) \ + BOOST_PP_COMMA_IF(n) std::is_nothrow_swappable + +#define IRIS_ALLOY_DETAIL_LVALUE_GET(z, n, data) \ + BOOST_PP_EXPR_IF(n, else) if constexpr (I == n) return BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n); + +#define IRIS_ALLOY_DETAIL_FORWARDING_GET(z, n, const_) \ + BOOST_PP_EXPR_IF(n, else) \ + if constexpr (I == n) return static_cast( \ + BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n)); + +#define IRIS_ALLOY_DETAIL_EQUAL_TO(z, n, other) \ + BOOST_PP_EXPR_IF(n, &&) BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n) == other.BOOST_PP_CAT(IRIS_ALLOY_DETAIL_MEMBER_PREFIX, n) + +#define IRIS_ALLOY_DETAIL_NOTHROW_EQUALITY_COMPARABLE(z, n, data) \ + BOOST_PP_COMMA_IF(n) \ + is_nothrow_equality_comparable + +#define IRIS_ALLOY_DETAIL_TUPLE_IMPL_DEF(z, n, data) \ + template \ + class tuple_impl \ + { \ + template \ + friend class tuple_impl; \ +\ + template \ + requires tuple_all_elements_have_equality_operator, tuple> \ + friend constexpr bool alloy::operator==(tuple const&, tuple const&) \ + noexcept(detail::are_tuple_all_elements_nothrow_equality_comparable_v, tuple>); \ +\ + private: \ + template \ + constexpr bool equal_to(tuple_impl const& other) const \ + noexcept(std::conjunction_v) \ + { \ + return BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_EQUAL_TO, other); \ + } \ +\ + public: \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_MEM_DEFS, ) \ +\ + explicit tuple_impl() = default; \ +\ + explicit tuple_impl(tuple_impl const&) = default; \ +\ + explicit tuple_impl(tuple_impl&&) = default; \ +\ + constexpr explicit tuple_impl(value_initialize_t) \ + noexcept(std::conjunction_v) \ + : BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_VALUE_INITS, ) \ + { \ + } \ +\ + template \ + constexpr explicit tuple_impl(BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_FWD_PARAMS, )) \ + noexcept(std::conjunction_v) \ + : BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_FWD_INITS, ) \ + { \ + } \ +\ + template \ + constexpr explicit tuple_impl(tuple_impl& other) \ + noexcept(std::conjunction_v) \ + : BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_INITS, other) \ + { \ + } \ +\ + template \ + constexpr explicit tuple_impl(tuple_impl const& other) \ + noexcept(std::conjunction_v) \ + : BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_INITS, other) \ + { \ + } \ +\ + template \ + constexpr explicit tuple_impl(tuple_impl&& other) \ + noexcept(std::conjunction_v) \ + : BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_INITS, static_cast(other)) \ + { \ + } \ +\ + template \ + constexpr explicit tuple_impl( \ + tuple_impl const&& other) \ + noexcept(std::conjunction_v) \ + : BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_INITS, static_cast(other)) \ + { \ + } \ +\ + constexpr tuple_impl& operator=(tuple_impl const& other) \ + noexcept(std::conjunction_v) \ + { \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_ASSIGN, other) \ + return *this; \ + } \ +\ + constexpr tuple_impl& operator=(tuple_impl&& other) \ + noexcept(std::conjunction_v) \ + { \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_ASSIGN, static_cast(other)) \ + return *this; \ + } \ +\ + template \ + constexpr tuple_impl& \ + operator=(tuple_impl const& other) \ + noexcept(std::conjunction_v) \ + { \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_ASSIGN, other) \ + return *this; \ + } \ +\ + template \ + constexpr tuple_impl& operator=(tuple_impl&& other) \ + noexcept(std::conjunction_v) \ + { \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_ASSIGN, static_cast(other)) \ + return *this; \ + } \ +\ + template \ + constexpr tuple_impl& operator=(UTuple&& other) \ + { \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_ASSIGN_GET, other) \ + return *this; \ + } \ +\ + constexpr void swap(tuple_impl& other) noexcept(std::conjunction_v) \ + { \ + static_assert(std::conjunction_v); \ + using std::swap; \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_SWAP, other) \ + } \ +\ + template \ + constexpr pack_indexing_t& get() & noexcept \ + { \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_LVALUE_GET, ) \ + } \ +\ + template \ + constexpr pack_indexing_t const& \ + get() const& noexcept \ + { \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_LVALUE_GET, ) \ + } \ +\ + template \ + constexpr pack_indexing_t&& get() && noexcept \ + { \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_FORWARDING_GET, ) \ + } \ +\ + template \ + constexpr pack_indexing_t const&& \ + get() const&& noexcept \ + { \ + BOOST_PP_REPEAT(n, IRIS_ALLOY_DETAIL_FORWARDING_GET, const) \ + } \ + }; + +BOOST_PP_REPEAT_FROM_TO(1, IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_TUPLE_IMPL_DEF, ) + +template +class tuple_impl +{ + template + friend class tuple_impl; + + template + requires tuple_all_elements_have_equality_operator, tuple> + friend constexpr bool alloy::operator==(tuple const& a, tuple const& b) + noexcept(detail::are_tuple_all_elements_nothrow_equality_comparable_v, tuple>); + +private: + template + constexpr void assign(BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_FWD_PARAMS, ), Us&&... us) + { + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_ASSIGN_ASSIGN, ) + rest.assign(static_cast(us)...); + } + + template + constexpr bool equal_to(tuple_impl const& other) const + noexcept(std::conjunction_v) \ + { + return BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_EQUAL_TO, other) && rest == other.rest; + } + +public: + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_MEM_DEFS, ) + IRIS_NO_UNIQUE_ADDRESS tuple_impl rest; + + explicit tuple_impl() = default; + + explicit tuple_impl(tuple_impl const&) = default; + + explicit tuple_impl(tuple_impl&&) = default; + + constexpr explicit tuple_impl(value_initialize_t vi) + noexcept(std::conjunction_v...>) + : BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_VALUE_INITS, ), rest(vi) + {} + + template + requires (sizeof...(Ts) == sizeof...(Us)) + constexpr explicit tuple_impl(BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_FWD_PARAMS, ), Us&&... us) + noexcept(std::conjunction_v...>) + : BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_FWD_INITS, ), rest(static_cast(us)...) + {} + + template + constexpr explicit tuple_impl( + tuple_impl& other) + noexcept(std::conjunction_v...>) + : BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_INITS, other), rest(other.rest) + {} + + template + constexpr explicit tuple_impl( + tuple_impl const& + other) noexcept(std::conjunction_v...>) + : BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_INITS, other), rest(other.rest) + {} + + template + constexpr explicit tuple_impl( + tuple_impl&& other) + noexcept(std::conjunction_v...>) + : BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_INITS, static_cast(other)), + rest(static_cast(other).rest) + {} + + template + constexpr explicit tuple_impl( + tuple_impl const&& + other) noexcept(std::conjunction_v...>) + : BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_INITS, static_cast(other)), + rest(static_cast(other).rest) + {} + + constexpr tuple_impl& operator=(tuple_impl const& other) + noexcept(std::conjunction_v...>) + { + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_ASSIGN, other) + rest = other.rest; + return *this; + } + + constexpr tuple_impl& operator=(tuple_impl&& other) + noexcept(std::conjunction_v...>) + { + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_ASSIGN, static_cast(other)) + rest = static_cast(other).rest; + return *this; + } + + template + constexpr tuple_impl& operator=( + tuple_impl const& other) + noexcept(std::conjunction_v...>) + { + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_ASSIGN, other) + rest = other.rest; + return *this; + } + + template + constexpr tuple_impl& + operator=(tuple_impl&& other) + noexcept(std::conjunction_v...>) + { + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_ASSIGN, static_cast(other)) + rest = static_cast(other).rest; + return *this; + } + + template + constexpr tuple_impl& operator=(UTuple&& other) + { + [&, this](std::index_sequence) { assign(alloy::get(static_cast(other))...); }(std::index_sequence_for{}); + return *this; + } + + constexpr void swap(tuple_impl& other) noexcept( + std::conjunction_v...>) + { + static_assert(std::conjunction_v...>); + using std::swap; + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_SWAP, other) + rest.swap(other.rest); + } + + template + constexpr pack_indexing_t< + I, + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_ARGS, IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_1), + Ts... + >& + get() & noexcept + { + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_LVALUE_GET, ) + else return rest.template get(); + } + + template + constexpr pack_indexing_t< + I, + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_ARGS, IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_1), + Ts... + > const& + get() const& noexcept + { + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_LVALUE_GET, ) + else return rest.template get(); + } + + template + constexpr pack_indexing_t< + I, + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_ARGS, IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_1), + Ts... + >&& + get() && noexcept + { + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_FORWARDING_GET, ) + else return std::move(rest).template get(); + } + + template + constexpr pack_indexing_t< + I, + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_ARGS, IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_1), + Ts... + > const&& + get() const&& noexcept + { + BOOST_PP_REPEAT(IRIS_ALLOY_TUPLE_LIMIT, IRIS_ALLOY_DETAIL_FORWARDING_GET, const) + else return std::move(rest).template get(); + } +}; + +#undef IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_1 +#undef IRIS_ALLOY_DETAIL_TEMPLATE_PARAM_2 +#undef IRIS_ALLOY_DETAIL_FUNCTION_PARAM_1 +#undef IRIS_ALLOY_DETAIL_FUNCTION_PARAM_2 +#undef IRIS_ALLOY_DETAIL_MEMBER_PREFIX +#undef IRIS_ALLOY_DETAIL_TEMPLATE_PARAMS +#undef IRIS_ALLOY_DETAIL_ARGS +#undef IRIS_ALLOY_DETAIL_MEM_DEFS +#undef IRIS_ALLOY_DETAIL_FWD_PARAMS +#undef IRIS_ALLOY_DETAIL_FWD_INITS +#undef IRIS_ALLOY_DETAIL_INITS +#undef IRIS_ALLOY_DETAIL_ASSIGN +#undef IRIS_ALLOY_DETAIL_ASSIGN_GET +#undef IRIS_ALLOY_DETAIL_NOTHROW_DEFAULT_CONSTRUCTIBLE +#undef IRIS_ALLOY_DETAIL_NOTHROW_CONSTRUCTIBLE +#undef IRIS_ALLOY_DETAIL_NOTHROW_COPY_ASSIGNABLE +#undef IRIS_ALLOY_DETAIL_NOTHROW_MOVE_ASSIGNABLE +#undef IRIS_ALLOY_DETAIL_NOTHROW_ASSIGNABLE +#undef IRIS_ALLOY_DETAIL_VALUE_INITS +#undef IRIS_ALLOY_DETAIL_LVALUE_GET +#undef IRIS_ALLOY_DETAIL_TUPLE_IMPL_DEF + +} // detail + +} // iris::alloy + +#endif diff --git a/include/iris/alloy/io.hpp b/include/iris/alloy/io.hpp new file mode 100644 index 000000000..13175be17 --- /dev/null +++ b/include/iris/alloy/io.hpp @@ -0,0 +1,50 @@ +#ifndef IRIS_ALLOY_IO_HPP +#define IRIS_ALLOY_IO_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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 + +#include +#include + +#include + +namespace iris::alloy { + +namespace detail { + +template +struct tuple_ostream_impl; + +template +struct tuple_ostream_impl> +{ + template + static constexpr std::ostream& apply(std::ostream& os, tuple const& t) + { + os << '('; + [[maybe_unused]] bool first = true; + ((std::exchange(first, false) ? os << alloy::get(t) : os << ", " << alloy::get(t)), ...); + os << ')'; + return os; + } +}; + +} // detail + +template +std::ostream& operator<<(std::ostream& os, tuple const& t) +{ + return detail::tuple_ostream_impl>::apply(os, t); +} + +} // iris::alloy + +#endif diff --git a/include/iris/alloy/traits.hpp b/include/iris/alloy/traits.hpp new file mode 100644 index 000000000..afcae7f71 --- /dev/null +++ b/include/iris/alloy/traits.hpp @@ -0,0 +1,198 @@ +#ifndef IRIS_ALLOY_COMMON_DEF_HPP +#define IRIS_ALLOY_COMMON_DEF_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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 + +#include + +#include +#include + +#include + +namespace iris::alloy { + +template +struct adaptor; + +namespace detail { + +template +struct non_type_list_size {}; + +template class TList, auto... Vs> +struct non_type_list_size> : std::integral_constant {}; + +template +struct non_type_list_indexing {}; + +template class TList, auto... Vs> +struct non_type_list_indexing> : cpack_indexing {}; + +} // detail + +struct value_initialize_t {}; + +inline constexpr value_initialize_t value_initialize{}; + +template +class tuple; + +template +struct adaptor; + +namespace detail { + +template +concept PureAdapted = requires { typename adaptor::getters_list; }; + +template +concept PureTupleLike = is_ttp_specialization_of_v || PureAdapted; + +} // detail + +template +struct is_tuple_like : std::bool_constant> {}; + +template +inline constexpr bool is_tuple_like_v = is_tuple_like::value; + +template +concept Adapted = detail::PureAdapted>; + +template +concept TupleLike = detail::PureTupleLike>; + +template +struct tuple_size {}; + +template +struct tuple_size : tuple_size {}; + +template +struct tuple_size> : std::integral_constant {}; + +template +struct tuple_size : detail::non_type_list_size::getters_list> {}; + +template +inline constexpr std::size_t tuple_size_v = tuple_size::value; + +template +struct tuple_element {}; + +template +struct tuple_element> +{ + using type = IRIS_CORE_PACK_INDEXING(I, Ts...); +}; + +template +using tuple_element_t = typename tuple_element::type; + +template +[[nodiscard]] constexpr tuple_element_t>& get(tuple& t) noexcept; + +template +[[nodiscard]] constexpr tuple_element_t> const& get(tuple const& t) noexcept; + +template +[[nodiscard]] constexpr tuple_element_t>&& get(tuple&& t) noexcept; + +template +[[nodiscard]] constexpr tuple_element_t> const&& get(tuple const&& t) noexcept; + +namespace detail { + +template +inline constexpr auto getter_of = non_type_list_indexing::getters_list>::value; + +} // namespace detail + +template +[[nodiscard]] constexpr auto get(T&& x) + noexcept(std::is_nothrow_invocable_v>), T>) + -> std::invoke_result_t>), T> +{ + return std::invoke(detail::getter_of>, std::forward(x)); +} + +namespace detail { + +template +using tuple_get_t = decltype(alloy::get(std::declval())); + +template +struct is_nothrow_gettable : std::bool_constant(std::declval()))> {}; + +template +inline constexpr bool is_nothrow_gettable_v = is_nothrow_gettable::value; + +} // detail + +template +struct tuple_element +{ + // Since we only have access through getters, we don't know exact types of user-defined tuple-like types' elements. + // Threrefore, we deduce the types from what we get from getters. + using type = detail::deduce_t&>&&, detail::tuple_get_t&&>&&>; +}; + +namespace detail { + +template +struct is_view_impl {}; + +template +struct is_view_impl> : std::conjunction>...> {}; + +template +struct is_view : std::false_type {}; + +template + requires is_tuple_like_v +struct is_view : is_view_impl>> {}; + +} // detail + +template +struct is_tuple_like_view : std::conjunction, detail::is_view> {}; + +template +concept TupleLikeView = TupleLike && detail::is_view>::value; + +template +inline constexpr bool is_tuple_like_view_v = is_tuple_like_view::value; + +namespace detail { + +template class TQual, template class UQual, class IndexSeq> +struct basic_common_reference_impl; + +template class TQual, template class UQual, std::size_t... Is> +struct basic_common_reference_impl> +{ + using type = tuple>, UQual>>...>; +}; + +} // detail + +} // iris::alloy + +template class TQual, template class UQual> + requires (iris::is_ttp_specialization_of_v || + iris::is_ttp_specialization_of_v) && + (iris::alloy::tuple_size_v == iris::alloy::tuple_size_v) +struct std::basic_common_reference + : iris::alloy::detail::basic_common_reference_impl>> {}; + +#endif diff --git a/include/iris/alloy/tuple.hpp b/include/iris/alloy/tuple.hpp new file mode 100644 index 000000000..824825fa5 --- /dev/null +++ b/include/iris/alloy/tuple.hpp @@ -0,0 +1,412 @@ +#ifndef IRIS_ALLOY_TUPLE_HPP +#define IRIS_ALLOY_TUPLE_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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) +==============================================================================*/ + +#ifndef IRIS_USE_PREPROCESSED +#define IRIS_USE_PREPROCESSED 1 +#endif + +#if IRIS_USE_PREPROCESSED +#include +#else +#include +#endif + +#include +#include + +#include +#include + +#include + +namespace iris::alloy { + +namespace detail { + +template +struct type_list; + +template +struct tuple_traits_impl; + +template +struct tuple_traits_impl, UTuple, Ts...> +{ + static constexpr bool all_convertible = std::conjunction_v, Ts>...>; + static constexpr bool all_constructible = std::conjunction_v>...>; + static constexpr bool all_nothrow_constructible = std::conjunction_v>...>; + static constexpr bool all_assignable = std::conjunction_v>...>; + static constexpr bool all_nothrow_assignable = std::conjunction_v>...>; + static constexpr bool all_nothrow_gettable = std::conjunction_v...>; +#if __cpp_lib_reference_from_temporary >= 202202L + static constexpr bool any_reference_constructs_from_temporary = std::disjunction_v>...>; +#endif +}; + +template +struct tuple_traits : tuple_traits_impl, UTuple, Ts...> {}; + +template +struct tuple_one_element_is_constructible_from_tuple + : std::bool_constant<(sizeof...(Ts) == 1) && + (std::is_convertible_v || std::is_constructible_v)> +{}; + +template +inline constexpr bool tuple_one_element_is_constructible_from_tuple_v = tuple_one_element_is_constructible_from_tuple::value; + +} // detail + +template +class tuple : public detail::tuple_impl +{ +private: + static_assert(!std::disjunction_v...>, "alloy::tuple must not be instantiated with rvalue reference type"); + using base_type = detail::tuple_impl; + + template + static constexpr bool disambiguating_constraint = []() { + if constexpr (sizeof...(Ts) == 1) { + return !std::is_same_v, tuple>; + } else { + return true; + } + }(); + + struct construct_t {}; + + static constexpr construct_t construct{}; + + template + constexpr explicit tuple(construct_t, std::index_sequence, UTuple&& other) + noexcept(detail::tuple_traits::all_nothrow_gettable && detail::tuple_traits::all_nothrow_constructible) + : base_type(alloy::get(static_cast(other))...) + {} + +public: + tuple() = default; + + tuple(tuple const&) = default; + + tuple(tuple&&) + requires std::conjunction_v...> + = default; + + constexpr explicit tuple(value_initialize_t vi) + noexcept(std::conjunction_v...>) + : base_type(vi) {} + + constexpr explicit(!std::conjunction_v...>) tuple(Ts const&... ts) + noexcept(std::conjunction_v...>) + requires requires { + requires (sizeof...(Ts) > 0); + requires std::conjunction_v...>; + } + : base_type(ts...) + {} + + template + requires requires { + requires (sizeof...(Ts) == sizeof...(Us)); + requires disambiguating_constraint; + requires std::conjunction_v...>; + } +#if __cpp_lib_reference_from_temporary >= 202202L + && (!(std::reference_constructs_from_temporary_v || ...)) +#endif + constexpr explicit(!std::conjunction_v...>) tuple(Us&&... us) + noexcept(std::conjunction_v...>) + : base_type(static_cast(us)...) + {} + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires std::negation_v...>>; + requires detail::tuple_traits&, Ts...>::all_constructible; + requires (!detail::tuple_one_element_is_constructible_from_tuple_v&, Ts...>); + } +#if __cpp_lib_reference_from_temporary >= 202202L + && (!detail::tuple_traits&, Ts...>::any_reference_constructs_from_temporary) +#endif + constexpr explicit(!detail::tuple_traits&, Ts...>::all_convertible) tuple(tuple& other) + noexcept(detail::tuple_traits&, Ts...>::all_nothrow_constructible) + : base_type(static_cast&>(other)) + {} + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires std::negation_v...>>; + requires detail::tuple_traits const&, Ts...>::all_constructible; + requires (!detail::tuple_one_element_is_constructible_from_tuple_v const&, Ts...>); + } +#if __cpp_lib_reference_from_temporary >= 202202L + && (!detail::tuple_traits const&, Ts...>::any_reference_constructs_from_temporary) +#endif + constexpr explicit(!detail::tuple_traits const&, Ts...>::all_convertible) tuple(tuple const& other) + noexcept(detail::tuple_traits const&, Ts...>::all_nothrow_constructible) + : base_type(static_cast const&>(other)) + {} + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires std::negation_v...>>; + requires detail::tuple_traits&&, Ts...>::all_constructible; + requires (!detail::tuple_one_element_is_constructible_from_tuple_v&&, Ts...>); + } +#if __cpp_lib_reference_from_temporary >= 202202L + && (!detail::tuple_traits&&, Ts...>::any_reference_constructs_from_temporary) +#endif + constexpr explicit(!detail::tuple_traits&&, Ts...>::all_convertible) tuple(tuple&& other) + noexcept(detail::tuple_traits&&, Ts...>::all_nothrow_constructible) + : base_type(static_cast&&>(other)) + {} + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires std::negation_v...>>; + requires detail::tuple_traits const&&, Ts...>::all_constructible; + requires (!detail::tuple_one_element_is_constructible_from_tuple_v const&&, Ts...>); + } +#if __cpp_lib_reference_from_temporary >= 202202L + && (!detail::tuple_traits const&&, Ts...>::any_reference_constructs_from_temporary) +#endif + constexpr explicit(!detail::tuple_traits const&&, Ts...>::all_convertible) tuple(tuple const&& other) + noexcept(detail::tuple_traits const&&, Ts...>::all_nothrow_constructible) + : base_type(static_cast const&&>(other)) + {} + + template + requires requires { + requires !std::is_same_v, tuple>; + requires sizeof...(Ts) == tuple_size_v>; + requires detail::tuple_traits::all_constructible; + requires !detail::tuple_one_element_is_constructible_from_tuple_v; + } +#if __cpp_lib_reference_from_temporary >= 202202L + && (!detail::tuple_traits::any_reference_constructs_from_temporary) +#endif + constexpr explicit(!detail::tuple_traits::all_convertible) tuple(UTuple&& other) + noexcept(detail::tuple_traits::all_nothrow_gettable && detail::tuple_traits::all_nothrow_constructible) + : tuple(construct, std::make_index_sequence>>{}, static_cast(other)) + {} + +#if __cpp_lib_reference_from_temporary >= 202202L + template + requires requires { + requires (sizeof...(Ts) == sizeof...(Us)); + requires disambiguating_constraint; + requires std::conjunction_v...>; + } + && (std::reference_constructs_from_temporary_v || ...) + constexpr explicit(!std::conjunction_v...>) tuple(Us&&... us) + noexcept(std::conjunction_v...>) + = delete; + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires std::negation_v...>>; + requires detail::tuple_traits&, Ts...>::all_constructible; + requires (!detail::tuple_one_element_is_constructible_from_tuple_v&, Ts...>); + } + && detail::tuple_traits&, Ts...>::any_reference_constructs_from_temporary + constexpr explicit(!detail::tuple_traits&, Ts...>::all_convertible) tuple(tuple& other) + noexcept(detail::tuple_traits&, Ts...>::all_nothrow_constructible) + = delete; + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires std::negation_v...>>; + requires detail::tuple_traits const&, Ts...>::all_constructible; + requires (!detail::tuple_one_element_is_constructible_from_tuple_v const&, Ts...>); + } + && detail::tuple_traits const&, Ts...>::any_reference_constructs_from_temporary + constexpr explicit(!detail::tuple_traits const&, Ts...>::all_convertible) tuple(tuple const& other) + noexcept(detail::tuple_traits const&, Ts...>::all_nothrow_constructible) + = delete; + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires std::negation_v...>>; + requires detail::tuple_traits&&, Ts...>::all_constructible; + requires (!detail::tuple_one_element_is_constructible_from_tuple_v&&, Ts...>); + } + && detail::tuple_traits&&, Ts...>::any_reference_constructs_from_temporary + constexpr explicit(!detail::tuple_traits&&, Ts...>::all_convertible) tuple(tuple&& other) + noexcept(detail::tuple_traits&&, Ts...>::all_nothrow_constructible) + = delete; + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires std::negation_v...>>; + requires detail::tuple_traits const&&, Ts...>::all_constructible; + requires (!detail::tuple_one_element_is_constructible_from_tuple_v const&&, Ts...>); + } + && detail::tuple_traits const&&, Ts...>::any_reference_constructs_from_temporary + constexpr explicit(!detail::tuple_traits const&&, Ts...>::all_convertible) tuple(tuple const&& other) + noexcept(detail::tuple_traits const&&, Ts...>::all_nothrow_constructible) + = delete; + + template + requires requires { + requires !std::is_same_v, tuple>; + requires sizeof...(Ts) == tuple_size_v>; + requires detail::tuple_traits::all_constructible; + requires !detail::tuple_one_element_is_constructible_from_tuple_v; + } + && detail::tuple_traits::any_reference_constructs_from_temporary + constexpr explicit(!detail::tuple_traits::all_convertible) tuple(UTuple&& other) + noexcept(detail::tuple_traits::all_nothrow_gettable && detail::tuple_traits::all_nothrow_constructible) + = delete; +#endif + + constexpr tuple& operator=(tuple const& other) + noexcept(std::conjunction_v...>) + { + base_type::operator=(other); + return *this; + + } + constexpr tuple& operator=(tuple&& other) + noexcept(std::conjunction_v...>) + requires std::conjunction_v...> + { + base_type::operator=(static_cast(other)); + return *this; + } + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires detail::tuple_traits const&, Ts...>::all_assignable; + } + constexpr tuple& operator=(tuple const& other) + noexcept(detail::tuple_traits const&, Ts...>::all_nothrow_assignable) + { + base_type::operator=(static_cast const&>(other)); + return *this; + } + + template + requires requires { + requires sizeof...(Ts) == sizeof...(Us); + requires detail::tuple_traits&&, Ts...>::all_assignable; + } + constexpr tuple& operator=(tuple&& other) + noexcept(detail::tuple_traits&&, Ts...>::all_nothrow_assignable) + { + base_type::operator=(static_cast &&>(other)); + return *this; + } + + template + requires requires { + requires !std::is_same_v, tuple>; + requires sizeof...(Ts) == tuple_size_v>; + requires detail::tuple_traits::all_assignable; + } + constexpr tuple& operator=(UTuple&& other) + noexcept(detail::tuple_traits::all_nothrow_assignable) + { + base_type::operator=(static_cast(other)); + return *this; + } + + constexpr void swap(tuple& other) noexcept(std::conjunction_v...>) + { + base_type::swap(other); + } + + template + [[nodiscard]] constexpr tuple_element_t& get() & noexcept + { + static_assert(I < sizeof...(Ts)); + return base_type::template get(); + } + + template + [[nodiscard]] constexpr tuple_element_t const& get() const& noexcept + { + static_assert(I < sizeof...(Ts)); + return base_type::template get(); + } + + template + [[nodiscard]] constexpr tuple_element_t&& get() && noexcept + { + static_assert(I < sizeof...(Ts)); + return std::move(*this).base_type::template get(); + } + + template + [[nodiscard]] constexpr tuple_element_t const&& get() const&& noexcept + { + static_assert(I < sizeof...(Ts)); + return std::move(*this).base_type::template get(); + } +}; + +template +tuple(Ts...) -> tuple; + +template + requires std::conjunction_v...> +constexpr void swap(tuple& a, tuple& b) noexcept(noexcept(a.swap(b))) +{ + a.swap(b); +} + +template + requires detail::tuple_all_elements_have_equality_operator, tuple> +constexpr bool operator==(tuple const& a, tuple const& b) + noexcept(detail::are_tuple_all_elements_nothrow_equality_comparable_v, tuple>) +{ + return a.equal_to(b); +} + +template +[[nodiscard]] constexpr tuple_element_t>& get(tuple& t) noexcept +{ + static_assert(I < sizeof...(Ts)); + return t.template get(); +} + +template +[[nodiscard]] constexpr tuple_element_t> const& get(tuple const& t) noexcept +{ + static_assert(I < sizeof...(Ts)); + return t.template get(); +} + +template +[[nodiscard]] constexpr tuple_element_t>&& get(tuple&& t) noexcept +{ + static_assert(I < sizeof...(Ts)); + return static_cast&&>(t).template get(); +} + +template +[[nodiscard]] constexpr tuple_element_t> const&& get(tuple const&& t) noexcept +{ + static_assert(I < sizeof...(Ts)); + return static_cast const&&>(t).template get(); +} + +} // iris::alloy + +#endif diff --git a/include/iris/alloy/utility.hpp b/include/iris/alloy/utility.hpp new file mode 100644 index 000000000..90dd8cc8d --- /dev/null +++ b/include/iris/alloy/utility.hpp @@ -0,0 +1,333 @@ +#ifndef IRIS_ALLOY_UTILITY_HPP +#define IRIS_ALLOY_UTILITY_HPP + +/*============================================================================= + Copyright (c) 2025 Yaito Kakeyama + 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 +#include + +#include +#include +#include + +#include + +namespace iris::alloy { + +namespace detail { + +template +struct type_list; + +template +struct tuple_cat_result_impl; + +template +struct tuple_cat_result_impl, type_list<>> +{ + using type = tuple; +}; + +template +struct tuple_cat_result_impl, type_list, IndexSeqs...>, Tuple, Tuples...> + : tuple_cat_result_impl>...>, type_list, Tuples...> {}; + +template +struct tuple_cat_result : tuple_cat_result_impl, type_list>>...>, Tuples...> {}; + +template +struct tuple_cat_impl_base; + +template +struct tuple_cat_impl_base> +{ + template + static constexpr bool nothrow = std::is_nothrow_constructible_v; + + template + static constexpr ResultTuple apply(Args&&... args) noexcept(nothrow) + { + return ResultTuple(std::forward(args)...); + } +}; + +template +struct tuple_cat_impl_base, IndexSeqs...>, Tuple, Tuples...> +{ + template + static constexpr bool nothrow = + tuple_cat_impl_base, Tuples...>::template nothrow && (is_nothrow_gettable_v && ...); + + template + static constexpr ResultTuple apply(Tuple&& tuple, Tuples&&... tuples, Args&&... args) noexcept(nothrow) + { + return tuple_cat_impl_base, Tuples...>::apply(std::forward(tuples)..., std::forward(args)..., + alloy::get(std::forward(tuple))...); + } +}; + +template +struct tuple_cat_impl +{ + using Base = tuple_cat_impl_base::type, + detail::type_list>>...>, Tuples...>; + + static constexpr bool nothrow = Base::template nothrow<>; + + static constexpr typename tuple_cat_result::type apply(Tuples&&... tuples) noexcept(nothrow) + { + return Base::apply(std::forward(tuples)...); + } +}; + +template +struct index_sequence_split_impl; + +template + requires (sizeof...(Is) < N) +struct index_sequence_split_impl, std::index_sequence> + : index_sequence_split_impl, std::index_sequence> {}; + +template + requires (sizeof...(Is) == N) +struct index_sequence_split_impl, std::index_sequence> +{ + using head = std::index_sequence; + using tail = std::index_sequence; +}; + +template +struct index_sequence_split : index_sequence_split_impl, IndexSeq> {}; + +template +struct index_sequence_take +{ + using type = typename index_sequence_split::head; +}; + +template +using index_sequence_take_t = typename index_sequence_take::type; + +template +struct index_sequence_drop +{ + using type = typename index_sequence_split::tail; +}; + +template +using index_sequence_drop_t = typename index_sequence_drop::type; + +template +struct index_sequence_subrange +{ + using type = index_sequence_take_t>; +}; + +template +using index_sequence_subrange_t = typename index_sequence_subrange::type; + +template +struct index_sequence_sum; + +template +struct index_sequence_sum> : std::integral_constant {}; + +template +inline constexpr std::size_t index_sequence_sum_v = index_sequence_sum::value; + +template +struct index_sequence_cumulative_sum_impl; + +template +struct index_sequence_cumulative_sum_impl, ValIndexSeq> +{ + using type = std::index_sequence<0, index_sequence_sum_v>...>; +}; + +template +struct index_sequence_cumulative_sum; + +template +struct index_sequence_cumulative_sum> + : index_sequence_cumulative_sum_impl, std::index_sequence> {}; + +template +using index_sequence_cumulative_sum_t = typename index_sequence_cumulative_sum::type; + +template +struct index_sequence_segment_impl; + +template +struct index_sequence_segment_impl, std::index_sequence> +{ + using type = type_list...>; +}; + +template +struct index_sequence_segment; + +template +struct index_sequence_segment, Sizes...> +{ + using CumSumIndexSeq = index_sequence_cumulative_sum_t>; + + using type = typename index_sequence_segment_impl, index_sequence_take_t, + index_sequence_drop_t<1, CumSumIndexSeq>>::type; +}; + +template +using index_sequence_segment_t = typename index_sequence_segment::type; + +template +struct tuple_from_tuple_and_index_sequence; + +template +struct tuple_from_tuple_and_index_sequence> +{ + using type = tuple>...>; +}; + +template +using tuple_from_tuple_and_index_sequence_t = typename tuple_from_tuple_and_index_sequence::type; + +template +struct tuple_split_result_impl; + +template +struct tuple_split_result_impl> +{ + using type = tuple...>; +}; + +template +struct tuple_split_result +{ + using type = typename tuple_split_result_impl>>, Sizes...>>::type; +}; + +template +struct tuple_split_make_inner; + +template +struct tuple_split_make_inner> +{ + static constexpr bool nothrow = std::conjunction_v< + is_nothrow_gettable..., + std::is_nothrow_constructible...> + >; + + static constexpr ResultInnerTuple apply(Tuple&& t) noexcept(nothrow) + { + return ResultInnerTuple(alloy::get(std::forward(t))...); + } +}; + +template +struct tuple_split_make_outer; + +template +struct tuple_split_make_outer, Tuple, type_list> +{ + static constexpr bool nothrow = (tuple_split_make_inner::nothrow && ...); + + static constexpr tuple apply(Tuple&& t) noexcept(nothrow) + { + return tuple(tuple_split_make_inner::apply(std::forward(t))...); + } +}; + +template +struct tuple_split_impl : tuple_split_make_outer::type, Tuple, + index_sequence_segment_t>>, Sizes...>> {}; + +template>>> +struct tuple_assign_impl; + +template +struct tuple_assign_impl> +{ + static constexpr bool nothrow = std::conjunction_v, is_nothrow_gettable>..., + std::is_nothrow_assignable, tuple_get_t>...>; + + static constexpr void apply(From&& from, To&& to) noexcept(nothrow) + { + ((void)(alloy::get(std::forward(to)) = alloy::get(std::forward(from))), ...); + } +}; + +template +struct tuple_ref_result_impl; + +template +struct tuple_ref_result_impl> +{ + using type = tuple&...>; +}; + +template +struct tuple_ref_result : tuple_ref_result_impl>> {}; + +template +struct for_each_impl; + +template +struct for_each_impl> +{ + template + static constexpr void apply(Tuple&& t, F&& f){ + ((void)std::invoke(std::forward(f), alloy::get(std::forward(t))), ...); + } +}; + +} // detail + +template +using tuple_cat_t = typename detail::tuple_cat_result::type; + +template +using tuple_split_t = typename detail::tuple_split_result::type; + +template +using tuple_ref_t = typename detail::tuple_ref_result::type; + +template +[[nodiscard]] constexpr tuple_cat_t tuple_cat(Tuples&&... tuples) noexcept(detail::tuple_cat_impl::nothrow) +{ + return detail::tuple_cat_impl::apply(std::forward(tuples)...); +} + +template +[[nodiscard]] constexpr tuple_split_t tuple_split(Tuple&& t) noexcept(detail::tuple_split_impl::nothrow) +{ + static_assert((0 + ... + Sizes) == tuple_size_v>); + return detail::tuple_split_impl::apply(std::forward(t)); +} + +template +constexpr void tuple_assign(From&& from, To&& to) noexcept(detail::tuple_assign_impl::nothrow) +{ + static_assert(tuple_size_v> == tuple_size_v>); + detail::tuple_assign_impl::apply(std::forward(from), std::forward(to)); +} + +template +[[nodiscard]] constexpr tuple_ref_t tuple_ref(Tuple& t) noexcept(std::is_nothrow_constructible_v, Tuple&>) +{ + return tuple_ref_t(t); +} + +template +constexpr void for_each(Tuple&& t, F&& f) +{ + return detail::for_each_impl>>>::apply(std::forward(t), std::forward(f)); +} + +} // iris::alloy + +#endif diff --git a/include/iris/x4/core/detail/parse_alternative.hpp b/include/iris/x4/core/detail/parse_alternative.hpp index 07d3e6924..352330273 100644 --- a/include/iris/x4/core/detail/parse_alternative.hpp +++ b/include/iris/x4/core/detail/parse_alternative.hpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -112,7 +112,7 @@ template struct pass_non_variant_attribute { using attr_type = typename std::remove_reference_t< - typename boost::fusion::result_of::front::type + alloy::tuple_element_t<0, Attr> >; using pass = pass_parser_attribute; using type = typename pass::type; @@ -120,9 +120,9 @@ struct pass_non_variant_attribute template [[nodiscard]] static constexpr type call(Attr_& attr) - noexcept(noexcept(pass::call(boost::fusion::front(attr)))) + noexcept(noexcept(pass::call(alloy::get<0>(attr)))) { - return pass::call(boost::fusion::front(attr)); + return pass::call(alloy::get<0>(attr)); } }; diff --git a/include/iris/x4/core/detail/parse_into_container.hpp b/include/iris/x4/core/detail/parse_into_container.hpp index 58ba564e8..ac90a9a5a 100644 --- a/include/iris/x4/core/detail/parse_into_container.hpp +++ b/include/iris/x4/core/detail/parse_into_container.hpp @@ -18,9 +18,7 @@ #include #include -#include -#include -#include +#include #include #include @@ -89,11 +87,11 @@ struct parse_into_container_base_impl // ------------------------------------------------------ - // Parser has attribute && it is NOT fusion sequence + // Parser has attribute && it is NOT tuple-like template Se, class Context, X4Attribute Attr> requires has_attribute_v && - (!boost::fusion::traits::is_sequence::value) + (!alloy::is_tuple_like_v) [[nodiscard]] static constexpr bool call( Parser const& parser, It& first, Se const& last, @@ -104,20 +102,20 @@ struct parse_into_container_base_impl return parse_into_container_base_impl::call_synthesize(parser, first, last, ctx, attr); } - // Parser has attribute && it is fusion sequence + // Parser has attribute && it is tuple-like template Se, class Context, X4Attribute Attr> requires has_attribute_v && - boost::fusion::traits::is_sequence::value + alloy::is_tuple_like_v [[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, boost::fusion::front(attr)))) + ) noexcept(noexcept(parse_into_container_base_impl::call_synthesize(parser, first, last, ctx, alloy::get<0>(attr)))) { - static_assert(traits::has_size_v, "Expecting a single element fusion sequence"); + static_assert(traits::has_size_v, "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, boost::fusion::front(attr)); + return parse_into_container_base_impl::call_synthesize(parser, first, last, ctx, alloy::get<0>(attr)); } // Parser has no attribute (pass unused) diff --git a/include/iris/x4/core/detail/parse_sequence.hpp b/include/iris/x4/core/detail/parse_sequence.hpp index b2aba10f2..eee6e0dcf 100644 --- a/include/iris/x4/core/detail/parse_sequence.hpp +++ b/include/iris/x4/core/detail/parse_sequence.hpp @@ -20,11 +20,8 @@ #include #include -#include -#include -#include -#include -#include +#include +#include #include #include @@ -55,15 +52,13 @@ struct pass_sequence_attribute_unused template struct pass_sequence_attribute_size_one_view { - using type = typename boost::fusion::result_of::deref< - typename boost::fusion::result_of::begin::type - >::type; + using type = alloy::tuple_element_t<0, Attr>; [[nodiscard]] static constexpr type call(Attr& attribute) - noexcept(noexcept(boost::fusion::deref(boost::fusion::begin(attribute)))) + noexcept(noexcept(alloy::get<0>(attribute))) { - return boost::fusion::deref(boost::fusion::begin(attribute)); + return alloy::get<0>(attribute); } }; @@ -114,11 +109,11 @@ struct partition_attribute static constexpr std::size_t l_size = parser_traits::sequence_size; static constexpr std::size_t r_size = parser_traits::sequence_size; - static constexpr std::size_t actual_size = static_cast(boost::fusion::result_of::size::value); + static constexpr std::size_t actual_size = alloy::tuple_size_v; static constexpr std::size_t expected_size = l_size + r_size; // If you got an error here, then you are trying to pass - // a fusion sequence with the wrong number of elements + // a tuple-like with the wrong number of elements // as that expected by the (sequence) parser. static_assert( actual_size >= expected_size, @@ -129,28 +124,23 @@ struct partition_attribute "Sequence size of the passed attribute is greater than expected." ); - using l_begin = boost::fusion::result_of::begin::type; - using l_end = boost::fusion::result_of::advance_c::type; - using r_end = boost::fusion::result_of::end::type; - using l_part = boost::fusion::iterator_range; - using r_part = boost::fusion::iterator_range; + using view = alloy::tuple_ref_t; + using splitted = alloy::tuple_split_t; + using l_part = alloy::tuple_element_t<0, splitted>; + using r_part = alloy::tuple_element_t<1, splitted>; using l_pass = pass_sequence_attribute; using r_pass = pass_sequence_attribute; [[nodiscard]] static constexpr l_part left(Attr& s) // TODO: noexcept { - auto i = boost::fusion::begin(s); - return l_part(i, boost::fusion::advance_c(i)); + return alloy::get<0>(alloy::tuple_split(alloy::tuple_ref(s))); } [[nodiscard]] static constexpr r_part right(Attr& s) // TODO: noexcept { - return r_part( - boost::fusion::advance_c(boost::fusion::begin(s)), - boost::fusion::end(s) - ); + return alloy::get<1>(alloy::tuple_split(alloy::tuple_ref(s))); } }; diff --git a/include/iris/x4/core/move_to.hpp b/include/iris/x4/core/move_to.hpp index d355a7de5..61c81534c 100644 --- a/include/iris/x4/core/move_to.hpp +++ b/include/iris/x4/core/move_to.hpp @@ -18,9 +18,8 @@ #include #include -#include -#include -#include +#include +#include #include #include @@ -120,11 +119,11 @@ template constexpr void move_to(Source&& src, Dest& dest) - noexcept(noexcept(dest = std::forward_like(boost::fusion::front(std::forward(src))))) + noexcept(noexcept(dest = std::forward_like(alloy::get<0>(std::forward(src))))) { static_assert(!std::same_as, 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(boost::fusion::front(std::forward(src))); + dest = std::forward_like(alloy::get<0>(std::forward(src))); } template Dest> @@ -144,21 +143,13 @@ template) constexpr void move_to(Source&& src, Dest& dest) - noexcept( - std::is_rvalue_reference_v ? - noexcept(boost::fusion::move(std::move(src), dest)) : - noexcept(boost::fusion::copy(src, dest)) - ) + noexcept(noexcept(alloy::tuple_assign(std::forward(src), dest))) { static_assert(!std::same_as, 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 - if constexpr (std::is_rvalue_reference_v) { - boost::fusion::move(std::move(src), dest); - } else { - boost::fusion::copy(src, dest); - } + alloy::tuple_assign(std::forward(src), dest); } template Dest> @@ -169,7 +160,7 @@ move_to(Source&& src, Dest& dest) { static_assert(!std::same_as, 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 + // dest is a variant, src is a single element tuple-like that the variant // *can* directly hold. static_assert(std::is_assignable_v); dest = std::forward(src); @@ -179,21 +170,21 @@ template && (!traits::variant_has_substitute_v) constexpr void move_to(Source&& src, Dest& dest) - noexcept(noexcept(dest = std::forward_like(boost::fusion::front(std::forward(src))))) + noexcept(noexcept(dest = std::forward_like(alloy::get<0>(std::forward(src))))) { static_assert(!std::same_as, 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. + // 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::type>, + traits::variant_has_substitute_v>, "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(boost::fusion::front(std::forward(src))); + dest = std::forward_like(alloy::get<0>(std::forward(src))); } template Dest> @@ -256,9 +247,9 @@ template Se, traits::Categorized requires traits::is_size_one_sequence_v constexpr void move_to(It first, Se last, Dest& dest) - noexcept(noexcept(x4::move_to(first, last, boost::fusion::front(dest)))) + noexcept(noexcept(x4::move_to(first, last, alloy::get<0>(dest)))) { - x4::move_to(first, last, boost::fusion::front(dest)); + x4::move_to(first, last, alloy::get<0>(dest)); } // Move non-container `src` into container `dest`. @@ -294,16 +285,16 @@ move_to(Source&& src, Dest& dest) } } -// Size-one fusion tuple forwarding +// Size-one tuple-like forwarding template Dest> requires traits::is_size_one_sequence_v constexpr void move_to(Source&& src, Dest& dest) - noexcept(noexcept(x4::move_to(std::forward(src), boost::fusion::front(dest)))) + noexcept(noexcept(x4::move_to(std::forward(src), alloy::get<0>(dest)))) { static_assert(!std::same_as, Dest>, "[BUG] This call should instead resolve to the overload handling identical types"); - x4::move_to(std::forward(src), boost::fusion::front(dest)); + x4::move_to(std::forward(src), alloy::get<0>(dest)); } template diff --git a/include/iris/x4/debug/print_attribute.hpp b/include/iris/x4/debug/print_attribute.hpp index b81774fcc..378569695 100644 --- a/include/iris/x4/debug/print_attribute.hpp +++ b/include/iris/x4/debug/print_attribute.hpp @@ -16,7 +16,7 @@ #include -#include +#include #ifdef IRIS_X4_UNICODE # include @@ -30,9 +30,9 @@ void print_attribute(Out& out, T const& val); namespace detail { template -struct print_fusion_sequence +struct print_tuple_like { - print_fusion_sequence(Out& out) + print_tuple_like(Out& out) : out(out) , is_first(true) {} @@ -114,11 +114,11 @@ struct print_attribute_debug } #endif - // for fusion data types + // for tuple-likes static void call(Out& out, CategorizedAttr auto const& val) { out << '['; - boost::fusion::for_each(val, detail::print_fusion_sequence(out)); + alloy::for_each(val, detail::print_tuple_like(out)); out << ']'; } diff --git a/include/iris/x4/operator/sequence.hpp b/include/iris/x4/operator/sequence.hpp index 949b66141..b2d95c11d 100644 --- a/include/iris/x4/operator/sequence.hpp +++ b/include/iris/x4/operator/sequence.hpp @@ -19,7 +19,7 @@ #include -#include // TODO: remove this +#include #include #include @@ -31,7 +31,7 @@ namespace iris::x4 { template struct sequence : binary_parser> { - using attribute_type = traits::attribute_of_binary::type; + using attribute_type = traits::attribute_of_binary::type; static constexpr std::size_t sequence_size = parser_traits::sequence_size + parser_traits::sequence_size; diff --git a/include/iris/x4/traits/attribute_category.hpp b/include/iris/x4/traits/attribute_category.hpp index f347abdc1..5032b1ff8 100644 --- a/include/iris/x4/traits/attribute_category.hpp +++ b/include/iris/x4/traits/attribute_category.hpp @@ -15,8 +15,7 @@ #include #include -#include -#include +#include #include @@ -89,7 +88,7 @@ concept NonUnusedAttr = !std::is_same_v>::type, unused_attr>; template - requires boost::fusion::traits::is_sequence>::value + requires alloy::is_tuple_like_v struct attribute_category { using type = tuple_attr; diff --git a/include/iris/x4/traits/container_traits.hpp b/include/iris/x4/traits/container_traits.hpp index a46272f63..c5c9b28fc 100644 --- a/include/iris/x4/traits/container_traits.hpp +++ b/include/iris/x4/traits/container_traits.hpp @@ -14,9 +14,8 @@ #include #include -#include -#include -#include +#include +#include #include #include @@ -431,9 +430,6 @@ struct is_container> template requires - // required; fusion pollutes ADL on `size`, which is called by `std::ranges::empty` on Clang 22 - (!boost::fusion::traits::is_sequence>::value) && - std::default_initializable && requires(T& c) { @@ -476,7 +472,7 @@ template using build_container_t = typename build_container::type; template -struct build_container> : build_container {}; +struct build_container> : build_container {}; template<> struct build_container diff --git a/include/iris/x4/traits/substitution.hpp b/include/iris/x4/traits/substitution.hpp index 387343517..49d2b2fa0 100644 --- a/include/iris/x4/traits/substitution.hpp +++ b/include/iris/x4/traits/substitution.hpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -52,8 +52,8 @@ struct is_substitute_impl : std::false_type {}; template requires std::conjunction_v< - boost::fusion::traits::is_sequence, - boost::fusion::traits::is_sequence + alloy::is_tuple_like, + alloy::is_tuple_like > struct is_substitute_impl : boost::mpl::equal> diff --git a/include/iris/x4/traits/tuple_traits.hpp b/include/iris/x4/traits/tuple_traits.hpp index bd277ff09..5f7810621 100644 --- a/include/iris/x4/traits/tuple_traits.hpp +++ b/include/iris/x4/traits/tuple_traits.hpp @@ -10,10 +10,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ================================================_==============================*/ -#include -#include -#include -#include +#include #include @@ -22,8 +19,8 @@ namespace iris::x4::traits { template struct has_same_size : std::bool_constant< - boost::fusion::result_of::size>::value == - boost::fusion::result_of::size>::value + alloy::tuple_size_v> == + alloy::tuple_size_v> > {}; @@ -32,7 +29,7 @@ constexpr bool has_same_size_v = has_same_size::value; template struct has_size - : std::bool_constant>::value == N> + : std::bool_constant> == N> {}; template @@ -41,8 +38,8 @@ constexpr bool has_size_v = has_size::value; template struct is_same_size_sequence : std::bool_constant>, - boost::fusion::traits::is_sequence>, + alloy::is_tuple_like>, + alloy::is_tuple_like>, has_same_size >> {}; @@ -53,7 +50,7 @@ constexpr bool is_same_size_sequence_v = is_same_size_sequence::value; template struct is_size_one_sequence : std::bool_constant>, + alloy::is_tuple_like>, has_size >> {}; @@ -64,7 +61,7 @@ constexpr bool is_size_one_sequence_v = is_size_one_sequence::value; template struct is_size_one_view : std::bool_constant>, + alloy::is_tuple_like_view>, has_size >> {}; @@ -86,7 +83,7 @@ template requires is_size_one_sequence_v> struct synthesized_value { - using type = std::remove_cvref_t::type>; + using type = std::remove_cvref_t>; }; } // iris::x4::traits diff --git a/iris_x4.natvis b/iris_x4.natvis new file mode 100644 index 000000000..5f8063c4a --- /dev/null +++ b/iris_x4.natvis @@ -0,0 +1,82 @@ + + + + + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}, {_23}, {_24}, {_25}, {_26}, {_27}, {_28}, {_29}, {_30}, {_31}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}, {_23}, {_24}, {_25}, {_26}, {_27}, {_28}, {_29}, {_30}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}, {_23}, {_24}, {_25}, {_26}, {_27}, {_28}, {_29}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}, {_23}, {_24}, {_25}, {_26}, {_27}, {_28}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}, {_23}, {_24}, {_25}, {_26}, {_27}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}, {_23}, {_24}, {_25}, {_26}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}, {_23}, {_24}, {_25}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}, {_23}, {_24}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}, {_23}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}, {_22}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}, {_21}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}, {_20}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}, {_19}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}, {_18}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}, {_17}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}, {_16}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}, {_15}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}, {_14}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}, {_13}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}, {_12}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}, {_11}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}, {_10}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}, {_9}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}, {_8}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}, {_7}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}, {_6}) + ({_0}, {_1}, {_2}, {_3}, {_4}, {_5}) + ({_0}, {_1}, {_2}, {_3}, {_4}) + ({_0}, {_1}, {_2}, {_3}) + ({_0}, {_1}, {_2}) + ({_0}, {_1}) + ({_0}) + + + _0 + _1 + _2 + _3 + _4 + _5 + _6 + _7 + _8 + _9 + _10 + _11 + _12 + _13 + _14 + _15 + _16 + _17 + _18 + _19 + _20 + _21 + _22 + _23 + _24 + _25 + _26 + _27 + _28 + _29 + _30 + _31 + + + diff --git a/scripts/generate_natvis.py b/scripts/generate_natvis.py new file mode 100644 index 000000000..29f479234 --- /dev/null +++ b/scripts/generate_natvis.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# Copyright 2026 The Iris Project Contributors +# +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +N = 32 + +print('') +print('') +print(' ') + +# DisplayString: 32 -> 1 +for k in range(N, 0, -1): + elems = ", ".join(f"{{_{i}}}" for i in range(k)) + print(f' ({elems})') + +print() +print(' ') + +# Expand: 0 -> 31 +for i in range(N): + print(f' _{i}') + +print(' ') +print(' ') +print('') diff --git a/scripts/generate_tuple_members.bat b/scripts/generate_tuple_members.bat new file mode 100644 index 000000000..38b74cb0f --- /dev/null +++ b/scripts/generate_tuple_members.bat @@ -0,0 +1,11 @@ +REM Copyright 2026 The Iris Project Contributors +REM +REM Distributed under the Boost Software License, Version 1.0. +REM https://www.boost.org/LICENSE_1_0.txt +@echo off +cl /TP /std:c++23preview /Iinclude /I..\preprocessor\include /Imodules\iris\include /P /EP /C /DIRIS_ALLOY_GENERATE_PREPROCESSED /Fiinclude\iris\alloy\detail\preprocessed\temp.hpp include\iris\alloy\detail\tuple_impl.hpp +pushd include\iris\alloy\detail\preprocessed +type tuple_impl.hpp.pre.in temp.hpp tuple_impl.hpp.post.in > tuple_impl.hpp +clang-format -i tuple_impl.hpp +del temp.hpp +popd diff --git a/scripts/generate_tuple_members.sh b/scripts/generate_tuple_members.sh new file mode 100755 index 000000000..4bf8bc68f --- /dev/null +++ b/scripts/generate_tuple_members.sh @@ -0,0 +1,10 @@ +#!/usr/bin/sh +# Copyright 2026 The Iris Project Contributors +# +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt +g++ -Iinclude -I../preprocessor/include -Imodules/iris/include -E -P -DIRIS_ALLOY_GENERATE_PREPROCESSED include/iris/alloy/detail/tuple_impl.hpp > include/iris/alloy/detail/preprocessed/temp.hpp +cd include/iris/alloy/detail/preprocessed +cat tuple_impl.hpp.pre.in temp.hpp tuple_impl.hpp.post.in > tuple_impl.hpp +clang-format -i tuple_impl.hpp +rm temp.hpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 52344c86a..8e984fbc4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,5 +5,12 @@ # https://www.boost.org/LICENSE_1_0.txt if(PROJECT_IS_TOP_LEVEL) - add_subdirectory(x4) + option(IRIS_TEST_ALLOY "test alloy" ON) + if(IRIS_TEST_ALLOY) + add_subdirectory(alloy) + endif() + option(IRIS_TEST_X4 "test x4" ON) + if(IRIS_TEST_X4) + add_subdirectory(x4) + endif() endif() diff --git a/test/alloy/CMakeLists.txt b/test/alloy/CMakeLists.txt new file mode 100644 index 000000000..9099e526d --- /dev/null +++ b/test/alloy/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2026 The Iris Project Contributors +# +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +function(alloy_define_test test_name) + iris_define_test(alloy_${test_name} ${ARGN}) + target_link_libraries(alloy_${test_name}_test PRIVATE Iris::Alloy) + set_target_properties(alloy_${test_name}_test PROPERTIES FOLDER "test/alloy") +endfunction() + +function(alloy_define_tests) + foreach(test_name IN LISTS ARGV) + alloy_define_test(${test_name} ${test_name}.cpp) + endforeach() +endfunction() + +alloy_define_tests( + alloy +) diff --git a/test/alloy/alloy.cpp b/test/alloy/alloy.cpp new file mode 100644 index 000000000..9d6e9bc9e --- /dev/null +++ b/test/alloy/alloy.cpp @@ -0,0 +1,523 @@ +/*============================================================================= + 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 + +#include +#include + +#include +#include +#include +#include + +namespace alloy = iris::alloy; + +struct NonAdaptedStruct +{}; + +struct AdaptedStruct +{ + int x; + double y; +}; + +template<> +struct alloy::adaptor +{ + using getters_list = make_getters_list<&AdaptedStruct::x, &AdaptedStruct::y>; +}; + +struct OldStyle +{ + int i; + std::string str; + int get_int() const { return i; } + std::string const& get_string() const { return str; } +}; + +template<> +struct alloy::adaptor +{ + using getters_list = make_getters_list<&OldStyle::get_int, &OldStyle::get_string>; +}; + +template +using alloy_get_t = decltype(alloy::get(std::declval())); + +namespace { + +void swap() = delete; // poison-pill + +} + +TEST_CASE("adapt_struct") +{ + + { + STATIC_CHECK(!alloy::TupleLike); + } + + { + STATIC_CHECK(alloy::TupleLike); + + STATIC_CHECK(alloy::tuple_size_v == 2); + + STATIC_CHECK(std::is_same_v, int&>); + STATIC_CHECK(std::is_same_v, int const&>); + STATIC_CHECK(std::is_same_v, int&&>); + STATIC_CHECK(std::is_same_v, int const&&>); + + STATIC_CHECK(std::is_same_v, double&>); + STATIC_CHECK(std::is_same_v, double const&>); + STATIC_CHECK(std::is_same_v, double&&>); + STATIC_CHECK(std::is_same_v, double const&&>); + + constexpr AdaptedStruct a{42, 3.14}; + + STATIC_CHECK(alloy::get<0>(a) == 42); + STATIC_CHECK(alloy::get<1>(a) == 3.14); + } + + { + STATIC_CHECK(alloy::TupleLike); + + STATIC_CHECK(alloy::tuple_size_v == 2); + + STATIC_CHECK(std::is_same_v, int>); + STATIC_CHECK(std::is_same_v, int>); + STATIC_CHECK(std::is_same_v, std::string const&>); + STATIC_CHECK(std::is_same_v, std::string const&>); + } +} + +TEST_CASE("adapt_std_pair") +{ + { + using Pair = std::pair; + + STATIC_CHECK(alloy::TupleLike); + + STATIC_CHECK(alloy::tuple_size_v == 2); + + STATIC_CHECK(std::is_same_v, int&>); + STATIC_CHECK(std::is_same_v, int const&>); + STATIC_CHECK(std::is_same_v, int&&>); + STATIC_CHECK(std::is_same_v, int const&&>); + + STATIC_CHECK(std::is_same_v, double&>); + STATIC_CHECK(std::is_same_v, double const&>); + STATIC_CHECK(std::is_same_v, double&&>); + STATIC_CHECK(std::is_same_v, double const&&>); + + constexpr Pair p(42, 3.14); + + STATIC_CHECK(alloy::get<0>(p) == 42); + STATIC_CHECK(alloy::get<1>(p) == 3.14); + } +} + +TEST_CASE("adapt_std_tuple") +{ + { + using Tuple = std::tuple; + + STATIC_CHECK(alloy::TupleLike); + + STATIC_CHECK(alloy::tuple_size_v == 3); + + STATIC_CHECK(std::is_same_v, int&>); + STATIC_CHECK(std::is_same_v, int const&>); + STATIC_CHECK(std::is_same_v, int&&>); + STATIC_CHECK(std::is_same_v, int const&&>); + + STATIC_CHECK(std::is_same_v, double&>); + STATIC_CHECK(std::is_same_v, double const&>); + STATIC_CHECK(std::is_same_v, double&&>); + STATIC_CHECK(std::is_same_v, double const&&>); + + STATIC_CHECK(std::is_same_v, char&>); + STATIC_CHECK(std::is_same_v, char const&>); + STATIC_CHECK(std::is_same_v, char&&>); + STATIC_CHECK(std::is_same_v, char const&&>); + + constexpr Tuple p(42, 3.14, 'A'); + + STATIC_CHECK(alloy::get<0>(p) == 42); + STATIC_CHECK(alloy::get<1>(p) == 3.14); + STATIC_CHECK(alloy::get<2>(p) == 'A'); + } +} + +TEST_CASE("tuple") +{ + { + STATIC_CHECK(std::is_trivially_default_constructible_v>); + + using Tuple = alloy::tuple; + + STATIC_CHECK(alloy::TupleLike); + + STATIC_CHECK(alloy::tuple_size_v == 3); + + STATIC_CHECK(std::is_same_v, int&>); + STATIC_CHECK(std::is_same_v, int const&>); + STATIC_CHECK(std::is_same_v, int&&>); + STATIC_CHECK(std::is_same_v, int const&&>); + + STATIC_CHECK(std::is_same_v, double&>); + STATIC_CHECK(std::is_same_v, double const&>); + STATIC_CHECK(std::is_same_v, double&&>); + STATIC_CHECK(std::is_same_v, double const&&>); + + STATIC_CHECK(std::is_same_v, char&>); + STATIC_CHECK(std::is_same_v, char const&>); + STATIC_CHECK(std::is_same_v, char&&>); + STATIC_CHECK(std::is_same_v, char const&&>); + + constexpr Tuple t(42, 3.14, 'A'); + + STATIC_CHECK(alloy::get<0>(t) == 42); + STATIC_CHECK(alloy::get<1>(t) == 3.14); + STATIC_CHECK(alloy::get<2>(t) == 'A'); + } + + { + using Tuple = alloy::tuple; + + STATIC_CHECK(alloy::TupleLike); + STATIC_CHECK(alloy::TupleLikeView); + + STATIC_CHECK(alloy::tuple_size_v == 3); + + STATIC_CHECK(std::is_same_v, int&>); + STATIC_CHECK(std::is_same_v, int&>); + STATIC_CHECK(std::is_same_v, int&>); + STATIC_CHECK(std::is_same_v, int&>); + + STATIC_CHECK(std::is_same_v, double&>); + STATIC_CHECK(std::is_same_v, double&>); + STATIC_CHECK(std::is_same_v, double&>); + STATIC_CHECK(std::is_same_v, double&>); + + STATIC_CHECK(std::is_same_v, char&>); + STATIC_CHECK(std::is_same_v, char&>); + STATIC_CHECK(std::is_same_v, char&>); + STATIC_CHECK(std::is_same_v, char&>); + + int x = 42; + double y = 3.14; + char z = 'A'; + Tuple const t(x, y, z); + + CHECK(alloy::get<0>(t) == 42); + CHECK(alloy::get<1>(t) == 3.14); + CHECK(alloy::get<2>(t) == 'A'); + } + + { + using Tuple = alloy::tuple; + + STATIC_CHECK(alloy::TupleLike); + STATIC_CHECK(alloy::TupleLikeView); + + STATIC_CHECK(alloy::tuple_size_v == 3); + + STATIC_CHECK(std::is_same_v, int const&>); + STATIC_CHECK(std::is_same_v, int const&>); + STATIC_CHECK(std::is_same_v, int const&>); + STATIC_CHECK(std::is_same_v, int const&>); + + STATIC_CHECK(std::is_same_v, double const&>); + STATIC_CHECK(std::is_same_v, double const&>); + STATIC_CHECK(std::is_same_v, double const&>); + STATIC_CHECK(std::is_same_v, double const&>); + + STATIC_CHECK(std::is_same_v, char const&>); + STATIC_CHECK(std::is_same_v, char const&>); + STATIC_CHECK(std::is_same_v, char const&>); + STATIC_CHECK(std::is_same_v, char const&>); + + int const x = 42; + double const y = 3.14; + char const z = 'A'; + Tuple const t(x, y, z); + + CHECK(alloy::get<0>(t) == 42); + CHECK(alloy::get<1>(t) == 3.14); + CHECK(alloy::get<2>(t) == 'A'); + } + + { + STATIC_CHECK(std::is_constructible_v, alloy::tuple&>); + STATIC_CHECK(std::is_constructible_v, alloy::tuple const&>); + STATIC_CHECK(std::is_constructible_v, alloy::tuple&&>); + STATIC_CHECK(std::is_constructible_v, alloy::tuple const&&>); + + STATIC_CHECK(std::is_nothrow_constructible_v, alloy::tuple&>); + STATIC_CHECK(std::is_nothrow_constructible_v, alloy::tuple const&>); + STATIC_CHECK(std::is_nothrow_constructible_v, alloy::tuple&&>); + STATIC_CHECK(std::is_nothrow_constructible_v, alloy::tuple const&&>); + + STATIC_CHECK(std::is_convertible_v&, alloy::tuple>); + STATIC_CHECK(std::is_convertible_v const&, alloy::tuple>); + STATIC_CHECK(std::is_convertible_v&&, alloy::tuple>); + STATIC_CHECK(std::is_convertible_v const&&, alloy::tuple>); + + STATIC_CHECK(std::is_nothrow_convertible_v&, alloy::tuple>); + STATIC_CHECK(std::is_nothrow_convertible_v const&, alloy::tuple>); + STATIC_CHECK(std::is_nothrow_convertible_v&&, alloy::tuple>); + STATIC_CHECK(std::is_nothrow_convertible_v const&&, alloy::tuple>); + + struct NeedExplicitConversion + { + explicit NeedExplicitConversion(int) {} + }; + + STATIC_CHECK(std::is_constructible_v, alloy::tuple&>); + STATIC_CHECK(std::is_constructible_v, alloy::tuple const&>); + STATIC_CHECK(std::is_constructible_v, alloy::tuple&&>); + STATIC_CHECK(std::is_constructible_v, alloy::tuple const&&>); + + STATIC_CHECK(!std::is_convertible_v&, alloy::tuple>); + STATIC_CHECK(!std::is_convertible_v const&, alloy::tuple>); + STATIC_CHECK(!std::is_convertible_v&&, alloy::tuple>); + STATIC_CHECK(!std::is_convertible_v const&&, alloy::tuple>); + + struct PotentiallyThrowing + { + PotentiallyThrowing(int) noexcept(false) {} + }; + + STATIC_CHECK(std::is_constructible_v, alloy::tuple&>); + STATIC_CHECK(std::is_constructible_v, alloy::tuple const&>); + STATIC_CHECK(std::is_constructible_v, alloy::tuple&&>); + STATIC_CHECK(std::is_constructible_v, alloy::tuple const&&>); + + STATIC_CHECK(!std::is_nothrow_constructible_v, alloy::tuple&>); + STATIC_CHECK(!std::is_nothrow_constructible_v, alloy::tuple const&>); + STATIC_CHECK(!std::is_nothrow_constructible_v, alloy::tuple&&>); + STATIC_CHECK(!std::is_nothrow_constructible_v, alloy::tuple const&&>); + + alloy::tuple a(42); + alloy::tuple b(a); + CHECK(alloy::get<0>(b) == 42L); + } + + { + STATIC_CHECK(std::is_constructible_v, AdaptedStruct>); + + constexpr AdaptedStruct a{42, 3.14}; + constexpr alloy::tuple t(a); + STATIC_CHECK(alloy::get<0>(t) == 42); + STATIC_CHECK(alloy::get<1>(t) == 3.14); + } + + { + STATIC_CHECK(std::is_nothrow_copy_assignable_v>); + STATIC_CHECK(std::is_nothrow_move_assignable_v>); + + alloy::tuple a(33), b(4); + a = b; + a = std::move(b); + CHECK(alloy::get<0>(a) == 4); + } + + { + STATIC_CHECK(std::is_nothrow_copy_assignable_v>); + STATIC_CHECK(std::is_nothrow_move_assignable_v>); + + int x = 33, y = 4; + alloy::tuple a(x); + alloy::tuple b(y); + a = b; + a = std::move(b); + CHECK(alloy::get<0>(a) == 4); + } + + { + STATIC_CHECK(std::is_assignable_v&, alloy::tuple const&>); + STATIC_CHECK(std::is_assignable_v&, alloy::tuple&&>); + STATIC_CHECK(std::is_nothrow_assignable_v&, alloy::tuple const&>); + STATIC_CHECK(std::is_nothrow_assignable_v&, alloy::tuple&&>); + + alloy::tuple a(33L); + alloy::tuple b(4); + a = b; + a = std::move(b); + CHECK(alloy::get<0>(a) == 4L); + } + + { + STATIC_CHECK(std::is_assignable_v&, AdaptedStruct const&>); + STATIC_CHECK(std::is_assignable_v&, AdaptedStruct&&>); + + alloy::tuple a(33, 3.14); + AdaptedStruct b{4, 2.18}; + a = b; + a = std::move(b); + CHECK(alloy::get<0>(a) == 4); + CHECK(alloy::get<1>(a) == 2.18); + } + + { + alloy::tuple a(33), b(4); + a.swap(b); + swap(a, b); + CHECK(alloy::get<0>(a) == 33); + CHECK(alloy::get<0>(b) == 4); + } + + { + alloy::tuple a(42, 3.14), b = a; + CHECK(a == b); + } + + { + struct Empty + {}; + struct OnlyChar + { + char c; + }; + [[maybe_unused]] constexpr alloy::tuple a = {{}, {'A'}}; + [[maybe_unused]] constexpr alloy::tuple b = {{'A'}, {}}; + STATIC_CHECK(sizeof(a) == sizeof(OnlyChar)); + STATIC_CHECK(sizeof(b) == sizeof(OnlyChar)); + } + + STATIC_CHECK(std::is_same_v, alloy::tuple&>, alloy::tuple>); + STATIC_CHECK(std::is_same_v&>, alloy::tuple>); + +#if __cpp_lib_reference_from_temporary >= 202202L + STATIC_CHECK(!std::is_constructible_v, double>); + STATIC_CHECK(!std::is_constructible_v, double&>); + STATIC_CHECK(!std::is_constructible_v, double&&>); + + STATIC_CHECK(!std::is_constructible_v, alloy::tuple&>); + STATIC_CHECK(!std::is_constructible_v, alloy::tuple&>); + + STATIC_CHECK(!std::is_constructible_v, alloy::tuple const&>); + STATIC_CHECK(!std::is_constructible_v, alloy::tuple const&>); + + STATIC_CHECK(!std::is_constructible_v, alloy::tuple&&>); + STATIC_CHECK(!std::is_constructible_v, alloy::tuple&&>); + + STATIC_CHECK(!std::is_constructible_v, alloy::tuple const&&>); + STATIC_CHECK(!std::is_constructible_v, alloy::tuple const&&>); + + STATIC_CHECK(!std::is_constructible_v, AdaptedStruct>); +#endif +} + +TEST_CASE("utility") +{ + { + constexpr alloy::tuple a(42); + constexpr alloy::tuple b(3.14); + constexpr auto c = alloy::tuple_cat(a, b); + STATIC_CHECK(alloy::get<0>(c) == 42); + STATIC_CHECK(alloy::get<1>(c) == 3.14); + } + + { + constexpr alloy::tuple a(12); + constexpr AdaptedStruct b{34, 3.14}; + constexpr auto c = alloy::tuple_cat(a, b); + STATIC_CHECK(alloy::get<0>(c) == 12); + STATIC_CHECK(alloy::get<1>(c) == 34); + STATIC_CHECK(alloy::get<2>(c) == 3.14); + } + + { + constexpr AdaptedStruct a{12, 3.14}; + constexpr alloy::tuple b(34); + constexpr auto c = alloy::tuple_cat(a, b); + STATIC_CHECK(alloy::get<0>(c) == 12); + STATIC_CHECK(alloy::get<1>(c) == 3.14); + STATIC_CHECK(alloy::get<2>(c) == 34); + } + + { + constexpr AdaptedStruct a{12, 3.14}; + constexpr AdaptedStruct b{34, 2.18}; + constexpr auto c = alloy::tuple_cat(a, b); + STATIC_CHECK(alloy::get<0>(c) == 12); + STATIC_CHECK(alloy::get<1>(c) == 3.14); + STATIC_CHECK(alloy::get<2>(c) == 34); + STATIC_CHECK(alloy::get<3>(c) == 2.18); + } + + { + OldStyle const a{12, "foo"}; + OldStyle const b{34, "bar"}; + auto const c = alloy::tuple_cat(a, b); + CHECK(alloy::get<0>(c) == 12); + CHECK(alloy::get<1>(c) == "foo"); + CHECK(alloy::get<2>(c) == 34); + CHECK(alloy::get<3>(c) == "bar"); + } + + { + constexpr alloy::tuple a(42, 3.14f, 2.18); + constexpr auto b = alloy::tuple_split<1, 2>(a); + STATIC_CHECK(alloy::get<0>(alloy::get<0>(b)) == 42); + STATIC_CHECK(alloy::get<0>(alloy::get<1>(b)) == 3.14f); + STATIC_CHECK(alloy::get<1>(alloy::get<1>(b)) == 2.18); + } + + { + alloy::tuple const from(33, 3.14); + alloy::tuple to(4, 2.18); + alloy::tuple_assign(from, to); + CHECK(alloy::get<0>(to) == 33); + CHECK(alloy::get<1>(to) == 3.14); + } + + { + alloy::tuple from(33, 3.14); + alloy::tuple to(4, 2.18); + alloy::tuple_assign(std::move(from), to); + CHECK(alloy::get<0>(to) == 33); + CHECK(alloy::get<1>(to) == 3.14); + } + + { + alloy::tuple tuple(42, 3.14); + auto view = alloy::tuple_ref(tuple); + CHECK(alloy::get<0>(view) == 42); + CHECK(alloy::get<1>(view) == 3.14); + } + + { + alloy::tuple tuple(42, 3.14); + alloy::for_each(tuple, [](auto& elem) { elem = 33 - 4; }); + CHECK(alloy::get<0>(tuple) == 29); + CHECK(alloy::get<1>(tuple) == 29.); + } +} + +TEST_CASE("io") +{ + { + { + std::stringstream ss; + ss << alloy::tuple<>(); + CHECK(ss.str() == "()"); + } + { + std::stringstream ss; + ss << alloy::tuple(42); + CHECK(ss.str() == "(42)"); + } + { + std::stringstream ss; + ss << alloy::tuple(42, 3.14); + CHECK(ss.str() == "(42, 3.14)"); + } + } +} diff --git a/test/x4/alternative.cpp b/test/x4/alternative.cpp index da0184c64..bb0db2d74 100644 --- a/test/x4/alternative.cpp +++ b/test/x4/alternative.cpp @@ -26,9 +26,8 @@ #include -#include -#include -#include +#include +#include #include #include @@ -43,13 +42,15 @@ struct di_include std::string FileName; }; -BOOST_FUSION_ADAPT_STRUCT(di_ignore, - text -) +template<> +struct alloy::adaptor { + using getters_list = make_getters_list<&di_ignore::text>; +}; -BOOST_FUSION_ADAPT_STRUCT(di_include, - FileName -) +template<> +struct alloy::adaptor { + using getters_list = make_getters_list<&di_include::FileName>; +}; struct undefined {}; @@ -130,13 +131,10 @@ TEST_CASE("alternative") // test if alternatives with all components having unused // attributes have an unused attribute - using boost::fusion::vector; - using boost::fusion::at_c; - - vector v; + alloy::tuple v; REQUIRE((parse("abc", char_ >> (omit[char_] | omit[char_]) >> char_, v))); - CHECK((at_c<0>(v) == 'a')); - CHECK((at_c<1>(v) == 'c')); + CHECK((alloy::get<0>(v) == 'a')); + CHECK((alloy::get<1>(v) == 'c')); } { @@ -222,30 +220,30 @@ TEST_CASE("alternative") (void)line; } - // single-element fusion vector tests + // single-element tuple tests { - boost::fusion::vector> fv; + alloy::tuple> fv; REQUIRE(parse("12345", int_ | +char_, fv)); - CHECK(iris::get(boost::fusion::at_c<0>(fv)) == 12345); + CHECK(iris::get(alloy::get<0>(fv)) == 12345); } { - boost::fusion::vector> fvi; + alloy::tuple> fvi; REQUIRE(parse("12345", int_ | int_, fvi)); - CHECK(iris::get(boost::fusion::at_c<0>(fvi)) == 12345); + CHECK(iris::get(alloy::get<0>(fvi)) == 12345); } - // alternative over single element sequences as part of another sequence + // alternative over single element tuple as part of another tuple { constexpr auto key1 = lit("long") >> attr(long()); constexpr auto key2 = lit("char") >> attr(char()); constexpr auto keys = key1 | key2; constexpr auto pair = keys >> lit("=") >> +char_; - boost::fusion::deque, std::string> attr_; + alloy::tuple, std::string> attr_; REQUIRE(parse("long=ABC", pair, attr_)); - CHECK(iris::get_if(&boost::fusion::front(attr_)) != nullptr); - CHECK(iris::get_if(&boost::fusion::front(attr_)) == nullptr); + CHECK(iris::get_if(&alloy::get<0>(attr_)) != nullptr); + CHECK(iris::get_if(&alloy::get<0>(attr_)) == nullptr); } { diff --git a/test/x4/attr.cpp b/test/x4/attr.cpp index b2a0463e8..01194ff5c 100644 --- a/test/x4/attr.cpp +++ b/test/x4/attr.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/test/x4/attribute.cpp b/test/x4/attribute.cpp index 3739107b7..2dee8dbd9 100644 --- a/test/x4/attribute.cpp +++ b/test/x4/attribute.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/test/x4/attribute_type_check.cpp b/test/x4/attribute_type_check.cpp index e153f446a..d70d218e6 100644 --- a/test/x4/attribute_type_check.cpp +++ b/test/x4/attribute_type_check.cpp @@ -13,9 +13,7 @@ #include #include -#include -#include -#include +#include #include #include @@ -99,7 +97,7 @@ void gen_tests(Values const&... values) { gen_single_item_tests(values...); - boost::fusion::vector attribute = boost::fusion::make_vector(values...); + alloy::tuple attribute(values...); gen_sequence_tests(attribute, values...); } @@ -111,13 +109,13 @@ void make_test(Attributes const&... attrs) gen_tests(attrs...); gen_tests< std::optional..., - boost::fusion::vector... + alloy::tuple... >(attrs..., attrs...); gen_tests< - std::optional>..., - boost::fusion::vector>... - >(boost::fusion::vector(attrs)..., attrs...); + std::optional>..., + alloy::tuple>... + >(alloy::tuple(attrs)..., attrs...); } } // anonymous diff --git a/test/x4/container_support.cpp b/test/x4/container_support.cpp index c6ea8ccee..0722b7425 100644 --- a/test/x4/container_support.cpp +++ b/test/x4/container_support.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include diff --git a/test/x4/debug.cpp b/test/x4/debug.cpp index 5701e9f52..32104d81d 100644 --- a/test/x4/debug.cpp +++ b/test/x4/debug.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -120,8 +120,8 @@ TEST_CASE("debug") { // std::container attributes - using fs = boost::fusion::vector; - rule> start("start"); + using tpl = alloy::tuple; + rule> start("start"); auto start_def = start = *(int_ >> alpha); CHECK(parse("1 a 2 b 3 c", start_def, space)); diff --git a/test/x4/expect.cpp b/test/x4/expect.cpp index 341ed37a7..553839718 100644 --- a/test/x4/expect.cpp +++ b/test/x4/expect.cpp @@ -48,8 +48,7 @@ #include #include -#include -#include +#include #include #include @@ -313,9 +312,6 @@ TEST_CASE("expect") using x4::shared_symbols; using x4::with; - using boost::fusion::vector; - using boost::fusion::at_c; - IRIS_X4_ASSERT_CONSTEXPR_CTORS(expect['x']); IRIS_X4_ASSERT_CONSTEXPR_CTORS(char_ > char_); @@ -369,27 +365,27 @@ TEST_CASE("expect") // Test that attributes with > (sequences) work just like >> (sequences) { - vector attr; + alloy::tuple attr; TEST_ATTR_SUCCESS_PASS(" a\n b\n c", char_ > char_ > char_, space, attr); - CHECK((at_c<0>(attr) == 'a')); - CHECK((at_c<1>(attr) == 'b')); - CHECK((at_c<2>(attr) == 'c')); + CHECK((alloy::get<0>(attr) == 'a')); + CHECK((alloy::get<1>(attr) == 'b')); + CHECK((alloy::get<2>(attr) == 'c')); } { - vector attr; + alloy::tuple attr; TEST_ATTR_SUCCESS_PASS(" a\n b\n c", char_ > char_ >> char_, space, attr); - CHECK((at_c<0>(attr) == 'a')); - CHECK((at_c<1>(attr) == 'b')); - CHECK((at_c<2>(attr) == 'c')); + CHECK((alloy::get<0>(attr) == 'a')); + CHECK((alloy::get<1>(attr) == 'b')); + CHECK((alloy::get<2>(attr) == 'c')); } { - vector attr; + alloy::tuple attr; TEST_ATTR_SUCCESS_PASS(" a, b, c", char_ >> ',' > char_ >> ',' > char_, space, attr); - CHECK((at_c<0>(attr) == 'a')); - CHECK((at_c<1>(attr) == 'b')); - CHECK((at_c<2>(attr) == 'c')); + CHECK((alloy::get<0>(attr) == 'a')); + CHECK((alloy::get<1>(attr) == 'b')); + CHECK((alloy::get<2>(attr) == 'c')); } { diff --git a/test/x4/int.cpp b/test/x4/int.cpp index 9f3ac3fc9..7a1cc7394 100644 --- a/test/x4/int.cpp +++ b/test/x4/int.cpp @@ -14,8 +14,7 @@ #include #include -#include -#include +#include #include @@ -232,11 +231,11 @@ TEST_CASE("int") CHECK(parse("-12", int2, i)); } - // single-element fusion vector tests + // single-element tuple tests { - boost::fusion::vector i{}; + alloy::tuple i{}; REQUIRE(parse("-123456", int_, i)); - CHECK(boost::fusion::at_c<0>(i) == -123456); + CHECK(alloy::get<0>(i) == -123456); } } diff --git a/test/x4/iris_x4_test.hpp b/test/x4/iris_x4_test.hpp index 34e42c737..45d6dbd4b 100644 --- a/test/x4/iris_x4_test.hpp +++ b/test/x4/iris_x4_test.hpp @@ -23,6 +23,7 @@ #include #include +namespace alloy = iris::alloy; namespace x4 = iris::x4; using x4::unused_type; diff --git a/test/x4/lit.cpp b/test/x4/lit.cpp index 6312820d0..ba370320a 100644 --- a/test/x4/lit.cpp +++ b/test/x4/lit.cpp @@ -16,8 +16,7 @@ #include #include -#include -#include +#include #include @@ -148,9 +147,9 @@ TEST_CASE("lit") } { - // single-element fusion vector tests - boost::fusion::vector s; + // single-element tuple tests + alloy::tuple s; REQUIRE(parse("kimpo", x4::standard::string("kimpo"), s)); - CHECK(boost::fusion::at_c<0>(s) == "kimpo"); + CHECK(alloy::get<0>(s) == "kimpo"); } } diff --git a/test/x4/omit.cpp b/test/x4/omit.cpp index 9d09141d5..bc24f4a18 100644 --- a/test/x4/omit.cpp +++ b/test/x4/omit.cpp @@ -17,8 +17,7 @@ #include #include -#include -#include +#include #include @@ -44,9 +43,6 @@ TEST_CASE("omit") using x4::int_; using x4::_attr; - using boost::fusion::vector; - using boost::fusion::at_c; - IRIS_X4_ASSERT_CONSTEXPR_CTORS(omit['x']); CHECK(parse("a", omit['a'])); @@ -60,8 +56,8 @@ TEST_CASE("omit") { // If all elements except 1 is omitted, the attribute is - // a single-element sequence. For this case alone, we allow - // naked attributes (unwrapped in a fusion sequence). + // a single-element tuple. For this case alone, we allow + // naked attributes. char attr{}; REQUIRE(parse("abc", omit[char_] >> 'b' >> char_, attr)); CHECK(attr == 'c'); @@ -69,7 +65,7 @@ TEST_CASE("omit") { // omit[] means we don't receive the attribute - vector<> attr; + alloy::tuple<> attr; CHECK(parse("abc", omit[char_] >> omit['b'] >> omit[char_], attr)); } @@ -85,18 +81,18 @@ TEST_CASE("omit") // omit[] means we don't receive the attribute, if all elements of a // sequence have unused attributes, the whole sequence has an unused // attribute as well - vector attr; + alloy::tuple attr; REQUIRE(parse("abcde", char_ >> (omit[char_] >> omit['c'] >> omit[char_]) >> char_, attr)); - CHECK(at_c<0>(attr) == 'a'); - CHECK(at_c<1>(attr) == 'e'); + CHECK(alloy::get<0>(attr) == 'a'); + CHECK(alloy::get<1>(attr) == 'e'); } { // "hello" has an unused_type. unused attrubutes are not part of the sequence - vector attr; + alloy::tuple attr; REQUIRE(parse("a hello c", char_ >> "hello" >> char_, space, attr)); - CHECK(at_c<0>(attr) == 'a'); - CHECK(at_c<1>(attr) == 'c'); + CHECK(alloy::get<0>(attr) == 'a'); + CHECK(alloy::get<1>(attr) == 'c'); } { diff --git a/test/x4/optional.cpp b/test/x4/optional.cpp index 4ff1bb769..d45152329 100644 --- a/test/x4/optional.cpp +++ b/test/x4/optional.cpp @@ -18,9 +18,8 @@ #include #include -#include -#include -#include +#include +#include #include #include @@ -37,9 +36,10 @@ struct adata std::optional b; }; -BOOST_FUSION_ADAPT_STRUCT(adata, - a, b -) +template<> +struct alloy::adaptor { + using getters_list = make_getters_list<&adata::a, &adata::b>; +}; namespace { @@ -94,8 +94,6 @@ TEST_CASE("optional") { // test propagation of unused - using boost::fusion::at_c; - using boost::fusion::vector; // optional of `unused_type` { @@ -107,10 +105,10 @@ TEST_CASE("optional") static_assert(!x4::parser_traits>::has_attribute); static_assert(std::same_as>::attribute_type, unused_type>); - vector v; + alloy::tuple v; REQUIRE(parse("a1234c", char_ >> -omit[int_] >> char_, v)); - CHECK(at_c<0>(v) == 'a'); - CHECK(at_c<1>(v) == 'c'); + CHECK(alloy::get<0>(v) == 'a'); + CHECK(alloy::get<1>(v) == 'c'); } // optional of `unused_container_type` { @@ -134,10 +132,10 @@ TEST_CASE("optional") } } { - vector v; + alloy::tuple v; REQUIRE(parse("a1234c", char_ >> omit[-int_] >> char_, v)); - CHECK(at_c<0>(v) == 'a'); - CHECK(at_c<1>(v) == 'c'); + CHECK(alloy::get<0>(v) == 'a'); + CHECK(alloy::get<1>(v) == 'c'); } { diff --git a/test/x4/plus.cpp b/test/x4/plus.cpp index 12abab392..d51da684e 100644 --- a/test/x4/plus.cpp +++ b/test/x4/plus.cpp @@ -18,8 +18,7 @@ #include #include -#include -#include +#include #include #include @@ -134,11 +133,11 @@ TEST_CASE("plus") (void)parse("abcde", +char_, x); } - // single-element fusion vector tests + // single-element tuple tests { - boost::fusion::vector fs; + alloy::tuple fs; REQUIRE(parse("12345", +char_, fs)); - CHECK(boost::fusion::at_c<0>(fs) == "12345"); + CHECK(alloy::get<0>(fs) == "12345"); } { diff --git a/test/x4/raw.cpp b/test/x4/raw.cpp index 010c0b7f4..d7e7a08ac 100644 --- a/test/x4/raw.cpp +++ b/test/x4/raw.cpp @@ -22,7 +22,7 @@ #include -#include +#include #include #include diff --git a/test/x4/rule3.cpp b/test/x4/rule3.cpp index 6b2442f56..7ad893611 100644 --- a/test/x4/rule3.cpp +++ b/test/x4/rule3.cpp @@ -22,8 +22,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -85,7 +85,10 @@ struct recursive_tuple std::vector children; }; -BOOST_FUSION_ADAPT_STRUCT(recursive_tuple, value, children) +template<> +struct alloy::adaptor { + using getters_list = make_getters_list<&recursive_tuple::value, &recursive_tuple::children>; +}; // regression test for #461 namespace check_recursive_tuple { diff --git a/test/x4/rule4.cpp b/test/x4/rule4.cpp index cf071a44d..cf1c4a21f 100644 --- a/test/x4/rule4.cpp +++ b/test/x4/rule4.cpp @@ -18,8 +18,7 @@ #include -#include -#include +#include #include #include @@ -169,15 +168,13 @@ TEST_CASE("rule4") CHECK(*ov == 1); } - // test handling of single element fusion sequences + // test handling of single element tuple { - using boost::fusion::vector; - using boost::fusion::at_c; - auto r = rule>{} = int_; + auto r = rule>{} = int_; - vector v(0); + alloy::tuple v(0); REQUIRE(parse("1", r, v)); - CHECK(at_c<0>(v) == 1); + CHECK(alloy::get<0>(v) == 1); } // attribute compatibility test diff --git a/test/x4/sequence.cpp b/test/x4/sequence.cpp index c0f9e4bd2..fc3628a70 100644 --- a/test/x4/sequence.cpp +++ b/test/x4/sequence.cpp @@ -28,10 +28,7 @@ #include -#include -#include -#include -#include +#include #include #include @@ -56,10 +53,6 @@ TEST_CASE("sequence") using x4::_attr; using x4::eps; - using boost::fusion::vector; - using boost::fusion::deque; - using boost::fusion::at_c; - IRIS_X4_ASSERT_CONSTEXPR_CTORS(char_ >> char_); CHECK(parse("aa", char_ >> char_)); @@ -76,42 +69,42 @@ TEST_CASE("sequence") CHECK(parse(" Hello, World", lit("Hello") >> ',' >> "World", space)); { - vector vec; + alloy::tuple vec; REQUIRE(parse("ab", char_ >> char_, vec)); - CHECK(at_c<0>(vec) == 'a'); - CHECK(at_c<1>(vec) == 'b'); + CHECK(alloy::get<0>(vec) == 'a'); + CHECK(alloy::get<1>(vec) == 'b'); } { - vector vec; + alloy::tuple vec; REQUIRE(parse(" a\n b\n c", char_ >> char_ >> char_, space, vec)); - CHECK(at_c<0>(vec) == 'a'); - CHECK(at_c<1>(vec) == 'b'); - CHECK(at_c<2>(vec) == 'c'); + CHECK(alloy::get<0>(vec) == 'a'); + CHECK(alloy::get<1>(vec) == 'b'); + CHECK(alloy::get<2>(vec) == 'c'); } { // 'b' has an unused_type. unused attributes are not part of the sequence - vector vec; + alloy::tuple vec; REQUIRE(parse("abc", char_ >> 'b' >> char_, vec)); - CHECK(at_c<0>(vec) == 'a'); - CHECK(at_c<1>(vec) == 'c'); + CHECK(alloy::get<0>(vec) == 'a'); + CHECK(alloy::get<1>(vec) == 'c'); } { // 'b' has an unused_type. unused attributes are not part of the sequence - vector vec; + alloy::tuple vec; REQUIRE(parse("acb", char_ >> char_ >> 'b', vec)); - CHECK(at_c<0>(vec) == 'a'); - CHECK(at_c<1>(vec) == 'c'); + CHECK(alloy::get<0>(vec) == 'a'); + CHECK(alloy::get<1>(vec) == 'c'); } { // "hello" has an unused_type. unused attributes are not part of the sequence - vector vec; + alloy::tuple vec; REQUIRE(parse("a hello c", char_ >> "hello" >> char_, space, vec)); - CHECK(at_c<0>(vec) == 'a'); - CHECK(at_c<1>(vec) == 'c'); + CHECK(alloy::get<0>(vec) == 'a'); + CHECK(alloy::get<1>(vec) == 'c'); } { @@ -122,10 +115,10 @@ TEST_CASE("sequence") } { - // a single element fusion sequence - vector vec; + // a single element tuple + alloy::tuple vec; REQUIRE(parse("ab", char_ >> 'b', vec)); - CHECK(at_c<0>(vec) == 'a'); + CHECK(alloy::get<0>(vec) == 'a'); } { @@ -134,16 +127,15 @@ TEST_CASE("sequence") // actually the issue here is that if the rhs in this case a rule // (r), it should get it (i.e. the sequence parser should not // unwrap it). It's odd that the RHS (r) does not really have a - // single element tuple (it's a deque), so the original - // comment is not accurate. + // single element tuple, so the original comment is not accurate. - using attr_type = deque; - attr_type fv; + using attr_type = alloy::tuple; + attr_type tpl; auto r = rule{} = char_ >> ',' >> int_; - REQUIRE(parse("test:x,1", "test:" >> r, fv)); - CHECK((fv == attr_type('x', 1))); + REQUIRE(parse("test:x,1", "test:" >> r, tpl)); + CHECK((tpl == attr_type('x', 1))); } { @@ -151,13 +143,13 @@ TEST_CASE("sequence") // has a single element tuple as its attribute. This is a correction // of the test above. - using attr_type = deque; - attr_type fv; + using attr_type = alloy::tuple; + attr_type tpl; auto r = rule{} = int_; - REQUIRE(parse("test:1", "test:" >> r, fv)); - CHECK((fv == attr_type(1))); + REQUIRE(parse("test:1", "test:" >> r, tpl)); + CHECK((tpl == attr_type(1))); } // unused means we don't care about the attribute @@ -344,33 +336,33 @@ TEST_CASE("sequence") // Test from spirit mailing list // "Error with container within sequence" { - using attr_type = vector; + using attr_type = alloy::tuple; attr_type vec; constexpr auto r = *alnum; REQUIRE(parse("abcdef", r, vec)); - CHECK(at_c<0>(vec) == "abcdef"); + CHECK(alloy::get<0>(vec) == "abcdef"); } { - using attr_type = vector>; + using attr_type = alloy::tuple>; attr_type vec; constexpr auto r = *int_; REQUIRE(parse("123 456", r, space, vec)); - REQUIRE(at_c<0>(vec).size() == 2); - CHECK(at_c<0>(vec)[0] == 123); - CHECK(at_c<0>(vec)[1] == 456); + REQUIRE(alloy::get<0>(vec).size() == 2); + CHECK(alloy::get<0>(vec)[0] == 123); + CHECK(alloy::get<0>(vec)[1] == 456); } { // Non-flat optional - vector>> v; + alloy::tuple>> v; constexpr auto p = int_ >> -(':' >> int_ >> '-' >> int_); REQUIRE(parse("1:2-3", p, v)); - REQUIRE(at_c<1>(v).has_value()); - CHECK(at_c<0>(*at_c<1>(v)) == 2); + REQUIRE(alloy::get<1>(v).has_value()); + CHECK(alloy::get<0>(*alloy::get<1>(v)) == 2); } // optional with container attribute @@ -378,15 +370,15 @@ TEST_CASE("sequence") constexpr auto p = char_ >> -(':' >> +char_); { - vector> v; + alloy::tuple> v; REQUIRE(parse("x", p, v)); - CHECK(!at_c<1>(v).has_value()); + CHECK(!alloy::get<1>(v).has_value()); } { - vector> v; + alloy::tuple> v; REQUIRE(parse("x:abc", p, v)); - REQUIRE(at_c<1>(v).has_value()); - CHECK(*at_c<1>(v) == "abc"); + REQUIRE(alloy::get<1>(v).has_value()); + CHECK(*alloy::get<1>(v) == "abc"); } } @@ -418,8 +410,8 @@ TEST_CASE("sequence") char c = 0; int n = 0; auto f = [&](auto&& ctx) { - c = at_c<0>(_attr(ctx)); - n = at_c<1>(_attr(ctx)); + c = alloy::get<0>(_attr(ctx)); + n = alloy::get<1>(_attr(ctx)); }; REQUIRE(parse("x123\"a string\"", (char_ >> int_ >> "\"a string\"")[f])); @@ -432,8 +424,8 @@ TEST_CASE("sequence") char c = 0; int n = 0; auto f = [&](auto&& ctx) { - c = at_c<0>(_attr(ctx)); - n = at_c<1>(_attr(ctx)); + c = alloy::get<0>(_attr(ctx)); + n = alloy::get<1>(_attr(ctx)); }; REQUIRE(parse("x 123 \"a string\"", (char_ >> int_ >> "\"a string\"")[f], space)); diff --git a/test/x4/symbols3.cpp b/test/x4/symbols3.cpp index fd2fa5ad4..e943ff53b 100644 --- a/test/x4/symbols3.cpp +++ b/test/x4/symbols3.cpp @@ -18,9 +18,8 @@ #include #include -#include -#include -#include +#include +#include #include #include @@ -32,9 +31,10 @@ struct roman std::optional c; }; -BOOST_FUSION_ADAPT_STRUCT(roman, - a, b, c -) +template<> +struct alloy::adaptor { + using getters_list = make_getters_list<&roman::a, &roman::b, &roman::c>; +}; namespace {