Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 0 additions & 262 deletions pp/bare_bones/snug_composite.h
Original file line number Diff line number Diff line change
Expand Up @@ -708,266 +708,4 @@ class EncodingBimap : public GenericDecodingTable<EncodingBimap<Filament, Vector
}
};

template <template <template <class> class> class Filament, template <class> class Vector>
class ParallelEncodingBimap : public GenericDecodingTable<ParallelEncodingBimap<Filament, Vector>, Filament, Vector> {
using Base = GenericDecodingTable<ParallelEncodingBimap, Filament, Vector>;

friend class GenericDecodingTable<ParallelEncodingBimap, Filament, Vector>;

phmap::parallel_flat_hash_set<typename Base::Proxy, typename Base::Hasher, typename Base::EqualityComparator> set_;

PROMPP_ALWAYS_INLINE void after_items_load_impl(uint32_t first_loaded_id) noexcept {
set_.reserve(Base::items_.size());
for (auto id = first_loaded_id; id != Base::items_.size(); ++id) {
set_.emplace(typename Base::Proxy(id));
}
}

public:
inline __attribute__((always_inline)) ParallelEncodingBimap() noexcept : set_({}, 0, Base::hasher(), Base::equality_comparator()) {}

ParallelEncodingBimap(const ParallelEncodingBimap&) = delete;
ParallelEncodingBimap(ParallelEncodingBimap&&) = delete;
ParallelEncodingBimap& operator=(const ParallelEncodingBimap&) = delete;
ParallelEncodingBimap& operator=(ParallelEncodingBimap&&) = delete;

template <class Class>
inline __attribute__((always_inline)) uint32_t find_or_emplace(const Class& c) noexcept {
return *set_.lazy_emplace(c, [&](const auto& ctor) {
uint32_t id = Base::items_.size();
Base::items_.emplace_back(Base::data_, c);
ctor(id);
});
}

template <class Class>
inline __attribute__((always_inline)) uint32_t find_or_emplace(const Class& c, size_t hashval) noexcept {
return *set_.lazy_emplace_with_hash(c, phmap::phmap_mix<sizeof(size_t)>()(hashval), [&](const auto& ctor) {
uint32_t id = Base::items_.size();
Base::items_.emplace_back(Base::data_, c);
ctor(id);
});
}

template <class Class>
inline __attribute__((always_inline)) std::optional<uint32_t> find(const Class& c) const noexcept {
if (auto i = set_.find(c); i != set_.end()) {
return *i;
}
return {};
}

template <class Class>
inline __attribute__((always_inline)) std::optional<uint32_t> find(const Class& c, size_t hashval) const noexcept {
if (auto i = set_.find(c, phmap::phmap_mix<sizeof(size_t)>()(hashval)); i != set_.end()) {
return *i;
}
return {};
}

inline __attribute__((always_inline)) void rollback_impl(const typename Base::checkpoint_type& s) noexcept
requires(!Base::kIsReadOnly)
{
assert(s.size() <= Base::items_.size());

for (uint32_t i = s.size(); i != Base::items_.size(); ++i) {
set_.erase(typename Base::Proxy(i));
}
}

// TODO wrap everything with read/write mutex, and test it!
};

