mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Factor out some iterator traits detection code
There are a few different cases where we check iterator categorization, mostly for forward iterators for preallocating buffers of the correct size. Factoring this out makes it easier to make all of these cases support the C++20 iterator model. PiperOrigin-RevId: 725791190 Change-Id: Icf9d687654618c7ceff98ec76ec59e83c682dd6b
This commit is contained in:
committed by
Copybara-Service
parent
05e72a3285
commit
9e764b4f25
@@ -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"
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
45
absl/base/internal/iterator_traits.h
Normal file
45
absl/base/internal/iterator_traits.h
Normal file
@@ -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 <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
template <typename IteratorTag, typename Iterator>
|
||||
using IsAtLeastIterator = std::is_convertible<
|
||||
typename std::iterator_traits<Iterator>::iterator_category, IteratorTag>;
|
||||
|
||||
template <typename Iterator>
|
||||
using IsAtLeastForwardIterator =
|
||||
IsAtLeastIterator<std::forward_iterator_tag, Iterator>;
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_
|
||||
75
absl/base/internal/iterator_traits_test.cc
Normal file
75
absl/base/internal/iterator_traits_test.cc
Normal file
@@ -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 <forward_list>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
namespace {
|
||||
|
||||
TEST(IsAtLeastIteratorTest, IsAtLeastIterator) {
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::input_iterator_tag, int*>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::forward_iterator_tag, int*>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::bidirectional_iterator_tag, int*>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::random_access_iterator_tag, int*>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::input_iterator_tag,
|
||||
std::vector<int>::iterator>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::forward_iterator_tag,
|
||||
std::vector<int>::iterator>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::bidirectional_iterator_tag,
|
||||
std::vector<int>::iterator>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::random_access_iterator_tag,
|
||||
std::vector<int>::iterator>()));
|
||||
|
||||
EXPECT_TRUE(
|
||||
(IsAtLeastIterator<std::input_iterator_tag, std::list<int>::iterator>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::forward_iterator_tag,
|
||||
std::list<int>::iterator>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::bidirectional_iterator_tag,
|
||||
std::list<int>::iterator>()));
|
||||
EXPECT_FALSE((IsAtLeastIterator<std::random_access_iterator_tag,
|
||||
std::list<int>::iterator>()));
|
||||
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::input_iterator_tag,
|
||||
std::forward_list<int>::iterator>()));
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::forward_iterator_tag,
|
||||
std::forward_list<int>::iterator>()));
|
||||
EXPECT_FALSE((IsAtLeastIterator<std::bidirectional_iterator_tag,
|
||||
std::forward_list<int>::iterator>()));
|
||||
EXPECT_FALSE((IsAtLeastIterator<std::random_access_iterator_tag,
|
||||
std::forward_list<int>::iterator>()));
|
||||
|
||||
EXPECT_TRUE((IsAtLeastIterator<std::input_iterator_tag,
|
||||
std::istream_iterator<int>>()));
|
||||
EXPECT_FALSE((IsAtLeastIterator<std::forward_iterator_tag,
|
||||
std::istream_iterator<int>>()));
|
||||
EXPECT_FALSE((IsAtLeastIterator<std::bidirectional_iterator_tag,
|
||||
std::istream_iterator<int>>()));
|
||||
EXPECT_FALSE((IsAtLeastIterator<std::random_access_iterator_tag,
|
||||
std::istream_iterator<int>>()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <typename Iterator>
|
||||
using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
|
||||
typename std::iterator_traits<Iterator>::iterator_category,
|
||||
std::forward_iterator_tag>::value>;
|
||||
using EnableIfForwardIterator = std::enable_if_t<
|
||||
base_internal::IsAtLeastForwardIterator<Iterator>::value>;
|
||||
static constexpr bool NoexceptCopyable() {
|
||||
return std::is_nothrow_copy_constructible<StorageElement>::value &&
|
||||
absl::allocator_is_nothrow<allocator_type>::value;
|
||||
|
||||
@@ -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<TheA>;
|
||||
|
||||
template <typename Iterator>
|
||||
using EnableIfAtLeastForwardIterator = absl::enable_if_t<
|
||||
inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
|
||||
using EnableIfAtLeastForwardIterator = std::enable_if_t<
|
||||
base_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
|
||||
template <typename Iterator>
|
||||
using DisableIfAtLeastForwardIterator = absl::enable_if_t<
|
||||
!inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
|
||||
using DisableIfAtLeastForwardIterator = std::enable_if_t<
|
||||
!base_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
|
||||
|
||||
using MemcpyPolicy = typename Storage::MemcpyPolicy;
|
||||
using ElementwiseAssignPolicy = typename Storage::ElementwiseAssignPolicy;
|
||||
|
||||
@@ -73,11 +73,6 @@ using ConstReverseIterator = typename std::reverse_iterator<ConstIterator<A>>;
|
||||
template <typename A>
|
||||
using MoveIterator = typename std::move_iterator<Iterator<A>>;
|
||||
|
||||
template <typename Iterator>
|
||||
using IsAtLeastForwardIterator = std::is_convertible<
|
||||
typename std::iterator_traits<Iterator>::iterator_category,
|
||||
std::forward_iterator_tag>;
|
||||
|
||||
template <typename A>
|
||||
using IsMoveAssignOk = std::is_move_assignable<ValueType<A>>;
|
||||
template <typename A>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <utility>
|
||||
|
||||
#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 <typename Iterator,
|
||||
typename = typename std::enable_if<std::is_convertible<
|
||||
typename std::iterator_traits<Iterator>::iterator_category,
|
||||
std::forward_iterator_tag>::value>::type>
|
||||
typename = std::enable_if_t<
|
||||
base_internal::IsAtLeastForwardIterator<Iterator>::value>>
|
||||
std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
|
||||
NoFormatter) {
|
||||
std::string result;
|
||||
|
||||
Reference in New Issue
Block a user