Refactored
This commit is contained in:
parent
514cdf401b
commit
fdd64dd6ed
283
src/data_structures/map/rh_common.hpp
Normal file
283
src/data_structures/map/rh_common.hpp
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "utils/crtp.hpp"
|
||||||
|
#include "utils/option_ptr.hpp"
|
||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
// RobinHood base.
|
||||||
|
// Entrys are POINTERS alligned to 8B.
|
||||||
|
// Entrys must know thers key.
|
||||||
|
// D must have method K& get_key()
|
||||||
|
// K must be comparable with ==.
|
||||||
|
template <class K, class D, size_t init_size_pow2 = 2>
|
||||||
|
class RhBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
class Combined
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Combined() : data(0) {}
|
||||||
|
|
||||||
|
Combined(D *data, size_t off)
|
||||||
|
{
|
||||||
|
// assert((((size_t)data) & 0x7) == 0 && off < 8);
|
||||||
|
this->data = ((size_t)data) | off;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid() const { return data != 0; }
|
||||||
|
|
||||||
|
size_t off() const { return data & 0x7; }
|
||||||
|
|
||||||
|
void decrement_off_unsafe() { data--; }
|
||||||
|
|
||||||
|
bool decrement_off()
|
||||||
|
{
|
||||||
|
if (off() > 0) {
|
||||||
|
data--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool increment_off()
|
||||||
|
{
|
||||||
|
if (off() < 7) {
|
||||||
|
data++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D *ptr() const { return (D *)(data & (~(0x7))); }
|
||||||
|
|
||||||
|
bool equal(const K &key, size_t off)
|
||||||
|
{
|
||||||
|
return this->off() == off && key == ptr()->get_key();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const Combined &a, const Combined &b)
|
||||||
|
{
|
||||||
|
return a.off() == b.off() &&
|
||||||
|
a.ptr()->get_key() == b.ptr()->get_key();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const Combined &a, const Combined &b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t data;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class It>
|
||||||
|
class IteratorBase : public Crtp<It>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
IteratorBase() : map(nullptr) { advanced = index = ~((size_t)0); }
|
||||||
|
IteratorBase(const RhBase *map) : map(map)
|
||||||
|
{
|
||||||
|
index = 0;
|
||||||
|
while (index < map->capacity && !map->array[index].valid()) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (index == map->capacity) {
|
||||||
|
map = nullptr;
|
||||||
|
advanced = index = ~((size_t)0);
|
||||||
|
} else {
|
||||||
|
advanced = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IteratorBase(const RhBase *map, size_t start)
|
||||||
|
: map(map), index(start), advanced(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const RhBase *map;
|
||||||
|
size_t advanced;
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IteratorBase(const IteratorBase &) = default;
|
||||||
|
IteratorBase(IteratorBase &&) = default;
|
||||||
|
|
||||||
|
D *operator*()
|
||||||
|
{
|
||||||
|
assert(index < map->capacity && map->array[index].valid());
|
||||||
|
return map->array[index].ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
D *operator->()
|
||||||
|
{
|
||||||
|
assert(index < map->capacity && map->array[index].valid());
|
||||||
|
return map->array[index].ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
It &operator++()
|
||||||
|
{
|
||||||
|
assert(index < map->capacity && map->array[index].valid());
|
||||||
|
auto mask = map->mask();
|
||||||
|
do {
|
||||||
|
advanced++;
|
||||||
|
if (advanced >= map->capacity) {
|
||||||
|
map = nullptr;
|
||||||
|
advanced = index = ~((size_t)0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
index = (index + 1) & mask;
|
||||||
|
} while (!map->array[index].valid());
|
||||||
|
|
||||||
|
return this->derived();
|
||||||
|
}
|
||||||
|
|
||||||
|
It &operator++(int) { return operator++(); }
|
||||||
|
|
||||||
|
friend bool operator==(const It &a, const It &b)
|
||||||
|
{
|
||||||
|
return a.index == b.index && a.map == b.map;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const It &a, const It &b) { return !(a == b); }
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
class ConstIterator : public IteratorBase<ConstIterator>
|
||||||
|
{
|
||||||
|
friend class RhBase;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ConstIterator(const RhBase *map) : IteratorBase<ConstIterator>(map) {}
|
||||||
|
ConstIterator(const RhBase *map, size_t index)
|
||||||
|
: IteratorBase<ConstIterator>(map, index)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConstIterator() = default;
|
||||||
|
ConstIterator(const ConstIterator &) = default;
|
||||||
|
|
||||||
|
const D *operator->()
|
||||||
|
{
|
||||||
|
return IteratorBase<ConstIterator>::operator->();
|
||||||
|
}
|
||||||
|
|
||||||
|
const D *operator*()
|
||||||
|
{
|
||||||
|
return IteratorBase<ConstIterator>::operator*();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Iterator : public IteratorBase<Iterator>
|
||||||
|
{
|
||||||
|
friend class RhBase;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Iterator(const RhBase *map) : IteratorBase<Iterator>(map) {}
|
||||||
|
Iterator(const RhBase *map, size_t index)
|
||||||
|
: IteratorBase<Iterator>(map, index)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Iterator() = default;
|
||||||
|
Iterator(const Iterator &) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
RhBase() {}
|
||||||
|
|
||||||
|
RhBase(const RhBase &other)
|
||||||
|
{
|
||||||
|
capacity = other.capacity;
|
||||||
|
count = other.count;
|
||||||
|
if (capacity > 0) {
|
||||||
|
size_t bytes = sizeof(Combined) * capacity;
|
||||||
|
array = (Combined *)malloc(bytes);
|
||||||
|
memcpy(array, other.array, bytes);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
array = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~RhBase() { this->clear(); }
|
||||||
|
|
||||||
|
Iterator begin() { return Iterator(this); }
|
||||||
|
|
||||||
|
ConstIterator begin() const { return ConstIterator(this); }
|
||||||
|
|
||||||
|
ConstIterator cbegin() const { return ConstIterator(this); }
|
||||||
|
|
||||||
|
Iterator end() { return Iterator(); }
|
||||||
|
|
||||||
|
ConstIterator end() const { return ConstIterator(); }
|
||||||
|
|
||||||
|
ConstIterator cend() const { return ConstIterator(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void init_array(size_t size)
|
||||||
|
{
|
||||||
|
size_t bytes = sizeof(Combined) * size;
|
||||||
|
array = (Combined *)malloc(bytes);
|
||||||
|
std::memset(array, 0, bytes);
|
||||||
|
capacity = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// True if before array has some values.
|
||||||
|
// Before array has to be released also.
|
||||||
|
bool increase_size()
|
||||||
|
{
|
||||||
|
if (capacity == 0) {
|
||||||
|
// assert(array == nullptr && count == 0);
|
||||||
|
size_t new_size = 1 << init_size_pow2;
|
||||||
|
init_array(new_size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t new_size = capacity * 2;
|
||||||
|
init_array(new_size);
|
||||||
|
count = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator create_it(size_t index) { return Iterator(this, index); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
free(array);
|
||||||
|
array = nullptr;
|
||||||
|
capacity = 0;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const { return count; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
size_t before_index(size_t now, size_t mask)
|
||||||
|
{
|
||||||
|
return (now - 1) & mask; // THIS IS VALID
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t index(const K &key, size_t mask) const
|
||||||
|
{
|
||||||
|
return hash(std::hash<K>()(key)) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is rather expensive but offers good distribution.
|
||||||
|
size_t hash(size_t x) const
|
||||||
|
{
|
||||||
|
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
|
||||||
|
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
|
||||||
|
x = x ^ (x >> 31);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mask() const { return capacity - 1; }
|
||||||
|
|
||||||
|
Combined *array = nullptr;
|
||||||
|
size_t capacity = 0;
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
friend class IteratorBase<Iterator>;
|
||||||
|
friend class IteratorBase<ConstIterator>;
|
||||||
|
};
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "rh_common.hpp"
|
||||||
#include "utils/crtp.hpp"
|
#include "utils/crtp.hpp"
|
||||||
#include "utils/option_ptr.hpp"
|
#include "utils/option_ptr.hpp"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -10,197 +11,33 @@
|
|||||||
// K must be comparable with ==.
|
// K must be comparable with ==.
|
||||||
// HashMap behaves as if it isn't owner of entrys.
|
// HashMap behaves as if it isn't owner of entrys.
|
||||||
template <class K, class D, size_t init_size_pow2 = 2>
|
template <class K, class D, size_t init_size_pow2 = 2>
|
||||||
class RhHashMap
|
class RhHashMap : public RhBase<K, D, init_size_pow2>
|
||||||
{
|
{
|
||||||
private:
|
typedef RhBase<K, D, init_size_pow2> base;
|
||||||
class Combined
|
using base::array;
|
||||||
{
|
using base::index;
|
||||||
|
using base::capacity;
|
||||||
public:
|
using base::count;
|
||||||
Combined() : data(0) {}
|
using typename base::Combined;
|
||||||
|
|
||||||
Combined(D *data, size_t off)
|
|
||||||
{
|
|
||||||
// assert(((((size_t)(data)) & 0x7) == 0) && off < 8);
|
|
||||||
this->data = ((size_t)data) | off;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool valid() { return data != 0; }
|
|
||||||
|
|
||||||
size_t off() { return data & 0x7; }
|
|
||||||
|
|
||||||
void decrement_off() { data--; }
|
|
||||||
|
|
||||||
bool increment_off()
|
|
||||||
{
|
|
||||||
if (off() < 7) {
|
|
||||||
data++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
D *ptr() { return (D *)(data & (~(0x7))); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t data;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class It>
|
|
||||||
class IteratorBase : public Crtp<It>
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
IteratorBase() : map(nullptr) { index = ~((size_t)0); }
|
|
||||||
IteratorBase(const RhHashMap *map) : map(map)
|
|
||||||
{
|
|
||||||
index = 0;
|
|
||||||
while (index < map->capacity && !map->array[index].valid()) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
if (index == map->capacity) {
|
|
||||||
map = nullptr;
|
|
||||||
index = ~((size_t)0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const RhHashMap *map;
|
|
||||||
size_t index;
|
|
||||||
|
|
||||||
public:
|
|
||||||
IteratorBase(const IteratorBase &) = default;
|
|
||||||
IteratorBase(IteratorBase &&) = default;
|
|
||||||
|
|
||||||
D *operator*()
|
|
||||||
{
|
|
||||||
assert(index < map->capacity && map->array[index].valid());
|
|
||||||
return map->array[index].ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
D *operator->()
|
|
||||||
{
|
|
||||||
assert(index < map->capacity && map->array[index].valid());
|
|
||||||
return map->array[index].ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
It &operator++()
|
|
||||||
{
|
|
||||||
assert(index < map->capacity && map->array[index].valid());
|
|
||||||
do {
|
|
||||||
index++;
|
|
||||||
if (index >= map->capacity) {
|
|
||||||
map = nullptr;
|
|
||||||
index = ~((size_t)0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (!map->array[index].valid());
|
|
||||||
|
|
||||||
return this->derived();
|
|
||||||
}
|
|
||||||
|
|
||||||
It &operator++(int) { return operator++(); }
|
|
||||||
|
|
||||||
friend bool operator==(const It &a, const It &b)
|
|
||||||
{
|
|
||||||
return a.index == b.index && a.map == b.map;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const It &a, const It &b) { return !(a == b); }
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
class ConstIterator : public IteratorBase<ConstIterator>
|
|
||||||
{
|
|
||||||
friend class RhHashMap;
|
|
||||||
ConstIterator(const RhHashMap *map) : IteratorBase<ConstIterator>(map)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ConstIterator() = default;
|
|
||||||
ConstIterator(const ConstIterator &) = default;
|
|
||||||
|
|
||||||
const D *operator->()
|
|
||||||
{
|
|
||||||
return IteratorBase<ConstIterator>::operator->();
|
|
||||||
}
|
|
||||||
|
|
||||||
const D *operator*()
|
|
||||||
{
|
|
||||||
return IteratorBase<ConstIterator>::operator*();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Iterator : public IteratorBase<Iterator>
|
|
||||||
{
|
|
||||||
friend class RhHashMap;
|
|
||||||
Iterator(const RhHashMap *map) : IteratorBase<Iterator>(map) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Iterator() = default;
|
|
||||||
Iterator(const Iterator &) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
RhHashMap() {}
|
|
||||||
|
|
||||||
RhHashMap(const RhHashMap &other)
|
|
||||||
{
|
|
||||||
capacity = other.capacity;
|
|
||||||
count = other.count;
|
|
||||||
if (capacity > 0) {
|
|
||||||
size_t bytes = sizeof(Combined) * capacity;
|
|
||||||
array = (Combined *)malloc(bytes);
|
|
||||||
memcpy(array, other.array, bytes);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
array = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~RhHashMap() { this->clear(); }
|
|
||||||
|
|
||||||
Iterator begin() { return Iterator(this); }
|
|
||||||
|
|
||||||
ConstIterator begin() const { return ConstIterator(this); }
|
|
||||||
|
|
||||||
ConstIterator cbegin() const { return ConstIterator(this); }
|
|
||||||
|
|
||||||
Iterator end() { return Iterator(); }
|
|
||||||
|
|
||||||
ConstIterator end() const { return ConstIterator(); }
|
|
||||||
|
|
||||||
ConstIterator cend() const { return ConstIterator(); }
|
|
||||||
|
|
||||||
void init_array(size_t size)
|
|
||||||
{
|
|
||||||
size_t bytes = sizeof(Combined) * size;
|
|
||||||
array = (Combined *)malloc(bytes);
|
|
||||||
memset(array, 0, bytes);
|
|
||||||
capacity = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void increase_size()
|
void increase_size()
|
||||||
{
|
{
|
||||||
if (capacity == 0) {
|
|
||||||
// assert(array == nullptr && count == 0);
|
|
||||||
size_t new_size = 1 << init_size_pow2;
|
|
||||||
init_array(new_size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
size_t new_size = capacity * 2;
|
|
||||||
size_t old_size = capacity;
|
size_t old_size = capacity;
|
||||||
auto a = array;
|
auto a = array;
|
||||||
init_array(new_size);
|
if (base::increase_size()) {
|
||||||
count = 0;
|
for (int i = 0; i < old_size; i++) {
|
||||||
|
if (a[i].valid()) {
|
||||||
for (int i = 0; i < old_size; i++) {
|
insert(a[i].ptr());
|
||||||
if (a[i].valid()) {
|
}
|
||||||
insert(a[i].ptr());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(a);
|
free(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using base::RhBase;
|
||||||
|
|
||||||
bool contains(const K &key) { return find(key).is_present(); }
|
bool contains(const K &key) { return find(key).is_present(); }
|
||||||
|
|
||||||
OptionPtr<D> find(const K key)
|
OptionPtr<D> find(const K key)
|
||||||
@ -293,9 +130,10 @@ public:
|
|||||||
|
|
||||||
auto before = now;
|
auto before = now;
|
||||||
do {
|
do {
|
||||||
other.decrement_off(); // This is alright even for off=0
|
// This is alright even for off=0 on found element
|
||||||
// on found element because it
|
// because it wont be seen.
|
||||||
// wont be seen.
|
other.decrement_off_unsafe();
|
||||||
|
|
||||||
array[before] = other;
|
array[before] = other;
|
||||||
before = now;
|
before = now;
|
||||||
now = (now + 1) & mask;
|
now = (now + 1) & mask;
|
||||||
@ -318,36 +156,4 @@ public:
|
|||||||
}
|
}
|
||||||
return OptionPtr<D>();
|
return OptionPtr<D>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
free(array);
|
|
||||||
array = nullptr;
|
|
||||||
capacity = 0;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() { return count; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t index(const K &key, size_t mask)
|
|
||||||
{
|
|
||||||
return hash(std::hash<K>()(key)) & mask;
|
|
||||||
}
|
|
||||||
size_t hash(size_t x) const
|
|
||||||
{
|
|
||||||
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
|
|
||||||
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
|
|
||||||
x = x ^ (x >> 31);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mask() { return capacity - 1; }
|
|
||||||
|
|
||||||
Combined *array = nullptr;
|
|
||||||
size_t capacity = 0;
|
|
||||||
size_t count = 0;
|
|
||||||
|
|
||||||
friend class IteratorBase<Iterator>;
|
|
||||||
friend class IteratorBase<ConstIterator>;
|
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
#include "rh_common.hpp"
|
||||||
#include "utils/crtp.hpp"
|
#include "utils/crtp.hpp"
|
||||||
|
#include "utils/likely.hpp"
|
||||||
#include "utils/option_ptr.hpp"
|
#include "utils/option_ptr.hpp"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -11,236 +13,38 @@
|
|||||||
// K must be comparable with ==.
|
// K must be comparable with ==.
|
||||||
// HashMap behaves as if it isn't owner of entrys.
|
// HashMap behaves as if it isn't owner of entrys.
|
||||||
template <class K, class D, size_t init_size_pow2 = 2>
|
template <class K, class D, size_t init_size_pow2 = 2>
|
||||||
class RhHashMultiMap
|
class RhHashMultiMap : public RhBase<K, D, init_size_pow2>
|
||||||
{
|
{
|
||||||
private:
|
typedef RhBase<K, D, init_size_pow2> base;
|
||||||
class Combined
|
using base::array;
|
||||||
{
|
using base::index;
|
||||||
|
using base::capacity;
|
||||||
public:
|
using base::count;
|
||||||
Combined() : data(0) {}
|
using typename base::Combined;
|
||||||
|
using base::before_index;
|
||||||
Combined(D *data, size_t off)
|
using base::create_it;
|
||||||
{
|
|
||||||
assert((data & 0x7) == 0 && off < 8);
|
|
||||||
this->data = ((size_t)data) | off;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool valid() { return data != 0; }
|
|
||||||
|
|
||||||
size_t off() { return data & 0x7; }
|
|
||||||
|
|
||||||
bool decrement_off()
|
|
||||||
{
|
|
||||||
if (off() > 0) {
|
|
||||||
data--;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool increment_off()
|
|
||||||
{
|
|
||||||
if (off() < 7) {
|
|
||||||
data++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
D *ptr() { return (D *)(data & (~(0x7))); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t data;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class It>
|
|
||||||
class IteratorBase : public Crtp<It>
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
IteratorBase() : map(nullptr) { advanced = index = ~((size_t)0); }
|
|
||||||
IteratorBase(const RhHashMultiMap *map) : map(map)
|
|
||||||
{
|
|
||||||
index = 0;
|
|
||||||
while (index < map->capacity && !map->array[index].valid()) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
if (index == map->capacity) {
|
|
||||||
map = nullptr;
|
|
||||||
advanced = index = ~((size_t)0);
|
|
||||||
} else {
|
|
||||||
advanced = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IteratorBase(const RhHashMultiMap *map, size_t start)
|
|
||||||
: map(map), index(start), advanced(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const RhHashMultiMap *map;
|
|
||||||
size_t advanced;
|
|
||||||
size_t index;
|
|
||||||
|
|
||||||
public:
|
|
||||||
IteratorBase(const IteratorBase &) = default;
|
|
||||||
IteratorBase(IteratorBase &&) = default;
|
|
||||||
|
|
||||||
D *operator*()
|
|
||||||
{
|
|
||||||
assert(index < map->capacity && map->array[index].valid());
|
|
||||||
return map->array[index].ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
D *operator->()
|
|
||||||
{
|
|
||||||
assert(index < map->capacity && map->array[index].valid());
|
|
||||||
return map->array[index].ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
It &operator++()
|
|
||||||
{
|
|
||||||
assert(index < map->capacity && map->array[index].valid());
|
|
||||||
auto mask = map->mask();
|
|
||||||
do {
|
|
||||||
advanced++;
|
|
||||||
if (advanced >= map->capacity) {
|
|
||||||
map = nullptr;
|
|
||||||
advanced = index = ~((size_t)0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
index = (index + 1) & mask;
|
|
||||||
} while (!map->array[index].valid());
|
|
||||||
|
|
||||||
return this->derived();
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// // True if value is present
|
|
||||||
// bool is_present() { return map != nullptr; }
|
|
||||||
|
|
||||||
It &operator++(int) { return operator++(); }
|
|
||||||
|
|
||||||
friend bool operator==(const It &a, const It &b)
|
|
||||||
{
|
|
||||||
return a.index == b.index && a.map == b.map;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const It &a, const It &b) { return !(a == b); }
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
class ConstIterator : public IteratorBase<ConstIterator>
|
|
||||||
{
|
|
||||||
friend class RhHashMultiMap;
|
|
||||||
ConstIterator(const RhHashMultiMap *map)
|
|
||||||
: IteratorBase<ConstIterator>(map)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
ConstIterator(const RhHashMultiMap *map, size_t index)
|
|
||||||
: IteratorBase<ConstIterator>(map, index)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ConstIterator() = default;
|
|
||||||
ConstIterator(const ConstIterator &) = default;
|
|
||||||
|
|
||||||
const D *operator->()
|
|
||||||
{
|
|
||||||
return IteratorBase<ConstIterator>::operator->();
|
|
||||||
}
|
|
||||||
|
|
||||||
const D *operator*()
|
|
||||||
{
|
|
||||||
return IteratorBase<ConstIterator>::operator*();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Iterator : public IteratorBase<Iterator>
|
|
||||||
{
|
|
||||||
friend class RhHashMultiMap;
|
|
||||||
Iterator(const RhHashMultiMap *map) : IteratorBase<Iterator>(map) {}
|
|
||||||
Iterator(const RhHashMultiMap *map, size_t index)
|
|
||||||
: IteratorBase<Iterator>(map, index)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Iterator() = default;
|
|
||||||
Iterator(const Iterator &) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
RhHashMultiMap() {}
|
|
||||||
|
|
||||||
RhHashMultiMap(const RhHashMultiMap &other)
|
|
||||||
{
|
|
||||||
capacity = other.capacity;
|
|
||||||
count = other.count;
|
|
||||||
if (capacity > 0) {
|
|
||||||
size_t bytes = sizeof(Combined) * capacity;
|
|
||||||
array = (Combined *)malloc(bytes);
|
|
||||||
memcpy(array, other.array, bytes);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
array = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RhHashMultiMap(RhHashMultiMap &&other)
|
|
||||||
// {
|
|
||||||
// capacity = other.capacity;
|
|
||||||
// count = other.count;
|
|
||||||
// array = other.array;
|
|
||||||
//
|
|
||||||
// other.array = nullptr;
|
|
||||||
// other.capacity = 0;
|
|
||||||
// other.count = 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
~RhHashMultiMap() { this->clear(); }
|
|
||||||
|
|
||||||
Iterator begin() { return Iterator(this); }
|
|
||||||
|
|
||||||
ConstIterator begin() const { return ConstIterator(this); }
|
|
||||||
|
|
||||||
ConstIterator cbegin() const { return ConstIterator(this); }
|
|
||||||
|
|
||||||
Iterator end() { return Iterator(); }
|
|
||||||
|
|
||||||
ConstIterator end() const { return ConstIterator(); }
|
|
||||||
|
|
||||||
ConstIterator cend() const { return ConstIterator(); }
|
|
||||||
|
|
||||||
void init_array(size_t size)
|
|
||||||
{
|
|
||||||
size_t bytes = sizeof(Combined) * size;
|
|
||||||
array = (Combined *)malloc(bytes);
|
|
||||||
std::memset(array, 0, bytes);
|
|
||||||
capacity = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void increase_size()
|
void increase_size()
|
||||||
{
|
{
|
||||||
if (capacity == 0) {
|
|
||||||
assert(array == nullptr && count == 0);
|
|
||||||
size_t new_size = 1 << init_size_pow2;
|
|
||||||
init_array(new_size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
size_t new_size = capacity * 2;
|
|
||||||
size_t old_size = capacity;
|
size_t old_size = capacity;
|
||||||
auto a = array;
|
auto a = array;
|
||||||
init_array(new_size);
|
if (base::increase_size()) {
|
||||||
count = 0;
|
for (int i = 0; i < old_size; i++) {
|
||||||
|
if (a[i].valid()) {
|
||||||
for (int i = 0; i < old_size; i++) {
|
add(a[i].ptr());
|
||||||
if (a[i].valid()) {
|
}
|
||||||
add(a[i].ptr());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(a);
|
free(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using base::RhBase;
|
||||||
|
using base::end;
|
||||||
|
using typename base::ConstIterator;
|
||||||
|
using typename base::Iterator;
|
||||||
|
|
||||||
bool contains(const K &key) { return find(key) != end(); }
|
bool contains(const K &key) { return find(key) != end(); }
|
||||||
|
|
||||||
Iterator find(const K &key_in)
|
Iterator find(const K &key_in)
|
||||||
@ -250,30 +54,20 @@ public:
|
|||||||
size_t mask = this->mask();
|
size_t mask = this->mask();
|
||||||
size_t now = index(key, mask);
|
size_t now = index(key, mask);
|
||||||
size_t off = 0;
|
size_t off = 0;
|
||||||
size_t checked = 0;
|
|
||||||
size_t border = 8 <= capacity ? 8 : capacity;
|
size_t border = 8 <= capacity ? 8 : capacity;
|
||||||
Combined other = array[now];
|
Combined other = array[now];
|
||||||
while (other.valid() && off < border) {
|
while (other.valid() && off < border) {
|
||||||
auto other_off = other.off();
|
auto other_off = other.off();
|
||||||
if (other_off == off && key == other.ptr()->get_key()) {
|
if (other_off == off && key == other.ptr()->get_key()) {
|
||||||
return Iterator(this, now);
|
return create_it(now);
|
||||||
|
|
||||||
} else if (other_off < off) { // Other is rich
|
} else if (other_off < off) { // Other is rich
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} else { // Else other has equal or greater
|
} else { // Else other has equal or greater off, so he is poor.
|
||||||
// offset, so he is poor.
|
if (UNLIKELY(skip(now, other, other_off, mask))) {
|
||||||
auto other_key = other.ptr()->get_key();
|
break;
|
||||||
do {
|
}
|
||||||
now = (now + 1) & mask;
|
|
||||||
other = array[now];
|
|
||||||
checked++;
|
|
||||||
if (checked >= count) { // Reason is possibility of map
|
|
||||||
// full of same values.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (other.valid() && other.off() == other_off &&
|
|
||||||
other.ptr()->get_key() == other_key);
|
|
||||||
off++;
|
off++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,31 +95,24 @@ public:
|
|||||||
Combined other = array[now];
|
Combined other = array[now];
|
||||||
while (off < border) {
|
while (off < border) {
|
||||||
if (other.valid()) {
|
if (other.valid()) {
|
||||||
auto other_off = other.off();
|
const size_t other_off = other.off();
|
||||||
bool multi = false;
|
bool multi = false;
|
||||||
if (other_off == off &&
|
if (other_off == off && other.ptr()->get_key() == key) {
|
||||||
other.ptr()->get_key() == key) { // Found the
|
// Found the same
|
||||||
do { // same
|
do {
|
||||||
now = (now + 1) & mask;
|
now = (now + 1) & mask;
|
||||||
other = array[now];
|
other = array[now];
|
||||||
if (!other.valid()) {
|
if (!other.valid()) {
|
||||||
set(now, data, off);
|
set(now, data, off);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
other_off = other.off();
|
} while (other.equal(key, off));
|
||||||
} while (other_off == off &&
|
|
||||||
other.ptr()->get_key() == key);
|
|
||||||
multi = true;
|
multi = true;
|
||||||
} else if (other_off > off ||
|
} else if (other_off > off ||
|
||||||
other_poor(other, mask, start,
|
other_poor(other, mask, start,
|
||||||
now)) { // Other is poor or the same
|
now)) { // Else other has equal or
|
||||||
auto other_key = other.ptr()->get_key();
|
// greater off, so he is poor.
|
||||||
|
skip(now, other, other_off, mask); // TRUE IS IMPOSSIBLE
|
||||||
do {
|
|
||||||
now = (now + 1) & mask;
|
|
||||||
other = array[now];
|
|
||||||
} while (other.valid() && other.off() == other_off &&
|
|
||||||
other.ptr()->get_key() == other_key);
|
|
||||||
off++;
|
off++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -357,136 +144,6 @@ public:
|
|||||||
add(data);
|
add(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
void set(size_t now, D *data, size_t off)
|
|
||||||
{
|
|
||||||
array[now] = Combined(data, off);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// True if no adjusment is needed, false otherwise.
|
|
||||||
bool is_off_adjusted(Combined &com, size_t mask, size_t start, size_t now,
|
|
||||||
bool multi)
|
|
||||||
{
|
|
||||||
if (com.off() == 0) { // Must be adjusted
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
size_t cin = index(com.ptr()->get_key(), mask);
|
|
||||||
if ((start <= now && (cin < start || cin > now)) ||
|
|
||||||
(now < start && cin < start &&
|
|
||||||
cin > now)) { // Outside [start,now] interval
|
|
||||||
return multi;
|
|
||||||
}
|
|
||||||
auto a = array[cin];
|
|
||||||
auto b = array[(cin + 1) & mask];
|
|
||||||
return (a.off() == b.off() && a.ptr()->get_key() == b.ptr()->get_key());
|
|
||||||
// Check if different key has eneterd in to
|
|
||||||
// range of other.
|
|
||||||
}
|
|
||||||
|
|
||||||
bool other_poor(Combined other, size_t mask, size_t start, size_t now)
|
|
||||||
{
|
|
||||||
auto cin = index(other.ptr()->get_key(), mask);
|
|
||||||
return (start <= now && (cin <= start || cin > now)) ||
|
|
||||||
(now < start && cin <= start &&
|
|
||||||
cin > now); // If other index is smaller then he is poorer.
|
|
||||||
}
|
|
||||||
|
|
||||||
// True if no adjusment is needed, false otherwise.
|
|
||||||
bool is_off_adjusted_rem(Combined &com, size_t mask, size_t start,
|
|
||||||
size_t bef, size_t now, bool multi)
|
|
||||||
{
|
|
||||||
if (com.off() == 0) { // Must be adjusted
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
size_t cin = index(com.ptr()->get_key(), mask);
|
|
||||||
if (cin == bef) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((start <= now && (cin < start || cin > now)) ||
|
|
||||||
(now < start && cin < start &&
|
|
||||||
cin > now)) { // Outside [start,now] interval
|
|
||||||
return multi;
|
|
||||||
}
|
|
||||||
auto a = array[cin];
|
|
||||||
auto b = array[before_index(cin, mask)];
|
|
||||||
return b.valid() &&
|
|
||||||
(a.off() == b.off() && a.ptr()->get_key() == b.ptr()->get_key());
|
|
||||||
// Check if different key has eneterd in to
|
|
||||||
// range of other.
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Removes element. Returns removed element if it existed. It doesn't
|
|
||||||
// specify which element from same key group will be removed.
|
|
||||||
OptionPtr<D> remove(const K &key_in)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (count > 0) {
|
|
||||||
auto key = std::ref(key_in);
|
|
||||||
size_t mask = this->mask();
|
|
||||||
size_t now = index(key, mask);
|
|
||||||
size_t off = 0;
|
|
||||||
size_t checked = 0;
|
|
||||||
size_t border = 8 <= capacity ? 8 : capacity;
|
|
||||||
Combined other = array[now];
|
|
||||||
while (other.valid() && off < border) {
|
|
||||||
auto other_off = other.off();
|
|
||||||
bool multi = false;
|
|
||||||
if (other_off == off && key == other.ptr()->get_key()) {
|
|
||||||
do {
|
|
||||||
now = (now + 1) & mask;
|
|
||||||
other = array[now];
|
|
||||||
if (!other.valid()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
other_off = other.off();
|
|
||||||
} while (other_off == off &&
|
|
||||||
other.ptr()->get_key() == key &&
|
|
||||||
(multi = true)); // multi = true is correct
|
|
||||||
|
|
||||||
auto bef = before_index(now, mask);
|
|
||||||
auto ret = OptionPtr<D>(array[bef].ptr());
|
|
||||||
|
|
||||||
auto start_rem = bef;
|
|
||||||
while (other.valid() &&
|
|
||||||
(is_off_adjusted_rem(other, mask, start_rem, bef,
|
|
||||||
now, multi) ||
|
|
||||||
other.decrement_off())) {
|
|
||||||
array[bef] = other;
|
|
||||||
bef = now;
|
|
||||||
now = (now + 1) & mask;
|
|
||||||
other = array[now];
|
|
||||||
}
|
|
||||||
|
|
||||||
array[bef] = Combined();
|
|
||||||
count--;
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
} else if (other_off < off) { // Other is rich
|
|
||||||
break;
|
|
||||||
|
|
||||||
} else { // Else other has equal or greater
|
|
||||||
// offset, so he is poor.
|
|
||||||
auto other_key = other.ptr()->get_key();
|
|
||||||
do {
|
|
||||||
now = (now + 1) & mask;
|
|
||||||
other = array[now];
|
|
||||||
checked++;
|
|
||||||
if (checked >= count) { // Reason is possibility of map
|
|
||||||
// full of same values.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (other.valid() && other.off() == other_off &&
|
|
||||||
other.ptr()->get_key() == other_key);
|
|
||||||
off++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return OptionPtr<D>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes element equal by key and value. Returns true if it existed.
|
// Removes element equal by key and value. Returns true if it existed.
|
||||||
bool remove(D *data)
|
bool remove(D *data)
|
||||||
{
|
{
|
||||||
@ -495,34 +152,32 @@ public:
|
|||||||
size_t mask = this->mask();
|
size_t mask = this->mask();
|
||||||
size_t now = index(key, mask);
|
size_t now = index(key, mask);
|
||||||
size_t off = 0;
|
size_t off = 0;
|
||||||
size_t checked = 0;
|
|
||||||
size_t border = 8 <= capacity ? 8 : capacity;
|
size_t border = 8 <= capacity ? 8 : capacity;
|
||||||
Combined other = array[now];
|
Combined other = array[now];
|
||||||
while (other.valid() && off < border) {
|
while (other.valid() && off < border) {
|
||||||
auto other_off = other.off();
|
const size_t other_off = other.off();
|
||||||
bool multi = false;
|
|
||||||
if (other_off == off && key == other.ptr()->get_key()) {
|
if (other_off == off && key == other.ptr()->get_key()) {
|
||||||
auto founded = capacity;
|
auto founded = capacity;
|
||||||
|
size_t started = now;
|
||||||
|
bool multi = false;
|
||||||
do {
|
do {
|
||||||
if (other.ptr() == data) {
|
if (other.ptr() == data) {
|
||||||
founded = now;
|
founded = now;
|
||||||
}
|
}
|
||||||
now = (now + 1) & mask;
|
now = (now + 1) & mask;
|
||||||
other = array[now];
|
other = array[now];
|
||||||
if (!other.valid()) {
|
if (!other.valid() || UNLIKELY(started == now)) {
|
||||||
|
// Reason is possibility of map full of same values.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
other_off = other.off();
|
} while (other.equal(key, off) && (multi = true));
|
||||||
} while (other_off == off &&
|
// multi = true is correct
|
||||||
other.ptr()->get_key() == key &&
|
|
||||||
(multi = true)); // multi = true is correct
|
|
||||||
if (founded == capacity) {
|
if (founded == capacity) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bef = before_index(now, mask);
|
auto bef = before_index(now, mask);
|
||||||
array[founded] = array[bef];
|
array[founded] = array[bef];
|
||||||
// Same as remove of key only diffrence is with founded
|
|
||||||
|
|
||||||
auto start_rem = bef;
|
auto start_rem = bef;
|
||||||
while (other.valid() &&
|
while (other.valid() &&
|
||||||
@ -542,19 +197,10 @@ public:
|
|||||||
} else if (other_off < off) { // Other is rich
|
} else if (other_off < off) { // Other is rich
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} else { // Else other has equal or greater
|
} else { // Else other has equal or greater off, so he is poor.
|
||||||
// offset, so he is poor.
|
if (UNLIKELY(skip(now, other, other_off, mask))) {
|
||||||
auto other_key = other.ptr()->get_key();
|
break;
|
||||||
do {
|
}
|
||||||
now = (now + 1) & mask;
|
|
||||||
other = array[now];
|
|
||||||
checked++;
|
|
||||||
if (checked >= count) { // Reason is possibility of map
|
|
||||||
// full of same values.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (other.valid() && other.off() == other_off &&
|
|
||||||
other.ptr()->get_key() == other_key);
|
|
||||||
off++;
|
off++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -562,41 +208,138 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
free(array);
|
|
||||||
array = nullptr;
|
|
||||||
capacity = 0;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const { return count; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t before_index(size_t now, size_t mask)
|
// Skips same key valus as other. true if whole map is full of same key
|
||||||
|
// values.
|
||||||
|
bool skip(size_t &now, Combined &other, size_t other_off, size_t mask)
|
||||||
{
|
{
|
||||||
return (now - 1) & mask; // THIS IS VALID
|
auto other_key = other.ptr()->get_key();
|
||||||
|
size_t start = now;
|
||||||
|
do {
|
||||||
|
now = (now + 1) & mask;
|
||||||
|
other = array[now];
|
||||||
|
if (UNLIKELY(start == now)) { // Reason is possibility of map
|
||||||
|
// full of same values.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (other.valid() && other.equal(other_key, other_off));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t index(const K &key, size_t mask) const
|
void set(size_t now, D *data, size_t off)
|
||||||
{
|
{
|
||||||
return hash(std::hash<K>()(key)) & mask;
|
array[now] = Combined(data, off);
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t hash(size_t x) const
|
// True if no adjusment is needed, false otherwise.
|
||||||
|
bool is_off_adjusted(Combined &com, size_t mask, size_t start, size_t now,
|
||||||
|
bool multi)
|
||||||
{
|
{
|
||||||
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
|
if (com.off() == 0) { // Must be adjusted
|
||||||
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
|
return false;
|
||||||
x = x ^ (x >> 31);
|
}
|
||||||
return x;
|
size_t cin = index(com.ptr()->get_key(), mask);
|
||||||
|
if (outside(start, now, cin)) { // Outside [start,now] interval
|
||||||
|
return multi;
|
||||||
|
}
|
||||||
|
auto a = array[cin];
|
||||||
|
auto b = array[(cin + 1) & mask];
|
||||||
|
return a == b;
|
||||||
|
// Check if different key has eneterd in to
|
||||||
|
// range of other.
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mask() const { return capacity - 1; }
|
bool other_poor(Combined other, size_t mask, size_t start, size_t now)
|
||||||
|
{
|
||||||
|
// If other index is smaller then he is poorer.
|
||||||
|
return outside_left_weak(start, now,
|
||||||
|
index(other.ptr()->get_key(), mask));
|
||||||
|
}
|
||||||
|
|
||||||
Combined *array = nullptr;
|
// True if no adjusment is needed, false otherwise.
|
||||||
size_t capacity = 0;
|
bool is_off_adjusted_rem(Combined &com, size_t mask, size_t start,
|
||||||
size_t count = 0;
|
size_t bef, size_t now, bool multi)
|
||||||
|
{
|
||||||
|
if (com.off() == 0) { // Must be adjusted
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t cin = index(com.ptr()->get_key(), mask);
|
||||||
|
if (cin == bef) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (outside(start, now, cin)) {
|
||||||
|
return multi;
|
||||||
|
}
|
||||||
|
auto a = array[cin];
|
||||||
|
auto b = array[before_index(cin, mask)];
|
||||||
|
return b.valid() && a == b;
|
||||||
|
// Check if different key has eneterd in to
|
||||||
|
// range of other.
|
||||||
|
}
|
||||||
|
|
||||||
friend class IteratorBase<Iterator>;
|
// True if p is uutside [start,end] interval
|
||||||
friend class IteratorBase<ConstIterator>;
|
bool outside(size_t start, size_t end, size_t p)
|
||||||
|
{
|
||||||
|
return (start <= end && (p < start || p > end)) ||
|
||||||
|
(end < start && p < start && p > end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// True if p is outside <start,end] interval
|
||||||
|
bool outside_left_weak(size_t start, size_t end, size_t p)
|
||||||
|
{
|
||||||
|
return (start <= end && (p <= start || p > end)) ||
|
||||||
|
(end < start && p <= start && p > end);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Unnecessary
|
||||||
|
// // Removes element. Returns removed element if it existed. It doesn't
|
||||||
|
// // specify which element from same key group will be removed.
|
||||||
|
// OptionPtr<D> remove(const K &key_in)
|
||||||
|
// {
|
||||||
|
//
|
||||||
|
// if (count > 0) {
|
||||||
|
// auto key = std::ref(key_in);
|
||||||
|
// size_t mask = this->mask();
|
||||||
|
// size_t now = index(key, mask);
|
||||||
|
// size_t off = 0;
|
||||||
|
// size_t checked = 0;
|
||||||
|
// size_t border = 8 <= capacity ? 8 : capacity;
|
||||||
|
// Combined other = array[now];
|
||||||
|
// while (other.valid() && off < border) {
|
||||||
|
// auto other_off = other.off();
|
||||||
|
// bool multi = false;
|
||||||
|
// if (other_off == off && key == other.ptr()->get_key()) {
|
||||||
|
// do {
|
||||||
|
// now = (now + 1) & mask;
|
||||||
|
// other = array[now];
|
||||||
|
// if (!other.valid()) {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// other_off = other.off();
|
||||||
|
// } while (other_off == off &&
|
||||||
|
// other.ptr()->get_key() == key &&
|
||||||
|
// (multi = true)); // multi = true is correct
|
||||||
|
//
|
||||||
|
// auto bef = before_index(now, mask);
|
||||||
|
// auto ret = OptionPtr<D>(array[bef].ptr());
|
||||||
|
//
|
||||||
|
// move_before(now, bef, other, mask, multi);
|
||||||
|
// return ret;
|
||||||
|
//
|
||||||
|
// } else if (other_off < off) { // Other is rich
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// } else { // Else other has equal or greater off, so he is
|
||||||
|
// poor.
|
||||||
|
// if (UNLIKELY(skip(now, other, other_off, mask))) {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// off++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return OptionPtr<D>();
|
||||||
|
// }
|
||||||
|
@ -42,6 +42,36 @@ TEST_CASE("Robin hood hashmultimap insert/get check")
|
|||||||
REQUIRE(*map.find(0) == ptr0);
|
REQUIRE(*map.find(0) == ptr0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Robin hood hashmultimap extreme same key valus full")
|
||||||
|
{
|
||||||
|
RhHashMultiMap<int, Data> map;
|
||||||
|
|
||||||
|
for (int i = 0; i < 128; i++) {
|
||||||
|
map.add(new Data(7));
|
||||||
|
}
|
||||||
|
REQUIRE(map.size() == 128);
|
||||||
|
REQUIRE(map.find(7) != map.end());
|
||||||
|
REQUIRE(map.find(0) == map.end());
|
||||||
|
auto ptr0 = new Data(0);
|
||||||
|
map.add(ptr0);
|
||||||
|
REQUIRE(map.find(0) != map.end());
|
||||||
|
REQUIRE(*map.find(0) == ptr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Robin hood hashmultimap extreme same key valus full with remove")
|
||||||
|
{
|
||||||
|
RhHashMultiMap<int, Data> map;
|
||||||
|
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
map.add(new Data(7));
|
||||||
|
}
|
||||||
|
auto ptr = new Data(7);
|
||||||
|
map.add(ptr);
|
||||||
|
REQUIRE(map.size() == 128);
|
||||||
|
REQUIRE(!map.remove(new Data(0)));
|
||||||
|
REQUIRE(map.remove(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Robin hood hasmultihmap remove functionality")
|
TEST_CASE("Robin hood hasmultihmap remove functionality")
|
||||||
{
|
{
|
||||||
RhHashMultiMap<int, Data> map;
|
RhHashMultiMap<int, Data> map;
|
||||||
@ -51,7 +81,7 @@ TEST_CASE("Robin hood hasmultihmap remove functionality")
|
|||||||
map.add(ptr0);
|
map.add(ptr0);
|
||||||
REQUIRE(map.find(0) != map.end());
|
REQUIRE(map.find(0) != map.end());
|
||||||
REQUIRE(*map.find(0) == ptr0);
|
REQUIRE(*map.find(0) == ptr0);
|
||||||
REQUIRE(map.remove(0).get() == ptr0);
|
REQUIRE(map.remove(ptr0));
|
||||||
REQUIRE(map.find(0) == map.end());
|
REQUIRE(map.find(0) == map.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,37 +174,6 @@ TEST_CASE("Robin hood hashmultimap checked rand")
|
|||||||
cross_validate(map, s_map);
|
cross_validate(map, s_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Robin hood hashmultimap with remove checked")
|
|
||||||
{
|
|
||||||
RhHashMultiMap<int, Data> map;
|
|
||||||
std::multimap<int, Data *> s_map;
|
|
||||||
|
|
||||||
std::srand(std::time(0));
|
|
||||||
for (int i = 0; i < 162638; i++) {
|
|
||||||
int key = (std::rand() % 10000) << 3;
|
|
||||||
if ((std::rand() % 3) == 0) {
|
|
||||||
auto removed = map.remove(key);
|
|
||||||
auto it = s_map.find(key);
|
|
||||||
if (removed.is_present()) {
|
|
||||||
while (it != s_map.end() && it->second != removed.get()) {
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
REQUIRE(it != s_map.end());
|
|
||||||
s_map.erase(it);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
REQUIRE(it == s_map.end());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto data = new Data(key);
|
|
||||||
map.add(data);
|
|
||||||
s_map.insert(std::pair<int, Data *>(key, data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cross_validate(map, s_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Robin hood hashmultimap with remove data checked")
|
TEST_CASE("Robin hood hashmultimap with remove data checked")
|
||||||
{
|
{
|
||||||
RhHashMultiMap<int, Data> map;
|
RhHashMultiMap<int, Data> map;
|
||||||
|
Loading…
Reference in New Issue
Block a user