| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783 | /*************************************************************************//*  array.cpp                                                            *//*************************************************************************//*                       This file is part of:                           *//*                           GODOT ENGINE                                *//*                      https://godotengine.org                          *//*************************************************************************//* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 *//* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   *//*                                                                       *//* Permission is hereby granted, free of charge, to any person obtaining *//* a copy of this software and associated documentation files (the       *//* "Software"), to deal in the Software without restriction, including   *//* without limitation the rights to use, copy, modify, merge, publish,   *//* distribute, sublicense, and/or sell copies of the Software, and to    *//* permit persons to whom the Software is furnished to do so, subject to *//* the following conditions:                                             *//*                                                                       *//* The above copyright notice and this permission notice shall be        *//* included in all copies or substantial portions of the Software.       *//*                                                                       *//* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *//* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *//* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*//* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  *//* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  *//* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     *//* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                *//*************************************************************************/#include "array.h"#include "container_type_validate.h"#include "core/math/math_funcs.h"#include "core/object/class_db.h"#include "core/object/script_language.h"#include "core/templates/hashfuncs.h"#include "core/templates/search_array.h"#include "core/templates/vector.h"#include "core/variant/callable.h"#include "core/variant/variant.h"class ArrayPrivate {public:	SafeRefCount refcount;	Vector<Variant> array;	Variant *read_only = nullptr; // If enabled, a pointer is used to a temporary value that is used to return read-only values.	ContainerTypeValidate typed;};void Array::_ref(const Array &p_from) const {	ArrayPrivate *_fp = p_from._p;	ERR_FAIL_COND(!_fp); // should NOT happen.	if (unlikely(_fp->read_only != nullptr)) {		// If p_from is a read-only array, just copy the contents to avoid further modification.		_unref();		_p = memnew(ArrayPrivate);		_p->refcount.init();		_p->array = _fp->array;		_p->typed = _fp->typed;		return;	}	if (_fp == _p) {		return; // whatever it is, nothing to do here move along	}	bool success = _fp->refcount.ref();	ERR_FAIL_COND(!success); // should really not happen either	_unref();	_p = p_from._p;}void Array::_unref() const {	if (!_p) {		return;	}	if (_p->refcount.unref()) {		if (_p->read_only) {			memdelete(_p->read_only);		}		memdelete(_p);	}	_p = nullptr;}Variant &Array::operator[](int p_idx) {	if (unlikely(_p->read_only)) {		*_p->read_only = _p->array[p_idx];		return *_p->read_only;	}	return _p->array.write[p_idx];}const Variant &Array::operator[](int p_idx) const {	if (unlikely(_p->read_only)) {		*_p->read_only = _p->array[p_idx];		return *_p->read_only;	}	return _p->array[p_idx];}int Array::size() const {	return _p->array.size();}bool Array::is_empty() const {	return _p->array.is_empty();}void Array::clear() {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	_p->array.clear();}bool Array::operator==(const Array &p_array) const {	return recursive_equal(p_array, 0);}bool Array::operator!=(const Array &p_array) const {	return !recursive_equal(p_array, 0);}bool Array::recursive_equal(const Array &p_array, int recursion_count) const {	// Cheap checks	if (_p == p_array._p) {		return true;	}	const Vector<Variant> &a1 = _p->array;	const Vector<Variant> &a2 = p_array._p->array;	const int size = a1.size();	if (size != a2.size()) {		return false;	}	// Heavy O(n) check	if (recursion_count > MAX_RECURSION) {		ERR_PRINT("Max recursion reached");		return true;	}	recursion_count++;	for (int i = 0; i < size; i++) {		if (!a1[i].hash_compare(a2[i], recursion_count)) {			return false;		}	}	return true;}bool Array::operator<(const Array &p_array) const {	int a_len = size();	int b_len = p_array.size();	int min_cmp = MIN(a_len, b_len);	for (int i = 0; i < min_cmp; i++) {		if (operator[](i) < p_array[i]) {			return true;		} else if (p_array[i] < operator[](i)) {			return false;		}	}	return a_len < b_len;}bool Array::operator<=(const Array &p_array) const {	return !operator>(p_array);}bool Array::operator>(const Array &p_array) const {	return p_array < *this;}bool Array::operator>=(const Array &p_array) const {	return !operator<(p_array);}uint32_t Array::hash() const {	return recursive_hash(0);}uint32_t Array::recursive_hash(int recursion_count) const {	if (recursion_count > MAX_RECURSION) {		ERR_PRINT("Max recursion reached");		return 0;	}	uint32_t h = hash_murmur3_one_32(Variant::ARRAY);	recursion_count++;	for (int i = 0; i < _p->array.size(); i++) {		h = hash_murmur3_one_32(_p->array[i].recursive_hash(recursion_count), h);	}	return hash_fmix32(h);}bool Array::_assign(const Array &p_array) {	if (_p->typed.type != Variant::OBJECT && _p->typed.type == p_array._p->typed.type) {		//same type or untyped, just reference, should be fine		_ref(p_array);	} else if (_p->typed.type == Variant::NIL) { //from typed to untyped, must copy, but this is cheap anyway		_p->array = p_array._p->array;	} else if (p_array._p->typed.type == Variant::NIL) { //from untyped to typed, must try to check if they are all valid		if (_p->typed.type == Variant::OBJECT) {			//for objects, it needs full validation, either can be converted or fail			for (int i = 0; i < p_array._p->array.size(); i++) {				if (!_p->typed.validate(p_array._p->array[i], "assign")) {					return false;				}			}			_p->array = p_array._p->array; //then just copy, which is cheap anyway		} else {			//for non objects, we need to check if there is a valid conversion, which needs to happen one by one, so this is the worst case.			Vector<Variant> new_array;			new_array.resize(p_array._p->array.size());			for (int i = 0; i < p_array._p->array.size(); i++) {				Variant src_val = p_array._p->array[i];				if (src_val.get_type() == _p->typed.type) {					new_array.write[i] = src_val;				} else if (Variant::can_convert_strict(src_val.get_type(), _p->typed.type)) {					Variant *ptr = &src_val;					Callable::CallError ce;					Variant::construct(_p->typed.type, new_array.write[i], (const Variant **)&ptr, 1, ce);					if (ce.error != Callable::CallError::CALL_OK) {						ERR_FAIL_V_MSG(false, "Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");					}				} else {					ERR_FAIL_V_MSG(false, "Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");				}			}			_p->array = new_array;		}	} else if (_p->typed.can_reference(p_array._p->typed)) { //same type or compatible		_ref(p_array);	} else {		ERR_FAIL_V_MSG(false, "Assignment of arrays of incompatible types.");	}	return true;}void Array::operator=(const Array &p_array) {	if (this == &p_array) {		return;	}	_ref(p_array);}void Array::push_back(const Variant &p_value) {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	ERR_FAIL_COND(!_p->typed.validate(p_value, "push_back"));	_p->array.push_back(p_value);}void Array::append_array(const Array &p_array) {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	for (int i = 0; i < p_array.size(); ++i) {		ERR_FAIL_COND(!_p->typed.validate(p_array[i], "append_array"));	}	_p->array.append_array(p_array._p->array);}Error Array::resize(int p_new_size) {	ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");	return _p->array.resize(p_new_size);}Error Array::insert(int p_pos, const Variant &p_value) {	ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");	ERR_FAIL_COND_V(!_p->typed.validate(p_value, "insert"), ERR_INVALID_PARAMETER);	return _p->array.insert(p_pos, p_value);}void Array::fill(const Variant &p_value) {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	ERR_FAIL_COND(!_p->typed.validate(p_value, "fill"));	_p->array.fill(p_value);}void Array::erase(const Variant &p_value) {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	ERR_FAIL_COND(!_p->typed.validate(p_value, "erase"));	_p->array.erase(p_value);}Variant Array::front() const {	ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");	return operator[](0);}Variant Array::back() const {	ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");	return operator[](_p->array.size() - 1);}Variant Array::pick_random() const {	ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");	return operator[](Math::rand() % _p->array.size());}int Array::find(const Variant &p_value, int p_from) const {	ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find"), -1);	return _p->array.find(p_value, p_from);}int Array::rfind(const Variant &p_value, int p_from) const {	if (_p->array.size() == 0) {		return -1;	}	ERR_FAIL_COND_V(!_p->typed.validate(p_value, "rfind"), -1);	if (p_from < 0) {		// Relative offset from the end		p_from = _p->array.size() + p_from;	}	if (p_from < 0 || p_from >= _p->array.size()) {		// Limit to array boundaries		p_from = _p->array.size() - 1;	}	for (int i = p_from; i >= 0; i--) {		if (_p->array[i] == p_value) {			return i;		}	}	return -1;}int Array::find_last(const Variant &p_value) const {	ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find_last"), -1);	return rfind(p_value);}int Array::count(const Variant &p_value) const {	ERR_FAIL_COND_V(!_p->typed.validate(p_value, "count"), 0);	if (_p->array.size() == 0) {		return 0;	}	int amount = 0;	for (int i = 0; i < _p->array.size(); i++) {		if (_p->array[i] == p_value) {			amount++;		}	}	return amount;}bool Array::has(const Variant &p_value) const {	ERR_FAIL_COND_V(!_p->typed.validate(p_value, "use 'has'"), false);	return _p->array.find(p_value, 0) != -1;}void Array::remove_at(int p_pos) {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	_p->array.remove_at(p_pos);}void Array::set(int p_idx, const Variant &p_value) {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	ERR_FAIL_COND(!_p->typed.validate(p_value, "set"));	operator[](p_idx) = p_value;}const Variant &Array::get(int p_idx) const {	return operator[](p_idx);}Array Array::duplicate(bool p_deep) const {	return recursive_duplicate(p_deep, 0);}Array Array::recursive_duplicate(bool p_deep, int recursion_count) const {	Array new_arr;	if (recursion_count > MAX_RECURSION) {		ERR_PRINT("Max recursion reached");		return new_arr;	}	int element_count = size();	new_arr.resize(element_count);	new_arr._p->typed = _p->typed;	if (p_deep) {		recursion_count++;		for (int i = 0; i < element_count; i++) {			new_arr[i] = get(i).recursive_duplicate(true, recursion_count);		}	} else {		for (int i = 0; i < element_count; i++) {			new_arr[i] = get(i);		}	}	return new_arr;}Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {	Array result;	result._p->typed = _p->typed;	ERR_FAIL_COND_V_MSG(p_step == 0, result, "Slice step cannot be zero.");	const int s = size();	int begin = CLAMP(p_begin, -s, s);	if (begin < 0) {		begin += s;	}	int end = CLAMP(p_end, -s, s);	if (end < 0) {		end += s;	}	ERR_FAIL_COND_V_MSG(p_step > 0 && begin > end, result, "Slice is positive, but bounds is decreasing.");	ERR_FAIL_COND_V_MSG(p_step < 0 && begin < end, result, "Slice is negative, but bounds is increasing.");	int result_size = (end - begin) / p_step;	result.resize(result_size);	for (int src_idx = begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) {		result[dest_idx] = p_deep ? get(src_idx).duplicate(true) : get(src_idx);		src_idx += p_step;	}	return result;}Array Array::filter(const Callable &p_callable) const {	Array new_arr;	new_arr.resize(size());	new_arr._p->typed = _p->typed;	int accepted_count = 0;	const Variant *argptrs[1];	for (int i = 0; i < size(); i++) {		argptrs[0] = &get(i);		Variant result;		Callable::CallError ce;		p_callable.callp(argptrs, 1, result, ce);		if (ce.error != Callable::CallError::CALL_OK) {			ERR_FAIL_V_MSG(Array(), "Error calling method from 'filter': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));		}		if (result.operator bool()) {			new_arr[accepted_count] = get(i);			accepted_count++;		}	}	new_arr.resize(accepted_count);	return new_arr;}Array Array::map(const Callable &p_callable) const {	Array new_arr;	new_arr.resize(size());	const Variant *argptrs[1];	for (int i = 0; i < size(); i++) {		argptrs[0] = &get(i);		Variant result;		Callable::CallError ce;		p_callable.callp(argptrs, 1, result, ce);		if (ce.error != Callable::CallError::CALL_OK) {			ERR_FAIL_V_MSG(Array(), "Error calling method from 'map': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));		}		new_arr[i] = result;	}	return new_arr;}Variant Array::reduce(const Callable &p_callable, const Variant &p_accum) const {	int start = 0;	Variant ret = p_accum;	if (ret == Variant() && size() > 0) {		ret = front();		start = 1;	}	const Variant *argptrs[2];	for (int i = start; i < size(); i++) {		argptrs[0] = &ret;		argptrs[1] = &get(i);		Variant result;		Callable::CallError ce;		p_callable.callp(argptrs, 2, result, ce);		if (ce.error != Callable::CallError::CALL_OK) {			ERR_FAIL_V_MSG(Variant(), "Error calling method from 'reduce': " + Variant::get_callable_error_text(p_callable, argptrs, 2, ce));		}		ret = result;	}	return ret;}bool Array::any(const Callable &p_callable) const {	const Variant *argptrs[1];	for (int i = 0; i < size(); i++) {		argptrs[0] = &get(i);		Variant result;		Callable::CallError ce;		p_callable.callp(argptrs, 1, result, ce);		if (ce.error != Callable::CallError::CALL_OK) {			ERR_FAIL_V_MSG(false, "Error calling method from 'any': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));		}		if (result.operator bool()) {			// Return as early as possible when one of the conditions is `true`.			// This improves performance compared to relying on `filter(...).size() >= 1`.			return true;		}	}	return false;}bool Array::all(const Callable &p_callable) const {	const Variant *argptrs[1];	for (int i = 0; i < size(); i++) {		argptrs[0] = &get(i);		Variant result;		Callable::CallError ce;		p_callable.callp(argptrs, 1, result, ce);		if (ce.error != Callable::CallError::CALL_OK) {			ERR_FAIL_V_MSG(false, "Error calling method from 'all': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));		}		if (!(result.operator bool())) {			// Return as early as possible when one of the inverted conditions is `false`.			// This improves performance compared to relying on `filter(...).size() >= array_size().`.			return false;		}	}	return true;}struct _ArrayVariantSort {	_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {		bool valid = false;		Variant res;		Variant::evaluate(Variant::OP_LESS, p_l, p_r, res, valid);		if (!valid) {			res = false;		}		return res;	}};void Array::sort() {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	_p->array.sort_custom<_ArrayVariantSort>();}void Array::sort_custom(const Callable &p_callable) {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	_p->array.sort_custom<CallableComparator, true>(p_callable);}void Array::shuffle() {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	const int n = _p->array.size();	if (n < 2) {		return;	}	Variant *data = _p->array.ptrw();	for (int i = n - 1; i >= 1; i--) {		const int j = Math::rand() % (i + 1);		const Variant tmp = data[j];		data[j] = data[i];		data[i] = tmp;	}}int Array::bsearch(const Variant &p_value, bool p_before) {	ERR_FAIL_COND_V(!_p->typed.validate(p_value, "binary search"), -1);	SearchArray<Variant, _ArrayVariantSort> avs;	return avs.bisect(_p->array.ptrw(), _p->array.size(), p_value, p_before);}int Array::bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before) {	ERR_FAIL_COND_V(!_p->typed.validate(p_value, "custom binary search"), -1);	return _p->array.bsearch_custom<CallableComparator>(p_value, p_before, p_callable);}void Array::reverse() {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	_p->array.reverse();}void Array::push_front(const Variant &p_value) {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	ERR_FAIL_COND(!_p->typed.validate(p_value, "push_front"));	_p->array.insert(0, p_value);}Variant Array::pop_back() {	ERR_FAIL_COND_V_MSG(_p->read_only, Variant(), "Array is in read-only state.");	if (!_p->array.is_empty()) {		const int n = _p->array.size() - 1;		const Variant ret = _p->array.get(n);		_p->array.resize(n);		return ret;	}	return Variant();}Variant Array::pop_front() {	ERR_FAIL_COND_V_MSG(_p->read_only, Variant(), "Array is in read-only state.");	if (!_p->array.is_empty()) {		const Variant ret = _p->array.get(0);		_p->array.remove_at(0);		return ret;	}	return Variant();}Variant Array::pop_at(int p_pos) {	ERR_FAIL_COND_V_MSG(_p->read_only, Variant(), "Array is in read-only state.");	if (_p->array.is_empty()) {		// Return `null` without printing an error to mimic `pop_back()` and `pop_front()` behavior.		return Variant();	}	if (p_pos < 0) {		// Relative offset from the end		p_pos = _p->array.size() + p_pos;	}	ERR_FAIL_INDEX_V_MSG(			p_pos,			_p->array.size(),			Variant(),			vformat(					"The calculated index %s is out of bounds (the array has %s elements). Leaving the array untouched and returning `null`.",					p_pos,					_p->array.size()));	const Variant ret = _p->array.get(p_pos);	_p->array.remove_at(p_pos);	return ret;}Variant Array::min() const {	Variant minval;	for (int i = 0; i < size(); i++) {		if (i == 0) {			minval = get(i);		} else {			bool valid;			Variant ret;			Variant test = get(i);			Variant::evaluate(Variant::OP_LESS, test, minval, ret, valid);			if (!valid) {				return Variant(); //not a valid comparison			}			if (bool(ret)) {				//is less				minval = test;			}		}	}	return minval;}Variant Array::max() const {	Variant maxval;	for (int i = 0; i < size(); i++) {		if (i == 0) {			maxval = get(i);		} else {			bool valid;			Variant ret;			Variant test = get(i);			Variant::evaluate(Variant::OP_GREATER, test, maxval, ret, valid);			if (!valid) {				return Variant(); //not a valid comparison			}			if (bool(ret)) {				//is less				maxval = test;			}		}	}	return maxval;}const void *Array::id() const {	return _p;}Array::Array(const Array &p_from, uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {	_p = memnew(ArrayPrivate);	_p->refcount.init();	set_typed(p_type, p_class_name, p_script);	_assign(p_from);}bool Array::typed_assign(const Array &p_other) {	return _assign(p_other);}void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");	ERR_FAIL_COND_MSG(_p->array.size() > 0, "Type can only be set when array is empty.");	ERR_FAIL_COND_MSG(_p->refcount.get() > 1, "Type can only be set when array has no more than one user.");	ERR_FAIL_COND_MSG(_p->typed.type != Variant::NIL, "Type can only be set once.");	ERR_FAIL_COND_MSG(p_class_name != StringName() && p_type != Variant::OBJECT, "Class names can only be set for type OBJECT");	Ref<Script> script = p_script;	ERR_FAIL_COND_MSG(script.is_valid() && p_class_name == StringName(), "Script class can only be set together with base class name");	_p->typed.type = Variant::Type(p_type);	_p->typed.class_name = p_class_name;	_p->typed.script = script;	_p->typed.where = "TypedArray";}bool Array::is_typed() const {	return _p->typed.type != Variant::NIL;}uint32_t Array::get_typed_builtin() const {	return _p->typed.type;}StringName Array::get_typed_class_name() const {	return _p->typed.class_name;}Variant Array::get_typed_script() const {	return _p->typed.script;}void Array::set_read_only(bool p_enable) {	if (p_enable == bool(_p->read_only != nullptr)) {		return;	}	if (p_enable) {		_p->read_only = memnew(Variant);	} else {		memdelete(_p->read_only);		_p->read_only = nullptr;	}}bool Array::is_read_only() const {	return _p->read_only != nullptr;}Array::Array(const Array &p_from) {	_p = nullptr;	_ref(p_from);}Array::Array() {	_p = memnew(ArrayPrivate);	_p->refcount.init();}Array::~Array() {	_unref();}
 |