Skip to content

Commit

Permalink
FlatBag using hashmap
Browse files Browse the repository at this point in the history
  • Loading branch information
malytomas committed Jan 11, 2024
1 parent 40425d9 commit 4ac651c
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 97 deletions.
73 changes: 25 additions & 48 deletions sources/include/cage-core/flatBag.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#ifndef guard_flatBag_sezik4edrt5
#define guard_flatBag_sezik4edrt5

#include <algorithm> // lower_bound, binary_search
#include <vector>

#include <unordered_dense.h>

#include <cage-core/core.h>

namespace cage
Expand All @@ -19,67 +20,46 @@ namespace cage

constexpr void insert(const Value &value)
{
CAGE_ASSERT(count(value) == 0);
if (indices.count(value))
return;
indices[value] = data_.size();
data_.push_back(value);
unsorted++;
if (unsorted > 100)
{
std::sort(data_.begin(), data_.end());
sorted = data_.size();
unsorted = 0;
}
}

constexpr uintPtr erase(const Value &value)
{
CAGE_ASSERT(sorted + unsorted == data_.size());
if (unsorted > 0)
{
auto it = std::find(data_.begin() + sorted, data_.end(), value);
if (it != data_.end())
{
std::swap(*it, data_.back());
data_.pop_back();
unsorted--;
return 1;
}
}
if (sorted > 0)
auto it = indices.find(value);
if (it == indices.end())
return 0;
const uintPtr off = it->second;
indices.erase(it);
if (off + 1 != data_.size())
{
auto it = std::lower_bound(data_.begin(), data_.begin() + sorted, value);
if (it == data_.begin() + sorted)
return 0;
if (*it != value)
return 0;
std::copy_n(it + 1, data_.end() - it - 1, it);
data_.pop_back();
sorted--;
return 1;
indices[data_.back()] = off;
std::swap(data_[off], data_.back());
}
return 0;
data_.pop_back();
return 1;
}

constexpr void clear()
{
indices.clear();
data_.clear();
sorted = unsorted = 0;
}

constexpr void reserve(uintPtr s) { data_.reserve(s); }
constexpr void reserve(uintPtr s)
{
indices.reserve(s);
data_.reserve(s);
}

constexpr const_iterator find(const Value &value) const
{
CAGE_ASSERT(sorted + unsorted == data_.size());
CAGE_ASSERT(std::is_sorted(data_.begin(), data_.begin() + sorted));
auto it = std::find(data_.begin() + sorted, data_.end(), value);
if (it != data_.end())
return it;
it = std::lower_bound(data_.begin(), data_.begin() + sorted, value);
if (it == data_.begin() + sorted)
auto it = indices.find(value);
if (it == indices.end())
return data_.end();
if (*it == value)
return it;
return data_.end();
return data_.begin() + it->second;
}

constexpr uintPtr count(const Value &value) const { return find(value) == end() ? 0 : 1; }
Expand All @@ -94,14 +74,11 @@ namespace cage

constexpr const_iterator end() const noexcept { return data_.end(); }

constexpr const std::vector<Value> &unsafeData() const noexcept { return data_; }

constexpr std::vector<Value> &unsafeData() noexcept { return data_; }

private:
ankerl::unordered_dense::map<Value, uintPtr> indices;
std::vector<Value> data_;
uintPtr sorted = 0;
uintPtr unsorted = 0;
};
}

Expand Down
2 changes: 0 additions & 2 deletions sources/include/cage-core/flatSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ namespace cage

constexpr const_reverse_iterator rend() const noexcept { return data_.rend(); }

constexpr const std::vector<Value> &unsafeData() const noexcept { return data_; }

constexpr std::vector<Value> &unsafeData() noexcept { return data_; }

private:
Expand Down
49 changes: 2 additions & 47 deletions sources/test-core/flatBag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,7 @@
#include <cage-core/flatBag.h>
#include <cage-core/flatSet.h>
#include <cage-core/math.h>

namespace
{
constexpr uint32 testConstexpr()
{
FlatBag<String> s;
s.insert("hello");
s.insert("there");
s.insert("Obi-Wan");
s.insert("Kenobi");
s.insert("says");
s.insert("how");
s.insert("are");
s.insert("you");
s.erase("bro");
return s.size();
}
}
#include <cage-core/stdHash.h>

void testFlatBag()
{
Expand All @@ -34,7 +17,7 @@ void testFlatBag()
s.insert(1024);
s.insert(42);
CAGE_TEST(s.size() == 3);
CAGE_TEST_ASSERTED(s.insert(1024));
s.insert(42);
CAGE_TEST(s.size() == 3);
CAGE_TEST(s.count(20) == 0);
CAGE_TEST(s.count(42) == 1);
Expand Down Expand Up @@ -71,31 +54,10 @@ void testFlatBag()
s.insert(1024);
s.insert(13);
s.insert(42);
CAGE_TEST_ASSERTED(s.insert(1024));
PointerRange<const uint32> pr = s;
CAGE_TEST(pr.size() == 3);
}

{
CAGE_TESTCASE("custom struct");

struct Custom
{
uint32 v = m;
constexpr explicit Custom(uint32 v) : v(v) {}
constexpr bool operator<(const Custom &b) const noexcept { return v < b.v; }
constexpr bool operator==(const Custom &b) const noexcept { return v == b.v; }
};

FlatBag<Custom> s;
s.insert(Custom(1024));
s.insert(Custom(13));
s.insert(Custom(42));
CAGE_TEST(s.size() == 3);
CAGE_TEST(s.count(Custom(20)) == 0);
CAGE_TEST(s.count(Custom(42)) == 1);
}

{
CAGE_TESTCASE("find");

Expand All @@ -122,13 +84,6 @@ void testFlatBag()
CAGE_TEST(s.count(42) == 0);
}

{
CAGE_TESTCASE("constexpr");
constexpr const uint32 a = testConstexpr();
uint32 b = testConstexpr();
CAGE_TEST(a == b);
}

{
CAGE_TESTCASE("randomized");

Expand Down

0 comments on commit 4ac651c

Please sign in to comment.