template <template <template <class> class> class Filament, template <class> class Vector>
class OrderedEncodingBimap : public GenericDecodingTable<OrderedEncodingBimap<Filament, Vector>, Filament, Vector> {
using Base = GenericDecodingTable<OrderedEncodingBimap, Filament, Vector>;

friend class GenericDecodingTable<OrderedEncodingBimap, Filament, Vector>;

using Set = phmap::btree_set<typename Base::Proxy, typename Base::LessComparator>;
Set set_;

protected:
PROMPP_ALWAYS_INLINE void after_items_load_impl(uint32_t first_loaded_id) noexcept {
for (auto id = first_loaded_id; id != Base::items_.size(); ++id) {
set_.emplace(typename Base::Proxy(id));
}
}

public:
inline __attribute__((always_inline)) OrderedEncodingBimap() noexcept : set_({}, Base::less_comparator()) {}

OrderedEncodingBimap(const OrderedEncodingBimap&) = delete;
OrderedEncodingBimap(OrderedEncodingBimap&&) = delete;
OrderedEncodingBimap& operator=(const OrderedEncodingBimap&) = delete;
OrderedEncodingBimap& operator=(OrderedEncodingBimap&&) = delete;

template <class Class>
inline __attribute__((always_inline)) uint32_t find_or_emplace(const Class& c) noexcept {
auto i = set_.lower_bound(c);
if (i != set_.end() && (*this)[*i] == c) {
return *i;
}

uint32_t id = Base::items_.size();
Base::items_.emplace_back(Base::data_, c);
set_.insert(i, typename Base::Proxy(id));

return id;
}

template <class Class>
inline __attribute__((always_inline)) uint32_t find_or_emplace(const Class& c, [[maybe_unused]] size_t hashval) noexcept {
return find_or_emplace(c);
}

template <class Class>
inline __attribute__((always_inline)) std::optional<uint32_t> find(const Class& c) const noexcept {
if (auto i = set_.find(c); i != set_.end()) {
return *i;
}
return {};
}

template <class Class>
inline __attribute__((always_inline)) std::optional<uint32_t> find(const Class& c, [[maybe_unused]] size_t hashval) const noexcept {
if (auto i = set_.find(c); i != set_.end()) {
return *i;
}
return {};
}

PROMPP_ALWAYS_INLINE void rollback_impl(const typename Base::checkpoint_type& s) noexcept
requires(!Base::kIsReadOnly)
{
assert(s.size() <= Base::items_.size());

for (uint32_t i = s.size(); i != Base::items_.size(); ++i) {
set_.erase(typename Base::Proxy(i));
}
}

inline __attribute__((always_inline)) auto begin() const noexcept {
return typename Base::template ItemIDIterator<typename Set::const_iterator>(this, set_.begin());
}
inline __attribute__((always_inline)) auto end() const noexcept { return typename Base::template IteratorSentinel<typename Set::const_iterator>(set_.end()); }

inline __attribute__((always_inline)) auto unordered_begin() const noexcept { return Base::begin(); }
inline __attribute__((always_inline)) auto unordered_end() const noexcept { return Base::end(); }
};

template <template <template <class> class> class Filament, template <class> class Vector>
class OrderedDecodingTable : public GenericDecodingTable<OrderedDecodingTable<Filament, Vector>, Filament, Vector> {
using Base = GenericDecodingTable<OrderedDecodingTable, Filament, Vector>;

public:
using Base::Base;
OrderedDecodingTable(const OrderedDecodingTable&) = delete;
OrderedDecodingTable(OrderedDecodingTable&&) = delete;
OrderedDecodingTable& operator=(const OrderedDecodingTable&) = delete;
OrderedDecodingTable& operator=(OrderedDecodingTable&&) = delete;

auto back() const noexcept { return Base::items_.back().composite(Base::data_); }

template <class Class>
inline __attribute__((always_inline)) uint32_t emplace_back(const Class& c) {
const uint32_t id = Base::items_.size();

if (id != 0 && c < back()) {
throw BareBones::Exception(0xf677f03159e75ee7, "Broken order of OrderedDecodingTable item emplacement");
}

Base::items_.emplace_back(Base::data_, c);

return id;
}
};

