Finished remove method in RhMultiMap.

Remove passes tests.
Needs refactoring, has lot of duplicate code.
This commit is contained in:
Kruno Tomola Fabro 2016-08-10 23:05:24 +01:00
parent 3fffa17b0d
commit 15f7b14704
3 changed files with 291 additions and 266 deletions

View File

@ -191,6 +191,19 @@ void a_star(Db &db, int64_t sys_id_start, uint max_depth, EdgeFilter e_filter[],
t.commit();
}
// class Data
// {
//
// private:
// size_t data = 0;
// int key;
//
// public:
// Data(int key) : key(key) {}
//
// const int &get_key() { return key; }
// };
int main()
{
Db db;
@ -209,6 +222,24 @@ int main()
double elapsed_ms = (double(end - begin) / CLOCKS_PER_SEC) * 1000;
std::cout << "A-star: " << elapsed_ms << " [ms]\n";
// RhHashMultiMap benchmark
// const int n_pow2 = 20;
// int n = 1 << n_pow2;
// RhHashMultiMap<int, Data, n_pow2 + 1> map;
// std::srand(time(0));
// auto data = std::vector<Data *>();
// for (int i = 0; i < n; i++) {
// data.push_back(new Data(std::rand()));
// }
//
// begin = clock();
// for (auto e : data) {
// map.add(e);
// }
// end = clock();
// elapsed_ms = (double(end - begin) / CLOCKS_PER_SEC) * 1000;
// std::cout << "Map: " << elapsed_ms << " [ms]\n";
return 0;
}

View File

