Skip to content

Commit

Permalink
merge from master
Browse files Browse the repository at this point in the history
  • Loading branch information
skypjack committed Mar 7, 2018
1 parent aea48d5 commit 86b7018
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 54 deletions.
26 changes: 15 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,26 +186,29 @@ amazing set of features. And even more, of course.
As it stands right now, `EnTT` is just fast enough for my requirements if
compared to my first choice (it was already amazingly fast actually).<br/>
Here is a comparison between the two (both of them compiled with GCC 7.2.0 on a
Here is a comparison between the two (both of them compiled with GCC 7.3.0 on a
Dell XPS 13 out of the mid 2014):
| Benchmark | EntityX (compile-time) | EnTT |
|-----------|-------------|-------------|
| Create 1M entities | 0.0167s | **0.0046s** |
| Destroy 1M entities | 0.0053s | **0.0022s** |
| Standard view, 1M entities, one component | 0.0012s | **1.9e-07s** |
| Standard view, 1M entities, two components | **0.0012s** | 0.0013s |
| Standard view, 1M entities, two components<br/>Half of the entities have all the components | 0.0009s | **0.0007s** |
| Standard view, 1M entities, two components<br/>One of the entities has all the components | 0.0008s | **1.3e-06s** |
| Standard view, 1M entities, two components | 0.0012s | **0.0010s** |
| Standard view, 1M entities, two components<br/>Half of the entities have all the components | 0.0009s | **0.0006s** |
| Standard view, 1M entities, two components<br/>One of the entities has all the components | 0.0008s | **1.0e-06s** |
| Persistent view, 1M entities, two components | 0.0012s | **2.8e-07s** |
| Standard view, 1M entities, five components | **0.0010s** | 0.0034s |
| Standard view, 1M entities, five components | **0.0010s** | 0.0024s |
| Persistent view, 1M entities, five components | 0.0010s | **2.8e-07s** |
| Standard view, 1M entities, ten components | **0.0011s** | 0.0075s |
| Standard view, 1M entities, ten components<br/>Half of the entities have all the components | **0.0010s** | 0.0041s |
| Standard view, 1M entities, ten components | **0.0011s** | 0.0058s |
| Standard view, 1M entities, ten components<br/>Half of the entities have all the components | **0.0010s** | 0.0032s |
| Standard view, 1M entities, ten components<br/>One of the entities has all the components | 0.0008s | **1.7e-06s** |
| Persistent view, 1M entities, ten components | 0.0011s | **3.0e-07s** |
| Sort 150k entities, one component<br/>Arrays are in reverse order | - | **0.0040s** |
| Sort 150k entities, enforce permutation<br/>Arrays are in reverse order | - | **0.0006s** |
| Sort 150k entities, one component<br/>Arrays are in reverse order | - | **0.0036s** |
| Sort 150k entities, enforce permutation<br/>Arrays are in reverse order | - | **0.0005s** |
Note: The default version of `EntityX` (`master` branch) wasn't added to the
comparison because it's already much slower than its compile-time counterpart.
`EnTT` includes its own tests and benchmarks. See
[benchmark.cpp](https://github.com/skypjack/entt/blob/master/test/benchmark.cpp)
Expand Down Expand Up @@ -1007,8 +1010,9 @@ components in their bags. During construction, these views look at the number
of entities available for each component and pick up a reference to the smallest
set of candidates in order to speed up iterations.<br/>
They offer fewer functionalities than their companion views for single
component, the most important of which can be used to reset the view and refresh
the reference to the set of candidate entities to iterate.<br/>
component. In particular, a multi component standard view exposes utility
functions to reset its internal state (optimization purposes) and to get the
estimated number of entities it is going to return.<br/>
Refer to the [official documentation](https://skypjack.github.io/entt/) for all
the details.

Expand Down
20 changes: 8 additions & 12 deletions src/entt/entity/registry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,8 @@ class Registry {
* @return True if the identifier is still valid, false otherwise.
*/
bool valid(entity_type entity) const noexcept {
using promotion_type = std::conditional_t<sizeof(size_type) >= sizeof(entity_type), size_type, entity_type>;
// explicit promotion to avoid warnings with std::uint16_t
const auto entt = promotion_type{entity} & traits_type::entity_mask;
return (entt < entities.size() && entities[entt] == entity);
const auto pos = size_type(entity & traits_type::entity_mask);
return (pos < entities.size() && entities[pos] == entity);
}

/**
Expand Down Expand Up @@ -325,11 +323,9 @@ class Registry {
* @return Actual version for the given entity identifier.
*/
version_type current(entity_type entity) const noexcept {
using promotion_type = std::conditional_t<sizeof(size_type) >= sizeof(entity_type), size_type, entity_type>;
// explicit promotion to avoid warnings with std::uint16_t
const auto entt = promotion_type{entity} & traits_type::entity_mask;
assert(entt < entities.size());
return version_type((entities[entt] >> traits_type::entity_shift) & traits_type::version_mask);
const auto pos = size_type(entity & traits_type::entity_mask);
assert(pos < entities.size());
return version_type((entities[pos] >> traits_type::entity_shift) & traits_type::version_mask);
}

/**
Expand Down Expand Up @@ -487,7 +483,7 @@ class Registry {
tags.resize(ttype + 1);
}

tags[ttype].reset(new Attaching<Tag>{entity, Tag{ std::forward<Args>(args)... }});
tags[ttype].reset(new Attaching<Tag>{entity, Tag{std::forward<Args>(args)...}});

return static_cast<Attaching<Tag> *>(tags[ttype].get())->tag;
}
Expand Down Expand Up @@ -694,7 +690,7 @@ class Registry {
template<typename... Component>
std::enable_if_t<(sizeof...(Component) > 1), std::tuple<const Component &...>>
get(entity_type entity) const noexcept {
return std::tuple<const Component &...>{ get<Component>(entity)... };
return std::tuple<const Component &...>{get<Component>(entity)...};
}

/**
Expand All @@ -714,7 +710,7 @@ class Registry {
template<typename... Component>
std::enable_if_t<(sizeof...(Component) > 1), std::tuple<Component &...>>
get(entity_type entity) noexcept {
return std::tuple<Component &...>{ get<Component>(entity)... };
return std::tuple<Component &...>{get<Component>(entity)...};
}

/**
Expand Down
55 changes: 44 additions & 11 deletions src/entt/entity/sparse_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,23 @@ class SparseSet<Entity> {
* @param cap Desired capacity.
*/
void reserve(size_type cap) {
reverse.reserve(cap);
direct.reserve(cap);
}

/**
* @brief Returns the extent of a sparse set.
*
* The extent of a sparse set is also the size of the internal sparse array.
* There is no guarantee that the internal packed array has the same size.
* Usually the size of the internal sparse array is equal or greater than
* the one of the internal packed array.
*
* @return Extent of the sparse set.
*/
size_type extent() const noexcept {
return reverse.size();
}

/**
* @brief Returns the number of elements in a sparse set.
*
Expand Down Expand Up @@ -220,11 +233,33 @@ class SparseSet<Entity> {
* @return True if the sparse set contains the entity, false otherwise.
*/
bool has(entity_type entity) const noexcept {
using promotion_type = std::conditional_t<sizeof(size_type) >= sizeof(entity_type), size_type, entity_type>;
// explicit promotion to avoid warnings with std::uint16_t
const auto entt = promotion_type{entity} & traits_type::entity_mask;
const auto pos = size_type(entity & traits_type::entity_mask);
// the in-use control bit permits to avoid accessing the direct vector
return (pos < reverse.size()) && (reverse[pos] & in_use);
}

/**
* @brief Checks if a sparse set contains an entity (unsafe).
*
* Alternative version of `has`. It accesses the underlying data structures
* without bounds checking and thus it's both unsafe and risky to use.<br/>
* You should not invoke directly this function unless you know exactly what
* you are doing. Prefer the `has` member function instead.
*
* @warning
* Attempting to use an entity that doesn't belong to the sparse set can
* result in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* bounds violation.
*
* @param entity A valid entity identifier.
* @return True if the sparse set contains the entity, false otherwise.
*/
bool fast(entity_type entity) const noexcept {
const auto pos = size_type(entity & traits_type::entity_mask);
assert(pos < reverse.size());
// the in-use control bit permits to avoid accessing the direct vector
return (entt < reverse.size()) && (reverse[entt] & in_use);
return (reverse[pos] & in_use);
}

/**
Expand Down Expand Up @@ -259,17 +294,15 @@ class SparseSet<Entity> {
*/
void construct(entity_type entity) {
assert(!has(entity));
using promotion_type = std::conditional_t<sizeof(size_type) >= sizeof(entity_type), size_type, entity_type>;
// explicit promotion to avoid warnings with std::uint16_t
const auto entt = promotion_type{entity} & traits_type::entity_mask;
const auto pos = size_type(entity & traits_type::entity_mask);

if(!(entt < reverse.size())) {
reverse.resize(entt+1, pos_type{});
if(!(pos < reverse.size())) {
reverse.resize(pos+1, pos_type{});
}

// we exploit the fact that pos_type is equal to entity_type and pos has
// traits_type::version_mask bits unused we can use to mark it as in-use
reverse[entt] = pos_type(direct.size()) | in_use;
reverse[pos] = pos_type(direct.size()) | in_use;
direct.emplace_back(entity);
}

Expand Down
50 changes: 37 additions & 13 deletions src/entt/entity/view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <utility>
#include <algorithm>
#include <type_traits>
#include "entt_traits.hpp"
#include "sparse_set.hpp"


Expand Down Expand Up @@ -209,7 +210,7 @@ class PersistentView final {
template<typename... Comp>
std::enable_if_t<(sizeof...(Comp) > 1), std::tuple<const Comp &...>>
get(entity_type entity) const noexcept {
return std::tuple<const Comp &...>{ get<Comp>(entity)... };
return std::tuple<const Comp &...>{get<Comp>(entity)...};
}

/**
Expand All @@ -232,7 +233,7 @@ class PersistentView final {
template<typename... Comp>
std::enable_if_t<(sizeof...(Comp) > 1), std::tuple<Comp &...>>
get(entity_type entity) noexcept {
return std::tuple<Comp &...>{ get<Comp>(entity)... };
return std::tuple<Comp &...>{get<Comp>(entity)...};
}

/**
Expand Down Expand Up @@ -302,7 +303,7 @@ class PersistentView final {

private:
view_type &view;
pattern_type pools;
const pattern_type pools;
};


Expand Down Expand Up @@ -358,20 +359,32 @@ class View final {
using underlying_iterator_type = typename view_type::iterator_type;
using unchecked_type = std::array<const view_type *, (sizeof...(Component) - 1)>;
using pattern_type = std::tuple<pool_type<Component> &...>;
using traits_type = entt_traits<Entity>;

class Iterator {
using size_type = typename view_type::size_type;

inline bool valid() const noexcept {
const auto entity = *begin;
const auto sz = size_type(entity & traits_type::entity_mask);
auto i = unchecked.size();
for(const auto entity = *begin; i && unchecked[i-1]->has(entity); --i);

if(sz < extent) {
for(; i && unchecked[i-1]->fast(entity); --i);
}

return !i;
}

public:
using difference_type = typename underlying_iterator_type::difference_type;
using value_type = typename view_type::entity_type;

Iterator(unchecked_type unchecked, underlying_iterator_type begin, underlying_iterator_type end) noexcept
: unchecked{unchecked}, begin{begin}, end{end}
Iterator(unchecked_type unchecked, size_type extent, underlying_iterator_type begin, underlying_iterator_type end) noexcept
: unchecked{unchecked},
extent{extent},
begin{begin},
end{end}
{
if(begin != end && !valid()) {
++(*this);
Expand All @@ -393,7 +406,7 @@ class View final {
}

Iterator operator+(difference_type value) noexcept {
return Iterator{unchecked, begin+value, end};
return Iterator{unchecked, extent, begin+value, end};
}

bool operator==(const Iterator &other) const noexcept {
Expand All @@ -409,7 +422,8 @@ class View final {
}

private:
unchecked_type unchecked;
const unchecked_type unchecked;
const size_type extent;
underlying_iterator_type begin;
underlying_iterator_type end;
};
Expand All @@ -428,6 +442,14 @@ class View final {
/*! @brief Unsigned integer type. */
using size_type = typename view_type::size_type;

/**
* @brief Estimates the number of entities that have the given components.
* @return Estimated number of entities that have the given components.
*/
size_type size() const noexcept {
return view->size();
}

/**
* @brief Returns an iterator to the first entity that has the given
* components.
Expand All @@ -443,7 +465,8 @@ class View final {
* @return An iterator to the first entity that has the given components.
*/
iterator_type begin() const noexcept {
return Iterator{unchecked, view->begin(), view->end()};
const auto extent = std::min({ std::get<pool_type<Component> &>(pools).extent()... });
return Iterator{unchecked, extent, view->begin(), view->end()};
}

/**
Expand All @@ -462,7 +485,8 @@ class View final {
* given components.
*/
iterator_type end() const noexcept {
return Iterator{unchecked, view->end(), view->end()};
const auto extent = std::min({ std::get<pool_type<Component> &>(pools).extent()... });
return Iterator{unchecked, extent, view->end(), view->end()};
}

/**
Expand Down Expand Up @@ -529,7 +553,7 @@ class View final {
template<typename... Comp>
std::enable_if_t<(sizeof...(Comp) > 1), std::tuple<const Comp &...>>
get(entity_type entity) const noexcept {
return std::tuple<const Comp &...>{ get<Comp>(entity)... };
return std::tuple<const Comp &...>{get<Comp>(entity)...};
}

/**
Expand All @@ -552,7 +576,7 @@ class View final {
template<typename... Comp>
std::enable_if_t<(sizeof...(Comp) > 1), std::tuple<Comp &...>>
get(entity_type entity) noexcept {
return std::tuple<Comp &...>{ get<Comp>(entity)... };
return std::tuple<Comp &...>{get<Comp>(entity)...};
}

/**
Expand Down Expand Up @@ -630,7 +654,7 @@ class View final {
}

private:
pattern_type pools;
const pattern_type pools;
const view_type *view;
unchecked_type unchecked;
};
Expand Down
2 changes: 1 addition & 1 deletion src/entt/process/process.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ struct ProcessAdaptor: Process<ProcessAdaptor<Func, Delta>, Delta>, private Func
* @param data Optional data.
*/
void update(Delta delta, void *data) {
Func::operator()(delta, data, [this](){ this->succeed(); }, [this](){ this->fail(); });
Func::operator()(delta, data, [this]() { this->succeed(); }, [this]() { this->fail(); });
}
};

Expand Down
Loading

0 comments on commit 86b7018

Please sign in to comment.