Ver código fonte

Add array slice method

Cameron Reikes 6 anos atrás
pai
commit
757c509437

+ 57 - 0
core/array.cpp

@@ -222,6 +222,63 @@ Array Array::duplicate(bool p_deep) const {
 
 
 	return new_arr;
 	return new_arr;
 }
 }
+
+int Array::_fix_slice_index(int p_index, int p_arr_len, int p_top_mod) {
+	p_index = CLAMP(p_index, -p_arr_len, p_arr_len + p_top_mod);
+	if (p_index < 0) {
+		p_index = (p_index % p_arr_len + p_arr_len) % p_arr_len; // positive modulo
+	}
+	return p_index;
+}
+
+int Array::_clamp_index(int p_index) const {
+	return CLAMP(p_index, -size() + 1, size() - 1);
+}
+
+#define ARRAY_GET_DEEP(idx, is_deep) is_deep ? get(idx).duplicate(is_deep) : get(idx)
+
+Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const { // like python, but inclusive on upper bound
+	Array new_arr;
+
+	p_begin = Array::_fix_slice_index(p_begin, size(), -1); // can't start out of range
+	p_end = Array::_fix_slice_index(p_end, size(), 0);
+
+	int x = p_begin;
+	int new_arr_i = 0;
+
+	ERR_FAIL_COND_V(p_step == 0, new_arr);
+	if (Array::_clamp_index(p_begin) == Array::_clamp_index(p_end)) { // don't include element twice
+		new_arr.resize(1);
+		// new_arr[0] = 1;
+		new_arr[0] = ARRAY_GET_DEEP(Array::_clamp_index(p_begin), p_deep);
+		return new_arr;
+	} else {
+		int element_count = ceil((int)MAX(0, (p_end - p_begin) / p_step)) + 1;
+		if (element_count == 1) { // delta going in wrong direction to reach end
+			new_arr.resize(0);
+			return new_arr;
+		}
+		new_arr.resize(element_count);
+	}
+
+	// if going backwards, have to have a different terminating condition
+	if (p_step < 0) {
+		while (x >= p_end) {
+			new_arr[new_arr_i] = ARRAY_GET_DEEP(Array::_clamp_index(x), p_deep);
+			x += p_step;
+			new_arr_i += 1;
+		}
+	} else if (p_step > 0) {
+		while (x <= p_end) {
+			new_arr[new_arr_i] = ARRAY_GET_DEEP(Array::_clamp_index(x), p_deep);
+			x += p_step;
+			new_arr_i += 1;
+		}
+	}
+
+	return new_arr;
+}
+
 struct _ArrayVariantSort {
 struct _ArrayVariantSort {
 
 
 	_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
 	_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {

+ 5 - 0
core/array.h

@@ -44,6 +44,9 @@ class Array {
 	void _ref(const Array &p_from) const;
 	void _ref(const Array &p_from) const;
 	void _unref() const;
 	void _unref() const;
 
 
+	int _clamp_index(int p_index) const;
+	static int _fix_slice_index(int p_index, int p_arr_len, int p_top_mod);
+
 public:
 public:
 	Variant &operator[](int p_idx);
 	Variant &operator[](int p_idx);
 	const Variant &operator[](int p_idx) const;
 	const Variant &operator[](int p_idx) const;
@@ -91,6 +94,8 @@ public:
 
 
 	Array duplicate(bool p_deep = false) const;
 	Array duplicate(bool p_deep = false) const;
 
 
+	Array slice(int p_begin, int p_end, int p_step = 1, bool p_deep = false) const;
+
 	Variant min() const;
 	Variant min() const;
 	Variant max() const;
 	Variant max() const;
 
 

+ 2 - 0
core/variant_call.cpp

@@ -534,6 +534,7 @@ struct _VariantCall {
 	VCALL_LOCALMEM2R(Array, bsearch);
 	VCALL_LOCALMEM2R(Array, bsearch);
 	VCALL_LOCALMEM4R(Array, bsearch_custom);
 	VCALL_LOCALMEM4R(Array, bsearch_custom);
 	VCALL_LOCALMEM1R(Array, duplicate);
 	VCALL_LOCALMEM1R(Array, duplicate);
+	VCALL_LOCALMEM4R(Array, slice);
 	VCALL_LOCALMEM0(Array, invert);
 	VCALL_LOCALMEM0(Array, invert);
 	VCALL_LOCALMEM0R(Array, max);
 	VCALL_LOCALMEM0R(Array, max);
 	VCALL_LOCALMEM0R(Array, min);
 	VCALL_LOCALMEM0R(Array, min);
@@ -1759,6 +1760,7 @@ void register_variant_methods() {
 	ADDFUNC4R(ARRAY, INT, Array, bsearch_custom, NIL, "value", OBJECT, "obj", STRING, "func", BOOL, "before", varray(true));
 	ADDFUNC4R(ARRAY, INT, Array, bsearch_custom, NIL, "value", OBJECT, "obj", STRING, "func", BOOL, "before", varray(true));
 	ADDFUNC0NC(ARRAY, NIL, Array, invert, varray());
 	ADDFUNC0NC(ARRAY, NIL, Array, invert, varray());
 	ADDFUNC1R(ARRAY, ARRAY, Array, duplicate, BOOL, "deep", varray(false));
 	ADDFUNC1R(ARRAY, ARRAY, Array, duplicate, BOOL, "deep", varray(false));
+	ADDFUNC4R(ARRAY, ARRAY, Array, slice, INT, "begin", INT, "end", INT, "step", BOOL, "deep", varray(1, false));
 	ADDFUNC0R(ARRAY, NIL, Array, max, varray());
 	ADDFUNC0R(ARRAY, NIL, Array, max, varray());
 	ADDFUNC0R(ARRAY, NIL, Array, min, varray());
 	ADDFUNC0R(ARRAY, NIL, Array, min, varray());
 
 

+ 15 - 0
doc/classes/Array.xml

@@ -124,6 +124,21 @@
 				[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
 				[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="slice">
+			<return type="Array">
+			</return>
+			<argument index="0" name="begin" type="int">
+			</argument>
+			<argument index="1" name="end" type="int">
+			</argument>
+			<argument index="2" name="step" type="int" default="1">
+			</argument>
+			<argument index="3" name="deep" type="bool" default="False">
+			</argument>
+			<description>
+				Duplicates the subset described in the function and returns it in an array, deeply copying the array if [code]deep[/code] is true. Lower and upper index are inclusive, with the [code]step[/code] describing the change between indices while slicing.
+			</description>
+		</method>
 		<method name="clear">
 		<method name="clear">
 			<description>
 			<description>
 				Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
 				Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].

+ 9 - 0
modules/gdnative/gdnative/array.cpp

@@ -327,6 +327,15 @@ godot_array GDAPI godot_array_duplicate(const godot_array *p_self, const godot_b
 	return res;
 	return res;
 }
 }
 
 
+godot_array GDAPI godot_array_slice(const godot_array *p_self, const godot_int p_begin, const godot_int p_end, const godot_int p_step, const godot_bool p_deep) {
+	const Array *self = (const Array *)p_self;
+	godot_array res;
+	Array *val = (Array *)&res;
+	memnew_placement(val, Array);
+	*val = self->slice(p_begin, p_end, p_step, p_deep);
+	return res;
+}
+
 godot_variant GDAPI godot_array_max(const godot_array *p_self) {
 godot_variant GDAPI godot_array_max(const godot_array *p_self) {
 	const Array *self = (const Array *)p_self;
 	const Array *self = (const Array *)p_self;
 	godot_variant v;
 	godot_variant v;

+ 11 - 0
modules/gdnative/gdnative_api.json

@@ -80,6 +80,17 @@
               ["const godot_vector2 *", "p_self"],
               ["const godot_vector2 *", "p_self"],
               ["const godot_vector2 *", "p_to"]
               ["const godot_vector2 *", "p_to"]
             ]
             ]
+          },
+          {
+            "name": "godot_array_slice",
+            "return_type": "godot_array",
+            "arguments": [
+              ["const godot_array *", "p_self"],
+              ["const godot_int", "p_begin"],
+              ["const godot_int", "p_end"],
+              ["const godot_int", "p_step"],
+              ["const godot_bool", "p_deep"]
+            ]
           }
           }
         ]
         ]
       },
       },

+ 2 - 0
modules/gdnative/include/gdnative/array.h

@@ -132,6 +132,8 @@ void GDAPI godot_array_destroy(godot_array *p_self);
 
 
 godot_array GDAPI godot_array_duplicate(const godot_array *p_self, const godot_bool p_deep);
 godot_array GDAPI godot_array_duplicate(const godot_array *p_self, const godot_bool p_deep);
 
 
+godot_array GDAPI godot_array_slice(const godot_array *p_self, const godot_int p_begin, const godot_int p_end, const godot_int p_delta, const godot_bool p_deep);
+
 godot_variant GDAPI godot_array_max(const godot_array *p_self);
 godot_variant GDAPI godot_array_max(const godot_array *p_self);
 
 
 godot_variant GDAPI godot_array_min(const godot_array *p_self);
 godot_variant GDAPI godot_array_min(const godot_array *p_self);