@ -30,7 +30,14 @@ private:
size_t off() { return data & 0x7; }
void decrement_off() { data--; }
bool decrement_off()
{
if (off() > 0) {
data--;
return true;
}
return false;
}
bool increment_off()
{
@ -255,7 +262,7 @@ public:
break;
} else { // Else other has equal or greater
// offset, so he is poor.
// offset, so he is poor.
auto other_key = other.ptr()->get_key();
do {
now = (now + 1) & mask;
@ -275,6 +282,9 @@ public:
return end();
}
// Inserts element.
void add(D *data) { add(data->get_key(), data); }
// Inserts element with the given key.
void add(const K &key_in, D *data)
{
@ -287,12 +297,12 @@ public:
size_t start = now;
size_t off = 0;
size_t border = 8 <= capacity ? 8 : capacity;
bool multi = false;
Combined other = array[now];
while (off < border) {
if (other.valid()) {
auto other_off = other.off();
bool multi = false;
if (other_off == off &&
other.ptr()->get_key() == key) { // Found the
do { // same
@ -321,8 +331,10 @@ public:
}
array[now] = Combined(data, off);
auto start = now;
while (adjust_off(other, mask, start, now, multi)) {
auto start_insert = now;
while (is_off_adjusted(other, mask, start_insert, now,
multi) ||
other.increment_off()) {
now = (now + 1) & mask;
auto tmp = array[now];
array[now] = other;
@ -352,244 +364,204 @@ private:
count++;
}
bool adjust_off(Combined &com, size_t mask, size_t start, size_t now,
bool multi)
// 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) {
com.increment_off();
return true;
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)) {
return multi || com.increment_off();
(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()) ||
com.increment_off();
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);
(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.
}
// void skip(size_t &now, size_t mask)
// {
// Combined start = array[now];
// size_t end = now;
// auto off = start.off();
// auto key = start.ptr()->get_key();
// do {
// now = (now + 1) & mask;
// start = array[now];
// } while (start.valid() && start.off() == off &&
// start.ptr()->get_key() == key && now != end);
// }
//
// void _insert(size_t now, Combined com)
// {
// Combined other = array[now];
// array[now] = com;
// if (other.valid()) {
// _add(now, other.off(), other.ptr());
// } else {
// count++;
// }
// }
//
// void _add(size_t now, size_t off, Data *data) {
// size_t mask = this->mask();
// auto key = std::ref(data->get_key());
// size_t border = 8 <= capacity ? 8 : capacity;
//
// skip()
//
// while(off<border){
// Combined other = array[now];
// if (other.valid()) {
// _add(now, other.off(), other.ptr());
// } else {
// _insert(now, RhHashMultiMap::Combined com)
// }
// }
//
// increase_size();
// add(data);
// }
public:
// // Inserts element with the given key.
// void add(const K &key_in, D *data)
// {
// assert(key_in == data->get_key());
//
// if (count < capacity) {
// auto key = std::ref(key_in);
// size_t mask = this->mask();
// size_t now = index(key, mask);
// size_t off = 0;
//
// bool bef_init = false;
// size_t before_off;
// auto before_key = std::ref(key);
// bool found_it = false;
//
// size_t border = 8 <= capacity ? 8 : capacity;
// while (off < border) {
// Combined other = array[now];
// if (other.valid()) {
// auto other_off = other.off();
// auto other_key = std::ref<const
// K>(other.ptr()->get_key());
// if (other_off == off && key == other_key) {
// found_it = true;
// // Proceed
//
// } else if (other_off < off || found_it) { // Other is
// rich
// // or after
// list
// // of my keys
// assert(other_off <= off);
//
// array[now] = Combined(data, off);
// // add(other.ptr()->get_key(), other.ptr());
// // return;
//
// // Hacked reusing of function
// before_off = off;
// before_key = key;
// data = other.ptr();
// key = other_key;
// off = other_off;
//
// if (found_it) { // Offset isn't increased
// found_it = false;
// } else {
// off++;
// }
// } else if (bef_init) { // Else other has equal or greater
// // offset, so he is poor.
// if (before_off == other_off &&
// before_key == other_key) {
// if (count == capacity) {
// break;
// }
// // Proceed
// } else {
// before_off = other_off;
// before_key = other_key;
// off++;
// }
// } else {
// bef_init = true;
// before_off = other_off;
// before_key = other_key;
// off++;
// }
//
// } else {
// array[now] = Combined(data, off);
// count++;
// return;
// }
//
// now = (now + 1) & mask;
// }
// }
//
// increase_size();
// add(data);
// }
// Inserts element.
void add(D *data) { add(data->get_key(), data); }
// 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)
{
// auto key = std::ref(key_in);
// size_t mask = this->mask();
// size_t now = index(key, mask);
// size_t off = 0;
//
// bool bef_init = false;
// size_t before_off;
// auto before_key = key;
// bool found_it = false;
//
// size_t border = 8 <= capacity ? 8 : capacity;
// while (off < border) {
// Combined other = array[now];
// if (other.valid()) {
// auto other_off = other.off();
// auto other_ptr = other.ptr();
// auto other_key = std::ref<const K>(other_ptr->get_key());
// if (other_off == off && key == other_key) { // Found it
// found_it = true;
//
// } else if (found_it) { // Found first element after last
// element
// // for remove.
// auto before = before_index(now, mask);
// auto ret = OptionPtr<D>(array[before].ptr());
// std::cout << "<-" << ret.get()->get_key() << "\n";
// while (other.valid() && other.off() > 0) {
// std::cout << "<>" << other.ptr()->get_key() << "\n";
// other.decrement_off();
// array[before] = other;
// before = now;
// now = (now + 1) & mask;
// other = array[now];
// }
//
// array[before] = Combined();
// count--;
// return ret;
// } else if (other_off < off) { // Other is rich
// break;
//
// } else if (bef_init) { // Else other has equal or greater
// // offset, so he is poor.
// if (before_off == other_off && before_key == other_key) {
// if (count == capacity) { // I am stuck.
// break;
// }
// // Proceed
// } else {
// before_off = other_off;
// before_key = other_key;
// off++;
// }
// } else {
// bef_init = true;
// before_off = other_off;
// before_key = other_key;
// off++;
// }
//
// } else if (found_it) { // Found empty space after last element
// for
// // remove.
// auto before = before_index(now, mask);
// auto ret = OptionPtr<D>(array[before].ptr());
// array[before] = Combined();
//
// return ret;
// } else {
// break;
// }
//
// now = (now + 1) & mask;
// }
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.
bool remove(D *data)
{
if (count > 0) {
auto key = std::ref(data->get_key());
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()) {
auto founded = capacity;
do {
if (other.ptr() == data) {
founded = now;
}
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
if (founded == capacity) {
return false;
}
auto bef = before_index(now, mask);
array[founded] = array[bef];
// Same as remove of key only diffrence is with founded
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 true;
} 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 false;
}
void clear()
{
free(array);

View File

@ -42,18 +42,18 @@ TEST_CASE("Robin hood hashmultimap insert/get check")
REQUIRE(*map.find(0) == ptr0);
}
// TEST_CASE("Robin hood hasmultihmap remove functionality")
// {
// RhHashMultiMap<int, Data> map;
//
// 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);
// REQUIRE(map.remove(0).get() == ptr0);
// REQUIRE(map.find(0) == map.end());
// }
TEST_CASE("Robin hood hasmultihmap remove functionality")
{
RhHashMultiMap<int, Data> map;
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);
REQUIRE(map.remove(0).get() == ptr0);
REQUIRE(map.find(0) == map.end());
}
TEST_CASE("Robin hood hashmultimap double insert")
{
@ -144,39 +144,62 @@ TEST_CASE("Robin hood hashmultimap checked rand")
cross_validate(map, s_map);
}
// TEST_CASE("Robin hood hashmultimap with remove checked")
// {
// RhHashMultiMap<int, Data> map;
// std::multimap<int, Data *> s_map;
//
// for (int i = 0; i < 2638; i++) {
// int key = (std::rand() % 100) << 3;
// if ((std::rand() % 3) == 0) {
// std::cout << "Remove: " << key << "\n";
// 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);
// // cross_validate(map, s_map);
//
// } else {
// // REQUIRE(it == s_map.end());
// }
// } else {
// std::cout << "Insert: " << key << "\n";
// auto data = new Data(key);
// map.add(data);
// s_map.insert(std::pair<int, Data *>(key, data));
// cross_validate(map, s_map);
// }
// }
//
// cross_validate_weak(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")
{
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() % 2) == 0) {
auto it = s_map.find(key);
if (it == s_map.end()) {
REQUIRE(map.find(key) == map.end());
} else {
s_map.erase(it);
REQUIRE(map.remove(it->second));
}
} else {
auto data = new Data(key);
map.add(data);
s_map.insert(std::pair<int, Data *>(key, data));
}
}
cross_validate(map, s_map);
}
void cross_validate(RhHashMultiMap<int, Data> &map,
std::multimap<int, Data *> &s_map)
@ -193,7 +216,6 @@ void cross_validate(RhHashMultiMap<int, Data> &map,
for (auto e : s_map) {
auto it = map.find(e.first);
// std::cout << "s_map: " << e.first << "\n";
while (it != map.end() && *it != e.second) {
it++;