diff --git a/cth/CMakeLists.txt b/cth/CMakeLists.txt index adb41cc..3c69052 100644 --- a/cth/CMakeLists.txt +++ b/cth/CMakeLists.txt @@ -15,6 +15,11 @@ target_compile_options(cth INTERFACE $<$:/Zc:preprocessor> cth_pkg_target_find_package(cth boost_pfr CONFIG REQUIRED) target_link_libraries(cth INTERFACE Boost::pfr) +# cth/data/hash_map.hpp includes gtl/phmap.hpp, gtl installs no cmake package +cth_pkg_add_find_modules(cmake/Findgtl.cmake) +cth_pkg_target_find_package(cth gtl MODULE REQUIRED) +target_link_libraries(cth INTERFACE gtl::gtl) + target_link_libraries(cth INTERFACE $<$,$>>:stdc++exp>) # tests diff --git a/cth/cmake/Findgtl.cmake b/cth/cmake/Findgtl.cmake new file mode 100644 index 0000000..f1b5900 --- /dev/null +++ b/cth/cmake/Findgtl.cmake @@ -0,0 +1,12 @@ +# gtl installs only its headers and no cmake package, this module creates the target gtl::gtl +include(FindPackageHandleStandardArgs) + +find_path(gtl_INCLUDE_DIR gtl/phmap.hpp) +find_package_handle_standard_args(gtl REQUIRED_VARS gtl_INCLUDE_DIR) + +if(gtl_FOUND AND NOT TARGET gtl::gtl) + add_library(gtl::gtl INTERFACE IMPORTED) + target_include_directories(gtl::gtl SYSTEM INTERFACE "${gtl_INCLUDE_DIR}") +endif() + +mark_as_advanced(gtl_INCLUDE_DIR) diff --git a/cth/incl/cth/algorithm/combine.hpp b/cth/incl/cth/algorithm/combine.hpp index fbc33a6..0a168d0 100644 --- a/cth/incl/cth/algorithm/combine.hpp +++ b/cth/incl/cth/algorithm/combine.hpp @@ -1,4 +1,5 @@ #pragma once +#include "cth/data/hash_map.hpp" #include "cth/io/log.hpp" #include "cth/meta/ranges.hpp" @@ -9,7 +10,6 @@ #include #include #include -#include #include #include @@ -26,7 +26,7 @@ template Rng> [[nodiscard]] auto unique_combine(Rng const& selections) { using T = std::remove_cvref_t>; using node_t = T const*; - using node_selection_map_t = std::unordered_map; + using node_selection_map_t = dt::flat_hash_map; static constexpr node_t EMPTY_NODE = nullptr; auto const selectionCount = std::ranges::size(selections); diff --git a/cth/incl/cth/data/hash_map.hpp b/cth/incl/cth/data/hash_map.hpp new file mode 100644 index 0000000..632cf6c --- /dev/null +++ b/cth/incl/cth/data/hash_map.hpp @@ -0,0 +1,16 @@ +#pragma once +#include + +namespace cth::dt { +/** + * @brief hash map without pointer stability, a rehash moves the elements + */ +template +using flat_hash_map = gtl::flat_hash_map; + +/** + * @brief hash set without pointer stability, a rehash moves the elements + */ +template +using flat_hash_set = gtl::flat_hash_set; +} diff --git a/cth/incl/cth/data/pool.hpp b/cth/incl/cth/data/pool.hpp index 637a077..bdfb460 100644 --- a/cth/incl/cth/data/pool.hpp +++ b/cth/incl/cth/data/pool.hpp @@ -1,4 +1,5 @@ #pragma once +#include "cth/data/hash_map.hpp" #include "cth/io/log.hpp" #include "cth/meta/concepts.hpp" @@ -7,7 +8,6 @@ #include #include #include -#include #include namespace cth::dt { @@ -113,7 +113,7 @@ class pool { private: void resetActive() { if constexpr(HAS_RESET) { - std::unordered_set inactiveSet{std::from_range, _inactive}; + flat_hash_set const inactiveSet{_inactive.begin(), _inactive.end()}; for(auto& stored : _storage) if(!inactiveSet.contains(&stored)) diff --git a/cth/incl/cth/data/thread_pool.hpp b/cth/incl/cth/data/thread_pool.hpp index 1442b1a..24a9af2 100644 --- a/cth/incl/cth/data/thread_pool.hpp +++ b/cth/incl/cth/data/thread_pool.hpp @@ -1,10 +1,10 @@ #pragma once +#include "cth/data/hash_map.hpp" #include "cth/data/pool.hpp" #include #include #include -#include namespace cth::dt { @@ -91,7 +91,7 @@ class thread_pool { private: mutable std::mutex _mtx; pool_t _pool; - std::unordered_map _bound{}; + flat_hash_map _bound{}; public: /** total number of instances in the pool */ diff --git a/cth/incl/cth/data/union_find.hpp b/cth/incl/cth/data/union_find.hpp index 91ff5c4..2bf96eb 100644 --- a/cth/incl/cth/data/union_find.hpp +++ b/cth/incl/cth/data/union_find.hpp @@ -2,8 +2,8 @@ #include "cth/data/poly_vector.hpp" #include -#include -#include +#include +#include namespace cth::dt { /** @@ -162,14 +162,16 @@ class union_find { [[nodiscard]] constexpr std::vector all() { std::vector result{}; - std::unordered_map groups{}; + // group of each root, the roots are indices + constexpr size_t NO_GROUP = std::numeric_limits::max(); + std::vector groups(size(), NO_GROUP); for(index_type idx = 0; idx < size(); idx++) { - auto const parent = find(idx); - if(auto groupIt = groups.find(parent); groupIt != groups.end()) - result[groupIt->second].emplace_back(idx); + auto& group = groups[find(idx)]; + if(group != NO_GROUP) + result[group].emplace_back(idx); else { - groups[parent] = result.size(); + group = result.size(); result.emplace_back(1)[0] = idx; } } diff --git a/cth/tests/src/data/thread_pool_test.cpp b/cth/tests/src/data/thread_pool_test.cpp index 421938e..6a80648 100644 --- a/cth/tests/src/data/thread_pool_test.cpp +++ b/cth/tests/src/data/thread_pool_test.cpp @@ -1,5 +1,6 @@ #include "cth/data/thread_pool.hpp" #include "cth/constants.hpp" +#include "cth/data/hash_map.hpp" #include "test.hpp" #include @@ -7,7 +8,6 @@ #include #include #include -#include #include @@ -157,7 +157,7 @@ DATA_TEST(thread_pool, distinct_ids_get_distinct_resources) { EXPECT_TRUE(tp.exhausted()); // three owners hold three distinct resources - std::unordered_set refs{&a, &b, &c}; + cth::dt::flat_hash_set refs{&a, &b, &c}; EXPECT_EQ(refs.size(), 3); } @@ -292,7 +292,7 @@ DATA_TEST(thread_pool, concurrent_acquire_gives_each_thread_a_distinct_resource) EXPECT_TRUE(tp.exhausted()); // every thread received a distinct resource, none null - std::unordered_set unique{acquired.begin(), acquired.end()}; + cth::dt::flat_hash_set unique{acquired.begin(), acquired.end()}; EXPECT_EQ(unique.size(), THREADS); EXPECT_FALSE(unique.contains(nullptr)); } diff --git a/cth_net/src/websocket_server.cpp b/cth_net/src/websocket_server.cpp index 0b68e50..4181504 100644 --- a/cth_net/src/websocket_server.cpp +++ b/cth_net/src/websocket_server.cpp @@ -3,13 +3,14 @@ #include "cth/net/exception.hpp" #include "websocket_connection_state.hpp" +#include "cth/data/hash_map.hpp" + #include #include #include #include #include -#include #include #include @@ -22,7 +23,7 @@ struct websocket_server::impl { std::uint16_t boundPort{}; mutable std::mutex mutex; - std::unordered_map> + dt::flat_hash_map> connections; std::deque> accepted; os::fence readyFence; diff --git a/lib/cth_cmake b/lib/cth_cmake index 09a6c5d..79a6191 160000 --- a/lib/cth_cmake +++ b/lib/cth_cmake @@ -1 +1 @@ -Subproject commit 09a6c5d02421cba58fcf33bc3e4fd3d4fb646002 +Subproject commit 79a619176696cebe86d5d56059681f369a8b50e6 diff --git a/vcpkg.json b/vcpkg.json index cb8f175..c7df85b 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -6,6 +6,7 @@ "boost-pfr", "glm", "gtest", + "gtl", "stb", "asio", "libhv"