Compare commits

..

24 Commits

Author SHA1 Message Date
Michele Caini
043f9a5025 updated single include file 2020-03-07 00:41:15 +01:00
Michele Caini
822264a65e workflow: --dry-run for the deploy.yml debut (see #397) 2020-03-07 00:30:24 +01:00
Michele Caini
8e9a6a4f06 registry: fixed a bug that affects late group initialization (close #440) 2020-03-07 00:30:21 +01:00
Michele Caini
76f3909ec9 workflow: update homebrew-entt (see #397) 2020-03-07 00:30:19 +01:00
Michele Caini
23e839b40e build system: updated install process (close #421) 2020-03-07 00:30:16 +01:00
Michele Caini
6a560fc7bf observer: use any<T...> rather than a fold expression with has<T> 2020-03-07 00:30:08 +01:00
Michele Caini
709d1c93a4 registry: fixed a bug that affects late group initialization (close #436) 2020-03-07 00:29:57 +01:00
Michele Caini
8d4b5f4bb7 sparse_set: remove copy ctor/assignment operator (use range-construct instead) 2020-03-07 00:11:30 +01:00
Paul Gruenbacher
9eb5a85e9e doc: update clone example to handle empty types (#441) 2020-03-07 00:09:19 +01:00
Paul Gruenbacher
e7521445e9 doc: update stamp example (#442) 2020-03-07 00:09:15 +01:00
Michele Caini
bb050e2660 actor: (has<T>(e) && ...) -> has<T...>(e) 2020-03-07 00:07:56 +01:00
Michele Caini
bc3b0eb491 links: added references to Chrysalis (project and blog post) 2020-03-07 00:06:39 +01:00
Michele Caini
7cea05d376 doc: updated documentation for snapshot archives (close #431) 2020-03-07 00:06:32 +01:00
Michele Caini
b8a3bdf6b5 build system: minor changes 2020-03-07 00:06:25 +01:00
Michele Caini
638b6dba17 build system: updated version, now working on v3.3.2 2020-03-06 23:56:55 +01:00
Michele Caini
50ba8c6c39 updated single include file 2020-02-28 23:27:20 +01:00
Michele Caini
94d15ebbef config: being empty isn't enough for ETO, type must be default constructible 2020-02-28 23:18:12 +01:00
Michele Caini
e150882231 doc: udpated doc (see #431) 2020-02-28 23:18:09 +01:00
Michele Caini
80a659c90c doc: typo 2020-02-28 23:18:03 +01:00
Michele Caini
17d96427ea registry: assign_or_replace works also with aggregates now (close #429) 2020-02-28 23:17:58 +01:00
Michele Caini
7fdda788af registry: minor changes (close #424) 2020-02-28 23:17:53 +01:00
Ezekiel Warren
182adbd9d9 Re-added bazel support (#430) 2020-02-28 23:17:45 +01:00
Michele Caini
4931c9cd9b build system: updated version, now working on v3.3.1 2020-02-28 23:17:24 +01:00
Michele Caini
a112409735 updated single include file (close #425) 2020-02-23 16:54:02 +01:00
28 changed files with 4462 additions and 4496 deletions

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
env:
@@ -45,7 +45,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
run: |
@@ -62,7 +62,7 @@ jobs:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
run: |

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
env:

40
.github/workflows/deploy.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: deploy
on:
release:
types: published
jobs:
homebrew-entt:
timeout-minutes: 5
runs-on: ubuntu-latest
env:
GH_REPO: homebrew-entt
FORMULA: entt.rb
steps:
- uses: actions/checkout@v2
- name: Clone repository
working-directory: build
env:
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
run: |
git clone https://$GITHUB_ACTOR:$PERSONAL_ACCESS_TOKEN@github.com/$GITHUB_ACTOR/$GH_REPO.git
- name: Prepare formula
working-directory: build
run: |
cd $GH_REPO
curl "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" --location --fail --silent --show-error --output archive.tar.gz
sed -i -e '/url/s/".*"/"'$(echo "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" | sed -e 's/[\/&]/\\&/g')'"/' $FORMULA
sed -i -e '/sha256/s/".*"/"'$(openssl sha256 archive.tar.gz | cut -d " " -f 2)'"/' $FORMULA
- name: Update remote
working-directory: build
run: |
cd $GH_REPO
git config --local user.email "action@github.com"
git config --local user.name "$GITHUB_ACTOR"
git add $FORMULA
git commit -m "Update to ${{ github.ref }}"
git push --dry-run origin master

15
BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
_msvc_copts = ["/std:c++17"]
_gcc_copts = ["-std=c++17"]
cc_library(
name = "entt",
visibility = ["//visibility:public"],
strip_include_prefix = "src",
hdrs = glob(["src/**/*.h", "src/**/*.hpp"]),
copts = select({
"@bazel_tools//src/conditions:windows": _msvc_copts,
"@bazel_tools//src/conditions:windows_msvc": _msvc_copts,
"@bazel_tools//src/conditions:windows_msys": _msvc_copts,
"//conditions:default": _gcc_copts,
}),
)

View File

@@ -81,17 +81,10 @@ add_library(EnTT::EnTT ALIAS EnTT)
target_include_directories(
EnTT
INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_compile_definitions(
EnTT
INTERFACE
$<$<AND:$<CONFIG:Debug>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:DEBUG>
$<$<AND:$<CONFIG:Release>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:RELEASE>
)
if(USE_ASAN)
target_compile_options(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
@@ -107,16 +100,28 @@ target_compile_features(EnTT INTERFACE cxx_std_17)
# Install EnTT
#
include(CMakePackageConfigHelpers)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(CUSTOM_INSTALL_CONFIGDIR cmake)
else()
set(CUSTOM_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/entt)
endif()
install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS EnTT EXPORT EnTTTargets)
export(EXPORT EnTTTargets FILE ${EnTT_BINARY_DIR}/EnTTTargets.cmake)
configure_package_config_file(
${EnTT_SOURCE_DIR}/cmake/in/EnTTConfig.cmake.in
EnTTConfig.cmake
INSTALL_DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
PATH_VARS CMAKE_INSTALL_INCLUDEDIR
)
write_basic_package_version_file(
EnTTConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
install(
EXPORT EnTTTargets
@@ -125,39 +130,14 @@ install(
NAMESPACE EnTT::
)
#
# Build tree package config file
#
configure_file(cmake/in/EnTTBuildConfig.cmake.in EnTTConfig.cmake @ONLY)
include(CMakePackageConfigHelpers)
#
# Install tree package config file
#
configure_package_config_file(
cmake/in/EnTTConfig.cmake.in
${CUSTOM_INSTALL_CONFIGDIR}/EnTTConfig.cmake
INSTALL_DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
PATH_VARS CMAKE_INSTALL_INCLUDEDIR
)
write_basic_package_version_file(
${EnTT_BINARY_DIR}/EnTTConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
install(
FILES
${EnTT_BINARY_DIR}/${CUSTOM_INSTALL_CONFIGDIR}/EnTTConfig.cmake
${EnTT_BINARY_DIR}/EnTTConfigVersion.cmake
${PROJECT_BINARY_DIR}/EnTTConfig.cmake
${PROJECT_BINARY_DIR}/EnTTConfigVersion.cmake
DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
)
export(PACKAGE EnTT)
install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
#
# Tests
@@ -193,16 +173,16 @@ endif()
# AOB
#
set(
AOB_SOURCES
.github/workflows/build.yml
.github/workflows/coverage.yml
.github/FUNDING.yml
AUTHORS
CONTRIBUTING.md
LICENSE
README.md
TODO
add_custom_target(
aob
SOURCES
.github/workflows/build.yml
.github/workflows/coverage.yml
.github/workflows/deploy.yml
.github/FUNDING.yml
AUTHORS
CONTRIBUTING.md
LICENSE
README.md
TODO
)
add_custom_target(aob SOURCES ${AOB_SOURCES})

View File

@@ -222,6 +222,11 @@ documentation:
* `CMake` version 3.7 or later.
* `Doxygen` version 1.8 or later.
Alternatively, [Bazel](https://bazel.build) is also supported as a build system
(credits to [zaucy](https://github.com/zaucy) who offered to maintain it).<br/>
In the documentation below I'll still refer to `CMake`, this being the official
build system of the library.
If you are looking for a C++14 version of `EnTT`, check out the git tag `cpp14`.
## Library

9
TODO
View File

@@ -9,7 +9,6 @@
* add examples (and credits) from @alanjfs :)
* static reflection, hint: template<> meta_type_t<Type>: meta_descriptor<name, func..., props..., etc...> (see #342)
* observer: user defined filters (eg .replace<T, &function> or .group<T, U, &func>)
* use underlying_type as entity type within pools and registry? it would make different registries work together flawlessy
* can we write a bool conv func for entt::entity that silently compares it to null?
* reset... reset everywhere...
* is it possible to make 0 the entity null?
@@ -17,7 +16,13 @@
* any-of rule for views/groups (eg entity has A and any of B/C/D)
- get -> all, exclude -> none
* review prepare after clone and the others have been removed
* remove copy-ctor/op from sparse set and storage (it doesn't make much sense)
* unlock deploy.yml
Next:
* review pool<T>::remove, ::assign
* replace observer class with observer functions
* workflow to update the single include file automatically
* workflow to update the doc automatically
* WIP:
- deprecate snapshot, loader, ...

1
WORKSPACE Normal file
View File

@@ -0,0 +1 @@
workspace(name = "com_github_skypjack_entt")

View File

@@ -1,6 +0,0 @@
set(ENTT_VERSION "@PROJECT_VERSION@")
set(ENTT_INCLUDE_DIRS "@CMAKE_CURRENT_SOURCE_DIR@/src")
if(NOT CMAKE_VERSION VERSION_LESS "3.0")
include("${CMAKE_CURRENT_LIST_DIR}/EnTTTargets.cmake")
endif()

View File

@@ -9,28 +9,24 @@ set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
configure_file(doxy.in doxy.cfg @ONLY)
set(
DOC_SOURCES
dox/extra.dox
md/core.md
md/entity.md
md/faq.md
md/lib.md
md/links.md
md/locator.md
md/meta.md
md/process.md
md/resource.md
md/signal.md
doxy.in
)
add_custom_target(
docs ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg
WORKING_DIRECTORY ${EnTT_SOURCE_DIR}
VERBATIM
SOURCES ${DOC_SOURCES}
SOURCES
dox/extra.dox
md/core.md
md/entity.md
md/faq.md
md/lib.md
md/links.md
md/locator.md
md/meta.md
md/process.md
md/resource.md
md/signal.md
doxy.in
)
install(

View File

@@ -701,7 +701,11 @@ A general purpose cloning function could be defined as:
```cpp
template<typename Type>
void clone(const entt::registry &from, entt::registry &to) {
to.assign<Type>(from.data<Type>(), from.data<Type>() + from.size<Type>(), from.raw<Type>());
if constexpr(ENTT_ENABLE_ETO(Type)) {
to.assign<Type>(from.data<Type>(), from.data<Type>() + from.size<Type>());
} else {
to.assign<Type>(from.data<Type>(), from.data<Type>() + from.size<Type>(), from.raw<Type>());
}
}
```
@@ -765,7 +769,7 @@ the type identifiers and their opaque functions for stamping. As an example:
```
template<typename Type>
void stamp(const entt::registry &from, const entt::entity src, entt::registry &to, const entt::entity dst) {
to.assign_or_replace<Type>(dst, from.get_or_assign<Type>(src));
to.assign_or_replace<Type>(dst, from.get<Type>(src));
}
```
@@ -989,9 +993,15 @@ In particular:
void operator()(entt::entity);
```
Where `entt::entity` is the type of the entities used by the registry. Note
that all the member functions of the snapshot class make also an initial call
to this endpoint to save the _size_ of the set they are going to store.<br/>
Where `entt::entity` is the type of the entities used by the registry.<br/>
Note that all member functions of the snapshot class make also an initial call
to store aside the _size_ of the set they are going to store. In this case,
the expected function type for the function call operator is:
```cpp
void operator()(std::underlying_type_t<entt::entity>);
```
In addition, an archive must accept a pair of entity and component for each
type to be serialized. Therefore, given a type `T`, the archive must contain a
function call operator with the following signature:
@@ -1012,12 +1022,18 @@ In particular:
Where `entt::entity` is the type of the entities used by the registry. Each
time the function is invoked, the archive must read the next element from the
underlying storage and copy it in the given variable. Note that all the member
functions of a loader class make also an initial call to this endpoint to read
the _size_ of the set they are going to load.<br/>
In addition, the archive must accept a pair of entity and component for each
type to be restored. Therefore, given a type `T`, the archive must contain a
function call operator with the following signature:
underlying storage and copy it in the given variable.<br/>
Note that all member functions of a loader class make also an initial call to
read the _size_ of the set they are going to load. In this case, the expected
function type for the function call operator is:
```cpp
void operator()(std::underlying_type_t<entt::entity> &);
```
In addition, the archive must accept a pair of references to an entity and its
component for each type to be restored. Therefore, given a type `T`, the
archive must contain a function call operator with the following signature:
```cpp
void operator()(entt::entity &, T &);

View File

@@ -76,6 +76,8 @@ I hope this list can grow much more in the future:
developed for educational purposes.
* [Lumos](https://github.com/jmorton06/Lumos): game engine written in C++
using OpenGL and Vulkan.
* [Chrysalis](https://github.com/ivanhawkes/Chrysalis): action RPG SDK for
CRYENGINE games.
* Articles and blog posts:
* [Some posts](https://skypjack.github.io/tags/#entt) on my personal
@@ -91,6 +93,9 @@ I hope this list can grow much more in the future:
giant space battle.
* [Conan Adventures (SFML and EnTT in C++)](https://leinnan.github.io/blog/conan-adventuressfml-and-entt-in-c.html):
create projects in modern C++ using `SFML`, `EnTT`, `Conan` and `CMake`.
* [Adding EnTT ECS to Chrysalis](https://www.tauradius.com/post/adding-an-ecs-to-chrysalis/):
a blog entry about the process followed and the results of the integration
of `EnTT` into `Chrysalis`.
* Any Other Business:
* The [ArcGIS Runtime SDKs](https://developers.arcgis.com/arcgis-runtime/)

File diff suppressed because it is too large Load Diff

View File

@@ -44,10 +44,10 @@
#ifndef ENTT_DISABLE_ETO
# include <type_traits>
# define ENTT_ENABLE_ETO(Type) std::is_empty_v<Type>
# define ENTT_ENABLE_ETO(Type) (std::is_default_constructible_v<Type> && std::is_empty_v<Type>)
#else
# // sfinae-friendly definition
# define ENTT_ENABLE_ETO(Type) (false && std::is_empty_v<Type>)
# define ENTT_ENABLE_ETO(Type) (false && std::is_void_v<Type>)
#endif

View File

@@ -4,7 +4,7 @@
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 3
#define ENTT_VERSION_PATCH 0
#define ENTT_VERSION_PATCH 2
#endif

View File

@@ -130,7 +130,7 @@ struct basic_actor {
*/
template<typename... Component>
bool has() const {
return (reg->template has<Component>(entt) && ...);
return reg->template has<Component...>(entt);
}
/**

View File

@@ -54,7 +54,7 @@ class basic_group;
* all of them because they _share_ entities and components).
*
* @warning
* Lifetime of a group must overcome the one of the registry that generated it.
* Lifetime of a group must not overcome that of the registry that generated it.
* In any other case, attempting to use a group results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
@@ -484,7 +484,7 @@ private:
* of them because they share the underlying data structure).
*
* @warning
* Lifetime of a group must overcome the one of the registry that generated it.
* Lifetime of a group must not overcome that of the registry that generated it.
* In any other case, attempting to use a group results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).

View File

@@ -159,7 +159,7 @@ constexpr basic_collector<> collector{};
* behavior.
*
* @warning
* Lifetime of an observer doesn't necessarily have to overcome the one of the
* Lifetime of an observer doesn't necessarily have to overcome that of the
* registry to which it is connected. However, the observer must be disconnected
* from the registry before being destroyed to avoid crashes due to dangling
* pointers.
@@ -177,7 +177,7 @@ class basic_observer {
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
template<std::size_t Index>
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> &reg, const Entity entt) {
if(reg.template has<Require...>(entt) && !(reg.template has<Reject>(entt) || ...)) {
if(reg.template has<Require...>(entt) && !reg.template any<Reject...>(entt)) {
if(auto *comp = obs.view.try_get(entt); !comp) {
obs.view.construct(entt);
}
@@ -213,7 +213,7 @@ class basic_observer {
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> {
template<std::size_t Index>
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> &reg, const Entity entt) {
if(reg.template has<AllOf..., Require...>(entt) && !(reg.template has<NoneOf>(entt) || ...) && !(reg.template has<Reject>(entt) || ...)) {
if(reg.template has<AllOf..., Require...>(entt) && !reg.template any<NoneOf..., Reject...>(entt)) {
if(auto *comp = obs.view.try_get(entt); !comp) {
obs.view.construct(entt);
}

View File

@@ -47,8 +47,6 @@ class basic_registry {
static_assert(std::is_same_v<Component, std::decay_t<Component>>);
std::size_t super{};
using storage<Entity, Component>::storage;
auto on_construct() ENTT_NOEXCEPT {
return sink{construction};
}
@@ -110,11 +108,11 @@ class basic_registry {
};
struct pool_data {
ENTT_ID_TYPE type_id;
std::unique_ptr<sparse_set<Entity>> pool;
void(* assure)(basic_registry &, const sparse_set<Entity> &);
void(* remove)(sparse_set<Entity> &, basic_registry &, const Entity);
void(* stamp)(basic_registry &, const Entity, const sparse_set<Entity> &, const Entity);
ENTT_ID_TYPE type_id{};
std::unique_ptr<sparse_set<Entity>> pool{};
void(* assure)(basic_registry &, const sparse_set<Entity> &){};
void(* remove)(sparse_set<Entity> &, basic_registry &, const Entity){};
void(* stamp)(basic_registry &, const Entity, const sparse_set<Entity> &, const Entity){};
};
template<typename...>
@@ -717,7 +715,7 @@ public:
auto &cpool = assure<Component>();
return cpool.has(entity)
? (cpool.replace(*this, entity, [args = std::forward_as_tuple(std::forward<Args>(args)...)](auto &&component) { component = std::make_from_tuple<Component>(std::move(args)); }), cpool.get(entity))
? (cpool.replace(*this, entity, [&args...](auto &&component) { component = Component{std::forward<Args>(args)...}; }), cpool.get(entity))
: cpool.assign(*this, entity, std::forward<Args>(args)...);
}
@@ -1406,13 +1404,9 @@ public:
handler->current.construct(entity);
}
} else {
const auto curr = view<Owned..., Get...>(exclude<Exclude...>);
// we cannot iterate backwards because we want to leave behind valid entities in case of owned types
std::for_each(std::make_reverse_iterator(curr.end()), std::make_reverse_iterator(curr.begin()), [cpools, handler](const auto entity) {
if(const auto pos = handler->current; !(std::get<0>(cpools).index(entity) < ++handler->current)) {
(std::get<pool_handler<std::decay_t<Owned>> &>(cpools).swap(std::get<pool_handler<std::decay_t<Owned>> &>(cpools).data()[pos], entity), ...);
}
std::for_each(std::get<0>(cpools).data(), std::get<0>(cpools).data() + std::get<0>(cpools).size(), [this, handler](const auto entity) {
handler->template maybe_valid_if<std::tuple_element_t<0, std::tuple<std::decay_t<Owned>...>>>(*this, entity);
});
}
}

View File

@@ -49,7 +49,7 @@ namespace entt {
* have a valid reference and won't be updated accordingly).
*
* @warning
* Lifetime of a view must overcome the one of the registry that generated it.
* Lifetime of a view must not overcome that of the registry that generated it.
* In any other case, attempting to use a view results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).

View File

@@ -186,41 +186,12 @@ public:
/*! @brief Default constructor. */
sparse_set() = default;
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
sparse_set(const sparse_set &other)
: reverse{},
direct{other.direct}
{
for(size_type pos{}, last = other.reverse.size(); pos < last; ++pos) {
if(other.reverse[pos]) {
std::copy_n(other.reverse[pos].get(), entt_per_page, assure(pos));
}
}
}
/*! @brief Default move constructor. */
sparse_set(sparse_set &&) = default;
/*! @brief Default destructor. */
virtual ~sparse_set() = default;
/**
* @brief Copy assignment operator.
* @param other The instance to copy from.
* @return This sparse set.
*/
sparse_set & operator=(const sparse_set &other) {
if(&other != this) {
auto tmp{other};
*this = std::move(tmp);
}
return *this;
}
/*! @brief Default move assignment operator. @return This sparse set. */
sparse_set & operator=(sparse_set &&) = default;

View File

@@ -330,7 +330,7 @@ public:
/**
* @brief Assigns one or more entities to a storage and constructs their
* objects with from a given instance.
* objects from a given instance.
*
* @warning
* Attempting to assign an entity that already belongs to the storage

View File

@@ -55,7 +55,7 @@ class basic_view;
* made by means of the registry are immediately reflected by views.
*
* @warning
* Lifetime of a view must overcome the one of the registry that generated it.
* Lifetime of a view must not overcome that of the registry that generated it.
* In any other case, attempting to use a view results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
@@ -559,7 +559,7 @@ private:
* made by means of the registry are immediately reflected by views.
*
* @warning
* Lifetime of a view must overcome the one of the registry that generated it.
* Lifetime of a view must not overcome that of the registry that generated it.
* In any other case, attempting to use a view results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).

View File

@@ -24,9 +24,8 @@ namespace entt {
* type `Event`, listeners are such that they can be invoked with an argument of
* type `const Event &`, no matter what the return type is.
*
* The types of the instances are `Class &`. Users must guarantee that the
* lifetimes of the objects overcome the one of the dispatcher itself to avoid
* crashes.
* The dispatcher creates instances of the `sigh` class internally. Refer to the
* documentation of the latter for more details.
*/
class dispatcher {
struct basic_pool {

View File

@@ -407,13 +407,13 @@ public:
*
* The signal isn't responsible for the connected object or the payload.
* Users must always guarantee that the lifetime of the instance overcomes
* the one of the delegate. On the other side, the signal handler performs
* the one of the signal. On the other side, the signal handler performs
* checks to avoid multiple connections for the same function.<br/>
* When used to connect a free function with payload, its signature must be
* such that the instance is the first argument before the ones used to
* define the delegate itself.
* define the signal itself.
*
* @tparam Candidate Function or member to connect to the delegate.
* @tparam Candidate Function or member to connect to the signal.
* @tparam Type Type of class or type of payload.
* @param value_or_instance A valid object that fits the purpose.
* @return A properly initialized connection object.
@@ -433,7 +433,7 @@ public:
/**
* @brief Disconnects a free function or an unbound member from a signal.
* @tparam Candidate Function or member to disconnect from the delegate.
* @tparam Candidate Function or member to disconnect from the signal.
*/
template<auto Candidate>
void disconnect() {
@@ -446,7 +446,7 @@ public:
/**
* @brief Disconnects a free function with payload or a bound member from a
* signal.
* @tparam Candidate Function or member to disconnect from the delegate.
* @tparam Candidate Function or member to disconnect from the signal.
* @tparam Type Type of class or type of payload.
* @param value_or_instance A valid object that fits the purpose.
*/

View File

@@ -1120,3 +1120,33 @@ TEST(OwningGroup, SignalRace) {
ASSERT_EQ(registry.group<int>(entt::get<double>).size(), 1u);
}
TEST(OwningGroup, StableLateInitialization) {
entt::registry registry;
for(std::size_t i{}; i < 30u; ++i) {
auto entity = registry.create();
if(!(i % 2u)) registry.assign<int>(entity);
if(!(i % 3u)) registry.assign<char>(entity);
}
// thanks to @pgruenbacher for pointing out this corner case
ASSERT_EQ((registry.group<int, char>().size()), 5u);
}
TEST(OwningGroup, PreventEarlyOptOut) {
entt::registry registry;
registry.assign<int>(registry.create(), 3);
const auto entity = registry.create();
registry.assign<char>(entity, 'c');
registry.assign<int>(entity, 2);
// thanks to @pgruenbacher for pointing out this corner case
registry.group<char, int>().each([entity](const auto entt, const auto &c, const auto &i) {
ASSERT_EQ(entity, entt);
ASSERT_EQ(c, 'c');
ASSERT_EQ(i, 2);
});
}

View File

@@ -16,6 +16,10 @@ struct non_default_constructible {
int value;
};
struct aggregate {
int value{};
};
struct listener {
template<typename Component>
static void sort(entt::registry &registry) {
@@ -256,6 +260,14 @@ TEST(Registry, Functionalities) {
ASSERT_EQ(registry.capacity<char>(), entt::registry::size_type{});
}
TEST(Registry, AssignOrReplaceAggregates) {
entt::registry registry;
const auto entity = registry.create();
auto &instance = registry.assign_or_replace<aggregate>(entity, 42);
ASSERT_EQ(instance.value, 42);
}
TEST(Registry, Identifiers) {
entt::registry registry;
const auto pre = registry.create();

View File

@@ -53,14 +53,6 @@ TEST(SparseSet, Functionalities) {
ASSERT_TRUE(std::is_move_constructible_v<decltype(set)>);
ASSERT_TRUE(std::is_move_assignable_v<decltype(set)>);
entt::sparse_set<entt::entity> cpy{set};
set = cpy;
ASSERT_FALSE(set.empty());
ASSERT_FALSE(cpy.empty());
ASSERT_EQ(set.index(entt::entity{42}), 0u);
ASSERT_EQ(cpy.index(entt::entity{42}), 0u);
entt::sparse_set<entt::entity> other{std::move(set)};
set = std::move(other);