sparse containers refactoring

This commit is contained in:
2018-12-29 01:03:32 +07:00
parent 4956a9efbd
commit 8f87d23c9b
2 changed files with 34 additions and 78 deletions

107
ecs.hpp
View File

@@ -212,7 +212,8 @@ namespace ecs_hpp
namespace detail namespace detail
{ {
template < typename T template < typename T
, bool = std::is_unsigned<T>::value && sizeof(T) <= sizeof(std::size_t) > , bool = std::is_unsigned<T>::value
&& sizeof(T) <= sizeof(std::size_t) >
struct sparse_unsigned_indexer { struct sparse_unsigned_indexer {
std::size_t operator()(const T v) const noexcept { std::size_t operator()(const T v) const noexcept {
return static_cast<std::size_t>(v); return static_cast<std::size_t>(v);
@@ -250,8 +251,7 @@ namespace ecs_hpp
} }
iterator end() noexcept { iterator end() noexcept {
using dt = typename std::iterator_traits<iterator>::difference_type; return dense_.end();
return begin() + static_cast<dt>(size_);
} }
const_iterator begin() const noexcept { const_iterator begin() const noexcept {
@@ -259,8 +259,7 @@ namespace ecs_hpp
} }
const_iterator end() const noexcept { const_iterator end() const noexcept {
using dt = typename std::iterator_traits<const_iterator>::difference_type; return dense_.end();
return begin() + static_cast<dt>(size_);
} }
const_iterator cbegin() const noexcept { const_iterator cbegin() const noexcept {
@@ -268,8 +267,7 @@ namespace ecs_hpp
} }
const_iterator cend() const noexcept { const_iterator cend() const noexcept {
using dt = typename std::iterator_traits<const_iterator>::difference_type; return dense_.cend();
return cbegin() + static_cast<dt>(size_);
} }
public: public:
sparse_set(const Indexer& indexer = Indexer()) sparse_set(const Indexer& indexer = Indexer())
@@ -280,12 +278,11 @@ namespace ecs_hpp
return false; return false;
} }
const std::size_t vi = indexer_(v); const std::size_t vi = indexer_(v);
if ( vi >= capacity_ ) { if ( vi >= sparse_.size() ) {
reserve(new_capacity_for_(vi + 1u)); sparse_.resize(new_sparse_size_for_(vi + 1u));
} }
dense_[size_] = std::move(v); dense_.push_back(std::move(v));
sparse_[vi] = size_; sparse_[vi] = dense_.size() - 1u;
++size_;
return true; return true;
} }
@@ -294,12 +291,11 @@ namespace ecs_hpp
return false; return false;
} }
const std::size_t vi = indexer_(v); const std::size_t vi = indexer_(v);
if ( vi >= capacity_ ) { if ( vi >= sparse_.size() ) {
reserve(new_capacity_for_(vi + 1u)); sparse_.resize(new_sparse_size_for_(vi + 1u));
} }
dense_[size_] = v; dense_.push_back(v);
sparse_[vi] = size_; sparse_[vi] = dense_.size() - 1u;
++size_;
return true; return true;
} }
@@ -315,21 +311,21 @@ namespace ecs_hpp
return false; return false;
} }
const std::size_t vi = indexer_(v); const std::size_t vi = indexer_(v);
const std::size_t index = sparse_[vi]; const std::size_t dense_index = sparse_[vi];
dense_[index] = std::move(dense_[size_ - 1u]); dense_[dense_index] = std::move(dense_.back());
sparse_[indexer_(dense_[index])] = index; sparse_[indexer_(dense_[dense_index])] = dense_index;
--size_; dense_.pop_back();
return true; return true;
} }
void clear() noexcept { void clear() noexcept {
size_ = 0u; dense_.clear();
} }
bool has(const T& v) const noexcept { bool has(const T& v) const noexcept {
const std::size_t vi = indexer_(v); const std::size_t vi = indexer_(v);
return vi < capacity_ return vi < sparse_.size()
&& sparse_[vi] < size_ && sparse_[vi] < dense_.size()
&& dense_[sparse_[vi]] == v; && dense_[sparse_[vi]] == v;
} }
@@ -355,49 +351,27 @@ namespace ecs_hpp
} }
bool empty() const noexcept { bool empty() const noexcept {
return size_ == 0u; return dense_.empty();
}
void reserve(std::size_t ncapacity) {
if ( ncapacity > capacity_ ) {
std::vector<T> ndense(ncapacity);
std::vector<std::size_t> nsparse(ncapacity);
std::copy(dense_.begin(), dense_.end(), ndense.begin());
std::copy(sparse_.begin(), sparse_.end(), nsparse.begin());
ndense.swap(dense_);
nsparse.swap(sparse_);
capacity_ = ncapacity;
}
} }
std::size_t size() const noexcept { std::size_t size() const noexcept {
return size_; return dense_.size();
}
std::size_t max_size() const noexcept {
return std::min(dense_.max_size(), sparse_.max_size());
}
std::size_t capacity() const noexcept {
return capacity_;
} }
private: private:
std::size_t new_capacity_for_(std::size_t nsize) const { std::size_t new_sparse_size_for_(std::size_t nsize) const {
const std::size_t ms = max_size(); const std::size_t ms = sparse_.max_size();
if ( nsize > ms ) { if ( nsize > ms ) {
throw std::length_error("ecs_hpp::sparse_set"); throw std::length_error("ecs_hpp::sparse_set");
} }
if ( capacity_ >= ms / 2u ) { if ( sparse_.size() >= ms / 2u ) {
return ms; return ms;
} }
return std::max(capacity_ * 2u, nsize); return std::max(sparse_.size() * 2u, nsize);
} }
private: private:
Indexer indexer_; Indexer indexer_;
std::vector<T> dense_; std::vector<T> dense_;
std::vector<std::size_t> sparse_; std::vector<std::size_t> sparse_;
std::size_t size_{0u};
std::size_t capacity_{0u};
}; };
} }
} }
@@ -494,8 +468,8 @@ namespace ecs_hpp
if ( !keys_.has(k) ) { if ( !keys_.has(k) ) {
return false; return false;
} }
const std::size_t index = keys_.get_dense_index(k); const std::size_t value_index = keys_.get_dense_index(k);
values_[index] = std::move(values_.back()); values_[value_index] = std::move(values_.back());
values_.pop_back(); values_.pop_back();
keys_.unordered_erase(k); keys_.unordered_erase(k);
return true; return true;
@@ -519,16 +493,16 @@ namespace ecs_hpp
} }
T* find(const K& k) noexcept { T* find(const K& k) noexcept {
const auto ip = keys_.find_dense_index(k); const auto value_index_p = keys_.find_dense_index(k);
return ip.second return value_index_p.second
? &values_[ip.first] ? &values_[value_index_p.first]
: nullptr; : nullptr;
} }
const T* find(const K& k) const noexcept { const T* find(const K& k) const noexcept {
const auto ip = keys_.find_dense_index(k); const auto value_index_p = keys_.find_dense_index(k);
return ip.second return value_index_p.second
? &values_[ip.first] ? &values_[value_index_p.first]
: nullptr; : nullptr;
} }
@@ -536,22 +510,9 @@ namespace ecs_hpp
return values_.empty(); return values_.empty();
} }
void reserve(std::size_t ncapacity) {
keys_.reserve(ncapacity);
values_.reserve(ncapacity);
}
std::size_t size() const noexcept { std::size_t size() const noexcept {
return values_.size(); return values_.size();
} }
std::size_t max_size() const noexcept {
return std::min(keys_.max_size(), values_.max_size());
}
std::size_t capacity() const noexcept {
return values_.capacity();
}
private: private:
sparse_set<K, Indexer> keys_; sparse_set<K, Indexer> keys_;
std::vector<T> values_; std::vector<T> values_;

