name refactoring

This commit is contained in:
2018-12-28 09:23:38 +07:00
parent 28b58a8811
commit 98bfc99a0d
2 changed files with 121 additions and 108 deletions

110
ecs.hpp
View File

@@ -13,10 +13,8 @@
#include <tuple>
#include <memory>
#include <vector>
#include <limits>
#include <utility>
#include <iterator>
#include <exception>
#include <stdexcept>
#include <algorithm>
#include <functional>
@@ -37,35 +35,22 @@ namespace ecs_hpp
using family_id = std::uint16_t;
using entity_id = std::uint32_t;
const std::size_t entity_id_index_bits = 22;
const std::size_t entity_id_index_mask = (1 << entity_id_index_bits) - 1;
const std::size_t entity_id_version_bits = 10;
const std::size_t entity_id_version_mask = (1 << entity_id_version_bits) - 1;
constexpr std::size_t entity_id_index_bits = 22u;
constexpr std::size_t entity_id_version_bits = 10u;
static_assert(
std::is_unsigned<family_id>::value,
"ecs_hpp::family_id must be an unsigned integer");
"ecs_hpp (family_id must be an unsigned integer)");
static_assert(
std::is_unsigned<entity_id>::value,
"ecs_hpp::entity_id must be an unsigned integer");
"ecs_hpp (entity_id must be an unsigned integer)");
static_assert(
entity_id_index_bits > 0u &&
entity_id_version_bits > 0u &&
sizeof(entity_id) == (entity_id_index_bits + entity_id_version_bits) / 8u,
"ecs_hpp::entity_id mismatch index and version bits");
constexpr inline entity_id entity_id_index(entity_id id) noexcept {
return id & entity_id_index_mask;
}
constexpr inline entity_id entity_id_version(entity_id id) noexcept {
return (id >> entity_id_index_bits) & entity_id_version_mask;
}
constexpr inline entity_id entity_id_join(entity_id index, entity_id version) noexcept {
return index | (version << entity_id_index_bits);
}
"ecs_hpp (invalid entity id index and version bits)");
}
// -----------------------------------------------------------------------------
@@ -144,6 +129,31 @@ namespace ecs_hpp
}
return tuple_contains(tuple_tail(t), v);
}
//
// entity_id index/version
//
constexpr std::size_t entity_id_index_mask = (1u << entity_id_index_bits) - 1u;
constexpr std::size_t entity_id_version_mask = (1u << entity_id_version_bits) - 1u;
constexpr inline entity_id entity_id_index(entity_id id) noexcept {
return id & entity_id_index_mask;
}
constexpr inline entity_id entity_id_version(entity_id id) noexcept {
return (id >> entity_id_index_bits) & entity_id_version_mask;
}
constexpr inline entity_id entity_id_join(entity_id index, entity_id version) noexcept {
return index | (version << entity_id_index_bits);
}
constexpr inline entity_id upgrade_entity_id(entity_id id) noexcept {
return entity_id_join(
entity_id_index(id),
entity_id_version(id) + 1u);
}
}
}
@@ -320,15 +330,15 @@ namespace ecs_hpp
: end();
}
std::size_t get_index(const T& v) const {
const auto p = find_index(v);
std::size_t get_dense_index(const T& v) const {
const auto p = find_dense_index(v);
if ( p.second ) {
return p.first;
}
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_index(const T& v) const noexcept {
std::pair<std::size_t,bool> find_dense_index(const T& v) const noexcept {
return has(v)
? std::make_pair(sparse_[indexer_(v)], true)
: std::make_pair(std::size_t(-1), false);
@@ -474,7 +484,7 @@ namespace ecs_hpp
if ( !keys_.has(k) ) {
return false;
}
const std::size_t index = keys_.get_index(k);
const std::size_t index = keys_.get_dense_index(k);
values_[index] = std::move(values_.back());
values_.pop_back();
keys_.unordered_erase(k);
@@ -490,23 +500,23 @@ namespace ecs_hpp
return keys_.has(k);
}
T& get_value(const K& k) {
return values_[keys_.get_index(k)];
T& get(const K& k) {
return values_[keys_.get_dense_index(k)];
}
const T& get_value(const K& k) const {
return values_[keys_.get_index(k)];
const T& get(const K& k) const {
return values_[keys_.get_dense_index(k)];
}
T* find_value(const K& k) noexcept {
const auto ip = keys_.find_index(k);
T* find(const K& k) noexcept {
const auto ip = keys_.find_dense_index(k);
return ip.second
? &values_[ip.first]
: nullptr;
}
const T* find_value(const K& k) const noexcept {
const auto ip = keys_.find_index(k);
const T* find(const K& k) const noexcept {
const auto ip = keys_.find_dense_index(k);
return ip.second
? &values_[ip.first]
: nullptr;
@@ -603,7 +613,7 @@ namespace ecs_hpp
template < typename... Args >
void component_storage<T>::assign(entity_id id, Args&&... args) {
if ( !components_.emplace(id, std::forward<Args>(args)...) ) {
components_.get_value(id) = T(std::forward<Args>(args)...);
components_.get(id) = T(std::forward<Args>(args)...);
}
}
@@ -619,19 +629,19 @@ namespace ecs_hpp
template < typename T >
T* component_storage<T>::find(entity_id id) noexcept {
return components_.find_value(id);
return components_.find(id);
}
template < typename T >
const T* component_storage<T>::find(entity_id id) const noexcept {
return components_.find_value(id);
return components_.find(id);
}
template < typename T >
template < typename F >
void component_storage<T>::for_each_component(F&& f) noexcept {
for ( const auto id : components_ ) {
f(entity(owner_, id), components_.get_value(id));
f(entity(owner_, id), components_.get(id));
}
}
@@ -639,7 +649,7 @@ namespace ecs_hpp
template < typename F >
void component_storage<T>::for_each_component(F&& f) const noexcept {
for ( const auto id : components_ ) {
f(entity(owner_, id), components_.get_value(id));
f(entity(owner_, id), components_.get(id));
}
}
}
@@ -977,21 +987,19 @@ namespace ecs_hpp
inline entity registry::create_entity() {
if ( !free_entity_ids_.empty() ) {
const auto free_ent_id = free_entity_ids_.back();
const auto new_ent_id = entity_id_join(
entity_id_index(free_ent_id),
entity_id_version(free_ent_id) + 1u);
const auto new_ent_id = detail::upgrade_entity_id(free_ent_id);
auto ent = entity(*this, new_ent_id);
entity_ids_.insert(new_ent_id);
free_entity_ids_.pop_back();
return ent;
}
if ( last_entity_id_ < entity_id_index_mask ) {
if ( last_entity_id_ < detail::entity_id_index_mask ) {
auto ent = entity(*this, ++last_entity_id_);
entity_ids_.insert(ent.id());
return ent;
}
throw std::logic_error("ecs_hpp::registry(entity index overlow)");
throw std::logic_error("ecs_hpp::registry (entity index overlow)");
}
inline bool registry::destroy_entity(const entity& ent) {
@@ -1050,7 +1058,7 @@ namespace ecs_hpp
if ( component ) {
return *component;
}
throw std::logic_error("ecs_hpp::registry(component not found)");
throw std::logic_error("ecs_hpp::registry (component not found)");
}
template < typename T >
@@ -1059,7 +1067,7 @@ namespace ecs_hpp
if ( component ) {
return *component;
}
throw std::logic_error("ecs_hpp::registry(component not found)");
throw std::logic_error("ecs_hpp::registry (component not found)");
}
template < typename T >
@@ -1139,7 +1147,7 @@ namespace ecs_hpp
const auto family = detail::type_family<T>::id();
using raw_storage_ptr = detail::component_storage<T>*;
return storages_.has(family)
? static_cast<raw_storage_ptr>(storages_.get_value(family).get())
? static_cast<raw_storage_ptr>(storages_.get(family).get())
: nullptr;
}
@@ -1148,7 +1156,7 @@ namespace ecs_hpp
const auto family = detail::type_family<T>::id();
using raw_storage_ptr = const detail::component_storage<T>*;
return storages_.has(family)
? static_cast<raw_storage_ptr>(storages_.get_value(family).get())
? static_cast<raw_storage_ptr>(storages_.get(family).get())
: nullptr;
}
@@ -1163,7 +1171,7 @@ namespace ecs_hpp
family,
std::make_unique<detail::component_storage<T>>(*this));
return *static_cast<detail::component_storage<T>*>(
storages_.get_value(family).get());
storages_.get(family).get());
}
inline bool registry::is_entity_alive_impl_(const entity& ent) const noexcept {
@@ -1176,7 +1184,7 @@ namespace ecs_hpp
}
std::size_t removed_components = 0u;
for ( const auto id : storages_ ) {
if ( storages_.get_value(id)->remove(ent.id()) ) {
if ( storages_.get(id)->remove(ent.id()) ) {
++removed_components;
}
}

View File

@@ -90,8 +90,8 @@ TEST_CASE("detail") {
REQUIRE(s.capacity() == 0u);
REQUIRE_FALSE(s.has(42u));
REQUIRE(s.find(42u) == s.end());
REQUIRE_FALSE(s.find_index(42u).second);
REQUIRE_THROWS(s.get_index(42u));
REQUIRE_FALSE(s.find_dense_index(42u).second);
REQUIRE_THROWS(s.get_dense_index(42u));
REQUIRE(s.insert(42u));
@@ -102,9 +102,9 @@ TEST_CASE("detail") {
REQUIRE_FALSE(s.has(84u));
REQUIRE(s.find(42u) == s.begin());
REQUIRE(s.find_index(42u).second);
REQUIRE(s.find_index(42u).first == 0u);
REQUIRE(s.get_index(42u) == 0u);
REQUIRE(s.find_dense_index(42u).second);
REQUIRE(s.find_dense_index(42u).first == 0u);
REQUIRE(s.get_dense_index(42u) == 0u);
s.clear();
@@ -129,22 +129,22 @@ TEST_CASE("detail") {
REQUIRE(s.has(42u));
REQUIRE(s.has(84u));
REQUIRE(s.size() == 2u);
REQUIRE(s.find_index(42u).second);
REQUIRE(s.find_index(42u).first == 0u);
REQUIRE(s.find_index(84u).second);
REQUIRE(s.find_index(84u).first == 1u);
REQUIRE(s.get_index(42u) == 0u);
REQUIRE(s.get_index(84u) == 1u);
REQUIRE(s.find_dense_index(42u).second);
REQUIRE(s.find_dense_index(42u).first == 0u);
REQUIRE(s.find_dense_index(84u).second);
REQUIRE(s.find_dense_index(84u).first == 1u);
REQUIRE(s.get_dense_index(42u) == 0u);
REQUIRE(s.get_dense_index(84u) == 1u);
REQUIRE(s.unordered_erase(42u));
REQUIRE_FALSE(s.has(42u));
REQUIRE(s.has(84u));
REQUIRE(s.size() == 1u);
REQUIRE(s.find_index(84u).second);
REQUIRE(s.find_index(84u).first == 0u);
REQUIRE_THROWS(s.get_index(42u));
REQUIRE(s.get_index(84u) == 0u);
REQUIRE(s.find_dense_index(84u).second);
REQUIRE(s.find_dense_index(84u).first == 0u);
REQUIRE_THROWS(s.get_dense_index(42u));
REQUIRE(s.get_dense_index(84u) == 0u);
}
{
sparse_set<position_c, position_c_indexer> s{position_c_indexer()};
@@ -153,14 +153,14 @@ TEST_CASE("detail") {
REQUIRE(s.has(position_c(1,2)));
REQUIRE(s.emplace(3,4));
REQUIRE(s.has(position_c(3,4)));
REQUIRE(s.get_index(position_c(1,2)) == 0);
REQUIRE(s.get_index(position_c(3,4)) == 1);
REQUIRE(s.find_index(position_c(1,2)).first == 0);
REQUIRE(s.find_index(position_c(3,4)).first == 1);
REQUIRE(s.find_index(position_c(1,2)).second);
REQUIRE(s.find_index(position_c(3,4)).second);
REQUIRE(s.get_dense_index(position_c(1,2)) == 0);
REQUIRE(s.get_dense_index(position_c(3,4)) == 1);
REQUIRE(s.find_dense_index(position_c(1,2)).first == 0);
REQUIRE(s.find_dense_index(position_c(3,4)).first == 1);
REQUIRE(s.find_dense_index(position_c(1,2)).second);
REQUIRE(s.find_dense_index(position_c(3,4)).second);
REQUIRE(s.unordered_erase(position_c(1,2)));
REQUIRE(s.get_index(position_c(3,4)) == 0);
REQUIRE(s.get_dense_index(position_c(3,4)) == 0);
}
}
SECTION("sparse_map") {
@@ -177,10 +177,10 @@ TEST_CASE("detail") {
REQUIRE_FALSE(m.size());
REQUIRE(m.capacity() == 0u);
REQUIRE_FALSE(m.has(42u));
REQUIRE_THROWS(m.get_value(42u));
REQUIRE_THROWS(as_const(m).get_value(42u));
REQUIRE_FALSE(m.find_value(42u));
REQUIRE_FALSE(as_const(m).find_value(42u));
REQUIRE_THROWS(m.get(42u));
REQUIRE_THROWS(as_const(m).get(42u));
REQUIRE_FALSE(m.find(42u));
REQUIRE_FALSE(as_const(m).find(42u));
{
obj_t o{21u};
@@ -206,23 +206,23 @@ TEST_CASE("detail") {
REQUIRE_FALSE(m.has(25u));
REQUIRE_FALSE(m.has(99u));
REQUIRE(m.get_value(21u).x == 21u);
REQUIRE(m.get_value(42u).x == 42u);
REQUIRE(m.get_value(84u).x == 84u);
REQUIRE(as_const(m).get_value(84u).x == 84u);
REQUIRE_THROWS(m.get_value(11u));
REQUIRE_THROWS(m.get_value(25u));
REQUIRE_THROWS(m.get_value(99u));
REQUIRE_THROWS(as_const(m).get_value(99u));
REQUIRE(m.get(21u).x == 21u);
REQUIRE(m.get(42u).x == 42u);
REQUIRE(m.get(84u).x == 84u);
REQUIRE(as_const(m).get(84u).x == 84u);
REQUIRE_THROWS(m.get(11u));
REQUIRE_THROWS(m.get(25u));
REQUIRE_THROWS(m.get(99u));
REQUIRE_THROWS(as_const(m).get(99u));
REQUIRE(m.find_value(21u)->x == 21u);
REQUIRE(m.find_value(42u)->x == 42u);
REQUIRE(m.find_value(84u)->x == 84u);
REQUIRE(as_const(m).find_value(84u)->x == 84u);
REQUIRE_FALSE(m.find_value(11u));
REQUIRE_FALSE(m.find_value(25u));
REQUIRE_FALSE(m.find_value(99u));
REQUIRE_FALSE(as_const(m).find_value(99u));
REQUIRE(m.find(21u)->x == 21u);
REQUIRE(m.find(42u)->x == 42u);
REQUIRE(m.find(84u)->x == 84u);
REQUIRE(as_const(m).find(84u)->x == 84u);
REQUIRE_FALSE(m.find(11u));
REQUIRE_FALSE(m.find(25u));
REQUIRE_FALSE(m.find(99u));
REQUIRE_FALSE(as_const(m).find(99u));
REQUIRE(m.unordered_erase(42u));
REQUIRE_FALSE(m.unordered_erase(42u));
@@ -251,14 +251,14 @@ TEST_CASE("detail") {
REQUIRE(s.has(position_c(1,2)));
REQUIRE(s.emplace(position_c(3,4), obj_t{3}));
REQUIRE(s.has(position_c(3,4)));
REQUIRE(s.get_value(position_c(1,2)).x == 1);
REQUIRE(s.get_value(position_c(3,4)).x == 3);
REQUIRE(s.find_value(position_c(1,2))->x == 1);
REQUIRE(s.find_value(position_c(3,4))->x == 3);
REQUIRE(s.find_value(position_c(1,2)));
REQUIRE(s.find_value(position_c(3,4)));
REQUIRE(s.get(position_c(1,2)).x == 1);
REQUIRE(s.get(position_c(3,4)).x == 3);
REQUIRE(s.find(position_c(1,2))->x == 1);
REQUIRE(s.find(position_c(3,4))->x == 3);
REQUIRE(s.find(position_c(1,2)));
REQUIRE(s.find(position_c(3,4)));
REQUIRE(s.unordered_erase(position_c(1,2)));
REQUIRE(s.get_value(position_c(3,4)).x == 3);
REQUIRE(s.get(position_c(3,4)).x == 3);
}
}
}
@@ -301,38 +301,43 @@ TEST_CASE("registry") {
}
{
ecs::registry w;
using namespace ecs::detail;
const auto e1 = w.create_entity();
w.destroy_entity(e1);
const auto e2 = w.create_entity();
REQUIRE(e1 != e2);
REQUIRE(ecs::entity_id_index(e1.id()) == ecs::entity_id_index(e2.id()));
REQUIRE(ecs::entity_id_version(e1.id()) + 1 == ecs::entity_id_version(e2.id()));
REQUIRE(entity_id_index(e1.id()) == entity_id_index(e2.id()));
REQUIRE(entity_id_version(e1.id()) + 1 == entity_id_version(e2.id()));
w.destroy_entity(e2);
const auto e3 = w.create_entity();
REQUIRE(e3 != e2);
REQUIRE(ecs::entity_id_index(e2.id()) == ecs::entity_id_index(e3.id()));
REQUIRE(ecs::entity_id_version(e2.id()) + 1 == ecs::entity_id_version(e3.id()));
REQUIRE(entity_id_index(e2.id()) == entity_id_index(e3.id()));
REQUIRE(entity_id_version(e2.id()) + 1 == entity_id_version(e3.id()));
}
{
ecs::registry w;
using namespace ecs::detail;
auto e = w.create_entity();
const auto e_id = e.id();
for ( std::size_t i = 0; i < ecs::entity_id_version_mask; ++i ) {
for ( std::size_t i = 0; i < entity_id_version_mask; ++i ) {
e.destroy();
e = w.create_entity();
REQUIRE(ecs::entity_id_version(e_id) != ecs::entity_id_version(e.id()));
REQUIRE(entity_id_version(e_id) != entity_id_version(e.id()));
}
// entity version wraps around
e.destroy();
e = w.create_entity();
REQUIRE(ecs::entity_id_version(e_id) == ecs::entity_id_version(e.id()));
REQUIRE(entity_id_version(e_id) == entity_id_version(e.id()));
}
{
ecs::registry w;
for ( std::size_t i = 0; i < ecs::entity_id_index_mask; ++i ) {
using namespace ecs::detail;
for ( std::size_t i = 0; i < entity_id_index_mask; ++i ) {
w.create_entity();
}
// entity index overflow