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