Compare commits

..

21 Commits

Author SHA1 Message Date
Michele Caini
bd83fba6cd updated version 2018-08-02 17:17:09 +02:00
Michele Caini
15b9255a25 fix #120 2018-08-02 16:55:03 +02:00
Michele Caini
6794d21487 one shot bubble sort alg 2018-07-31 09:11:18 +02:00
Michele Caini
118c4432ec typo 2018-07-24 09:25:01 +02:00
Michele Caini
ccda429bf1 Update README.md 2018-07-23 12:10:48 +02:00
Michele Caini
590937d2a0 added Registry::entity 2018-07-20 22:17:18 +02:00
Michele Caini
241827dd80 added gitter badge 2018-07-20 22:03:24 +02:00
Michele Caini
77b4e0b4bd EnTT in action: Face Smash 2018-07-18 15:01:36 +02:00
Michele Caini
6a53cb32d8 updated TODO 2018-07-18 14:08:30 +02:00
Michele Caini
f12ff3b15e fix #116 2018-07-18 14:07:48 +02:00
Michele Caini
69ad8676b7 added USE_ASAN option 2018-07-18 14:07:43 +02:00
Michele Caini
d0fd756f6b logo + review doc 2018-07-12 15:30:52 +02:00
Michele Caini
7f8ab67e9e performance improvements 2018-07-09 16:48:35 +02:00
Michele Caini
0e68bb3d2c added entt::label 2018-07-07 13:40:20 +02:00
Michele Caini
d5b3933752 updated README (added a note on EnTT and shared libraries - see #111) 2018-07-05 16:14:42 +02:00
Michele Caini
0b7206a92d review: README 2018-07-04 13:42:37 +02:00
Michele Caini
e875f306fd added FIND_GTEST_PACKAGE to force using system-wide gtest version (#106) 2018-07-03 22:09:28 +02:00
Michele Caini
8ed5e5ee28 updated cmake min version 2018-07-03 16:57:46 +02:00
Indi Kernick
948b0d40f6 Update packages with Travis-CI (#110) 2018-07-03 12:57:36 +02:00
David Kalnischkies
48f4feb7a7 Fix README: identifiers are accessed via type<>() 2018-07-02 13:29:03 +02:00
Michele Caini
ddc0a32bbc fix: runtime view (#108) 2018-07-02 08:40:30 +02:00
25 changed files with 561 additions and 627 deletions

View File

@@ -37,7 +37,7 @@ matrix:
compiler: clang
env: COMPILER=clang++
- os: osx
osx_image: xcode9.1
osx_image: xcode9.4
compiler: clang
env: COMPILER=clang++
- os: linux
@@ -71,3 +71,9 @@ script:
- mkdir -p build && cd build
- cmake .. && make -j4
- CTEST_OUTPUT_ON_FAILURE=1 make test
deploy:
provider: script
script: scripts/update_packages.sh $TRAVIS_TAG
on:
tags: true

View File

@@ -8,3 +8,4 @@ Paolo Monteverde aka morbo84
David Nerjes aka DavidHamburg
Indi Kernick aka Kerndog73
Malte Müller-Rowold aka m-waka
Richard Caseres aka richardbmx

View File

@@ -2,7 +2,7 @@
# EnTT
#
cmake_minimum_required(VERSION 3.2)
cmake_minimum_required(VERSION 3.7.2)
#
# Building in-tree is not allowed (we take care of your craziness).
@@ -16,7 +16,7 @@ endif()
# Project configuration
#
project(entt VERSION 2.6.1)
project(EnTT VERSION 2.7.2)
include(GNUInstallDirs)
@@ -31,11 +31,12 @@ set(PROJECT_AUTHOR_EMAIL "michele.caini@gmail.com")
message("*")
message("* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
message("* Copyright (c) 2018 ${PROJECT_AUTHOR} <${PROJECT_AUTHOR_EMAIL}>")
message("* Copyright (c) 2017-2018 ${PROJECT_AUTHOR} <${PROJECT_AUTHOR_EMAIL}>")
message("*")
option(ENTT_COMPILE_OPTIONS "Use compile options from EnTT." ON)
option(USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if availbale." ON)
option(USE_ASAN "Use address sanitizer by adding -fsanitize=address -fno-omit-frame-pointer flags" OFF)
option(USE_COMPILE_OPTIONS "Use compile options from EnTT." ON)
#
# Compiler stuff
@@ -79,18 +80,23 @@ target_compile_definitions(
INTERFACE $<$<AND:$<CONFIG:Release>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:RELEASE>
)
if(ENTT_COMPILE_OPTIONS)
if(USE_ASAN)
target_compile_options(EnTT INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:-fsanitize=address -fno-omit-frame-pointer>)
target_link_libraries(EnTT INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:-fsanitize=address -fno-omit-frame-pointer>)
endif()
if(USE_COMPILE_OPTIONS)
target_compile_options(
EnTT
INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:-O0 -g>
# it seems that -O3 ruins the performance when using clang ...
# it seems that -O3 ruins a bit the performance when using clang ...
INTERFACE $<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:Clang>>:-O2>
# ... on the other side, GCC is incredibly comfortable with it.
INTERFACE $<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:GNU>>:-O3>
)
endif()
if(USE_LIBCPP AND HAS_LIBCPP)
if(HAS_LIBCPP)
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
endif()
@@ -101,20 +107,20 @@ target_compile_features(EnTT INTERFACE cxx_std_14)
#
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(ENTT_INSTALL_CONFIGDIR cmake)
set(CUSTOM_INSTALL_CONFIGDIR cmake)
else()
set(ENTT_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/entt)
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)
export(EXPORT EnTTTargets FILE ${EnTT_BINARY_DIR}/EnTTTargets.cmake)
install(
EXPORT EnTTTargets
FILE EnTTTargets.cmake
DESTINATION ${ENTT_INSTALL_CONFIGDIR}
DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
)
#
@@ -131,23 +137,23 @@ include(CMakePackageConfigHelpers)
configure_package_config_file(
cmake/in/EnTTConfig.cmake.in
${ENTT_INSTALL_CONFIGDIR}/EnTTConfig.cmake
INSTALL_DESTINATION ${ENTT_INSTALL_CONFIGDIR}
${CUSTOM_INSTALL_CONFIGDIR}/EnTTConfig.cmake
INSTALL_DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
PATH_VARS CMAKE_INSTALL_INCLUDEDIR
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file(
${entt_BINARY_DIR}/EnTTConfigVersion.cmake
${EnTT_BINARY_DIR}/EnTTConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
install(
FILES
${entt_BINARY_DIR}/${ENTT_INSTALL_CONFIGDIR}/EnTTConfig.cmake
${entt_BINARY_DIR}/EnTTConfigVersion.cmake
DESTINATION ${ENTT_INSTALL_CONFIGDIR}
${EnTT_BINARY_DIR}/${CUSTOM_INSTALL_CONFIGDIR}/EnTTConfig.cmake
${EnTT_BINARY_DIR}/EnTTConfigVersion.cmake
DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
)
export(PACKAGE EnTT)
@@ -162,18 +168,25 @@ if(BUILD_TESTING)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
option(FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
if(FIND_GTEST_PACKAGE)
find_package(GTest REQUIRED)
else()
# gtest, gtest_main, gmock and gmock_main targets are available from now on
set(GOOGLETEST_DEPS_DIR ${EnTT_SOURCE_DIR}/deps/googletest)
configure_file(${EnTT_SOURCE_DIR}/cmake/in/googletest.in ${GOOGLETEST_DEPS_DIR}/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(${GOOGLETEST_DEPS_DIR}/src ${GOOGLETEST_DEPS_DIR}/build)
add_library(GTest::Main ALIAS gtest_main)
endif()
option(BUILD_BENCHMARK "Build benchmark." OFF)
option(BUILD_MOD "Build mod example." OFF)
option(BUILD_SNAPSHOT "Build snapshot example." OFF)
# gtest, gtest_main, gmock and gmock_main targets are available from now on
set(GOOGLETEST_DEPS_DIR ${entt_SOURCE_DIR}/deps/googletest)
configure_file(${entt_SOURCE_DIR}/cmake/in/googletest.in ${GOOGLETEST_DEPS_DIR}/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(${GOOGLETEST_DEPS_DIR}/src ${GOOGLETEST_DEPS_DIR}/build)
enable_testing()
add_subdirectory(test)
endif()
@@ -201,9 +214,10 @@ add_custom_target(
SOURCES
appveyor.yml
AUTHORS
CONTRIBUTING
LICENSE
README.md
TODO
.travis.yml
docs/CONTRIBUTING.md
docs/extra.dox
)

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2018 Michele Caini
Copyright (c) 2017-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

216
README.md
View File

@@ -1,8 +1,12 @@
# EnTT Framework
![EnTT: Gaming meets modern C++](https://user-images.githubusercontent.com/1812216/42513718-ee6e98d0-8457-11e8-9baf-8d83f61a3097.png)
<!--
@cond TURN_OFF_DOXYGEN
-->
[![Build Status](https://travis-ci.org/skypjack/entt.svg?branch=master)](https://travis-ci.org/skypjack/entt)
[![Build status](https://ci.appveyor.com/api/projects/status/rvhaabjmghg715ck?svg=true)](https://ci.appveyor.com/project/skypjack/entt)
[![Coverage Status](https://coveralls.io/repos/github/skypjack/entt/badge.svg?branch=master)](https://coveralls.io/github/skypjack/entt?branch=master)
[![Gitter chat](https://badges.gitter.im/skypjack/entt.png)](https://gitter.im/skypjack/entt)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=W2HF9FESD5LJY&lc=IT&item_name=Michele%20Caini&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted)
# Table of Contents
@@ -29,6 +33,7 @@
* [Prototype](#prototype)
* [Helpers](#helpers)
* [Dependency function](#dependency-function)
* [Labels](#labels)
* [Null entity](#null-entity)
* [View: to persist or not to persist?](#view-to-persist-or-not-to-persist)
* [Standard View](#standard-view)
@@ -62,13 +67,16 @@
* [Support](#support)
* [Donation](#donation)
* [Hire me](#hire-me)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
`EnTT` is a header-only, tiny and easy to use framework written in modern
C++.<br/>
It was originally designed entirely around an architectural pattern called _ECS_
that is used mostly in game development. For further details:
`EnTT` is a header-only, tiny and easy to use entity-component system (and much
more) written in modern C++.<br/>
The entity-component-system (also known as _ECS_) is an architectural pattern
used mostly in game development. For further details:
* [Entity Systems Wiki](http://entity-systems.wikidot.com/)
* [Evolve Your Hierarchy](http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/)
@@ -77,35 +85,12 @@ that is used mostly in game development. For further details:
A long time ago, the sole entity-component system was part of the project. After
a while the codebase has grown and more and more classes have become part of the
repository.<br/>
That's why today it's called _the EnTT Framework_.
Currently, `EnTT` is tested on Linux, Microsoft Windows and OS X. It has proven
to work also on both Android and iOS.<br/>
Most likely it will not be problematic on other systems as well, but has not
been sufficiently tested so far.
## The framework
`EnTT` was written initially as a faster alternative to other well known and
open source entity-component systems. Nowadays the `EnTT` framework is moving
its first steps. Much more will come in the future and hopefully I'm going to
work on it for a long time.<br/>
Requests for feature, PR, suggestions ad feedback are highly appreciated.
If you find you can help me and want to contribute to the `EnTT` framework with
your experience or you do want to get part of the project for some other
reasons, feel free to contact me directly (you can find the mail in the
[profile](https://github.com/skypjack)).<br/>
I can't promise that each and every contribution will be accepted, but I can
assure that I'll do my best to take them all seriously.
### State of the art
Here is a brief list of what it offers today:
Here is a brief, yet incomplete list of what it offers today:
* Statically generated integer identifiers for types (assigned either at
compile-time or at runtime).
* A constexpr utility for human readable resource identifiers.
* A minimal configuration system built on top of the monostate pattern.
* An incredibly fast entity-component system based on sparse sets, with its own
views and a _pay for what you use_ policy to adjust performance and memory
usage according to users' requirements.
@@ -120,12 +105,13 @@ Here is a brief list of what it offers today:
* ...
* Any other business.
Consider it a work in progress. For more details and an updated list, please
refer to the [online documentation](https://skypjack.github.io/entt/). It
probably contains much more. Moreover, the whole API is fully documented in-code
for those who are brave enough to read it.<br/>
Continue reading to know how the different parts of the project work or follow
the link above to take a look at the API reference.
Consider it a work in progress. The whole API is also fully documented in-code
for those who are brave enough to read it.
Currently, `EnTT` is tested on Linux, Microsoft Windows and OS X. It has proven
to work also on both Android and iOS.<br/>
Most likely it will not be problematic on other systems as well, but has not
been sufficiently tested so far.
## Code Example
@@ -197,7 +183,7 @@ satisfying at all. The fastest and nothing more, fairly little indeed. When I
realized it, I tried hard to keep intact the great performance of `EnTT` and to
add all the features I wanted to see in *my own library* at the same time.
Today `EnTT` is finally what I was looking for: still faster than its
Nowadays, `EnTT` is finally what I was looking for: still faster than its
_competitors_, lower memory usage in the average case, a really good API and an
amazing set of features. And even more, of course.
@@ -265,8 +251,8 @@ documentation:
## Library
`EnTT` is a header-only library. This means that including the `entt.hpp`
header is enough to include the whole framework and use it. For those who are
`EnTT` is a header-only library. This means that including the `entt.hpp` header
is enough to include the library as a whole and use it. For those who are
interested only in the entity-component system, consider to include the sole
`entity/registry.hpp` header instead.<br/>
It's a matter of adding the following line to the top of a file:
@@ -284,6 +270,46 @@ Use the line below to include only the entity-component system instead:
Then pass the proper `-I` argument to the compiler to add the `src` directory to
the include paths.
### Side note: shared libraries
To make sure that an application and a shared library that use both `EnTT` can
interact correctly when symbols are hidden by default, there are some tricks to
follow.<br/>
In particular and in order to avoid undefined behaviors, all the instantiation
of the `Family` class template shall be made explicit along with the system-wide
specifier to use to export them.
At the time I'm writing this document, the classes that use internally the above
mentioned class template are `Dispatcher`, `Emitter` and `Registry`. Therefore
and as an example, if you use the `Registry` class template in your shared
library and want to set symbols visibility to _hidden_ by default, the following
lines are required to allow it to function properly with a client that also uses
the `Registry` somehow:
* On GNU/Linux:
```cpp
namespace entt {
template class __attribute__((visibility("default"))) Family<struct InternalRegistryTagFamily>;
template class __attribute__((visibility("default"))) Family<struct InternalRegistryComponentFamily>;
template class __attribute__((visibility("default"))) Family<struct InternalRegistryHandlerFamily>;
}
```
* On Windows:
```cpp
namespace entt {
template class __declspec(dllexport) Family<struct InternalRegistryTagFamily>;
template class __declspec(dllexport) Family<struct InternalRegistryComponentFamily>;
template class __declspec(dllexport) Family<struct InternalRegistryHandlerFamily>;
}
```
Otherwise, the risk is that type identifiers are different between the shared
library and the application and this will prevent the whole thing from
functioning correctly for obvious reasons.
## Documentation
The documentation is based on [doxygen](http://www.stack.nl/~dimitri/doxygen/).
@@ -299,8 +325,14 @@ The API reference will be created in HTML format within the directory
$ cd build
$ your_favorite_browser docs/html/index.html
<!--
@cond TURN_OFF_DOXYGEN
-->
The API reference is also available [online](https://skypjack.github.io/entt/)
for the latest version.
<!--
@endcond TURN_OFF_DOXYGEN
-->
## Tests
@@ -380,8 +412,8 @@ them the way they prefer. No need to register systems or their types neither
with the registry nor with the entity-component system at all.
The following sections will explain in short how to use the entity-component
system, the core part of the whole framework.<br/>
In fact, the framework is composed of many other classes in addition to those
system, the core part of the whole library.<br/>
In fact, the project is composed of many other classes in addition to those
describe below. For more details, please refer to the inline documentation.
## The Registry, the Entity and the Component
@@ -730,10 +762,10 @@ In `EnTT`, identifiers are easily accessible:
entt::DefaultRegistry registry;
// standard component identifier
auto ctype = registry.component<Position>();
auto ctype = registry.type<Position>();
// single instance component identifier
auto ttype = registry.tag<PlayingCharacter>();
auto ttype = registry.type<PlayingCharacter>(entt::tag_t{});
```
Once the identifiers are made available, almost everything becomes pretty
@@ -1134,11 +1166,25 @@ A dependency can easily be broken by means of the same function template:
entt::dependency<AType, AnotherType>(entt::break_t{}, registry.construction<MyType>());
```
#### Labels
There's nothing magical about the way labels can be assigned to entities while
avoiding a performance hit at runtime. Nonetheless, the syntax can be annoying
and that's why a more user-friendly shortcut is provided to do it.<br/>
This shortcut is the alias template `entt::label`.
If used in combination with hashed strings, it helps to use labels where types
would be required otherwise. As an example:
```cpp
registry.assign<entt::label<"enemy"_hs>>(entity);
```
### Null entity
In `EnTT`, there exists a sort of _null entity_ made available to users that is
accessible via the `entt::null` variable.<br/>
The framework guarantees that the following expression always returns false:
The library guarantees that the following expression always returns false:
```cpp
registry.valid(entt::null);
@@ -1658,11 +1704,10 @@ expedients.
# Crash Course: core functionalities
The `EnTT` framework comes with a bunch of core functionalities mostly used by
the other parts of the library itself.<br/>
Hardly users of the framework will include these features in their code, but
it's worth describing what `EnTT` offers so as not to reinvent the wheel in case
of need.
`EnTT` comes with a bunch of core functionalities mostly used by the other parts
of the library itself.<br/>
Hardly users will include these features in their code, but it's worth
describing what `EnTT` offers so as not to reinvent the wheel in case of need.
## Compile-time identifiers
@@ -1721,7 +1766,7 @@ Sometimes it's useful to be able to give unique identifiers to types at
runtime.<br/>
There are plenty of different solutions out there and I could have used one of
them. In fact, I adapted the most common one to my requirements and used it
extensively within the entire framework.
extensively within the entire library.
It's the `Family` class. Here is an example of use directly from the
entity-component system:
@@ -1765,6 +1810,13 @@ auto load(entt::HashedString::hash_type resource) {
auto resource = load(entt::HashedString{"gui/background"});
```
There is also a _user defined literal_ dedicated to hashed strings to make them
more user-friendly:
```cpp
constexpr auto str = "text"_hs;
```
### Conflicts
The hashed string class uses internally FNV-1a to compute the numeric
@@ -1868,8 +1920,8 @@ Sometimes processes are a useful tool to work around the strict definition of a
system and introduce logic in a different way, usually without resorting to the
introduction of other components.
The `EnTT` framework offers a minimal support to this paradigm by introducing a
few classes that users can use to define and execute cooperative processes.
`EnTT` offers a minimal support to this paradigm by introducing a few classes
that users can use to define and execute cooperative processes.
## The process
@@ -2068,9 +2120,9 @@ requirements of the piece of software in which they are used.<br/>
Examples are loading everything on start, loading on request, predictive
loading, and so on.
The `EnTT` framework doesn't pretend to offer a _one-fits-all_ solution for the
different cases. Instead, it offers a minimal and perhaps trivial cache that can
be useful most of the time during prototyping and sometimes even in a production
`EnTT` doesn't pretend to offer a _one-fits-all_ solution for the different
cases. Instead, it offers a minimal and perhaps trivial cache that can be useful
most of the time during prototyping and sometimes even in a production
environment.<br/>
For those interested in the subject, the plan is to improve it considerably over
time in terms of performance, memory usage and functionalities. Hoping to make
@@ -2302,8 +2354,8 @@ it solves a problem but may not adapt well to other requirements that may arise
from time to time.
In case that the flexibility and potential of an `std::function` are not
required or where you are looking for something different, the `EnTT` framework
offers a full set of classes to solve completely different problems.
required or where you are looking for something different, `EnTT` offers a full
set of classes to solve completely different problems.
## Signals
@@ -2472,7 +2524,7 @@ auto ret = delegate(42);
Probably too much small and pretty poor of functionalities, but the delegate
class can help in a lot of cases and it has shown that it is worth keeping it
within the framework.
within the library.
## Event dispatcher
@@ -2709,8 +2761,10 @@ projects based on EnTT and did not hold back when it came to documenting them.
Below an incomplete list of projects and articles:
* [EnttPong](https://github.com/reworks/EnttPong): example game for `EnTT`
framework.
* [Minecraft](https://minecraft.net/en-us/attribution/): of course, **that** Minecraft, by Mojang (see the open source attributions page).
* [Face Smash](https://play.google.com/store/apps/details?id=com.gamee.facesmash):
the emojis dominate the world, destroy them all with your facial expressions.
* [EnttPong](https://github.com/reworks/EnttPong): example game with `EnTT`.
* [Space Battle: Huge edition](http://victor.madtriangles.com/code%20experiment/2018/06/11/post-ecs-battle-huge.html):
huge space battle built entirely from scratch.
* [Space Battle](https://github.com/vblanco20-1/ECS_SpaceBattle): huge space
@@ -2728,30 +2782,55 @@ Below an incomplete list of projects and articles:
If you know of other resources out there that are about `EnTT`, feel free to
open an issue or a PR and I'll be glad to add them to the list.
<!--
@cond TURN_OFF_DOXYGEN
-->
# Contributors
If you want to participate, please see the guidelines for
[contributing](https://github.com/skypjack/entt/blob/master/CONTRIBUTING)
before to create issues or pull requests.<br/>
`EnTT` was written initially as a faster alternative to other well known and
open source entity-component systems. Nowadays this library is moving its first
steps. Much more will come in the future and hopefully I'm going to work on it
for a long time.<br/>
Requests for features, PR, suggestions ad feedback are highly appreciated.
If you find you can help me and want to contribute to the project with your
experience or you do want to get part of the project for some other reasons,
feel free to contact me directly (you can find the mail in the
[profile](https://github.com/skypjack)).<br/>
I can't promise that each and every contribution will be accepted, but I can
assure that I'll do my best to take them all seriously.
If you decide to participate, please see the guidelines for
[contributing](docs/CONTRIBUTING.md) before to create issues or pull requests.<br/>
Take also a look at the
[contributors list](https://github.com/skypjack/entt/blob/master/AUTHORS) to
know who has participated so far.
<!--
@endcond TURN_OFF_DOXYGEN
-->
# License
Code and documentation Copyright (c) 2018 Michele Caini.<br/>
Code and documentation Copyright (c) 2017-2018 Michele Caini.<br/>
Logo Copyright (c) 2018 Richard Caseres.
Code released under
[the MIT license](https://github.com/skypjack/entt/blob/master/LICENSE).
Docs released under
[Creative Commons](https://github.com/skypjack/entt/blob/master/docs/LICENSE).
Documentation released under
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).<br/>
Logo released under
[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
<!--
@cond TURN_OFF_DOXYGEN
-->
# Support
## Donation
Developing and maintaining `EnTT` takes some time and lots of coffee. I'd like
to add more and more functionalities in future and turn it in a full-featured
framework.<br/>
solution.<br/>
If you want to support this project, you can offer me an espresso. I'm from
Italy, we're used to turning the best coffee ever in code. If you find that
it's not enough, feel free to support me the way you prefer.<br/>
@@ -2765,3 +2844,6 @@ to give it the highest priority, if you have any other reason to contact me:
do not hesitate. I'm available for hiring.<br/>
Feel free to take a look at my [profile](https://github.com/skypjack) and
contact me by mail.
<!--
@endcond TURN_OFF_DOXYGEN
-->

7
TODO
View File

@@ -5,8 +5,11 @@
* define basic reactive systems (track entities to which component is attached, track entities from which component is removed, and so on)
* define systems as composable mixins (initializazion, reactive, update, whatever) with flexible auto-detected arguments (registry, views, etc)
* create dedicated flat map based on types implementation (sort of "type map") for types to use within the registry and so on...
* ease the assignment of tags as string (type-less assign member function + user defined literal for hashed strings)
* family -> std::uint32_t (or some other fixed and known size type)
* registry::create with a "hint" on the entity identifier to use, it should ease combining multiple registries
* optimize for empty components, it would be a mid improvement in terms of memory usage
* add some lazy iterative sorters like "single bubble sort loop"
* can we do more for shared libraries? who knows... see #144
* work stealing job system (see #100)
* reflection system (maybe)
* C++17. That's all.
* AOB

View File

@@ -2,7 +2,7 @@
# Doxygen configuration (documentation)
#
set(DOXY_SOURCE_DIRECTORY ${entt_SOURCE_DIR}/src)
set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src)
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
@@ -11,7 +11,7 @@ configure_file(doxy.in doxy.cfg @ONLY)
add_custom_target(
docs ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg
WORKING_DIRECTORY ${entt_SOURCE_DIR}
WORKING_DIRECTORY ${EnTT_SOURCE_DIR}
VERBATIM
SOURCES doxy.in
)

View File

@@ -1,395 +0,0 @@
Attribution 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More_considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution 4.0 International Public License ("Public License"). To the
extent this Public License may be interpreted as a contract, You are
granted the Licensed Rights in consideration of Your acceptance of
these terms and conditions, and the Licensor grants You such rights in
consideration of benefits the Licensor receives from making the
Licensed Material available under these terms and conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
d. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
e. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
f. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
g. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
h. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
i. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
j. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
k. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
4. If You Share Adapted Material You produce, the Adapter's
License You apply must not prevent recipients of the Adapted
Material from complying with this Public License.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material; and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

60
scripts/update_homebrew.sh Executable file
View File

@@ -0,0 +1,60 @@
#!/bin/sh
# only argument should be the version to upgrade to
if [ $# != 1 ]
then
echo "Expected a version tag like v2.7.1"
exit 1
fi
VERSION="$1"
URL="https://github.com/skypjack/entt/archive/$VERSION.tar.gz"
FORMULA="entt.rb"
echo "Updating homebrew package to $VERSION"
echo "Cloning..."
git clone https://github.com/skypjack/homebrew-entt.git
if [ $? != 0 ]
then
exit 1
fi
cd homebrew-entt
# download the repo at the version
# exit with error messages if curl fails
echo "Curling..."
curl "$URL" --location --fail --silent --show-error --output archive.tar.gz
if [ $? != 0 ]
then
exit 1
fi
# compute sha256 hash
echo "Hashing..."
HASH="$(openssl sha256 archive.tar.gz | cut -d " " -f 2)"
# delete the archive
rm archive.tar.gz
echo "Sedding..."
# change the url in the formula file
# the slashes in the URL must be escaped
ESCAPED_URL="$(sed -e 's/[\/&]/\\&/g' <<< "$URL")"
sed -i -e '/url/s/".*"/"'$ESCAPED_URL'"/' $FORMULA
# change the hash in the formula file
sed -i -e '/sha256/s/".*"/"'$HASH'"/' $FORMULA
# delete temporary file created by sed
rm "$FORMULA-e"
# update remote repo
echo "Gitting..."
git add entt.rb
git commit -m "Update to $VERSION"
git push origin master
# out of homebrew-entt dir
cd ..

3
scripts/update_packages.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
scripts/update_homebrew.sh $1

View File

@@ -18,11 +18,11 @@ namespace entt {
* This class fills the gap by wrapping some flavors of `std::sort` in a
* function object.
*/
struct StdSort {
struct StdSort final {
/**
* @brief Sorts the element in a range.
* @brief Sorts the elements in a range.
*
* Sorts the element in a range using the given binary comparison function.
* Sorts the elements in a range using the given binary comparison function.
*
* @tparam It Type of random access iterator.
* @tparam Compare Type of comparison function object.
@@ -40,11 +40,11 @@ struct StdSort {
/*! @brief Function object for performing insertion sort. */
struct InsertionSort {
struct InsertionSort final {
/**
* @brief Sorts the element in a range.
* @brief Sorts the elements in a range.
*
* Sorts the element in a range using the given binary comparison function.
* Sorts the elements in a range using the given binary comparison function.
*
* @tparam It Type of random access iterator.
* @tparam Compare Type of comparison function object.
@@ -72,6 +72,39 @@ struct InsertionSort {
};
/*! @brief Function object for performing bubble sort (single iteration). */
struct OneShotBubbleSort final {
/**
* @brief Tries to sort the elements in a range.
*
* Performs a single iteration to sort the elements in a range using the
* given binary comparison function. The range may not be completely sorted
* after running this function.
*
* @tparam It Type of random access iterator.
* @tparam Compare Type of comparison function object.
* @param first An iterator to the first element of the range to sort.
* @param last An iterator past the last element of the range to sort.
* @param compare A valid comparison function object.
*/
template<typename It, typename Compare = std::less<>>
void operator()(It first, It last, Compare compare = Compare{}) const {
if(first != last) {
auto it = first++;
while(first != last) {
if(compare(*first, *it)) {
using std::swap;
std::swap(*first, *it);
}
it = first++;
}
}
}
};
}

View File

@@ -108,6 +108,11 @@ constexpr bool operator!=(const HashedString &lhs, const HashedString &rhs) ENTT
}
/**
* @brief User defined literal for hashed strings.
* @param str The literal without its suffix.
* @return A properly initialized hashed string.
*/
constexpr entt::HashedString operator"" ENTT_HS_SUFFIX(const char *str, std::size_t) ENTT_NOEXCEPT {
return entt::HashedString{str};
}

View File

@@ -2,6 +2,8 @@
#define ENTT_ENTITY_HELPER_HPP
#include <type_traits>
#include "../core/hashed_string.hpp"
#include "../signal/sigh.hpp"
#include "registry.hpp"
#include "utility.hpp"
@@ -78,6 +80,25 @@ void dependency(break_t, Sink<void(Registry<Entity> &, const Entity)> sink) {
}
/**
* @brief Alias template to ease the assignment of labels to entities.
*
* If used in combination with hashed strings, it simplifies the assignment of
* labels to entities and the use of labels in general where a type would be
* required otherwise.<br/>
* As an example and where the user defined literal for hashed strings hasn't
* been changed:
* @code{.cpp}
* entt::DefaultRegistry registry;
* registry.assign<entt::label<"enemy"_hs>>(entity);
* @endcode
*
* @tparam Value The numeric representation of an instance of hashed string.
*/
template<typename HashedString::hash_type Value>
using label = std::integral_constant<typename HashedString::hash_type, Value>;
}

View File

@@ -44,10 +44,10 @@ class Registry {
using signal_type = SigH<void(Registry &, const Entity)>;
using traits_type = entt_traits<Entity>;
template<typename... Component>
template<typename handler_family::family_type(*Type)(), typename... Component>
static void creating(Registry &registry, const Entity entity) {
if(registry.has<Component...>(entity)) {
registry.handlers[handler_family::type<Component...>()]->construct(entity);
registry.handlers[Type()]->construct(entity);
}
}
@@ -74,6 +74,35 @@ class Registry {
Tag tag;
};
template<typename Comp, std::size_t Pivot, typename... Component, std::size_t... Indexes>
void connect(std::index_sequence<Indexes...>) {
auto &cpool = pools[component_family::type<Comp>()];
std::get<1>(cpool).sink().template connect<&Registry::creating<&handler_family::type<Component...>, std::tuple_element_t<(Indexes < Pivot ? Indexes : (Indexes+1)), std::tuple<Component...>>...>>();
std::get<2>(cpool).sink().template connect<&Registry::destroying<Component...>>();
}
template<typename... Component, std::size_t... Indexes>
void connect(std::index_sequence<Indexes...>) {
using accumulator_type = int[];
accumulator_type accumulator = { (assure<Component>(), connect<Component, Indexes, Component...>(std::make_index_sequence<sizeof...(Component)-1>{}), 0)... };
(void)accumulator;
}
template<typename Comp, std::size_t Pivot, typename... Component, std::size_t... Indexes>
void disconnect(std::index_sequence<Indexes...>) {
auto &cpool = pools[component_family::type<Comp>()];
std::get<1>(cpool).sink().template disconnect<&Registry::creating<&handler_family::type<Component...>, std::tuple_element_t<(Indexes < Pivot ? Indexes : (Indexes+1)), std::tuple<Component...>>...>>();
std::get<2>(cpool).sink().template disconnect<&Registry::destroying<Component...>>();
}
template<typename... Component, std::size_t... Indexes>
void disconnect(std::index_sequence<Indexes...>) {
using accumulator_type = int[];
// if a set exists, pools have already been created for it
accumulator_type accumulator = { (disconnect<Component, Indexes, Component...>(std::make_index_sequence<sizeof...(Component)-1>{}), 0)... };
(void)accumulator;
}
template<typename Component>
inline bool managed() const ENTT_NOEXCEPT {
const auto ctype = component_family::type<Component>();
@@ -187,11 +216,19 @@ public:
return managed<Component>() ? pool<Component>().size() : size_type{};
}
/**
* @brief Returns the number of entities created so far.
* @return Number of entities created so far.
*/
size_type size() const ENTT_NOEXCEPT {
return entities.size();
}
/**
* @brief Returns the number of entities still in use.
* @return Number of entities still in use.
*/
size_type size() const ENTT_NOEXCEPT {
size_type alive() const ENTT_NOEXCEPT {
return entities.size() - available;
}
@@ -350,10 +387,19 @@ public:
return (entities[pos] == entity);
}
/**
* @brief Returns the entity identifier without the version.
* @param entity An entity identifier, either valid or not.
* @return The entity identifier without the version.
*/
entity_type entity(const entity_type entity) const ENTT_NOEXCEPT {
return entity & traits_type::entity_mask;
}
/**
* @brief Returns the version stored along with an entity identifier.
* @param entity An entity identifier, either valid or not.
* @return Version stored along with the given entity identifier.
* @return The version stored along with the given entity identifier.
*/
version_type version(const entity_type entity) const ENTT_NOEXCEPT {
return version_type((entity >> traits_type::entity_shift) & traits_type::version_mask);
@@ -405,7 +451,6 @@ public:
if(available) {
const auto entt = next;
const auto version = entities[entt] & (~traits_type::entity_mask);
entity = entt | version;
next = entities[entt] & traits_type::entity_mask;
entities[entt] = entity;
@@ -487,17 +532,17 @@ public:
// just a way to protect users from listeners that attach components
assert(orphan(entity));
// lengthens the implicit list of destroyed entities
const auto entt = entity & traits_type::entity_mask;
const auto version = (((entity >> traits_type::entity_shift) + 1) & traits_type::version_mask) << traits_type::entity_shift;
const auto node = (available ? next : ((entt + 1) & traits_type::entity_mask)) | version;
entities[entt] = node;
next = entt;
++available;
}
/**
* @brief Destroys the entities that own he given components, if any.
* @brief Destroys the entities that own the given components, if any.
*
* Convenient shortcut to destroy a set of entities at once.<br/>
* Syntactic sugar for the following snippet:
@@ -1335,22 +1380,13 @@ public:
}
if(!handlers[htype]) {
connect<Component...>(std::make_index_sequence<sizeof...(Component)>{});
handlers[htype] = std::make_unique<SparseSet<entity_type>>();
auto &handler = handlers[htype];
auto &handler = *handlers[htype];
for(auto entity: view<Component...>()) {
handler->construct(entity);
handler.construct(entity);
}
auto connect = [this](const auto ctype) {
auto &cpool = pools[ctype];
std::get<1>(cpool).sink().template connect<&Registry::creating<Component...>>();
std::get<2>(cpool).sink().template connect<&Registry::destroying<Component...>>();
};
using accumulator_type = int[];
accumulator_type accumulator = { (assure<Component>(), connect(component_family::type<Component>()), 0)... };
(void)accumulator;
}
}
@@ -1372,19 +1408,8 @@ public:
template<typename... Component>
void discard() {
if(contains<Component...>()) {
const auto htype = handler_family::type<Component...>();
auto disconnect = [this](const auto ctype) {
auto &cpool = pools[ctype];
std::get<1>(cpool).sink().template disconnect<&Registry::creating<Component...>>();
std::get<2>(cpool).sink().template disconnect<&Registry::destroying<Component...>>();
};
// if a set exists, pools have already been created for it
using accumulator_type = int[];
accumulator_type accumulator = { (disconnect(component_family::type<Component>()), 0)... };
handlers[htype].reset();
(void)accumulator;
disconnect<Component...>(std::make_index_sequence<sizeof...(Component)>{});
handlers[handler_family::type<Component...>()].reset();
}
}

View File

@@ -100,7 +100,7 @@ public:
*/
template<typename Archive>
const Snapshot & entities(Archive &archive) const {
archive(static_cast<Entity>(registry.size()));
archive(static_cast<Entity>(registry.alive()));
registry.each([&archive](const auto entity) { archive(entity); });
return *this;
}
@@ -117,7 +117,7 @@ public:
*/
template<typename Archive>
const Snapshot & destroyed(Archive &archive) const {
auto size = registry.capacity() - registry.size();
auto size = registry.size() - registry.alive();
archive(static_cast<Entity>(size));
auto curr = seed;

View File

@@ -63,16 +63,16 @@ class SparseSet<Entity> {
class Iterator final {
friend class SparseSet<Entity>;
using entity_type = Entity;
using direct_type = const std::vector<Entity>;
using index_type = typename traits_type::difference_type;
Iterator(const entity_type *direct, index_type index) ENTT_NOEXCEPT
Iterator(direct_type *direct, index_type index) ENTT_NOEXCEPT
: direct{direct}, index{index}
{}
public:
using difference_type = index_type;
using value_type = const entity_type;
using value_type = const Entity;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::random_access_iterator_tag;
@@ -122,7 +122,7 @@ class SparseSet<Entity> {
}
reference operator[](const difference_type value) const ENTT_NOEXCEPT {
return direct[index-value-1];
return (*direct)[index-value-1];
}
bool operator==(const Iterator &other) const ENTT_NOEXCEPT {
@@ -150,7 +150,7 @@ class SparseSet<Entity> {
}
pointer operator->() const ENTT_NOEXCEPT {
return (direct+index-1);
return &(*direct)[index-1];
}
inline reference operator*() const ENTT_NOEXCEPT {
@@ -158,7 +158,7 @@ class SparseSet<Entity> {
}
private:
pointer direct;
direct_type *direct;
index_type index;
};
@@ -278,7 +278,7 @@ public:
*/
const_iterator_type cbegin() const ENTT_NOEXCEPT {
const typename traits_type::difference_type pos = direct.size();
return const_iterator_type{direct.data(), pos};
return const_iterator_type{&direct, pos};
}
/**
@@ -327,7 +327,7 @@ public:
* internal packed array.
*/
const_iterator_type cend() const ENTT_NOEXCEPT {
return const_iterator_type{direct.data(), {}};
return const_iterator_type{&direct, {}};
}
/**
@@ -578,7 +578,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
class Iterator final {
friend class SparseSet<Entity, Type>;
using instance_type = std::conditional_t<Const, const Type, Type>;
using instance_type = std::conditional_t<Const, const std::vector<Type>, std::vector<Type>>;
using index_type = typename traits_type::difference_type;
Iterator(instance_type *instances, index_type index) ENTT_NOEXCEPT
@@ -587,7 +587,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
public:
using difference_type = index_type;
using value_type = instance_type;
using value_type = std::conditional_t<Const, const Type, Type>;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::random_access_iterator_tag;
@@ -637,7 +637,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
}
reference operator[](const difference_type value) const ENTT_NOEXCEPT {
return instances[index-value-1];
return (*instances)[index-value-1];
}
bool operator==(const Iterator &other) const ENTT_NOEXCEPT {
@@ -665,7 +665,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
}
pointer operator->() const ENTT_NOEXCEPT {
return (instances+index-1);
return &(*instances)[index-1];
}
inline reference operator*() const ENTT_NOEXCEPT {
@@ -673,7 +673,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
}
private:
pointer instances;
instance_type *instances;
index_type index;
};
@@ -767,7 +767,7 @@ public:
*/
const_iterator_type cbegin() const ENTT_NOEXCEPT {
const typename traits_type::difference_type pos = instances.size();
return const_iterator_type{instances.data(), pos};
return const_iterator_type{&instances, pos};
}
/**
@@ -800,7 +800,7 @@ public:
*/
iterator_type begin() ENTT_NOEXCEPT {
const typename traits_type::difference_type pos = instances.size();
return iterator_type{instances.data(), pos};
return iterator_type{&instances, pos};
}
/**
@@ -818,7 +818,7 @@ public:
* given type.
*/
const_iterator_type cend() const ENTT_NOEXCEPT {
return const_iterator_type{instances.data(), {}};
return const_iterator_type{&instances, {}};
}
/**
@@ -854,7 +854,7 @@ public:
* given type.
*/
iterator_type end() ENTT_NOEXCEPT {
return iterator_type{instances.data(), {}};
return iterator_type{&instances, {}};
}
/**

View File

@@ -590,26 +590,21 @@ class View final {
template<typename Comp, typename Func, std::size_t... Indexes>
void each(const pool_type<Comp> &cpool, Func func, std::index_sequence<Indexes...>) const {
const auto other = unchecked(&cpool);
std::array<underlying_iterator_type, sizeof...(Component)> data{{cpool.view_type::cbegin(), std::get<Indexes>(other)->cbegin()...}};
std::array<underlying_iterator_type, sizeof...(Indexes)> data{{std::get<Indexes>(other)->cbegin()...}};
const auto extent = std::min({ pool<Component>().extent()... });
auto raw = std::make_tuple(pool<Component>().cbegin()...);
const auto end = cpool.view_type::cend();
std::size_t pos{};
auto begin = cpool.view_type::cbegin();
// we can directly use the raw iterators if pools are ordered
while(!pos && data[0] != end) {
for(pos = data.size() - 1; pos && *(data[pos]++) == *data[pos-1]; --pos);
if(!pos) {
func(*(data[0]++), *(std::get<component_iterator_type<Component>>(raw)++)...);
}
while(begin != end && std::min({ (*(std::get<Indexes>(data)++) == *begin)... })) {
func(*(begin++), *(std::get<component_iterator_type<Component>>(raw)++)...);
}
const auto extent = std::min({ pool<Component>().extent()... });
auto it = std::get<component_iterator_type<Comp>>(raw);
// fallback to visit what remains using indirections
for(; data[0] != end; ++data[0], ++it) {
const auto entity = *data[0];
while(begin != end) {
const auto entity = *(begin++);
const auto it = std::get<component_iterator_type<Comp>>(raw)++;
const auto sz = size_type(entity & traits_type::entity_mask);
if(sz < extent && std::all_of(other.cbegin(), other.cend(), [entity](const view_type *view) { return view->fast(entity); })) {
@@ -1675,7 +1670,7 @@ class RuntimeView {
: pools{std::move(others)}
{
const auto it = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
return !lhs || (rhs && (lhs->size() < rhs->size()));
return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
});
// brings the best candidate (if any) on front of the vector

View File

@@ -2,31 +2,21 @@
# Tests configuration
#
include_directories($<TARGET_PROPERTY:EnTT,INTERFACE_INCLUDE_DIRECTORIES>)
add_compile_options($<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_OPTIONS>)
add_library(odr OBJECT odr.cpp)
set_target_properties(odr PROPERTIES CXX_EXTENSIONS OFF)
target_compile_definitions(odr PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_DEFINITIONS>)
target_compile_features(odr PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>)
target_compile_options(odr PRIVATE $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-pedantic -Wall>)
target_include_directories(odr
PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_INCLUDE_DIRECTORIES>
)
target_compile_definitions(odr
PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_DEFINITIONS>
)
target_compile_options(odr
PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_OPTIONS>
PRIVATE $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-pedantic -Wall>
)
target_compile_features(odr
PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>
)
macro(ADD_ENTT_TEST TEST_NAME TEST_SOURCE)
macro(SETUP_AND_ADD_TEST TEST_NAME TEST_SOURCE)
add_executable(${TEST_NAME} $<TARGET_OBJECTS:odr> ${TEST_SOURCE})
target_link_libraries(${TEST_NAME} PRIVATE EnTT gtest_main Threads::Threads)
set_target_properties(${TEST_NAME} PROPERTIES CXX_EXTENSIONS OFF)
target_link_libraries(${TEST_NAME} PRIVATE EnTT GTest::Main Threads::Threads)
target_compile_definitions(${TEST_NAME} PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_DEFINITIONS>)
target_compile_features(${TEST_NAME} PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>)
target_compile_options(${TEST_NAME} PRIVATE $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-pedantic -Wall>)
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
endmacro()
@@ -34,71 +24,71 @@ endmacro()
# Test benchmark
if(BUILD_BENCHMARK)
ADD_ENTT_TEST(benchmark benchmark/benchmark.cpp)
SETUP_AND_ADD_TEST(benchmark benchmark/benchmark.cpp)
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)
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)
set(MOD_TEST_SOURCE ${DUKTAPE_SRC_DIR}/duktape.c mod/mod.cpp)
ADD_ENTT_TEST(mod "${MOD_TEST_SOURCE}")
SETUP_AND_ADD_TEST(mod "${MOD_TEST_SOURCE}")
target_include_directories(mod PRIVATE ${DUKTAPE_SRC_DIR})
endif()
# Test snapshot
if(BUILD_SNAPSHOT)
set(CEREAL_DEPS_DIR ${entt_SOURCE_DIR}/deps/cereal)
configure_file(${entt_SOURCE_DIR}/cmake/in/cereal.in ${CEREAL_DEPS_DIR}/CMakeLists.txt)
set(CEREAL_DEPS_DIR ${EnTT_SOURCE_DIR}/deps/cereal)
configure_file(${EnTT_SOURCE_DIR}/cmake/in/cereal.in ${CEREAL_DEPS_DIR}/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${CEREAL_DEPS_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CEREAL_DEPS_DIR})
set(CEREAL_SRC_DIR ${CEREAL_DEPS_DIR}/src/include)
ADD_ENTT_TEST(cereal snapshot/snapshot.cpp)
SETUP_AND_ADD_TEST(cereal snapshot/snapshot.cpp)
target_include_directories(cereal PRIVATE ${CEREAL_SRC_DIR})
endif()
# Test core
ADD_ENTT_TEST(algorithm entt/core/algorithm.cpp)
ADD_ENTT_TEST(family entt/core/family.cpp)
ADD_ENTT_TEST(hashed_string entt/core/hashed_string.cpp)
ADD_ENTT_TEST(ident entt/core/ident.cpp)
ADD_ENTT_TEST(monostate entt/core/monostate.cpp)
SETUP_AND_ADD_TEST(algorithm entt/core/algorithm.cpp)
SETUP_AND_ADD_TEST(family entt/core/family.cpp)
SETUP_AND_ADD_TEST(hashed_string entt/core/hashed_string.cpp)
SETUP_AND_ADD_TEST(ident entt/core/ident.cpp)
SETUP_AND_ADD_TEST(monostate entt/core/monostate.cpp)
# Test entity
ADD_ENTT_TEST(actor entt/entity/actor.cpp)
ADD_ENTT_TEST(entity entt/entity/entity.cpp)
ADD_ENTT_TEST(helper entt/entity/helper.cpp)
ADD_ENTT_TEST(prototype entt/entity/prototype.cpp)
ADD_ENTT_TEST(registry entt/entity/registry.cpp)
ADD_ENTT_TEST(snapshot entt/entity/snapshot.cpp)
ADD_ENTT_TEST(sparse_set entt/entity/sparse_set.cpp)
ADD_ENTT_TEST(view entt/entity/view.cpp)
SETUP_AND_ADD_TEST(actor entt/entity/actor.cpp)
SETUP_AND_ADD_TEST(entity entt/entity/entity.cpp)
SETUP_AND_ADD_TEST(helper entt/entity/helper.cpp)
SETUP_AND_ADD_TEST(prototype entt/entity/prototype.cpp)
SETUP_AND_ADD_TEST(registry entt/entity/registry.cpp)
SETUP_AND_ADD_TEST(snapshot entt/entity/snapshot.cpp)
SETUP_AND_ADD_TEST(sparse_set entt/entity/sparse_set.cpp)
SETUP_AND_ADD_TEST(view entt/entity/view.cpp)
# Test locator
ADD_ENTT_TEST(locator entt/locator/locator.cpp)
SETUP_AND_ADD_TEST(locator entt/locator/locator.cpp)
# Test process
ADD_ENTT_TEST(process entt/process/process.cpp)
ADD_ENTT_TEST(scheduler entt/process/scheduler.cpp)
SETUP_AND_ADD_TEST(process entt/process/process.cpp)
SETUP_AND_ADD_TEST(scheduler entt/process/scheduler.cpp)
# Test resource
ADD_ENTT_TEST(resource entt/resource/resource.cpp)
SETUP_AND_ADD_TEST(resource entt/resource/resource.cpp)
# Test signal
ADD_ENTT_TEST(delegate entt/signal/delegate.cpp)
ADD_ENTT_TEST(dispatcher entt/signal/dispatcher.cpp)
ADD_ENTT_TEST(emitter entt/signal/emitter.cpp)
ADD_ENTT_TEST(sigh entt/signal/sigh.cpp)
SETUP_AND_ADD_TEST(delegate entt/signal/delegate.cpp)
SETUP_AND_ADD_TEST(dispatcher entt/signal/dispatcher.cpp)
SETUP_AND_ADD_TEST(emitter entt/signal/emitter.cpp)
SETUP_AND_ADD_TEST(sigh entt/signal/sigh.cpp)

View File

@@ -9,7 +9,7 @@ TEST(Algorithm, StdSort) {
sort(arr.begin(), arr.end());
for(auto i = 0; i < 4; ++i) {
for(typename decltype(arr)::size_type i = 0; i < (arr.size() - 1); ++i) {
ASSERT_LT(arr[i], arr[i+1]);
}
}
@@ -20,7 +20,21 @@ TEST(Algorithm, InsertionSort) {
sort(arr.begin(), arr.end());
for(auto i = 0; i < 4; ++i) {
for(typename decltype(arr)::size_type i = 0; i < (arr.size() - 1); ++i) {
ASSERT_LT(arr[i], arr[i+1]);
}
}
TEST(Algorithm, OneShotBubbleSort) {
std::array<int, 5> arr{{4, 1, 3, 2, 0}};
entt::OneShotBubbleSort sort;
sort(arr.begin(), arr.end());
sort(arr.begin(), arr.end());
sort(arr.begin(), arr.end());
sort(arr.begin(), arr.end());
for(typename decltype(arr)::size_type i = 0; i < (arr.size() - 1); ++i) {
ASSERT_LT(arr[i], arr[i+1]);
}
}

View File

@@ -20,7 +20,6 @@ TEST(Identifier, Uniqueness) {
switch(ID::get<AnotherType>()) {
case ID::get<AType>():
FAIL();
break;
case ID::get<AnotherType>():
SUCCEED();
}

View File

@@ -1,8 +1,9 @@
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/entity/helper.hpp>
#include <entt/entity/registry.hpp>
TEST(Dependency, Functionalities) {
TEST(Helper, Dependency) {
entt::DefaultRegistry registry;
const auto entity = registry.create();
entt::dependency<double, float>(registry.construction<int>());
@@ -47,3 +48,28 @@ TEST(Dependency, Functionalities) {
ASSERT_FALSE(registry.has<double>(entity));
ASSERT_FALSE(registry.has<float>(entity));
}
TEST(Helper, Label) {
entt::DefaultRegistry registry;
const auto entity = registry.create();
registry.assign<entt::label<"foobar"_hs>>(entity);
registry.assign<int>(entity, 42);
int counter{};
ASSERT_FALSE(registry.has<entt::label<"barfoo"_hs>>(entity));
ASSERT_TRUE(registry.has<entt::label<"foobar"_hs>>(entity));
for(auto entity: registry.view<int, entt::label<"foobar"_hs>>()) {
(void)entity;
++counter;
}
ASSERT_NE(counter, 0);
for(auto entity: registry.view<entt::label<"foobar"_hs>>()) {
(void)entity;
--counter;
}
ASSERT_EQ(counter, 0);
}

View File

@@ -59,6 +59,7 @@ TEST(DefaultRegistry, Functionalities) {
entt::DefaultRegistry registry;
ASSERT_EQ(registry.size(), entt::DefaultRegistry::size_type{0});
ASSERT_EQ(registry.alive(), entt::DefaultRegistry::size_type{0});
ASSERT_NO_THROW(registry.reserve(42));
ASSERT_NO_THROW(registry.reserve<int>(8));
ASSERT_NO_THROW(registry.reserve<char>(8));
@@ -134,6 +135,7 @@ TEST(DefaultRegistry, Functionalities) {
ASSERT_EQ(static_cast<const entt::DefaultRegistry &>(registry).get<int>(e1), 1);
ASSERT_EQ(registry.size(), entt::DefaultRegistry::size_type{3});
ASSERT_EQ(registry.alive(), entt::DefaultRegistry::size_type{3});
ASSERT_FALSE(registry.empty());
ASSERT_EQ(registry.version(e2), entt::DefaultRegistry::version_type{0});
@@ -149,12 +151,14 @@ TEST(DefaultRegistry, Functionalities) {
ASSERT_FALSE(registry.valid(e2));
ASSERT_FALSE(registry.fast(e2));
ASSERT_EQ(registry.size(), entt::DefaultRegistry::size_type{2});
ASSERT_EQ(registry.size(), entt::DefaultRegistry::size_type{3});
ASSERT_EQ(registry.alive(), entt::DefaultRegistry::size_type{2});
ASSERT_FALSE(registry.empty());
ASSERT_NO_THROW(registry.reset());
ASSERT_EQ(registry.size(), entt::DefaultRegistry::size_type{0});
ASSERT_EQ(registry.size(), entt::DefaultRegistry::size_type{3});
ASSERT_EQ(registry.alive(), entt::DefaultRegistry::size_type{0});
ASSERT_TRUE(registry.empty());
const auto e3 = registry.create();
@@ -194,6 +198,22 @@ TEST(DefaultRegistry, Functionalities) {
ASSERT_TRUE(registry.empty<int>());
}
TEST(DefaultRegistry, Identifiers) {
entt::DefaultRegistry registry;
const auto pre = registry.create();
ASSERT_EQ(pre, registry.entity(pre));
registry.destroy(pre);
const auto post = registry.create();
ASSERT_NE(pre, post);
ASSERT_EQ(registry.entity(pre), registry.entity(post));
ASSERT_NE(registry.version(pre), registry.version(post));
ASSERT_NE(registry.version(pre), registry.current(pre));
ASSERT_EQ(registry.version(post), registry.current(post));
}
TEST(DefaultRegistry, RawData) {
entt::DefaultRegistry registry;
const entt::DefaultRegistry &cregistry = registry;

View File

@@ -337,6 +337,22 @@ TEST(SparseSetNoType, RespectUnordered) {
ASSERT_EQ(rhs.get(5), 5u);
}
TEST(SparseSetNoType, CanModifyDuringIteration) {
entt::SparseSet<std::uint64_t> set;
set.construct(0);
ASSERT_EQ(set.capacity(), entt::SparseSet<std::uint64_t>::size_type{1});
const auto it = set.cbegin();
set.reserve(entt::SparseSet<std::uint64_t>::size_type{2});
ASSERT_EQ(set.capacity(), entt::SparseSet<std::uint64_t>::size_type{2});
// this should crash with asan enabled if we break the constraint
const auto entity = *it;
(void)entity;
}
TEST(SparseSetWithType, Functionalities) {
entt::SparseSet<std::uint64_t, int> set;
const auto &cset = set;
@@ -823,6 +839,22 @@ TEST(SparseSetWithType, RespectUnordered) {
ASSERT_EQ(*(rhs.data() + 5u), 5u);
}
TEST(SparseSetWithType, CanModifyDuringIteration) {
entt::SparseSet<std::uint64_t, int> set;
set.construct(0, 42);
ASSERT_EQ(set.capacity(), entt::SparseSet<std::uint64_t>::size_type{1});
const auto it = set.cbegin();
set.reserve(entt::SparseSet<std::uint64_t>::size_type{2});
ASSERT_EQ(set.capacity(), entt::SparseSet<std::uint64_t>::size_type{2});
// this should crash with asan enabled if we break the constraint
const auto entity = *it;
(void)entity;
}
TEST(SparseSetWithType, ReferencesGuaranteed) {
struct InternalType { int value; };

View File

@@ -142,7 +142,7 @@ TEST(SigH, Functions) {
sigh.publish(v);
ASSERT_FALSE(sigh.empty());
ASSERT_EQ((entt::SigH<bool(int)>::size_type)1, sigh.size());
ASSERT_EQ(static_cast<entt::SigH<bool(int)>::size_type>(1), sigh.size());
ASSERT_EQ(42, v);
v = 0;
@@ -150,7 +150,7 @@ TEST(SigH, Functions) {
sigh.publish(v);
ASSERT_TRUE(sigh.empty());
ASSERT_EQ((entt::SigH<bool(int)>::size_type)0, sigh.size());
ASSERT_EQ(static_cast<entt::SigH<bool(int)>::size_type>(0), sigh.size());
ASSERT_EQ(0, v);
sigh.sink().connect<&SigHListener::f>();
@@ -166,25 +166,25 @@ TEST(SigH, Members) {
ASSERT_TRUE(s.k);
ASSERT_FALSE(sigh.empty());
ASSERT_EQ((entt::SigH<bool(int)>::size_type)1, sigh.size());
ASSERT_EQ(static_cast<entt::SigH<bool(int)>::size_type>(1), sigh.size());
sigh.sink().disconnect<SigHListener, &SigHListener::g>(ptr);
sigh.publish(42);
ASSERT_TRUE(s.k);
ASSERT_TRUE(sigh.empty());
ASSERT_EQ((entt::SigH<bool(int)>::size_type)0, sigh.size());
ASSERT_EQ(static_cast<entt::SigH<bool(int)>::size_type>(0), sigh.size());
sigh.sink().connect<SigHListener, &SigHListener::g>(ptr);
sigh.sink().connect<SigHListener, &SigHListener::h>(ptr);
ASSERT_FALSE(sigh.empty());
ASSERT_EQ((entt::SigH<bool(int)>::size_type)2, sigh.size());
ASSERT_EQ(static_cast<entt::SigH<bool(int)>::size_type>(2), sigh.size());
sigh.sink().disconnect(ptr);
ASSERT_TRUE(sigh.empty());
ASSERT_EQ((entt::SigH<bool(int)>::size_type)0, sigh.size());
ASSERT_EQ(static_cast<entt::SigH<bool(int)>::size_type>(0), sigh.size());
}
TEST(SigH, Collector) {
@@ -205,7 +205,7 @@ TEST(SigH, Collector) {
ASSERT_FALSE(sigh_all.empty());
ASSERT_FALSE(collector_all.vec.empty());
ASSERT_EQ((std::vector<int>::size_type)2, collector_all.vec.size());
ASSERT_EQ(static_cast<std::vector<int>::size_type>(2), collector_all.vec.size());
ASSERT_EQ(42, collector_all.vec[0]);
ASSERT_EQ(42, collector_all.vec[1]);
@@ -217,6 +217,6 @@ TEST(SigH, Collector) {
ASSERT_FALSE(sigh_first.empty());
ASSERT_FALSE(collector_first.vec.empty());
ASSERT_EQ((std::vector<int>::size_type)1, collector_first.vec.size());
ASSERT_EQ(static_cast<std::vector<int>::size_type>(1), collector_first.vec.size());
ASSERT_EQ(42, collector_first.vec[0]);
}