Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/templates/span.h
20952 views
1
/**************************************************************************/
2
/* span.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "core/error/error_macros.h"
34
#include "core/typedefs.h"
35
36
template <typename LHS, typename RHS>
37
bool are_spans_equal(const LHS *p_lhs, const RHS *p_rhs, size_t p_size) {
38
if constexpr (std::is_same_v<LHS, RHS> && std::is_fundamental_v<LHS>) {
39
// Optimize trivial type comparison.
40
// is_trivially_equality_comparable would help, but it doesn't exist.
41
return memcmp(p_lhs, p_rhs, p_size * sizeof(LHS)) == 0;
42
} else {
43
// Normal case: Need to iterate the array manually.
44
for (size_t j = 0; j < p_size; j++) {
45
if (p_lhs[j] != p_rhs[j]) {
46
return false;
47
}
48
}
49
50
return true;
51
}
52
}
53
54
// Equivalent of std::span.
55
// Represents a view into a contiguous memory space.
56
// DISCLAIMER: This data type does not own the underlying buffer. DO NOT STORE IT.
57
// Additionally, for the lifetime of the Span, do not resize the buffer, and do not insert or remove elements from it.
58
// Failure to respect this may lead to crashes or undefined behavior.
59
template <typename T>
60
class Span {
61
const T *_ptr = nullptr;
62
uint64_t _len = 0;
63
64
public:
65
static constexpr bool is_string = std::disjunction_v<
66
std::is_same<T, char>,
67
std::is_same<T, char16_t>,
68
std::is_same<T, char32_t>,
69
std::is_same<T, wchar_t>>;
70
71
_FORCE_INLINE_ constexpr Span() = default;
72
73
_FORCE_INLINE_ Span(const T *p_ptr, uint64_t p_len) :
74
_ptr(p_ptr), _len(p_len) {
75
#ifdef DEBUG_ENABLED
76
// TODO In c++20, make this check run only in non-consteval, and make this constructor constexpr.
77
if (_ptr == nullptr && _len > 0) {
78
ERR_PRINT("Internal bug, please report: Span was created from nullptr with size > 0. Recovering by using size = 0.");
79
_len = 0;
80
}
81
#endif
82
}
83
84
// Allows creating Span directly from C arrays and string literals.
85
template <size_t N>
86
_FORCE_INLINE_ constexpr Span(const T (&p_array)[N]) :
87
_ptr(p_array), _len(N) {
88
if constexpr (is_string) {
89
// Cut off the \0 terminator implicitly added to string literals.
90
if (N > 0 && p_array[N - 1] == '\0') {
91
_len--;
92
}
93
}
94
}
95
96
_FORCE_INLINE_ constexpr uint64_t size() const { return _len; }
97
_FORCE_INLINE_ constexpr bool is_empty() const { return _len == 0; }
98
99
_FORCE_INLINE_ constexpr const T *ptr() const { return _ptr; }
100
101
// NOTE: Span subscripts sanity check the bounds to avoid undefined behavior.
102
// This is slower than direct buffer access and can prevent autovectorization.
103
// If the bounds are known, use ptr() subscript instead.
104
_FORCE_INLINE_ constexpr const T &operator[](uint64_t p_idx) const {
105
CRASH_COND(p_idx >= _len);
106
return _ptr[p_idx];
107
}
108
109
_FORCE_INLINE_ constexpr const T *begin() const { return _ptr; }
110
_FORCE_INLINE_ constexpr const T *end() const { return _ptr + _len; }
111
112
template <typename T1>
113
_FORCE_INLINE_ constexpr Span<T1> reinterpret() const {
114
return Span<T1>(reinterpret_cast<const T1 *>(_ptr), _len * sizeof(T) / sizeof(T1));
115
}
116
117
// Algorithms.
118
constexpr int64_t find(const T &p_val, uint64_t p_from = 0) const;
119
template <typename T1 = T>
120
constexpr int64_t find_sequence(const Span<T1> &p_span, uint64_t p_from = 0) const;
121
constexpr int64_t rfind(const T &p_val, uint64_t p_from) const;
122
_FORCE_INLINE_ constexpr int64_t rfind(const T &p_val) const { return rfind(p_val, size() - 1); }
123
template <typename T1 = T>
124
constexpr int64_t rfind_sequence(const Span<T1> &p_span, uint64_t p_from) const;
125
template <typename T1 = T>
126
_FORCE_INLINE_ constexpr int64_t rfind_sequence(const Span<T1> &p_span) const { return rfind_sequence(p_span, size() - p_span.size()); }
127
constexpr uint64_t count(const T &p_val) const;
128
/// Find the index of the given value using binary search.
129
/// Note: Assumes that elements in the span are sorted. Otherwise, use find() instead.
130
template <typename Comparator = Comparator<T>>
131
constexpr uint64_t bisect(const T &p_value, bool p_before, Comparator compare = Comparator()) const;
132
133
/// The caller is responsible to ensure size() > 0.
134
constexpr T max() const;
135
};
136
137
template <typename T>
138
constexpr int64_t Span<T>::find(const T &p_val, uint64_t p_from) const {
139
for (uint64_t i = p_from; i < size(); i++) {
140
if (ptr()[i] == p_val) {
141
return i;
142
}
143
}
144
return -1;
145
}
146
147
template <typename T>
148
template <typename T1>
149
constexpr int64_t Span<T>::find_sequence(const Span<T1> &p_span, uint64_t p_from) const {
150
for (uint64_t i = p_from; i <= size() - p_span.size(); i++) {
151
if (are_spans_equal(ptr() + i, p_span.ptr(), p_span.size())) {
152
return i;
153
}
154
}
155
156
return -1;
157
}
158
159
template <typename T>
160
constexpr int64_t Span<T>::rfind(const T &p_val, uint64_t p_from) const {
161
DEV_ASSERT(p_from < size());
162
for (int64_t i = p_from; i >= 0; i--) {
163
if (ptr()[i] == p_val) {
164
return i;
165
}
166
}
167
return -1;
168
}
169
170
template <typename T>
171
template <typename T1>
172
constexpr int64_t Span<T>::rfind_sequence(const Span<T1> &p_span, uint64_t p_from) const {
173
DEV_ASSERT(p_from + p_span.size() <= size());
174
for (int64_t i = p_from; i >= 0; i--) {
175
if (are_spans_equal(ptr() + i, p_span.ptr(), p_span.size())) {
176
return i;
177
}
178
}
179
180
return -1;
181
}
182
183
template <typename T>
184
constexpr uint64_t Span<T>::count(const T &p_val) const {
185
uint64_t amount = 0;
186
for (uint64_t i = 0; i < size(); i++) {
187
if (ptr()[i] == p_val) {
188
amount++;
189
}
190
}
191
return amount;
192
}
193
194
template <typename T>
195
template <typename Comparator>
196
constexpr uint64_t Span<T>::bisect(const T &p_value, bool p_before, Comparator compare) const {
197
uint64_t lo = 0;
198
uint64_t hi = size();
199
if (p_before) {
200
while (lo < hi) {
201
const uint64_t mid = (lo + hi) / 2;
202
if (compare(ptr()[mid], p_value)) {
203
lo = mid + 1;
204
} else {
205
hi = mid;
206
}
207
}
208
} else {
209
while (lo < hi) {
210
const uint64_t mid = (lo + hi) / 2;
211
if (compare(p_value, ptr()[mid])) {
212
hi = mid;
213
} else {
214
lo = mid + 1;
215
}
216
}
217
}
218
return lo;
219
}
220
221
template <typename T>
222
constexpr T Span<T>::max() const {
223
DEV_ASSERT(size() > 0);
224
T max_val = _ptr[0];
225
for (size_t i = 1; i < _len; ++i) {
226
if (_ptr[i] > max_val) {
227
max_val = _ptr[i];
228
}
229
}
230
return max_val;
231
}
232
233
template <typename LHS, typename RHS>
234
bool operator==(const Span<LHS> &p_lhs, const Span<RHS> &p_rhs) {
235
return p_lhs.size() == p_rhs.size() && are_spans_equal(p_lhs.ptr(), p_rhs.ptr(), p_lhs.size());
236
}
237
238
template <typename LHS, typename RHS>
239
_FORCE_INLINE_ bool operator!=(const Span<LHS> &p_lhs, const Span<RHS> &p_rhs) {
240
return !(p_lhs == p_rhs);
241
}
242
243
// Zero-constructing Span initializes _ptr and _len to 0 (and thus empty).
244
template <typename T>
245
struct is_zero_constructible<Span<T>> : std::true_type {};
246
247