Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a method to construct a NodePath from a StringName #72702

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

aaronfranke
Copy link
Member

@aaronfranke aaronfranke commented Feb 4, 2023

This allows constructing a NodePath directly from a StringName, which skips the String parsing logic, if the given StringName does not contain a slash or colon and can be used as-is.

I considered a constructor, but this would break all uses in the C++ code that construct NodePath from char * literals, and we need to depend on two other constructors anyway, so this uses a static method instead.

@Zireael07
Copy link
Contributor

I just ran into a situation where code that worked fine in 3.x doesn't due to this. Can this get merged into one of the patch releases?

@dalexeev
Copy link
Member

I considered a constructor, but this would break all uses in the C++ code that construct NodePath from char * literals, and we need to depend on two other constructors anyway, so this uses a static method instead.

Perhaps we just need to add the StringName(NodePath) and NodePath(StringName) constructors for GDScript only?

case STRING: {
static const Type valid[] = {
NODE_PATH,
STRING_NAME,
NIL
};

case STRING_NAME: {
static const Type valid[] = {
STRING,
NIL
};

case NODE_PATH: {
static const Type valid[] = {
STRING,
NIL
};

@aaronfranke
Copy link
Member Author

@dalexeev Good idea, pushed a change to add that, but we should also keep the method exposed for explicitness.

@dalexeev
Copy link
Member

See also:

add_constructor<VariantConstructNoArgs<String>>(sarray());
add_constructor<VariantConstructor<String, String>>(sarray("from"));
add_constructor<VariantConstructor<String, StringName>>(sarray("from"));
add_constructor<VariantConstructor<String, NodePath>>(sarray("from"));

add_constructor<VariantConstructNoArgs<StringName>>(sarray());
add_constructor<VariantConstructor<StringName, StringName>>(sarray("from"));
add_constructor<VariantConstructor<StringName, String>>(sarray("from"));
add_constructor<VariantConstructNoArgs<NodePath>>(sarray());
add_constructor<VariantConstructor<NodePath, NodePath>>(sarray("from"));
add_constructor<VariantConstructor<NodePath, String>>(sarray("from"));

Perhaps it makes sense to add constructors only in GDScript, even if we can't add them in C++?

Copy link
Member

@raulsntos raulsntos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me.

From the perspective of the C# bindings, I wonder if it'd be better to provide a static method or constructor that takes the StringName and just creates the NodePath assuming it contains no slashes or colons.

This would be an "unsafe" way to create a NodePath from StringName but I wouldn't expose this in the C# bindings. It would be used internally to create the NodePath when we can guarantee that the StringName doesn't contain slashes or colons. This means the logic to check this would be done in C# directly which would allow us to use IndexOfAny which is vectorized.

However, using IndexOfAny would require us to convert the StringName to a C# string first and that means creating a NodePath would take 2 interop calls instead of 1. I haven't benchmarked any of this so I don't know what would be better. It's possible that vectorizing the check for slashes and colons wouldn't bring much improvement over using this PR's static method, and I guess it's also possible to vectorize the C++ code in the future.

So, having said all that, I think this PR is still an improvement over the current way to create NodePaths from StringNames. I wonder if other language bindings authors are also interested in this API and would use it to either expose a way to create NodePaths from StringNames or, if it already exists, to improve their current implementation.

cc @Bromeon

// Check if p_string_name contains a slash or colon. If so, we need to parse it.
const char32_t *chars = string.ptr();
for (int i = 0; i < size; i++) {
if (unlikely(chars[i] == '/' || chars[i] == ':')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes me think it'd be interesting to see if we should add a findmc to complement findmk, and perhaps a contains_any or similar, there's many places that look for "is any of these present" and it'd be a good feature, just to think about I might look at an implementation later

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't that require constructing a Vector<char32_t>, so less efficient than as it is now?

But in general, that seems like a good idea.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For two arguments I'd tend to agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants