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