Compare commits

..

14 Commits

Author SHA1 Message Date
Paolo Monteverde
59cec88a28 fixing clang build (#38) 2018-02-08 14:56:07 +01:00
Michele Caini
3ebc75af80 updated version 2018-02-08 12:42:38 +01:00
Michele Caini
4dce474e03 revert: too risky a function 2018-02-08 12:27:48 +01:00
Michele Caini
31a18da578 fix #37 2018-02-08 12:23:48 +01:00
Michele Caini
8c499850fc fixed doc 2018-02-04 12:36:50 +01:00
Michele Caini
6b6998a247 duktape is now an external 2018-02-04 12:31:24 +01:00
Michele Caini
a6cb0fc856 added Registry::alive and Registry::orphans 2018-02-02 17:35:15 +01:00
Michele Caini
e36b93e87b fixed 2018-02-02 12:58:10 +01:00
Michele Caini
1e3723b8bb minor changes 2018-02-02 12:38:17 +01:00
Michele Caini
412372289e updated copyright 2018-01-26 17:28:40 +01:00
Michele Caini
96f7e66073 fixed 2018-01-14 00:53:55 +01:00
Michele Caini
6040f8f263 issue #31: multi component get 2018-01-14 00:32:23 +01:00
Michele Caini
9761b6e14a updated version 2017-12-29 18:29:38 +01:00
Michele Caini
cb49910ed2 allow attaching listeners at any time, allow removing current listener 2017-12-29 18:25:49 +01:00
21 changed files with 253 additions and 100182 deletions

2
.gitignore vendored
View File

@@ -1,2 +1,2 @@
# QtCreator
*.user
TODO

View File

@@ -16,7 +16,7 @@ endif()
# Project configuration
#
project(entt VERSION 2.4.0)
project(entt VERSION 2.4.2)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
@@ -29,7 +29,7 @@ set(PROJECT_AUTHOR_EMAIL "michele.caini@gmail.com")
message("*")
message("* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
message("* Copyright (c) 2017 ${PROJECT_AUTHOR} <${PROJECT_AUTHOR_EMAIL}>")
message("* Copyright (c) 2018 ${PROJECT_AUTHOR} <${PROJECT_AUTHOR_EMAIL}>")
message("*")
#

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2017 Michele Caini
Copyright (c) 2018 Michele Caini
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -377,7 +377,7 @@ registry.assign<Position>(entity, 0., 0.);
// ...
auto &velocity = registry.assign<Velocity>(entity);
Velocity &velocity = registry.assign<Velocity>(entity);
velocity.dx = 0.;
velocity.dy = 0.;
```
@@ -390,7 +390,7 @@ registry.replace<Position>(entity, 0., 0.);
// ...
auto &velocity = registry.replace<Velocity>(entity);
Velocity &velocity = registry.replace<Velocity>(entity);
velocity.dx = 0.;
velocity.dy = 0.;
```
@@ -405,7 +405,7 @@ registry.accomodate<Position>(entity, 0., 0.);
// ...
auto &velocity = registry.accomodate<Velocity>(entity);
Velocity &velocity = registry.accomodate<Velocity>(entity);
velocity.dx = 0.;
velocity.dy = 0.;
```
@@ -464,13 +464,16 @@ their components are destroyed:
Finally, references to components can be retrieved simply by doing this:
```cpp
// either a non-const reference ...
entt::DefaultRegistry registry;
auto &position = registry.get<Position>(entity);
// ... or a const one
const auto &cregistry = registry;
const auto &position = cregistry.get<Position>(entity);
// const and non-const reference
const Position &position = cregistry.get<Position>(entity);
Position &position = registry.get<Position>(entity);
// const and non-const references
std::tuple<const Position &, const Velocity &> tup = cregistry.get<Position, Velocity>(entity);
std::tuple<Position &, Velocity &> tup = registry.get<Position, Velocity>(entity);
```
The `get` member function template gives direct access to the component of an
@@ -516,11 +519,11 @@ References to tags can be retrieved simply by doing this:
```cpp
// either a non-const reference ...
entt::DefaultRegistry registry;
auto &player = registry.get<PlayingCharacter>();
PlayingCharacter &player = registry.get<PlayingCharacter>();
// ... or a const one
const auto &cregistry = registry;
const auto &camera = cregistry.get<Camera>();
const Camera &camera = cregistry.get<Camera>();
```
The `get` member function template gives direct access to the tag as stored in
@@ -705,7 +708,7 @@ To iterate a single component standard view, either use it in range-for loop:
auto view = registry.view<Renderable>();
for(auto entity: view) {
auto &renderable = view.get(entity);
Renderable &renderable = view.get(entity);
// ...
}
@@ -749,8 +752,12 @@ To iterate a multi component standard view, either use it in range-for loop:
auto view = registry.view<Position, Velocity>();
for(auto entity: view) {
auto &position = view.get<Position>(entity);
auto &velocity = view.get<Velocity>(entity);
// a component at a time ...
Position &position = view.get<Position>(entity);
Velocity &velocity = view.get<Velocity>(entity);
// ... or multiple components at once
std::tuple<Position &, Velocity &> tup = view.get<Position, Velocity>(entity);
// ...
}
@@ -817,8 +824,12 @@ To iterate a persistent view, either use it in range-for loop:
auto view = registry.persistent<Position, Velocity>();
for(auto entity: view) {
auto &position = view.get<Position>(entity);
auto &velocity = view.get<Velocity>(entity);
// a component at a time ...
Position &position = view.get<Position>(entity);
Velocity &velocity = view.get<Velocity>(entity);
// ... or multiple components at once
std::tuple<Position &, Velocity &> tup = view.get<Position, Velocity>(entity);
// ...
}
@@ -918,7 +929,7 @@ who has partecipated so far.
# License
Code and documentation Copyright (c) 2017 Michele Caini.<br/>
Code and documentation Copyright (c) 2018 Michele Caini.<br/>
Code released under
[the MIT license](https://github.com/skypjack/entt/blob/master/LICENSE).
Docs released under

19
cmake/in/duktape.in Normal file
View File

@@ -0,0 +1,19 @@
project(duktape-download NONE)
cmake_minimum_required(VERSION 3.2)
include(ExternalProject)
ExternalProject_Add(
duktape
GIT_REPOSITORY https://github.com/svaarala/duktape-releases.git
GIT_TAG v2.2.0
DOWNLOAD_DIR ${DUKTAPE_DEPS_DIR}
TMP_DIR ${DUKTAPE_DEPS_DIR}/tmp
STAMP_DIR ${DUKTAPE_DEPS_DIR}/stamp
SOURCE_DIR ${DUKTAPE_DEPS_DIR}/src
BINARY_DIR ${DUKTAPE_DEPS_DIR}/build
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

View File

@@ -2,6 +2,7 @@
#define ENTT_CORE_HASHED_STRING_HPP
#include <cstddef>
#include <cstdint>

View File

@@ -22,6 +22,8 @@ template<typename Entity, typename Delta>
struct Actor {
/*! @brief Type of registry used internally. */
using registry_type = Registry<Entity>;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Type used to provide elapsed time. */
using delta_type = Delta;

View File

@@ -1,5 +1,5 @@
#ifndef ENTT_ENTITY_ENTT_HPP
#define ENTT_ENTITY_ENTT_HPP
#ifndef ENTT_ENTITY_ENTT_TRAITS_HPP
#define ENTT_ENTITY_ENTT_TRAITS_HPP
#include <cstdint>
@@ -93,4 +93,4 @@ struct entt_traits<std::uint64_t> {
}
#endif // ENTT_ENTITY_ENTT_HPP
#endif // ENTT_ENTITY_ENTT_TRAITS_HPP

View File

@@ -2,6 +2,7 @@
#define ENTT_ENTITY_REGISTRY_HPP
#include <tuple>
#include <vector>
#include <memory>
#include <utility>
@@ -9,9 +10,10 @@
#include <cstdint>
#include <cassert>
#include <algorithm>
#include <type_traits>
#include "../core/family.hpp"
#include "entt_traits.hpp"
#include "sparse_set.hpp"
#include "traits.hpp"
#include "view.hpp"
@@ -644,7 +646,7 @@ public:
*
* @tparam Component Type of component to get.
* @param entity A valid entity identifier.
* @return A reference to the instance of the component owned by the entity.
* @return A reference to the component owned by the entity.
*/
template<typename Component>
const Component & get(entity_type entity) const noexcept {
@@ -664,13 +666,53 @@ public:
*
* @tparam Component Type of component to get.
* @param entity A valid entity identifier.
* @return A reference to the instance of the component owned by the entity.
* @return A reference to the component owned by the entity.
*/
template<typename Component>
Component & get(entity_type entity) noexcept {
return const_cast<Component &>(const_cast<const Registry *>(this)->get<Component>(entity));
}
/**
* @brief Returns a reference to the given components for an entity.
*
* @warning
* Attempting to use an invalid entity or to get components from an entity
* that doesn't own them results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entity or if the entity doesn't own instances of the given
* components.
*
* @tparam Component Type of components to get.
* @param entity A valid entity identifier.
* @return References to the components owned by the entity.
*/
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)... };
}
/**
* @brief Returns a reference to the given components for an entity.
*
* @warning
* Attempting to use an invalid entity or to get components from an entity
* that doesn't own them results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entity or if the entity doesn't own instances of the given
* components.
*
* @tparam Component Type of components to get.
* @param entity A valid entity identifier.
* @return References to the components owned by the entity.
*/
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)... };
}
/**
* @brief Replaces the given component for an entity.
*

View File

@@ -9,7 +9,7 @@
#include <cstddef>
#include <cassert>
#include <type_traits>
#include "traits.hpp"
#include "entt_traits.hpp"
namespace entt {
@@ -56,10 +56,10 @@ template<typename Entity>
class SparseSet<Entity> {
using traits_type = entt_traits<Entity>;
struct Iterator {
struct Iterator final {
using value_type = Entity;
Iterator(const std::vector<Entity> *direct, std::size_t pos)
Iterator(const std::vector<value_type> *direct, std::size_t pos)
: direct{direct}, pos{pos}
{}
@@ -85,7 +85,7 @@ class SparseSet<Entity> {
}
private:
const std::vector<Entity> *direct;
const std::vector<value_type> *direct;
std::size_t pos;
};
@@ -516,7 +516,7 @@ public:
object_type & construct(entity_type entity, Args&&... args) {
underlying_type::construct(entity);
// emplace_back doesn't work well with PODs because of its placement new
instances.push_back({ std::forward<Args>(args)... });
instances.push_back(object_type{ std::forward<Args>(args)... });
return instances.back();
}
@@ -533,7 +533,9 @@ public:
*/
void destroy(entity_type entity) override {
// swapping isn't required here, we are getting rid of the last element
instances[underlying_type::get(entity)] = std::move(instances.back());
// however, we must protect ourselves from self assignments (see #37)
auto tmp = std::move(instances.back());
instances[underlying_type::get(entity)] = std::move(tmp);
instances.pop_back();
underlying_type::destroy(entity);
}

View File

@@ -5,6 +5,7 @@
#include <tuple>
#include <utility>
#include <algorithm>
#include <type_traits>
#include "sparse_set.hpp"
@@ -188,6 +189,52 @@ public:
return const_cast<Comp &>(const_cast<const PersistentView *>(this)->get<Comp>(entity));
}
/**
* @brief Returns the components assigned to the given entity.
*
* Prefer this function instead of `Registry::get` during iterations. It has
* far better performance than its companion function.
*
* @warning
* Attempting to use invalid component types results in a compilation error.
* Attempting to use an entity that doesn't belong to the view results in
* undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if
* the view doesn't contain the given entity.
*
* @tparam Comp Types of the components to get.
* @param entity A valid entity identifier.
* @return The components assigned to the entity.
*/
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)... };
}
/**
* @brief Returns the components assigned to the given entity.
*
* Prefer this function instead of `Registry::get` during iterations. It has
* far better performance than its companion function.
*
* @warning
* Attempting to use invalid component types results in a compilation error.
* Attempting to use an entity that doesn't belong to the view results in
* undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if
* the view doesn't contain the given entity.
*
* @tparam Comp Types of the components to get.
* @param entity A valid entity identifier.
* @return The components assigned to the entity.
*/
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)... };
}
/**
* @brief Iterate the entities and applies them the given function object.
*
@@ -457,6 +504,52 @@ public:
return const_cast<Comp &>(const_cast<const View *>(this)->get<Comp>(entity));
}
/**
* @brief Returns the components assigned to the given entity.
*
* Prefer this function instead of `Registry::get` during iterations. It has
* far better performance than its companion function.
*
* @warning
* Attempting to use invalid component types results in a compilation error.
* Attempting to use an entity that doesn't belong to the view results in
* undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if
* the view doesn't contain the given entity.
*
* @tparam Comp Types of the components to get.
* @param entity A valid entity identifier.
* @return The components assigned to the entity.
*/
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)... };
}
/**
* @brief Returns the components assigned to the given entity.
*
* Prefer this function instead of `Registry::get` during iterations. It has
* far better performance than its companion function.
*
* @warning
* Attempting to use invalid component types results in a compilation error.
* Attempting to use an entity that doesn't belong to the view results in
* undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if
* the view doesn't contain the given entity.
*
* @tparam Comp Types of the components to get.
* @param entity A valid entity identifier.
* @return The components assigned to the entity.
*/
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)... };
}
/**
* @brief Iterate the entities and applies them the given function object.
*

View File

@@ -2,9 +2,9 @@
#include "core/hashed_string.hpp"
#include "core/ident.hpp"
#include "entity/actor.hpp"
#include "entity/entt_traits.hpp"
#include "entity/registry.hpp"
#include "entity/sparse_set.hpp"
#include "entity/traits.hpp"
#include "entity/view.hpp"
#include "locator/locator.hpp"
#include "process/process.hpp"

View File

@@ -181,7 +181,9 @@ public:
const auto buf = buffer(mode);
mode = !mode;
for(auto &&wrapper: wrappers) {
for(auto pos = wrappers.size(); pos > decltype(pos){0}; --pos) {
auto &wrapper = wrappers[pos-1];
if(wrapper) {
wrapper->publish(buf);
}

View File

@@ -229,7 +229,8 @@ public:
* @param args Arguments to use to invoke listeners.
*/
void publish(Args... args) {
for(auto &&call: calls) {
for(auto pos = calls.size(); pos > size_type{0}; --pos) {
auto &call = calls[pos-1];
call.second(call.first, args...);
}
}
@@ -242,7 +243,9 @@ public:
collector_type collect(Args... args) {
collector_type collector;
for(auto &&call: calls) {
for(auto pos = calls.size(); pos > size_type{0}; --pos) {
auto &call = calls[pos-1];
if(!this->invoke(collector, call.second, call.first, args...)) {
break;
}

View File

@@ -167,11 +167,17 @@ public:
* @param args Arguments to use to invoke listeners.
*/
void publish(Args... args) {
for(auto it = calls.rbegin(), end = calls.rend(); it != end; it++) {
if(!(it->second)(it->first, args...)) {
calls.erase(std::next(it).base());
std::vector<call_type> next;
for(auto pos = calls.size(); pos > size_type{0}; --pos) {
auto &call = calls[pos-1];
if((call.second)(call.first, args...)) {
next.push_back(call);
}
}
calls.swap(next);
}
/**

View File

@@ -19,12 +19,19 @@ endif()
# Test mod
if(BUILD_MOD)
set(DUKTAPE_DEPS_DIR ${entt_SOURCE_DIR}/deps/duktape)
configure_file(${entt_SOURCE_DIR}/cmake/in/duktape.in ${DUKTAPE_DEPS_DIR}/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${DUKTAPE_DEPS_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${DUKTAPE_DEPS_DIR})
set(DUKTAPE_SRC_DIR ${DUKTAPE_DEPS_DIR}/src/src)
add_executable(
mod
$<TARGET_OBJECTS:odr>
mod/duktape.c
${DUKTAPE_SRC_DIR}/duktape.c
mod/mod.cpp
)
target_include_directories(mod PRIVATE ${DUKTAPE_SRC_DIR})
target_link_libraries(mod PRIVATE gtest_main Threads::Threads m)
add_test(NAME mod COMMAND mod)
endif()

View File

@@ -1,3 +1,4 @@
#include <unordered_set>
#include <functional>
#include <gtest/gtest.h>
#include <entt/entity/registry.hpp>
@@ -57,6 +58,10 @@ TEST(DefaultRegistry, Functionalities) {
ASSERT_TRUE(registry.has<char>(e3));
ASSERT_EQ(registry.get<int>(e1), 42);
ASSERT_EQ(registry.get<char>(e1), 'c');
ASSERT_EQ(std::get<0>(registry.get<int, char>(e1)), 42);
ASSERT_EQ(std::get<1>(static_cast<const entt::DefaultRegistry &>(registry).get<int, char>(e1)), 'c');
ASSERT_EQ(registry.get<int>(e1), registry.get<int>(e3));
ASSERT_EQ(registry.get<char>(e1), registry.get<char>(e3));
ASSERT_NE(&registry.get<int>(e1), &registry.get<int>(e3));
@@ -346,3 +351,11 @@ TEST(DefaultRegistry, SortMulti) {
ASSERT_EQ(registry.get<int>(entity), ival++);
}
}
TEST(DefaultRegistry, ComponentsWithTypesFromStandardTemplateLibrary) {
// see #37 - the test shouldn't crash, that's all
entt::DefaultRegistry registry;
auto entity = registry.create();
registry.assign<std::unordered_set<int>>(entity).insert(42);
registry.destroy(entity);
}

View File

@@ -90,10 +90,13 @@ TEST(View, MultipleComponent) {
view.get<char>(e1) = '1';
view.get<char>(e2) = '2';
view.get<int>(e2) = 42;
for(auto entity: view) {
const auto &cview = static_cast<const decltype(view) &>(view);
ASSERT_TRUE(cview.get<char>(entity) == '2');
ASSERT_EQ(std::get<0>(cview.get<int, char>(entity)), 42);
ASSERT_EQ(std::get<1>(view.get<int, char>(entity)), '2');
ASSERT_EQ(cview.get<char>(entity), '2');
}
registry.remove<char>(e1);
@@ -161,10 +164,13 @@ TEST(PersistentView, Prepare) {
view.get<char>(e1) = '1';
view.get<char>(e2) = '2';
view.get<int>(e2) = 42;
for(auto entity: view) {
const auto &cview = static_cast<const decltype(view) &>(view);
ASSERT_TRUE(cview.get<char>(entity) == '2');
ASSERT_EQ(std::get<0>(cview.get<int, char>(entity)), 42);
ASSERT_EQ(std::get<1>(view.get<int, char>(entity)), '2');
ASSERT_EQ(cview.get<char>(entity), '2');
}
ASSERT_EQ(*(view.data() + 0), e2);
@@ -199,10 +205,13 @@ TEST(PersistentView, NoPrepare) {
view.get<char>(e1) = '1';
view.get<char>(e2) = '2';
view.get<int>(e2) = 42;
for(auto entity: view) {
const auto &cview = static_cast<const decltype(view) &>(view);
ASSERT_TRUE(cview.get<char>(entity) == '2');
ASSERT_EQ(std::get<0>(cview.get<int, char>(entity)), 42);
ASSERT_EQ(std::get<1>(view.get<int, char>(entity)), '2');
ASSERT_EQ(cview.get<char>(entity), '2');
}
ASSERT_EQ(*(view.data() + 0), e2);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff