diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index e10f970f..2a5391f8 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -21,6 +21,7 @@ set(ABSL_INTERNAL_DLL_FILES "base/internal/fast_type_id.h" "base/internal/hide_ptr.h" "base/internal/identity.h" + "base/internal/iterator_traits.h" "base/internal/invoke.h" "base/internal/inline_variable.h" "base/internal/low_level_alloc.cc" diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 50038cde..b5b5d5a3 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -955,6 +955,27 @@ cc_test( ], ) +cc_library( + name = "iterator_traits_internal", + hdrs = ["internal/iterator_traits.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [":config"], +) + +cc_test( + name = "iterator_traits_test", + srcs = ["internal/iterator_traits_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":config", + ":iterator_traits_internal", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + cc_library( name = "tracing_internal", srcs = ["internal/tracing.cc"], diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index d0b67c73..43c93168 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -834,3 +834,29 @@ absl_cc_test( absl::tracing_internal GTest::gtest_main ) + +# Internal-only target, do not depend on directly. +absl_cc_library( + NAME + iterator_traits_internal + HDRS + "internal/iterator_traits.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + PUBLIC +) + +absl_cc_test( + NAME + iterator_traits_test + SRCS + "internal/iterator_traits_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::config + absl::iterator_traits_internal + GTest::gtest_main +) diff --git a/absl/base/internal/iterator_traits.h b/absl/base/internal/iterator_traits.h new file mode 100644 index 00000000..eb3e8f05 --- /dev/null +++ b/absl/base/internal/iterator_traits.h @@ -0,0 +1,45 @@ +// Copyright 2025 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: internal/iterator_traits.h +// ----------------------------------------------------------------------------- +// +// Helpers for querying traits of iterators, for implementing containers, etc. + +#ifndef ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_ +#define ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_ + +#include +#include + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace base_internal { + +template +using IsAtLeastIterator = std::is_convertible< + typename std::iterator_traits::iterator_category, IteratorTag>; + +template +using IsAtLeastForwardIterator = + IsAtLeastIterator; + +} // namespace base_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_ diff --git a/absl/base/internal/iterator_traits_test.cc b/absl/base/internal/iterator_traits_test.cc new file mode 100644 index 00000000..0aa9f0bb --- /dev/null +++ b/absl/base/internal/iterator_traits_test.cc @@ -0,0 +1,75 @@ +// Copyright 2025 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/base/internal/iterator_traits.h" + +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace base_internal { +namespace { + +TEST(IsAtLeastIteratorTest, IsAtLeastIterator) { + EXPECT_TRUE((IsAtLeastIterator())); + EXPECT_TRUE((IsAtLeastIterator())); + EXPECT_TRUE((IsAtLeastIterator())); + EXPECT_TRUE((IsAtLeastIterator())); + EXPECT_TRUE((IsAtLeastIterator::iterator>())); + EXPECT_TRUE((IsAtLeastIterator::iterator>())); + EXPECT_TRUE((IsAtLeastIterator::iterator>())); + EXPECT_TRUE((IsAtLeastIterator::iterator>())); + + EXPECT_TRUE( + (IsAtLeastIterator::iterator>())); + EXPECT_TRUE((IsAtLeastIterator::iterator>())); + EXPECT_TRUE((IsAtLeastIterator::iterator>())); + EXPECT_FALSE((IsAtLeastIterator::iterator>())); + + EXPECT_TRUE((IsAtLeastIterator::iterator>())); + EXPECT_TRUE((IsAtLeastIterator::iterator>())); + EXPECT_FALSE((IsAtLeastIterator::iterator>())); + EXPECT_FALSE((IsAtLeastIterator::iterator>())); + + EXPECT_TRUE((IsAtLeastIterator>())); + EXPECT_FALSE((IsAtLeastIterator>())); + EXPECT_FALSE((IsAtLeastIterator>())); + EXPECT_FALSE((IsAtLeastIterator>())); +} + +} // namespace +} // namespace base_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index c1212125..6b295211 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -70,6 +70,7 @@ cc_library( "//absl/base:config", "//absl/base:core_headers", "//absl/base:dynamic_annotations", + "//absl/base:iterator_traits_internal", "//absl/base:throw_delegate", "//absl/memory", ], @@ -144,6 +145,7 @@ cc_library( ":inlined_vector_internal", "//absl/algorithm", "//absl/base:core_headers", + "//absl/base:iterator_traits_internal", "//absl/base:throw_delegate", "//absl/memory", "//absl/meta:type_traits", diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index a2dd69f2..c3f57493 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt @@ -131,6 +131,7 @@ absl_cc_library( absl::config absl::core_headers absl::dynamic_annotations + absl::iterator_traits_internal absl::throw_delegate absl::memory PUBLIC diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h index 95abb0a5..94042059 100644 --- a/absl/container/fixed_array.h +++ b/absl/container/fixed_array.h @@ -44,6 +44,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/dynamic_annotations.h" +#include "absl/base/internal/iterator_traits.h" #include "absl/base/internal/throw_delegate.h" #include "absl/base/macros.h" #include "absl/base/optimization.h" @@ -85,9 +86,8 @@ class ABSL_ATTRIBUTE_WARN_UNUSED FixedArray { // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17, // but this seems to be mostly pedantic. template - using EnableIfForwardIterator = absl::enable_if_t::iterator_category, - std::forward_iterator_tag>::value>; + using EnableIfForwardIterator = std::enable_if_t< + base_internal::IsAtLeastForwardIterator::value>; static constexpr bool NoexceptCopyable() { return std::is_nothrow_copy_constructible::value && absl::allocator_is_nothrow::value; diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h index cbf8bc2c..318d654d 100644 --- a/absl/container/inlined_vector.h +++ b/absl/container/inlined_vector.h @@ -47,6 +47,7 @@ #include "absl/algorithm/algorithm.h" #include "absl/base/attributes.h" +#include "absl/base/internal/iterator_traits.h" #include "absl/base/internal/throw_delegate.h" #include "absl/base/macros.h" #include "absl/base/optimization.h" @@ -90,11 +91,11 @@ class ABSL_ATTRIBUTE_WARN_UNUSED InlinedVector { inlined_vector_internal::DefaultValueAdapter; template - using EnableIfAtLeastForwardIterator = absl::enable_if_t< - inlined_vector_internal::IsAtLeastForwardIterator::value, int>; + using EnableIfAtLeastForwardIterator = std::enable_if_t< + base_internal::IsAtLeastForwardIterator::value, int>; template - using DisableIfAtLeastForwardIterator = absl::enable_if_t< - !inlined_vector_internal::IsAtLeastForwardIterator::value, int>; + using DisableIfAtLeastForwardIterator = std::enable_if_t< + !base_internal::IsAtLeastForwardIterator::value, int>; using MemcpyPolicy = typename Storage::MemcpyPolicy; using ElementwiseAssignPolicy = typename Storage::ElementwiseAssignPolicy; diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index 0bd0a1c4..5f9f9e56 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h @@ -73,11 +73,6 @@ using ConstReverseIterator = typename std::reverse_iterator>; template using MoveIterator = typename std::move_iterator>; -template -using IsAtLeastForwardIterator = std::is_convertible< - typename std::iterator_traits::iterator_category, - std::forward_iterator_tag>; - template using IsMoveAssignOk = std::is_move_assignable>; template diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 81b8d893..6946865a 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -104,6 +104,7 @@ cc_library( "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", + "//absl/base:iterator_traits_internal", "//absl/base:nullability", "//absl/base:raw_logging_internal", "//absl/base:throw_delegate", diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 993d7517..76830ee9 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -84,6 +84,7 @@ absl_cc_library( absl::core_headers absl::endian absl::int128 + absl::iterator_traits_internal absl::memory absl::nullability absl::raw_logging_internal diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h index 3e730c7a..31fcf6dc 100644 --- a/absl/strings/internal/str_join_internal.h +++ b/absl/strings/internal/str_join_internal.h @@ -43,6 +43,7 @@ #include #include "absl/base/config.h" +#include "absl/base/internal/iterator_traits.h" #include "absl/base/internal/raw_logging.h" #include "absl/strings/internal/ostringstream.h" #include "absl/strings/internal/resize_uninitialized.h" @@ -228,9 +229,8 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, // range will be traversed twice: once to calculate the total needed size, and // then again to copy the elements and delimiters to the output string. template ::iterator_category, - std::forward_iterator_tag>::value>::type> + typename = std::enable_if_t< + base_internal::IsAtLeastForwardIterator::value>> std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, NoFormatter) { std::string result;