checked_iterators_unittest.cc 4.6 KB

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