Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/templates/span.h
9973 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
// Equivalent of std::span.
37
// Represents a view into a contiguous memory space.
38
// DISCLAIMER: This data type does not own the underlying buffer. DO NOT STORE IT.
39
// Additionally, for the lifetime of the Span, do not resize the buffer, and do not insert or remove elements from it.
40
// Failure to respect this may lead to crashes or undefined behavior.
41
template <typename T>
42
class Span {
43
const T *_ptr = nullptr;
44
uint64_t _len = 0;
45
46
public:
47
static constexpr bool is_string = std::disjunction_v<
48
std::is_same<T, char>,
49
std::is_same<T, char16_t>,
50
std::is_same<T, char32_t>,
51
std::is_same<T, wchar_t>>;
52
53
_FORCE_INLINE_ constexpr Span() = default;
54
55
_FORCE_INLINE_ Span(const T *p_ptr, uint64_t p_len) :
56
_ptr(p_ptr), _len(p_len) {
57
#ifdef DEBUG_ENABLED
58
// TODO In c++20, make this check run only in non-consteval, and make this constructor constexpr.
59
if (_ptr == nullptr && _len > 0) {
60
ERR_PRINT("Internal bug, please report: Span was created from nullptr with size > 0. Recovering by using size = 0.");
61
_len = 0;
62
}
63
#endif
64
}
65
66
// Allows creating Span directly from C arrays and string literals.
67
template <size_t N>
68
_FORCE_INLINE_ constexpr Span(const T (&p_array)[N]) :
69
_ptr(p_array), _len(N) {
70
if constexpr (is_string) {
71
// Cut off the \0 terminator implicitly added to string literals.
72
if (N > 0 && p_array[N - 1] == '\0') {
73
_len--;
74
}
75
}
76
}
77
78
_FORCE_INLINE_ constexpr uint64_t size() const { return _len; }
79
_FORCE_INLINE_ constexpr bool is_empty() const { return _len == 0; }
80
81
_FORCE_INLINE_ constexpr const T *ptr() const { return _ptr; }
82
83
// NOTE: Span subscripts sanity check the bounds to avoid undefined behavior.
84
// This is slower than direct buffer access and can prevent autovectorization.
85
// If the bounds are known, use ptr() subscript instead.
86
_FORCE_INLINE_ constexpr const T &operator[](uint64_t p_idx) const {
87
CRASH_COND(p_idx >= _len);
88
return _ptr[p_idx];
89
}
90
91
_FORCE_INLINE_ constexpr const T *begin() const { return _ptr; }
92
_FORCE_INLINE_ constexpr const T *end() const { return _ptr + _len; }
93
94
template <typename T1>
95
_FORCE_INLINE_ constexpr Span<T1> reinterpret() const {
96
return Span<T1>(reinterpret_cast<const T1 *>(_ptr), _len * sizeof(T) / sizeof(T1));
97
}
98
99
// Algorithms.
100
constexpr int64_t find(const T &p_val, uint64_t p_from = 0) const;
101
constexpr int64_t rfind(const T &p_val, uint64_t p_from) const;
102
_FORCE_INLINE_ constexpr int64_t rfind(const T &p_val) const { return rfind(p_val, size() - 1); }
103
constexpr uint64_t count(const T &p_val) const;
104
/// Find the index of the given value using binary search.
105
/// Note: Assumes that elements in the span are sorted. Otherwise, use find() instead.
106
template <typename Comparator = Comparator<T>>
107
constexpr uint64_t bisect(const T &p_value, bool p_before, Comparator compare = Comparator()) const;
108
};
109
110
template <typename T>
111
constexpr int64_t Span<T>::find(const T &p_val, uint64_t p_from) const {
112
for (uint64_t i = p_from; i < size(); i++) {
113
if (ptr()[i] == p_val) {
114
return i;
115
}
116
}
117
return -1;
118
}
119
120
template <typename T>
121
constexpr int64_t Span<T>::rfind(const T &p_val, uint64_t p_from) const {
122
for (int64_t i = p_from; i >= 0; i--) {
123
if (ptr()[i] == p_val) {
124
return i;
125
}
126
}
127
return -1;
128
}
129
130
template <typename T>
131
constexpr uint64_t Span<T>::count(const T &p_val) const {
132
uint64_t amount = 0;
133
for (uint64_t i = 0; i < size(); i++) {
134
if (ptr()[i] == p_val) {
135
amount++;
136
}
137
}
138
return amount;
139
}
140
141
template <typename T>
142
template <typename Comparator>
143
constexpr uint64_t Span<T>::bisect(const T &p_value, bool p_before, Comparator compare) const {
144
uint64_t lo = 0;
145
uint64_t hi = size();
146
if (p_before) {
147
while (lo < hi) {
148
const uint64_t mid = (lo + hi) / 2;
149
if (compare(ptr()[mid], p_value)) {
150
lo = mid + 1;
151
} else {
152
hi = mid;
153
}
154
}
155
} else {
156
while (lo < hi) {
157
const uint64_t mid = (lo + hi) / 2;
158
if (compare(p_value, ptr()[mid])) {
159
hi = mid;
160
} else {
161
lo = mid + 1;
162
}
163
}
164
}
165
return lo;
166
}
167
168
// Zero-constructing Span initializes _ptr and _len to 0 (and thus empty).
169
template <typename T>
170
struct is_zero_constructible<Span<T>> : std::true_type {};
171
172