From 48a6bf4c854688a5372011a13fa0f7cbed6577b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 5 May 2026 10:19:30 +0200 Subject: [PATCH] Add BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS option --- .../experimental/segmented_count.hpp | 27 +++++++++++++++++++ .../experimental/segmented_count_if.hpp | 27 +++++++++++++++++++ .../segmented_iterator_traits.hpp | 20 +++++++++++++- 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/include/boost/container/experimental/segmented_count.hpp b/include/boost/container/experimental/segmented_count.hpp index fc07940..16f0be8 100644 --- a/include/boost/container/experimental/segmented_count.hpp +++ b/include/boost/container/experimental/segmented_count.hpp @@ -45,6 +45,16 @@ segmented_count_dispatch difference_type n = last - first; difference_type count = 0; while(n >= difference_type(4)) { + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + count += static_cast(*first == value); + ++first; + count += static_cast(*first == value); + ++first; + count += static_cast(*first == value); + ++first; + count += static_cast(*first == value); + ++first; + #else if(*first == value) ++count; ++first; if(*first == value) ++count; @@ -53,20 +63,33 @@ segmented_count_dispatch ++first; if(*first == value) ++count; ++first; + #endif n -= 4; } switch(n) { case 3: + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + count += static_cast(*first == value); + #else if(*first == value) ++count; + #endif ++first; BOOST_FALLTHROUGH; case 2: + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + count += static_cast(*first == value); + #else if(*first == value) ++count; + #endif ++first; BOOST_FALLTHROUGH; case 1: + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + count += static_cast(*first == value); + #else if(*first == value) ++count; + #endif ++first; BOOST_FALLTHROUGH; default: @@ -89,7 +112,11 @@ segmented_count_dispatch diff_t n = 0; for (; first != last; ++first) + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + n += static_cast(*first == value); + #else if (*first == value) ++n; + #endif return n; } diff --git a/include/boost/container/experimental/segmented_count_if.hpp b/include/boost/container/experimental/segmented_count_if.hpp index e4c6891..45ca816 100644 --- a/include/boost/container/experimental/segmented_count_if.hpp +++ b/include/boost/container/experimental/segmented_count_if.hpp @@ -44,6 +44,16 @@ segmented_count_if_dispatch difference_type n = last - first; difference_type count = 0; while(n >= difference_type(4)) { + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + count += static_cast(pred(*first)); + ++first; + count += static_cast(pred(*first)); + ++first; + count += static_cast(pred(*first)); + ++first; + count += static_cast(pred(*first)); + ++first; + #else if(pred(*first)) ++count; ++first; if(pred(*first)) ++count; @@ -52,20 +62,33 @@ segmented_count_if_dispatch ++first; if(pred(*first)) ++count; ++first; + #endif n -= 4; } switch(n) { case 3: + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + count += static_cast(pred(*first)); + #else if(pred(*first)) ++count; + #endif ++first; BOOST_FALLTHROUGH; case 2: + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + count += static_cast(pred(*first)); + #else if(pred(*first)) ++count; + #endif ++first; BOOST_FALLTHROUGH; case 1: + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + count += static_cast(pred(*first)); + #else if(pred(*first)) ++count; + #endif ++first; BOOST_FALLTHROUGH; default: @@ -87,7 +110,11 @@ segmented_count_if_dispatch diff_t n = 0; for (; first != last; ++first) + #if defined(BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS) + n += static_cast(pred(*first)); + #else if (pred(*first)) ++n; + #endif return n; } diff --git a/include/boost/container/experimental/segmented_iterator_traits.hpp b/include/boost/container/experimental/segmented_iterator_traits.hpp index 82de826..0ab0138 100644 --- a/include/boost/container/experimental/segmented_iterator_traits.hpp +++ b/include/boost/container/experimental/segmented_iterator_traits.hpp @@ -381,10 +381,28 @@ struct deepest_local_iterator //#define BOOST_CONTAINER_DISABLE_MULTI_SEGMENTED_ALGO +// When defined, segmented algorithms that have a dual random-access fast path +// (e.g. segmented_copy_if_dst_bounded) will not attempt to detect whether the +// remaining source range fits the destination capacity and will always take the +// fast path when both iterators are random-access. This is useful for benchmarking +// the advantage of the dual-RA optimisation in isolation. +// //#define BOOST_CONTAINER_SEGMENTED_DISABLE_DUAL_RA_OPTIMIZATION - #if !defined(BOOST_CONTAINER_SEGMENTED_DISABLE_DUAL_RA_OPTIMIZATION) #define BOOST_CONTAINER_SEGMENTED_ENABLE_DUAL_RA_OPTIMIZATION #endif +// When defined, segmented algorithms that count elements (e.g. segmented_count, +// segmented_count_if) will use a branchless counting strategy in their +// innermost loops, incrementing the count by the boolean result of the +// predicate rather than testing the predicate result in a branch and conditionally +// incrementing. This can improve performance on some platforms by avoiding branch mispredictions, +// at the cost of potentially increased instruction count and/or reduced vectorization opportunities. +// +// However, the optimal strategy is highly platform- and algorithm-specific, so this is disabled by default. +// There are regressions on some algorithms and platforms when this is enabled, and the performance impact +// varies widely across different scenarios. +// +//#define BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS + #endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_ITERATOR_TRAITS_HPP