sparse_map::insert_or_assign and noexcept fixes

This commit is contained in:
2019-04-10 01:37:37 +07:00
parent a4a0ab7560
commit 007f1b228c
2 changed files with 75 additions and 42 deletions

98
ecs.hpp
View File

@@ -321,16 +321,19 @@ namespace ecs_hpp
return insert(T(std::forward<Args>(args)...)); return insert(T(std::forward<Args>(args)...));
} }
bool unordered_erase(const T& v) bool unordered_erase(const T& v) noexcept(
noexcept(std::is_nothrow_move_assignable<T>::value) noexcept(indexer_(std::declval<T>())) &&
std::is_nothrow_move_assignable<T>::value)
{ {
if ( !has(v) ) { if ( !has(v) ) {
return false; return false;
} }
const std::size_t vi = indexer_(v); const std::size_t vi = indexer_(v);
const std::size_t dense_index = sparse_[vi]; const std::size_t dense_index = sparse_[vi];
dense_[dense_index] = std::move(dense_.back()); if ( dense_index != dense_.size() - 1 ) {
sparse_[indexer_(dense_[dense_index])] = dense_index; dense_[dense_index] = std::move(dense_.back());
sparse_[indexer_(dense_[dense_index])] = dense_index;
}
dense_.pop_back(); dense_.pop_back();
return true; return true;
} }
@@ -339,17 +342,20 @@ namespace ecs_hpp
dense_.clear(); dense_.clear();
} }
bool has(const T& v) const noexcept { bool has(const T& v) const noexcept(
noexcept(indexer_(std::declval<T>())))
{
const std::size_t vi = indexer_(v); const std::size_t vi = indexer_(v);
return vi < sparse_.size() return vi < sparse_.size()
&& sparse_[vi] < dense_.size() && sparse_[vi] < dense_.size()
&& dense_[sparse_[vi]] == v; && dense_[sparse_[vi]] == v;
} }
const_iterator find(const T& v) const noexcept { const_iterator find(const T& v) const noexcept(
const std::size_t vi = indexer_(v); noexcept(indexer_(std::declval<T>())))
{
return has(v) return has(v)
? begin() + sparse_[vi] ? begin() + sparse_[indexer_(v)]
: end(); : end();
} }
@@ -361,7 +367,9 @@ namespace ecs_hpp
throw std::logic_error("ecs_hpp::sparse_set (value not found)"); throw std::logic_error("ecs_hpp::sparse_set (value not found)");
} }
std::pair<std::size_t,bool> find_dense_index(const T& v) const noexcept { std::pair<std::size_t,bool> find_dense_index(const T& v) const noexcept(
noexcept(indexer_(std::declval<T>())))
{
return has(v) return has(v)
? std::make_pair(sparse_[indexer_(v)], true) ? std::make_pair(sparse_[indexer_(v)], true)
: std::make_pair(std::size_t(-1), false); : std::make_pair(std::size_t(-1), false);
@@ -438,57 +446,59 @@ namespace ecs_hpp
sparse_map(const Indexer& indexer = Indexer()) sparse_map(const Indexer& indexer = Indexer())
: keys_(indexer) {} : keys_(indexer) {}
bool insert(const K& k, const T& v) { template < typename UK, typename UT >
bool insert(UK&& k, UT&& v) {
if ( keys_.has(k) ) { if ( keys_.has(k) ) {
return false; return false;
} }
values_.push_back(v); values_.push_back(std::forward<UT>(v));
try { try {
return keys_.insert(k); return keys_.insert(std::forward<UK>(k));
} catch (...) { } catch (...) {
values_.pop_back(); values_.pop_back();
throw; throw;
} }
} }
bool insert(const K& k, T&& v) { template < typename UK, typename... Args >
if ( keys_.has(k) ) { bool emplace(UK&& k, Args&&... args) {
return false;
}
values_.push_back(std::move(v));
try {
return keys_.insert(k);
} catch (...) {
values_.pop_back();
throw;
}
}
template < typename... Args >
bool emplace(const K& k, Args&&... args) {
if ( keys_.has(k) ) { if ( keys_.has(k) ) {
return false; return false;
} }
values_.emplace_back(std::forward<Args>(args)...); values_.emplace_back(std::forward<Args>(args)...);
try { try {
return keys_.insert(k); return keys_.insert(std::forward<UK>(k));
} catch (...) { } catch (...) {
values_.pop_back(); values_.pop_back();
throw; throw;
} }
} }
std::enable_if_t< template < typename UK, typename UT >
std::is_nothrow_move_assignable<K>::value, bool insert_or_assign(UK&& k, UT&& v) {
bool> if ( keys_.has(k) ) {
unordered_erase(const K& k) get(k) = std::forward<UT>(v);
noexcept(std::is_nothrow_move_assignable<T>::value) return false;
} else {
insert(std::forward<UK>(k), std::forward<UT>(v));
return true;
}
}
bool unordered_erase(const K& k) noexcept(
noexcept(keys_.find_dense_index(k)) &&
std::is_nothrow_move_assignable<T>::value)
{ {
if ( !keys_.has(k) ) { static_assert(
noexcept(keys_.unordered_erase(k)),
"unsupported with current key type");
const auto value_index_p = keys_.find_dense_index(k);
if ( !value_index_p.second ) {
return false; return false;
} }
const std::size_t value_index = keys_.get_dense_index(k); if ( value_index_p.first != values_.size() - 1 ) {
values_[value_index] = std::move(values_.back()); values_[value_index_p.first] = std::move(values_.back());
}
values_.pop_back(); values_.pop_back();
keys_.unordered_erase(k); keys_.unordered_erase(k);
return true; return true;
@@ -499,7 +509,9 @@ namespace ecs_hpp
values_.clear(); values_.clear();
} }
bool has(const K& k) const noexcept { bool has(const K& k) const noexcept(
noexcept(keys_.has(k)))
{
return keys_.has(k); return keys_.has(k);
} }
@@ -511,14 +523,18 @@ namespace ecs_hpp
return values_[keys_.get_dense_index(k)]; return values_[keys_.get_dense_index(k)];
} }
T* find(const K& k) noexcept { T* find(const K& k) noexcept(
noexcept(keys_.find_dense_index(k)))
{
const auto value_index_p = keys_.find_dense_index(k); const auto value_index_p = keys_.find_dense_index(k);
return value_index_p.second return value_index_p.second
? &values_[value_index_p.first] ? &values_[value_index_p.first]
: nullptr; : nullptr;
} }
const T* find(const K& k) const noexcept { const T* find(const K& k) const noexcept(
noexcept(keys_.find_dense_index(k)))
{
const auto value_index_p = keys_.find_dense_index(k); const auto value_index_p = keys_.find_dense_index(k);
return value_index_p.second return value_index_p.second
? &values_[value_index_p.first] ? &values_[value_index_p.first]
@@ -606,9 +622,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
template < typename... Args > template < typename... Args >
void component_storage<T>::assign(entity_id id, Args&&... args) { void component_storage<T>::assign(entity_id id, Args&&... args) {
if ( !components_.emplace(id, std::forward<Args>(args)...) ) { components_.insert_or_assign(id, T(std::forward<Args>(args)...));
components_.get(id) = T(std::forward<Args>(args)...);
}
} }
template < typename T > template < typename T >

View File

@@ -280,6 +280,25 @@ TEST_CASE("detail") {
REQUIRE(s.unordered_erase(position_c(1,2))); REQUIRE(s.unordered_erase(position_c(1,2)));
REQUIRE(s.get(position_c(3,4)).x == 3); REQUIRE(s.get(position_c(3,4)).x == 3);
} }
{
struct obj_t {
int x;
obj_t(int nx) : x(nx) {}
};
sparse_map<unsigned, obj_t> m;
REQUIRE(m.insert_or_assign(42, obj_t(42)));
REQUIRE(m.has(42));
REQUIRE(m.get(42).x == 42);
REQUIRE_FALSE(m.insert_or_assign(42, obj_t(21)));
REQUIRE(m.has(42));
REQUIRE(m.get(42).x == 21);
REQUIRE(m.size() == 1);
REQUIRE(m.insert_or_assign(84, obj_t(84)));
REQUIRE(m.has(84));
REQUIRE(m.get(84).x == 84);
REQUIRE(m.size() == 2);
}
} }
} }