FName performance question

Hi,

I wrote a basic function that ensures all component names of a given actor are unique, and renames as necessary to enforce it.

Here is the code:

TSet<FString> ExistingNames; // Notice FString

TArray<USceneComponent*> Components;
Actor->GetComponents(Components);

for (USceneComponent* Component : Components) {
	FString Name = Component->GetName();
	FString NewName = Name;

	int32 Counter = 1;
	if (ExistingNames.Contains(NewName.ToLower())) {
		do {
			NewName = FString::Printf(TEXT("%s_%d"), *Name, Counter++);
		} while (ExistingNames.Contains(NewName.ToLower()));
	}

	while (!Component->Rename(*NewName, Actor, REN_Test)) {
		NewName = FString::Printf(TEXT("%s_%d"), *Name, Counter++);
	}

	Component->Rename(*NewName, Actor);
	ExistingNames.Add(NewName.ToLower());
}

A couple points about this code:

  • I want to maintain the original case of the name, but ensure case-insensitive uniqueness. This is why all the ToLower() are here.
  • I need this code to be as fast as possible.

I’ve heard that FName is better optimized for comparaisons, and is also case-insensitive. This would in theory make this code faster and eliminate the need for ToLower().

But here is my question: by using a TSet of FNames, instead of FStrings, I would need to change all occurences of ExistingNames.Contains(NewName.ToLower()) to ExistingNames.Contains(FName(*NewName)).

I wonder if the performance gains from querying and comparing FName values in the TSet would outweigh the overhead costs of casting to FName constantly. (I am also a bit unsure how this handles the point I made about case above).

What do you think?

FName is case-sensitive in editor builds, and case-insensitive in non-editor builds.

In case-insensitive situation, FName constructor (from string) performs a ToLower on the string, and then calculates a hash of it. So there is additional hashing overhead. At best, performance would be the same, but I’d expect it to be slightly worse than lowering + comparing strings directly.

FName is more optimized for comparison only when it is already constructed, since it’s gonna compare by hash which has been calculated at construction.