From f4ff4aef25554eca58a50965736750f22bab972a Mon Sep 17 00:00:00 2001 From: isidorostsa Date: Wed, 27 Mar 2024 15:48:56 -0500 Subject: [PATCH 01/10] Add inplace_vector as specialization of small_vector --- .../datastructures/detail/small_vector.hpp | 107 ++++++++++++++++-- 1 file changed, 99 insertions(+), 8 deletions(-) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index d6379378d138..ebb890e5b288 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -218,7 +218,7 @@ namespace hpx::detail { // note: Allocator is currently unused template > + typename Allocator = std::allocator, bool emulate_inplace_vector = false> class small_vector { static_assert(MinInlineCapacity <= 127, @@ -249,7 +249,8 @@ namespace hpx::detail { [[nodiscard]] constexpr auto is_direct() const noexcept -> bool { - return (m_data[0] & 1U) != 0U; + if constexpr (emulate_inplace_vector) return true; + else return (m_data[0] & 1U) != 0U; } [[nodiscard]] auto indirect() noexcept -> storage* @@ -310,6 +311,7 @@ namespace hpx::detail { void realloc(std::size_t new_capacity) { + static_assert(!emulate_inplace_vector, "If called in an inplace_vector, it is a bug."); if (new_capacity <= N) { // put everything into direct storage @@ -539,9 +541,17 @@ namespace hpx::detail { template void assign(It first, It last, std::forward_iterator_tag /*unused*/) { + auto s = std::distance(first, last); + if constexpr (emulate_inplace_vector) + { + // Can not have an inplace_vector with a size larger than N + if (s <= capacity()) { + throw std::bad_alloc(); + } + } + clear(); - auto s = std::distance(first, last); reserve(s); std::uninitialized_copy(first, last, data()); set_size(s); @@ -577,7 +587,7 @@ namespace hpx::detail { // * source_begin <= target_begin // * source_end onwards is uninitialized memory // - // Destroys then empty elements in [source_begin, source_end) + // Destroys the empty elements in [source_begin, source_end) auto shift_right( T* source_begin, T* source_end, T* target_begin) noexcept { @@ -594,7 +604,7 @@ namespace hpx::detail { std::destroy(source_begin, (std::min)(source_end, target_begin)); } - // makes space for uninitialized data of cout elements. Also updates + // makes space for uninitialized data of count elements. Also updates // size. template [[nodiscard]] auto make_uninitialized_space_new( @@ -710,12 +720,26 @@ namespace hpx::detail { std::size_t count, T const& value, Allocator const& = Allocator()) : small_vector() { + if constexpr (emulate_inplace_vector) + { + // Can not have an inplace_vector with a size larger than N + if (count > N) { + throw std::bad_alloc(); + } + } resize(count, value); } explicit small_vector(std::size_t count, Allocator const& = Allocator()) : small_vector() { + if constexpr (emulate_inplace_vector) + { + // Can not have an inplace_vector with a size larger than N + if (count > N) { + throw std::bad_alloc(); + } + } reserve(count); if (is_direct()) { @@ -741,7 +765,14 @@ namespace hpx::detail { : small_vector() { auto s = other.size(); - reserve(s); + // If both vectors are direct with the same capacity it will fit + // without further allocations needed. + + if constexpr (!emulate_inplace_vector) + { + reserve(s); + } + std::uninitialized_copy(other.begin(), other.end(), begin()); set_size(s); } @@ -816,6 +847,13 @@ namespace hpx::detail { void resize(std::size_t count) { + if constexpr (emulate_inplace_vector) { + // Static vector cannot be resized beyond capacity + if (count > N) { + throw std::bad_alloc(); + } + } + if (count > capacity()) { reserve(count); @@ -833,6 +871,13 @@ namespace hpx::detail { void resize(std::size_t count, value_type const& value) { + if constexpr (emulate_inplace_vector) { + // Static vector cannot resize beyond capacity + if (count > N) { + throw std::bad_alloc(); + } + } + if (count > capacity()) { reserve(count); @@ -850,6 +895,12 @@ namespace hpx::detail { auto reserve(std::size_t s) { + if constexpr (emulate_inplace_vector) { + // Static vector cannot reserve beyond capacity + if (s > N) { + throw std::bad_alloc(); + } + } auto const old_capacity = capacity(); auto const new_capacity = calculate_new_capacity(s, old_capacity); if (new_capacity > old_capacity) @@ -860,6 +911,9 @@ namespace hpx::detail { [[nodiscard]] constexpr auto capacity() const noexcept -> std::size_t { + if constexpr (emulate_inplace_vector) { + return capacity(); + } if (is_direct()) { return capacity(); @@ -898,7 +952,15 @@ namespace hpx::detail { if (is_direct()) { s = direct_size(); - if (s < N) + if constexpr (emulate_inplace_vector) { + // Exceeded static_storage + if (s + 1 > N) { + throw std::bad_alloc(); + } + } + + // avoid double-checking for inplace_vector + if (emulate_inplace_vector || s < N) { set_direct_and_size(s + 1); return *hpx::construct_at( @@ -1097,6 +1159,7 @@ namespace hpx::detail { [[nodiscard]] static constexpr auto max_size() -> std::size_t { + if constexpr (emulate_inplace_vector) return N; return (std::numeric_limits::max)(); } @@ -1110,6 +1173,12 @@ namespace hpx::detail { { // per the standard we wouldn't need to do anything here. But since // we are so nice, let's do the shrink. + + if constexpr (emulate_inplace_vector) { + // Can not change the capacity of a static vector so noop + return; + } + auto const c = capacity(); auto const s = size(); if (s >= c) @@ -1130,6 +1199,12 @@ namespace hpx::detail { template auto emplace(const_iterator pos, Args&&... args) -> iterator { + if constexpr(emulate_inplace_vector) { + // it will be expanded by one element + if (direct_size() + 1 > N) { + throw std::bad_alloc(); + } + } auto* p = make_uninitialized_space(pos, 1); return hpx::construct_at( static_cast(p), HPX_FORWARD(Args, args)...); @@ -1148,6 +1223,11 @@ namespace hpx::detail { auto insert(const_iterator pos, std::size_t count, T const& value) -> iterator { + if constexpr(emulate_inplace_vector) { + if (direct_size() + count > N) { + throw std::bad_alloc(); + } + } auto* p = make_uninitialized_space(pos, count); std::uninitialized_fill_n(p, count, value); return p; @@ -1170,6 +1250,8 @@ namespace hpx::detail { auto s = size(); while (first != last) { + // if we are emulating inplace_vector, the out-of-bounds + // emplacement is caught in emplace_back emplace_back(*first); ++first; } @@ -1185,7 +1267,13 @@ namespace hpx::detail { auto insert(const_iterator pos, It first, It last, std::forward_iterator_tag /*unused*/) { - auto* p = make_uninitialized_space(pos, std::distance(first, last)); + auto d = std::distance(first, last); + if constexpr(emulate_inplace_vector) { + if (direct_size() + d > N) { + throw std::bad_alloc(); + } + } + auto* p = make_uninitialized_space(pos, d); std::uninitialized_copy(first, last, p); return p; } @@ -1262,6 +1350,9 @@ namespace hpx::detail { { return !(a > b); } + + template > + using inplace_vector = small_vector; } // namespace hpx::detail // NOLINTNEXTLINE(cert-dcl58-cpp) From db444dc02633c80761ff4a6dcb2e32699078d612 Mon Sep 17 00:00:00 2001 From: Hartmut Kaiser Date: Mon, 25 Nov 2024 09:03:48 -0600 Subject: [PATCH 02/10] Fixing clang-format issues --- .../datastructures/detail/small_vector.hpp | 95 ++++++++++++------- 1 file changed, 60 insertions(+), 35 deletions(-) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index ebb890e5b288..ba7a4c351880 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -85,8 +85,8 @@ namespace hpx::detail { inline constexpr bool is_argument_iterator_v = is_argument_iterator::value; - constexpr auto round_up(std::size_t n, std::size_t multiple) noexcept - -> std::size_t + constexpr auto round_up( + std::size_t n, std::size_t multiple) noexcept -> std::size_t { return ((n + (multiple - 1)) / multiple) * multiple; } @@ -208,8 +208,8 @@ namespace hpx::detail { } template - constexpr auto automatic_capacity(std::size_t min_inline_capacity) noexcept - -> std::size_t + constexpr auto automatic_capacity( + std::size_t min_inline_capacity) noexcept -> std::size_t { return cx_min( (size_of_small_vector(min_inline_capacity) - 1U) / sizeof(T), @@ -218,7 +218,8 @@ namespace hpx::detail { // note: Allocator is currently unused template , bool emulate_inplace_vector = false> + typename Allocator = std::allocator, + bool emulate_inplace_vector = false> class small_vector { static_assert(MinInlineCapacity <= 127, @@ -249,8 +250,10 @@ namespace hpx::detail { [[nodiscard]] constexpr auto is_direct() const noexcept -> bool { - if constexpr (emulate_inplace_vector) return true; - else return (m_data[0] & 1U) != 0U; + if constexpr (emulate_inplace_vector) + return true; + else + return (m_data[0] & 1U) != 0U; } [[nodiscard]] auto indirect() noexcept -> storage* @@ -311,7 +314,8 @@ namespace hpx::detail { void realloc(std::size_t new_capacity) { - static_assert(!emulate_inplace_vector, "If called in an inplace_vector, it is a bug."); + static_assert(!emulate_inplace_vector, + "If called in an inplace_vector, it is a bug."); if (new_capacity <= N) { // put everything into direct storage @@ -365,8 +369,8 @@ namespace hpx::detail { } [[nodiscard]] static constexpr auto calculate_new_capacity( - std::size_t size_to_fit, std::size_t starting_capacity) noexcept - -> std::size_t + std::size_t size_to_fit, + std::size_t starting_capacity) noexcept -> std::size_t { if (size_to_fit == 0) { @@ -545,7 +549,8 @@ namespace hpx::detail { if constexpr (emulate_inplace_vector) { // Can not have an inplace_vector with a size larger than N - if (s <= capacity()) { + if (s <= capacity()) + { throw std::bad_alloc(); } } @@ -723,7 +728,8 @@ namespace hpx::detail { if constexpr (emulate_inplace_vector) { // Can not have an inplace_vector with a size larger than N - if (count > N) { + if (count > N) + { throw std::bad_alloc(); } } @@ -736,7 +742,8 @@ namespace hpx::detail { if constexpr (emulate_inplace_vector) { // Can not have an inplace_vector with a size larger than N - if (count > N) { + if (count > N) + { throw std::bad_alloc(); } } @@ -847,9 +854,11 @@ namespace hpx::detail { void resize(std::size_t count) { - if constexpr (emulate_inplace_vector) { + if constexpr (emulate_inplace_vector) + { // Static vector cannot be resized beyond capacity - if (count > N) { + if (count > N) + { throw std::bad_alloc(); } } @@ -871,9 +880,11 @@ namespace hpx::detail { void resize(std::size_t count, value_type const& value) { - if constexpr (emulate_inplace_vector) { + if constexpr (emulate_inplace_vector) + { // Static vector cannot resize beyond capacity - if (count > N) { + if (count > N) + { throw std::bad_alloc(); } } @@ -895,9 +906,11 @@ namespace hpx::detail { auto reserve(std::size_t s) { - if constexpr (emulate_inplace_vector) { + if constexpr (emulate_inplace_vector) + { // Static vector cannot reserve beyond capacity - if (s > N) { + if (s > N) + { throw std::bad_alloc(); } } @@ -911,7 +924,8 @@ namespace hpx::detail { [[nodiscard]] constexpr auto capacity() const noexcept -> std::size_t { - if constexpr (emulate_inplace_vector) { + if constexpr (emulate_inplace_vector) + { return capacity(); } if (is_direct()) @@ -952,9 +966,11 @@ namespace hpx::detail { if (is_direct()) { s = direct_size(); - if constexpr (emulate_inplace_vector) { + if constexpr (emulate_inplace_vector) + { // Exceeded static_storage - if (s + 1 > N) { + if (s + 1 > N) + { throw std::bad_alloc(); } } @@ -994,8 +1010,8 @@ namespace hpx::detail { emplace_back(HPX_MOVE(value)); } - [[nodiscard]] auto operator[](std::size_t idx) const noexcept - -> T const& + [[nodiscard]] auto operator[]( + std::size_t idx) const noexcept -> T const& { return *(data() + idx); } @@ -1159,7 +1175,8 @@ namespace hpx::detail { [[nodiscard]] static constexpr auto max_size() -> std::size_t { - if constexpr (emulate_inplace_vector) return N; + if constexpr (emulate_inplace_vector) + return N; return (std::numeric_limits::max)(); } @@ -1174,7 +1191,8 @@ namespace hpx::detail { // per the standard we wouldn't need to do anything here. But since // we are so nice, let's do the shrink. - if constexpr (emulate_inplace_vector) { + if constexpr (emulate_inplace_vector) + { // Can not change the capacity of a static vector so noop return; } @@ -1199,9 +1217,11 @@ namespace hpx::detail { template auto emplace(const_iterator pos, Args&&... args) -> iterator { - if constexpr(emulate_inplace_vector) { + if constexpr (emulate_inplace_vector) + { // it will be expanded by one element - if (direct_size() + 1 > N) { + if (direct_size() + 1 > N) + { throw std::bad_alloc(); } } @@ -1220,11 +1240,13 @@ namespace hpx::detail { return emplace(pos, HPX_MOVE(value)); } - auto insert(const_iterator pos, std::size_t count, T const& value) - -> iterator + auto insert( + const_iterator pos, std::size_t count, T const& value) -> iterator { - if constexpr(emulate_inplace_vector) { - if (direct_size() + count > N) { + if constexpr (emulate_inplace_vector) + { + if (direct_size() + count > N) + { throw std::bad_alloc(); } } @@ -1268,8 +1290,10 @@ namespace hpx::detail { std::forward_iterator_tag /*unused*/) { auto d = std::distance(first, last); - if constexpr(emulate_inplace_vector) { - if (direct_size() + d > N) { + if constexpr (emulate_inplace_vector) + { + if (direct_size() + d > N) + { throw std::bad_alloc(); } } @@ -1351,7 +1375,8 @@ namespace hpx::detail { return !(a > b); } - template > + template > using inplace_vector = small_vector; } // namespace hpx::detail From 63a28da26445e298d25e089aed1c1b9fbbd589bf Mon Sep 17 00:00:00 2001 From: isidorostsa Date: Thu, 28 Nov 2024 13:52:23 +0200 Subject: [PATCH 03/10] Prevent materialization of unused code --- .../datastructures/detail/small_vector.hpp | 119 ++++++++++-------- 1 file changed, 70 insertions(+), 49 deletions(-) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index ba7a4c351880..54a08110225a 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -314,8 +314,8 @@ namespace hpx::detail { void realloc(std::size_t new_capacity) { - static_assert(!emulate_inplace_vector, - "If called in an inplace_vector, it is a bug."); + // static_assert(!emulate_inplace_vector, + // "If called in an inplace_vector, it is a bug."); if (new_capacity <= N) { // put everything into direct storage @@ -913,12 +913,17 @@ namespace hpx::detail { { throw std::bad_alloc(); } + // No-op } - auto const old_capacity = capacity(); - auto const new_capacity = calculate_new_capacity(s, old_capacity); - if (new_capacity > old_capacity) + else { - realloc(new_capacity); + auto const old_capacity = capacity(); + auto const new_capacity = + calculate_new_capacity(s, old_capacity); + if (new_capacity > old_capacity) + { + realloc(new_capacity); + } } } @@ -962,42 +967,46 @@ namespace hpx::detail { template auto emplace_back(Args&&... args) -> T& { - std::size_t s; // NOLINT(cppcoreguidelines-init-variables) - if (is_direct()) + if constexpr (emulate_inplace_vector) { - s = direct_size(); - if constexpr (emulate_inplace_vector) + std::size_t s = direct_size(); + if (s == N) { - // Exceeded static_storage - if (s + 1 > N) - { - throw std::bad_alloc(); - } - } - - // avoid double-checking for inplace_vector - if (emulate_inplace_vector || s < N) - { - set_direct_and_size(s + 1); - return *hpx::construct_at( - static_cast(direct_data() + s), - HPX_FORWARD(Args, args)...); + throw std::bad_alloc(); } - realloc(calculate_new_capacity(N + 1, N)); + set_direct_and_size(s + 1); + return *hpx::construct_at(static_cast(direct_data() + s), + HPX_FORWARD(Args, args)...); } else { - s = size(); - if (s == capacity()) + std::size_t s; // NOLINT(cppcoreguidelines-init-variables) + if (is_direct()) { - realloc(calculate_new_capacity(s + 1, s)); + s = direct_size(); + if (s < N) + { + set_direct_and_size(s + 1); + return *hpx::construct_at( + static_cast(direct_data() + s), + HPX_FORWARD(Args, args)...); + } + realloc(calculate_new_capacity(N + 1, N)); + } + else + { + s = size(); + if (s == capacity()) + { + realloc(calculate_new_capacity(s + 1, s)); + } } - } - set_size(s + 1); - return *hpx::construct_at( - static_cast(data() + s), - HPX_FORWARD(Args, args)...); + set_size(s + 1); + return *hpx::construct_at( + static_cast(data() + s), + HPX_FORWARD(Args, args)...); + } } void push_back(T const& value) @@ -1056,11 +1065,20 @@ namespace hpx::detail { [[nodiscard]] auto end() const noexcept -> T const* { - if (is_direct()) + if constexpr (emulate_inplace_vector) { return data() + size(); } - return data() + size(); + else + { + if (is_direct()) + { + return data() + + size(); + } + return data() + + size(); + } } [[nodiscard]] auto cend() const noexcept -> T const* @@ -1177,7 +1195,8 @@ namespace hpx::detail { { if constexpr (emulate_inplace_vector) return N; - return (std::numeric_limits::max)(); + else + return (std::numeric_limits::max)(); } void swap(small_vector& other) noexcept @@ -1196,22 +1215,24 @@ namespace hpx::detail { // Can not change the capacity of a static vector so noop return; } - - auto const c = capacity(); - auto const s = size(); - if (s >= c) + else { - return; - } + auto const c = capacity(); + auto const s = size(); + if (s >= c) + { + return; + } - auto new_capacity = calculate_new_capacity(s, N); - if (new_capacity == c) - { - // nothing change! - return; - } + auto new_capacity = calculate_new_capacity(s, N); + if (new_capacity == c) + { + // nothing change! + return; + } - realloc(new_capacity); + realloc(new_capacity); + } } template From 7f6118599ea538559f1ff8c337f1c59b660f6942 Mon Sep 17 00:00:00 2001 From: isidorostsa Date: Thu, 28 Nov 2024 13:53:04 +0200 Subject: [PATCH 04/10] Editorial --- .../include/hpx/datastructures/detail/small_vector.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index 54a08110225a..902c81cf0ca8 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -1,4 +1,5 @@ // Copyright (c) 2022 Hartmut Kaiser +// Copyright (c) 2024 Isidoros Tsaousis-Seiras // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -649,7 +650,7 @@ namespace hpx::detail { return p; } - // makes space for uninitialized data of cout elements. Also updates size. + // makes space for uninitialized data of count elements. Also updates size. [[nodiscard]] auto make_uninitialized_space( T const* pos, std::size_t count) -> T* { From 5254908aa1571bf426a8c4e02b1abe83b9c9ae38 Mon Sep 17 00:00:00 2001 From: isidorostsa Date: Thu, 28 Nov 2024 13:53:48 +0200 Subject: [PATCH 05/10] Default allocator to std::monostate for inplace_vector --- .../include/hpx/datastructures/detail/small_vector.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index 902c81cf0ca8..93bb9b9f2e3a 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -49,6 +49,7 @@ #include #include #include +#include namespace hpx::detail { @@ -1397,9 +1398,9 @@ namespace hpx::detail { return !(a > b); } - template > - using inplace_vector = small_vector; + template + using inplace_vector = small_vector; } // namespace hpx::detail // NOLINTNEXTLINE(cert-dcl58-cpp) From a59fbcf0a6bf7db1249a6b9075c365d3742c7e84 Mon Sep 17 00:00:00 2001 From: isidorostsa Date: Thu, 28 Nov 2024 13:54:10 +0200 Subject: [PATCH 06/10] Opposite comparison side bugfix --- .../include/hpx/datastructures/detail/small_vector.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index 93bb9b9f2e3a..4c5f52688497 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -551,7 +551,9 @@ namespace hpx::detail { if constexpr (emulate_inplace_vector) { // Can not have an inplace_vector with a size larger than N - if (s <= capacity()) + + // Enforce same signedness (forward iterator so s > 0) + if (static_cast(s) > capacity()) { throw std::bad_alloc(); } From 9f7349de6d5e58f6c62c5c5e058f895fd9eeaa53 Mon Sep 17 00:00:00 2001 From: isidorostsa Date: Thu, 28 Nov 2024 13:56:04 +0200 Subject: [PATCH 07/10] Enable inplace_vector for comparison operators --- .../datastructures/detail/small_vector.hpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index 4c5f52688497..2df3a0c407c0 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -1356,46 +1356,46 @@ namespace hpx::detail { } }; - template - [[nodiscard]] constexpr auto operator==(small_vector const& a, - small_vector const& b) noexcept -> bool + template + [[nodiscard]] constexpr auto operator==(small_vector const& a, + small_vector const& b) noexcept -> bool { return std::equal(a.begin(), a.end(), b.begin(), b.end()); } - template - [[nodiscard]] constexpr auto operator!=(small_vector const& a, - small_vector const& b) noexcept -> bool + template + [[nodiscard]] constexpr auto operator!=(small_vector const& a, + small_vector const& b) noexcept -> bool { return !(a == b); } - template - [[nodiscard]] constexpr auto operator<(small_vector const& a, - small_vector const& b) noexcept -> bool + template + [[nodiscard]] constexpr auto operator<(small_vector const& a, + small_vector const& b) noexcept -> bool { return std::lexicographical_compare( a.begin(), a.end(), b.begin(), b.end()); } - template - [[nodiscard]] constexpr auto operator>=(small_vector const& a, - small_vector const& b) noexcept -> bool + template + [[nodiscard]] constexpr auto operator>=(small_vector const& a, + small_vector const& b) noexcept -> bool { return !(a < b); } - template - [[nodiscard]] constexpr auto operator>(small_vector const& a, - small_vector const& b) noexcept -> bool + template + [[nodiscard]] constexpr auto operator>(small_vector const& a, + small_vector const& b) noexcept -> bool { return std::lexicographical_compare( b.begin(), b.end(), a.begin(), a.end()); } - template - [[nodiscard]] constexpr auto operator<=(small_vector const& a, - small_vector const& b) noexcept -> bool + template + [[nodiscard]] constexpr auto operator<=(small_vector const& a, + small_vector const& b) noexcept -> bool { return !(a > b); } From 16043ebac169be8124fe5b0228ef3c4718505e85 Mon Sep 17 00:00:00 2001 From: isidorostsa Date: Thu, 28 Nov 2024 13:56:59 +0200 Subject: [PATCH 08/10] inplace_vector test --- .../datastructures/tests/unit/CMakeLists.txt | 1 + .../tests/unit/inplace_vector.cpp | 774 ++++++++++++++++++ 2 files changed, 775 insertions(+) create mode 100644 libs/core/datastructures/tests/unit/inplace_vector.cpp diff --git a/libs/core/datastructures/tests/unit/CMakeLists.txt b/libs/core/datastructures/tests/unit/CMakeLists.txt index 5d4fdb4ab645..edaaa19a6737 100644 --- a/libs/core/datastructures/tests/unit/CMakeLists.txt +++ b/libs/core/datastructures/tests/unit/CMakeLists.txt @@ -15,6 +15,7 @@ set(tests dynamic_bitset5 flat_map flat_set + inplace_vector intrusive_list is_tuple_like serializable_any diff --git a/libs/core/datastructures/tests/unit/inplace_vector.cpp b/libs/core/datastructures/tests/unit/inplace_vector.cpp new file mode 100644 index 000000000000..d03e568935bd --- /dev/null +++ b/libs/core/datastructures/tests/unit/inplace_vector.cpp @@ -0,0 +1,774 @@ +// Copyright (c) 2021-2024 Hartmut Kaiser +// Copyright (c) 2024 Isidoros Tsaousis-Seiras +// +// SPDX-License-Identifier: BSL-1.0 +// 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) +// +// (C) Copyright Ion Gaztanaga 2004-2014. Distributed under the Boost +// Copyright (C) 2013 Cromwell D. Enage +// +// See http://www.boost.org/libs/container for documentation. + +#include + +#if !defined(HPX_HAVE_HIP) +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace test { + + class movable_and_copyable_int + { + public: + static inline unsigned int count = 0; + + movable_and_copyable_int() noexcept + : int_(0) + { + ++count; + } + + explicit movable_and_copyable_int(int a) noexcept + : int_(a) + { + // Disallow INT_MIN + HPX_TEST(this->int_ != INT_MIN); + ++count; + } + + movable_and_copyable_int(movable_and_copyable_int const& mmi) noexcept + : int_(mmi.int_) + { + ++count; + } + + movable_and_copyable_int(movable_and_copyable_int&& mmi) noexcept + : int_(mmi.int_) + { + mmi.int_ = 0; + ++count; + } + + ~movable_and_copyable_int() + { + HPX_TEST(this->int_ != INT_MIN); + this->int_ = INT_MIN; + --count; + } + + movable_and_copyable_int& operator=( + movable_and_copyable_int const& mi) noexcept + { + this->int_ = mi.int_; + return *this; + } + + movable_and_copyable_int& operator=( + movable_and_copyable_int&& mmi) noexcept + { + this->int_ = mmi.int_; + mmi.int_ = 0; + return *this; + } + + movable_and_copyable_int& operator=(int i) noexcept + { + this->int_ = i; + HPX_TEST(this->int_ != INT_MIN); + return *this; + } + + friend bool operator==(const movable_and_copyable_int& l, + const movable_and_copyable_int& r) noexcept + { + return l.int_ == r.int_; + } + + friend bool operator!=(const movable_and_copyable_int& l, + const movable_and_copyable_int& r) noexcept + { + return l.int_ != r.int_; + } + + friend bool operator<(const movable_and_copyable_int& l, + const movable_and_copyable_int& r) noexcept + { + return l.int_ < r.int_; + } + + friend bool operator<=(const movable_and_copyable_int& l, + const movable_and_copyable_int& r) noexcept + { + return l.int_ <= r.int_; + } + + friend bool operator>=(const movable_and_copyable_int& l, + const movable_and_copyable_int& r) noexcept + { + return l.int_ >= r.int_; + } + + friend bool operator>(const movable_and_copyable_int& l, + const movable_and_copyable_int& r) noexcept + { + return l.int_ > r.int_; + } + + int get_int() const noexcept + { + return int_; + } + + friend bool operator==( + const movable_and_copyable_int& l, int r) noexcept + { + return l.get_int() == r; + } + + friend bool operator==( + int l, const movable_and_copyable_int& r) noexcept + { + return l == r.get_int(); + } + + private: + int int_; + }; +} // namespace test + +namespace hpx { + + // Explicit instantiation to detect compilation errors + + // inplace_vector is an alias of small_vector so we have to write it out + // explicitly: + /* + template + using inplace_vector = small_vector< + T, + MinInlineCapacity, + std::monostate, // Ignore the allocator + true>; // emulate inplace_vector + */ + + // inplace_vector + template class hpx::detail::small_vector; + + // inplace_vector + template class hpx::detail::small_vector; + + // inplace_vector + template class hpx::detail::small_vector; + + // inplace_vector + template class hpx::detail::small_vector; + + // inplace_vector + template class hpx::detail::small_vector; + + // inplace_vector + template class hpx::detail::small_vector; + + // inplace_vector + template class hpx::detail::small_vector; +} // namespace hpx + +namespace test { + + void inplace_vector_test() + { + // basic test with fewer elements than static size + { + using sm5_t = hpx::detail::small_vector; + static_assert( + sm5_t::static_capacity == 5, "sm5_t::static_capacity == 5"); + + sm5_t sm5; + sm5.push_back(1); + HPX_TEST_EQ(sm5[0], 1); + + sm5_t const sm5_copy(sm5); + HPX_TEST(sm5 == sm5_copy); + } + { + using sm7_t = hpx::detail::inplace_vector; + static_assert( + sm7_t::static_capacity == 7, "sm7_t::static_capacity == 7"); + + sm7_t sm7; + sm7.push_back(1); + HPX_TEST_EQ(sm7[0], 1); + + sm7_t const sm7_copy(sm7); + HPX_TEST(sm7 == sm7_copy); + } + { + using sm5_t = hpx::detail::inplace_vector; + sm5_t sm5; + sm5.push_back(1); + HPX_TEST_EQ(sm5[0], 1); + + sm5_t sm5_copy(sm5); + HPX_TEST(sm5 == sm5_copy); + + sm5.push_back(2); + HPX_TEST_EQ(sm5[1], 2); + HPX_TEST_EQ(sm5.size(), static_cast(2)); + + sm5_copy = sm5; + HPX_TEST(sm5 == sm5_copy); + + sm5[0] = 3; + HPX_TEST_EQ(sm5[0], 3); + HPX_TEST_EQ(sm5_copy[0], 1); + + sm5_copy = sm5; + sm5_t sm5_move(std::move(sm5)); + sm5 = sm5_t(); + HPX_TEST(sm5_move == sm5_copy); + + sm5 = sm5_copy; + sm5_move = std::move(sm5); + sm5 = sm5_t(); + HPX_TEST(sm5_move == sm5_copy); + } + + // basic test with more elements than static size + { + using sm2_t = hpx::detail::inplace_vector; + sm2_t sm2; + sm2.push_back(1); + HPX_TEST_EQ(sm2[0], 1); + + sm2_t sm2_copy(sm2); + HPX_TEST(sm2 == sm2_copy); + + sm2.push_back(2); + sm2.push_back(3); + HPX_TEST_EQ(sm2[1], 2); + HPX_TEST_EQ(sm2[2], 3); + HPX_TEST_EQ(sm2.size(), static_cast(3)); + + sm2_copy = sm2; + HPX_TEST(sm2 == sm2_copy); + + sm2[2] = 4; + HPX_TEST_EQ(sm2[2], 4); + HPX_TEST_EQ(sm2_copy[2], 3); + + sm2_copy = sm2; + sm2_t sm2_move(std::move(sm2)); + sm2 = sm2_t(); + HPX_TEST(sm2_move == sm2_copy); + + sm2 = sm2_copy; + sm2_move = std::move(sm2); + sm2 = sm2_t(); + HPX_TEST(sm2_move == sm2_copy); + } + } + + // inplace vector has internal storage so some special swap cases must be + // tested + void test_swap() + { + using vec = hpx::detail::inplace_vector; + + { + // v has elements, w empty + vec v; + for (std::size_t i = 0, max = v.capacity() - 1; i != max; ++i) + { + v.push_back(static_cast(i)); + } + + vec w; + + vec const v_copy(v); + vec const w_copy(w); + + v.swap(w); + HPX_TEST(v == w_copy); + HPX_TEST(w == v_copy); + } + { + // v & w have elements + vec v; + for (std::size_t i = 0, max = v.capacity() - 1; i != max; ++i) + { + v.push_back(static_cast(i)); + } + + vec w; + for (std::size_t i = 0, max = v.capacity() / 2; i != max; ++i) + { + w.push_back(static_cast(i)); + } + + vec const v_copy(v); + vec const w_copy(w); + + v.swap(w); + HPX_TEST(v == w_copy); + HPX_TEST(w == v_copy); + } + } + + /////////////////////////////////////////////////////////////////////////// + template + void check_equal_containers(ContA const& cont_a, ContB const& cont_b) + { + HPX_TEST_EQ(cont_a.size(), cont_b.size()); + + auto itcont_a(cont_a.begin()); + auto itcont_a_end(cont_a.end()); + std::size_t dist = std::distance(itcont_a, itcont_a_end); + HPX_TEST_EQ(dist, cont_a.size()); + + auto itcont_b(cont_b.begin()); + auto itcont_b_end(cont_b.end()); + std::size_t dist2 = std::distance(itcont_b, itcont_b_end); + HPX_TEST_EQ(dist2, cont_b.size()); + + for (std::size_t i = 0; itcont_a != itcont_a_end; + ++itcont_a, ++itcont_b, ++i) + { + HPX_TEST_EQ(*itcont_a, *itcont_b); + } + } + + template + void test_insert_range(std::deque& std_deque, + SeqContainer& seq_container, std::deque const& input_deque, + std::size_t index) + { + HPX_ASSERT(std::size(input_deque) + std::size(seq_container) <= + seq_container.max_size()); + check_equal_containers(std_deque, seq_container); + + std_deque.insert( + std_deque.begin() + index, input_deque.begin(), input_deque.end()); + seq_container.insert(seq_container.begin() + index, input_deque.begin(), + input_deque.end()); + + check_equal_containers(std_deque, seq_container); + } + + template + void test_range_insertion() + { + using value_type = typename SeqContainer::value_type; + constexpr auto max_size = SeqContainer::static_capacity; + static_assert( + max_size > 100, "max_size must be greater than 100 for this test."); + + std::deque input_deque; + for (int element = -10; element < 10; ++element) + { + input_deque.push_back(element + 20); + } + + for (std::size_t i = 0; i <= input_deque.size(); ++i) + { + std::deque std_deque; + SeqContainer seq_container; + + for (int element = -10; element < 10; ++element) + { + std_deque.push_back(element); + seq_container.push_back(value_type(element)); + } + + test_insert_range(std_deque, seq_container, input_deque, i); + } + } + + /////////////////////////////////////////////////////////////////////////// + class emplace_int + { + public: + explicit emplace_int( + int a = 0, int b = 0, int c = 0, int d = 0, int e = 0) noexcept + : a_(a) + , b_(b) + , c_(c) + , d_(d) + , e_(e) + { + } + + emplace_int(emplace_int const& o) = delete; + emplace_int(emplace_int&& o) noexcept + : a_(o.a_) + , b_(o.b_) + , c_(o.c_) + , d_(o.d_) + , e_(o.e_) + { + } + + emplace_int& operator=(emplace_int const& o) = delete; + emplace_int& operator=(emplace_int&& o) noexcept + { + a_ = o.a_; + b_ = o.b_; + c_ = o.c_; + d_ = o.d_; + e_ = o.e_; + return *this; + } + + friend bool operator==(emplace_int const& l, emplace_int const& r) + { + return l.a_ == r.a_ && l.b_ == r.b_ && l.c_ == r.c_ && + l.d_ == r.d_ && l.e_ == r.e_; + } + + friend bool operator<(emplace_int const& l, emplace_int const& r) + { + return l.sum() < r.sum(); + } + + friend bool operator>(emplace_int const& l, emplace_int const& r) + { + return l.sum() > r.sum(); + } + + friend bool operator!=(emplace_int const& l, emplace_int const& r) + { + return !(l == r); + } + + ~emplace_int() + { + a_ = b_ = c_ = d_ = e_ = 0; + } + + int sum() const + { + return a_ + b_ + c_ + d_ + e_; + } + + int a_, b_, c_, d_, e_; + int padding[6] = {}; + }; + + static emplace_int expected[10]; + + template + void test_expected_container(Container const& ec, + emplace_int const* expected, unsigned int only_first_n, + unsigned int cont_offset = 0) + { + HPX_TEST(cont_offset <= ec.size()); + HPX_TEST(only_first_n <= (ec.size() - cont_offset)); + + using const_iterator = typename Container::const_iterator; + + const_iterator itb(ec.begin()), ite(ec.end()); + unsigned int cur = 0; + while (cont_offset--) + { + ++itb; + } + + for (; itb != ite && only_first_n--; ++itb, ++cur) + { + emplace_int const& cr = *itb; + HPX_TEST(cr == expected[cur]); + } + } + + template + void test_emplace_back() + { + { + new (&expected[0]) emplace_int(); + new (&expected[1]) emplace_int(1); + new (&expected[2]) emplace_int(1, 2); + new (&expected[3]) emplace_int(1, 2, 3); + new (&expected[4]) emplace_int(1, 2, 3, 4); + new (&expected[5]) emplace_int(1, 2, 3, 4, 5); + + Container c; + using reference = typename Container::reference; + + { + reference r = c.emplace_back(); + HPX_TEST(&r == &c.back()); + test_expected_container(c, &expected[0], 1); + } + { + reference r = c.emplace_back(1); + HPX_TEST(&r == &c.back()); + test_expected_container(c, &expected[0], 2); + } + + c.emplace_back(1, 2); + test_expected_container(c, &expected[0], 3); + + c.emplace_back(1, 2, 3); + test_expected_container(c, &expected[0], 4); + + c.emplace_back(1, 2, 3, 4); + test_expected_container(c, &expected[0], 5); + + c.emplace_back(1, 2, 3, 4, 5); + test_expected_container(c, &expected[0], 6); + } + } + + template + void test_emplace_before() + { + { + new (&expected[0]) emplace_int(); + new (&expected[1]) emplace_int(1); + new (&expected[2]) emplace_int(); + + Container c; + c.emplace(c.cend(), 1); + c.emplace(c.cbegin()); + test_expected_container(c, &expected[0], 2); + + c.emplace(c.cend()); + test_expected_container(c, &expected[0], 3); + } + { + new (&expected[0]) emplace_int(); + new (&expected[1]) emplace_int(1); + new (&expected[2]) emplace_int(1, 2); + new (&expected[3]) emplace_int(1, 2, 3); + new (&expected[4]) emplace_int(1, 2, 3, 4); + new (&expected[5]) emplace_int(1, 2, 3, 4, 5); + + // emplace_front-like + Container c; + c.emplace(c.cbegin(), 1, 2, 3, 4, 5); + c.emplace(c.cbegin(), 1, 2, 3, 4); + c.emplace(c.cbegin(), 1, 2, 3); + c.emplace(c.cbegin(), 1, 2); + c.emplace(c.cbegin(), 1); + c.emplace(c.cbegin()); + test_expected_container(c, &expected[0], 6); + c.clear(); + + // emplace_back-like + auto i = c.emplace(c.cend()); + test_expected_container(c, &expected[0], 1); + + i = c.emplace(++i, 1); + test_expected_container(c, &expected[0], 2); + + i = c.emplace(++i, 1, 2); + test_expected_container(c, &expected[0], 3); + + i = c.emplace(++i, 1, 2, 3); + test_expected_container(c, &expected[0], 4); + + i = c.emplace(++i, 1, 2, 3, 4); + test_expected_container(c, &expected[0], 5); + + i = c.emplace(++i, 1, 2, 3, 4, 5); + test_expected_container(c, &expected[0], 6); + c.clear(); + + // emplace in the middle + c.emplace(c.cbegin()); + test_expected_container(c, &expected[0], 1); + + i = c.emplace(c.cend(), 1, 2, 3, 4, 5); + test_expected_container(c, &expected[0], 1); + + test_expected_container(c, &expected[5], 1, 1); + + i = c.emplace(i, 1, 2, 3, 4); + test_expected_container(c, &expected[0], 1); + + test_expected_container(c, &expected[4], 2, 1); + + i = c.emplace(i, 1, 2, 3); + test_expected_container(c, &expected[0], 1); + test_expected_container(c, &expected[3], 3, 1); + + i = c.emplace(i, 1, 2); + test_expected_container(c, &expected[0], 1); + test_expected_container(c, &expected[2], 4, 1); + + i = c.emplace(i, 1); + test_expected_container(c, &expected[0], 6); + } + } + + template + void test_vector_methods_with_initializer_list_as_argument_for() + { + using allocator_type = typename VectorContainerType::allocator_type; + + { + VectorContainerType const tested_vector = {1, 2, 3}; + std::vector const expected_vector = {1, 2, 3}; + check_equal_containers(tested_vector, expected_vector); + } + { + VectorContainerType const tested_vector( + {1, 2, 3}, allocator_type()); + std::vector const expected_vector = {1, 2, 3}; + check_equal_containers(tested_vector, expected_vector); + } + { + VectorContainerType tested_vector = {1, 2, 3}; + tested_vector = {11, 12, 13}; + + std::vector const expected_vector = {11, 12, 13}; + check_equal_containers(tested_vector, expected_vector); + } + + { + VectorContainerType tested_vector = {1, 2, 3}; + tested_vector.assign({5, 6, 7}); + + std::vector const expected_vector = {5, 6, 7}; + check_equal_containers(tested_vector, expected_vector); + } + + { + VectorContainerType tested_vector = {1, 2, 3}; + tested_vector.insert(tested_vector.cend(), {5, 6, 7}); + + std::vector const expected_vector = {1, 2, 3, 5, 6, 7}; + check_equal_containers(tested_vector, expected_vector); + } + } + + void test_general() + { + using hpx::detail::inplace_vector; + + { + inplace_vector const v1 = {1, 2, 3, 4, 5}; + inplace_vector const v2 = {1, 2, 3, 4, 5}; + + HPX_TEST(v1 == v2); + } + { + inplace_vector const v_init_list = {1, 2, 3, 4, 5}; + inplace_vector v_push_back; + inplace_vector v_emplace_back; + inplace_vector v_insert; + + for (int i = 0; i < 5; ++i) + { + v_push_back.push_back(i); + v_emplace_back.emplace_back(i); + v_insert.insert(v_insert.end(), i); + } + + HPX_TEST(v_init_list == v_push_back); + HPX_TEST(v_init_list == v_emplace_back); + HPX_TEST(v_init_list == v_insert); + } + } + + void test_exceptions() + { + using hpx::detail::inplace_vector; + { + inplace_vector v = {1, 2, 3, 4, 5}; + try + { + v.push_back(42); + } + catch (std::bad_alloc&) + { + } + catch (...) + { + HPX_ASSERT(false); + } + } + { + inplace_vector v = {1, 2, 3, 4, 5}; + try + { + v.emplace_back(42); + } + catch (std::bad_alloc&) + { + } + catch (...) + { + HPX_ASSERT(false); + } + } + { + inplace_vector v = {1, 2, 3, 4, 5}; + try + { + v.insert(v.end(), 3); + } + catch (std::bad_alloc&) + { + } + catch (...) + { + HPX_ASSERT(false); + } + } + { + inplace_vector v = {1, 2, 3, 4, 5}; + try + { + (void)v.at(6); + } + catch (std::out_of_range&) + { + } + catch (...) + { + HPX_ASSERT(false); + } + } + + + } +} // namespace test + +int main() +{ + test::inplace_vector_test(); + test::test_swap(); + test::test_exceptions(); + + // Emplace testing + test::test_emplace_before< + hpx::detail::inplace_vector>(); + + // Initializer lists testing + test::test_vector_methods_with_initializer_list_as_argument_for< + hpx::detail::inplace_vector>(); + + return hpx::util::report_errors(); +} + +#else + +int main() +{ + return 0; +} + +#endif From abb4d992ea83ae9a565fc6d6f2ce9e95af218fc5 Mon Sep 17 00:00:00 2001 From: isidorostsa Date: Thu, 28 Nov 2024 14:35:24 +0200 Subject: [PATCH 09/10] clang-format conflicts --- .../datastructures/detail/small_vector.hpp | 98 +++++++++++++------ 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index 2df3a0c407c0..db4faa5f0ef0 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -87,8 +87,10 @@ namespace hpx::detail { inline constexpr bool is_argument_iterator_v = is_argument_iterator::value; - constexpr auto round_up( - std::size_t n, std::size_t multiple) noexcept -> std::size_t + // clang-format off + constexpr auto round_up(std::size_t n, std::size_t multiple) noexcept + -> std::size_t + // clang-format on { return ((n + (multiple - 1)) / multiple) * multiple; } @@ -209,9 +211,11 @@ namespace hpx::detail { alignment_of_small_vector()); } + // clang-format off template - constexpr auto automatic_capacity( - std::size_t min_inline_capacity) noexcept -> std::size_t + constexpr auto automatic_capacity(std::size_t min_inline_capacity) noexcept + -> std::size_t + // clang-format on { return cx_min( (size_of_small_vector(min_inline_capacity) - 1U) / sizeof(T), @@ -316,8 +320,6 @@ namespace hpx::detail { void realloc(std::size_t new_capacity) { - // static_assert(!emulate_inplace_vector, - // "If called in an inplace_vector, it is a bug."); if (new_capacity <= N) { // put everything into direct storage @@ -370,9 +372,11 @@ namespace hpx::detail { } } + // clang-format off [[nodiscard]] static constexpr auto calculate_new_capacity( - std::size_t size_to_fit, - std::size_t starting_capacity) noexcept -> std::size_t + std::size_t size_to_fit, std::size_t starting_capacity) noexcept + -> std::size_t + // clang-format on { if (size_to_fit == 0) { @@ -1023,8 +1027,10 @@ namespace hpx::detail { emplace_back(HPX_MOVE(value)); } - [[nodiscard]] auto operator[]( - std::size_t idx) const noexcept -> T const& + // clang-format off + [[nodiscard]] auto operator[](std::size_t idx) const noexcept + -> T const& + // clang-format on { return *(data() + idx); } @@ -1265,8 +1271,10 @@ namespace hpx::detail { return emplace(pos, HPX_MOVE(value)); } - auto insert( - const_iterator pos, std::size_t count, T const& value) -> iterator + // clang-format off + auto insert(const_iterator pos, std::size_t count, T const& value) + -> iterator + // clang-format on { if constexpr (emulate_inplace_vector) { @@ -1356,46 +1364,76 @@ namespace hpx::detail { } }; - template - [[nodiscard]] constexpr auto operator==(small_vector const& a, - small_vector const& b) noexcept -> bool + // clang-format off + template + [[nodiscard]] constexpr auto operator==( + small_vector const& a, + small_vector const& b) noexcept + -> bool + // clang-format on { return std::equal(a.begin(), a.end(), b.begin(), b.end()); } - template - [[nodiscard]] constexpr auto operator!=(small_vector const& a, - small_vector const& b) noexcept -> bool + // clang-format off + template + [[nodiscard]] constexpr auto operator!=( + small_vector const& a, + small_vector const& b) noexcept + -> bool + // clang-format on { return !(a == b); } - template - [[nodiscard]] constexpr auto operator<(small_vector const& a, - small_vector const& b) noexcept -> bool + // clang-format off + template + [[nodiscard]] constexpr auto operator<( + small_vector const& a, + small_vector const& b) noexcept + -> bool + // clang-format on { return std::lexicographical_compare( a.begin(), a.end(), b.begin(), b.end()); } - template - [[nodiscard]] constexpr auto operator>=(small_vector const& a, - small_vector const& b) noexcept -> bool + // clang-format off + template + [[nodiscard]] constexpr auto operator>=( + small_vector const& a, + small_vector const& b) noexcept + -> bool + // clang-format on { return !(a < b); } - template - [[nodiscard]] constexpr auto operator>(small_vector const& a, - small_vector const& b) noexcept -> bool + // clang-format off + template + [[nodiscard]] constexpr auto operator>( + small_vector const& a, + small_vector const& b) noexcept + -> bool + // clang-format on { return std::lexicographical_compare( b.begin(), b.end(), a.begin(), a.end()); } - template - [[nodiscard]] constexpr auto operator<=(small_vector const& a, - small_vector const& b) noexcept -> bool + // clang-format off + template + [[nodiscard]] constexpr auto operator<=( + small_vector const& a, + small_vector const& b) noexcept + -> bool + // clang-format on { return !(a > b); } From d875efc5123d60620e2fe01cafbf5369f41b0036 Mon Sep 17 00:00:00 2001 From: isidorostsa Date: Thu, 28 Nov 2024 14:38:36 +0200 Subject: [PATCH 10/10] clang-format conflicts --- .../include/hpx/datastructures/detail/small_vector.hpp | 2 +- libs/core/datastructures/tests/unit/inplace_vector.cpp | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index db4faa5f0ef0..2a4f4310dde2 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -625,7 +625,7 @@ namespace hpx::detail { { auto target = small_vector(); - // we know target is indirect because we're increasing capacity + // we know target is indirect because we are increasing capacity target.reserve(s + count); // move everything [begin, pos[ diff --git a/libs/core/datastructures/tests/unit/inplace_vector.cpp b/libs/core/datastructures/tests/unit/inplace_vector.cpp index d03e568935bd..579d725af071 100644 --- a/libs/core/datastructures/tests/unit/inplace_vector.cpp +++ b/libs/core/datastructures/tests/unit/inplace_vector.cpp @@ -344,7 +344,7 @@ namespace test { HPX_TEST_EQ(dist2, cont_b.size()); for (std::size_t i = 0; itcont_a != itcont_a_end; - ++itcont_a, ++itcont_b, ++i) + ++itcont_a, ++itcont_b, ++i) { HPX_TEST_EQ(*itcont_a, *itcont_b); } @@ -728,11 +728,11 @@ namespace test { HPX_ASSERT(false); } } - { + { inplace_vector v = {1, 2, 3, 4, 5}; try { - (void)v.at(6); + (void) v.at(6); } catch (std::out_of_range&) { @@ -742,8 +742,6 @@ namespace test { HPX_ASSERT(false); } } - - } } // namespace test