Badminton-Scoreboard/Libraries/libil2cpp/include/gc/AppendOnlyGCHashMap.h
2023-10-08 10:24:48 +08:00

128 lines
3.9 KiB
C++

#pragma once
#include "utils/Il2CppHashMap.h"
#include "utils/NonCopyable.h"
#include "GarbageCollector.h"
#include "os/FastReaderReaderWriterLock.h"
namespace il2cpp
{
namespace gc
{
template<class Key, class T,
class HashFcn,
class EqualKey = std::equal_to<Key> >
class AppendOnlyGCHashMap : public il2cpp::utils::NonCopyable
{
typedef Il2CppHashMap<Key, size_t, HashFcn, EqualKey> hash_map_type;
typedef typename Il2CppHashMap<Key, size_t, HashFcn, EqualKey>::const_iterator ConstIterator;
public:
typedef typename hash_map_type::key_type key_type;
typedef T data_type;
typedef typename hash_map_type::size_type size_type;
typedef typename hash_map_type::hasher hasher;
typedef typename hash_map_type::key_equal key_equal;
AppendOnlyGCHashMap() :
m_Data(NULL),
m_Size(0)
{
}
~AppendOnlyGCHashMap()
{
if (m_Data)
il2cpp::gc::GarbageCollector::FreeFixed(m_Data);
}
bool Contains(const Key& k)
{
os::FastReaderReaderWriterAutoSharedLock readLock(&lock);
return m_Map.find(k) != m_Map.end();
}
// Returns the existing value if the it was already added or inserts and returns value
T GetOrAdd(const Key& k, T value)
{
os::FastReaderReaderWriterAutoExclusiveLock writeLock(&lock);
ConstIterator iter = m_Map.find(k);
if (iter != m_Map.end())
{
size_t index = iter->second;
IL2CPP_ASSERT(index <= m_Map.size());
return m_Data[index];
}
if (m_Size == 0)
{
m_Size = 8;
m_Data = (T*)il2cpp::gc::GarbageCollector::AllocateFixed(m_Size * sizeof(T), NULL);
IL2CPP_ASSERT(m_Data);
}
else if (m_Map.size() == m_Size)
{
size_t newSize = 2 * m_Size;
T* newData = (T*)il2cpp::gc::GarbageCollector::AllocateFixed(newSize * sizeof(T), NULL);
MemCpyData memCpyData = { newData, m_Data, m_Size * sizeof(T) };
// perform memcpy with GC lock held so GC doesn't see torn pointer values.I think this is less of an issue with Boehm than other GCs, but being safe.
il2cpp::gc::GarbageCollector::CallWithAllocLockHeld(&CopyValues, &memCpyData);
il2cpp::gc::GarbageCollector::FreeFixed(m_Data);
GarbageCollector::SetWriteBarrier((void**)newData, m_Size * sizeof(T));
m_Size = newSize;
m_Data = newData;
IL2CPP_ASSERT(m_Data);
}
size_t index = m_Map.size();
m_Map.insert(std::make_pair(k, index));
m_Data[index] = value;
GarbageCollector::SetWriteBarrier((void**)(m_Data + index));
IL2CPP_ASSERT(m_Map.size() <= m_Size);
return value;
}
bool TryGetValue(const Key& k, T* value)
{
os::FastReaderReaderWriterAutoSharedLock readLock(&lock);
ConstIterator iter = m_Map.find(k);
if (iter == m_Map.end())
return false;
size_t index = iter->second;
IL2CPP_ASSERT(index <= m_Map.size());
*value = m_Data[index];
return true;
}
private:
struct MemCpyData
{
void* dst;
const void* src;
size_t size;
};
static void* CopyValues(void* arg)
{
MemCpyData* thisPtr = (MemCpyData*)arg;
memcpy(thisPtr->dst, thisPtr->src, thisPtr->size);
return NULL;
}
Il2CppHashMap<Key, size_t, HashFcn, EqualKey> m_Map;
T* m_Data;
size_t m_Size;
os::FastReaderReaderWriterLock lock;
};
}
}