#ifndef Map_h
#define Map_h
#include "Array.h"
namespace dyld3 {
template<typename T>
struct Hash {
static size_t hash(const T&);
};
template<typename T>
struct Equal {
static bool equal(const T&a, const T& b);
};
template<typename KeyT, typename ValueT, class GetHash = Hash<KeyT>, class IsEqual = Equal<KeyT>>
class Map {
typedef std::pair<KeyT, ValueT> NodeT;
typedef NodeT* iterator;
typedef const NodeT* const_iterator;
enum : size_t {
SentinelHash = (size_t)-1
};
public:
Map() {
nextHashBufferGrowth = 768;
hashBufferUseCount = 0;
hashBuffer.reserve(1024);
for (size_t i = 0; i != 1024; ++i) {
hashBuffer.push_back(SentinelHash);
}
nodeBuffer.reserve(1024);
}
iterator find(const KeyT& key) {
size_t hashIndex = GetHash::hash(key) & (hashBuffer.count() - 1);
size_t probeAmount = 1;
while (true) {
size_t nodeBufferIndex = hashBuffer[hashIndex];
if (nodeBufferIndex == SentinelHash) {
return end();
}
if (IsEqual::equal(nodeBuffer[nodeBufferIndex].first, key)) {
return &nodeBuffer[nodeBufferIndex];
}
hashIndex += probeAmount;
hashIndex &= (hashBuffer.count() - 1);
++probeAmount;
}
assert(0 && "unreachable");
}
const_iterator find(const KeyT& key) const {
size_t hashIndex = GetHash::hash(key) & (hashBuffer.count() - 1);
size_t probeAmount = 1;
while (true) {
size_t nodeBufferIndex = hashBuffer[hashIndex];
if (nodeBufferIndex == SentinelHash) {
return end();
}
if (IsEqual::equal(nodeBuffer[nodeBufferIndex].first, key)) {
return &nodeBuffer[nodeBufferIndex];
}
hashIndex += probeAmount;
hashIndex &= (hashBuffer.count() - 1);
++probeAmount;
}
assert(0 && "unreachable");
}
iterator begin() {
return nodeBuffer.begin();
}
iterator end() {
return nodeBuffer.end();
}
const_iterator begin() const {
return nodeBuffer.begin();
}
const_iterator end() const {
return nodeBuffer.end();
}
const Array<NodeT>& array() const {
return nodeBuffer;
}
std::pair<iterator, bool> insert(NodeT&& v) {
if (hashBufferUseCount == nextHashBufferGrowth) {
size_t newHashTableSize = hashBuffer.count() * 2;
nextHashBufferGrowth *= 2;
dyld3::OverflowSafeArray<size_t> newHashBuffer;
newHashBuffer.reserve(newHashTableSize);
for (size_t i = 0; i != newHashTableSize; ++i) {
newHashBuffer.push_back(SentinelHash);
}
for (size_t i = 0; i != nodeBuffer.count(); ++i) {
const KeyT& key = nodeBuffer[i].first;
size_t newHashIndex = GetHash::hash(key) & (newHashBuffer.count() - 1);
size_t probeAmount = 1;
while (true) {
size_t newNodeBufferIndex = newHashBuffer[newHashIndex];
if (newNodeBufferIndex == SentinelHash) {
newHashBuffer[newHashIndex] = i;
break;
}
newHashIndex += probeAmount;
newHashIndex &= (newHashBuffer.count() - 1);
++probeAmount;
}
}
hashBuffer = std::move(newHashBuffer);
}
size_t hashIndex = GetHash::hash(v.first) & (hashBuffer.count() - 1);
size_t probeAmount = 1;
while (true) {
size_t nodeBufferIndex = hashBuffer[hashIndex];
if (nodeBufferIndex == SentinelHash) {
hashBuffer[hashIndex] = nodeBuffer.count();
++hashBufferUseCount;
nodeBuffer.push_back(v);
return { &nodeBuffer.back(), true };
}
if (IsEqual::equal(nodeBuffer[nodeBufferIndex].first, v.first)) {
return { &nodeBuffer[nodeBufferIndex], false };
}
hashIndex += probeAmount;
hashIndex &= (hashBuffer.count() - 1);
++probeAmount;
}
assert(0 && "unreachable");
}
ValueT& operator[](KeyT idx) {
auto itAndInserted = insert({ idx, ValueT() });
return itAndInserted.first->second;
}
private:
size_t nextHashBufferGrowth;
size_t hashBufferUseCount;
dyld3::OverflowSafeArray<size_t> hashBuffer;
dyld3::OverflowSafeArray<NodeT> nodeBuffer;
};
template<typename KeyT, typename ValueT, class GetHash = Hash<KeyT>, class IsEqual = Equal<KeyT>>
class MultiMap {
struct NextNode {
size_t isDuplicateHead : 1;
size_t isDuplicateEntry : 1;
size_t isDuplicateTail : 1;
size_t nextIndex : 29;
bool hasAnyDuplicates() const {
return isDuplicateHead || isDuplicateEntry || isDuplicateTail;
}
bool hasMoreDuplicates() const {
return isDuplicateHead || isDuplicateEntry;
}
static NextNode makeNoDuplicates() {
return { 0, 0, 0, 0 };
}
static NextNode makeDuplicateTailNode() {
return { 0, 0, 1, 0 };
}
};
static_assert(sizeof(NextNode) == sizeof(size_t), "Invalid size");
typedef std::pair<KeyT, ValueT> NodeT;
typedef std::tuple<KeyT, ValueT, NextNode> NodeEntryT;
typedef NodeT* iterator;
typedef const NodeT* const_iterator;
enum : size_t {
SentinelHash = (size_t)-1
};
public:
MultiMap() {
nextHashBufferGrowth = 768;
hashBufferUseCount = 0;
hashBuffer.reserve(1024);
for (size_t i = 0; i != 1024; ++i) {
hashBuffer.push_back(SentinelHash);
}
nodeBuffer.reserve(1024);
}
void forEachEntry(void (^handler)(const KeyT& key, const ValueT** values, uint64_t valuesCount)) const {
for (const NodeEntryT& headNode : nodeBuffer) {
NextNode nextNode = std::get<2>(headNode);
if (!nextNode.hasAnyDuplicates()) {
const ValueT* value[1] = { &std::get<1>(headNode) };
handler(std::get<0>(headNode), value, 1);
continue;
}
if (!nextNode.isDuplicateHead)
continue;
uint64_t valuesCount = 1;
while (std::get<2>(nodeBuffer[nextNode.nextIndex]).hasMoreDuplicates()) {
nextNode = std::get<2>(nodeBuffer[nextNode.nextIndex]);
++valuesCount;
}
++valuesCount;
const ValueT* values[valuesCount];
values[0] = &std::get<1>(headNode);
nextNode = std::get<2>(headNode);
valuesCount = 1;
while (std::get<2>(nodeBuffer[nextNode.nextIndex]).hasMoreDuplicates()) {
values[valuesCount] = &std::get<1>(nodeBuffer[nextNode.nextIndex]);
nextNode = std::get<2>(nodeBuffer[nextNode.nextIndex]);
++valuesCount;
}
values[valuesCount] = &std::get<1>(nodeBuffer[nextNode.nextIndex]);
++valuesCount;
handler(std::get<0>(headNode), values, valuesCount);
}
}
void insert(NodeT&& v) {
if (hashBufferUseCount == nextHashBufferGrowth) {
size_t newHashTableSize = hashBuffer.count() * 2;
nextHashBufferGrowth *= 2;
dyld3::OverflowSafeArray<size_t> newHashBuffer;
newHashBuffer.reserve(newHashTableSize);
for (size_t i = 0; i != newHashTableSize; ++i) {
newHashBuffer.push_back(SentinelHash);
}
for (size_t i = 0; i != nodeBuffer.count(); ++i) {
NextNode nextNode = std::get<2>(nodeBuffer[i]);
if (nextNode.isDuplicateEntry || nextNode.isDuplicateTail)
continue;
const KeyT& key = std::get<0>(nodeBuffer[i]);
size_t newHashIndex = GetHash::hash(key) & (newHashBuffer.count() - 1);
size_t probeAmount = 1;
while (true) {
size_t newNodeBufferIndex = newHashBuffer[newHashIndex];
if (newNodeBufferIndex == SentinelHash) {
newHashBuffer[newHashIndex] = i;
break;
}
newHashIndex += probeAmount;
newHashIndex &= (newHashBuffer.count() - 1);
++probeAmount;
}
}
hashBuffer = std::move(newHashBuffer);
}
size_t hashIndex = GetHash::hash(v.first) & (hashBuffer.count() - 1);
size_t probeAmount = 1;
while (true) {
size_t nodeBufferIndex = hashBuffer[hashIndex];
if (nodeBufferIndex == SentinelHash) {
hashBuffer[hashIndex] = nodeBuffer.count();
++hashBufferUseCount;
nodeBuffer.push_back({ v.first, v.second, NextNode::makeNoDuplicates() } );
return;
}
if (IsEqual::equal(std::get<0>(nodeBuffer[nodeBufferIndex]), v.first)) {
while (std::get<2>(nodeBuffer[nodeBufferIndex]).hasMoreDuplicates()) {
nodeBufferIndex = std::get<2>(nodeBuffer[nodeBufferIndex]).nextIndex;
}
NextNode& tailNode = std::get<2>(nodeBuffer[nodeBufferIndex]);
if (!tailNode.hasAnyDuplicates()) {
tailNode.isDuplicateHead = 1;
tailNode.nextIndex = nodeBuffer.count();
} else {
assert(tailNode.isDuplicateTail);
tailNode.isDuplicateTail = 0;
tailNode.isDuplicateEntry = 1;
tailNode.nextIndex = nodeBuffer.count();
}
nodeBuffer.push_back({ v.first, v.second, NextNode::makeDuplicateTailNode() } );
return;
}
hashIndex += probeAmount;
hashIndex &= (hashBuffer.count() - 1);
++probeAmount;
}
assert(0 && "unreachable");
}
private:
size_t nextHashBufferGrowth;
size_t hashBufferUseCount;
dyld3::OverflowSafeArray<size_t> hashBuffer;
dyld3::OverflowSafeArray<NodeEntryT> nodeBuffer;
};
}
#endif