diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -14,6 +14,7 @@ __hash_table __iterator/advance.h __iterator/concepts.h + __iterator/distance.h __iterator/incrementable_traits.h __iterator/iter_move.h __iterator/iterator_traits.h diff --git a/libcxx/include/__iterator/distance.h b/libcxx/include/__iterator/distance.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__iterator/distance.h @@ -0,0 +1,67 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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___ITERATOR_DISTANCE_H +#define _LIBCPP___ITERATOR_DISTANCE_H + +#include <__config> +#include <__function_like.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__ranges/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { +struct __distance_fn final : __function_like { + constexpr explicit __distance_fn(__tag __x) noexcept : __function_like(__x) {} + + template _Sp> + [[nodiscard]] constexpr iter_difference_t<_Ip> operator()(_Ip __first, _Sp __last) const { + if constexpr (sized_sentinel_for<_Sp, _Ip>) { + return __last - __first; + } + + auto __distance = iter_difference_t<_Ip>(0); + for (; __first != __last; ++__first) { + ++__distance; + } + + return __distance; + } + + template + [[nodiscard]] constexpr range_difference_t<_Rp> operator()(_Rp&& __r) const { + if constexpr (sized_range<_Rp>) { + return static_cast >(ranges::size(__r)); + } else { + return (*this)(ranges::begin(__r), ranges::end(__r)); + } + } +}; + +inline constexpr auto distance = __distance_fn(__function_like::__value); +} // namespace ranges + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_DISTANCE_H diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -485,6 +485,7 @@ #include <__functional_base> #include <__iterator/advance.h> #include <__iterator/concepts.h> +#include <__iterator/distance.h> #include <__iterator/incrementable_traits.h> #include <__iterator/iter_move.h> #include <__iterator/iterator_traits.h> diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.pass.cpp --- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.pass.cpp +++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.pass.cpp @@ -10,12 +10,178 @@ // UNSUPPORTED: libcpp-no-concepts // UNSUPPORTED: gcc-10 -// std::forward_iterator; +// std::ranges::distance #include -#include +#include +#include +#include +#include #include "test_iterators.h" +#include "test_range.h" +#include "test_standard_function.h" -int main(int, char**) { return 0; } +static_assert(is_function_like()); + +constexpr auto range = std::array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +using iterator = decltype(range)::const_iterator; + +template +constexpr bool operator==(external_stride_counting_iterator const& x, sentinel_wrapper const& y) { + return x.base() == y; +} + +template