You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-21 14:57:09 +00:00
Add Span equality (== and !=) operators.
Exchange duplicate equality iteration implementations across `Vector` and `String` with the `Span` version, for a speed boost.
This commit is contained in:
@@ -303,28 +303,8 @@ String &String::operator+=(char32_t p_char) {
|
||||
}
|
||||
|
||||
bool String::operator==(const char *p_str) const {
|
||||
// compare Latin-1 encoded c-string
|
||||
int len = strlen(p_str);
|
||||
|
||||
if (length() != len) {
|
||||
return false;
|
||||
}
|
||||
if (is_empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int l = length();
|
||||
|
||||
const char32_t *dst = get_data();
|
||||
|
||||
// Compare char by char
|
||||
for (int i = 0; i < l; i++) {
|
||||
if ((char32_t)p_str[i] != dst[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
// Compare Latin-1 encoded c-string.
|
||||
return span() == Span(p_str, strlen(p_str)).reinterpret<uint8_t>();
|
||||
}
|
||||
|
||||
bool String::operator==(const wchar_t *p_str) const {
|
||||
@@ -338,40 +318,16 @@ bool String::operator==(const wchar_t *p_str) const {
|
||||
}
|
||||
|
||||
bool String::operator==(const char32_t *p_str) const {
|
||||
const int len = strlen(p_str);
|
||||
|
||||
if (length() != len) {
|
||||
return false;
|
||||
}
|
||||
if (is_empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return memcmp(ptr(), p_str, len * sizeof(char32_t)) == 0;
|
||||
// Compare UTF-32 encoded c-string.
|
||||
return span() == Span(p_str, strlen(p_str));
|
||||
}
|
||||
|
||||
bool String::operator==(const String &p_str) const {
|
||||
if (length() != p_str.length()) {
|
||||
return false;
|
||||
}
|
||||
if (is_empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return memcmp(ptr(), p_str.ptr(), length() * sizeof(char32_t)) == 0;
|
||||
return span() == p_str.span();
|
||||
}
|
||||
|
||||
bool String::operator==(const Span<char32_t> &p_str_range) const {
|
||||
const int len = p_str_range.size();
|
||||
|
||||
if (length() != len) {
|
||||
return false;
|
||||
}
|
||||
if (is_empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return memcmp(ptr(), p_str_range.ptr(), len * sizeof(char32_t)) == 0;
|
||||
return span() == p_str_range;
|
||||
}
|
||||
|
||||
bool operator==(const char *p_chr, const String &p_str) {
|
||||
@@ -384,7 +340,7 @@ bool operator==(const wchar_t *p_chr, const String &p_str) {
|
||||
return p_str == String::utf16((const char16_t *)p_chr);
|
||||
#else
|
||||
// wchar_t is 32-bi
|
||||
return p_str == String((const char32_t *)p_chr);
|
||||
return p_str == (const char32_t *)p_chr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -211,12 +211,7 @@ public:
|
||||
_FORCE_INLINE_ CharStringT(const T *p_cstr) { copy_from(p_cstr); }
|
||||
_FORCE_INLINE_ void operator=(const T *p_cstr) { copy_from(p_cstr); }
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const CharStringT<T> &p_other) const {
|
||||
if (length() != p_other.length()) {
|
||||
return false;
|
||||
}
|
||||
return memcmp(ptr(), p_other.ptr(), length() * sizeof(T)) == 0;
|
||||
}
|
||||
_FORCE_INLINE_ bool operator==(const CharStringT<T> &p_other) const { return span() == p_other.span(); }
|
||||
_FORCE_INLINE_ bool operator!=(const CharStringT<T> &p_other) const { return !(*this == p_other); }
|
||||
_FORCE_INLINE_ bool operator<(const CharStringT<T> &p_other) const {
|
||||
if (length() == 0) {
|
||||
|
||||
@@ -33,6 +33,24 @@
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/typedefs.h"
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
bool are_spans_equal(const LHS *p_lhs, const RHS *p_rhs, size_t p_size) {
|
||||
if constexpr (std::is_same_v<LHS, RHS> && std::is_fundamental_v<LHS>) {
|
||||
// Optimize trivial type comparison.
|
||||
// is_trivially_equality_comparable would help, but it doesn't exist.
|
||||
return memcmp(p_lhs, p_rhs, p_size * sizeof(LHS)) == 0;
|
||||
} else {
|
||||
// Normal case: Need to iterate the array manually.
|
||||
for (size_t j = 0; j < p_size; j++) {
|
||||
if (p_lhs[j] != p_rhs[j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent of std::span.
|
||||
// Represents a view into a contiguous memory space.
|
||||
// DISCLAIMER: This data type does not own the underlying buffer. DO NOT STORE IT.
|
||||
@@ -126,14 +144,7 @@ constexpr int64_t Span<T>::find(const T &p_val, uint64_t p_from) const {
|
||||
template <typename T>
|
||||
constexpr int64_t Span<T>::find_sequence(const Span<T> &p_span, uint64_t p_from) const {
|
||||
for (uint64_t i = p_from; i <= size() - p_span.size(); i++) {
|
||||
bool found = true;
|
||||
for (uint64_t j = 0; j < p_span.size(); j++) {
|
||||
if (ptr()[i + j] != p_span.ptr()[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if (are_spans_equal(ptr() + i, p_span.ptr(), p_span.size())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -154,14 +165,7 @@ constexpr int64_t Span<T>::rfind(const T &p_val, uint64_t p_from) const {
|
||||
template <typename T>
|
||||
constexpr int64_t Span<T>::rfind_sequence(const Span<T> &p_span, uint64_t p_from) const {
|
||||
for (int64_t i = p_from; i >= 0; i--) {
|
||||
bool found = true;
|
||||
for (uint64_t j = 0; j < p_span.size(); j++) {
|
||||
if (ptr()[i + j] != p_span.ptr()[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if (are_spans_equal(ptr() + i, p_span.ptr(), p_span.size())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -219,6 +223,16 @@ constexpr T Span<T>::max() const {
|
||||
return max_val;
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
bool operator==(const Span<LHS> &p_lhs, const Span<RHS> &p_rhs) {
|
||||
return p_lhs.size() == p_rhs.size() && are_spans_equal(p_lhs.ptr(), p_rhs.ptr(), p_lhs.size());
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
_FORCE_INLINE_ bool operator!=(const Span<LHS> &p_lhs, const Span<RHS> &p_rhs) {
|
||||
return !(p_lhs == p_rhs);
|
||||
}
|
||||
|
||||
// Zero-constructing Span initializes _ptr and _len to 0 (and thus empty).
|
||||
template <typename T>
|
||||
struct is_zero_constructible<Span<T>> : std::true_type {};
|
||||
|
||||
@@ -248,31 +248,8 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const Vector<T> &p_arr) const {
|
||||
Size s = size();
|
||||
if (s != p_arr.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Size i = 0; i < s; i++) {
|
||||
if (operator[](i) != p_arr[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const Vector<T> &p_arr) const {
|
||||
Size s = size();
|
||||
if (s != p_arr.size()) {
|
||||
return true;
|
||||
}
|
||||
for (Size i = 0; i < s; i++) {
|
||||
if (operator[](i) != p_arr[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool operator==(const Vector<T> &p_arr) const { return span() == p_arr.span(); }
|
||||
bool operator!=(const Vector<T> &p_arr) const { return span() != p_arr.span(); }
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ T &operator*() const {
|
||||
|
||||
@@ -61,6 +61,10 @@ TEST_CASE("[Span] Constexpr Validators") {
|
||||
static_assert(span_string[0] == U'1');
|
||||
static_assert(span_string[span_string.size() - 1] == U'5');
|
||||
|
||||
CHECK_EQ(span_string, span_string); // Same identity / ptr.
|
||||
CHECK_EQ(span_string, Span(U"1223456", 6)); // Different ptr.
|
||||
CHECK_EQ(span_string, Span("122345").reinterpret<uint8_t>()); // Different type.
|
||||
|
||||
int idx = 0;
|
||||
for (const char32_t &chr : span_string) {
|
||||
CHECK_EQ(chr, span_string[idx++]);
|
||||
|
||||
Reference in New Issue
Block a user