UE4隨筆——TMap自定義結構體鍵值

在UE4中,TMap是一個比較常用的容器,TMap的用法很簡單,本文將著重介紹一下TMap如何自定義結構體鍵值。

UE4隨筆

和眾多Map容器的實現方法類似,TMap也是通過將Key轉換為Hash,來建立對Value的索引,故而想要建立自定義結構體的Key,勢必要確保其可順利轉換為Value。下面是UE4中TMap中關于創建Hash的相關代碼:

    /** Defines how the map's pairs are hashed. */
    template<typename KeyType, typename ValueType, bool bInAllowDuplicateKeys>
    struct TDefaultMapKeyFuncs : BaseKeyFuncs<TPair<KeyType,ValueType>,KeyType,bInAllowDuplicateKeys>
    {
        typedef typename TTypeTraits<KeyType>::ConstPointerType KeyInitType;
        typedef const TPairInitializer<typename TTypeTraits<KeyType>::ConstInitType, typename TTypeTraits<ValueType>::ConstInitType>& ElementInitType;

        static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element)
        {
            return Element.Key;
        }
        static FORCEINLINE bool Matches(KeyInitType A,KeyInitType B)
        {
            return A == B;
        }
        static FORCEINLINE uint32 GetKeyHash(KeyInitType Key)
        {
            return GetTypeHash(Key);
        }
    };

其中GetSetKey()用于設置Key的值,Matches()用于進行Key值碰撞測試,GetTypeHash()用于獲取Key的Hash。根據以上代碼不難發現,在生成Hash的時候會會調用Key值結構體的“==”運算符來判斷兩個Key值是否相等,以及GetTypeHash()來產生Hash,由此我們可以得到第一種構建自定義結構體鍵值的方法:

struct FMyKey 
{
    FString Name;
    FString Type;

    FORCEINLINE friend bool operator==(const FMyKey& Lhs, const FMyKey& Rhs)
    {
        return (Lhs.Name == Rhs.Name) && (Lhs.Type == Rhs.Type);
    }


};
/** Case insensitive string hash function. */
FORCEINLINE uint32 GetTypeHash(const FMyKey& Key)
{
    return HashCombine(GetTypeHash(Key.Name), GetTypeHash(Key.Type));
}

該方法相當于是寫了Key結構體的“==”運算符函數和GetTypeHash函數,它們均為全局函數,這樣可以通過我們定義好的全局函數來生成Hash。
第二種方式就是定義自己的MapKeyFuncs來替代TDefaultMapKeyFuncs,代碼如下:

struct FMyStruct
{
    // String which identifies our key
    FString UniqueID;

    // Some state which doesn't affect struct identity
    float SomeFloat;

    explicit FMyStruct(float InFloat)
        :UniqueID(FGuid::NewGuid().ToString())
        , SomeFloat(InFloat)
    {
    }
};
template <typename ValueType>
struct TMyStructMapKeyFuncs :
    BaseKeyFuncs<
    TPair<FMyStruct, ValueType>,
    FString
    >
{
private:
    typedef BaseKeyFuncs<
        TPair<FMyStruct, ValueType>,
        FString
    > Super;

public:
    typedef typename Super::ElementInitType ElementInitType;
    typedef typename Super::KeyInitType     KeyInitType;

    static KeyInitType GetSetKey(ElementInitType Element)
    {
        return Element.Key.UniqueID;
    }

    static bool Matches(KeyInitType A, KeyInitType B)
    {
        return A.Compare(B, ESearchCase::CaseSensitive) == 0;
    }

    static uint32 GetKeyHash(KeyInitType Key)
    {
        return FCrc::StrCrc32(*Key);
    }
};
TMap<
    FMyStruct,
    int32,
    FDefaultSetAllocator,
    TMyStructMapKeyFuncs<int32>
> MyMapToInt32;