template <template <template <class> class> class Filament, template <class> class Vector>
class EncodingBimapWithOrderedAccess : public GenericDecodingTable<EncodingBimapWithOrderedAccess<Filament, Vector>, Filament, Vector> {
using Base = GenericDecodingTable<EncodingBimapWithOrderedAccess, Filament, Vector>;

friend class GenericDecodingTable<EncodingBimapWithOrderedAccess, Filament, Vector>;

using OrderedSet = phmap::btree_set<typename Base::Proxy, typename Base::LessComparator>;
OrderedSet ordered_set_;

using Set = phmap::flat_hash_set<typename Base::Proxy, typename Base::Hasher, typename Base::EqualityComparator>;
Set set_;

PROMPP_ALWAYS_INLINE void after_items_load_impl(uint32_t first_loaded_id) noexcept {
set_.reserve(Base::items_.size());
for (auto id = first_loaded_id; id != Base::items_.size(); ++id) {
set_.emplace(typename Base::Proxy(id));
ordered_set_.emplace(typename Base::Proxy(id));
}
}

public:
inline __attribute__((always_inline)) EncodingBimapWithOrderedAccess() noexcept
: ordered_set_({}, Base::less_comparator()), set_({}, 0, Base::hasher(), Base::equality_comparator()) {}

EncodingBimapWithOrderedAccess(const EncodingBimapWithOrderedAccess&) = delete;
EncodingBimapWithOrderedAccess(EncodingBimapWithOrderedAccess&&) = delete;
EncodingBimapWithOrderedAccess& operator=(const EncodingBimapWithOrderedAccess&) = delete;
EncodingBimapWithOrderedAccess& operator=(EncodingBimapWithOrderedAccess&&) = delete;

template <class Class>
inline __attribute__((always_inline)) uint32_t find_or_emplace(const Class& c) noexcept {
return *set_.lazy_emplace(c, [&](const auto& ctor) {
uint32_t id = Base::items_.size();
Base::items_.emplace_back(Base::data_, c);
ordered_set_.insert(typename Base::Proxy(id));
ctor(id);
});
}

template <class Class>
inline __attribute__((always_inline)) uint32_t find_or_emplace(const Class& c, size_t hashval) noexcept {
return *set_.lazy_emplace_with_hash(c, phmap::phmap_mix<sizeof(size_t)>()(hashval), [&](const auto& ctor) {
uint32_t id = Base::items_.size();
Base::items_.emplace_back(Base::data_, c);
ordered_set_.insert(typename Base::Proxy(id));
ctor(id);
});
}

template <class Class>
inline __attribute__((always_inline)) std::optional<uint32_t> find(const Class& c) const noexcept {
if (auto i = set_.find(c); i != set_.end()) {
return *i;
}
return {};
}

template <class Class>
inline __attribute__((always_inline)) std::optional<uint32_t> find(const Class& c, size_t hashval) const noexcept {
if (auto i = set_.find(c, phmap::phmap_mix<sizeof(size_t)>()(hashval)); i != set_.end()) {
return *i;
}
return {};
}

PROMPP_ALWAYS_INLINE void rollback_impl(const typename Base::checkpoint_type& s) noexcept
requires(!Base::kIsReadOnly)
{
assert(s.size() <= Base::items_.size());

for (uint32_t i = s.size(); i != Base::items_.size(); ++i) {
ordered_set_.erase(typename Base::Proxy(i));
set_.erase(typename Base::Proxy(i));
}
}

inline __attribute__((always_inline)) auto begin() const noexcept {
return typename Base::template ItemIDIterator<typename OrderedSet::const_iterator>(this, ordered_set_.begin());
}
inline __attribute__((always_inline)) auto end() const noexcept {
return typename Base::template IteratorSentinel<typename OrderedSet::const_iterator>(ordered_set_.end());
}

inline __attribute__((always_inline)) auto unordered_begin() const noexcept { return Base::begin(); }
inline __attribute__((always_inline)) auto unordered_end() const noexcept { return Base::end(); }
};

} // namespace BareBones::SnugComposite
72 changes: 32 additions & 40 deletions pp/bare_bones/tests/snug_composite_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,7 @@ class TestSnugCompositesStringFilament {
}
};

typedef testing::Types<BareBones::SnugComposite::EncodingBimap<TestSnugCompositesStringFilament, Vector>,
BareBones::SnugComposite::ParallelEncodingBimap<TestSnugCompositesStringFilament, Vector>,
BareBones::SnugComposite::OrderedEncodingBimap<TestSnugCompositesStringFilament, Vector>,
BareBones::SnugComposite::EncodingBimapWithOrderedAccess<TestSnugCompositesStringFilament, Vector>>
SnugCompositesBimapTypes;
typedef testing::Types<BareBones::SnugComposite::EncodingBimap<TestSnugCompositesStringFilament, Vector>> SnugCompositesBimapTypes;

