From 83621423de148febb1c4dcdffb77cbdd313dc172 Mon Sep 17 00:00:00 2001 From: i80287 Date: Fri, 20 Dec 2024 03:29:26 +0300 Subject: [PATCH] move config_macros.hpp to misc and update misc --- DisjointSetUnion/dsu.hpp | 164 +++--- DisjointSetUnion/test_dsu.cpp | 137 ++--- bstrees/RBTree.cppm | 2 +- graphs/HungarianAlgorithm/hungarian_algo.hpp | 2 +- {number_theory => misc}/config_macros.hpp | 10 +- misc/get_typename.hpp | 289 ++++++++++ misc/join_strings.hpp | 309 +++++++++++ misc/test_get_typename.cpp | 29 + misc/test_join_strings.cpp | 90 +++ misc/test_tools.hpp | 228 ++++++++ number_theory/CNKCounter.hpp | 2 +- number_theory/bitmatrix.hpp | 2 +- number_theory/fft.hpp | 2 +- number_theory/fibonacci_num.hpp | 2 +- number_theory/gosper_algorithm.hpp | 2 +- number_theory/integers_128_bit.hpp | 2 +- number_theory/is_prime.hpp | 2 +- number_theory/longint.hpp | 16 +- number_theory/math_functions.hpp | 25 +- number_theory/measure_is_prime_bpsw.cpp | 2 +- number_theory/test_bitmatrix.cpp | 4 +- number_theory/test_cnk_counter.cpp | 4 +- number_theory/test_fibonacci_num.cpp | 2 +- number_theory/test_gosper_algorithm.cpp | 4 +- number_theory/test_integers_128_bit.cpp | 4 +- number_theory/test_is_prime_bpsw.cpp | 4 +- number_theory/test_kronecker_symbol.cpp | 4 +- number_theory/test_long_int.cpp | 4 +- number_theory/test_math_functions.cpp | 5 +- number_theory/test_tools.hpp | 520 ------------------ run_clang_format.sh | 4 +- string-switch-map/StringMap.hpp | 2 +- .../tests/test_string_switch_map.cpp | 2 +- tests/CMakeLists.txt | 24 + vec_instructs/measure_memset_int.c | 2 +- vec_instructs/memcount.h | 11 +- vec_instructs/memset_int.h | 8 +- 37 files changed, 1204 insertions(+), 721 deletions(-) rename {number_theory => misc}/config_macros.hpp (98%) create mode 100644 misc/get_typename.hpp create mode 100644 misc/join_strings.hpp create mode 100644 misc/test_get_typename.cpp create mode 100644 misc/test_join_strings.cpp create mode 100644 misc/test_tools.hpp delete mode 100644 number_theory/test_tools.hpp diff --git a/DisjointSetUnion/dsu.hpp b/DisjointSetUnion/dsu.hpp index dfece22..5623255 100644 --- a/DisjointSetUnion/dsu.hpp +++ b/DisjointSetUnion/dsu.hpp @@ -3,15 +3,28 @@ #include #include #include -#if __cplusplus >= 202002L -#include -#endif +#include #include #include #include +#include "../misc/config_macros.hpp" + +#if CONFIG_HAS_CONCEPTS +#include +#endif + +#if (CONFIG_HAS_AT_LEAST_CXX_20 && !defined(_GLIBCXX_DEBUG) && !defined(_GLIBCXX_ASSERTIONS)) || \ + CONFIG_HAS_AT_LEAST_CXX_23 +#define CONSTEXPR_VECTOR constexpr +#else +#define CONSTEXPR_VECTOR inline +#endif + namespace dsu_impl { +using Weight = std::int64_t; + // Node with rank heuristic struct dsu_node_t { dsu_node_t* parent_{}; @@ -24,11 +37,11 @@ struct wdsu_node_t { wdsu_node_t* parent_{}; std::size_t rank_{}; std::size_t set_size_ = 1; // node itself - std::int64_t weight_{}; + Weight weight_{}; }; template -#if __cplusplus >= 202002L +#if CONFIG_HAS_CONCEPTS requires requires(node_type node) { { node.parent_ } -> std::convertible_to; { node.set_size_ } -> std::convertible_to; @@ -48,63 +61,65 @@ class dsu_base { using difference_type = typename container::difference_type; using allocator_type = typename container::allocator_type; - constexpr size_type size() const noexcept { + [[nodiscard]] constexpr size_type size() const noexcept { return nodes_.size(); } - constexpr size_type sets_size() const noexcept { + [[nodiscard]] constexpr size_type sets_size() const noexcept { return sets_size_; } // O(1) - constexpr size_type set_size_of(size_type node_index) const noexcept { + [[nodiscard]] CONSTEXPR_VECTOR size_type set_size_of(size_type node_index) const noexcept { assert(node_index < size()); const node_t& node = nodes_[node_index]; const_pointer parent_ptr = node.parent_; return parent_ptr != nullptr ? parent_ptr->set_size_ : node.set_size_; } // O(log*(n)) = O(a(n)) - constexpr size_type set_size_of(size_type node_index) noexcept { + [[nodiscard]] CONSTEXPR_VECTOR size_type set_size_of(size_type node_index) noexcept { assert(node_index < size()); - return findRoot(node_index)->set_size_; + return find_root(node_index)->set_size_; } protected: - constexpr dsu_base(size_type nodes_count) : nodes_(nodes_count), sets_size_(nodes_count) {} - constexpr dsu_base(const dsu_base& other) = default; - constexpr dsu_base& operator=(const dsu_base& other) = default; - constexpr dsu_base(dsu_base&& other) noexcept + CONSTEXPR_VECTOR dsu_base(size_type nodes_count) + : nodes_(nodes_count), sets_size_(nodes_count) {} + CONSTEXPR_VECTOR dsu_base(const dsu_base& other) = default; + CONSTEXPR_VECTOR dsu_base& operator=(const dsu_base& other) = default; + CONSTEXPR_VECTOR dsu_base(dsu_base&& other) noexcept : nodes_(std::move(other.nodes_)), sets_size_(std::exchange(other.sets_size_, 0)) {} - constexpr dsu_base& operator=(dsu_base&& other) noexcept { + CONSTEXPR_VECTOR dsu_base& operator=(dsu_base&& other) noexcept { swap(other); return *this; } - constexpr ~dsu_base() = default; - constexpr void swap(dsu_base& other) noexcept { + CONSTEXPR_VECTOR ~dsu_base() = default; + CONSTEXPR_VECTOR void swap(dsu_base& other) noexcept ATTRIBUTE_LIFETIME_BOUND { nodes_.swap(other.nodes_); std::swap(sets_size_, other.sets_size_); } - constexpr const_pointer data() const noexcept { + [[nodiscard]] CONSTEXPR_VECTOR const_pointer data() const noexcept ATTRIBUTE_LIFETIME_BOUND { return nodes_.data(); } - constexpr pointer data() noexcept { + [[nodiscard]] CONSTEXPR_VECTOR pointer data() noexcept ATTRIBUTE_LIFETIME_BOUND { return nodes_.data(); } - constexpr void reset() noexcept(std::is_nothrow_default_constructible_v && - std::is_nothrow_copy_assignable_v && - std::is_nothrow_destructible_v) { + CONSTEXPR_VECTOR void reset() noexcept(std::is_nothrow_default_constructible_v && + std::is_nothrow_copy_assignable_v && + std::is_nothrow_destructible_v) { std::fill_n(data(), size(), value_type{}); sets_size_ = size(); } - constexpr void clear() noexcept { + CONSTEXPR_VECTOR void clear() noexcept { nodes_.clear(); } - constexpr bool equal(size_type lhs_node_index, size_type rhs_node_index) noexcept { - return findRoot(lhs_node_index) == findRoot(rhs_node_index); + [[nodiscard]] CONSTEXPR_VECTOR bool equal(size_type lhs_node_index, + size_type rhs_node_index) noexcept { + return find_root(lhs_node_index) == find_root(rhs_node_index); } - constexpr pointer findRoot(size_type node_index) noexcept { - return findRoot(std::addressof(nodes_[node_index])); + [[nodiscard]] CONSTEXPR_VECTOR pointer find_root(size_type node_index) noexcept { + return find_root(std::addressof(nodes_[node_index])); } - static constexpr pointer findRoot(pointer node) noexcept { + [[nodiscard]] static constexpr pointer find_root(pointer node) noexcept { pointer current_node = node; assert(current_node != nullptr); while (current_node->parent_ != nullptr) { @@ -136,9 +151,11 @@ class dsu_t final : public dsu_impl::dsu_base { public: dsu_t() = delete; - constexpr explicit dsu_t(size_type nodes_count) : base(nodes_count) {} - - dsu_t(const dsu_t& other) : base(other) { + [[nodiscard]] + static CONSTEXPR_VECTOR dsu_t with_nodes_count(size_type nodes_count) { + return dsu_t{nodes_count}; + } + CONSTEXPR_VECTOR dsu_t(const dsu_t& other) : base(other) { node_t* const this_first_node = data(); const node_t* const other_first_node = other.data(); @@ -151,31 +168,33 @@ class dsu_t final : public dsu_impl::dsu_base { : nullptr; } } - dsu_t& operator=(const dsu_t& other) { + CONSTEXPR_VECTOR dsu_t& operator=(const dsu_t& other) ATTRIBUTE_LIFETIME_BOUND { return *this = dsu_t(other); } - constexpr dsu_t(dsu_t&& other) noexcept : base(std::move(other)) {} - dsu_t& operator=(dsu_t&& other) noexcept { + CONSTEXPR_VECTOR dsu_t(dsu_t&& other) noexcept : base(std::move(other)) {} + CONSTEXPR_VECTOR dsu_t& operator=(dsu_t&& other) noexcept ATTRIBUTE_LIFETIME_BOUND { base::operator=(std::move(other)); return *this; } - constexpr void swap(dsu_t& other) noexcept { + + CONSTEXPR_VECTOR void swap(dsu_t& other) noexcept { base::swap(other); } - friend constexpr void swap(dsu_t& lhs, dsu_t& rhs) noexcept { + friend CONSTEXPR_VECTOR void swap(dsu_t& lhs, dsu_t& rhs) noexcept { lhs.swap(rhs); } // O(log*(n)) = O(a(n)) - constexpr bool equal(size_type node_x_index, size_type node_y_index) noexcept { + [[nodiscard]] CONSTEXPR_VECTOR bool equal(size_type node_x_index, + size_type node_y_index) noexcept { assert(node_x_index < size() && node_y_index < size()); return base::equal(node_x_index, node_y_index); } // O(log*(n)) = O(a(n)) - constexpr void unite(size_type node_x_index, size_type node_y_index) noexcept { + CONSTEXPR_VECTOR void unite(size_type node_x_index, size_type node_y_index) noexcept { assert(node_x_index < size() && node_y_index < size()); - node_t* node_x_root_ptr = findRoot(node_x_index); - node_t* node_y_root_ptr = findRoot(node_y_index); + node_t* node_x_root_ptr = base::find_root(node_x_index); + node_t* node_y_root_ptr = base::find_root(node_y_index); if (node_x_root_ptr == node_y_root_ptr) { // Do not unite already united nodes so that for each root node: // root_node->parent_ == nullptr @@ -195,6 +214,9 @@ class dsu_t final : public dsu_impl::dsu_base { } } } + +private: + explicit CONSTEXPR_VECTOR dsu_t(size_type nodes_count) : base(nodes_count) {} }; /// @brief See also class dsu_t and @@ -206,16 +228,20 @@ class weighted_dsu_t final : public dsu_impl::dsu_base { weighted_dsu_t() = delete; // O(n) - explicit weighted_dsu_t(size_type nodes_count) : base(nodes_count) {} + [[nodiscard]] + static CONSTEXPR_VECTOR weighted_dsu_t with_nodes_count(size_type nodes_count) { + return weighted_dsu_t{nodes_count}; + } + + using WeightsVec = std::vector; // O(n) - explicit weighted_dsu_t(const std::vector& weights) : base(weights.size()) { - for (node_t* nodes_iter = data(); const auto weight : weights) { - nodes_iter->weight_ = weight; - ++nodes_iter; - } + [[nodiscard]] + static CONSTEXPR_VECTOR weighted_dsu_t from_weights_vec(const WeightsVec& weights) { + return weighted_dsu_t{weights}; } + // O(n) - constexpr weighted_dsu_t(const weighted_dsu_t& other) : base(other) { + CONSTEXPR_VECTOR weighted_dsu_t(const weighted_dsu_t& other) : base(other) { node_t* const this_first_node = data(); const node_t* const other_first_node = other.data(); @@ -229,31 +255,34 @@ class weighted_dsu_t final : public dsu_impl::dsu_base { } } // O(n) - constexpr weighted_dsu_t& operator=(const weighted_dsu_t& other) { + CONSTEXPR_VECTOR weighted_dsu_t& operator=(const weighted_dsu_t& other) + ATTRIBUTE_LIFETIME_BOUND { return *this = weighted_dsu_t(other); } - constexpr weighted_dsu_t(weighted_dsu_t&& other) noexcept : base(std::move(other)) {} - constexpr weighted_dsu_t& operator=(weighted_dsu_t&& other) noexcept { + CONSTEXPR_VECTOR weighted_dsu_t(weighted_dsu_t&& other) noexcept : base(std::move(other)) {} + CONSTEXPR_VECTOR weighted_dsu_t& operator=(weighted_dsu_t&& other) noexcept { base::operator=(std::move(other)); return *this; } - constexpr void swap(weighted_dsu_t& other) noexcept { + + CONSTEXPR_VECTOR void swap(weighted_dsu_t& other) noexcept { base::swap(other); } - friend constexpr void swap(weighted_dsu_t& lhs, weighted_dsu_t& rhs) noexcept { + friend CONSTEXPR_VECTOR void swap(weighted_dsu_t& lhs, weighted_dsu_t& rhs) noexcept { lhs.swap(rhs); } // O(log*(n)) - constexpr bool equal(size_type node_x_index, size_type node_y_index) noexcept { + [[nodiscard]] CONSTEXPR_VECTOR bool equal(size_type node_x_index, + size_type node_y_index) noexcept { assert(node_x_index < size() && node_y_index < size()); return base::equal(node_x_index, node_y_index); } // O(log*(n)) - constexpr void unite(size_type node_x_index, size_type node_y_index) noexcept { + CONSTEXPR_VECTOR void unite(size_type node_x_index, size_type node_y_index) noexcept { assert(node_x_index < size() && node_y_index < size()); - node_t* node_x_root_ptr = findRoot(node_x_index); - node_t* node_y_root_ptr = findRoot(node_y_index); + node_t* node_x_root_ptr = base::find_root(node_x_index); + node_t* node_y_root_ptr = base::find_root(node_y_index); if (node_x_root_ptr == node_y_root_ptr) { // Do not unite already united nodes so that for each root node: // root_node->parent_ == nullptr @@ -278,20 +307,31 @@ class weighted_dsu_t final : public dsu_impl::dsu_base { } // O(log*(n)) - constexpr int64_t getWeightInSet(size_type node_index) noexcept { + [[nodiscard]] CONSTEXPR_VECTOR int64_t get_weight_is_set(size_type node_index) noexcept { assert(node_index < size()); - return findRoot(node_index)->weight_; + return base::find_root(node_index)->weight_; } // O(log*(n)) - constexpr void addWeightInSet(size_type node_index, int64_t delta) noexcept { + CONSTEXPR_VECTOR void add_weight_in_set(size_type node_index, int64_t delta) noexcept { assert(node_index < size()); - findRoot(node_index)->weight_ += delta; + base::find_root(node_index)->weight_ += delta; } // O(log*(n)) - constexpr void setWeightInSet(size_type node_index, int64_t weight) noexcept { + CONSTEXPR_VECTOR void set_weight_in_set(size_type node_index, int64_t weight) noexcept { assert(node_index < size()); - findRoot(node_index)->weight_ = weight; + base::find_root(node_index)->weight_ = weight; + } + +private: + explicit CONSTEXPR_VECTOR weighted_dsu_t(size_type nodes_count) : base(nodes_count) {} + + explicit CONSTEXPR_VECTOR weighted_dsu_t(const WeightsVec& weights) : base(weights.size()) { + node_t* nodes_iter = data(); + for (const dsu_impl::Weight weight : weights) { + nodes_iter->weight_ = weight; + ++nodes_iter; + } } }; diff --git a/DisjointSetUnion/test_dsu.cpp b/DisjointSetUnion/test_dsu.cpp index 2bed939..799951c 100644 --- a/DisjointSetUnion/test_dsu.cpp +++ b/DisjointSetUnion/test_dsu.cpp @@ -7,6 +7,7 @@ #include #include +#include "../misc/get_typename.hpp" #include "dsu.hpp" template @@ -51,43 +52,12 @@ struct slowdsu { } }; -template -consteval std::string_view get_type_name() { - const std::string_view func_name = std::source_location::current().function_name(); - const char* p1 = std::char_traits::find(func_name.data(), func_name.size(), '['); - if (p1 == nullptr) { - return ""; - } - - const char* p2 = nullptr; - for (bool state = false;; p1++) { - switch (*p1) { - case '=': - state = true; - break; - case ' ': - if (state) { - p2 = p1 + 1; - state = false; - } - break; - case ';': - case ']': - case '\0': - if (p2 == nullptr) { - return ""; - } - const size_t len = static_cast(p1 - p2); - return std::string_view(p2, len); - } - } -} - template static void test_manual() { constexpr size_t N = 40; constexpr bool is_weighted = std::is_same_v; - DsuType tree(N); + + DsuType tree = DsuType::with_nodes_count(N); for (size_t i = 1; i < N; i++) { assert(!tree.equal(i - 1, i)); @@ -107,15 +77,15 @@ static void test_manual() { } if constexpr (is_weighted) { - tree.addWeightInSet(0, 10); - tree.addWeightInSet(2, 10); + tree.add_weight_in_set(0, 10); + tree.add_weight_in_set(2, 10); for (size_t i = 0; i <= 3; i++) { - assert(tree.getWeightInSet(i) == 20); + assert(tree.get_weight_is_set(i) == 20); } - tree.setWeightInSet(0, 10); + tree.set_weight_in_set(0, 10); for (size_t i = 0; i <= 3; i++) { - assert(tree.getWeightInSet(i) == 10); + assert(tree.get_weight_is_set(i) == 10); } } @@ -133,7 +103,7 @@ static void test_manual() { */ tree.unite(34, 35); if constexpr (is_weighted) { - tree.addWeightInSet(34, 2); + tree.add_weight_in_set(34, 2); } assert(tree.equal(34, 35)); assert(!tree.equal(35, 36)); @@ -141,16 +111,16 @@ static void test_manual() { assert(!tree.equal(37, 38)); assert(!tree.equal(38, 39)); if constexpr (is_weighted) { - assert(tree.getWeightInSet(34) == 2); - assert(tree.getWeightInSet(35) == 2); - assert(tree.getWeightInSet(36) == 0); - assert(tree.getWeightInSet(37) == 0); - assert(tree.getWeightInSet(38) == 0); - assert(tree.getWeightInSet(39) == 0); + assert(tree.get_weight_is_set(34) == 2); + assert(tree.get_weight_is_set(35) == 2); + assert(tree.get_weight_is_set(36) == 0); + assert(tree.get_weight_is_set(37) == 0); + assert(tree.get_weight_is_set(38) == 0); + assert(tree.get_weight_is_set(39) == 0); } tree.unite(36, 37); if constexpr (is_weighted) { - tree.addWeightInSet(37, 3); + tree.add_weight_in_set(37, 3); } assert(tree.equal(34, 35)); assert(!tree.equal(35, 36)); @@ -158,16 +128,16 @@ static void test_manual() { assert(!tree.equal(37, 38)); assert(!tree.equal(38, 39)); if constexpr (is_weighted) { - assert(tree.getWeightInSet(34) == 2); - assert(tree.getWeightInSet(35) == 2); - assert(tree.getWeightInSet(36) == 3); - assert(tree.getWeightInSet(37) == 3); - assert(tree.getWeightInSet(38) == 0); - assert(tree.getWeightInSet(39) == 0); + assert(tree.get_weight_is_set(34) == 2); + assert(tree.get_weight_is_set(35) == 2); + assert(tree.get_weight_is_set(36) == 3); + assert(tree.get_weight_is_set(37) == 3); + assert(tree.get_weight_is_set(38) == 0); + assert(tree.get_weight_is_set(39) == 0); } tree.unite(38, 39); if constexpr (is_weighted) { - tree.addWeightInSet(38, 4); + tree.add_weight_in_set(38, 4); } assert(tree.equal(34, 35)); assert(!tree.equal(35, 36)); @@ -175,12 +145,12 @@ static void test_manual() { assert(!tree.equal(37, 38)); assert(tree.equal(38, 39)); if constexpr (is_weighted) { - assert(tree.getWeightInSet(34) == 2); - assert(tree.getWeightInSet(35) == 2); - assert(tree.getWeightInSet(36) == 3); - assert(tree.getWeightInSet(37) == 3); - assert(tree.getWeightInSet(38) == 4); - assert(tree.getWeightInSet(39) == 4); + assert(tree.get_weight_is_set(34) == 2); + assert(tree.get_weight_is_set(35) == 2); + assert(tree.get_weight_is_set(36) == 3); + assert(tree.get_weight_is_set(37) == 3); + assert(tree.get_weight_is_set(38) == 4); + assert(tree.get_weight_is_set(39) == 4); } tree.unite(35, 37); assert(tree.equal(34, 35)); @@ -189,12 +159,12 @@ static void test_manual() { assert(!tree.equal(37, 38)); assert(tree.equal(38, 39)); if constexpr (is_weighted) { - assert(tree.getWeightInSet(34) == 5); - assert(tree.getWeightInSet(35) == 5); - assert(tree.getWeightInSet(36) == 5); - assert(tree.getWeightInSet(37) == 5); - assert(tree.getWeightInSet(38) == 4); - assert(tree.getWeightInSet(39) == 4); + assert(tree.get_weight_is_set(34) == 5); + assert(tree.get_weight_is_set(35) == 5); + assert(tree.get_weight_is_set(36) == 5); + assert(tree.get_weight_is_set(37) == 5); + assert(tree.get_weight_is_set(38) == 4); + assert(tree.get_weight_is_set(39) == 4); } tree.unite(37, 38); assert(tree.equal(34, 35)); @@ -203,12 +173,12 @@ static void test_manual() { assert(tree.equal(37, 38)); assert(tree.equal(38, 39)); if constexpr (is_weighted) { - assert(tree.getWeightInSet(34) == 9); - assert(tree.getWeightInSet(35) == 9); - assert(tree.getWeightInSet(36) == 9); - assert(tree.getWeightInSet(37) == 9); - assert(tree.getWeightInSet(38) == 9); - assert(tree.getWeightInSet(39) == 9); + assert(tree.get_weight_is_set(34) == 9); + assert(tree.get_weight_is_set(35) == 9); + assert(tree.get_weight_is_set(36) == 9); + assert(tree.get_weight_is_set(37) == 9); + assert(tree.get_weight_is_set(38) == 9); + assert(tree.get_weight_is_set(39) == 9); } for (size_t i = 34; i <= 39; i++) { for (size_t j = 34; j <= 39; j++) { @@ -226,16 +196,16 @@ static void test_manual() { } if constexpr (is_weighted) { - assert(tree.getWeightInSet(i) == 10 + 9); + assert(tree.get_weight_is_set(i) == 10 + 9); } } if constexpr (is_weighted) { std::vector vec{1, 2, 4, 8, 16, 32, 64}; - size_t n = vec.size(); - DsuType wdsu{vec}; + size_t n = vec.size(); + DsuType wdsu = DsuType::from_weights_vec(vec); for (size_t i = 0; i < n; i++) { - assert(wdsu.getWeightInSet(i) == vec[i]); + assert(wdsu.get_weight_is_set(i) == vec[i]); } wdsu.unite(0, 1); @@ -243,7 +213,7 @@ static void test_manual() { wdsu.unite(0, 2); int64_t sum = vec[0] + vec[1] + vec[2] + vec[3]; for (size_t i = 0; i <= 3; i++) { - assert(wdsu.getWeightInSet(i) == sum); + assert(wdsu.get_weight_is_set(i) == sum); } for (size_t i = 1; i < n; i++) { @@ -255,14 +225,15 @@ static void test_manual() { } for (size_t i = 0; i < n; i++) { - assert(wdsu.getWeightInSet(i) == sum); + assert(wdsu.get_weight_is_set(i) == sum); } } } template static void test_value_semantic() { - DsuType d1(4); + DsuType d1 = DsuType::with_nodes_count(4); + d1.unite(0, 1); d1.unite(2, 3); auto d2 = d1; @@ -294,8 +265,10 @@ static void test_value_semantic() { constexpr std::size_t size_d4 = 9; constexpr std::size_t size_d5 = 10; - DsuType d4(size_d4); - DsuType d5(size_d5); + + DsuType d4 = DsuType::with_nodes_count(size_d4); + DsuType d5 = DsuType::with_nodes_count(size_d5); + assert(d4.size() == size_d4); assert(d4.sets_size() == size_d4); assert(d5.size() == size_d5); @@ -340,7 +313,7 @@ static void test_value_semantic() { template static void test_random_with_check() { constexpr size_t N = 3000; - DsuType dsu(N); + DsuType dsu = DsuType::with_nodes_count(N); assert(dsu.size() == N); slowdsu checker; std::mt19937 rnd; @@ -378,7 +351,7 @@ static void test_random_with_check() { template static void test_dsu() { - constexpr std::string_view tname = get_type_name(); + constexpr std::string_view tname = misc::get_typename(); printf("Started testing type \"%.*s\"\n", int(tname.size()), tname.data()); test_manual(); test_value_semantic(); diff --git a/bstrees/RBTree.cppm b/bstrees/RBTree.cppm index 2e6561c..627a9ff 100644 --- a/bstrees/RBTree.cppm +++ b/bstrees/RBTree.cppm @@ -19,7 +19,7 @@ module; #include #include -#include "../number_theory/config_macros.hpp" +#include "../misc/config_macros.hpp" export module rbtree; diff --git a/graphs/HungarianAlgorithm/hungarian_algo.hpp b/graphs/HungarianAlgorithm/hungarian_algo.hpp index 31636b6..1c32f48 100644 --- a/graphs/HungarianAlgorithm/hungarian_algo.hpp +++ b/graphs/HungarianAlgorithm/hungarian_algo.hpp @@ -11,7 +11,7 @@ #include #include -#include "../../number_theory/config_macros.hpp" +#include "../../misc/config_macros.hpp" namespace hungarian_algo { diff --git a/number_theory/config_macros.hpp b/misc/config_macros.hpp similarity index 98% rename from number_theory/config_macros.hpp rename to misc/config_macros.hpp index b529b22..4cf55ec 100644 --- a/number_theory/config_macros.hpp +++ b/misc/config_macros.hpp @@ -1,3 +1,5 @@ +#pragma once + #ifndef CONFIG_MACROS_HPP #define CONFIG_MACROS_HPP @@ -112,7 +114,7 @@ #endif // https://en.cppreference.com/w/cpp/feature_test -#if defined(__cpp_concepts) && __cpp_concepts >= 201907L +#if CONFIG_HAS_AT_LEAST_CXX_20 && defined(__cpp_concepts) && __cpp_concepts >= 201907L #define CONFIG_HAS_CONCEPTS 1 #else #define CONFIG_HAS_CONCEPTS 0 @@ -131,11 +133,11 @@ #endif #if defined(__GNUC__) || defined(__clang__) -#define FUNCTION_MACRO __PRETTY_FUNCTION__ +#define CONFIG_CURRENT_FUNCTION_NAME __PRETTY_FUNCTION__ #elif defined(_MSC_VER) -#define FUNCTION_MACRO __FUNCSIG__ +#define CONFIG_CURRENT_FUNCTION_NAME __FUNCSIG__ #else -#define FUNCTION_MACRO __func__ +#define CONFIG_CURRENT_FUNCTION_NAME __func__ #endif #if CONFIG_HAS_INCLUDE() diff --git a/misc/get_typename.hpp b/misc/get_typename.hpp new file mode 100644 index 0000000..b178650 --- /dev/null +++ b/misc/get_typename.hpp @@ -0,0 +1,289 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "config_macros.hpp" + +#if defined(__cpp_lib_source_location) && __cpp_lib_source_location >= 201907L && \ + CONFIG_HAS_INCLUDE() +#define MISC_GET_TYPENAME_HAS_SOURCE_LOCATION +#include +#endif + +// https://en.cppreference.com/w/cpp/language/consteval +#if defined(__cpp_consteval) && __cpp_consteval >= 201811L +#define MISC_GET_TYPENAME_CONSTEVAL consteval +#else +#define MISC_GET_TYPENAME_CONSTEVAL constexpr +#endif + +// NOLINTBEGIN(cppcoreguidelines-macro-usage) + +namespace misc { + +namespace misc_detail { + +ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") +MISC_GET_TYPENAME_CONSTEVAL std::size_t get_typenameEndPosImpl(const std::string_view s) { + // Variables are not inside of the for init for + // the compatibility with C++17. + std::size_t opened_square_brackets = 0; + std::size_t opened_round_brackets = 0; + std::size_t opened_curly_brackets = 0; + std::size_t opened_triangle_brackets = 0; + std::size_t i = 0; + for (const char c : s) { + switch (static_cast(c)) { + case '(': { + opened_round_brackets++; + break; + } + case ')': { + if (opened_round_brackets == 0) { + return i; + } + opened_round_brackets--; + break; + } + case '{': { + opened_curly_brackets++; + break; + } + case '}': { + if (opened_round_brackets == 0) { + return i; + } + opened_round_brackets--; + break; + } + case '[': { + opened_square_brackets++; + break; + } + case ']': { + if (opened_square_brackets == 0) { + return i; + } + opened_square_brackets--; + break; + } + case '<': { + opened_triangle_brackets++; + break; + } + case '>': { + if (opened_triangle_brackets == 0) { + return i; + } + opened_triangle_brackets--; + break; + } + case ',': + case ';': { + if (opened_square_brackets == 0 && opened_round_brackets == 0 && + opened_curly_brackets == 0 && opened_triangle_brackets == 0) { + return i; + } + break; + } + default: + break; + } + + i++; + } + + return s.size(); +} + +#define CONSTEVAL_ASSERT_CONCAT_IMPL(arg1, arg2, arg3) arg1##arg2##arg3 +#define CONSTEVAL_ASSERT_CONCAT(arg1, arg2, arg3) CONSTEVAL_ASSERT_CONCAT_IMPL(arg1, arg2, arg3) +#define CONSTEVAL_ASSERT_GENERATE_UNIQUE_NAME(prefix) \ + CONSTEVAL_ASSERT_CONCAT(prefix, _unique_addendum_, __COUNTER__) + +#if CONFIG_GNUC_AT_LEAST(12, 1) || defined(__clang__) +#define CONSTEVAL_ASSERT(expr) \ + do { \ + static_cast(bool{(expr)} ? 0 : throw 0); \ + } while (false) +#else +#define CONSTEVAL_ASSERT(expr) \ + do { \ + static_cast(static_cast(expr) ? 0 : throw 0); \ + } while (false) +#endif + +ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") +MISC_GET_TYPENAME_CONSTEVAL +std::string_view extract_typename_impl( + const std::string_view function_name ATTRIBUTE_LIFETIME_BOUND) { + const auto is_space = [](char c) constexpr noexcept { + switch (static_cast(c)) { + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + return true; + default: + return false; + } + }; + +#if defined(__GNUG__) || defined(__clang__) + constexpr std::string_view type_prefix = "T = "; + const auto prefix_start_pos = function_name.find(type_prefix); + CONSTEVAL_ASSERT(prefix_start_pos != std::string_view::npos); + auto typename_start_pos = prefix_start_pos + type_prefix.size(); +#elif defined(_MSC_VER) + constexpr std::string_view type_prefix = "get_typename_impl<"; + const auto prefix_start_pos = function_name.find(type_prefix); + CONSTEVAL_ASSERT(prefix_start_pos != std::string_view::npos); + auto typename_start_pos = prefix_start_pos + type_prefix.size(); + CONSTEVAL_ASSERT(typename_start_pos < function_name.size()); + std::string_view piece = function_name.substr(typename_start_pos); + constexpr std::string_view kKeywords[] = { + "class", + "struct", + "enum", + "union", + }; + for (bool continue_cut = true; continue_cut;) { + continue_cut = false; + while (is_space(piece.front())) { + piece.remove_prefix(1); + typename_start_pos++; + } + for (const auto keyword : kKeywords) { +#if CONFIG_HAS_AT_LEAST_CXX_20 + if (piece.starts_with(keyword)) +#else + if (keyword.size() <= piece.size() && keyword == piece.substr(0, keyword.size())) +#endif + { + piece.remove_prefix(keyword.size()); + typename_start_pos += keyword.size(); + continue_cut = true; + break; + } + } + } + +#else +// cppcheck-suppress [preprocessorErrorDirective] +#error("Unsupported compiler") +#endif + + CONSTEVAL_ASSERT(typename_start_pos < function_name.size()); + while (is_space(function_name[typename_start_pos])) { + typename_start_pos++; + } + CONSTEVAL_ASSERT(typename_start_pos < function_name.size()); + const auto typename_end_pos = + typename_start_pos + get_typenameEndPosImpl(function_name.substr(typename_start_pos)); + CONSTEVAL_ASSERT(typename_end_pos < function_name.size()); + CONSTEVAL_ASSERT(typename_start_pos < typename_end_pos); + return function_name.substr(typename_start_pos, typename_end_pos - typename_start_pos); +} + +template +ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") +MISC_GET_TYPENAME_CONSTEVAL std::string_view get_typename_impl() { + const std::string_view function_name = +#ifdef MISC_GET_TYPENAME_HAS_SOURCE_LOCATION + std::source_location::current().function_name(); +#else + CONFIG_CURRENT_FUNCTION_NAME; +#endif + + return ::misc::misc_detail::extract_typename_impl(function_name); +} + +} // namespace misc_detail + +namespace misc_detail { + +// clang-format off + +template +ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") +MISC_GET_TYPENAME_CONSTEVAL +std::string_view extract_enum_value_name_impl(const std::string_view function_name ATTRIBUTE_LIFETIME_BOUND) { + // clang-format on + + using std::string_view; + +#if defined(__GNUG__) || defined(__clang__) + constexpr string_view prefix = "EnumValue = "; +#elif defined(_MSC_VER) + constexpr string_view prefix = "get_enum_value_name_impl<"; +#else +// cppcheck-suppress [preprocessorErrorDirective] +#error("Unsupported compiler") +#endif + + const auto prefix_start_pos = function_name.find(prefix); + CONSTEVAL_ASSERT(prefix_start_pos != string_view::npos); + auto value_start_pos = prefix_start_pos + prefix.size(); + CONSTEVAL_ASSERT(value_start_pos < function_name.size()); + const auto value_end_pos = + value_start_pos + get_typenameEndPosImpl(function_name.substr(value_start_pos)); + CONSTEVAL_ASSERT(value_start_pos < value_end_pos); + CONSTEVAL_ASSERT(value_end_pos < function_name.size()); + std::string_view full_name = + function_name.substr(value_start_pos, value_end_pos - value_start_pos); + constexpr std::string_view kScopeResolutionOperator = "::"; + if (const auto scope_res_operator_pos = full_name.rfind(kScopeResolutionOperator); + scope_res_operator_pos != std::string_view::npos) { + full_name = full_name.substr(scope_res_operator_pos + kScopeResolutionOperator.size()); + } + return full_name; +} + +template +ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") +MISC_GET_TYPENAME_CONSTEVAL std::string_view get_enum_value_name_impl() { + const std::string_view function_name = +#ifdef MISC_GET_TYPENAME_HAS_SOURCE_LOCATION + std::source_location::current().function_name(); +#else + CONFIG_CURRENT_FUNCTION_NAME; +#endif + return ::misc::misc_detail::extract_enum_value_name_impl(function_name); +} + +#undef CONSTEVAL_ASSERT +#undef CONSTEVAL_ASSERT_GENERATE_UNIQUE_NAME +#undef CONSTEVAL_ASSERT_CONCAT +#undef CONSTEVAL_ASSERT_CONCAT_IMPL + +} // namespace misc_detail + +template +ATTRIBUTE_NODISCARD_WITH_MESSAGE("requested name of the type should be used") +MISC_GET_TYPENAME_CONSTEVAL std::string_view get_typename() { + constexpr std::string_view kTypename = ::misc::misc_detail::get_typename_impl(); + return kTypename; +} + +template +ATTRIBUTE_NODISCARD_WITH_MESSAGE("requested name of the enum value should be used") +MISC_GET_TYPENAME_CONSTEVAL std::string_view get_enum_value_name() { + using EnumType = decltype(EnumValue); + static_assert(std::is_enum_v, "Value of the enum is expected"); + + constexpr std::string_view kEnumValueName = + ::misc::misc_detail::get_enum_value_name_impl(); + return kEnumValueName; +} + +} // namespace misc + +#undef MISC_GET_TYPENAME_CONSTEVAL +#ifdef MISC_GET_TYPENAME_HAS_SOURCE_LOCATION +#undef MISC_GET_TYPENAME_HAS_SOURCE_LOCATION +#endif diff --git a/misc/join_strings.hpp b/misc/join_strings.hpp new file mode 100644 index 0000000..63c724b --- /dev/null +++ b/misc/join_strings.hpp @@ -0,0 +1,309 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "config_macros.hpp" + +namespace misc { + +namespace join_strings_detail { + +template +inline constexpr bool is_char_v = std::is_same_v || std::is_same_v || +#if CONFIG_HAS_AT_LEAST_CXX_20 && defined(__cpp_char8_t) && __cpp_char8_t >= 201811L + std::is_same_v || +#endif + std::is_same_v || std::is_same_v; + +template , int> = 0> +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE inline std::basic_string ToStringOneArg(const T &arg) { + if constexpr (std::is_arithmetic_v) { + if constexpr (std::is_same_v) { + return std::basic_string(std::size_t{1}, arg); + } else if constexpr (std::is_same_v) { + return std::to_wstring(arg); + } else { + auto str = std::to_string(arg); + if constexpr (std::is_same_v) { + return str; + } else { + return std::basic_string(str.begin(), str.end()); + } + } + } else { + return std::basic_string{std::basic_string_view{arg}}; + } +} + +// clang-format off + +template +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE +constexpr std::enable_if_t, std::size_t> CalculateStringArgsSize(CharType /*c*/, const Args&... args) noexcept; + +template +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE +constexpr std::enable_if_t, std::size_t> CalculateStringArgsSize(std::basic_string_view s, const Args&... args) noexcept; + +// clang-format on + +template +constexpr std::enable_if_t, std::size_t> CalculateStringArgsSize( + CharType /*c*/, const Args &...args) noexcept { + size_t size = 1; + if constexpr (sizeof...(args) > 0) { + size += join_strings_detail::CalculateStringArgsSize(args...); + } + return size; +} + +template +constexpr std::enable_if_t, std::size_t> CalculateStringArgsSize( + std::basic_string_view s, const Args &...args) noexcept { + size_t size = s.size(); + if constexpr (sizeof...(args) > 0) { + size += join_strings_detail::CalculateStringArgsSize(args...); + } + return size; +} + +// clang-format off + +template +ATTRIBUTE_NONNULL_ALL_ARGS +ATTRIBUTE_ACCESS(write_only, 1) +ATTRIBUTE_ALWAYS_INLINE +constexpr std::enable_if_t, void> WriteStringsInplace(CharType* result, CharType c, const Args&... args) noexcept; + +template +ATTRIBUTE_NONNULL_ALL_ARGS +ATTRIBUTE_ACCESS(write_only, 1) +ATTRIBUTE_ALWAYS_INLINE +constexpr std::enable_if_t, void> WriteStringsInplace(CharType* result, std::basic_string_view s, const Args&... args) noexcept; + +// clang-format on + +template +constexpr std::enable_if_t, void> WriteStringsInplace( + CharType *result, CharType c, const Args &...args) noexcept { + *result = c; + if constexpr (sizeof...(args) > 0) { + join_strings_detail::WriteStringsInplace(result + 1, args...); + } +} + +template +constexpr std::enable_if_t, void> WriteStringsInplace( + CharType *result, std::basic_string_view s, const Args &...args) noexcept { + std::char_traits::copy(result, s.data(), s.size()); + if constexpr (sizeof...(args) > 0) { + join_strings_detail::WriteStringsInplace(result + s.size(), args...); + } +} + +// clang-format off + +template +ATTRIBUTE_NONNULL_ALL_ARGS +ATTRIBUTE_SIZED_ACCESS(write_only, 1, 2) +ATTRIBUTE_ALWAYS_INLINE +constexpr std::enable_if_t, void> WriteStringToBuffer(CharType* buffer, size_t /*buffer_size*/, const Args&... args) noexcept { + join_strings_detail::WriteStringsInplace(buffer, args...); +} + +// clang-format on + +template +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE inline std::enable_if_t, std::basic_string> +JoinStringsImpl(const Args &...args) { + std::size_t size = CalculateStringArgsSize(args...); + std::basic_string result(size, CharType{}); + join_strings_detail::WriteStringToBuffer(result.data(), result.size(), args...); + return result; +} + +// clang-format off + +template +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE +inline std::enable_if_t, std::basic_string> JoinStringsConvArgsToStrViewImpl(std::basic_string_view str, const Args&... args); + +template +[[nodiscard]] +ATTRIBUTE_ACCESS(read_only, 1) +ATTRIBUTE_ALWAYS_INLINE +inline std::enable_if_t, std::basic_string> JoinStringsConvArgsToStrViewImpl(const CharType* str, const Args&... args); + +template +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE +inline std::enable_if_t && std::is_arithmetic_v, std::basic_string> JoinStringsConvArgsToStrViewImpl(T num, const Args&... args); + +// clang-format on + +template +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE inline std::enable_if_t, std::basic_string> +JoinStringsConvArgsToStrViewImpl(std::basic_string_view str, const Args &...args) { + if constexpr (I == 1 + sizeof...(args)) { + return join_strings_detail::JoinStringsImpl(str, args...); + } else { + return join_strings_detail::JoinStringsConvArgsToStrViewImpl(args..., str); + } +} +template +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE inline std::enable_if_t, std::basic_string> +JoinStringsConvArgsToStrViewImpl(const CharType *str, const Args &...args) { + static_assert(I < 1 + sizeof...(args)); + return join_strings_detail::JoinStringsConvArgsToStrViewImpl( + args..., str ? std::basic_string_view{str} : std::basic_string_view{}); +} + +template +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE inline std::enable_if_t && std::is_arithmetic_v, + std::basic_string> +JoinStringsConvArgsToStrViewImpl(T num, const Args &...args) { + if constexpr (std::is_same_v) { + if constexpr (I == 1 + sizeof...(args)) { + return join_strings_detail::JoinStringsImpl(num, args...); + } else { + return join_strings_detail::JoinStringsConvArgsToStrViewImpl(args..., + num); + } + } else { + static_assert(I < 1 + sizeof...(args)); + return join_strings_detail::JoinStringsConvArgsToStrViewImpl( + args..., std::basic_string_view{ToStringOneArg(num)}); + } +} + +struct dummy_base {}; + +template +struct same_char_types : std::conditional_t || std::is_floating_point_v, + std::true_type, + std::false_type> {}; + +template +struct same_char_types, CharType> : std::true_type {}; + +template +struct same_char_types, CharType> : std::true_type {}; + +template +struct same_char_types : std::true_type {}; + +template +struct same_char_types : std::true_type {}; + +template +struct same_char_types : std::true_type {}; + +template +struct same_char_types : std::true_type {}; + +template +struct same_char_types : std::true_type {}; + +template +struct determine_char_type final { + using type = void; +}; + +template +struct recursion_selector final { + using type = typename determine_char_type::type; +}; + +template +struct char_selector final { + using type = CharType; +}; + +template +struct determine_char_type final { + using selector = std:: + conditional_t, char_selector, recursion_selector>; + + using type = typename selector::type; +}; + +template +struct determine_char_type, Types...> final { + using type = CharType; +}; + +template +struct determine_char_type, Types...> final { + using type = CharType; +}; + +template +struct determine_char_type final + : std::enable_if_t, dummy_base> { + using type = CharType; +}; + +template +struct determine_char_type final + : std::enable_if_t, dummy_base> { + using type = CharType; +}; + +template +struct determine_char_type final + : std::enable_if_t, dummy_base> { + using type = CharType; +}; + +template +struct determine_char_type final + : std::enable_if_t, dummy_base> { + using type = CharType; +}; + +template +using determine_char_t = typename determine_char_type::type; + +} // namespace join_strings_detail + +// clang-format off + +template +[[nodiscard]] +ATTRIBUTE_ALWAYS_INLINE +inline auto JoinStrings(const Args&... args) { + using DeducedCharType = join_strings_detail::determine_char_t; + + static_assert(join_strings_detail::is_char_v, "Hint type should be char, wchar_t, char8_t, char16_t or char32_t"); + using CharType = std::conditional_t, DeducedCharType, HintCharType>; + + static_assert( + std::conjunction_v...>, + "Hint:\n" + " Some non integral/float arguments have different char types\n" + " For example, both std::string and std::wstring might have been passed to the JoinStrings\n" + ); + + static_assert(sizeof...(args) >= 1, "Empty input is explicitly prohibited"); + if constexpr (sizeof...(args) >= 2) { + return join_strings_detail::JoinStringsConvArgsToStrViewImpl(args...); + } else { + return join_strings_detail::ToStringOneArg(args...); + } +} + +// clang-format on + +} // namespace misc diff --git a/misc/test_get_typename.cpp b/misc/test_get_typename.cpp new file mode 100644 index 0000000..8bdc18d --- /dev/null +++ b/misc/test_get_typename.cpp @@ -0,0 +1,29 @@ +#include + +#include "get_typename.hpp" + +enum class E { + kValue1 = 1, + kValue2, + kValue3, +}; + +namespace ns1 { + +class C {}; + +} // namespace ns1 + +static_assert(misc::get_typename() == "E"); +static_assert(misc::get_typename() == "ns1::C"); +static_assert(misc::get_enum_value_name() == "kValue1"); + +int main() { + assert(misc::get_typename() == "E"); + assert(std::string(misc::get_typename()) == "E"); + assert(misc::get_typename() == "ns1::C"); + assert(std::string(misc::get_typename()) == "ns1::C"); + assert(misc::get_enum_value_name() == "kValue1"); + assert(std::string(misc::get_enum_value_name()) == "kValue1"); + return 0; +} diff --git a/misc/test_join_strings.cpp b/misc/test_join_strings.cpp new file mode 100644 index 0000000..b220355 --- /dev/null +++ b/misc/test_join_strings.cpp @@ -0,0 +1,90 @@ +#include +#include +#include + +#include "join_strings.hpp" + +int main() { + { + assert(misc::JoinStrings("") == ""); + assert(misc::JoinStrings("ab", "cde") == "abcde"); + assert(misc::JoinStrings("ab", "cde", "fghi") == "abcdefghi"); + assert(misc::JoinStrings("ab", "cde", "fghi", "jklmn") == "abcdefghijklmn"); + assert(misc::JoinStrings("ab", 1, "cde", 2, "fghi", 3, "jklmn") == "ab1cde2fghi3jklmn"); + + std::string s1 = "ab"; + std::string_view s2 = "cde"; + const char s3[] = "fghi"; + const char* s4 = "jklmn"; + + assert(misc::JoinStrings(s1, 1, "", s2, 2, "", s3, "", 3, s4) == "ab1cde2fghi3jklmn"); + assert(misc::JoinStrings(s2, 1, "", s3, 2, "", s4, "", 3, s1) == "cde1fghi2jklmn3ab"); + assert(misc::JoinStrings(s3, 1, "", s4, 2, "", s1, "", 3, s2) == "fghi1jklmn2ab3cde"); + assert(misc::JoinStrings(s4, 1, "", s1, 2, "", s2, "", 3, s3) == "jklmn1ab2cde3fghi"); + + assert(misc::JoinStrings(0, s1, "", 1, s2, "", 2, "", s3, 3, s4) == "0ab1cde2fghi3jklmn"); + assert(misc::JoinStrings(0, s2, "", 1, s3, "", 2, "", s4, 3, s1) == "0cde1fghi2jklmn3ab"); + assert(misc::JoinStrings(0, s3, "", 1, s4, "", 2, "", s1, 3, s2) == "0fghi1jklmn2ab3cde"); + assert(misc::JoinStrings(0, s4, "", 1, s1, "", 2, "", s2, 3, s3) == "0jklmn1ab2cde3fghi"); + + assert(misc::JoinStrings(s1, 1, s2, 2, s3, 3, s4) == "ab1cde2fghi3jklmn"); + assert(misc::JoinStrings(s2, 1, s3, 2, s4, 3, s1) == "cde1fghi2jklmn3ab"); + assert(misc::JoinStrings(s3, 1, s4, 2, s1, 3, s2) == "fghi1jklmn2ab3cde"); + assert(misc::JoinStrings(s4, 1, s1, 2, s2, 3, s3) == "jklmn1ab2cde3fghi"); + + assert(misc::JoinStrings(0, s1, 1, s2, 2, s3, 3, s4) == "0ab1cde2fghi3jklmn"); + assert(misc::JoinStrings(0, s2, 1, s3, 2, s4, 3, s1) == "0cde1fghi2jklmn3ab"); + assert(misc::JoinStrings(0, s3, 1, s4, 2, s1, 3, s2) == "0fghi1jklmn2ab3cde"); + assert(misc::JoinStrings(0, s4, 1, s1, 2, s2, 3, s3) == "0jklmn1ab2cde3fghi"); + + assert(misc::JoinStrings(1) == "1"); + assert(misc::JoinStrings(1, 2) == "12"); + assert(misc::JoinStrings(1, 2, 3) == "123"); + assert(misc::JoinStrings(1, 2, 3, 4) == "1234"); + assert(misc::JoinStrings(1, 2, 3, 4, 5) == "12345"); + } + + { + assert(misc::JoinStrings(L"") == L""); + assert(misc::JoinStrings(L"ab", L"cde") == L"abcde"); + assert(misc::JoinStrings(L"ab", L"cde", L"fghi") == L"abcdefghi"); + assert(misc::JoinStrings(L"ab", L"cde", L"fghi", L"jklmn") == L"abcdefghijklmn"); + assert(misc::JoinStrings(L"ab", 1, L"cde", 2, L"fghi", 3, L"jklmn") == + L"ab1cde2fghi3jklmn"); + + std::wstring s1 = L"ab"; + std::wstring_view s2 = L"cde"; + const wchar_t s3[] = L"fghi"; + const wchar_t* s4 = L"jklmn"; + + assert(misc::JoinStrings(s1, 1, s2, 2, s3, 3, s4) == L"ab1cde2fghi3jklmn"); + assert(misc::JoinStrings(s2, 1, s3, 2, s4, 3, s1) == L"cde1fghi2jklmn3ab"); + assert(misc::JoinStrings(s3, 1, s4, 2, s1, 3, s2) == L"fghi1jklmn2ab3cde"); + assert(misc::JoinStrings(s4, 1, s1, 2, s2, 3, s3) == L"jklmn1ab2cde3fghi"); + + assert(misc::JoinStrings(0, s1, 1, s2, 2, s3, 3, s4) == L"0ab1cde2fghi3jklmn"); + assert(misc::JoinStrings(0, s2, 1, s3, 2, s4, 3, s1) == L"0cde1fghi2jklmn3ab"); + assert(misc::JoinStrings(0, s3, 1, s4, 2, s1, 3, s2) == L"0fghi1jklmn2ab3cde"); + assert(misc::JoinStrings(0, s4, 1, s1, 2, s2, 3, s3) == L"0jklmn1ab2cde3fghi"); + + assert(misc::JoinStrings(s1, 1, L"", s2, 2, L"", s3, L"", 3, s4) == L"ab1cde2fghi3jklmn"); + assert(misc::JoinStrings(s2, 1, L"", s3, 2, L"", s4, L"", 3, s1) == L"cde1fghi2jklmn3ab"); + assert(misc::JoinStrings(s3, 1, L"", s4, 2, L"", s1, L"", 3, s2) == L"fghi1jklmn2ab3cde"); + assert(misc::JoinStrings(s4, 1, L"", s1, 2, L"", s2, L"", 3, s3) == L"jklmn1ab2cde3fghi"); + + assert(misc::JoinStrings(0, s1, L"", 1, s2, L"", 2, L"", s3, 3, s4) == + L"0ab1cde2fghi3jklmn"); + assert(misc::JoinStrings(0, s2, L"", 1, s3, L"", 2, L"", s4, 3, s1) == + L"0cde1fghi2jklmn3ab"); + assert(misc::JoinStrings(0, s3, L"", 1, s4, L"", 2, L"", s1, 3, s2) == + L"0fghi1jklmn2ab3cde"); + assert(misc::JoinStrings(0, s4, L"", 1, s1, L"", 2, L"", s2, 3, s3) == + L"0jklmn1ab2cde3fghi"); + + assert(misc::JoinStrings(1) == L"1"); + assert(misc::JoinStrings(1, 2) == L"12"); + assert(misc::JoinStrings(1, 2, 3) == L"123"); + assert(misc::JoinStrings(1, 2, 3, 4) == L"1234"); + assert(misc::JoinStrings(1, 2, 3, 4, 5) == L"12345"); + } +} diff --git a/misc/test_tools.hpp b/misc/test_tools.hpp new file mode 100644 index 0000000..1b2afe4 --- /dev/null +++ b/misc/test_tools.hpp @@ -0,0 +1,228 @@ +#pragma once + +#ifdef NDEBUG +#error("Can't test properly with NDEBUG macro defined (macro won't be undefined manually)") +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../misc/config_macros.hpp" + +#if defined(__cpp_lib_source_location) && __cpp_lib_source_location >= 201907L && \ + CONFIG_HAS_INCLUDE() +#define TEST_TOOLS_HAS_SOURCE_LOCATION +#include +#endif + +// NOLINTBEGIN(cppcoreguidelines-macro-usage) + +namespace test_tools { + +namespace test_tools_detail { + +[[noreturn]] ATTRIBUTE_COLD inline void throw_impl(const char* message, + const char* file_name, + std::uint32_t line, + const char* function_name) { + constexpr std::size_t kMaxErrorMessageSize = 1024 * sizeof(char); + std::array buffer{}; + const int bytes_written = + std::snprintf(buffer.data(), buffer.size(), "Check failed at %s:%u %s\nError message: %s\n", + file_name, line, function_name, message); + if (unlikely(bytes_written < 0)) { + std::perror("std::snprintf"); +#if defined(__cpp_lib_to_array) && __cpp_lib_to_array >= 201907L + constexpr std::array msg = + std::to_array("std::snprintf failed while filling exception message"); +#else + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + constexpr char msg[] = "std::snprintf failed while filling exception message"; +#endif + static_assert(std::size(msg) < kMaxErrorMessageSize, "impl error"); + std::char_traits::copy(buffer.data(), std::data(msg), std::size(msg)); + buffer[std::size(msg)] = '\0'; + } + + throw std::runtime_error(buffer.data()); +} + +inline void log_location_impl(const char* file_name, + std::uint32_t line, + const char* function_name) noexcept { + std::printf("%s:%u: %s\n", file_name, line, function_name); +} + +inline void log_message_impl(const char* file_name, + std::uint32_t line, + const char* function_name, + const char* message) noexcept { + std::printf("%s:%u: %s:\n %s\n", file_name, line, function_name, message); +} + +inline void log_message_impl(const char* file_name, + std::uint32_t line, + const char* function_name, + std::string_view message) noexcept { + const auto message_size = static_cast(message.size()); + std::printf("%s:%u: %s:\n %.*s\n", file_name, line, function_name, message_size, + message.data()); +} + +} // namespace test_tools_detail + +#if defined(TEST_TOOLS_HAS_SOURCE_LOCATION) + +ATTRIBUTE_ALWAYS_INLINE inline void log_tests_started( + const std::source_location src = std::source_location::current()) noexcept { + int ret = std::printf("Started tests in %s\n", src.function_name()); + assert(ret > 0); + ret = std::fflush(stdout); + assert(ret == 0); +} + +ATTRIBUTE_ALWAYS_INLINE inline void log_location( + const std::source_location src = std::source_location::current()) noexcept { + ::test_tools::test_tools_detail::log_location_impl(src.file_name(), src.line(), + src.function_name()); +} + +ATTRIBUTE_ALWAYS_INLINE inline void log_message( + const char* message, + const std::source_location src = std::source_location::current()) noexcept { + ::test_tools::test_tools_detail::log_message_impl(src.file_name(), src.line(), + src.function_name(), message); +} + +ATTRIBUTE_ALWAYS_INLINE inline void log_message( + std::string_view message, + const std::source_location src = std::source_location::current()) noexcept { + ::test_tools::test_tools_detail::log_message_impl(src.file_name(), src.line(), + src.function_name(), message); +} + +#else + +namespace test_tools_detail { + +ATTRIBUTE_ALWAYS_INLINE inline void log_tests_started_impl(const char* function_name) noexcept { + printf("Started tests in %s\n", function_name); +} + +} // namespace test_tools_detail + +#define log_tests_started() test_tools_detail::log_tests_started_impl(CONFIG_CURRENT_FUNCTION_NAME) + +#define log_location() \ + test_tools_detail::log_location_impl(__FILE__, __LINE__, CONFIG_CURRENT_FUNCTION_NAME) + +#define log_message(message) \ + test_tools_detail::log_message_impl(__FILE__, __LINE__, CONFIG_CURRENT_FUNCTION_NAME, message); + +#endif + +struct FilePtr final { + using FileHandle = std::FILE*; + FileHandle const file; // NOLINT(misc-misplaced-const) + + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + [[nodiscard]] /* implicit */ constexpr operator FileHandle() noexcept { + return file; + } + + FilePtr(const char* fname, const char* mode) : file(DoFOpenOrThrow(fname, mode)) {} + FilePtr(const FilePtr&) = delete; + FilePtr(FilePtr&&) = delete; + FilePtr& operator=(const FilePtr&) = delete; + FilePtr& operator=(FilePtr&&) = delete; + ~FilePtr() { + if (std::fclose(file) != 0) { + std::perror("fclose"); + } + } + +private: + ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") + ATTRIBUTE_RETURNS_NONNULL + ATTRIBUTE_ALWAYS_INLINE + static FileHandle DoFOpenOrThrow(const char* fname, const char* mode) { + // NOLINTNEXTLINE(misc-misplaced-const, cppcoreguidelines-owning-memory) + FileHandle const file_handle = std::fopen(fname, mode); + if (unlikely(file_handle == nullptr)) { + ThrowOnFOpenFail(fname, mode); + } + + return file_handle; + } + [[noreturn]] ATTRIBUTE_COLD static void ThrowOnFOpenFail(const char* fname, const char* mode) { + constexpr std::size_t kMaxErrorMessageSize = 1024 * sizeof(char); + const auto errno_value = errno; + std::array buffer{}; + const int bytes_written = std::snprintf( + buffer.data(), buffer.size(), + "FilePtr::FilePtr(const char* fname, const char* mode): " + "std::fopen(\"%s\", \"%s\") failed: %s", + fname, mode, std::strerror(errno_value)); // NOLINT(concurrency-mt-unsafe) + if (unlikely(bytes_written < 0)) { +#if defined(__cpp_lib_to_array) && __cpp_lib_to_array >= 201907L + constexpr std::array msg = std::to_array( + "FilePtr::FilePtr(const char* fname,const char* mode): std::snprintf failed after " + "std::fopen failed"); +#else + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + constexpr char msg[] = + "FilePtr::FilePtr(const char* fname,const char* mode): std::snprintf failed after " + "std::fopen failed"; +#endif + static_assert(std::size(msg) < kMaxErrorMessageSize, "impl error"); + std::char_traits::copy(buffer.data(), std::data(msg), std::size(msg)); + buffer[std::size(msg)] = '\0'; + } + + throw std::runtime_error(buffer.data()); + } +}; + +template +struct EchoLogger { + // NOLINTBEGIN(cert-oop54-cpp) + + EchoLogger() { + ::test_tools::log_location(); + } + EchoLogger(const EchoLogger& /*unused*/) noexcept { + ::test_tools::log_location(); + } + EchoLogger(EchoLogger&& /*unused*/) noexcept { + ::test_tools::log_location(); + } + EchoLogger& operator=(const EchoLogger& /*unused*/) noexcept { + ::test_tools::log_location(); + return *this; + } + EchoLogger& operator=(EchoLogger&& /*unused*/) noexcept { + ::test_tools::log_location(); + return *this; + } + ~EchoLogger() { + ::test_tools::log_location(); + } + + // NOLINTEND(cert-oop54-cpp) +}; + +} // namespace test_tools + +// NOLINTEND(cppcoreguidelines-macro-usage) + +#if defined(TEST_TOOLS_HAS_SOURCE_LOCATION) +#undef TEST_TOOLS_HAS_SOURCE_LOCATION +#endif diff --git a/number_theory/CNKCounter.hpp b/number_theory/CNKCounter.hpp index 35170ab..2ab9891 100644 --- a/number_theory/CNKCounter.hpp +++ b/number_theory/CNKCounter.hpp @@ -9,7 +9,7 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" #if CONFIG_HAS_AT_LEAST_CXX_20 #define CXX20_CONSTEXPR constexpr diff --git a/number_theory/bitmatrix.hpp b/number_theory/bitmatrix.hpp index 44a6fde..4c99b49 100644 --- a/number_theory/bitmatrix.hpp +++ b/number_theory/bitmatrix.hpp @@ -15,7 +15,7 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" #if CONFIG_HAS_AT_LEAST_CXX_20 && CONFIG_HAS_INCLUDE() #include diff --git a/number_theory/fft.hpp b/number_theory/fft.hpp index 4fae4aa..ac6cf72 100644 --- a/number_theory/fft.hpp +++ b/number_theory/fft.hpp @@ -10,7 +10,7 @@ #include #endif -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" namespace fft { diff --git a/number_theory/fibonacci_num.hpp b/number_theory/fibonacci_num.hpp index 9387e22..ff957c8 100644 --- a/number_theory/fibonacci_num.hpp +++ b/number_theory/fibonacci_num.hpp @@ -1,6 +1,6 @@ #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" #if CONFIG_HAS_INCLUDE("integers_128_bit.hpp") #include "integers_128_bit.hpp" diff --git a/number_theory/gosper_algorithm.hpp b/number_theory/gosper_algorithm.hpp index 2d3065b..a8bb94d 100644 --- a/number_theory/gosper_algorithm.hpp +++ b/number_theory/gosper_algorithm.hpp @@ -6,7 +6,7 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" #include "math_functions.hpp" namespace math_functions { diff --git a/number_theory/integers_128_bit.hpp b/number_theory/integers_128_bit.hpp index f0950a9..2ac3814 100644 --- a/number_theory/integers_128_bit.hpp +++ b/number_theory/integers_128_bit.hpp @@ -12,7 +12,7 @@ * */ -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" #if (defined(__clang__) || defined(__GNUC__)) && defined(__SIZEOF_INT128__) diff --git a/number_theory/is_prime.hpp b/number_theory/is_prime.hpp index e27a617..63f4af9 100644 --- a/number_theory/is_prime.hpp +++ b/number_theory/is_prime.hpp @@ -5,7 +5,7 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" #include "integers_128_bit.hpp" #include "kronecker_symbol.hpp" #include "math_functions.hpp" diff --git a/number_theory/longint.hpp b/number_theory/longint.hpp index 1e37867..3e31e37 100644 --- a/number_theory/longint.hpp +++ b/number_theory/longint.hpp @@ -17,7 +17,7 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" #include "fft.hpp" #if CONFIG_HAS_INCLUDE("integers_128_bit.hpp") #include "integers_128_bit.hpp" @@ -133,7 +133,7 @@ class inner_impl final { init_small_pages(); init_middle_pages(); #ifdef DEBUG_LI_ALLOC_PRINTING - printf("[INIT] Inited pages in %s\n", FUNCTION_MACRO); + printf("[INIT] Inited pages in %s\n", CONFIG_CURRENT_FUNCTION_NAME); #endif } @@ -152,7 +152,7 @@ class inner_impl final { "[MALLOC]:\n" " total bytes allocated: %zd\n" " malloc calls - free calls: %d\n", - FUNCTION_MACRO, total_small_pages_used, max_small_pages_used, current_small_pages_used, + CONFIG_CURRENT_FUNCTION_NAME, total_small_pages_used, max_small_pages_used, current_small_pages_used, total_middle_pages_used, max_middle_pages_used, current_middle_pages_used, bytes_allocated, malloc_free_count); } @@ -1655,7 +1655,7 @@ struct longint { DecFFT& operator=(const DecFFT&) = delete; DecFFT& operator=(DecFFT&&) = delete; ~DecFFT() { - ::operator delete(static_cast(poly_)); + deallocate_polynomials(poly_); } void multiply_and_store_to_impl(Decimal& product_result) const { @@ -1680,7 +1680,7 @@ struct longint { ATTRIBUTE_ALWAYS_INLINE static dec_size_type check_size_for_fft(const dec_size_type value) { if (unlikely(value > kMaxDecFFTSize)) { - throw_size_error(__FILE__, __LINE__, FUNCTION_MACRO, value, kMaxDecFFTSize); + throw_size_error(__FILE__, __LINE__, CONFIG_CURRENT_FUNCTION_NAME, value, kMaxDecFFTSize); } return value; @@ -1711,6 +1711,10 @@ struct longint { // and n for the second one return static_cast(::operator new(size_value * 2 * sizeof(fft::complex))); } + ATTRIBUTE_ALWAYS_INLINE + static void deallocate_polynomials(fft::complex* poly) noexcept { + ::operator delete(static_cast(poly)); + } ATTRIBUTE_SIZED_ACCESS(read_only, 1, 2) ATTRIBUTE_SIZED_ACCESS(read_only, 3, 4) ATTRIBUTE_SIZED_ACCESS(write_only, 6, 5) @@ -2799,7 +2803,7 @@ struct longint { } ATTRIBUTE_ALWAYS_INLINE static size_type check_size(const std::size_t value) { if (unlikely(value > max_size())) { - throw_size_error(__FILE__, __LINE__, FUNCTION_MACRO, value, max_size()); + throw_size_error(__FILE__, __LINE__, CONFIG_CURRENT_FUNCTION_NAME, value, max_size()); } const size_type checked_value = static_cast(value); if (checked_value > max_size()) { diff --git a/number_theory/math_functions.hpp b/number_theory/math_functions.hpp index dd0427f..daa56c8 100644 --- a/number_theory/math_functions.hpp +++ b/number_theory/math_functions.hpp @@ -32,7 +32,7 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" #if CONFIG_HAS_AT_LEAST_CXX_20 && CONFIG_HAS_INCLUDE() #include @@ -125,7 +125,7 @@ template const bool not_inverse = p >= 0; const size_t p_u = p >= 0 ? static_cast(p) : -static_cast(p); const T res = ::math_functions::bin_pow(std::move(n), p_u); - return not_inverse ? res : 1 / res; + return not_inverse ? res : T(1) / res; } /// @brief Calculate (n ^ p) % mod @@ -238,8 +238,8 @@ ATTRIBUTE_CONST I128_CONSTEXPR uint64_t bin_pow_mod(uint64_t n, uint64_t p, uint return static_cast(l - 1); #if defined(__GNUG__) || defined(__clang__) || CONFIG_HAS_AT_LEAST_CXX_20 } - return static_cast(std::sqrt(static_cast(n))); + return static_cast(std::sqrt(static_cast(n))); #endif } @@ -292,7 +292,7 @@ ATTRIBUTE_CONST I128_CONSTEXPR uint64_t bin_pow_mod(uint64_t n, uint64_t p, uint */ #if defined(__GNUG__) && !defined(__clang__) && CONFIG_HAS_AT_LEAST_CXX_17 - [[maybe_unused]] const auto n_original_value = n; + ATTRIBUTE_MAYBE_UNUSED const auto n_original_value = n; #endif uint32_t y = 0; @@ -1771,8 +1771,8 @@ namespace detail { /// number of different prime divisors of @a `n`. /// @param[in] n /// @return -[[nodiscard]] ATTRIBUTE_CONST constexpr uint32_t max_number_of_unique_prime_divisors( - uint32_t n) noexcept { +ATTRIBUTE_NODISCARD +ATTRIBUTE_CONST constexpr uint32_t max_number_of_unique_prime_divisors(uint32_t n) noexcept { constexpr uint32_t kBoundary2 = 2 * 3; constexpr uint32_t kBoundary3 = 2 * 3 * 5; constexpr uint32_t kBoundary4 = 2 * 3 * 5 * 7; @@ -2123,7 +2123,8 @@ class [[nodiscard]] Factorizer final { /// @return bitset, such that bitset[n] == true \iff n is prime template [[nodiscard]] CONSTEXPR_FIXED_PRIMES_SIEVE inline const auto& fixed_primes_sieve() noexcept { - using PrimesSet = std::bitset; + using PrimesSet = std::bitset; + static CONSTEXPR_PRIMES_SIEVE const PrimesSet primes_bs = []() CONSTEXPR_BITSET_OPS noexcept { PrimesSet primes{}; primes.set(); @@ -2399,8 +2400,14 @@ typename ::math_functions::InverseResult inv_range_mod_m_impl(Iter nums_begin, I const auto n = static_cast(std::distance(nums_begin, nums_end)); auto res = ::math_functions::InverseResult{ - std::vector(n), - std::vector(n), +#if CONFIG_HAS_AT_LEAST_CXX_20 + .numbers_mod_m = +#endif + std::vector(n), +#if CONFIG_HAS_AT_LEAST_CXX_20 + .inversed_numbers = +#endif + std::vector(n), }; uint32_t prod_mod_m = 1; diff --git a/number_theory/measure_is_prime_bpsw.cpp b/number_theory/measure_is_prime_bpsw.cpp index 9818350..b048eb9 100644 --- a/number_theory/measure_is_prime_bpsw.cpp +++ b/number_theory/measure_is_prime_bpsw.cpp @@ -5,8 +5,8 @@ #include #include +#include "../misc/test_tools.hpp" #include "is_prime.hpp" -#include "test_tools.hpp" using namespace test_tools; diff --git a/number_theory/test_bitmatrix.cpp b/number_theory/test_bitmatrix.cpp index b73f742..9d4f6d5 100644 --- a/number_theory/test_bitmatrix.cpp +++ b/number_theory/test_bitmatrix.cpp @@ -5,9 +5,9 @@ #include #include +#include "../misc/config_macros.hpp" +#include "../misc/test_tools.hpp" #include "bitmatrix.hpp" -#include "config_macros.hpp" -#include "test_tools.hpp" // clang-format off // NOLINTBEGIN(cert-dcl03-c, misc-static-assert, hicpp-static-assert, cppcoreguidelines-avoid-magic-numbers) diff --git a/number_theory/test_cnk_counter.cpp b/number_theory/test_cnk_counter.cpp index 8968b78..f9ddcad 100644 --- a/number_theory/test_cnk_counter.cpp +++ b/number_theory/test_cnk_counter.cpp @@ -8,9 +8,9 @@ #include #include +#include "../misc/config_macros.hpp" +#include "../misc/test_tools.hpp" #include "CNKCounter.hpp" -#include "config_macros.hpp" -#include "test_tools.hpp" // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) diff --git a/number_theory/test_fibonacci_num.cpp b/number_theory/test_fibonacci_num.cpp index adef1e9..15363ec 100644 --- a/number_theory/test_fibonacci_num.cpp +++ b/number_theory/test_fibonacci_num.cpp @@ -1,8 +1,8 @@ #include #include +#include "../misc/test_tools.hpp" #include "fibonacci_num.hpp" -#include "test_tools.hpp" // NOLINTBEGIN(cert-dcl03-c, misc-static-assert, hicpp-static-assert, // cppcoreguidelines-avoid-magic-numbers) diff --git a/number_theory/test_gosper_algorithm.cpp b/number_theory/test_gosper_algorithm.cpp index 8c2f184..3c99017 100644 --- a/number_theory/test_gosper_algorithm.cpp +++ b/number_theory/test_gosper_algorithm.cpp @@ -6,10 +6,10 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" +#include "../misc/test_tools.hpp" #include "gosper_algorithm.hpp" #include "math_functions.hpp" -#include "test_tools.hpp" // NOLINTBEGIN(cert-dcl03-c, misc-static-assert, hicpp-static-assert, // cppcoreguidelines-avoid-magic-numbers) diff --git a/number_theory/test_integers_128_bit.cpp b/number_theory/test_integers_128_bit.cpp index 7a4b23b..73b2d24 100644 --- a/number_theory/test_integers_128_bit.cpp +++ b/number_theory/test_integers_128_bit.cpp @@ -4,9 +4,9 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" +#include "../misc/test_tools.hpp" #include "integers_128_bit.hpp" -#include "test_tools.hpp" namespace { diff --git a/number_theory/test_is_prime_bpsw.cpp b/number_theory/test_is_prime_bpsw.cpp index f08432e..4ae0bf0 100644 --- a/number_theory/test_is_prime_bpsw.cpp +++ b/number_theory/test_is_prime_bpsw.cpp @@ -12,10 +12,10 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" +#include "../misc/test_tools.hpp" #include "integers_128_bit.hpp" #include "is_prime.hpp" -#include "test_tools.hpp" #if CONFIG_HAS_INCLUDE() #include diff --git a/number_theory/test_kronecker_symbol.cpp b/number_theory/test_kronecker_symbol.cpp index 2c95239..5663089 100644 --- a/number_theory/test_kronecker_symbol.cpp +++ b/number_theory/test_kronecker_symbol.cpp @@ -7,11 +7,11 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" +#include "../misc/test_tools.hpp" #include "fibonacci_num.hpp" #include "kronecker_symbol.hpp" #include "math_functions.hpp" -#include "test_tools.hpp" using math_functions::kronecker_symbol; using math_functions::nth_fibonacci_num; diff --git a/number_theory/test_long_int.cpp b/number_theory/test_long_int.cpp index a8a6ff8..0d55f33 100644 --- a/number_theory/test_long_int.cpp +++ b/number_theory/test_long_int.cpp @@ -12,11 +12,11 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" +#include "../misc/test_tools.hpp" #include "integers_128_bit.hpp" #include "longint.hpp" #include "math_functions.hpp" -#include "test_tools.hpp" // clang-format off // NOLINTBEGIN(cert-dcl03-c, misc-static-assert, hicpp-static-assert, cppcoreguidelines-avoid-magic-numbers) diff --git a/number_theory/test_math_functions.cpp b/number_theory/test_math_functions.cpp index e5c954a..ebb42af 100644 --- a/number_theory/test_math_functions.cpp +++ b/number_theory/test_math_functions.cpp @@ -23,12 +23,13 @@ #include #include -#include "config_macros.hpp" #include "math_functions.hpp" #if CONFIG_HAS_INCLUDE("integers_128_bit.hpp") #include "integers_128_bit.hpp" #endif -#include "test_tools.hpp" + +#include "../misc/config_macros.hpp" +#include "../misc/test_tools.hpp" #if CONFIG_HAS_AT_LEAST_CXX_20 #include diff --git a/number_theory/test_tools.hpp b/number_theory/test_tools.hpp deleted file mode 100644 index 0c7b5be..0000000 --- a/number_theory/test_tools.hpp +++ /dev/null @@ -1,520 +0,0 @@ -#pragma once - -#ifdef NDEBUG -#error("Can't test properly with NDEBUG macro defined (macro won't be undefined manually)") -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config_macros.hpp" - -#if defined(__cpp_lib_source_location) && __cpp_lib_source_location >= 201907L && \ - CONFIG_HAS_INCLUDE() -#define TEST_TOOLS_HAS_SOURCE_LOCATION -#include -#endif - -// https://en.cppreference.com/w/cpp/language/consteval -#if defined(__cpp_consteval) && __cpp_consteval >= 201811L -#define TEST_TOOLS_CONSTEVAL consteval -#else -#define TEST_TOOLS_CONSTEVAL constexpr -#endif - -// NOLINTBEGIN(cppcoreguidelines-macro-usage) - -namespace test_tools { -namespace test_tools_detail { - -[[noreturn]] ATTRIBUTE_COLD inline void throw_impl(const char* message, - const char* file_name, - std::uint32_t line, - const char* function_name) { - constexpr std::size_t kMaxErrorMessageSize = 1024 * sizeof(char); - std::array buffer{}; - const int bytes_written = - std::snprintf(buffer.data(), buffer.size(), "Check failed at %s:%u %s\nError message: %s\n", - file_name, line, function_name, message); - if (unlikely(bytes_written < 0)) { - std::perror("std::snprintf"); -#if defined(__cpp_lib_to_array) && __cpp_lib_to_array >= 201907L - constexpr std::array msg = - std::to_array("std::snprintf failed while filling exception message"); -#else - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - constexpr char msg[] = "std::snprintf failed while filling exception message"; -#endif - static_assert(std::size(msg) < kMaxErrorMessageSize, "impl error"); - std::char_traits::copy(buffer.data(), std::data(msg), std::size(msg)); - buffer[std::size(msg)] = '\0'; - } - - throw std::runtime_error(buffer.data()); -} - -inline void log_location_impl(const char* file_name, - std::uint32_t line, - const char* function_name) noexcept { - printf("%s:%u: %s\n", file_name, line, function_name); -} - -inline void log_message_impl(const char* file_name, - std::uint32_t line, - const char* function_name, - const char* message) noexcept { - printf("%s:%u: %s:\n %s\n", file_name, line, function_name, message); -} - -inline void log_message_impl(const char* file_name, - std::uint32_t line, - const char* function_name, - std::string_view message) noexcept { - const auto message_size = static_cast(message.size()); - printf("%s:%u: %s:\n %.*s\n", file_name, line, function_name, message_size, message.data()); -} - -} // namespace test_tools_detail - -#if defined(TEST_TOOLS_HAS_SOURCE_LOCATION) - -inline void throw_if_not(bool expr, - const char* message_format, - const std::source_location src = std::source_location::current()) { - if (unlikely(!expr)) { - ::test_tools::test_tools_detail::throw_impl(message_format, src.file_name(), src.line(), - src.function_name()); - } -} - -ATTRIBUTE_ALWAYS_INLINE inline void log_tests_started( - const std::source_location src = std::source_location::current()) noexcept { - int ret = printf("Started tests in %s\n", src.function_name()); - assert(ret > 0); - ret = fflush(stdout); - assert(ret == 0); -} - -ATTRIBUTE_ALWAYS_INLINE inline void log_location( - const std::source_location src = std::source_location::current()) noexcept { - ::test_tools::test_tools_detail::log_location_impl(src.file_name(), src.line(), - src.function_name()); -} - -ATTRIBUTE_ALWAYS_INLINE inline void log_message( - const char* message, - const std::source_location src = std::source_location::current()) noexcept { - ::test_tools::test_tools_detail::log_message_impl(src.file_name(), src.line(), - src.function_name(), message); -} - -ATTRIBUTE_ALWAYS_INLINE inline void log_message( - std::string_view message, - const std::source_location src = std::source_location::current()) noexcept { - ::test_tools::test_tools_detail::log_message_impl(src.file_name(), src.line(), - src.function_name(), message); -} - -#else - -namespace test_tools_detail { - -inline void throw_if_not_impl(bool expr, - const char* message_format, - const char* file_name, - std::uint32_t line, - const char* function_name) { - if (unlikely(!expr)) { - ::test_tools::test_tools_detail::throw_impl(message_format, file_name, line, function_name); - } -} - -} // namespace test_tools_detail - -#define throw_if_not(expr, message_format) \ - ::test_tools::test_tools_detail::throw_if_not_impl(expr, message_format, __FILE__, __LINE__, \ - FUNCTION_MACRO) - -namespace test_tools_detail { - -ATTRIBUTE_ALWAYS_INLINE inline void log_tests_started_impl(const char* function_name) noexcept { - printf("Started tests in %s\n", function_name); -} - -} // namespace test_tools_detail - -#define log_tests_started() test_tools_detail::log_tests_started_impl(FUNCTION_MACRO) - -#define log_location() test_tools_detail::log_location_impl(__FILE__, __LINE__, FUNCTION_MACRO) - -#define log_message(message) \ - test_tools_detail::log_message_impl(__FILE__, __LINE__, FUNCTION_MACRO, message); - -#endif - -struct FilePtr final { - using FileHandle = std::FILE*; - FileHandle const file; // NOLINT(misc-misplaced-const) - - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - [[nodiscard]] /* implicit */ constexpr operator FileHandle() noexcept { - return file; - } - - FilePtr(const char* fname, const char* mode) : file(DoFOpenOrThrow(fname, mode)) {} - FilePtr(const FilePtr&) = delete; - FilePtr(FilePtr&&) = delete; - FilePtr& operator=(const FilePtr&) = delete; - FilePtr& operator=(FilePtr&&) = delete; - ~FilePtr() { - if (std::fclose(file) != 0) { - std::perror("fclose"); - } - } - -private: - ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") - ATTRIBUTE_RETURNS_NONNULL - ATTRIBUTE_ALWAYS_INLINE - static FileHandle DoFOpenOrThrow(const char* fname, const char* mode) { - // NOLINTNEXTLINE(misc-misplaced-const, cppcoreguidelines-owning-memory) - FileHandle const file_handle = std::fopen(fname, mode); - if (unlikely(file_handle == nullptr)) { - ThrowOnFOpenFail(fname, mode); - } - - return file_handle; - } - [[noreturn]] ATTRIBUTE_COLD static void ThrowOnFOpenFail(const char* fname, const char* mode) { - constexpr std::size_t kMaxErrorMessageSize = 1024 * sizeof(char); - const auto errno_value = errno; - std::array buffer{}; - const int bytes_written = std::snprintf( - buffer.data(), buffer.size(), - "FilePtr::FilePtr(const char* fname, const char* mode): " - "std::fopen(\"%s\", \"%s\") failed: %s", - fname, mode, std::strerror(errno_value)); // NOLINT(concurrency-mt-unsafe) - if (unlikely(bytes_written < 0)) { -#if defined(__cpp_lib_to_array) && __cpp_lib_to_array >= 201907L - constexpr std::array msg = std::to_array( - "FilePtr::FilePtr(const char* fname,const char* mode): std::snprintf failed after " - "std::fopen failed"); -#else - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - constexpr char msg[] = - "FilePtr::FilePtr(const char* fname,const char* mode): std::snprintf failed after " - "std::fopen failed"; -#endif - static_assert(std::size(msg) < kMaxErrorMessageSize, "impl error"); - std::char_traits::copy(buffer.data(), std::data(msg), std::size(msg)); - buffer[std::size(msg)] = '\0'; - } - - throw std::runtime_error(buffer.data()); - } -}; - -namespace test_tools_detail { - -ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") -TEST_TOOLS_CONSTEVAL std::size_t get_typename_end_pos_impl(const std::string_view s) { - // Variables are not inside of the for init for - // the compatibility with C++17. - std::size_t opened_square_brackets = 0; - std::size_t opened_round_brackets = 0; - std::size_t opened_curly_brackets = 0; - std::size_t opened_triangle_brackets = 0; - std::size_t i = 0; - for (const char c : s) { - switch (static_cast(c)) { - case '(': { - opened_round_brackets++; - break; - } - case ')': { - if (opened_round_brackets == 0) { - return i; - } - opened_round_brackets--; - break; - } - case '{': { - opened_curly_brackets++; - break; - } - case '}': { - if (opened_round_brackets == 0) { - return i; - } - opened_round_brackets--; - break; - } - case '[': { - opened_square_brackets++; - break; - } - case ']': { - if (opened_square_brackets == 0) { - return i; - } - opened_square_brackets--; - break; - } - case '<': { - opened_triangle_brackets++; - break; - } - case '>': { - if (opened_triangle_brackets == 0) { - return i; - } - opened_triangle_brackets--; - break; - } - case ',': - case ';': { - if (opened_square_brackets == 0 && opened_round_brackets == 0 && - opened_curly_brackets == 0 && opened_triangle_brackets == 0) { - return i; - } - break; - } - default: - break; - } - - i++; - } - - return s.size(); -} - -#define CONSTEVAL_ASSERT_CONCAT_IMPL(arg1, arg2, arg3) arg1##arg2##arg3 -#define CONSTEVAL_ASSERT_CONCAT(arg1, arg2, arg3) CONSTEVAL_ASSERT_CONCAT_IMPL(arg1, arg2, arg3) -#define CONSTEVAL_ASSERT_GENERATE_UNIQUE_NAME(prefix) \ - CONSTEVAL_ASSERT_CONCAT(prefix, _unique_addendum_, __COUNTER__) - -#if CONFIG_GNUC_AT_LEAST(12, 1) || defined(__clang__) -#define CONSTEVAL_ASSERT(expr) \ - do { \ - [[maybe_unused]] const int CONSTEVAL_ASSERT_GENERATE_UNIQUE_NAME(guard) = \ - bool{(expr)} ? 0 : throw std::runtime_error("consteval guard"); \ - } while (false) -#else -#define CONSTEVAL_ASSERT(expr) \ - do { \ - ATTRIBUTE_MAYBE_UNUSED const int CONSTEVAL_ASSERT_GENERATE_UNIQUE_NAME(guard) = \ - static_cast(expr) ? 0 : throw 0; \ - } while (false) -#endif - -ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") -TEST_TOOLS_CONSTEVAL -std::string_view extract_typename_impl( - const std::string_view function_name ATTRIBUTE_LIFETIME_BOUND) { - const auto is_space = [](char c) constexpr noexcept { - switch (static_cast(c)) { - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - return true; - default: - return false; - } - }; - -#if defined(__GNUG__) || defined(__clang__) - constexpr std::string_view type_prefix = "T = "; - const auto prefix_start_pos = function_name.find(type_prefix); - CONSTEVAL_ASSERT(prefix_start_pos != std::string_view::npos); - auto typename_start_pos = prefix_start_pos + type_prefix.size(); -#elif defined(_MSC_VER) - constexpr std::string_view type_prefix = "get_typename<"; - const auto prefix_start_pos = function_name.find(type_prefix); - CONSTEVAL_ASSERT(prefix_start_pos != std::string_view::npos); - auto typename_start_pos = prefix_start_pos + type_prefix.size(); - CONSTEVAL_ASSERT(typename_start_pos < function_name.size()); - std::string_view piece = function_name.substr(typename_start_pos); - constexpr std::string_view kKeywords[] = { - "class", - "struct", - "enum", - "union", - }; - for (bool continue_cut = true; continue_cut;) { - continue_cut = false; - while (is_space(piece.front())) { - piece.remove_prefix(1); - typename_start_pos++; - } - for (const auto keyword : kKeywords) { -#if CONFIG_HAS_AT_LEAST_CXX_20 - if (piece.starts_with(keyword)) -#else - if (keyword.size() <= piece.size() && keyword == piece.substr(0, keyword.size())) -#endif - { - piece.remove_prefix(keyword.size()); - typename_start_pos += keyword.size(); - continue_cut = true; - break; - } - } - } - -#else -// cppcheck-suppress [preprocessorErrorDirective] -#error("Unsupported compiler") -#endif - - CONSTEVAL_ASSERT(typename_start_pos < function_name.size()); - while (is_space(function_name[typename_start_pos])) { - typename_start_pos++; - } - CONSTEVAL_ASSERT(typename_start_pos < function_name.size()); - const auto typename_end_pos = - typename_start_pos + get_typename_end_pos_impl(function_name.substr(typename_start_pos)); - CONSTEVAL_ASSERT(typename_end_pos < function_name.size()); - CONSTEVAL_ASSERT(typename_start_pos < typename_end_pos); - return function_name.substr(typename_start_pos, typename_end_pos - typename_start_pos); -} - -template -ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") -TEST_TOOLS_CONSTEVAL std::string_view get_typename_impl() { - const std::string_view function_name = -#if defined(TEST_TOOLS_HAS_SOURCE_LOCATION) - std::source_location::current().function_name(); -#else - FUNCTION_MACRO; -#endif - - return ::test_tools::test_tools_detail::extract_typename_impl(function_name); -} - -} // namespace test_tools_detail - -template -ATTRIBUTE_NODISCARD_WITH_MESSAGE("requested name of the type should be used") -TEST_TOOLS_CONSTEVAL std::string_view get_typename() { - constexpr std::string_view kTypename = ::test_tools::test_tools_detail::get_typename_impl(); - return kTypename; -} - -namespace test_tools_detail { - -// clang-format off - -template -ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") -TEST_TOOLS_CONSTEVAL -std::string_view extract_enum_value_name_impl(const std::string_view function_name ATTRIBUTE_LIFETIME_BOUND) { - // clang-format on - - using std::string_view; - -#if defined(__GNUG__) || defined(__clang__) - constexpr string_view prefix = "EnumValue = "; -#elif defined(_MSC_VER) - constexpr string_view prefix = "get_enum_value_name<"; -#else -// cppcheck-suppress [preprocessorErrorDirective] -#error("Unsupported compiler") -#endif - - const auto prefix_start_pos = function_name.find(prefix); - CONSTEVAL_ASSERT(prefix_start_pos != string_view::npos); - auto value_start_pos = prefix_start_pos + prefix.size(); - CONSTEVAL_ASSERT(value_start_pos < function_name.size()); - const auto value_end_pos = - value_start_pos + get_typename_end_pos_impl(function_name.substr(value_start_pos)); - CONSTEVAL_ASSERT(value_start_pos < value_end_pos); - CONSTEVAL_ASSERT(value_end_pos < function_name.size()); - std::string_view full_name = - function_name.substr(value_start_pos, value_end_pos - value_start_pos); - constexpr std::string_view kScopeResolutionOperator = "::"; - if (const auto scope_res_operator_pos = full_name.rfind(kScopeResolutionOperator); - scope_res_operator_pos != std::string_view::npos) { - full_name = full_name.substr(scope_res_operator_pos + kScopeResolutionOperator.size()); - } - return full_name; -} - -template -ATTRIBUTE_NODISCARD_WITH_MESSAGE("impl error") -TEST_TOOLS_CONSTEVAL std::string_view get_enum_value_name_impl() { - const std::string_view function_name = -#if defined(TEST_TOOLS_HAS_SOURCE_LOCATION) - std::source_location::current().function_name(); -#else - FUNCTION_MACRO; -#endif - return ::test_tools::test_tools_detail::extract_enum_value_name_impl( - function_name); -} - -#undef CONSTEVAL_ASSERT -#undef CONSTEVAL_ASSERT_GENERATE_UNIQUE_NAME -#undef CONSTEVAL_ASSERT_CONCAT -#undef CONSTEVAL_ASSERT_CONCAT_IMPL - -} // namespace test_tools_detail - -template -ATTRIBUTE_NODISCARD_WITH_MESSAGE("requested name of the enum value should be used") -TEST_TOOLS_CONSTEVAL std::string_view get_enum_value_name() { - using EnumType = decltype(EnumValue); - static_assert(std::is_enum_v, "Value of the enum is expected"); - - constexpr std::string_view kEnumValueName = - ::test_tools::test_tools_detail::get_enum_value_name_impl(); - return kEnumValueName; -} - -template -struct EchoLogger { - // NOLINTBEGIN(cert-oop54-cpp) - - EchoLogger() { - ::test_tools::log_location(); - } - EchoLogger(const EchoLogger& /*unused*/) noexcept { - ::test_tools::log_location(); - } - EchoLogger(EchoLogger&& /*unused*/) noexcept { - ::test_tools::log_location(); - } - EchoLogger& operator=(const EchoLogger& /*unused*/) noexcept { - ::test_tools::log_location(); - return *this; - } - EchoLogger& operator=(EchoLogger&& /*unused*/) noexcept { - ::test_tools::log_location(); - return *this; - } - ~EchoLogger() { - ::test_tools::log_location(); - } - - // NOLINTEND(cert-oop54-cpp) -}; - -} // namespace test_tools - -// NOLINTEND(cppcoreguidelines-macro-usage) - -#undef TEST_TOOLS_CONSTEVAL -#if defined(TEST_TOOLS_HAS_SOURCE_LOCATION) -#undef TEST_TOOLS_HAS_SOURCE_LOCATION -#endif diff --git a/run_clang_format.sh b/run_clang_format.sh index d0405b0..87bdc9d 100755 --- a/run_clang_format.sh +++ b/run_clang_format.sh @@ -1,9 +1,11 @@ -#!/usr/bin/env bash +#! /usr/bin/env bash clang-format -i \ ./number_theory/*.hpp ./number_theory/*.cpp \ ./tf_idf_actrie/*.hpp ./tf_idf_actrie/*.cpp \ ./graphs/HungarianAlgorithm/*.hpp ./graphs/HungarianAlgorithm/*.cpp \ ./string-switch-map/*.cpp ./string-switch-map/*.hpp ./string-switch-map/tests/*.cpp \ + ./vec_instructs/*.h ./vec_instructs/*.c ./vec_instructs/*.cpp \ + ./misc/*.hpp ./misc/*.cpp \ ./bstrees/*.cpp ./bstrees/*.cppm \ -style=file:./.clang-format diff --git a/string-switch-map/StringMap.hpp b/string-switch-map/StringMap.hpp index 11bc9b1..00729d4 100644 --- a/string-switch-map/StringMap.hpp +++ b/string-switch-map/StringMap.hpp @@ -10,7 +10,7 @@ #include #include -#include "../number_theory/config_macros.hpp" +#include "../misc/config_macros.hpp" #if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L && CONFIG_HAS_INCLUDE() #define STRING_MAP_HAS_SPAN diff --git a/string-switch-map/tests/test_string_switch_map.cpp b/string-switch-map/tests/test_string_switch_map.cpp index 08fc744..5ab280b 100644 --- a/string-switch-map/tests/test_string_switch_map.cpp +++ b/string-switch-map/tests/test_string_switch_map.cpp @@ -9,7 +9,7 @@ #include #include -#include "../../number_theory/config_macros.hpp" +#include "../../misc/config_macros.hpp" #include "../StringMap.hpp" // clang-format off diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index df7d8f3..ad8773f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -206,6 +206,30 @@ if (GENERATOR_SUPPORTS_MODULES AND COMPILER_SUPPORTS_MODULES) add_test(NAME rbtree_tests COMMAND $) endif() +list(APPEND TestFilenames "test_dsu.cpp") +list(APPEND TestDirectories "DisjointSetUnion") +list(APPEND TestLangVersions "17 20 23 26") +list(APPEND TestDependencies "") +list(APPEND TestOptionalDependencies "") +list(APPEND TestIsCProject False) +list(APPEND TestCompileOnly False) + +list(APPEND TestFilenames "test_get_typename.cpp") +list(APPEND TestDirectories "misc") +list(APPEND TestLangVersions "17 20 23 26") +list(APPEND TestDependencies "") +list(APPEND TestOptionalDependencies "") +list(APPEND TestIsCProject False) +list(APPEND TestCompileOnly False) + +list(APPEND TestFilenames "test_join_strings.cpp") +list(APPEND TestDirectories "misc") +list(APPEND TestLangVersions "17 20 23 26") +list(APPEND TestDependencies "") +list(APPEND TestOptionalDependencies "") +list(APPEND TestIsCProject False) +list(APPEND TestCompileOnly False) + list(POP_FRONT TestFilenames) # pop dummy list(POP_FRONT TestDirectories) # pop dummy list(POP_FRONT TestLangVersions) # pop dummy diff --git a/vec_instructs/measure_memset_int.c b/vec_instructs/measure_memset_int.c index 6c3fb8f..e1fabe9 100644 --- a/vec_instructs/measure_memset_int.c +++ b/vec_instructs/measure_memset_int.c @@ -8,7 +8,7 @@ #include #include -#include "config_macros.hpp" +#include "../misc/config_macros.hpp" #include "memset_int.h" const size_t kTests = 32; diff --git a/vec_instructs/memcount.h b/vec_instructs/memcount.h index 107066c..010c2b4 100644 --- a/vec_instructs/memcount.h +++ b/vec_instructs/memcount.h @@ -14,7 +14,7 @@ EXTERN_WITH_C_LINKAGE_BEGIN #include EXTERN_WITH_C_LINKAGE_END -#include "../number_theory/config_macros.hpp" +#include "../misc/config_macros.hpp" EXTERN_WITH_C_LINKAGE_BEGIN @@ -25,7 +25,8 @@ EXTERN_WITH_C_LINKAGE_BEGIN ATTRIBUTE_TARGET("popcnt,avx,avx2") MEMCOUNT_ATTRIBUTES -static inline size_t memcount_avx(const uint8_t* const src, const uint8_t chr, +static inline size_t memcount_avx(const uint8_t* const src, + const uint8_t chr, size_t size) CONFIG_NOEXCEPT_FUNCTION { #if defined(__cplusplus) #if defined(__clang__) @@ -81,7 +82,8 @@ static inline size_t memcount_avx(const uint8_t* const src, const uint8_t chr, } MEMCOUNT_ATTRIBUTES -static inline size_t memcount_default(const uint8_t* const src, const uint8_t chr, +static inline size_t memcount_default(const uint8_t* const src, + const uint8_t chr, size_t size) CONFIG_NOEXCEPT_FUNCTION { size_t cnt = 0; const uint32_t c = chr; @@ -149,7 +151,8 @@ __attribute__((constructor)) static inline void memcount_initializer(void) MEMCOUNT_ATTRIBUTES ATTRIBUTE_ALWAYS_INLINE -static inline size_t memcount(const uint8_t* const src, const uint8_t chr, +static inline size_t memcount(const uint8_t* const src, + const uint8_t chr, size_t size) CONFIG_NOEXCEPT_FUNCTION { return memcount_default(src, chr, size); } diff --git a/vec_instructs/memset_int.h b/vec_instructs/memset_int.h index 4537c3d..9027462 100644 --- a/vec_instructs/memset_int.h +++ b/vec_instructs/memset_int.h @@ -14,7 +14,7 @@ EXTERN_WITH_C_LINKAGE_BEGIN #include EXTERN_WITH_C_LINKAGE_END -#include "../number_theory/config_macros.hpp" +#include "../misc/config_macros.hpp" EXTERN_WITH_C_LINKAGE_BEGIN @@ -32,7 +32,8 @@ EXTERN_WITH_C_LINKAGE_BEGIN MEMSET_INT_FUNC_ATTRIBUTES ATTRIBUTE_TARGET("avx") -static inline void memset_int_avx(int32_t* dst, int32_t value, +static inline void memset_int_avx(int32_t* dst, + int32_t value, size_t size) CONFIG_NOEXCEPT_FUNCTION { uint32_t* aligned_4_address = (uint32_t*)dst; __m256i* aligned_32_address = (__m256i*)(((uintptr_t)aligned_4_address + 31) & ~(uintptr_t)31); @@ -81,7 +82,8 @@ static inline void memset_int_avx(int32_t* dst, int32_t value, } MEMSET_INT_FUNC_ATTRIBUTES -static inline void memset_int_default(int32_t* dst, int32_t value, +static inline void memset_int_default(int32_t* dst, + int32_t value, size_t size) CONFIG_NOEXCEPT_FUNCTION { while (size >= 4) { dst[0] = value;