Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/variant/array.cpp
20852 views
1
/**************************************************************************/
2
/* array.cpp */
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
#include "array.h"
32
33
STATIC_ASSERT_INCOMPLETE_TYPE(class, Dictionary);
34
STATIC_ASSERT_INCOMPLETE_TYPE(class, Object);
35
STATIC_ASSERT_INCOMPLETE_TYPE(class, String);
36
37
#include "container_type_validate.h"
38
#include "core/math/math_funcs.h"
39
#include "core/object/script_language.h"
40
#include "core/templates/hashfuncs.h"
41
#include "core/templates/vector.h"
42
#include "core/variant/callable.h"
43
#include "core/variant/dictionary.h"
44
45
struct ArrayPrivate {
46
SafeRefCount refcount;
47
Vector<Variant> array;
48
Variant *read_only = nullptr; // If enabled, a pointer is used to a temporary value that is used to return read-only values.
49
ContainerTypeValidate typed;
50
51
ArrayPrivate() {}
52
ArrayPrivate(std::initializer_list<Variant> p_init) :
53
array(p_init) {}
54
};
55
56
void Array::_ref(const Array &p_from) const {
57
ArrayPrivate *_fp = p_from._p;
58
59
ERR_FAIL_NULL(_fp); // Should NOT happen.
60
61
if (_fp == _p) {
62
return; // whatever it is, nothing to do here move along
63
}
64
65
bool success = _fp->refcount.ref();
66
67
ERR_FAIL_COND(!success); // should really not happen either
68
69
_unref();
70
71
_p = _fp;
72
}
73
74
void Array::_unref() const {
75
if (!_p) {
76
return;
77
}
78
79
if (_p->refcount.unref()) {
80
if (_p->read_only) {
81
memdelete(_p->read_only);
82
}
83
memdelete(_p);
84
}
85
_p = nullptr;
86
}
87
88
Array::Iterator Array::begin() {
89
return Iterator(_p->array.ptrw(), _p->read_only);
90
}
91
92
Array::Iterator Array::end() {
93
return Iterator(_p->array.ptrw() + _p->array.size(), _p->read_only);
94
}
95
96
Array::ConstIterator Array::begin() const {
97
return ConstIterator(_p->array.ptr());
98
}
99
100
Array::ConstIterator Array::end() const {
101
return ConstIterator(_p->array.ptr() + _p->array.size());
102
}
103
104
Variant &Array::operator[](int p_idx) {
105
if (unlikely(_p->read_only)) {
106
*_p->read_only = _p->array[p_idx];
107
return *_p->read_only;
108
}
109
return _p->array.write[p_idx];
110
}
111
112
const Variant &Array::operator[](int p_idx) const {
113
return _p->array[p_idx];
114
}
115
116
int Array::size() const {
117
return _p->array.size();
118
}
119
120
bool Array::is_empty() const {
121
return _p->array.is_empty();
122
}
123
124
void Array::clear() {
125
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
126
_p->array.clear();
127
}
128
129
bool Array::operator==(const Array &p_array) const {
130
return recursive_equal(p_array, 0);
131
}
132
133
bool Array::operator!=(const Array &p_array) const {
134
return !recursive_equal(p_array, 0);
135
}
136
137
bool Array::recursive_equal(const Array &p_array, int recursion_count) const {
138
// Cheap checks
139
if (_p == p_array._p) {
140
return true;
141
}
142
const Vector<Variant> &a1 = _p->array;
143
const Vector<Variant> &a2 = p_array._p->array;
144
const int size = a1.size();
145
if (size != a2.size()) {
146
return false;
147
}
148
149
// Heavy O(n) check
150
if (recursion_count > MAX_RECURSION) {
151
ERR_PRINT("Max recursion reached");
152
return true;
153
}
154
recursion_count++;
155
for (int i = 0; i < size; i++) {
156
if (!a1[i].hash_compare(a2[i], recursion_count, false)) {
157
return false;
158
}
159
}
160
161
return true;
162
}
163
164
bool Array::operator<(const Array &p_array) const {
165
int a_len = size();
166
int b_len = p_array.size();
167
168
int min_cmp = MIN(a_len, b_len);
169
170
for (int i = 0; i < min_cmp; i++) {
171
if (operator[](i) < p_array[i]) {
172
return true;
173
} else if (p_array[i] < operator[](i)) {
174
return false;
175
}
176
}
177
178
return a_len < b_len;
179
}
180
181
bool Array::operator<=(const Array &p_array) const {
182
return !operator>(p_array);
183
}
184
bool Array::operator>(const Array &p_array) const {
185
return p_array < *this;
186
}
187
bool Array::operator>=(const Array &p_array) const {
188
return !operator<(p_array);
189
}
190
191
uint32_t Array::hash() const {
192
return recursive_hash(0);
193
}
194
195
uint32_t Array::recursive_hash(int recursion_count) const {
196
if (recursion_count > MAX_RECURSION) {
197
ERR_PRINT("Max recursion reached");
198
return 0;
199
}
200
201
uint32_t h = hash_murmur3_one_32(Variant::ARRAY);
202
203
recursion_count++;
204
for (int i = 0; i < _p->array.size(); i++) {
205
h = hash_murmur3_one_32(_p->array[i].recursive_hash(recursion_count), h);
206
}
207
return hash_fmix32(h);
208
}
209
210
void Array::operator=(const Array &p_array) {
211
if (this == &p_array) {
212
return;
213
}
214
_ref(p_array);
215
}
216
217
void Array::assign(const Array &p_array) {
218
const ContainerTypeValidate &typed = _p->typed;
219
const ContainerTypeValidate &source_typed = p_array._p->typed;
220
221
if (typed == source_typed || typed.type == Variant::NIL || (source_typed.type == Variant::OBJECT && typed.can_reference(source_typed))) {
222
// from same to same or
223
// from anything to variants or
224
// from subclasses to base classes
225
_p->array = p_array._p->array;
226
return;
227
}
228
229
const Variant *source = p_array._p->array.ptr();
230
int size = p_array._p->array.size();
231
232
if ((source_typed.type == Variant::NIL && typed.type == Variant::OBJECT) || (source_typed.type == Variant::OBJECT && source_typed.can_reference(typed))) {
233
// from variants to objects or
234
// from base classes to subclasses
235
for (int i = 0; i < size; i++) {
236
const Variant &element = source[i];
237
if (element.get_type() != Variant::NIL && (element.get_type() != Variant::OBJECT || !typed.validate_object(element, "assign"))) {
238
ERR_FAIL_MSG(vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(element.get_type()), Variant::get_type_name(typed.type)));
239
}
240
}
241
_p->array = p_array._p->array;
242
return;
243
}
244
if (typed.type == Variant::OBJECT || source_typed.type == Variant::OBJECT) {
245
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Array[%s]" to "Array[%s]".)", Variant::get_type_name(source_typed.type), Variant::get_type_name(typed.type)));
246
}
247
248
Vector<Variant> array;
249
array.resize(size);
250
Variant *data = array.ptrw();
251
252
if (source_typed.type == Variant::NIL && typed.type != Variant::OBJECT) {
253
// from variants to primitives
254
for (int i = 0; i < size; i++) {
255
const Variant *value = source + i;
256
if (value->get_type() == typed.type) {
257
data[i] = *value;
258
continue;
259
}
260
if (!Variant::can_convert_strict(value->get_type(), typed.type)) {
261
ERR_FAIL_MSG(vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
262
}
263
Callable::CallError ce;
264
Variant::construct(typed.type, data[i], &value, 1, ce);
265
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
266
}
267
} else if (Variant::can_convert_strict(source_typed.type, typed.type)) {
268
// from primitives to different convertible primitives
269
for (int i = 0; i < size; i++) {
270
const Variant *value = source + i;
271
Callable::CallError ce;
272
Variant::construct(typed.type, data[i], &value, 1, ce);
273
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %d from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
274
}
275
} else {
276
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Array[%s]" to "Array[%s]".)", Variant::get_type_name(source_typed.type), Variant::get_type_name(typed.type)));
277
}
278
279
_p->array = array;
280
}
281
282
void Array::push_back(const Variant &p_value) {
283
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
284
Variant value = p_value;
285
ERR_FAIL_COND(!_p->typed.validate(value, "push_back"));
286
_p->array.push_back(std::move(value));
287
}
288
289
void Array::append_array(const Array &p_array) {
290
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
291
292
if (!is_typed() || _p->typed.can_reference(p_array._p->typed)) {
293
_p->array.append_array(p_array._p->array);
294
return;
295
}
296
297
Vector<Variant> validated_array = p_array._p->array;
298
Variant *write = validated_array.ptrw();
299
for (int i = 0; i < validated_array.size(); ++i) {
300
ERR_FAIL_COND(!_p->typed.validate(write[i], "append_array"));
301
}
302
303
_p->array.append_array(validated_array);
304
}
305
306
Error Array::resize(int p_new_size) {
307
ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");
308
Variant::Type &variant_type = _p->typed.type;
309
int old_size = _p->array.size();
310
Error err = _p->array.resize_initialized(p_new_size);
311
if (!err && variant_type != Variant::NIL && variant_type != Variant::OBJECT) {
312
Variant *write = _p->array.ptrw();
313
for (int i = old_size; i < p_new_size; i++) {
314
VariantInternal::initialize(&write[i], variant_type);
315
}
316
}
317
return err;
318
}
319
320
Error Array::reserve(int p_new_size) {
321
ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");
322
return _p->array.reserve(p_new_size);
323
}
324
325
Error Array::insert(int p_pos, const Variant &p_value) {
326
ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");
327
Variant value = p_value;
328
ERR_FAIL_COND_V(!_p->typed.validate(value, "insert"), ERR_INVALID_PARAMETER);
329
330
if (p_pos < 0) {
331
// Relative offset from the end.
332
p_pos = _p->array.size() + p_pos;
333
}
334
335
ERR_FAIL_INDEX_V_MSG(p_pos, _p->array.size() + 1, ERR_INVALID_PARAMETER, vformat("The calculated index %d is out of bounds (the array has %d elements). Leaving the array untouched.", p_pos, _p->array.size()));
336
337
return _p->array.insert(p_pos, std::move(value));
338
}
339
340
void Array::fill(const Variant &p_value) {
341
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
342
Variant value = p_value;
343
ERR_FAIL_COND(!_p->typed.validate(value, "fill"));
344
_p->array.fill(std::move(value));
345
}
346
347
void Array::erase(const Variant &p_value) {
348
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
349
Variant value = p_value;
350
ERR_FAIL_COND(!_p->typed.validate(value, "erase"));
351
_p->array.erase(value);
352
}
353
354
Variant Array::front() const {
355
ERR_FAIL_COND_V_MSG(_p->array.is_empty(), Variant(), "Can't take value from empty array.");
356
return operator[](0);
357
}
358
359
Variant Array::back() const {
360
ERR_FAIL_COND_V_MSG(_p->array.is_empty(), Variant(), "Can't take value from empty array.");
361
return operator[](_p->array.size() - 1);
362
}
363
364
Variant Array::pick_random() const {
365
ERR_FAIL_COND_V_MSG(_p->array.is_empty(), Variant(), "Can't take value from empty array.");
366
return operator[](Math::rand() % _p->array.size());
367
}
368
369
int Array::find(const Variant &p_value, int p_from) const {
370
if (_p->array.is_empty()) {
371
return -1;
372
}
373
Variant value = p_value;
374
ERR_FAIL_COND_V(!_p->typed.validate(value, "find"), -1);
375
376
int ret = -1;
377
378
if (p_from < 0 || size() == 0) {
379
return ret;
380
}
381
382
for (int i = p_from; i < size(); i++) {
383
if (StringLikeVariantComparator::compare(_p->array[i], value)) {
384
ret = i;
385
break;
386
}
387
}
388
389
return ret;
390
}
391
392
int Array::find_custom(const Callable &p_callable, int p_from) const {
393
int ret = -1;
394
395
if (p_from < 0 || size() == 0) {
396
return ret;
397
}
398
399
const Variant *argptrs[1];
400
401
for (int i = p_from; i < size(); i++) {
402
const Variant &val = _p->array[i];
403
argptrs[0] = &val;
404
Variant res;
405
Callable::CallError ce;
406
p_callable.callp(argptrs, 1, res, ce);
407
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
408
ERR_FAIL_V_MSG(ret, vformat("Error calling method from 'find_custom': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
409
}
410
411
ERR_FAIL_COND_V_MSG(res.get_type() != Variant::Type::BOOL, ret, "Error on method from 'find_custom': Return type of callable must be boolean.");
412
if (res.operator bool()) {
413
return i;
414
}
415
}
416
417
return ret;
418
}
419
420
int Array::rfind(const Variant &p_value, int p_from) const {
421
if (_p->array.is_empty()) {
422
return -1;
423
}
424
Variant value = p_value;
425
ERR_FAIL_COND_V(!_p->typed.validate(value, "rfind"), -1);
426
427
if (p_from < 0) {
428
// Relative offset from the end
429
p_from = _p->array.size() + p_from;
430
}
431
if (p_from < 0 || p_from >= _p->array.size()) {
432
// Limit to array boundaries
433
p_from = _p->array.size() - 1;
434
}
435
436
for (int i = p_from; i >= 0; i--) {
437
if (StringLikeVariantComparator::compare(_p->array[i], value)) {
438
return i;
439
}
440
}
441
442
return -1;
443
}
444
445
int Array::rfind_custom(const Callable &p_callable, int p_from) const {
446
if (_p->array.is_empty()) {
447
return -1;
448
}
449
450
if (p_from < 0) {
451
// Relative offset from the end.
452
p_from = _p->array.size() + p_from;
453
}
454
if (p_from < 0 || p_from >= _p->array.size()) {
455
// Limit to array boundaries.
456
p_from = _p->array.size() - 1;
457
}
458
459
const Variant *argptrs[1];
460
461
for (int i = p_from; i >= 0; i--) {
462
const Variant &val = _p->array[i];
463
argptrs[0] = &val;
464
Variant res;
465
Callable::CallError ce;
466
p_callable.callp(argptrs, 1, res, ce);
467
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
468
ERR_FAIL_V_MSG(-1, vformat("Error calling method from 'rfind_custom': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
469
}
470
471
ERR_FAIL_COND_V_MSG(res.get_type() != Variant::Type::BOOL, -1, "Error on method from 'rfind_custom': Return type of callable must be boolean.");
472
if (res.operator bool()) {
473
return i;
474
}
475
}
476
477
return -1;
478
}
479
480
int Array::count(const Variant &p_value) const {
481
Variant value = p_value;
482
ERR_FAIL_COND_V(!_p->typed.validate(value, "count"), 0);
483
if (_p->array.is_empty()) {
484
return 0;
485
}
486
487
int amount = 0;
488
for (int i = 0; i < _p->array.size(); i++) {
489
if (StringLikeVariantComparator::compare(_p->array[i], value)) {
490
amount++;
491
}
492
}
493
494
return amount;
495
}
496
497
bool Array::has(const Variant &p_value) const {
498
Variant value = p_value;
499
ERR_FAIL_COND_V(!_p->typed.validate(value, "use 'has'"), false);
500
501
return find(value) != -1;
502
}
503
504
void Array::remove_at(int p_pos) {
505
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
506
507
if (p_pos < 0) {
508
// Relative offset from the end.
509
p_pos = _p->array.size() + p_pos;
510
}
511
512
ERR_FAIL_INDEX_MSG(p_pos, _p->array.size(), vformat("The calculated index %d is out of bounds (the array has %d elements). Leaving the array untouched.", p_pos, _p->array.size()));
513
514
_p->array.remove_at(p_pos);
515
}
516
517
void Array::set(int p_idx, const Variant &p_value) {
518
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
519
Variant value = p_value;
520
ERR_FAIL_COND(!_p->typed.validate(value, "set"));
521
522
_p->array.write[p_idx] = std::move(value);
523
}
524
525
const Variant &Array::get(int p_idx) const {
526
return operator[](p_idx);
527
}
528
529
Array Array::duplicate(bool p_deep) const {
530
return recursive_duplicate(p_deep, RESOURCE_DEEP_DUPLICATE_NONE, 0);
531
}
532
533
Array Array::duplicate_deep(ResourceDeepDuplicateMode p_deep_subresources_mode) const {
534
return recursive_duplicate(true, p_deep_subresources_mode, 0);
535
}
536
537
Array Array::recursive_duplicate(bool p_deep, ResourceDeepDuplicateMode p_deep_subresources_mode, int recursion_count) const {
538
Array new_arr;
539
new_arr._p->typed = _p->typed;
540
541
if (recursion_count > MAX_RECURSION) {
542
ERR_PRINT("Max recursion reached");
543
return new_arr;
544
}
545
546
if (p_deep) {
547
bool is_call_chain_end = recursion_count == 0;
548
549
recursion_count++;
550
int element_count = size();
551
new_arr.resize(element_count);
552
Variant *write = new_arr._p->array.ptrw();
553
for (int i = 0; i < element_count; i++) {
554
write[i] = get(i).recursive_duplicate(true, p_deep_subresources_mode, recursion_count);
555
}
556
557
// Variant::recursive_duplicate() may have created a remap cache by now.
558
if (is_call_chain_end) {
559
Resource::_teardown_duplicate_from_variant();
560
}
561
} else {
562
new_arr._p->array = _p->array;
563
}
564
565
return new_arr;
566
}
567
568
Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
569
Array result;
570
result._p->typed = _p->typed;
571
572
ERR_FAIL_COND_V_MSG(p_step == 0, result, "Slice step cannot be zero.");
573
574
const int s = size();
575
576
if (s == 0 || (p_begin < -s && p_step < 0) || (p_begin >= s && p_step > 0)) {
577
return result;
578
}
579
580
int begin = CLAMP(p_begin, -s, s - 1);
581
if (begin < 0) {
582
begin += s;
583
}
584
int end = CLAMP(p_end, -s - 1, s);
585
if (end < 0) {
586
end += s;
587
}
588
589
ERR_FAIL_COND_V_MSG(p_step > 0 && begin > end, result, "Slice step is positive, but bounds are decreasing.");
590
ERR_FAIL_COND_V_MSG(p_step < 0 && begin < end, result, "Slice step is negative, but bounds are increasing.");
591
592
int result_size = (end - begin) / p_step + (((end - begin) % p_step != 0) ? 1 : 0);
593
result.resize(result_size);
594
595
Variant *write = result._p->array.ptrw();
596
for (int src_idx = begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) {
597
write[dest_idx] = p_deep ? get(src_idx).duplicate(true) : get(src_idx);
598
src_idx += p_step;
599
}
600
601
return result;
602
}
603
604
Array Array::filter(const Callable &p_callable) const {
605
Array new_arr;
606
new_arr.resize(size());
607
new_arr._p->typed = _p->typed;
608
int accepted_count = 0;
609
610
const Variant *argptrs[1];
611
Variant *write = new_arr._p->array.ptrw();
612
for (int i = 0; i < size(); i++) {
613
argptrs[0] = &get(i);
614
615
Variant result;
616
Callable::CallError ce;
617
p_callable.callp(argptrs, 1, result, ce);
618
if (ce.error != Callable::CallError::CALL_OK) {
619
ERR_FAIL_V_MSG(Array(), vformat("Error calling method from 'filter': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
620
}
621
622
if (result.operator bool()) {
623
write[accepted_count] = get(i);
624
accepted_count++;
625
}
626
}
627
628
new_arr.resize(accepted_count);
629
630
return new_arr;
631
}
632
633
Array Array::map(const Callable &p_callable) const {
634
Array new_arr;
635
new_arr.resize(size());
636
637
const Variant *argptrs[1];
638
Variant *write = new_arr._p->array.ptrw();
639
for (int i = 0; i < size(); i++) {
640
argptrs[0] = &get(i);
641
642
Callable::CallError ce;
643
p_callable.callp(argptrs, 1, write[i], ce);
644
if (ce.error != Callable::CallError::CALL_OK) {
645
ERR_FAIL_V_MSG(Array(), vformat("Error calling method from 'map': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
646
}
647
}
648
649
return new_arr;
650
}
651
652
Variant Array::reduce(const Callable &p_callable, const Variant &p_accum) const {
653
int start = 0;
654
Variant ret = p_accum;
655
if (ret == Variant() && size() > 0) {
656
ret = front();
657
start = 1;
658
}
659
660
const Variant *argptrs[2];
661
for (int i = start; i < size(); i++) {
662
argptrs[0] = &ret;
663
argptrs[1] = &get(i);
664
665
Variant result;
666
Callable::CallError ce;
667
p_callable.callp(argptrs, 2, result, ce);
668
if (ce.error != Callable::CallError::CALL_OK) {
669
ERR_FAIL_V_MSG(Variant(), vformat("Error calling method from 'reduce': %s.", Variant::get_callable_error_text(p_callable, argptrs, 2, ce)));
670
}
671
ret = result;
672
}
673
674
return ret;
675
}
676
677
bool Array::any(const Callable &p_callable) const {
678
const Variant *argptrs[1];
679
for (int i = 0; i < size(); i++) {
680
argptrs[0] = &get(i);
681
682
Variant result;
683
Callable::CallError ce;
684
p_callable.callp(argptrs, 1, result, ce);
685
if (ce.error != Callable::CallError::CALL_OK) {
686
ERR_FAIL_V_MSG(false, vformat("Error calling method from 'any': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
687
}
688
689
if (result.operator bool()) {
690
// Return as early as possible when one of the conditions is `true`.
691
// This improves performance compared to relying on `filter(...).size() >= 1`.
692
return true;
693
}
694
}
695
696
return false;
697
}
698
699
bool Array::all(const Callable &p_callable) const {
700
const Variant *argptrs[1];
701
for (int i = 0; i < size(); i++) {
702
argptrs[0] = &get(i);
703
704
Variant result;
705
Callable::CallError ce;
706
p_callable.callp(argptrs, 1, result, ce);
707
if (ce.error != Callable::CallError::CALL_OK) {
708
ERR_FAIL_V_MSG(false, vformat("Error calling method from 'all': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
709
}
710
711
if (!(result.operator bool())) {
712
// Return as early as possible when one of the inverted conditions is `false`.
713
// This improves performance compared to relying on `filter(...).size() >= array_size().`.
714
return false;
715
}
716
}
717
718
return true;
719
}
720
721
struct _ArrayVariantSort {
722
_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
723
bool valid = false;
724
Variant res;
725
Variant::evaluate(Variant::OP_LESS, p_l, p_r, res, valid);
726
if (!valid) {
727
res = false;
728
}
729
return res;
730
}
731
};
732
733
void Array::sort() {
734
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
735
_p->array.sort_custom<_ArrayVariantSort>();
736
}
737
738
void Array::sort_custom(const Callable &p_callable) {
739
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
740
_p->array.sort_custom<CallableComparator, true>(p_callable);
741
}
742
743
void Array::shuffle() {
744
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
745
const int n = _p->array.size();
746
if (n < 2) {
747
return;
748
}
749
Variant *data = _p->array.ptrw();
750
for (int i = n - 1; i >= 1; i--) {
751
const int j = Math::rand() % (i + 1);
752
SWAP(data[i], data[j]);
753
}
754
}
755
756
int Array::bsearch(const Variant &p_value, bool p_before) const {
757
Variant value = p_value;
758
ERR_FAIL_COND_V(!_p->typed.validate(value, "binary search"), -1);
759
return _p->array.span().bisect<_ArrayVariantSort>(value, p_before);
760
}
761
762
int Array::bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before) const {
763
Variant value = p_value;
764
ERR_FAIL_COND_V(!_p->typed.validate(value, "custom binary search"), -1);
765
766
return _p->array.bsearch_custom<CallableComparator>(value, p_before, p_callable);
767
}
768
769
void Array::reverse() {
770
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
771
_p->array.reverse();
772
}
773
774
void Array::push_front(const Variant &p_value) {
775
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
776
Variant value = p_value;
777
ERR_FAIL_COND(!_p->typed.validate(value, "push_front"));
778
_p->array.insert(0, std::move(value));
779
}
780
781
Variant Array::pop_back() {
782
ERR_FAIL_COND_V_MSG(_p->read_only, Variant(), "Array is in read-only state.");
783
if (!_p->array.is_empty()) {
784
const int n = _p->array.size() - 1;
785
const Variant ret = _p->array.get(n);
786
_p->array.resize(n);
787
return ret;
788
}
789
return Variant();
790
}
791
792
Variant Array::pop_front() {
793
ERR_FAIL_COND_V_MSG(_p->read_only, Variant(), "Array is in read-only state.");
794
if (!_p->array.is_empty()) {
795
const Variant ret = _p->array.get(0);
796
_p->array.remove_at(0);
797
return ret;
798
}
799
return Variant();
800
}
801
802
Variant Array::pop_at(int p_pos) {
803
ERR_FAIL_COND_V_MSG(_p->read_only, Variant(), "Array is in read-only state.");
804
if (_p->array.is_empty()) {
805
// Return `null` without printing an error to mimic `pop_back()` and `pop_front()` behavior.
806
return Variant();
807
}
808
809
if (p_pos < 0) {
810
// Relative offset from the end
811
p_pos = _p->array.size() + p_pos;
812
}
813
814
ERR_FAIL_INDEX_V_MSG(
815
p_pos,
816
_p->array.size(),
817
Variant(),
818
vformat(
819
"The calculated index %s is out of bounds (the array has %s elements). Leaving the array untouched and returning `null`.",
820
p_pos,
821
_p->array.size()));
822
823
const Variant ret = _p->array.get(p_pos);
824
_p->array.remove_at(p_pos);
825
return ret;
826
}
827
828
Variant Array::min() const {
829
int array_size = size();
830
if (array_size == 0) {
831
return Variant();
832
}
833
834
int min_index = 0;
835
Variant is_less;
836
for (int i = 1; i < array_size; i++) {
837
bool valid;
838
Variant::evaluate(Variant::OP_LESS, _p->array[i], _p->array[min_index], is_less, valid);
839
if (!valid) {
840
return Variant(); //not a valid comparison
841
}
842
if (bool(is_less)) {
843
min_index = i;
844
}
845
}
846
return _p->array[min_index];
847
}
848
849
Variant Array::max() const {
850
int array_size = size();
851
if (array_size == 0) {
852
return Variant();
853
}
854
855
int max_index = 0;
856
Variant is_greater;
857
for (int i = 1; i < array_size; i++) {
858
bool valid;
859
Variant::evaluate(Variant::OP_GREATER, _p->array[i], _p->array[max_index], is_greater, valid);
860
if (!valid) {
861
return Variant(); //not a valid comparison
862
}
863
if (bool(is_greater)) {
864
max_index = i;
865
}
866
}
867
return _p->array[max_index];
868
}
869
870
const void *Array::id() const {
871
return _p;
872
}
873
874
Array::Array(const Array &p_from, uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
875
_p = memnew(ArrayPrivate);
876
_p->refcount.init();
877
set_typed(p_type, p_class_name, p_script);
878
assign(p_from);
879
}
880
881
void Array::set_typed(const ContainerType &p_element_type) {
882
set_typed(p_element_type.builtin_type, p_element_type.class_name, p_element_type.script);
883
}
884
885
void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
886
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
887
ERR_FAIL_COND_MSG(_p->array.size() > 0, "Type can only be set when array is empty.");
888
ERR_FAIL_COND_MSG(_p->refcount.get() > 1, "Type can only be set when array has no more than one user.");
889
ERR_FAIL_COND_MSG(_p->typed.type != Variant::NIL, "Type can only be set once.");
890
ERR_FAIL_COND_MSG(p_class_name != StringName() && p_type != Variant::OBJECT, "Class names can only be set for type OBJECT");
891
Ref<Script> script = p_script;
892
ERR_FAIL_COND_MSG(script.is_valid() && p_class_name == StringName(), "Script class can only be set together with base class name");
893
894
_p->typed.type = Variant::Type(p_type);
895
_p->typed.class_name = p_class_name;
896
_p->typed.script = script;
897
_p->typed.where = "TypedArray";
898
}
899
900
bool Array::is_typed() const {
901
return _p->typed.type != Variant::NIL;
902
}
903
904
bool Array::is_same_typed(const Array &p_other) const {
905
return _p->typed == p_other._p->typed;
906
}
907
908
bool Array::is_same_instance(const Array &p_other) const {
909
return _p == p_other._p;
910
}
911
912
ContainerType Array::get_element_type() const {
913
ContainerType type;
914
type.builtin_type = _p->typed.type;
915
type.class_name = _p->typed.class_name;
916
type.script = _p->typed.script;
917
return type;
918
}
919
920
uint32_t Array::get_typed_builtin() const {
921
return _p->typed.type;
922
}
923
924
StringName Array::get_typed_class_name() const {
925
return _p->typed.class_name;
926
}
927
928
Variant Array::get_typed_script() const {
929
return _p->typed.script;
930
}
931
932
Array Array::create_read_only() {
933
Array array;
934
array.make_read_only();
935
return array;
936
}
937
938
void Array::make_read_only() {
939
if (_p->read_only == nullptr) {
940
_p->read_only = memnew(Variant);
941
}
942
}
943
944
bool Array::is_read_only() const {
945
return _p->read_only != nullptr;
946
}
947
948
Span<Variant> Array::span() const {
949
return _p->array.span();
950
}
951
952
Array::Array(const Array &p_from) {
953
_p = nullptr;
954
_ref(p_from);
955
}
956
957
Array::Array(std::initializer_list<Variant> p_init) {
958
_p = memnew(ArrayPrivate);
959
_p->refcount.init();
960
_p->array = Vector<Variant>(p_init);
961
}
962
963
Array::Array() {
964
_p = memnew(ArrayPrivate);
965
_p->refcount.init();
966
}
967
968
Array::~Array() {
969
_unref();
970
}
971
972