15 UE5 SetAllocator介绍

2024-03-06  本文已影响0人  游戏开发程序员

SetAllocator

#if !defined(DEFAULT_NUMBER_OF_ELEMENTS_PER_HASH_BUCKET)
#   define DEFAULT_NUMBER_OF_ELEMENTS_PER_HASH_BUCKET   2
#endif
#define DEFAULT_BASE_NUMBER_OF_HASH_BUCKETS             8
#define DEFAULT_MIN_NUMBER_OF_HASHED_ELEMENTS           4

TSetAllocator的模板参数

template<
    typename InSparseArrayAllocator               = TSparseArrayAllocator<>,
    typename InHashAllocator                      = TInlineAllocator<1,FDefaultAllocator>,
    uint32   AverageNumberOfElementsPerHashBucket = DEFAULT_NUMBER_OF_ELEMENTS_PER_HASH_BUCKET,
    uint32   BaseNumberOfHashBuckets              = DEFAULT_BASE_NUMBER_OF_HASH_BUCKETS,
    uint32   MinNumberOfHashedElements            = DEFAULT_MIN_NUMBER_OF_HASHED_ELEMENTS
    >
class TSetAllocator
{
......
    typedef InSparseArrayAllocator SparseArrayAllocator;
    typedef InHashAllocator        HashAllocator;
}

两个内存分配器的存储

TSparseArrayAllocator

/** Encapsulates the allocators used by a sparse array in a single type. */
template<typename InElementAllocator = FDefaultAllocator,typename InBitArrayAllocator = FDefaultBitArrayAllocator>
class TSparseArrayAllocator
{
public:

    typedef InElementAllocator ElementAllocator;
    typedef InBitArrayAllocator BitArrayAllocator;
};

union类型 TSparseArrayElementOrFreeListLink

template<typename ElementType>
union TSparseArrayElementOrFreeListLink
{
    // 有数据,这里是内容
    ElementType ElementData;

    // 无数据,这里是前后指针
    struct
    {
        int32 PrevFreeIndex;
        int32 NextFreeIndex;
    };
};

TSet添加元素

    template <typename ArgsType = ElementType>
    FSetElementId Emplace(ArgsType&& Args, bool* bIsAlreadyInSetPtr = nullptr)
    {
        // Create a new element.
        FSparseArrayAllocationInfo ElementAllocation = Elements.AddUninitialized();
        SetElementType& Element = *new (ElementAllocation) SetElementType(Forward<ArgsType>(Args));

        SizeType NewHashIndex = ElementAllocation.Index;

        uint32 KeyHash = KeyFuncs::GetKeyHash(KeyFuncs::GetSetKey(Element.Value));
        if (!TryReplaceExisting(KeyHash, Element, NewHashIndex, bIsAlreadyInSetPtr))
        {
            RehashOrLink(KeyHash, Element, NewHashIndex);
        }
        return FSetElementId(NewHashIndex);
    }

TryReplaceExisting分析

    bool TryReplaceExisting(uint32 KeyHash, SetElementType& Element, 
SizeType& InOutElementIndex, bool* bIsAlreadyInSetPtr)
    {
        bool bIsAlreadyInSet = false;
        // 如果不允许重复的KEY
        if (!KeyFuncs::bAllowDuplicateKeys)
        {
            // 添加第一个元素时不用麻烦了
            if (Elements.Num() != 1)
            {
                SizeType ExistingIndex = FindIndexByHash(KeyHash, KeyFuncs::GetSetKey(Element.Value));

                bIsAlreadyInSet = ExistingIndex != INDEX_NONE;
                if (bIsAlreadyInSet)
                {
                    //  用新的元素替换掉旧的
                    MoveByRelocate(Elements[ExistingIndex].Value, Element.Value);

                    Elements.RemoveAtUninitialized(InOutElementIndex);

                    // 返回索引的更新
                    InOutElementIndex = ExistingIndex;
                }
            }
        }
        if (bIsAlreadyInSetPtr)
        {
            *bIsAlreadyInSetPtr = bIsAlreadyInSet;
        }
        return bIsAlreadyInSet;
    }

TSet查找元素

    FORCEINLINE ElementType* Find(KeyInitType Key)
    {
        SizeType ElementIndex = FindIndexByHash(KeyFuncs::GetKeyHash(Key), Key);
        if (ElementIndex != INDEX_NONE)
        {
            return &Elements[ElementIndex].Value;
        }
        else
        {
            return nullptr;
        }
    }

FindIndexByHash函数分析

    template <typename ComparableKey>
    SizeType FindIndexByHash(uint32 KeyHash, const ComparableKey& Key) const
    {
        if (Elements.Num() == 0)
        {
            return INDEX_NONE;
        }

        FSetElementId* HashPtr      = Hash.GetAllocation();
        SizeType       ElementIndex = HashPtr[KeyHash & (HashSize - 1)].Index;
        for (;;)
        {
            if (ElementIndex == INDEX_NONE)
            {
                return INDEX_NONE;
            }

            if (KeyFuncs::Matches(KeyFuncs::GetSetKey(Elements[ElementIndex].Value), Key))
            {
                // 第一个匹配就返回,哪怕是有多个键匹配
                return ElementIndex;
            }

            // 不匹配 就继续在HashNextId 寻找
            ElementIndex = Elements[ElementIndex].HashNextId.Index;
        }
    }

TMap的区别

class TMap : public TSortableMapBase<InKeyType, InValueType, SetAllocator, KeyFuncs>
class TSortableMapBase : public TMapBase<KeyType, ValueType, SetAllocator, KeyFuncs>

    ValueType& Emplace(InitKeyType&& InKey, InitValueType&& InValue)
    {
        const FSetElementId PairId = Pairs.Emplace(
TPairInitializer<InitKeyType&&, InitValueType&&>(Forward<InitKeyType>(InKey), 
Forward<InitValueType>(InValue)));

        return Pairs[PairId].Value;
    }

    FORCEINLINE ValueType* Find(KeyConstPointerType Key)
    {
        if (auto* Pair = Pairs.Find(Key))
        {
            return &Pair->Value;
        }

        return nullptr;
    }

ElementSetType Pairs

typedef TPair<KeyType, ValueType> ElementType;
typedef TSet<ElementType, KeyFuncs, SetAllocator> ElementSetType;
ElementSetType Pairs
上一篇 下一篇

猜你喜欢

热点阅读