[libcxx-commits] [libcxx] [libc++] Optimize {std, ranges}::distance for segmented iterators (PR #133612)

Peng Liu via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 27 15:09:51 PDT 2025


================
@@ -10,41 +10,82 @@
 #ifndef _LIBCPP___ITERATOR_DISTANCE_H
 #define _LIBCPP___ITERATOR_DISTANCE_H
 
+#include <__algorithm/for_each_segment.h>
 #include <__config>
 #include <__iterator/concepts.h>
 #include <__iterator/incrementable_traits.h>
 #include <__iterator/iterator_traits.h>
+#include <__iterator/segmented_iterator.h>
 #include <__ranges/access.h>
 #include <__ranges/concepts.h>
 #include <__ranges/size.h>
 #include <__type_traits/decay.h>
+#include <__type_traits/enable_if.h>
 #include <__type_traits/remove_cvref.h>
+#include <__utility/move.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _InputIter>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 typename iterator_traits<_InputIter>::difference_type
-__distance(_InputIter __first, _InputIter __last, input_iterator_tag) {
-  typename iterator_traits<_InputIter>::difference_type __r(0);
+#if _LIBCPP_STD_VER >= 20
+template <class _Iter>
+using __iter_distance_t _LIBCPP_NODEBUG = std::iter_difference_t<_Iter>;
----------------
winner245 wrote:

> I am now consistently using `iterator_traits<I>::difference_type` as the return type for the non-range `std::__distance` algorithm.

However, this approach fails when the range algorithm `std::ranges::distance` forwards to `std::__distance` with `I = cpp20_input_iterator`, resulting in a hard substitution error: `no type named 'difference_type' in 'std::iterator_traits<cpp20_input_iterator<int *>>'`, as captured by the tests `range.pass.cpp` and `iterator_sentinel.pass.cpp` (see the full log: [stage1 (generic-modules, clang-21, clang++-21)](https://github.com/llvm/llvm-project/actions/runs/15912723755/job/44883824080?pr=133612#logs)).

The root cause for this error is that `cpp20_input_iterator` does not have the member type `iterator_category` (although it provides the `iterator_concept` member type), leading to a hard substitution failure in `std::iterator_traits<cpp20_input_iterator<Iter>>::difference_type` (See [A reproducer](https://godbolt.org/z/sdxevGM5z)). 

To resolve this, I still need the above internal definition of `__iter_distance_t`, which is used as the return type of the internal function `std::__distance`. This allows both the non-range `std::distance` and range version `std::ranges::distance` to share the same implementation and optimization. However, to handle the potential mismatch between `iterator_traits<I>::difference_type` and `iter_difference_t<I>`, I explicitly specified `iterator_traits<I>::difference_type` as the return type of `std::distance` and `iter_difference_t<I>` as the return type of `std::ranges::distance`. This way the underlying implicit conversion would automatically take place when there is a type mismatch. 

> Basically, we should try re-defining `__iter_diff_t` in `iterator_traits.h` as:
> 
> ```c++
> #if _LIBCPP_STD_VER >= 20
> template <class _Iter>
> using __iter_diff_t _LIBCPP_NODEBUG = std::iter_difference_t<_Iter>;
> #else
> template <class _Iter>
> using __iter_diff_t _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::difference_type;
> #endif
> ```
>
> And if that's not possible for some reason, it would be interesting to understand why.

I am a bit hesitant to make this change because `__iter_diff_t` is currently **unconditionally** defined as `iterator_traits<_Iter>::difference_type`, and it is used by many algorithms. Making this change would introduce the potential type mismatch to many algorithms. My current approach with the introduction of `__iter_distance_t` ensures that the potential type mismatch is confined and handled within `distance.h`. 

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


More information about the libcxx-commits mailing list