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 {
|
bool String::operator==(const char *p_str) const {
|
||||||
// compare Latin-1 encoded c-string
|
// Compare Latin-1 encoded c-string.
|
||||||
int len = strlen(p_str);
|
return span() == Span(p_str, strlen(p_str)).reinterpret<uint8_t>();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::operator==(const wchar_t *p_str) const {
|
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 {
|
bool String::operator==(const char32_t *p_str) const {
|
||||||
const int len = strlen(p_str);
|
// Compare UTF-32 encoded c-string.
|
||||||
|
return span() == Span(p_str, strlen(p_str));
|
||||||
if (length() != len) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (is_empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return memcmp(ptr(), p_str, len * sizeof(char32_t)) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::operator==(const String &p_str) const {
|
bool String::operator==(const String &p_str) const {
|
||||||
if (length() != p_str.length()) {
|
return span() == p_str.span();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (is_empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return memcmp(ptr(), p_str.ptr(), length() * sizeof(char32_t)) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::operator==(const Span<char32_t> &p_str_range) const {
|
bool String::operator==(const Span<char32_t> &p_str_range) const {
|
||||||
const int len = p_str_range.size();
|
return span() == p_str_range;
|
||||||
|
|
||||||
if (length() != len) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (is_empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return memcmp(ptr(), p_str_range.ptr(), len * sizeof(char32_t)) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const char *p_chr, const String &p_str) {
|
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);
|
return p_str == String::utf16((const char16_t *)p_chr);
|
||||||
#else
|
#else
|
||||||
// wchar_t is 32-bi
|
// wchar_t is 32-bi
|
||||||
return p_str == String((const char32_t *)p_chr);
|
return p_str == (const char32_t *)p_chr;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -211,12 +211,7 @@ public:
|
|||||||
_FORCE_INLINE_ CharStringT(const T *p_cstr) { copy_from(p_cstr); }
|
_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_ void operator=(const T *p_cstr) { copy_from(p_cstr); }
|
||||||
|
|
||||||
_FORCE_INLINE_ bool operator==(const CharStringT<T> &p_other) const {
|
_FORCE_INLINE_ bool operator==(const CharStringT<T> &p_other) const { return span() == p_other.span(); }
|
||||||
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 !(*this == p_other); }
|
_FORCE_INLINE_ bool operator!=(const CharStringT<T> &p_other) const { return !(*this == p_other); }
|
||||||
_FORCE_INLINE_ bool operator<(const CharStringT<T> &p_other) const {
|
_FORCE_INLINE_ bool operator<(const CharStringT<T> &p_other) const {
|
||||||
if (length() == 0) {
|
if (length() == 0) {
|
||||||
|
|||||||
@@ -33,6 +33,24 @@
|
|||||||
#include "core/error/error_macros.h"
|
#include "core/error/error_macros.h"
|
||||||
#include "core/typedefs.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.
|
// Equivalent of std::span.
|
||||||
// Represents a view into a contiguous memory space.
|
// Represents a view into a contiguous memory space.
|
||||||
// DISCLAIMER: This data type does not own the underlying buffer. DO NOT STORE IT.
|
// 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>
|
template <typename T>
|
||||||
constexpr int64_t Span<T>::find_sequence(const Span<T> &p_span, uint64_t p_from) const {
|
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++) {
|
for (uint64_t i = p_from; i <= size() - p_span.size(); i++) {
|
||||||
bool found = true;
|
if (are_spans_equal(ptr() + i, p_span.ptr(), p_span.size())) {
|
||||||
for (uint64_t j = 0; j < p_span.size(); j++) {
|
|
||||||
if (ptr()[i + j] != p_span.ptr()[j]) {
|
|
||||||
found = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found) {
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,14 +165,7 @@ constexpr int64_t Span<T>::rfind(const T &p_val, uint64_t p_from) const {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr int64_t Span<T>::rfind_sequence(const Span<T> &p_span, uint64_t p_from) const {
|
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--) {
|
for (int64_t i = p_from; i >= 0; i--) {
|
||||||
bool found = true;
|
if (are_spans_equal(ptr() + i, p_span.ptr(), p_span.size())) {
|
||||||
for (uint64_t j = 0; j < p_span.size(); j++) {
|
|
||||||
if (ptr()[i + j] != p_span.ptr()[j]) {
|
|
||||||
found = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found) {
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,6 +223,16 @@ constexpr T Span<T>::max() const {
|
|||||||
return max_val;
|
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).
|
// Zero-constructing Span initializes _ptr and _len to 0 (and thus empty).
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_zero_constructible<Span<T>> : std::true_type {};
|
struct is_zero_constructible<Span<T>> : std::true_type {};
|
||||||
|
|||||||
@@ -248,31 +248,8 @@ public:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Vector<T> &p_arr) const {
|
bool operator==(const Vector<T> &p_arr) const { return span() == p_arr.span(); }
|
||||||
Size s = size();
|
bool operator!=(const Vector<T> &p_arr) const { return span() != p_arr.span(); }
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Iterator {
|
struct Iterator {
|
||||||
_FORCE_INLINE_ T &operator*() const {
|
_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[0] == U'1');
|
||||||
static_assert(span_string[span_string.size() - 1] == U'5');
|
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;
|
int idx = 0;
|
||||||
for (const char32_t &chr : span_string) {
|
for (const char32_t &chr : span_string) {
|
||||||
CHECK_EQ(chr, span_string[idx++]);
|
CHECK_EQ(chr, span_string[idx++]);
|
||||||
|
|||||||
Reference in New Issue
Block a user