View File

@@ -112,7 +112,6 @@ TEST_CASE("detail") {
REQUIRE(s.empty()); REQUIRE(s.empty());
REQUIRE_FALSE(s.size()); REQUIRE_FALSE(s.size());
REQUIRE(s.capacity() == 0u);
REQUIRE_FALSE(s.has(42u)); REQUIRE_FALSE(s.has(42u));
REQUIRE(s.find(42u) == s.end()); REQUIRE(s.find(42u) == s.end());
REQUIRE_FALSE(s.find_dense_index(42u).second); REQUIRE_FALSE(s.find_dense_index(42u).second);
@@ -122,7 +121,6 @@ TEST_CASE("detail") {
REQUIRE_FALSE(s.empty()); REQUIRE_FALSE(s.empty());
REQUIRE(s.size() == 1u); REQUIRE(s.size() == 1u);
REQUIRE(s.capacity() == 85u);
REQUIRE(s.has(42u)); REQUIRE(s.has(42u));
REQUIRE_FALSE(s.has(84u)); REQUIRE_FALSE(s.has(84u));
@@ -146,7 +144,6 @@ TEST_CASE("detail") {
REQUIRE_FALSE(s.has(84u)); REQUIRE_FALSE(s.has(84u));
REQUIRE(s.empty()); REQUIRE(s.empty());
REQUIRE_FALSE(s.size()); REQUIRE_FALSE(s.size());
REQUIRE(s.capacity() == 85u * 2);
s.insert(42u); s.insert(42u);
s.insert(84u); s.insert(84u);
@@ -200,7 +197,6 @@ TEST_CASE("detail") {
REQUIRE(m.empty()); REQUIRE(m.empty());
REQUIRE_FALSE(m.size()); REQUIRE_FALSE(m.size());
REQUIRE(m.capacity() == 0u);
REQUIRE_FALSE(m.has(42u)); REQUIRE_FALSE(m.has(42u));
REQUIRE_THROWS(m.get(42u)); REQUIRE_THROWS(m.get(42u));
REQUIRE_THROWS(as_const(m).get(42u)); REQUIRE_THROWS(as_const(m).get(42u));
@@ -223,7 +219,6 @@ TEST_CASE("detail") {
REQUIRE_FALSE(m.empty()); REQUIRE_FALSE(m.empty());
REQUIRE(m.size() == 3u); REQUIRE(m.size() == 3u);
REQUIRE(m.capacity() >= 3u);
REQUIRE(m.has(21u)); REQUIRE(m.has(21u));
REQUIRE(m.has(42u)); REQUIRE(m.has(42u));
REQUIRE(m.has(84u)); REQUIRE(m.has(84u));