[libcxx-commits] [libcxx] [libc++] Optimize ranges::{for_each, for_each_n} for segmented iterators (PR #132896)

Peng Liu via libcxx-commits libcxx-commits at lists.llvm.org
Thu Apr 3 09:48:05 PDT 2025


================
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_FOR_EACH_N_SEGMENT_H
+#define _LIBCPP___ALGORITHM_FOR_EACH_N_SEGMENT_H
+
+#include <__config>
+#include <__iterator/distance.h>
+#include <__iterator/next.h>
+#include <__iterator/segmented_iterator.h>
+#include <__utility/convert_to_integral.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// __for_each_n_segment optimizes linear iteration over segmented iterators. It processes a segmented
+// input range defined by (__first, __orig_n), where __first is the starting segmented iterator and
+// __orig_n is the number of elements to process. The functor __func is applied to each segment using
+// local iterator pairs for that segment. The return value of __func is ignored, and the function
+// returns an iterator pointing to one past the last processed element in the input range.
+
+template <class _SegmentedIterator, class _Size, class _Functor>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator
+__for_each_n_segment(_SegmentedIterator __first, _Size __orig_n, _Functor __func) {
+  if (__orig_n == 0)
+    return __first;
+
+  using _Traits = __segmented_iterator_traits<_SegmentedIterator>;
+  typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize;
+  _IntegralSize __n = __orig_n;
+  auto __seg        = _Traits::__segment(__first);
+  auto __sfirst     = _Traits::__begin(__seg);
+  auto __slast      = _Traits::__end(__seg);
+  auto __lfirst     = _Traits::__local(__first);
+  auto __seg_size   = static_cast<_IntegralSize>(std::distance(__lfirst, __slast));
+
+  // Single-segment case: input range fits within a single segment (may not align with segment boundaries)
----------------
winner245 wrote:

Thank you for your suggestion! I agree that the current implementation might not be in its most ideal form. However, we are dealing with multiple corner cases here—such as single-segment vs. multi-segment, partial first and/or last segments, and combinations of these scenarios. Considering these complexities, I found it challenging to further simplify the logic.

While it might be possible to reduce a few lines of code, I am concerned that doing so could compromise clarity. After several attempts, I wasn't able to come up with a refactoring that I feel is an improvement over the current approach.

https://github.com/llvm/llvm-project/pull/132896


More information about the libcxx-commits mailing list