以上是自己在UE4的學習中總結的兩種構造自定義結構體鍵值的方法,希望對大家能有所幫助。

和眾多Map容器的實現方法類似,TMap也是通過將Key轉換為Hash,來建立對Value的索引,故而想要建立自定義結構體的Key,勢必要確保其可順利轉換為Value。下面是UE4中TMap中關于創建Hash的相關代碼:

    /** Defines how the map's pairs are hashed. */
    template<typename KeyType, typename ValueType, bool bInAllowDuplicateKeys>
    struct TDefaultMapKeyFuncs : BaseKeyFuncs<TPair<KeyType,ValueType>,KeyType,bInAllowDuplicateKeys>
    {
        typedef typename TTypeTraits<KeyType>::ConstPointerType KeyInitType;
        typedef const TPairInitializer<typename TTypeTraits<KeyType>::ConstInitType, typename TTypeTraits<ValueType>::ConstInitType>& ElementInitType;

        static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element)
        {
            return Element.Key;
        }
        static FORCEINLINE bool Matches(KeyInitType A,KeyInitType B)
        {
            return A == B;
        }
        static FORCEINLINE uint32 GetKeyHash(KeyInitType Key)
        {
            return GetTypeHash(Key);
        }
    };

其中GetSetKey()用于設置Key的值,Matches()用于進行Key值碰撞測試,GetTypeHash()用于獲取Key的Hash。根據以上代碼不難發現,在生成Hash的時候會會調用Key值結構體的“==”運算符來判斷兩個Key值是否相等,以及GetTypeHash()來產生Hash,由此我們可以得到第一種構建自定義結構體鍵值的方法:

struct FMyKey 
{
    FString Name;
    FString Type;

    FORCEINLINE friend bool operator==(const FMyKey& Lhs, const FMyKey& Rhs)
    {
        return (Lhs.Name == Rhs.Name) && (Lhs.Type == Rhs.Type);
    }


};
/** Case insensitive string hash function. */
FORCEINLINE uint32 GetTypeHash(const FMyKey& Key)
{
    return HashCombine(GetTypeHash(Key.Name), GetTypeHash(Key.Type));
}

該方法相當于是寫了Key結構體的“==”運算符函數和GetTypeHash函數,它們均為全局函數,這樣可以通過我們定義好的全局函數來生成Hash。
第二種方式就是定義自己的MapKeyFuncs來替代TDefaultMapKeyFuncs,代碼如下:

struct FMyStruct
{
    // String which identifies our key
    FString UniqueID;

    // Some state which doesn't affect struct identity
    float SomeFloat;

    explicit FMyStruct(float InFloat)
        :UniqueID(FGuid::NewGuid().ToString())
        , SomeFloat(InFloat)
    {
    }
};
template <typename ValueType>
struct TMyStructMapKeyFuncs :
    BaseKeyFuncs<
    TPair<FMyStruct, ValueType>,
    FString
    >
{
private:
    typedef BaseKeyFuncs<
        TPair<FMyStruct, ValueType>,
        FString
    > Super;

public:
    typedef typename Super::ElementInitType ElementInitType;
    typedef typename Super::KeyInitType     KeyInitType;

    static KeyInitType GetSetKey(ElementInitType Element)
    {
        return Element.Key.UniqueID;
    }

    static bool Matches(KeyInitType A, KeyInitType B)
    {
        return A.Compare(B, ESearchCase::CaseSensitive) == 0;
    }

    static uint32 GetKeyHash(KeyInitType Key)
    {
        return FCrc::StrCrc32(*Key);
    }
};
TMap<
    FMyStruct,
    int32,
    FDefaultSetAllocator,
    TMyStructMapKeyFuncs<int32>
> MyMapToInt32;

以上是自己在UE4的學習中總結的兩種構造自定義結構體鍵值的方法,希望對大家能有所幫助。

參考文獻:https://www.cnblogs.com/pengyingh/articles/5647879.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容