template <class T>
struct SnugComposite : public testing::Test {
Expand Down Expand Up @@ -141,30 +137,28 @@ TYPED_TEST(SnugComposite, should_return_same_id_for_same_data) {
}

TYPED_TEST(SnugComposite, should_return_same_id_for_same_data_with_hash) {
if constexpr (!std::is_same_v<TypeParam, BareBones::SnugComposite::OrderedEncodingBimap<TestSnugCompositesStringFilament, Vector>>) {
TypeParam outcomes;
this->fill_table_with_random_values(outcomes);
TypeParam outcomes;
this->fill_table_with_random_values(outcomes);

std::string v = "12";
auto hash_val = BareBones::XXHash::hash(v);
auto id = outcomes.find_or_emplace(v, hash_val);
std::string v = "12";
auto hash_val = BareBones::XXHash::hash(v);
auto id = outcomes.find_or_emplace(v, hash_val);

EXPECT_EQ(id, outcomes.find_or_emplace(v, hash_val));
EXPECT_EQ(id, outcomes.find_or_emplace(v));
EXPECT_EQ(id, outcomes.find_or_emplace(v, hash_val));
EXPECT_EQ(id, outcomes.find_or_emplace(v));

EXPECT_EQ(outcomes.find_or_emplace(v, hash_val), outcomes.find(v, hash_val));
EXPECT_EQ(outcomes.find_or_emplace(v, hash_val), outcomes.find(v));
EXPECT_EQ(outcomes.find_or_emplace(v, hash_val), outcomes.find(v, hash_val));
EXPECT_EQ(outcomes.find_or_emplace(v, hash_val), outcomes.find(v));

v = "21";
hash_val = BareBones::XXHash::hash(v);
id = outcomes.find_or_emplace(v);
v = "21";
hash_val = BareBones::XXHash::hash(v);
id = outcomes.find_or_emplace(v);

EXPECT_EQ(id, outcomes.find_or_emplace(v, hash_val));
EXPECT_EQ(id, outcomes.find_or_emplace(v));
EXPECT_EQ(id, outcomes.find_or_emplace(v, hash_val));
EXPECT_EQ(id, outcomes.find_or_emplace(v));

EXPECT_EQ(outcomes.find_or_emplace(v), outcomes.find(v));
EXPECT_EQ(outcomes.find_or_emplace(v), outcomes.find(v, hash_val));
}
EXPECT_EQ(outcomes.find_or_emplace(v), outcomes.find(v));
EXPECT_EQ(outcomes.find_or_emplace(v), outcomes.find(v, hash_val));
}

TYPED_TEST(SnugComposite, should_return_different_id_for_different_data) {
Expand All @@ -183,29 +177,27 @@ TYPED_TEST(SnugComposite, should_return_different_id_for_different_data) {
}

TYPED_TEST(SnugComposite, should_return_different_id_for_different_data_with_hash) {
if constexpr (!std::is_same_v<TypeParam, BareBones::SnugComposite::OrderedEncodingBimap<TestSnugCompositesStringFilament, Vector>>) {
TypeParam outcomes;
this->fill_table_with_random_values(outcomes);
TypeParam outcomes;
this->fill_table_with_random_values(outcomes);

std::string v = "12";
size_t hash_val = std::hash<std::string>()(v);
auto id = outcomes.find_or_emplace(v, hash_val);
std::string v = "12";
size_t hash_val = std::hash<std::string>()(v);
auto id = outcomes.find_or_emplace(v, hash_val);

v = "21";
hash_val = std::hash<std::string>()(v);
v = "21";
hash_val = std::hash<std::string>()(v);

EXPECT_NE(id, outcomes.find_or_emplace(v, hash_val));
EXPECT_NE(id, outcomes.find_or_emplace(v));
EXPECT_NE(id, outcomes.find_or_emplace(v, hash_val));
EXPECT_NE(id, outcomes.find_or_emplace(v));

v = "13";
id = outcomes.find_or_emplace(v);
v = "13";
id = outcomes.find_or_emplace(v);

v = "31";
hash_val = std::hash<std::string>()(v);
v = "31";
hash_val = std::hash<std::string>()(v);

EXPECT_NE(id, outcomes.find_or_emplace(v, hash_val));
EXPECT_NE(id, outcomes.find_or_emplace(v));
}
EXPECT_NE(id, outcomes.find_or_emplace(v, hash_val));
EXPECT_NE(id, outcomes.find_or_emplace(v));
}

TYPED_TEST(SnugComposite, should_assign_new_ids_after_rollback) {
Expand Down
Loading