From 945a193fcd15edaf83956bfad2f6a9a149fda6bb Mon Sep 17 00:00:00 2001 From: Mark Santaniello <marksan@meta.com> Date: Sat, 25 May 2024 01:30:00 -0700 Subject: [PATCH] Introduce reserve_if_available Summary: This is useful when writing generic code that handles containers. Some examples: - std::unordered_map provides reserve(), but std::map does not - std::vector provides reserve(), but std::deque and std::list do not Reviewed By: yfeldblum Differential Revision: D57718859 fbshipit-source-id: 9cb146b2950746e416c938b0cc6484715f58bb69 --- folly/container/Reserve.h | 29 ++++++++++++++++++++++++++++ folly/container/test/ReserveTest.cpp | 14 ++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/folly/container/Reserve.h b/folly/container/Reserve.h index 5681086dc14..77a235ecbb9 100644 --- a/folly/container/Reserve.h +++ b/folly/container/Reserve.h @@ -36,6 +36,13 @@ using detect_bucket_count = decltype(FOLLY_DECLVAL(C).bucket_count()); template <typename C> using detect_max_load_factor = decltype(FOLLY_DECLVAL(C).max_load_factor()); +template <typename C, typename... A> +using detect_reserve = decltype(FOLLY_DECLVAL(C).reserve(FOLLY_DECLVAL(A)...)); + +template <typename C> +using container_detect_reserve = + detect_reserve<C, typename remove_cvref_t<C>::size_type>; + } // namespace detail /** @@ -78,4 +85,26 @@ struct grow_capacity_by_fn { inline constexpr grow_capacity_by_fn grow_capacity_by{}; +/** + * Useful when writing generic code that handles containers. + * + * Examples: + * - std::unordered_map provides reserve(), but std::map does not + * - std::vector provides reserve(), but std::deque and std::list do not + */ +struct reserve_if_available_fn { + template <typename C> + auto operator()(C& c, typename C::size_type const n) const + noexcept(!folly::is_detected_v<detail::container_detect_reserve, C&>) { + constexpr auto match = + folly::is_detected_v<detail::container_detect_reserve, C&>; + if constexpr (match) { + c.reserve(n); + } + return std::bool_constant<match>{}; + } +}; + +inline constexpr reserve_if_available_fn reserve_if_available{}; + } // namespace folly diff --git a/folly/container/test/ReserveTest.cpp b/folly/container/test/ReserveTest.cpp index 8273a8bca7c..a474e7caecd 100644 --- a/folly/container/test/ReserveTest.cpp +++ b/folly/container/test/ReserveTest.cpp @@ -16,6 +16,7 @@ #include <folly/container/Reserve.h> +#include <list> #include <memory> #include <unordered_map> #include <vector> @@ -157,3 +158,16 @@ TEST(ReserveUtil, F14NodeMapGrowBy) { TEST(ReserveUtil, UnorderedMapGrowBy) { testMapGrowBy<unordered_map>(); } + +TEST(ReserveUtil, ReserveIfAvailableVector) { + std::vector<int> v; + auto r = folly::reserve_if_available(v, 42); + static_assert(std::is_same_v<decltype(r), std::true_type>); + EXPECT_GE(v.capacity(), 42); +} + +TEST(ReserveUtil, ReserveIfAvailableList) { + std::list<int> l; + auto r = folly::reserve_if_available(l, 42); + static_assert(std::is_same_v<decltype(r), std::false_type>); +}