257 lines
9.3 KiB
C
257 lines
9.3 KiB
C
|
#pragma once
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <vector>
|
||
|
#include <functional>
|
||
|
#include "NonCopyable.h"
|
||
|
|
||
|
namespace il2cpp
|
||
|
{
|
||
|
namespace utils
|
||
|
{
|
||
|
namespace collections
|
||
|
{
|
||
|
// Memory compact, map-like data structure that stores values and
|
||
|
// is a able to compute the key from the value with the provided converter
|
||
|
// This data structure is perfect to storing values that will not be changed
|
||
|
// for the duration of program (like type metadata) and need fast querying
|
||
|
//
|
||
|
// It is able to store multiple values associated with a single key, and query them through find()
|
||
|
// find_first() is a special case find() which improves performance for cases where we don't store multiple values for each key
|
||
|
template<typename TKey, typename TValue, typename TValueToKeyConverter, typename TKeyLess = std::less<TKey>, typename TKeyEquals = std::equal_to<TKey> >
|
||
|
class ArrayValueMap : NonCopyable
|
||
|
{
|
||
|
public:
|
||
|
typedef ArrayValueMap<TKey, TValue, TValueToKeyConverter, TKeyLess, TKeyEquals> map_type;
|
||
|
typedef const TValue* iterator;
|
||
|
|
||
|
private:
|
||
|
const TValue* m_Values;
|
||
|
const size_t m_ValueCount;
|
||
|
bool m_OwnStorage;
|
||
|
const TValueToKeyConverter m_ValueToKeyConverter;
|
||
|
const TKeyLess m_KeyLessComparer;
|
||
|
const TKeyEquals m_KeyEqualsComparer;
|
||
|
|
||
|
struct SortComparer
|
||
|
{
|
||
|
private:
|
||
|
const TValueToKeyConverter m_ValueToKeyConverter;
|
||
|
const TKeyLess m_KeyComparer;
|
||
|
|
||
|
public:
|
||
|
SortComparer(TValueToKeyConverter valueToKeyConverter, TKeyLess keyComparer) :
|
||
|
m_ValueToKeyConverter(valueToKeyConverter), m_KeyComparer(keyComparer)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
inline bool operator()(const TValue& left, const TValue& right) const
|
||
|
{
|
||
|
return m_KeyComparer(m_ValueToKeyConverter(left), m_ValueToKeyConverter(right));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct LowerBoundFindComparer
|
||
|
{
|
||
|
private:
|
||
|
const TValueToKeyConverter m_ValueToKeyConverter;
|
||
|
const TKeyLess m_KeyComparer;
|
||
|
|
||
|
public:
|
||
|
LowerBoundFindComparer(TValueToKeyConverter valueToKeyConverter, TKeyLess keyComparer) :
|
||
|
m_ValueToKeyConverter(valueToKeyConverter), m_KeyComparer(keyComparer)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
inline bool operator()(const TValue& left, const TKey& right) const
|
||
|
{
|
||
|
return m_KeyComparer(m_ValueToKeyConverter(left), right);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct UpperBoundFindComparer
|
||
|
{
|
||
|
private:
|
||
|
const TValueToKeyConverter m_ValueToKeyConverter;
|
||
|
const TKeyLess m_KeyComparer;
|
||
|
|
||
|
public:
|
||
|
UpperBoundFindComparer(TValueToKeyConverter valueToKeyConverter, TKeyLess keyComparer) :
|
||
|
m_ValueToKeyConverter(valueToKeyConverter), m_KeyComparer(keyComparer)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
inline bool operator()(const TKey& left, const TValue& right) const
|
||
|
{
|
||
|
return m_KeyComparer(left, m_ValueToKeyConverter(right));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
inline static TValue* InitializeInPlace(TValue* values, size_t valueCount, TValueToKeyConverter valueToKeyConverter, TKeyLess keyLessComparer)
|
||
|
{
|
||
|
std::sort(values, values + valueCount, SortComparer(valueToKeyConverter, keyLessComparer));
|
||
|
return values;
|
||
|
}
|
||
|
|
||
|
inline static TValue* AllocateAndInitialize(const TValue* originalValues, size_t valueCount, TValueToKeyConverter valueToKeyConverter, TKeyLess keyLessComparer)
|
||
|
{
|
||
|
TValue* values = new TValue[valueCount];
|
||
|
memcpy(values, originalValues, valueCount * sizeof(TValue));
|
||
|
|
||
|
return InitializeInPlace(values, valueCount, valueToKeyConverter, keyLessComparer);
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
inline ArrayValueMap() :
|
||
|
m_Values(NULL),
|
||
|
m_ValueCount(0),
|
||
|
m_OwnStorage(false),
|
||
|
m_ValueToKeyConverter(TValueToKeyConverter()),
|
||
|
m_KeyLessComparer(TKeyLess()),
|
||
|
m_KeyEqualsComparer(TKeyEquals())
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Non-allocating constructor. It will take a pointer and will not allocate any storage
|
||
|
// It WILL sort existing values
|
||
|
inline ArrayValueMap(TValue* values, size_t valueCount, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
|
||
|
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals()) :
|
||
|
m_Values(InitializeInPlace(values, valueCount, valueToKeyConverter, keyLessComparer)),
|
||
|
m_ValueCount(valueCount),
|
||
|
m_ValueToKeyConverter(valueToKeyConverter),
|
||
|
m_KeyLessComparer(keyLessComparer),
|
||
|
m_KeyEqualsComparer(keyEqualsComparer),
|
||
|
m_OwnStorage(false)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Allocating constructor
|
||
|
// Will copy values to newly allocated storage
|
||
|
inline ArrayValueMap(const std::vector<TValue>& values, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
|
||
|
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals()) :
|
||
|
m_Values(AllocateAndInitialize(values.data(), values.size(), valueToKeyConverter, keyLessComparer)),
|
||
|
m_ValueCount(values.size()),
|
||
|
m_ValueToKeyConverter(valueToKeyConverter),
|
||
|
m_KeyLessComparer(keyLessComparer),
|
||
|
m_KeyEqualsComparer(keyEqualsComparer),
|
||
|
m_OwnStorage(true)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
~ArrayValueMap()
|
||
|
{
|
||
|
if (m_OwnStorage)
|
||
|
{
|
||
|
delete[] m_Values;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void assign_external(TValue* values, size_t valueCount, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
|
||
|
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals())
|
||
|
{
|
||
|
this->~ArrayValueMap();
|
||
|
new(this) map_type(values, valueCount, valueToKeyConverter, keyLessComparer, keyEqualsComparer);
|
||
|
}
|
||
|
|
||
|
// Constructs map that contains pointers to original array
|
||
|
inline void assign_addresses(const TValue& valueArray, size_t valueCount, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
|
||
|
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals())
|
||
|
{
|
||
|
this->~ArrayValueMap();
|
||
|
|
||
|
TValue* storage = NULL;
|
||
|
|
||
|
if (valueCount > 0)
|
||
|
{
|
||
|
storage = new TValue[valueCount];
|
||
|
|
||
|
for (size_t i = 0; i < valueCount; i++)
|
||
|
{
|
||
|
storage[i] = &valueArray[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
new(this) map_type(storage, valueCount, valueToKeyConverter, keyLessComparer, keyEqualsComparer);
|
||
|
m_OwnStorage = true;
|
||
|
}
|
||
|
|
||
|
inline void assign(const std::vector<TValue>& values, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
|
||
|
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals())
|
||
|
{
|
||
|
this->~ArrayValueMap();
|
||
|
new(this) map_type(values, valueToKeyConverter, keyLessComparer, keyEqualsComparer);
|
||
|
}
|
||
|
|
||
|
inline iterator begin() const
|
||
|
{
|
||
|
return m_Values;
|
||
|
}
|
||
|
|
||
|
inline iterator end() const
|
||
|
{
|
||
|
return m_Values + m_ValueCount;
|
||
|
}
|
||
|
|
||
|
template<typename EqualsPredicate>
|
||
|
inline iterator find(const TKey& key, const EqualsPredicate& equalsPredicate) const
|
||
|
{
|
||
|
iterator dataStart = begin();
|
||
|
iterator dataEnd = end();
|
||
|
iterator ptr = std::lower_bound(dataStart, dataEnd, key, LowerBoundFindComparer(m_ValueToKeyConverter, m_KeyLessComparer));
|
||
|
|
||
|
for (; ptr != dataEnd && m_KeyEqualsComparer(m_ValueToKeyConverter(*ptr), key); ptr++)
|
||
|
{
|
||
|
if (equalsPredicate(*ptr))
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
return dataEnd;
|
||
|
}
|
||
|
|
||
|
inline iterator find_first(const TKey& key) const
|
||
|
{
|
||
|
iterator dataStart = begin();
|
||
|
iterator dataEnd = end();
|
||
|
iterator ptr = std::lower_bound(dataStart, dataEnd, key, LowerBoundFindComparer(m_ValueToKeyConverter, m_KeyLessComparer));
|
||
|
|
||
|
if (ptr != dataEnd && m_KeyEqualsComparer(m_ValueToKeyConverter(*ptr), key))
|
||
|
return ptr;
|
||
|
|
||
|
return dataEnd;
|
||
|
}
|
||
|
|
||
|
inline iterator lower_bound(const TKey& key) const
|
||
|
{
|
||
|
return std::lower_bound(begin(), end(), key, LowerBoundFindComparer(m_ValueToKeyConverter, m_KeyLessComparer));
|
||
|
}
|
||
|
|
||
|
inline iterator upper_bound(const TKey& key) const
|
||
|
{
|
||
|
return std::upper_bound(begin(), end(), key, UpperBoundFindComparer(m_ValueToKeyConverter, m_KeyLessComparer));
|
||
|
}
|
||
|
|
||
|
inline size_t size() const
|
||
|
{
|
||
|
return m_ValueCount;
|
||
|
}
|
||
|
|
||
|
inline const TValue& operator[](size_t i) const
|
||
|
{
|
||
|
return m_Values[i];
|
||
|
}
|
||
|
|
||
|
template<typename Mutator>
|
||
|
inline void mutate(Mutator& mutator)
|
||
|
{
|
||
|
size_t count = m_ValueCount;
|
||
|
const TValue* values = m_Values;
|
||
|
for (size_t i = 0; i < count; i++)
|
||
|
mutator(const_cast<TValue*>(values + i));
|
||
|
|
||
|
m_Values = InitializeInPlace(const_cast<TValue*>(values), count, m_ValueToKeyConverter, m_KeyLessComparer);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
} // namespace utils
|
||
|
} // namespace il2cpp
|