diff --git a/CMakeLists.txt b/CMakeLists.txt index 7594fa2..04b8214 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,13 @@ option( OFF ) +# Enable P3698 +option( + BEMAN_INPLACE_VECTOR_CROSS_CAPACITY_COMPARISON + "Enable comparison operators between vectors of different capacities. Default: OFF. Values: { ON, OFF }." + OFF +) + configure_file( "${PROJECT_SOURCE_DIR}/include/beman/inplace_vector/config_generated.hpp.in" "${PROJECT_BINARY_DIR}/include/beman/inplace_vector/config_generated.hpp" diff --git a/include/beman/inplace_vector/config.hpp b/include/beman/inplace_vector/config.hpp index 01aa0ca..673a293 100644 --- a/include/beman/inplace_vector/config.hpp +++ b/include/beman/inplace_vector/config.hpp @@ -8,6 +8,7 @@ #include #else #define BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS() 0 +#define BEMAN_INPLACE_VECTOR_CROSS_CAPACITY_COMPARISON() 0 #endif #endif diff --git a/include/beman/inplace_vector/config_generated.hpp.in b/include/beman/inplace_vector/config_generated.hpp.in index b2c8e25..e719a01 100644 --- a/include/beman/inplace_vector/config_generated.hpp.in +++ b/include/beman/inplace_vector/config_generated.hpp.in @@ -2,5 +2,6 @@ #define BEMAN_INPLACE_VECTOR_CONFIG_GENERATED_HPP #cmakedefine01 BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS() +#cmakedefine01 BEMAN_INPLACE_VECTOR_CROSS_CAPACITY_COMPARISON() #endif diff --git a/include/beman/inplace_vector/inplace_vector.hpp b/include/beman/inplace_vector/inplace_vector.hpp index dfd004f..03976a8 100644 --- a/include/beman/inplace_vector/inplace_vector.hpp +++ b/include/beman/inplace_vector/inplace_vector.hpp @@ -284,6 +284,7 @@ struct inplace_vector_base : private storage::storage_for { } // [containers.sequences.inplace_vector.data], data access + constexpr T *data() noexcept { return storage_data(); } constexpr const T *data() const noexcept { return storage_data(); } @@ -398,11 +399,6 @@ struct inplace_vector_base : private storage::storage_for { } } - constexpr friend bool operator==(const inplace_vector_base &x, - const inplace_vector_base &y) { - return x.size() == y.size() && std::ranges::equal(x, y); - } - constexpr void swap(inplace_vector_base &x) noexcept( N == 0 || (std::is_nothrow_swappable_v && std::is_nothrow_move_constructible_v)) @@ -420,6 +416,50 @@ struct inplace_vector_base : private storage::storage_for { x.swap(y); } + // [inplace.vector.comparison], comparison + +#if BEMAN_INPLACE_VECTOR_CROSS_CAPACITY_COMPARISON() + template + constexpr friend bool operator==(const inplace_vector_base &x, + const inplace_vector_base &y) { + const auto sz = std::min(x.size(), y.size()); + + return x.size() == y.size() && + std::ranges::equal(x.begin(), x.begin() + sz, y.begin(), + y.begin() + sz); + } + + template + requires std::three_way_comparable || lessthan_comparable + constexpr friend auto operator<=>(const inplace_vector_base &x, + const inplace_vector_base &y) { + using result_t = std::conditional_t, + std::compare_three_way_result, + std::strong_ordering>; + + if constexpr (std::three_way_comparable) { + return std::lexicographical_compare_three_way( + x.begin(), x.end(), y.begin(), y.end(), std::compare_three_way()); + } else { + const auto sz = std::min(x.size(), y.size()); + + for (std::size_t i = 0; i < sz; ++i) { + if (x[i] < y[i]) + return result_t::less; + if (y[i] < x[i]) + return result_t::greater; + // [container.opt.reqmts] < must be total ordering relationship + } + + return x.size() <=> y.size(); + } + } +#else + constexpr friend bool operator==(const inplace_vector_base &x, + const inplace_vector_base &y) { + return x.size() == y.size() && std::ranges::equal(x, y); + } + constexpr friend auto operator<=>(const inplace_vector_base &x, const inplace_vector_base &y) requires(details::lessthan_comparable) @@ -441,6 +481,8 @@ struct inplace_vector_base : private storage::storage_for { } } +#endif + // [containers.sequences.inplace_vector.cons], construct/copy/destroy constexpr inplace_vector_base() noexcept = default; @@ -925,6 +967,8 @@ struct inplace_vector : public details::inplace_vector_base { } // namespace freestanding +// [inplace.vector.erasure], erasure + template constexpr std::size_t erase(details::inplace_vector_base &c, const U &value) { diff --git a/tests/beman/inplace_vector/CMakeLists.txt b/tests/beman/inplace_vector/CMakeLists.txt index 83f1186..96a7dd6 100644 --- a/tests/beman/inplace_vector/CMakeLists.txt +++ b/tests/beman/inplace_vector/CMakeLists.txt @@ -2,7 +2,7 @@ find_package(GTest REQUIRED) -# Tests +# External test suite from @Hels15 add_executable(beman.inplace_vector.test inplace_vector.test.cpp) target_link_libraries(beman.inplace_vector.test PRIVATE beman.inplace_vector) @@ -20,6 +20,17 @@ add_test( COMMAND beman.inplace_vector.ref-test ) +# constexpr test +add_executable(beman.inplace_vector.tests.constexpr constexpr.test.cpp) +target_link_libraries( + beman.inplace_vector.tests.constexpr + PRIVATE beman.inplace_vector +) +add_test( + NAME beman.inplace_vector.tests.constexpr + COMMAND beman.inplace_vector.tests.constexpr +) + # GoogleTest based tests include(GoogleTest) @@ -43,7 +54,7 @@ add_gtest(erasure) add_gtest(modifiers) add_gtest(freestanding) -# only add noexception tests if NO_EXCEPTIONS option is set and compiler supports -fno-exceptions +# Only add noexception tests if NO_EXCEPTIONS option is set and compiler supports -fno-exceptions if( BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS AND ( @@ -57,14 +68,3 @@ if( PRIVATE -fno-exceptions ) endif() - -# constexpr test -add_executable(beman.inplace_vector.tests.constexpr constexpr.test.cpp) -target_link_libraries( - beman.inplace_vector.tests.constexpr - PRIVATE beman.inplace_vector -) -add_test( - NAME beman.inplace_vector.tests.constexpr - COMMAND beman.inplace_vector.tests.constexpr -) diff --git a/tests/beman/inplace_vector/README.md b/tests/beman/inplace_vector/README.md index a1993e4..c16c352 100644 --- a/tests/beman/inplace_vector/README.md +++ b/tests/beman/inplace_vector/README.md @@ -17,7 +17,7 @@ You can checkout `inplace_vector`'s [current state](https://eel.is/c++draft/inpl #### 6.1 Overview > An inplace_vector is a contiguous container. Its capacity is fixed and its -elements are stored within the inplace_vector object itself. +> elements are stored within the inplace_vector object itself. This is not testable. @@ -26,7 +26,7 @@ This is not testable. > An inplace_vector meets all of the requirements of a container ([container.reqmts]), > of a reversible container ([container.rev.reqmts]), of a contiguous container, > and of a sequence container, including most of the optional sequence -container requirements ([sequence.reqmts]). The exceptions are the push_front, +> container requirements ([sequence.reqmts]). The exceptions are the push_front, > prepend_range, pop_front, and emplace_front member functions, > which are not provided. > Descriptions are provided here only for operations on inplace_vector that @@ -50,7 +50,7 @@ Not tested for now. > then no `inplace_vector` member functions are usable in > constant expressions. -See [constexpr.test.cpp](constexpr.test.cpp), +See [constexpr.test.cpp](constexpr.test.cpp) - note that this test suite only ensure functions are usable in a constexpr environment. The validity of those functions are tested in the main test suite. @@ -67,6 +67,7 @@ These are tested with individual functions. #### 6.6 Triviality Let IV denote a specialization of `inplace_vector`. + > If N is zero, then IV is trivially copyable and empty, > and std​::​is_trivially_default_constructible_v is true. > (Sub-clauses omitted) diff --git a/tests/beman/inplace_vector/compare.test.cpp b/tests/beman/inplace_vector/compare.test.cpp index 365251b..a9a2be2 100644 --- a/tests/beman/inplace_vector/compare.test.cpp +++ b/tests/beman/inplace_vector/compare.test.cpp @@ -1,8 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - #include #include +#include + #include #include @@ -17,21 +18,23 @@ template concept lessthan_comparable = beman::inplace_vector::details::lessthan_comparable; -template struct vec_list { - T empty; +template struct vec_list { + U empty; T base; // base - T copy; // identical to base - T greater; // greater number of elements - T lesser; // lesser number of elements - T bigger; // bigger value of the elements - T smaller; // smaller value of the elements - T greater_smaller; // greater number of elements but smaller values - T lesser_bigger; // lesser number of elements but bigger values + U copy; // identical to base + U greater; // greater number of elements + U lesser; // lesser number of elements + U bigger; // bigger value of the elements + U smaller; // smaller value of the elements + U greater_smaller; // greater number of elements but smaller values + U lesser_bigger; // lesser number of elements but bigger values }; -template static void runtests(vec_list &list) { +template +static void runtests(vec_list &list) { static_assert(std::three_way_comparable || lessthan_comparable); + static_assert(std::three_way_comparable || lessthan_comparable); // if T::value_type is threewaycomparable with ordering X then T must also // be comparable with ordering X @@ -326,3 +329,41 @@ TEST(Compare, threeway_uncomparable) { static_assert(!std::three_way_comparable>); static_assert(!has_threeway>); } + +// In accordance with P3698R0, we compare vectors with identical elements but +// different capacities +#if BEMAN_INPLACE_VECTOR_CROSS_CAPACITY_COMPARISON() + +TEST(Compare, threeway_cross_capacity) { + vec_list, inplace_vector> list{ + .empty{}, + .base{1, 2, 3}, + .copy{1, 2, 3}, + .greater{4, 5, 6}, + .lesser{0, 0, 0}, + .bigger{1, 2, 3, 0}, + .smaller{1, 2}, + .greater_smaller{2, 2}, + .lesser_bigger{0, 2, 3, 4}, + }; + + runtests(list); +} + +TEST(Compare, threeway_cross_capacity_full) { + vec_list, inplace_vector> list{ + .empty{}, + .base{1, 2, 3}, + .copy{1, 2, 3}, + .greater{4, 5, 6}, + .lesser{0, 0, 0}, + .bigger{1, 2, 3, 0}, + .smaller{1, 2}, + .greater_smaller{2, 2}, + .lesser_bigger{0, 2, 3, 4}, + }; + + runtests(list); +} + +#endif diff --git a/tests/beman/inplace_vector/constexpr.test.cpp b/tests/beman/inplace_vector/constexpr.test.cpp index ace31b2..e00a284 100644 --- a/tests/beman/inplace_vector/constexpr.test.cpp +++ b/tests/beman/inplace_vector/constexpr.test.cpp @@ -1,5 +1,4 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - #include #include diff --git a/tests/beman/inplace_vector/constructors.test.cpp b/tests/beman/inplace_vector/constructors.test.cpp index ce53716..0f194ab 100644 --- a/tests/beman/inplace_vector/constructors.test.cpp +++ b/tests/beman/inplace_vector/constructors.test.cpp @@ -1,7 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include #include -#include #include #include "gtest_setup.hpp" diff --git a/tests/beman/inplace_vector/container_requirements.test.cpp b/tests/beman/inplace_vector/container_requirements.test.cpp index 7861af3..5e62843 100644 --- a/tests/beman/inplace_vector/container_requirements.test.cpp +++ b/tests/beman/inplace_vector/container_requirements.test.cpp @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include -#include "gtest/gtest.h" #include #include -#include #include #include "gtest_setup.hpp" diff --git a/tests/beman/inplace_vector/erasure.test.cpp b/tests/beman/inplace_vector/erasure.test.cpp index 8a4968c..c5209ad 100644 --- a/tests/beman/inplace_vector/erasure.test.cpp +++ b/tests/beman/inplace_vector/erasure.test.cpp @@ -1,7 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include #include -#include #include "gtest_setup.hpp" diff --git a/tests/beman/inplace_vector/freestanding.test.cpp b/tests/beman/inplace_vector/freestanding.test.cpp index a26429e..79e6b58 100644 --- a/tests/beman/inplace_vector/freestanding.test.cpp +++ b/tests/beman/inplace_vector/freestanding.test.cpp @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include #include #include +#include + // constexpr void assign(InputIterator first, InputIterator last); template concept has_assign_iterator = requires(T t, T::iterator it) { diff --git a/tests/beman/inplace_vector/gtest_setup.hpp b/tests/beman/inplace_vector/gtest_setup.hpp index 87a615f..3b9e849 100644 --- a/tests/beman/inplace_vector/gtest_setup.hpp +++ b/tests/beman/inplace_vector/gtest_setup.hpp @@ -1,9 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - +#include #include -#include -#include "beman/inplace_vector/inplace_vector.hpp" +#include // We run the tests on various element types with the help of GoogleTest's // typed tests. Which types shall we use? @@ -287,7 +286,7 @@ struct NonTrivial { } friend constexpr bool operator==(NonTrivial x, NonTrivial y) = default; }; -std::size_t NonTrivial::num_objects; +inline std::size_t NonTrivial::num_objects; template struct counts_objects : std::false_type {}; diff --git a/tests/beman/inplace_vector/inplace_vector.test.cpp b/tests/beman/inplace_vector/inplace_vector.test.cpp index 4d3d795..5652b68 100644 --- a/tests/beman/inplace_vector/inplace_vector.test.cpp +++ b/tests/beman/inplace_vector/inplace_vector.test.cpp @@ -1,5 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include + #include using namespace beman::inplace_vector; diff --git a/tests/beman/inplace_vector/modifiers.test.cpp b/tests/beman/inplace_vector/modifiers.test.cpp index 4f702e3..1891fad 100644 --- a/tests/beman/inplace_vector/modifiers.test.cpp +++ b/tests/beman/inplace_vector/modifiers.test.cpp @@ -1,9 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include #include #include "gtest_setup.hpp" -#include namespace { // 23.3.14.5 Modifiers [inplace.vector.modifiers] diff --git a/tests/beman/inplace_vector/noexceptions.test.cpp b/tests/beman/inplace_vector/noexceptions.test.cpp index 74d103a..9204791 100644 --- a/tests/beman/inplace_vector/noexceptions.test.cpp +++ b/tests/beman/inplace_vector/noexceptions.test.cpp @@ -1,4 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// #include 'BEMAN_IV_THROW_OR_ABORT' +// macro redfined +#include #include diff --git a/tests/beman/inplace_vector/ref_impl.test.cpp b/tests/beman/inplace_vector/ref_impl.test.cpp index e7f9d1a..c869c06 100644 --- a/tests/beman/inplace_vector/ref_impl.test.cpp +++ b/tests/beman/inplace_vector/ref_impl.test.cpp @@ -1,5 +1,4 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - #pragma GCC diagnostic ignored "-Wsign-compare" /// \file diff --git a/tests/beman/inplace_vector/size_n_data.test.cpp b/tests/beman/inplace_vector/size_n_data.test.cpp index 7b857c6..71f03db 100644 --- a/tests/beman/inplace_vector/size_n_data.test.cpp +++ b/tests/beman/inplace_vector/size_n_data.test.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - +#include #include + #include #include "gtest_setup.hpp" diff --git a/tests/beman/inplace_vector/triviality.test.cpp b/tests/beman/inplace_vector/triviality.test.cpp index 0d8d6f9..2db11a3 100644 --- a/tests/beman/inplace_vector/triviality.test.cpp +++ b/tests/beman/inplace_vector/triviality.test.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - +#include #include #include "gtest_setup.hpp"