Commit b0a9af24 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[base] Make CheckedContiguousIterator constexpr

This change makes base::CheckedContiguousIterator's API constexpr and
updates base::span's begin and end member functions.

Furthermore, this change makes the various CHECK_* macros usable in a
constexpr context (given that the condition actually is true), and makes
more use of them in CheckedContiguousIterator.

Bug: 817982, 828324
Change-Id: I012941d31237559a7776948c613c45e9ff60b2c0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1856519Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#705297}
parent 146c83c1
...@@ -27,15 +27,16 @@ class CheckedContiguousIterator { ...@@ -27,15 +27,16 @@ class CheckedContiguousIterator {
template <typename U> template <typename U>
friend class CheckedContiguousIterator; friend class CheckedContiguousIterator;
CheckedContiguousIterator() = default; constexpr CheckedContiguousIterator() = default;
CheckedContiguousIterator(T* start, const T* end) constexpr CheckedContiguousIterator(T* start, const T* end)
: CheckedContiguousIterator(start, start, end) {} : CheckedContiguousIterator(start, start, end) {}
CheckedContiguousIterator(const T* start, T* current, const T* end) constexpr CheckedContiguousIterator(const T* start, T* current, const T* end)
: start_(start), current_(current), end_(end) { : start_(start), current_(current), end_(end) {
CHECK(start <= current); CHECK_LE(start, current);
CHECK(current <= end); CHECK_LE(current, end);
} }
CheckedContiguousIterator(const CheckedContiguousIterator& other) = default; constexpr CheckedContiguousIterator(const CheckedContiguousIterator& other) =
default;
// Converting constructor allowing conversions like CRAI<T> to CRAI<const T>, // Converting constructor allowing conversions like CRAI<T> to CRAI<const T>,
// but disallowing CRAI<const T> to CRAI<T> or CRAI<Derived> to CRAI<Base>, // but disallowing CRAI<const T> to CRAI<T> or CRAI<Derived> to CRAI<Base>,
...@@ -45,75 +46,75 @@ class CheckedContiguousIterator { ...@@ -45,75 +46,75 @@ class CheckedContiguousIterator {
template < template <
typename U, typename U,
std::enable_if_t<std::is_convertible<U (*)[], T (*)[]>::value>* = nullptr> std::enable_if_t<std::is_convertible<U (*)[], T (*)[]>::value>* = nullptr>
CheckedContiguousIterator(const CheckedContiguousIterator<U>& other) constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other)
: start_(other.start_), current_(other.current_), end_(other.end_) { : start_(other.start_), current_(other.current_), end_(other.end_) {
// We explicitly don't delegate to the 3-argument constructor here. Its // We explicitly don't delegate to the 3-argument constructor here. Its
// CHECKs would be redundant, since we expect |other| to maintain its own // CHECKs would be redundant, since we expect |other| to maintain its own
// invariant. However, DCHECKs never hurt anybody. Presumably. // invariant. However, DCHECKs never hurt anybody. Presumably.
DCHECK(other.start_ <= other.current_); DCHECK_LE(other.start_, other.current_);
DCHECK(other.current_ <= other.end_); DCHECK_LE(other.current_, other.end_);
} }
~CheckedContiguousIterator() = default; ~CheckedContiguousIterator() = default;
CheckedContiguousIterator& operator=(const CheckedContiguousIterator& other) = constexpr CheckedContiguousIterator& operator=(
default; const CheckedContiguousIterator& other) = default;
bool operator==(const CheckedContiguousIterator& other) const { constexpr bool operator==(const CheckedContiguousIterator& other) const {
CheckComparable(other); CheckComparable(other);
return current_ == other.current_; return current_ == other.current_;
} }
bool operator!=(const CheckedContiguousIterator& other) const { constexpr bool operator!=(const CheckedContiguousIterator& other) const {
CheckComparable(other); CheckComparable(other);
return current_ != other.current_; return current_ != other.current_;
} }
bool operator<(const CheckedContiguousIterator& other) const { constexpr bool operator<(const CheckedContiguousIterator& other) const {
CheckComparable(other); CheckComparable(other);
return current_ < other.current_; return current_ < other.current_;
} }
bool operator<=(const CheckedContiguousIterator& other) const { constexpr bool operator<=(const CheckedContiguousIterator& other) const {
CheckComparable(other); CheckComparable(other);
return current_ <= other.current_; return current_ <= other.current_;
} }
bool operator>(const CheckedContiguousIterator& other) const { constexpr bool operator>(const CheckedContiguousIterator& other) const {
CheckComparable(other); CheckComparable(other);
return current_ > other.current_; return current_ > other.current_;
} }
bool operator>=(const CheckedContiguousIterator& other) const { constexpr bool operator>=(const CheckedContiguousIterator& other) const {
CheckComparable(other); CheckComparable(other);
return current_ >= other.current_; return current_ >= other.current_;
} }
CheckedContiguousIterator& operator++() { constexpr CheckedContiguousIterator& operator++() {
CHECK(current_ != end_); CHECK_NE(current_, end_);
++current_; ++current_;
return *this; return *this;
} }
CheckedContiguousIterator operator++(int) { constexpr CheckedContiguousIterator operator++(int) {
CheckedContiguousIterator old = *this; CheckedContiguousIterator old = *this;
++*this; ++*this;
return old; return old;
} }
CheckedContiguousIterator& operator--() { constexpr CheckedContiguousIterator& operator--() {
CHECK(current_ != start_); CHECK_NE(current_, start_);
--current_; --current_;
return *this; return *this;
} }
CheckedContiguousIterator& operator--(int) { constexpr CheckedContiguousIterator& operator--(int) {
CheckedContiguousIterator old = *this; CheckedContiguousIterator old = *this;
--*this; --*this;
return old; return old;
} }
CheckedContiguousIterator& operator+=(difference_type rhs) { constexpr CheckedContiguousIterator& operator+=(difference_type rhs) {
if (rhs > 0) { if (rhs > 0) {
CHECK_LE(rhs, end_ - current_); CHECK_LE(rhs, end_ - current_);
} else { } else {
...@@ -123,13 +124,13 @@ class CheckedContiguousIterator { ...@@ -123,13 +124,13 @@ class CheckedContiguousIterator {
return *this; return *this;
} }
CheckedContiguousIterator operator+(difference_type rhs) const { constexpr CheckedContiguousIterator operator+(difference_type rhs) const {
CheckedContiguousIterator it = *this; CheckedContiguousIterator it = *this;
it += rhs; it += rhs;
return it; return it;
} }
CheckedContiguousIterator& operator-=(difference_type rhs) { constexpr CheckedContiguousIterator& operator-=(difference_type rhs) {
if (rhs < 0) { if (rhs < 0) {
CHECK_LE(rhs, end_ - current_); CHECK_LE(rhs, end_ - current_);
} else { } else {
...@@ -139,30 +140,31 @@ class CheckedContiguousIterator { ...@@ -139,30 +140,31 @@ class CheckedContiguousIterator {
return *this; return *this;
} }
CheckedContiguousIterator operator-(difference_type rhs) const { constexpr CheckedContiguousIterator operator-(difference_type rhs) const {
CheckedContiguousIterator it = *this; CheckedContiguousIterator it = *this;
it -= rhs; it -= rhs;
return it; return it;
} }
friend difference_type operator-(const CheckedContiguousIterator& lhs, constexpr friend difference_type operator-(
const CheckedContiguousIterator& rhs) { const CheckedContiguousIterator& lhs,
CHECK(lhs.start_ == rhs.start_); const CheckedContiguousIterator& rhs) {
CHECK(lhs.end_ == rhs.end_); CHECK_EQ(lhs.start_, rhs.start_);
CHECK_EQ(lhs.end_, rhs.end_);
return lhs.current_ - rhs.current_; return lhs.current_ - rhs.current_;
} }
reference operator*() const { constexpr reference operator*() const {
CHECK(current_ != end_); CHECK_NE(current_, end_);
return *current_; return *current_;
} }
pointer operator->() const { constexpr pointer operator->() const {
CHECK(current_ != end_); CHECK_NE(current_, end_);
return current_; return current_;
} }
reference operator[](difference_type rhs) const { constexpr reference operator[](difference_type rhs) const {
CHECK_GE(rhs, 0); CHECK_GE(rhs, 0);
CHECK_LT(rhs, end_ - current_); CHECK_LT(rhs, end_ - current_);
return current_[rhs]; return current_[rhs];
...@@ -185,7 +187,7 @@ class CheckedContiguousIterator { ...@@ -185,7 +187,7 @@ class CheckedContiguousIterator {
} }
private: private:
void CheckComparable(const CheckedContiguousIterator& other) const { constexpr void CheckComparable(const CheckedContiguousIterator& other) const {
CHECK_EQ(start_, other.start_); CHECK_EQ(start_, other.start_);
CHECK_EQ(end_, other.end_); CHECK_EQ(end_, other.end_);
} }
......
...@@ -405,8 +405,10 @@ class span : public internal::ExtentStorage<Extent> { ...@@ -405,8 +405,10 @@ class span : public internal::ExtentStorage<Extent> {
constexpr T* data() const noexcept { return data_; } constexpr T* data() const noexcept { return data_; }
// [span.iter], span iterator support // [span.iter], span iterator support
iterator begin() const noexcept { return iterator(data_, data_ + size()); } constexpr iterator begin() const noexcept {
iterator end() const noexcept { return iterator(data_, data_ + size());
}
constexpr iterator end() const noexcept {
return iterator(data_, data_ + size(), data_ + size()); return iterator(data_, data_ + size(), data_ + size());
} }
......
...@@ -23,6 +23,24 @@ using ::testing::Pointwise; ...@@ -23,6 +23,24 @@ using ::testing::Pointwise;
namespace base { namespace base {
namespace {
// constexpr implementation of std::equal's 4 argument overload.
template <class InputIterator1, class InputIterator2>
constexpr bool constexpr_equal(InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
InputIterator2 last2) {
for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
if (*first1 != *first2)
return false;
}
return first1 == last1 && first2 == last2;
}
} // namespace
TEST(SpanTest, DefaultConstructor) { TEST(SpanTest, DefaultConstructor) {
span<int> dynamic_span; span<int> dynamic_span;
EXPECT_EQ(nullptr, dynamic_span.data()); EXPECT_EQ(nullptr, dynamic_span.data());
...@@ -962,6 +980,21 @@ TEST(SpanTest, Iterator) { ...@@ -962,6 +980,21 @@ TEST(SpanTest, Iterator) {
EXPECT_THAT(results, ElementsAre(1, 6, 1, 8, 0)); EXPECT_THAT(results, ElementsAre(1, 6, 1, 8, 0));
} }
TEST(SpanTest, ConstexprIterator) {
static constexpr int kArray[] = {1, 6, 1, 8, 0};
constexpr span<const int> span(kArray);
static_assert(constexpr_equal(std::begin(kArray), std::end(kArray),
span.begin(), span.end()),
"");
static_assert(1 == span.begin()[0], "");
static_assert(1 == *(span.begin() += 0), "");
static_assert(6 == *(span.begin() += 1), "");
static_assert(1 == *((span.begin() + 1) -= 1), "");
static_assert(6 == *((span.begin() + 1) -= 0), "");
}
TEST(SpanTest, ReverseIterator) { TEST(SpanTest, ReverseIterator) {
static constexpr int kArray[] = {1, 6, 1, 8, 0}; static constexpr int kArray[] = {1, 6, 1, 8, 0};
constexpr span<const int> span(kArray); constexpr span<const int> span(kArray);
......
...@@ -532,7 +532,7 @@ class CheckOpResult { ...@@ -532,7 +532,7 @@ class CheckOpResult {
// |message| must be non-null if and only if the check failed. // |message| must be non-null if and only if the check failed.
constexpr CheckOpResult(std::string* message) : message_(message) {} constexpr CheckOpResult(std::string* message) : message_(message) {}
// Returns true if the check succeeded. // Returns true if the check succeeded.
operator bool() const { return !message_; } constexpr operator bool() const { return !message_; }
// Returns the message. // Returns the message.
std::string* message() { return message_; } std::string* message() { return message_; }
...@@ -685,20 +685,21 @@ std::string* MakeCheckOpString<std::string, std::string>( ...@@ -685,20 +685,21 @@ std::string* MakeCheckOpString<std::string, std::string>(
// The checked condition is wrapped with ANALYZER_ASSUME_TRUE, which under // The checked condition is wrapped with ANALYZER_ASSUME_TRUE, which under
// static analysis builds, blocks analysis of the current path if the // static analysis builds, blocks analysis of the current path if the
// condition is false. // condition is false.
#define DEFINE_CHECK_OP_IMPL(name, op) \ #define DEFINE_CHECK_OP_IMPL(name, op) \
template <class t1, class t2> \ template <class t1, class t2> \
inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ constexpr std::string* Check##name##Impl(const t1& v1, const t2& v2, \
const char* names) { \ const char* names) { \
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \ if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
return NULL; \ return nullptr; \
else \ else \
return ::logging::MakeCheckOpString(v1, v2, names); \ return ::logging::MakeCheckOpString(v1, v2, names); \
} \ } \
inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ constexpr std::string* Check##name##Impl(int v1, int v2, \
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \ const char* names) { \
return NULL; \ if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
else \ return nullptr; \
return ::logging::MakeCheckOpString(v1, v2, names); \ else \
return ::logging::MakeCheckOpString(v1, v2, names); \
} }
DEFINE_CHECK_OP_IMPL(EQ, ==) DEFINE_CHECK_OP_IMPL(EQ, ==)
DEFINE_CHECK_OP_IMPL(NE, !=) DEFINE_CHECK_OP_IMPL(NE, !=)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment