Skip to content

HashHelper

Shmellyorc edited this page Aug 31, 2026 · 4 revisions

HashHelper provides high-performance FNV-1a hashing utilities with caching support for both 32-bit and 64-bit hash values. It is used extensively throughout the engine for fast string identification, dictionary lookups, and cache keys.


Overview

Feature Description
Algorithm FNV-1a (Fowler-Noll-Vo) non-cryptographic hash
Hash Sizes 32-bit and 64-bit variants
Caching Thread-safe caching for frequently accessed strings
Performance Stack allocation for small strings, array pooling for large strings
Enum Support Hash enum values directly
Thread Safety Fully thread-safe

Why FNV-1a?

FNV-1a is a non-cryptographic hash algorithm designed for speed. It produces high-quality hash values suitable for hash tables, dictionaries, and other data structures. It is significantly faster than cryptographic hashes like SHA-256 or MD5.

Use Case Recommended
Dictionary keys
Cache lookups
String identification
Security-sensitive ❌ (use cryptographic hashes)

Why HashHelper Is Used Throughout The Engine

The engine relies on HashHelper as a core performance optimization. Comparing strings directly is slow and allocates memory. Instead, the engine compares precomputed hash values, which makes dictionary lookups, cache accesses, and identifier matching significantly faster.

The 32-bit variant is used for internal system identifiers where speed is critical and collision probability is acceptable. When you load an LDtk map, the engine needs to quickly find levels by name, layers by ID, and tilesets by name. LDtk settings use hashes to look up field values without string comparisons. Spritesheet entries are stored by hash so sprite bounds, patches, and pivots can be retrieved instantly. JsonHelper uses hashes when parsing LDtk field instances to look up settings by identifier. All of these lookups happen frequently during asset loading and runtime access, so the performance gain from hashing is substantial.

The 64-bit variant is used for global identifiers where collision probability must be extremely low. AssetManager uses hashes to look up assets in the cache by path. LDtkMap uses hashes for entity IDs since these identifiers are unique across the entire project. BeaconManager uses hashes for topic names in the pub/sub system so events can be routed quickly. Game and GameSettings use hashes for version verification during build validation. ContentTypeWriterReader uses hashes for save file version verification to prevent loading saves from incompatible game versions.


Performance

HashHelper is optimized for minimal GC pressure. Small strings are processed on the stack with no heap allocation. Large strings use ArrayPool to rent and return buffers, reducing GC overhead. The caching system only allocates on first access; subsequent calls return the cached value with no allocation.


Thread Safety

HashHelper is fully thread-safe. All caching operations use concurrent collections, and the methods themselves are stateless.


Methods

Cache32

Gets a cached 32-bit hash for the specified input. The result is cached after the first computation, making subsequent calls extremely fast.

uint hash = HashHelper.Cache32("Hello World");
uint enumHash = HashHelper.Cache32(MyEnum.Value);

Cache64

Gets a cached 64-bit hash for the specified input. The result is cached after the first computation, making subsequent calls extremely fast.

ulong hash = HashHelper.Cache64("Hello World");
ulong enumHash = HashHelper.Cache64(MyEnum.Value);

Hash32

Computes a 32-bit FNV-1a hash from a string, byte array, or span without caching.

uint hash = HashHelper.Hash32("Hello World");
byte[] data = Encoding.UTF8.GetBytes("Hello World");
uint hash2 = HashHelper.Hash32(data);

Hash64

Computes a 64-bit FNV-1a hash from a string, byte array, or span without caching.

ulong hash = HashHelper.Hash64("Hello World");
byte[] data = Encoding.UTF8.GetBytes("Hello World");
ulong hash2 = HashHelper.Hash64(data);

Back to Home

Clone this wiki locally