From d23a5b1d88df513aff1dc1ba09730221567f2857 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Wed, 16 Dec 2020 13:02:28 +0530 Subject: BLI: constexpr Span, IndexRange, StringRef(Null/Base) Motivated by `std::string_view` being usable in const (compile-time) context. One functional change was needed for StringRef: `std::char_traits::length(str)` instead of `strlen`. Reviewed By: JacquesLucke, LazyDodo Differential Revision: https://developer.blender.org/D9788 --- source/blender/blenlib/BLI_index_range.hh | 45 ++++---- source/blender/blenlib/BLI_span.hh | 124 ++++++++++---------- source/blender/blenlib/BLI_string_ref.hh | 126 +++++++++++---------- .../blender/blenlib/tests/BLI_index_range_test.cc | 7 ++ source/blender/blenlib/tests/BLI_span_test.cc | 15 +++ .../blender/blenlib/tests/BLI_string_ref_test.cc | 8 ++ 6 files changed, 180 insertions(+), 145 deletions(-) diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh index 2b060c986cd..4121542c887 100644 --- a/source/blender/blenlib/BLI_index_range.hh +++ b/source/blender/blenlib/BLI_index_range.hh @@ -73,21 +73,22 @@ class IndexRange { int64_t size_ = 0; public: - IndexRange() = default; + constexpr IndexRange() = default; - explicit IndexRange(int64_t size) : start_(0), size_(size) + constexpr explicit IndexRange(int64_t size) : start_(0), size_(size) { BLI_assert(size >= 0); } - IndexRange(int64_t start, int64_t size) : start_(start), size_(size) + constexpr IndexRange(int64_t start, int64_t size) : start_(start), size_(size) { BLI_assert(start >= 0); BLI_assert(size >= 0); } template - IndexRange(const tbb::blocked_range &range) : start_(range.begin()), size_(range.size()) + constexpr IndexRange(const tbb::blocked_range &range) + : start_(range.begin()), size_(range.size()) { } @@ -96,33 +97,33 @@ class IndexRange { int64_t current_; public: - Iterator(int64_t current) : current_(current) + constexpr Iterator(int64_t current) : current_(current) { } - Iterator &operator++() + constexpr Iterator &operator++() { current_++; return *this; } - bool operator!=(const Iterator &iterator) const + constexpr bool operator!=(const Iterator &iterator) const { return current_ != iterator.current_; } - int64_t operator*() const + constexpr int64_t operator*() const { return current_; } }; - Iterator begin() const + constexpr Iterator begin() const { return Iterator(start_); } - Iterator end() const + constexpr Iterator end() const { return Iterator(start_ + size_); } @@ -130,7 +131,7 @@ class IndexRange { /** * Access an element in the range. */ - int64_t operator[](int64_t index) const + constexpr int64_t operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < this->size()); @@ -140,7 +141,7 @@ class IndexRange { /** * Two ranges compare equal when they contain the same numbers. */ - friend bool operator==(IndexRange a, IndexRange b) + constexpr friend bool operator==(IndexRange a, IndexRange b) { return (a.size_ == b.size_) && (a.start_ == b.start_ || a.size_ == 0); } @@ -148,7 +149,7 @@ class IndexRange { /** * Get the amount of numbers in the range. */ - int64_t size() const + constexpr int64_t size() const { return size_; } @@ -156,7 +157,7 @@ class IndexRange { /** * Create a new range starting at the end of the current one. */ - IndexRange after(int64_t n) const + constexpr IndexRange after(int64_t n) const { BLI_assert(n >= 0); return IndexRange(start_ + size_, n); @@ -165,7 +166,7 @@ class IndexRange { /** * Create a new range that ends at the start of the current one. */ - IndexRange before(int64_t n) const + constexpr IndexRange before(int64_t n) const { BLI_assert(n >= 0); return IndexRange(start_ - n, n); @@ -175,7 +176,7 @@ class IndexRange { * Get the first element in the range. * Asserts when the range is empty. */ - int64_t first() const + constexpr int64_t first() const { BLI_assert(this->size() > 0); return start_; @@ -185,7 +186,7 @@ class IndexRange { * Get the last element in the range. * Asserts when the range is empty. */ - int64_t last() const + constexpr int64_t last() const { BLI_assert(this->size() > 0); return start_ + size_ - 1; @@ -194,7 +195,7 @@ class IndexRange { /** * Get the element one after the end. The returned value is undefined when the range is empty. */ - int64_t one_after_last() const + constexpr int64_t one_after_last() const { return start_ + size_; } @@ -202,7 +203,7 @@ class IndexRange { /** * Get the first element in the range. The returned value is undefined when the range is empty. */ - int64_t start() const + constexpr int64_t start() const { return start_; } @@ -210,7 +211,7 @@ class IndexRange { /** * Returns true when the range contains a certain number, otherwise false. */ - bool contains(int64_t value) const + constexpr bool contains(int64_t value) const { return value >= start_ && value < start_ + size_; } @@ -218,7 +219,7 @@ class IndexRange { /** * Returns a new range, that contains a sub-interval of the current one. */ - IndexRange slice(int64_t start, int64_t size) const + constexpr IndexRange slice(int64_t start, int64_t size) const { BLI_assert(start >= 0); BLI_assert(size >= 0); @@ -226,7 +227,7 @@ class IndexRange { BLI_assert(new_start + size <= start_ + size_ || size == 0); return IndexRange(new_start, size); } - IndexRange slice(IndexRange range) const + constexpr IndexRange slice(IndexRange range) const { return this->slice(range.start(), range.size()); } diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh index 5b4d2769f57..3f410efe908 100644 --- a/source/blender/blenlib/BLI_span.hh +++ b/source/blender/blenlib/BLI_span.hh @@ -93,15 +93,15 @@ template class Span { /** * Create a reference to an empty array. */ - Span() = default; + constexpr Span() = default; - Span(const T *start, int64_t size) : data_(start), size_(size) + constexpr Span(const T *start, int64_t size) : data_(start), size_(size) { BLI_assert(size >= 0); } template> * = nullptr> - Span(const U *start, int64_t size) : data_(static_cast(start)), size_(size) + constexpr Span(const U *start, int64_t size) : data_(static_cast(start)), size_(size) { BLI_assert(size >= 0); } @@ -117,16 +117,17 @@ template class Span { * Span span = {1, 2, 3, 4}; * call_function_with_array(span); */ - Span(const std::initializer_list &list) + constexpr Span(const std::initializer_list &list) : Span(list.begin(), static_cast(list.size())) { } - Span(const std::vector &vector) : Span(vector.data(), static_cast(vector.size())) + constexpr Span(const std::vector &vector) + : Span(vector.data(), static_cast(vector.size())) { } - template Span(const std::array &array) : Span(array.data(), N) + template constexpr Span(const std::array &array) : Span(array.data(), N) { } @@ -135,7 +136,7 @@ template class Span { * Span -> Span */ template> * = nullptr> - Span(Span array) : data_(static_cast(array.data())), size_(array.size()) + constexpr Span(Span array) : data_(static_cast(array.data())), size_(array.size()) { } @@ -143,7 +144,7 @@ template class Span { * Returns a contiguous part of the array. This invokes undefined behavior when the slice does * not stay within the bounds of the array. */ - Span slice(int64_t start, int64_t size) const + constexpr Span slice(int64_t start, int64_t size) const { BLI_assert(start >= 0); BLI_assert(size >= 0); @@ -151,7 +152,7 @@ template class Span { return Span(data_ + start, size); } - Span slice(IndexRange range) const + constexpr Span slice(IndexRange range) const { return this->slice(range.start(), range.size()); } @@ -160,7 +161,7 @@ template class Span { * Returns a new Span with n elements removed from the beginning. This invokes undefined * behavior when the array is too small. */ - Span drop_front(int64_t n) const + constexpr Span drop_front(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -171,7 +172,7 @@ template class Span { * Returns a new Span with n elements removed from the beginning. This invokes undefined * behavior when the array is too small. */ - Span drop_back(int64_t n) const + constexpr Span drop_back(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -182,7 +183,7 @@ template class Span { * Returns a new Span that only contains the first n elements. This invokes undefined * behavior when the array is too small. */ - Span take_front(int64_t n) const + constexpr Span take_front(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -193,7 +194,7 @@ template class Span { * Returns a new Span that only contains the last n elements. This invokes undefined * behavior when the array is too small. */ - Span take_back(int64_t n) const + constexpr Span take_back(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -204,25 +205,25 @@ template class Span { * Returns the pointer to the beginning of the referenced array. This may be nullptr when the * size is zero. */ - const T *data() const + constexpr const T *data() const { return data_; } - const T *begin() const + constexpr const T *begin() const { return data_; } - const T *end() const + constexpr const T *end() const { return data_ + size_; } - std::reverse_iterator rbegin() const + constexpr std::reverse_iterator rbegin() const { return std::reverse_iterator(this->end()); } - std::reverse_iterator rend() const + constexpr std::reverse_iterator rend() const { return std::reverse_iterator(this->begin()); } @@ -231,7 +232,7 @@ template class Span { * Access an element in the array. This invokes undefined behavior when the index is out of * bounds. */ - const T &operator[](int64_t index) const + constexpr const T &operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < size_); @@ -241,7 +242,7 @@ template class Span { /** * Returns the number of elements in the referenced array. */ - int64_t size() const + constexpr int64_t size() const { return size_; } @@ -249,7 +250,7 @@ template class Span { /** * Returns true if the size is zero. */ - bool is_empty() const + constexpr bool is_empty() const { return size_ == 0; } @@ -257,7 +258,7 @@ template class Span { /** * Returns the number of bytes referenced by this Span. */ - int64_t size_in_bytes() const + constexpr int64_t size_in_bytes() const { return sizeof(T) * size_; } @@ -266,7 +267,7 @@ template class Span { * Does a linear search to see of the value is in the array. * Returns true if it is, otherwise false. */ - bool contains(const T &value) const + constexpr bool contains(const T &value) const { for (const T &element : *this) { if (element == value) { @@ -280,7 +281,7 @@ template class Span { * Does a constant time check to see if the pointer points to a value in the referenced array. * Return true if it is, otherwise false. */ - bool contains_ptr(const T *ptr) const + constexpr bool contains_ptr(const T *ptr) const { return (this->begin() <= ptr) && (ptr < this->end()); } @@ -289,7 +290,7 @@ template class Span { * Does a linear search to count how often the value is in the array. * Returns the number of occurrences. */ - int64_t count(const T &value) const + constexpr int64_t count(const T &value) const { int64_t counter = 0; for (const T &element : *this) { @@ -304,7 +305,7 @@ template class Span { * Return a reference to the first element in the array. This invokes undefined behavior when the * array is empty. */ - const T &first() const + constexpr const T &first() const { BLI_assert(size_ > 0); return data_[0]; @@ -314,7 +315,7 @@ template class Span { * Returns a reference to the last element in the array. This invokes undefined behavior when the * array is empty. */ - const T &last() const + constexpr const T &last() const { BLI_assert(size_ > 0); return data_[size_ - 1]; @@ -324,7 +325,7 @@ template class Span { * Returns the element at the given index. If the index is out of range, return the fallback * value. */ - T get(int64_t index, const T &fallback) const + constexpr T get(int64_t index, const T &fallback) const { if (index < size_ && index >= 0) { return data_[index]; @@ -336,7 +337,7 @@ template class Span { * Check if the array contains duplicates. Does a linear search for every element. So the total * running time is O(n^2). Only use this for small arrays. */ - bool has_duplicates__linear_search() const + constexpr bool has_duplicates__linear_search() const { /* The size should really be smaller than that. If it is not, the calling code should be * changed. */ @@ -358,7 +359,7 @@ template class Span { * called on small arrays, because it has a running time of O(n*m) where n and m are the sizes of * the arrays. */ - bool intersects__linear_search(Span other) const + constexpr bool intersects__linear_search(Span other) const { /* The size should really be smaller than that. If it is not, the calling code should be * changed. */ @@ -377,7 +378,7 @@ template class Span { * Returns the index of the first occurrence of the given value. This invokes undefined behavior * when the value is not in the array. */ - int64_t first_index(const T &search_value) const + constexpr int64_t first_index(const T &search_value) const { const int64_t index = this->first_index_try(search_value); BLI_assert(index >= 0); @@ -387,7 +388,7 @@ template class Span { /** * Returns the index of the first occurrence of the given value or -1 if it does not exist. */ - int64_t first_index_try(const T &search_value) const + constexpr int64_t first_index_try(const T &search_value) const { for (int64_t i = 0; i < size_; i++) { if (data_[i] == search_value) { @@ -401,7 +402,7 @@ template class Span { * Utility to make it more convenient to iterate over all indices that can be used with this * array. */ - IndexRange index_range() const + constexpr IndexRange index_range() const { return IndexRange(size_); } @@ -409,7 +410,7 @@ template class Span { /** * Returns a new Span to the same underlying memory buffer. No conversions are done. */ - template Span cast() const + template Span constexpr cast() const { BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0); int64_t new_size = size_ * sizeof(T) / sizeof(NewT); @@ -450,21 +451,22 @@ template class MutableSpan { int64_t size_; public: - MutableSpan() = default; + constexpr MutableSpan() = default; - MutableSpan(T *start, const int64_t size) : data_(start), size_(size) + constexpr MutableSpan(T *start, const int64_t size) : data_(start), size_(size) { } - MutableSpan(std::vector &vector) : MutableSpan(vector.data(), vector.size()) + constexpr MutableSpan(std::vector &vector) : MutableSpan(vector.data(), vector.size()) { } - template MutableSpan(std::array &array) : MutableSpan(array.data(), N) + template + constexpr MutableSpan(std::array &array) : MutableSpan(array.data(), N) { } - operator Span() const + constexpr operator Span() const { return Span(data_, size_); } @@ -472,7 +474,7 @@ template class MutableSpan { /** * Returns the number of elements in the array. */ - int64_t size() const + constexpr int64_t size() const { return size_; } @@ -480,7 +482,7 @@ template class MutableSpan { /** * Replace all elements in the referenced array with the given value. */ - void fill(const T &value) + constexpr void fill(const T &value) { initialized_fill_n(data_, size_, value); } @@ -489,7 +491,7 @@ template class MutableSpan { * Replace a subset of all elements with the given value. This invokes undefined behavior when * one of the indices is out of bounds. */ - void fill_indices(Span indices, const T &value) + constexpr void fill_indices(Span indices, const T &value) { for (int64_t i : indices) { BLI_assert(i < size_); @@ -501,30 +503,30 @@ template class MutableSpan { * Returns a pointer to the beginning of the referenced array. This may be nullptr, when the size * is zero. */ - T *data() const + constexpr T *data() const { return data_; } - T *begin() const + constexpr T *begin() const { return data_; } - T *end() const + constexpr T *end() const { return data_ + size_; } - std::reverse_iterator rbegin() const + constexpr std::reverse_iterator rbegin() const { return std::reverse_iterator(this->end()); } - std::reverse_iterator rend() const + constexpr std::reverse_iterator rend() const { return std::reverse_iterator(this->begin()); } - T &operator[](const int64_t index) const + constexpr T &operator[](const int64_t index) const { BLI_assert(index < this->size()); return data_[index]; @@ -534,7 +536,7 @@ template class MutableSpan { * Returns a contiguous part of the array. This invokes undefined behavior when the slice would * go out of bounds. */ - MutableSpan slice(const int64_t start, const int64_t length) const + constexpr MutableSpan slice(const int64_t start, const int64_t length) const { BLI_assert(start + length <= this->size()); return MutableSpan(data_ + start, length); @@ -544,7 +546,7 @@ template class MutableSpan { * Returns a new MutableSpan with n elements removed from the beginning. This invokes * undefined behavior when the array is too small. */ - MutableSpan drop_front(const int64_t n) const + constexpr MutableSpan drop_front(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(n, this->size() - n); @@ -554,7 +556,7 @@ template class MutableSpan { * Returns a new MutableSpan with n elements removed from the end. This invokes undefined * behavior when the array is too small. */ - MutableSpan drop_back(const int64_t n) const + constexpr MutableSpan drop_back(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(0, this->size() - n); @@ -564,7 +566,7 @@ template class MutableSpan { * Returns a new MutableSpan that only contains the first n elements. This invokes undefined * behavior when the array is too small. */ - MutableSpan take_front(const int64_t n) const + constexpr MutableSpan take_front(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(0, n); @@ -574,7 +576,7 @@ template class MutableSpan { * Return a new MutableSpan that only contains the last n elements. This invokes undefined * behavior when the array is too small. */ - MutableSpan take_back(const int64_t n) const + constexpr MutableSpan take_back(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(this->size() - n, n); @@ -584,7 +586,7 @@ template class MutableSpan { * Returns an (immutable) Span that references the same array. This is usually not needed, * due to implicit conversions. However, sometimes automatic type deduction needs some help. */ - Span as_span() const + constexpr Span as_span() const { return Span(data_, size_); } @@ -593,7 +595,7 @@ template class MutableSpan { * Utility to make it more convenient to iterate over all indices that can be used with this * array. */ - IndexRange index_range() const + constexpr IndexRange index_range() const { return IndexRange(size_); } @@ -602,7 +604,7 @@ template class MutableSpan { * Returns a reference to the last element. This invokes undefined behavior when the array is * empty. */ - T &last() const + constexpr T &last() const { BLI_assert(size_ > 0); return data_[size_ - 1]; @@ -612,7 +614,7 @@ template class MutableSpan { * Does a linear search to count how often the value is in the array. * Returns the number of occurrences. */ - int64_t count(const T &value) const + constexpr int64_t count(const T &value) const { int64_t counter = 0; for (const T &element : *this) { @@ -628,7 +630,7 @@ template class MutableSpan { * destination contains uninitialized data and T is not trivially copy constructible. * The size of both spans is expected to be the same. */ - void copy_from(Span values) + constexpr void copy_from(Span values) { BLI_assert(size_ == values.size()); initialized_copy_n(values.data(), size_, data_); @@ -637,7 +639,7 @@ template class MutableSpan { /** * Returns a new span to the same underlying memory buffer. No conversions are done. */ - template MutableSpan cast() const + template constexpr MutableSpan cast() const { BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0); int64_t new_size = size_ * sizeof(T) / sizeof(NewT); @@ -648,7 +650,7 @@ template class MutableSpan { /** * Utilities to check that arrays have the same size in debug builds. */ -template void assert_same_size(const T1 &v1, const T2 &v2) +template constexpr void assert_same_size(const T1 &v1, const T2 &v2) { UNUSED_VARS_NDEBUG(v1, v2); #ifdef DEBUG @@ -659,7 +661,7 @@ template void assert_same_size(const T1 &v1, const T2 } template -void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3) +constexpr void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3) { UNUSED_VARS_NDEBUG(v1, v2, v3); #ifdef DEBUG diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh index 8597e54d03b..a2562c6100a 100644 --- a/source/blender/blenlib/BLI_string_ref.hh +++ b/source/blender/blenlib/BLI_string_ref.hh @@ -64,7 +64,7 @@ class StringRefBase { const char *data_; int64_t size_; - StringRefBase(const char *data, const int64_t size) : data_(data), size_(size) + constexpr StringRefBase(const char *data, const int64_t size) : data_(data), size_(size) { } @@ -75,12 +75,12 @@ class StringRefBase { /** * Return the (byte-)length of the referenced string, without any null-terminator. */ - int64_t size() const + constexpr int64_t size() const { return size_; } - bool is_empty() const + constexpr bool is_empty() const { return size_ == 0; } @@ -88,12 +88,12 @@ class StringRefBase { /** * Return a pointer to the start of the string. */ - const char *data() const + constexpr const char *data() const { return data_; } - operator Span() const + constexpr operator Span() const { return Span(data_, size_); } @@ -107,22 +107,22 @@ class StringRefBase { return std::string(data_, static_cast(size_)); } - operator std::string_view() const + constexpr operator std::string_view() const { return std::string_view(data_, static_cast(size_)); } - const char *begin() const + constexpr const char *begin() const { return data_; } - const char *end() const + constexpr const char *end() const { return data_ + size_; } - IndexRange index_range() const + constexpr IndexRange index_range() const { return IndexRange(size_); } @@ -165,19 +165,19 @@ class StringRefBase { /** * Returns true when the string begins with the given prefix. Otherwise false. */ - bool startswith(StringRef prefix) const; + constexpr bool startswith(StringRef prefix) const; /** * Returns true when the string ends with the given suffix. Otherwise false. */ - bool endswith(StringRef suffix) const; + constexpr bool endswith(StringRef suffix) const; - StringRef substr(int64_t start, const int64_t size) const; + constexpr StringRef substr(int64_t start, const int64_t size) const; /** * Get the first char in the string. This invokes undefined behavior when the string is empty. */ - const char &front() const + constexpr const char &front() const { BLI_assert(size_ >= 1); return data_[0]; @@ -186,7 +186,7 @@ class StringRefBase { /** * Get the last char in the string. This invokes undefined behavior when the string is empty. */ - const char &back() const + constexpr const char &back() const { BLI_assert(size_ >= 1); return data_[size_ - 1]; @@ -196,18 +196,18 @@ class StringRefBase { * The behavior of those functions matches the standard library implementation of * std::string_view. */ - int64_t find(char c, int64_t pos = 0) const; - int64_t find(StringRef str, int64_t pos = 0) const; - int64_t rfind(char c, int64_t pos = INT64_MAX) const; - int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const; - int64_t find_first_of(StringRef chars, int64_t pos = 0) const; - int64_t find_first_of(char c, int64_t pos = 0) const; - int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const; - int64_t find_last_of(char c, int64_t pos = INT64_MAX) const; - int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const; - int64_t find_first_not_of(char c, int64_t pos = 0) const; - int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const; - int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const; + constexpr int64_t find(char c, int64_t pos = 0) const; + constexpr int64_t find(StringRef str, int64_t pos = 0) const; + constexpr int64_t rfind(char c, int64_t pos = INT64_MAX) const; + constexpr int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const; + constexpr int64_t find_first_of(StringRef chars, int64_t pos = 0) const; + constexpr int64_t find_first_of(char c, int64_t pos = 0) const; + constexpr int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const; + constexpr int64_t find_last_of(char c, int64_t pos = INT64_MAX) const; + constexpr int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const; + constexpr int64_t find_first_not_of(char c, int64_t pos = 0) const; + constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const; + constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const; }; /** @@ -216,7 +216,7 @@ class StringRefBase { class StringRefNull : public StringRefBase { public: - StringRefNull() : StringRefBase("", 0) + constexpr StringRefNull() : StringRefBase("", 0) { } @@ -226,7 +226,7 @@ class StringRefNull : public StringRefBase { */ StringRefNull(const char *str) : StringRefBase(str, static_cast(strlen(str))) { - BLI_assert(str != NULL); + BLI_assert(str != nullptr); BLI_assert(data_[size_] == '\0'); } @@ -234,7 +234,7 @@ class StringRefNull : public StringRefBase { * Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior * when the given size is not the correct size of the string. */ - StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size) + constexpr StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size) { BLI_assert(static_cast(strlen(str)) == size); } @@ -250,7 +250,7 @@ class StringRefNull : public StringRefBase { /** * Get the char at the given index. */ - char operator[](const int64_t index) const + constexpr char operator[](const int64_t index) const { BLI_assert(index >= 0); /* Use '<=' instead of just '<', so that the null character can be accessed as well. */ @@ -263,7 +263,7 @@ class StringRefNull : public StringRefBase { * * This is like ->data(), but can only be called on a StringRefNull. */ - const char *c_str() const + constexpr const char *c_str() const { return data_; } @@ -274,25 +274,26 @@ class StringRefNull : public StringRefBase { */ class StringRef : public StringRefBase { public: - StringRef() : StringRefBase(nullptr, 0) + constexpr StringRef() : StringRefBase(nullptr, 0) { } /** * StringRefNull can be converted into StringRef, but not the other way around. */ - StringRef(StringRefNull other) : StringRefBase(other.data(), other.size()) + constexpr StringRef(StringRefNull other) : StringRefBase(other.data(), other.size()) { } /** * Create a StringRef from a null-terminated c-string. */ - StringRef(const char *str) : StringRefBase(str, str ? static_cast(strlen(str)) : 0) + constexpr StringRef(const char *str) + : StringRefBase(str, str ? static_cast(std::char_traits::length(str)) : 0) { } - StringRef(const char *str, const int64_t length) : StringRefBase(str, length) + constexpr StringRef(const char *str, const int64_t length) : StringRefBase(str, length) { } @@ -300,7 +301,7 @@ class StringRef : public StringRefBase { * Create a StringRef from a start and end pointer. This invokes undefined behavior when the * second point points to a smaller address than the first one. */ - StringRef(const char *begin, const char *one_after_end) + constexpr StringRef(const char *begin, const char *one_after_end) : StringRefBase(begin, static_cast(one_after_end - begin)) { BLI_assert(begin <= one_after_end); @@ -314,7 +315,8 @@ class StringRef : public StringRefBase { { } - StringRef(std::string_view view) : StringRefBase(view.data(), static_cast(view.size())) + constexpr StringRef(std::string_view view) + : StringRefBase(view.data(), static_cast(view.size())) { } @@ -323,7 +325,7 @@ class StringRef : public StringRefBase { * * This is similar to std::string_view::remove_prefix. */ - StringRef drop_prefix(const int64_t n) const + constexpr StringRef drop_prefix(const int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= size_); @@ -334,7 +336,7 @@ class StringRef : public StringRefBase { * Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if * the string does not begin with the given prefix. */ - StringRef drop_prefix(StringRef prefix) const + constexpr StringRef drop_prefix(StringRef prefix) const { BLI_assert(this->startswith(prefix)); return this->drop_prefix(prefix.size()); @@ -345,7 +347,7 @@ class StringRef : public StringRefBase { * * This is similar to std::string_view::remove_suffix. */ - StringRef drop_suffix(const int64_t n) const + constexpr StringRef drop_suffix(const int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= size_); @@ -355,7 +357,7 @@ class StringRef : public StringRefBase { /** * Get the char at the given index. */ - char operator[](int64_t index) const + constexpr char operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < size_); @@ -391,7 +393,7 @@ inline std::string operator+(StringRef a, StringRef b) * not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a * std::string_view, one should convert the std::string_view to StringRef (which is very cheap). * Ideally, we only use StringRef in our code to avoid this problem altogether. */ -inline bool operator==(StringRef a, StringRef b) +constexpr inline bool operator==(StringRef a, StringRef b) { if (a.size() != b.size()) { return false; @@ -399,27 +401,27 @@ inline bool operator==(StringRef a, StringRef b) return STREQLEN(a.data(), b.data(), (size_t)a.size()); } -inline bool operator!=(StringRef a, StringRef b) +constexpr inline bool operator!=(StringRef a, StringRef b) { return !(a == b); } -inline bool operator<(StringRef a, StringRef b) +constexpr inline bool operator<(StringRef a, StringRef b) { return std::string_view(a) < std::string_view(b); } -inline bool operator>(StringRef a, StringRef b) +constexpr inline bool operator>(StringRef a, StringRef b) { return std::string_view(a) > std::string_view(b); } -inline bool operator<=(StringRef a, StringRef b) +constexpr inline bool operator<=(StringRef a, StringRef b) { return std::string_view(a) <= std::string_view(b); } -inline bool operator>=(StringRef a, StringRef b) +constexpr inline bool operator>=(StringRef a, StringRef b) { return std::string_view(a) >= std::string_view(b); } @@ -427,7 +429,7 @@ inline bool operator>=(StringRef a, StringRef b) /** * Return true when the string starts with the given prefix. */ -inline bool StringRefBase::startswith(StringRef prefix) const +constexpr inline bool StringRefBase::startswith(StringRef prefix) const { if (size_ < prefix.size_) { return false; @@ -443,7 +445,7 @@ inline bool StringRefBase::startswith(StringRef prefix) const /** * Return true when the string ends with the given suffix. */ -inline bool StringRefBase::endswith(StringRef suffix) const +constexpr inline bool StringRefBase::endswith(StringRef suffix) const { if (size_ < suffix.size_) { return false; @@ -460,8 +462,8 @@ inline bool StringRefBase::endswith(StringRef suffix) const /** * Return a new #StringRef containing only a sub-string of the original string. */ -inline StringRef StringRefBase::substr(const int64_t start, - const int64_t max_size = INT64_MAX) const +constexpr inline StringRef StringRefBase::substr(const int64_t start, + const int64_t max_size = INT64_MAX) const { BLI_assert(max_size >= 0); BLI_assert(start >= 0); @@ -469,7 +471,7 @@ inline StringRef StringRefBase::substr(const int64_t start, return StringRef(data_ + start, substr_size); } -inline int64_t index_or_npos_to_int64(size_t index) +constexpr inline int64_t index_or_npos_to_int64(size_t index) { /* The compiler will probably optimize this check away. */ if (index == std::string_view::npos) { @@ -478,62 +480,62 @@ inline int64_t index_or_npos_to_int64(size_t index) return static_cast(index); } -inline int64_t StringRefBase::find(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find(char c, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast(pos))); } -inline int64_t StringRefBase::find(StringRef str, int64_t pos) const +constexpr inline int64_t StringRefBase::find(StringRef str, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast(pos))); } -inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_first_of(chars, static_cast(pos))); } -inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const { return this->find_first_of(StringRef(&c, 1), pos); } -inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_last_of(chars, static_cast(pos))); } -inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const { return this->find_last_of(StringRef(&c, 1), pos); } -inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_first_not_of(chars, static_cast(pos))); } -inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const { return this->find_first_not_of(StringRef(&c, 1), pos); } -inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_last_not_of(chars, static_cast(pos))); } -inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const { return this->find_last_not_of(StringRef(&c, 1), pos); } diff --git a/source/blender/blenlib/tests/BLI_index_range_test.cc b/source/blender/blenlib/tests/BLI_index_range_test.cc index d472ded0f18..ddaa067f50e 100644 --- a/source/blender/blenlib/tests/BLI_index_range_test.cc +++ b/source/blender/blenlib/tests/BLI_index_range_test.cc @@ -140,4 +140,11 @@ TEST(index_range, AsSpan) EXPECT_EQ(span[3], 7); } +TEST(index_range, constexpr_) +{ + constexpr IndexRange range = IndexRange(1, 1); + std::array compiles = {1}; + BLI_STATIC_ASSERT(range.size() == 1, ""); + EXPECT_EQ(compiles[0], 1); +} } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_span_test.cc b/source/blender/blenlib/tests/BLI_span_test.cc index 9a8d9df7873..d1c9f312b97 100644 --- a/source/blender/blenlib/tests/BLI_span_test.cc +++ b/source/blender/blenlib/tests/BLI_span_test.cc @@ -337,4 +337,19 @@ TEST(span, MutableReverseIterator) EXPECT_EQ_ARRAY(src.data(), Span({14, 15, 16, 17}).data(), 4); } +TEST(span, constexpr_) +{ + static constexpr std::array src = {3, 2, 1}; + constexpr Span span(src); + BLI_STATIC_ASSERT(span[2] == 1, ""); + BLI_STATIC_ASSERT(span.size() == 3, ""); + BLI_STATIC_ASSERT(span.slice(1, 2).size() == 2, ""); + BLI_STATIC_ASSERT(span.has_duplicates__linear_search() == false, ""); + + std::integral_constant ic; + BLI_STATIC_ASSERT(ic.value, ""); + + EXPECT_EQ(span.slice(1, 2).size(), 2); +} + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_string_ref_test.cc b/source/blender/blenlib/tests/BLI_string_ref_test.cc index 2d488feff71..401a7bc1118 100644 --- a/source/blender/blenlib/tests/BLI_string_ref_test.cc +++ b/source/blender/blenlib/tests/BLI_string_ref_test.cc @@ -298,4 +298,12 @@ TEST(string_ref, ToStringView) EXPECT_EQ(view, "hello"); } +TEST(string_ref, constexpr_) +{ + constexpr StringRef sref("World"); + BLI_STATIC_ASSERT(sref[2] == 'r', ""); + BLI_STATIC_ASSERT(sref.size() == 5, ""); + std::array(sref.find_first_of('o'))> compiles = {1}; + EXPECT_EQ(compiles[0], 1); +} } // namespace blender::tests -- cgit v1.2.3