Merge pull request #81822 from nlupugla/nodepath-slice
Add `NodePath::slice` method
This commit is contained in:
commit
1cc9190c70
|
@ -92,6 +92,14 @@ StringName NodePath::get_subname(int p_idx) const {
|
|||
return data->subpath[p_idx];
|
||||
}
|
||||
|
||||
int NodePath::get_total_name_count() const {
|
||||
if (!data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return data->path.size() + data->subpath.size();
|
||||
}
|
||||
|
||||
void NodePath::unref() {
|
||||
if (data && data->refcount.unref()) {
|
||||
memdelete(data);
|
||||
|
@ -229,6 +237,27 @@ StringName NodePath::get_concatenated_subnames() const {
|
|||
return data->concatenated_subpath;
|
||||
}
|
||||
|
||||
NodePath NodePath::slice(int p_begin, int p_end) const {
|
||||
const int name_count = get_name_count();
|
||||
const int total_count = get_total_name_count();
|
||||
|
||||
int begin = CLAMP(p_begin, -total_count, total_count);
|
||||
if (begin < 0) {
|
||||
begin += total_count;
|
||||
}
|
||||
int end = CLAMP(p_end, -total_count, total_count);
|
||||
if (end < 0) {
|
||||
end += total_count;
|
||||
}
|
||||
const int sub_begin = MAX(begin - name_count - 1, 0);
|
||||
const int sub_end = MAX(end - name_count, 0);
|
||||
|
||||
const Vector<StringName> names = get_names().slice(begin, end);
|
||||
const Vector<StringName> sub_names = get_subnames().slice(sub_begin, sub_end);
|
||||
const bool absolute = is_absolute() && (begin == 0);
|
||||
return NodePath(names, sub_names, absolute);
|
||||
}
|
||||
|
||||
NodePath NodePath::rel_path_to(const NodePath &p_np) const {
|
||||
ERR_FAIL_COND_V(!is_absolute(), NodePath());
|
||||
ERR_FAIL_COND_V(!p_np.is_absolute(), NodePath());
|
||||
|
@ -331,7 +360,7 @@ NodePath NodePath::simplified() const {
|
|||
}
|
||||
|
||||
NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) {
|
||||
if (p_path.size() == 0) {
|
||||
if (p_path.size() == 0 && !p_absolute) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -343,7 +372,7 @@ NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) {
|
|||
}
|
||||
|
||||
NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute) {
|
||||
if (p_path.size() == 0 && p_subpath.size() == 0) {
|
||||
if (p_path.size() == 0 && p_subpath.size() == 0 && !p_absolute) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,10 +57,12 @@ public:
|
|||
StringName get_name(int p_idx) const;
|
||||
int get_subname_count() const;
|
||||
StringName get_subname(int p_idx) const;
|
||||
int get_total_name_count() const;
|
||||
Vector<StringName> get_names() const;
|
||||
Vector<StringName> get_subnames() const;
|
||||
StringName get_concatenated_names() const;
|
||||
StringName get_concatenated_subnames() const;
|
||||
NodePath slice(int p_begin, int p_end = INT_MAX) const;
|
||||
|
||||
NodePath rel_path_to(const NodePath &p_np) const;
|
||||
NodePath get_as_property_path() const;
|
||||
|
|
|
@ -2033,6 +2033,7 @@ static void _register_variant_builtin_methods() {
|
|||
bind_method(NodePath, get_subname, sarray("idx"), varray());
|
||||
bind_method(NodePath, get_concatenated_names, sarray(), varray());
|
||||
bind_method(NodePath, get_concatenated_subnames, sarray(), varray());
|
||||
bind_method(NodePath, slice, sarray("begin", "end"), varray(INT_MAX));
|
||||
bind_method(NodePath, get_as_property_path, sarray(), varray());
|
||||
bind_method(NodePath, is_empty, sarray(), varray());
|
||||
|
||||
|
|
|
@ -199,6 +199,16 @@
|
|||
Returns [code]true[/code] if the node path has been constructed from an empty [String] ([code]""[/code]).
|
||||
</description>
|
||||
</method>
|
||||
<method name="slice" qualifiers="const">
|
||||
<return type="NodePath" />
|
||||
<param index="0" name="begin" type="int" />
|
||||
<param index="1" name="end" type="int" default="2147483647" />
|
||||
<description>
|
||||
Returns the slice of the [NodePath], from [param begin] (inclusive) to [param end] (exclusive), as a new [NodePath].
|
||||
The absolute value of [param begin] and [param end] will be clamped to the sum of [method get_name_count] and [method get_subname_count], so the default value for [param end] makes it slice to the end of the [NodePath] by default (i.e. [code]path.slice(1)[/code] is a shorthand for [code]path.slice(1, path.get_name_count() + path.get_subname_count())[/code]).
|
||||
If either [param begin] or [param end] are negative, they will be relative to the end of the [NodePath] (i.e. [code]path.slice(0, -2)[/code] is a shorthand for [code]path.slice(0, path.get_name_count() + path.get_subname_count() - 2)[/code]).
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<operators>
|
||||
<operator name="operator !=">
|
||||
|
|
|
@ -167,6 +167,59 @@ TEST_CASE("[NodePath] Empty path") {
|
|||
node_path_empty.is_empty(),
|
||||
"The node path should be considered empty.");
|
||||
}
|
||||
|
||||
TEST_CASE("[NodePath] Slice") {
|
||||
const NodePath node_path_relative = NodePath("Parent/Child:prop");
|
||||
const NodePath node_path_absolute = NodePath("/root/Parent/Child:prop");
|
||||
CHECK_MESSAGE(
|
||||
node_path_relative.slice(0, 2) == NodePath("Parent/Child"),
|
||||
"The slice lower bound should be inclusive and the slice upper bound should be exclusive.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_relative.slice(3) == NodePath(":prop"),
|
||||
"Slicing on the length of the path should return the last entry.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_relative.slice(1, 3) == NodePath("Child:prop"),
|
||||
"Slicing should include names and subnames.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_relative.slice(-1) == NodePath(":prop"),
|
||||
"Slicing on -1 should return the last entry.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_relative.slice(0, -1) == NodePath("Parent/Child"),
|
||||
"Slicing up to -1 should include the second-to-last entry.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_relative.slice(-2, -1) == NodePath("Child"),
|
||||
"Slicing from negative to negative should treat lower bound as inclusive and upper bound as exclusive.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_relative.slice(0, 10) == NodePath("Parent/Child:prop"),
|
||||
"Slicing past the length of the path should work like slicing up to the last entry.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_relative.slice(-10, 2) == NodePath("Parent/Child"),
|
||||
"Slicing negatively past the length of the path should work like slicing from the first entry.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_relative.slice(1, 1) == NodePath(""),
|
||||
"Slicing with a lower bound equal to upper bound should return empty path.");
|
||||
|
||||
CHECK_MESSAGE(
|
||||
node_path_absolute.slice(0, 2) == NodePath("/root/Parent"),
|
||||
"Slice from beginning of an absolute path should be an absolute path.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_absolute.slice(1, 4) == NodePath("Parent/Child:prop"),
|
||||
"Slice of an absolute path that does not start at the beginning should be a relative path.");
|
||||
CHECK_MESSAGE(
|
||||
node_path_absolute.slice(3, 4) == NodePath(":prop"),
|
||||
"Slice of an absolute path that does not start at the beginning should be a relative path.");
|
||||
|
||||
CHECK_MESSAGE(
|
||||
NodePath("").slice(0, 1) == NodePath(""),
|
||||
"Slice of an empty path should be an empty path.");
|
||||
CHECK_MESSAGE(
|
||||
NodePath("").slice(-1, 2) == NodePath(""),
|
||||
"Slice of an empty path should be an empty path.");
|
||||
CHECK_MESSAGE(
|
||||
NodePath("/").slice(-1, 2) == NodePath("/"),
|
||||
"Slice of an empty absolute path should be an empty absolute path.");
|
||||
}
|
||||
|
||||
} // namespace TestNodePath
|
||||
|
||||
#endif // TEST_NODE_PATH_H
|
||||
|
|
Loading…
Reference in New Issue