Using Custom C++ Structs as TMap Keys in Unreal Engine
Tags: Hashing, Biq, Unreal Engine, Cpp, Metaprogramming

The title picture, selected to impress you with random code.

Intro

Structuring the data in your solutions is a vital part of success. Epic Games has made a quite convenient to integrate custom structs into Unreal Engine’s infrastructure. In this article, we take a look at how we can achieve integration of a custom struct into the Engine’s hashing system. This can be useful for comparisons and more excitingly, using your struct as a key value in a TMap instance.

Setup

Minimal Declaration

First let’s define our minimal data structure. We have three include statements, of which the third is of particular noteworthiness. The file HashMeIfYouCan.generated.h is an auto generated header, containing meta information gathered by the Unreal Header Tool. It is convetion, to set up your Engine Objects, with a consistent name for the file and type. In this case our type is called FHashMeIfYouCan. The F prefix is Unreal Engine’s (mandatory) naming convention for any engine struct. Notice also that we annotate the struct definition with Unreal Engine’s reflection and type system macros. We provide a BlueprintType struct specifier to ask for blueprint exposure. At the top of the structure body definition sits a bit of boiler plate code generation through the GENERATE_BODY macro, which generates all functionality needed to make your struct usable by the engine. Next we declare a string and designate it as a read only variable within the blueprint visual scripting system, through the BlueprintReadOnly specifier as paramter to the UPROPERTY macro.

Minimal setup for HashMeIfYouCan.h

If you load up for example, a level blueprint and create a new variable, you can now change it to be of type HashMeIfYouCan 🎉

Extending for hashing

The next step towards hash system integration, is to define a standardized way to compare two custom structures and generate a hash value on the basis of a struct instance. To cover all bases, we implement a triplet of constructors. A default constructor, a value constructor and a copy constructor. The default constructor is especially useful, if data structures like TArray or TMap will be used, since they might need to preallocate internal space. Now we add the comparison functions. To go with convention we implemented an Equals function, which in turn just compares the two string fields Impersonation of the current struct with the given reference. We use this Equals function, to implement an override of the == operator, associated with our custom struct. This will enable any code, using the == operator, to compare two instances of FHashMeIfYouCan. The last piece of the puzzle, is the hash function responsible for providing the Engine’s framework with a hash value for a specific type. To achieve this, we declare a function called GetTypeHash.

Extended HashMeIfYouCan.h header source.

Now for the actual implementation, we make use of a CRC hash function, provided by the Unreal Engine’s miscellaneous code base. The specific algorithm provided by FCrc::MemCrc32 has been inspired by Intel’s slice-by-8 implementation, release by Micheal Kounavis.

HashMeIfYouCan.cpp

Usage

Let’s look at how we might use our newly created hashable struct as a key value to a TMap instance.

UseStructAsMapKey.cpp

That’s it for now. Thank you for reading.