• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/containers/checked_iterators.h"
6 
7 #include <algorithm>
8 #include <iterator>
9 
10 #include "base/check_op.h"
11 #include "base/ranges/algorithm.h"
12 #include "build/build_config.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 namespace base {
16 
17 // Checks that constexpr CheckedContiguousConstIterators can be compared at
18 // compile time.
TEST(CheckedContiguousIterator,StaticComparisonOperators)19 TEST(CheckedContiguousIterator, StaticComparisonOperators) {
20   static constexpr int arr[] = {0};
21 
22   constexpr CheckedContiguousConstIterator<int> begin(arr, arr, arr + 1);
23   constexpr CheckedContiguousConstIterator<int> end(arr, arr + 1, arr + 1);
24 
25   static_assert(begin == begin, "");
26   static_assert(end == end, "");
27 
28   static_assert(begin != end, "");
29   static_assert(end != begin, "");
30 
31   static_assert(begin < end, "");
32 
33   static_assert(begin <= begin, "");
34   static_assert(begin <= end, "");
35   static_assert(end <= end, "");
36 
37   static_assert(end > begin, "");
38 
39   static_assert(end >= end, "");
40   static_assert(end >= begin, "");
41   static_assert(begin >= begin, "");
42 }
43 
44 // Checks that comparison between iterators and const iterators works in both
45 // directions.
TEST(CheckedContiguousIterator,ConvertingComparisonOperators)46 TEST(CheckedContiguousIterator, ConvertingComparisonOperators) {
47   static int arr[] = {0};
48 
49   CheckedContiguousIterator<int> begin(arr, arr, arr + 1);
50   CheckedContiguousConstIterator<int> cbegin(arr, arr, arr + 1);
51 
52   CheckedContiguousIterator<int> end(arr, arr + 1, arr + 1);
53   CheckedContiguousConstIterator<int> cend(arr, arr + 1, arr + 1);
54 
55   EXPECT_EQ(begin, cbegin);
56   EXPECT_EQ(cbegin, begin);
57   EXPECT_EQ(end, cend);
58   EXPECT_EQ(cend, end);
59 
60   EXPECT_NE(begin, cend);
61   EXPECT_NE(cbegin, end);
62   EXPECT_NE(end, cbegin);
63   EXPECT_NE(cend, begin);
64 
65   EXPECT_LT(begin, cend);
66   EXPECT_LT(cbegin, end);
67 
68   EXPECT_LE(begin, cbegin);
69   EXPECT_LE(cbegin, begin);
70   EXPECT_LE(begin, cend);
71   EXPECT_LE(cbegin, end);
72   EXPECT_LE(end, cend);
73   EXPECT_LE(cend, end);
74 
75   EXPECT_GT(end, cbegin);
76   EXPECT_GT(cend, begin);
77 
78   EXPECT_GE(end, cend);
79   EXPECT_GE(cend, end);
80   EXPECT_GE(end, cbegin);
81   EXPECT_GE(cend, begin);
82   EXPECT_GE(begin, cbegin);
83   EXPECT_GE(cbegin, begin);
84 }
85 
86 }  // namespace base
87 
88 // ChromeOS does not use the in-tree libc++, but rather a shared library that
89 // lags a bit behind.
90 // TODO(crbug.com/1166360): Enable this test on ChromeOS once the shared libc++
91 // is sufficiently modern.
92 #if defined(_LIBCPP_VERSION) && !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_CHROMEOS)
93 namespace {
94 
95 // Helper template that wraps an iterator and disables its dereference and
96 // increment operations.
97 // Note: We don't simply delete these operations, because code using these
98 // operations still needs to compile, even though the codepath will never be
99 // taken at runtime. This will crash at runtime in case code does try to use
100 // these operations.
101 template <typename Iterator>
102 struct DisableDerefAndIncr : Iterator {
103   using Iterator::Iterator;
DisableDerefAndIncr__anon99a332150111::DisableDerefAndIncr104   constexpr DisableDerefAndIncr(const Iterator& iter) : Iterator(iter) {}
105 
operator *__anon99a332150111::DisableDerefAndIncr106   constexpr typename Iterator::reference operator*() {
107     CHECK(false);
108     return Iterator::operator*();
109   }
110 
operator ++__anon99a332150111::DisableDerefAndIncr111   constexpr Iterator& operator++() {
112     CHECK(false);
113     return Iterator::operator++();
114   }
115 
operator ++__anon99a332150111::DisableDerefAndIncr116   constexpr Iterator operator++(int i) {
117     CHECK(false);
118     return Iterator::operator++(i);
119   }
120 };
121 
122 }  // namespace
123 
124 // Inherit `__is_cpp17_contiguous_iterator` and `pointer_traits` specializations
125 // from the base class.
126 namespace std {
127 template <typename Iter>
128 struct __is_cpp17_contiguous_iterator<DisableDerefAndIncr<Iter>>
129     : __is_cpp17_contiguous_iterator<Iter> {};
130 
131 template <typename Iter>
132 struct pointer_traits<DisableDerefAndIncr<Iter>> : pointer_traits<Iter> {};
133 }  // namespace std
134 
135 namespace base {
136 
137 // Tests that using std::copy with CheckedContiguousIterator<int> results in an
138 // optimized code-path that does not invoke the iterator's dereference and
139 // increment operations. This would fail at runtime if std::copy was not
140 // optimized.
TEST(CheckedContiguousIterator,OptimizedCopy)141 TEST(CheckedContiguousIterator, OptimizedCopy) {
142   using Iter = DisableDerefAndIncr<CheckedContiguousIterator<int>>;
143 
144   int arr_in[5] = {1, 2, 3, 4, 5};
145   int arr_out[5];
146 
147   Iter in_begin(std::begin(arr_in), std::end(arr_in));
148   Iter in_end(std::begin(arr_in), std::end(arr_in), std::end(arr_in));
149   Iter out_begin(std::begin(arr_out), std::end(arr_out));
150   Iter out_end = std::copy(in_begin, in_end, out_begin);
151   EXPECT_EQ(out_end, out_begin + (in_end - in_begin));
152 
153   EXPECT_TRUE(ranges::equal(arr_in, arr_out));
154 }
155 
156 }  // namespace base
157 
158 #endif
159