Compare commits
257 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aaa6dd986 | ||
|
|
3c39cfe645 | ||
|
|
6a46325e7e | ||
|
|
15c9688a5a | ||
|
|
d9f93ccc11 | ||
|
|
652e569afc | ||
|
|
c55372459f | ||
|
|
09f36e32f7 | ||
|
|
688d435d8e | ||
|
|
e7403d8551 | ||
|
|
60039441a1 | ||
|
|
97f4414cc4 | ||
|
|
df9595bc0d | ||
|
|
93533b7bc6 | ||
|
|
a99afa2ddf | ||
|
|
1e651a5145 | ||
|
|
79ecfa2573 | ||
|
|
e2b676d54c | ||
|
|
2b73bf35b6 | ||
|
|
2137b3a879 | ||
|
|
e52b3fd5bc | ||
|
|
0dfd2aa714 | ||
|
|
5d63c4c981 | ||
|
|
84d3f9ab9a | ||
|
|
1133dba9d8 | ||
|
|
cd2fdc2ffe | ||
|
|
57d017ed8e | ||
|
|
3ad2c559f1 | ||
|
|
c3facfa925 | ||
|
|
db8d9ebc72 | ||
|
|
3aef00af18 | ||
|
|
a4d576bae8 | ||
|
|
9320365ef6 | ||
|
|
0be7494042 | ||
|
|
df55f338ca | ||
|
|
8210efb548 | ||
|
|
43503e2fc9 | ||
|
|
448c3ae425 | ||
|
|
f7684a8a3e | ||
|
|
4f200ac71e | ||
|
|
4772559e8b | ||
|
|
a984ce5bba | ||
|
|
eee8a338e2 | ||
|
|
8894c0ef48 | ||
|
|
c5b8577d94 | ||
|
|
ce9def4a56 | ||
|
|
894601aad2 | ||
|
|
285c91e81b | ||
|
|
ba8ca93afc | ||
|
|
ad0dab2493 | ||
|
|
8b66316180 | ||
|
|
da4ee38914 | ||
|
|
62fde229e2 | ||
|
|
676115d214 | ||
|
|
f36d838df1 | ||
|
|
f32f3ab895 | ||
|
|
fc0432df8c | ||
|
|
797b5bcb53 | ||
|
|
b816f203cd | ||
|
|
714e2f86a1 | ||
|
|
ff75085f15 | ||
|
|
dbc8b18b80 | ||
|
|
efb2bbe8b2 | ||
|
|
8278c8eedd | ||
|
|
6f696a026b | ||
|
|
f558797246 | ||
|
|
c8671d1c2b | ||
|
|
7fd41e48b9 | ||
|
|
409d5f5966 | ||
|
|
5d1802faf7 | ||
|
|
a580bac385 | ||
|
|
c43214543f | ||
|
|
b3c568fb6f | ||
|
|
b34fe3200c | ||
|
|
dada8dbdeb | ||
|
|
e7d4077065 | ||
|
|
b1e54bfd86 | ||
|
|
85ad4c4766 | ||
|
|
3dce560759 | ||
|
|
969b8f0a7a | ||
|
|
ba8e738f40 | ||
|
|
4bc80fae8d | ||
|
|
ee5156704d | ||
|
|
986cd03732 | ||
|
|
937fdabaa9 | ||
|
|
c0fa97510e | ||
|
|
2fc6fe442d | ||
|
|
7ba14f5a57 | ||
|
|
352e4576fc | ||
|
|
210eebc0dc | ||
|
|
5904941361 | ||
|
|
b352815cf8 | ||
|
|
38a2751cd9 | ||
|
|
6388607d11 | ||
|
|
469276b8be | ||
|
|
2a863ee851 | ||
|
|
b6dae2fe57 | ||
|
|
d202bd3e50 | ||
|
|
dc2e44b2c0 | ||
|
|
32c481c28c | ||
|
|
8519c99706 | ||
|
|
5b1bac4c19 | ||
|
|
0a95a0674b | ||
|
|
2f11f6dc37 | ||
|
|
af66274c72 | ||
|
|
c5679b208f | ||
|
|
020fc179a5 | ||
|
|
dc9c1fc762 | ||
|
|
f0938d70b2 | ||
|
|
072761c5ba | ||
|
|
8aacd4d022 | ||
|
|
b6f9ca0021 | ||
|
|
a43f354511 | ||
|
|
43766406ae | ||
|
|
37dd1ae363 | ||
|
|
5a3effaef5 | ||
|
|
cd4bcce70f | ||
|
|
c1e7549b61 | ||
|
|
036ef25da9 | ||
|
|
9884c37ef4 | ||
|
|
23069d76eb | ||
|
|
b2d0e7fae2 | ||
|
|
30a039a031 | ||
|
|
8d67bb726c | ||
|
|
c4dec4cd4d | ||
|
|
f17b975fb9 | ||
|
|
7a3b7593d0 | ||
|
|
bad342b840 | ||
|
|
e3968a8f9d | ||
|
|
f577183c24 | ||
|
|
be58f2e68a | ||
|
|
99f81e82d5 | ||
|
|
7cfd3957de | ||
|
|
c51c88a17c | ||
|
|
e09af98dc5 | ||
|
|
89635f6583 | ||
|
|
14034642f1 | ||
|
|
4af7d975c1 | ||
|
|
d9884917fb | ||
|
|
95fd4e4c99 | ||
|
|
9457a55910 | ||
|
|
56e7dd0de0 | ||
|
|
f0dc882ae9 | ||
|
|
acb70d4440 | ||
|
|
167721bf8c | ||
|
|
4f438e5228 | ||
|
|
0f0aeb6d47 | ||
|
|
d1a6edad8a | ||
|
|
388feb7edb | ||
|
|
962b068c92 | ||
|
|
a32373bc3a | ||
|
|
94a5a4ac1e | ||
|
|
ed8eea12bd | ||
|
|
83bea8b654 | ||
|
|
d4d2db228e | ||
|
|
f8b8c91fe8 | ||
|
|
8451301a5a | ||
|
|
449b03f6bd | ||
|
|
3853ff725f | ||
|
|
ee66e3ef9e | ||
|
|
2643500957 | ||
|
|
88467a87a4 | ||
|
|
d1cdeb4a2d | ||
|
|
f5ced7fe39 | ||
|
|
023267ecab | ||
|
|
3d515a760c | ||
|
|
026c5987dd | ||
|
|
84fb3694f2 | ||
|
|
169dcbcd74 | ||
|
|
d28b6fbf1e | ||
|
|
9f7a2ef84e | ||
|
|
cc5ea60d2b | ||
|
|
8bc63494bc | ||
|
|
9acdeeed04 | ||
|
|
d2cdb2a209 | ||
|
|
36bad31355 | ||
|
|
427587e591 | ||
|
|
4f028d8201 | ||
|
|
d59c052554 | ||
|
|
93ebe91bc5 | ||
|
|
fadb8f695e | ||
|
|
8bb1518d09 | ||
|
|
e8d9d663a7 | ||
|
|
2d2648cf57 | ||
|
|
231036784d | ||
|
|
882b91b221 | ||
|
|
df346ab380 | ||
|
|
c7b8e82ada | ||
|
|
b8784863f2 | ||
|
|
3f67054f03 | ||
|
|
36d1b0a4bc | ||
|
|
748777b8eb | ||
|
|
acd8e0bce5 | ||
|
|
d2d068edff | ||
|
|
e2a7a7ce20 | ||
|
|
b25b1c45fb | ||
|
|
c3b0fa6c93 | ||
|
|
63a4e67174 | ||
|
|
88e37438fa | ||
|
|
5be1bf7d82 | ||
|
|
eb4689d2f1 | ||
|
|
e81549e5fd | ||
|
|
becaef36ff | ||
|
|
6aefa40ca2 | ||
|
|
250ef50361 | ||
|
|
5a1af60357 | ||
|
|
46db75308c | ||
|
|
33f5e13b29 | ||
|
|
54bb4797db | ||
|
|
7a14fbb221 | ||
|
|
18349f5ee4 | ||
|
|
22b93cdd0a | ||
|
|
63bc0b2ba1 | ||
|
|
c57a7c745d | ||
|
|
f2831b5f5c | ||
|
|
96f793f91b | ||
|
|
4e2a0d6e58 | ||
|
|
442c7f1f09 | ||
|
|
dbff4af7c6 | ||
|
|
93b09836da | ||
|
|
1782dc1565 | ||
|
|
cc16874d58 | ||
|
|
c8925b2ae3 | ||
|
|
fc043b9fcd | ||
|
|
ea86d33bc1 | ||
|
|
82f33b82e3 | ||
|
|
c645cb83a2 | ||
|
|
d6d79a2aa5 | ||
|
|
786568fd2f | ||
|
|
434f77a058 | ||
|
|
02f777a143 | ||
|
|
8025a84aeb | ||
|
|
c37a50d3b8 | ||
|
|
6dbbb265d1 | ||
|
|
02ce2ff74c | ||
|
|
28e5267132 | ||
|
|
f498b8a049 | ||
|
|
b31afe5c8c | ||
|
|
eac944dbea | ||
|
|
965b20c37a | ||
|
|
fba85754d7 | ||
|
|
3c69f98451 | ||
|
|
cad8a90124 | ||
|
|
b8d888b17f | ||
|
|
942d783e4e | ||
|
|
0e352cb466 | ||
|
|
50af38b952 | ||
|
|
1459c59cd0 | ||
|
|
e74f5b2991 | ||
|
|
0dec05fd70 | ||
|
|
3cff21b4d0 | ||
|
|
c380da7214 | ||
|
|
e2bf903c49 | ||
|
|
9cf64ba881 | ||
|
|
74d901b7ae | ||
|
|
b15cb46a6d | ||
|
|
89dc76e3b2 |
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
@@ -5,14 +5,13 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
timeout-minutes: 5
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-18.04]
|
||||
compiler: [g++, clang++]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
@@ -30,16 +29,18 @@ jobs:
|
||||
run: ctest --timeout 5 -C Debug -j4
|
||||
|
||||
windows:
|
||||
timeout-minutes: 5
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-2019, windows-2016]
|
||||
os: [windows-latest, windows-2016]
|
||||
toolset: [clang-cl, default]
|
||||
include:
|
||||
- os: windows-2019
|
||||
generator: Visual Studio 16 2019
|
||||
- toolset: clang-cl
|
||||
toolset_option: -T"ClangCl"
|
||||
exclude:
|
||||
- os: windows-2016
|
||||
generator: Visual Studio 15 2017
|
||||
toolset: clang-cl
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -48,7 +49,7 @@ jobs:
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DBUILD_TESTING=ON -DBUILD_LIB=ON -DCMAKE_CXX_FLAGS=/W1 -G"${{ matrix.generator }}" ..
|
||||
cmake -DBUILD_TESTING=ON -DBUILD_LIB=ON ${{ matrix.toolset_option }} ..
|
||||
cmake --build . -j 4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
@@ -57,8 +58,8 @@ jobs:
|
||||
run: ctest --timeout 5 -C Debug -j4
|
||||
|
||||
macos:
|
||||
timeout-minutes: 5
|
||||
runs-on: macOS-10.14
|
||||
timeout-minutes: 10
|
||||
runs-on: macOS-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
2
.github/workflows/coverage.yml
vendored
2
.github/workflows/coverage.yml
vendored
@@ -5,7 +5,7 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
|
||||
codecov:
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 10
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
33
.github/workflows/deploy.yml
vendored
33
.github/workflows/deploy.yml
vendored
@@ -1,33 +0,0 @@
|
||||
name: deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
|
||||
conan:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: docker://conanio/gcc8
|
||||
- uses: actions/checkout@v1
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@master
|
||||
with:
|
||||
version: 3.6
|
||||
- name: Install
|
||||
run: |
|
||||
chmod +x conan/ci/install.sh
|
||||
./conan/ci/install.sh
|
||||
- name: Deploy
|
||||
env:
|
||||
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }}
|
||||
CONAN_PASSWORD: ${{ secrets.CONAN_PASSWORD }}
|
||||
CONAN_UPLOAD: ${{ secrets.CONAN_UPLOAD }}
|
||||
CONAN_GCC_VERSIONS: 8
|
||||
run: |
|
||||
chmod +x conan/ci/build.sh
|
||||
./conan/ci/build.sh
|
||||
@@ -1,9 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_library(
|
||||
name = "entt",
|
||||
visibility = ["//visibility:public"],
|
||||
strip_include_prefix = "src",
|
||||
hdrs = glob(["src/**/*.h", "src/**/*.hpp"]),
|
||||
copts = entt_copts,
|
||||
)
|
||||
108
CMakeLists.txt
108
CMakeLists.txt
@@ -2,7 +2,7 @@
|
||||
# EnTT
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.7.2)
|
||||
cmake_minimum_required(VERSION 3.12.4)
|
||||
|
||||
#
|
||||
# Building in-tree is not allowed (we take care of your craziness).
|
||||
@@ -12,31 +12,38 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the source code and call cmake from there. Thank you.")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Read project version
|
||||
#
|
||||
|
||||
set(ENTT_VERSION_REGEX "#define ENTT_VERSION_.*[ \t]+(.+)")
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/src/entt/config/version.h" ENTT_VERSION REGEX ${ENTT_VERSION_REGEX})
|
||||
list(TRANSFORM ENTT_VERSION REPLACE ${ENTT_VERSION_REGEX} "\\1")
|
||||
string(JOIN "." ENTT_VERSION ${ENTT_VERSION})
|
||||
|
||||
#
|
||||
# Project configuration
|
||||
#
|
||||
|
||||
project(EnTT VERSION 3.2.2 LANGUAGES CXX)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
project(
|
||||
EnTT
|
||||
VERSION ${ENTT_VERSION}
|
||||
DESCRIPTION "Gaming meets modern C++ - a fast and reliable entity-component system (ECS) and much more"
|
||||
HOMEPAGE_URL "https://github.com/skypjack/entt"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
set(SETTINGS_ORGANIZATION "Michele Caini")
|
||||
set(SETTINGS_APPLICATION ${PROJECT_NAME})
|
||||
set(PROJECT_AUTHOR "Michele Caini")
|
||||
set(PROJECT_AUTHOR_EMAIL "michele.caini@gmail.com")
|
||||
|
||||
message("*")
|
||||
message("* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||
message("* Copyright (c) 2017-2019 ${PROJECT_AUTHOR} <${PROJECT_AUTHOR_EMAIL}>")
|
||||
message("* Copyright (c) 2017-2020 Michele Caini <michele.caini@gmail.com>")
|
||||
message("*")
|
||||
|
||||
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
|
||||
@@ -66,37 +73,28 @@ endif()
|
||||
# Add EnTT target
|
||||
#
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
add_library(EnTT INTERFACE)
|
||||
add_library(EnTT::EnTT ALIAS EnTT)
|
||||
|
||||
configure_file(${EnTT_SOURCE_DIR}/cmake/in/version.h.in ${EnTT_SOURCE_DIR}/src/entt/config/version.h @ONLY)
|
||||
|
||||
target_include_directories(
|
||||
EnTT INTERFACE
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
EnTT
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
target_compile_definitions(
|
||||
EnTT
|
||||
INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:DEBUG>
|
||||
INTERFACE $<$<AND:$<CONFIG:Release>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:RELEASE>
|
||||
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 $<$<AND:$<CONFIG:Debug>,$<NOT:$<PLATFORM_ID:Windows>>>:-fsanitize=address -fno-omit-frame-pointer>)
|
||||
target_link_libraries(EnTT INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<PLATFORM_ID:Windows>>>:-fsanitize=address -fno-omit-frame-pointer>)
|
||||
endif()
|
||||
|
||||
if(USE_COMPILE_OPTIONS)
|
||||
target_compile_options(
|
||||
EnTT
|
||||
INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<PLATFORM_ID:Windows>>>:-O0 -g>
|
||||
# it seems that -O3 ruins a bit the performance when using clang ...
|
||||
INTERFACE $<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:Clang>,$<OR:$<PLATFORM_ID:Darwin>,$<PLATFORM_ID:Linux>>>:-O2>
|
||||
# ... on the other side, GCC is incredibly comfortable with it.
|
||||
INTERFACE $<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:GNU>>:-O3>
|
||||
)
|
||||
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>)
|
||||
endif()
|
||||
|
||||
if(HAS_LIBCPP)
|
||||
@@ -168,35 +166,11 @@ export(PACKAGE EnTT)
|
||||
option(BUILD_TESTING "Enable testing with ctest." OFF)
|
||||
|
||||
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)
|
||||
target_compile_features(gmock_main PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>)
|
||||
target_compile_features(gmock PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>)
|
||||
add_library(GTest::Main ALIAS gtest_main)
|
||||
endif()
|
||||
|
||||
option(BUILD_BENCHMARK "Build benchmark." OFF)
|
||||
option(BUILD_LIB "Build lib example." OFF)
|
||||
option(BUILD_MOD "Build mod example." OFF)
|
||||
option(BUILD_SNAPSHOT "Build snapshot example." OFF)
|
||||
|
||||
if(BUILD_MOD)
|
||||
enable_language(C)
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
@@ -219,16 +193,16 @@ endif()
|
||||
# AOB
|
||||
#
|
||||
|
||||
FILE(GLOB GH_WORKFLOWS .github/workflows/*.yml)
|
||||
|
||||
add_custom_target(
|
||||
entt_aob
|
||||
SOURCES
|
||||
${GH_WORKFLOWS}
|
||||
.github/FUNDING.yml
|
||||
AUTHORS
|
||||
CONTRIBUTING.md
|
||||
LICENSE
|
||||
README.md
|
||||
TODO
|
||||
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 ${AOB_SOURCES})
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2019 Michele Caini
|
||||
Copyright (c) 2017-2020 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
|
||||
|
||||
29
README.md
29
README.md
@@ -17,7 +17,9 @@ much more written in **modern C++**, mainly known for its innovative
|
||||
[Among others](https://github.com/skypjack/entt/wiki/EnTT-in-Action), it's used
|
||||
in [**Minecraft**](https://minecraft.net/en-us/attribution/) by Mojang and the
|
||||
[**ArcGIS Runtime SDKs**](https://developers.arcgis.com/arcgis-runtime/) by
|
||||
Esri. Open an issue or submit a PR if you don't see your project in the list!
|
||||
Esri.<br/>
|
||||
If you don't see your project in the list, please open an issue, submit a PR or
|
||||
add the [#entt](https://github.com/topics/entt) tag to your _topics_! :+1:
|
||||
|
||||
---
|
||||
|
||||
@@ -217,16 +219,9 @@ supports at least C++17.<br/>
|
||||
The requirements below are mandatory to compile the tests and to extract the
|
||||
documentation:
|
||||
|
||||
* `CMake` version 3.2 or later.
|
||||
* `CMake` version 3.7 or later.
|
||||
* `Doxygen` version 1.8 or later.
|
||||
|
||||
Alternatively, `Bazel` is also supported as a build system (credits to
|
||||
[zaucy](https://github.com/zaucy) who introduced what's required with
|
||||
[this](https://github.com/skypjack/entt/pull/291) pull request and 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
|
||||
@@ -269,8 +264,8 @@ The API reference will be created in HTML format within the directory
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
It's also available [online](https://skypjack.github.io/entt/) for the latest
|
||||
version.<br/>
|
||||
Finally, there exists a [wiki](https://github.com/skypjack/entt/wiki) dedicated
|
||||
version, that is the last stable tag.<br/>
|
||||
Moreover, there exists a [wiki](https://github.com/skypjack/entt/wiki) dedicated
|
||||
to the project where users can find all related documentation pages.
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
@@ -295,11 +290,11 @@ Note that benchmarks are not part of this set.
|
||||
|
||||
`EnTT` is available for some of the most known packaging tools. In particular:
|
||||
|
||||
* [`Conan`](https://bintray.com/skypjack/conan/entt%3Askypjack/_latestVersion),
|
||||
the C/C++ Package Manager for Developers.
|
||||
* [`Conan`](https://github.com/conan-io/conan-center-index), the C/C++ Package
|
||||
Manager for Developers.
|
||||
|
||||
* [`vcpkg`](https://github.com/Microsoft/vcpkg/tree/master/ports/entt),
|
||||
Microsoft VC++ Packaging Tool.<br/>
|
||||
* [`vcpkg`](https://github.com/Microsoft/vcpkg), Microsoft VC++ Packaging
|
||||
Tool.<br/>
|
||||
You can download and install `EnTT` in just a few simple steps:
|
||||
|
||||
```
|
||||
@@ -371,8 +366,8 @@ know who has participated so far.
|
||||
|
||||
# License
|
||||
|
||||
Code and documentation Copyright (c) 2017-2019 Michele Caini.<br/>
|
||||
Logo Copyright (c) 2018-2019 Richard Caseres.
|
||||
Code and documentation Copyright (c) 2017-2020 Michele Caini.<br/>
|
||||
Logo Copyright (c) 2018-2020 Richard Caseres.
|
||||
|
||||
Code released under
|
||||
[the MIT license](https://github.com/skypjack/entt/blob/master/LICENSE).
|
||||
|
||||
60
TODO
60
TODO
@@ -1,40 +1,28 @@
|
||||
* long term feature: templated generic vm
|
||||
* long term feature: shared_ptr less locator
|
||||
* long term feature: shared_ptr less resource cache
|
||||
* long term feature: shared_ptr less locator and resource cache
|
||||
* custom allocators and EnTT allocator-aware in general (long term feature, I don't actually need it at the moment) - see #22
|
||||
* debugging tools (#60): the issue online already contains interesting tips on this, look at it
|
||||
* runner proposal: https://en.wikipedia.org/wiki/Fork%E2%80%93join_model https://slide-rs.github.io/specs/03_dispatcher.html
|
||||
* work stealing job system (see #100)
|
||||
- mt scheduler based on const awareness for types
|
||||
* meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects
|
||||
* allow for built-in parallel each if possible
|
||||
* allow to replace std:: with custom implementations
|
||||
* remove runtime views, welcome reflection and what about snapshot?
|
||||
* types defined at runtime that refer to the same compile-time type (but to different pools) are possible, the library is almost there
|
||||
* work stealing job system (see #100) + mt scheduler based on const awareness for types
|
||||
* meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects (remove runtime views, welcome reflection)
|
||||
* add opaque input iterators to views and groups that return tuples <entity, T &...> (proxy), multi-pass guaranteed
|
||||
* add fast lane for raw iterations, extend mt doc to describe allowed add/remove with pre-allocations on fast lanes
|
||||
* registry.each<T...>(first, last) by iterators, entities/components guaranteed
|
||||
* built-in support for dual (or N-) buffering
|
||||
* allow for custom stomp functions
|
||||
* deprecate/replace snapshot
|
||||
* hibitset, views and non-owning groups
|
||||
* custom (decoupled) pools ==> double buffering, shared components, multi-model
|
||||
* snapshot rework/deprecation
|
||||
- create(hint: entity) -> force-create
|
||||
- assign<T...>(first, last)
|
||||
* use unordered_map for named pools and context variables:
|
||||
- use direct access (pool-like) also for context variables
|
||||
- allow for key/value variables where the key is an ENTT_ID_TYPE
|
||||
- improves multi-stomp
|
||||
* multi component registry::remove and some others?
|
||||
- auto foo(It first, It last = entity_type{null})
|
||||
* range based registry::remove and some others?
|
||||
* allow to replace std:: with custom implementations
|
||||
* custom (decoupled) pools ==> N-buffering, shared components, multi-model, hibitsets, and so on
|
||||
* add examples (and credits) from @alanjfs :)
|
||||
* explore the possibility to wrap other backend with a XHandler component
|
||||
* use [[nodiscard]] consistently for safety purposes
|
||||
* static reflection, hint: template<> meta_type_t<Type>: meta_descriptor<name, func..., props..., etc...>
|
||||
* null support for entt::component
|
||||
* add ENTT_CUSTOM_NAMED_TYPE for custom names
|
||||
* Make another attempt to overcome named types
|
||||
* meta: members+class as fake functions, is it possible?
|
||||
* named types: almost-stable index optimization for direct access to pools, no more linear searches
|
||||
* 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?
|
||||
* document undocumented parts (entt::overload and a few others)
|
||||
* 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)
|
||||
|
||||
* WIP:
|
||||
- deprecate snapshot, loader, ...
|
||||
- provide documentation to describe alternatives
|
||||
|
||||
* WIP: snapshot rework/deprecation
|
||||
- remove snapshot/loader from registry, make them external (faster) tools
|
||||
- deprecate snapshot classes, update documentation to describe alternatives
|
||||
|
||||
41
WORKSPACE
41
WORKSPACE
@@ -1,41 +0,0 @@
|
||||
workspace(name = "com_github_skypjack_entt")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
strip_prefix = "googletest-release-1.8.1",
|
||||
url = "https://github.com/google/googletest/archive/release-1.8.1.tar.gz",
|
||||
sha256 = "9bf1fe5182a604b4135edc1a425ae356c9ad15e9b23f9f12a02e80184c3a249c",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "org_duktape",
|
||||
url = "https://duktape.org/duktape-2.4.0.tar.xz",
|
||||
strip_prefix = "duktape-2.4.0",
|
||||
sha256 = "86a89307d1633b5cedb2c6e56dc86e92679fc34b05be551722d8cc69ab0771fc",
|
||||
build_file_content = """
|
||||
cc_library(
|
||||
name = "duktape",
|
||||
visibility = ["//visibility:public"],
|
||||
strip_include_prefix = "src",
|
||||
hdrs = ["src/duktape.h", "src/duk_config.h"],
|
||||
srcs = ["src/duktape.c", "src/duktape.h", "src/duk_config.h"],
|
||||
)
|
||||
""",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "bazelregistry_cereal",
|
||||
strip_prefix = "cereal-8629f40d932d57c5337d4557327f6f22436211b7",
|
||||
url = "https://github.com/bazelregistry/cereal/archive/8629f40d932d57c5337d4557327f6f22436211b7.zip",
|
||||
sha256 = "c983a7a2e16b153c3de022a0818d2f4836e510a3fc3bea9d3703de79f58a90a6",
|
||||
)
|
||||
|
||||
# This is for bazelregistry_cereal
|
||||
http_archive(
|
||||
name = "bazelregistry_rapidjson",
|
||||
strip_prefix = "rapidjson-6b980984dacf689be8f65be823203b967c69da04",
|
||||
url = "https://github.com/bazelregistry/rapidjson/archive/6b980984dacf689be8f65be823203b967c69da04.zip",
|
||||
sha256 = "82187ba8de53bab3b4fb9e56d0bae81a96fa27a115e5a6ce14c70f0ef9338965",
|
||||
)
|
||||
@@ -1 +0,0 @@
|
||||
exports_files(["copts.bzl"], visibility = ["//:__subpackages__"])
|
||||
@@ -1,10 +0,0 @@
|
||||
_msvc_copts = ["/std:c++17"]
|
||||
_gcc_copts = ["-std=c++17"]
|
||||
|
||||
entt_copts = select({
|
||||
# Windows
|
||||
"@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,
|
||||
})
|
||||
@@ -1,20 +0,0 @@
|
||||
project(cereal-download NONE)
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(
|
||||
cereal
|
||||
GIT_REPOSITORY https://github.com/USCiLab/cereal.git
|
||||
GIT_TAG v1.2.2
|
||||
GIT_SHALLOW 1
|
||||
DOWNLOAD_DIR ${CEREAL_DEPS_DIR}
|
||||
TMP_DIR ${CEREAL_DEPS_DIR}/tmp
|
||||
STAMP_DIR ${CEREAL_DEPS_DIR}/stamp
|
||||
SOURCE_DIR ${CEREAL_DEPS_DIR}/src
|
||||
BINARY_DIR ${CEREAL_DEPS_DIR}/build
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@@ -1,20 +0,0 @@
|
||||
project(duktape-download NONE)
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(
|
||||
duktape
|
||||
GIT_REPOSITORY https://github.com/svaarala/duktape-releases.git
|
||||
GIT_TAG v2.2.0
|
||||
GIT_SHALLOW 1
|
||||
DOWNLOAD_DIR ${DUKTAPE_DEPS_DIR}
|
||||
TMP_DIR ${DUKTAPE_DEPS_DIR}/tmp
|
||||
STAMP_DIR ${DUKTAPE_DEPS_DIR}/stamp
|
||||
SOURCE_DIR ${DUKTAPE_DEPS_DIR}/src
|
||||
BINARY_DIR ${DUKTAPE_DEPS_DIR}/build
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@@ -1,20 +0,0 @@
|
||||
project(googletest-download NONE)
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
GIT_SHALLOW 1
|
||||
DOWNLOAD_DIR ${GOOGLETEST_DEPS_DIR}
|
||||
TMP_DIR ${GOOGLETEST_DEPS_DIR}/tmp
|
||||
STAMP_DIR ${GOOGLETEST_DEPS_DIR}/stamp
|
||||
SOURCE_DIR ${GOOGLETEST_DEPS_DIR}/src
|
||||
BINARY_DIR ${GOOGLETEST_DEPS_DIR}/build
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef ENTT_CONFIG_VERSION_H
|
||||
#define ENTT_CONFIG_VERSION_H
|
||||
|
||||
|
||||
#define ENTT_VERSION "@PROJECT_VERSION@"
|
||||
#define ENTT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
|
||||
#define ENTT_VERSION_MINOR @PROJECT_VERSION_MINOR@
|
||||
#define ENTT_VERSION_PATCH @PROJECT_VERSION_PATCH@
|
||||
|
||||
|
||||
#endif // ENTT_CONFIG_VERSION_H
|
||||
2
deps/.gitignore
vendored
2
deps/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -2,30 +2,38 @@
|
||||
# Doxygen configuration (documentation)
|
||||
#
|
||||
|
||||
set(DOXY_DEPS_DIRECTORY ${EnTT_SOURCE_DIR}/deps)
|
||||
set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src)
|
||||
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
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 doxy.in
|
||||
SOURCES ${DOC_SOURCES}
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY ${DOXY_OUTPUT_DIRECTORY}/html
|
||||
DESTINATION share/${PROJECT_NAME}-${PROJECT_VERSION}/
|
||||
)
|
||||
|
||||
FILE(GLOB MD_FILES md/*.md)
|
||||
|
||||
add_custom_target(
|
||||
docs_aob
|
||||
SOURCES
|
||||
dox/extra.dox
|
||||
${MD_FILES}
|
||||
)
|
||||
|
||||
226
docs/doxy.in
226
docs/doxy.in
@@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.8.13
|
||||
# Doxyfile 1.8.16
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project.
|
||||
@@ -17,11 +17,11 @@
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# This tag specifies the encoding used for all characters in the config file
|
||||
# that follow. The default is UTF-8 which is also the encoding used for all text
|
||||
# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
|
||||
# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
|
||||
# for the list of possible encodings.
|
||||
# This tag specifies the encoding used for all characters in the configuration
|
||||
# file that follow. The default is UTF-8 which is also the encoding used for all
|
||||
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
|
||||
# iconv built into libc) for the transcoding. See
|
||||
# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
|
||||
# The default value is: UTF-8.
|
||||
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
@@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all generated output in the proper direction.
|
||||
# Possible values are: None, LTR, RTL and Context.
|
||||
# The default value is: None.
|
||||
|
||||
OUTPUT_TEXT_DIRECTION = None
|
||||
|
||||
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
|
||||
# descriptions after the members that are listed in the file and class
|
||||
# documentation (similar to Javadoc). Set to NO to disable this.
|
||||
@@ -179,6 +187,16 @@ SHORT_NAMES = NO
|
||||
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
|
||||
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
|
||||
# such as
|
||||
# /***************
|
||||
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
|
||||
# Javadoc-style will behave just like regular comments and it will not be
|
||||
# interpreted by doxygen.
|
||||
# The default value is: NO.
|
||||
|
||||
JAVADOC_BANNER = NO
|
||||
|
||||
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
|
||||
# line (until the first dot) of a Qt-style comment as the brief description. If
|
||||
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
|
||||
@@ -226,7 +244,12 @@ TAB_SIZE = 4
|
||||
# will allow you to put the command \sideeffect (or @sideeffect) in the
|
||||
# documentation, which will result in a user-defined paragraph with heading
|
||||
# "Side Effects:". You can put \n's in the value part of an alias to insert
|
||||
# newlines.
|
||||
# newlines (in the resulting output). You can put ^^ in the value part of an
|
||||
# alias to insert a newline as if a physical newline was in the original file.
|
||||
# When you need a literal { or } or , in the value part of an alias you have to
|
||||
# escape them by means of a backslash (\), this can lead to conflicts with the
|
||||
# commands \{ and \} for these it is advised to use the version @{ and @} or use
|
||||
# a double escape (\\{ and \\})
|
||||
|
||||
ALIASES =
|
||||
|
||||
@@ -264,17 +287,26 @@ OPTIMIZE_FOR_FORTRAN = NO
|
||||
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
|
||||
# sources only. Doxygen will then generate output that is more tailored for that
|
||||
# language. For instance, namespaces will be presented as modules, types will be
|
||||
# separated into more groups, etc.
|
||||
# The default value is: NO.
|
||||
|
||||
OPTIMIZE_OUTPUT_SLICE = NO
|
||||
|
||||
# Doxygen selects the parser to use depending on the extension of the files it
|
||||
# parses. With this tag you can assign which parser to use for a given
|
||||
# extension. Doxygen has a built-in mapping, but you can override or extend it
|
||||
# using this tag. The format is ext=language, where ext is a file extension, and
|
||||
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
|
||||
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
|
||||
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
|
||||
# Fortran. In the later case the parser tries to guess whether the code is fixed
|
||||
# or free formatted code, this is the default for Fortran type files), VHDL. For
|
||||
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
|
||||
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
|
||||
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
|
||||
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
|
||||
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
|
||||
# tries to guess whether the code is fixed or free formatted code, this is the
|
||||
# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
|
||||
# .inc files as Fortran files (default is PHP), and .f files as C (default is
|
||||
# Fortran), use: inc=Fortran f=C.
|
||||
#
|
||||
# Note: For files without extension you can use no_extension as a placeholder.
|
||||
#
|
||||
@@ -285,7 +317,7 @@ EXTENSION_MAPPING =
|
||||
|
||||
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
||||
# according to the Markdown format, which allows for more readable
|
||||
# documentation. See http://daringfireball.net/projects/markdown/ for details.
|
||||
# documentation. See https://daringfireball.net/projects/markdown/ for details.
|
||||
# The output of markdown processing is further processed by doxygen, so you can
|
||||
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
|
||||
# case of backward compatibilities issues.
|
||||
@@ -297,10 +329,10 @@ MARKDOWN_SUPPORT = YES
|
||||
# to that level are automatically included in the table of contents, even if
|
||||
# they do not have an id attribute.
|
||||
# Note: This feature currently applies only to Markdown headings.
|
||||
# Minimum value: 0, maximum value: 99, default value: 0.
|
||||
# Minimum value: 0, maximum value: 99, default value: 5.
|
||||
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
|
||||
|
||||
TOC_INCLUDE_HEADINGS = 4
|
||||
TOC_INCLUDE_HEADINGS = 5
|
||||
|
||||
# When enabled doxygen tries to link words that correspond to documented
|
||||
# classes, or namespaces to their corresponding documentation. Such a link can
|
||||
@@ -327,7 +359,7 @@ BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
|
||||
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
|
||||
# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
|
||||
# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
|
||||
# will parse them like normal C++ but will assume all classes use public instead
|
||||
# of private inheritance when no explicit protection keyword is present.
|
||||
# The default value is: NO.
|
||||
@@ -433,6 +465,12 @@ EXTRACT_ALL = NO
|
||||
|
||||
EXTRACT_PRIVATE = NO
|
||||
|
||||
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
|
||||
# methods of a class will be included in the documentation.
|
||||
# The default value is: NO.
|
||||
|
||||
EXTRACT_PRIV_VIRTUAL = NO
|
||||
|
||||
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
|
||||
# scope will be included in the documentation.
|
||||
# The default value is: NO.
|
||||
@@ -511,7 +549,7 @@ INTERNAL_DOCS = NO
|
||||
# names in lower-case letters. If set to YES, upper-case letters are also
|
||||
# allowed. This is useful if you have classes or files whose names only differ
|
||||
# in case and if your file system supports case sensitive file names. Windows
|
||||
# and Mac users are advised to set this option to NO.
|
||||
# (including Cygwin) ands Mac users are advised to set this option to NO.
|
||||
# The default value is: system dependent.
|
||||
|
||||
CASE_SENSE_NAMES = YES
|
||||
@@ -698,7 +736,7 @@ LAYOUT_FILE =
|
||||
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
|
||||
# the reference definitions. This must be a list of .bib files. The .bib
|
||||
# extension is automatically appended if omitted. This requires the bibtex tool
|
||||
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
|
||||
# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
|
||||
# For LaTeX the style of the bibliography can be controlled using
|
||||
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
|
||||
# search path. See also \cite for info how to create references.
|
||||
@@ -743,7 +781,8 @@ WARN_IF_DOC_ERROR = YES
|
||||
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
|
||||
# are documented, but have no documentation for their parameters or return
|
||||
# value. If set to NO, doxygen will only warn about wrong or incomplete
|
||||
# parameter documentation, but not about the absence of documentation.
|
||||
# parameter documentation, but not about the absence of documentation. If
|
||||
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_NO_PARAMDOC = YES
|
||||
@@ -781,13 +820,13 @@ WARN_LOGFILE =
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = @DOXY_SOURCE_DIRECTORY@ \
|
||||
@DOXY_DOCS_DIRECTORY@ \
|
||||
@PROJECT_SOURCE_DIR@/README.md
|
||||
@DOXY_DOCS_DIRECTORY@ \
|
||||
@PROJECT_SOURCE_DIR@/README.md
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||
# documentation (see: http://www.gnu.org/software/libiconv) for the list of
|
||||
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
|
||||
# possible encodings.
|
||||
# The default value is: UTF-8.
|
||||
|
||||
@@ -805,7 +844,7 @@ INPUT_ENCODING = UTF-8
|
||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
|
||||
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
||||
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
|
||||
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
|
||||
|
||||
FILE_PATTERNS = *.h \
|
||||
*.hpp \
|
||||
@@ -825,7 +864,7 @@ RECURSIVE = YES
|
||||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE =
|
||||
EXCLUDE = @DOXY_DEPS_DIRECTORY@
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
@@ -963,7 +1002,7 @@ INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
|
||||
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
|
||||
# function all documented functions referencing it will be listed.
|
||||
# entity all documented functions referencing it will be listed.
|
||||
# The default value is: NO.
|
||||
|
||||
REFERENCED_BY_RELATION = NO
|
||||
@@ -995,12 +1034,12 @@ SOURCE_TOOLTIPS = YES
|
||||
# If the USE_HTAGS tag is set to YES then the references to source code will
|
||||
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
|
||||
# source browser. The htags tool is part of GNU's global source tagging system
|
||||
# (see http://www.gnu.org/software/global/global.html). You will need version
|
||||
# (see https://www.gnu.org/software/global/global.html). You will need version
|
||||
# 4.8.6 or higher.
|
||||
#
|
||||
# To use it do the following:
|
||||
# - Install the latest version of global
|
||||
# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
|
||||
# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
|
||||
# - Make sure the INPUT points to the root of the source tree
|
||||
# - Run doxygen as normal
|
||||
#
|
||||
@@ -1028,7 +1067,7 @@ VERBATIM_HEADERS = YES
|
||||
# rich C++ code for which doxygen's built-in parser lacks the necessary type
|
||||
# information.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# generated with the -Duse-libclang=ON option for CMake.
|
||||
# generated with the -Duse_libclang=ON option for CMake.
|
||||
# The default value is: NO.
|
||||
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
@@ -1041,6 +1080,16 @@ CLANG_ASSISTED_PARSING = NO
|
||||
|
||||
CLANG_OPTIONS =
|
||||
|
||||
# If clang assisted parsing is enabled you can provide the clang parser with the
|
||||
# path to the compilation database (see:
|
||||
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
|
||||
# were built. This is equivalent to specifying the "-p" option to a clang tool,
|
||||
# such as clang-check. These options will then be passed to the parser.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# generated with the -Duse_libclang=ON option for CMake.
|
||||
|
||||
CLANG_DATABASE_PATH =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -1159,7 +1208,7 @@ HTML_EXTRA_FILES =
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||
# will adjust the colors in the style sheet and background images according to
|
||||
# this color. Hue is specified as an angle on a colorwheel, see
|
||||
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
|
||||
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
|
||||
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
|
||||
# purple, and 360 is red again.
|
||||
# Minimum value: 0, maximum value: 359, default value: 220.
|
||||
@@ -1195,6 +1244,17 @@ HTML_COLORSTYLE_GAMMA = 80
|
||||
|
||||
HTML_TIMESTAMP = NO
|
||||
|
||||
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
||||
# documentation will contain a main index with vertical navigation menus that
|
||||
# are dynamically created via Javascript. If disabled, the navigation index will
|
||||
# consists of multiple levels of tabs that are statically embedded in every HTML
|
||||
# page. Disable this option to support browsers that do not have Javascript,
|
||||
# like the Qt help browser.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_DYNAMIC_MENUS = YES
|
||||
|
||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||
# documentation will contain sections that can be hidden and shown after the
|
||||
# page has loaded.
|
||||
@@ -1218,13 +1278,13 @@ HTML_INDEX_NUM_ENTRIES = 100
|
||||
|
||||
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
|
||||
# generated that can be used as input for Apple's Xcode 3 integrated development
|
||||
# environment (see: http://developer.apple.com/tools/xcode/), introduced with
|
||||
# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
|
||||
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
|
||||
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
|
||||
# Makefile in the HTML output directory. Running make will produce the docset in
|
||||
# that directory and running make install will install the docset in
|
||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
|
||||
# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
|
||||
# for more information.
|
||||
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
|
||||
# genXcode/_index.html for more information.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
@@ -1263,7 +1323,7 @@ DOCSET_PUBLISHER_NAME = Publisher
|
||||
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
|
||||
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
|
||||
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
|
||||
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
|
||||
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
|
||||
# Windows.
|
||||
#
|
||||
# The HTML Help Workshop contains a compiler that can convert all HTML output
|
||||
@@ -1339,7 +1399,7 @@ QCH_FILE =
|
||||
|
||||
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
|
||||
# Project output. For more information please see Qt Help Project / Namespace
|
||||
# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
|
||||
# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
||||
# The default value is: org.doxygen.Project.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1347,7 +1407,7 @@ QHP_NAMESPACE = org.doxygen.Project
|
||||
|
||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
|
||||
# Help Project output. For more information please see Qt Help Project / Virtual
|
||||
# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
|
||||
# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
|
||||
# folders).
|
||||
# The default value is: doc.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
@@ -1356,7 +1416,7 @@ QHP_VIRTUAL_FOLDER = doc
|
||||
|
||||
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
|
||||
# filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
|
||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1364,7 +1424,7 @@ QHP_CUST_FILTER_NAME =
|
||||
|
||||
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
|
||||
# custom filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
|
||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1372,7 +1432,7 @@ QHP_CUST_FILTER_ATTRS =
|
||||
|
||||
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
|
||||
# project's filter section matches. Qt Help Project / Filter Attributes (see:
|
||||
# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
@@ -1465,7 +1525,7 @@ EXT_LINKS_IN_WINDOW = NO
|
||||
|
||||
FORMULA_FONTSIZE = 10
|
||||
|
||||
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
|
||||
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
|
||||
# generated for formulas are transparent PNGs. Transparent PNGs are not
|
||||
# supported properly for IE 6.0, but are supported on all modern browsers.
|
||||
#
|
||||
@@ -1477,7 +1537,7 @@ FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
|
||||
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
|
||||
# http://www.mathjax.org) which uses client side Javascript for the rendering
|
||||
# https://www.mathjax.org) which uses client side Javascript for the rendering
|
||||
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
|
||||
# installed or if you want to formulas look prettier in the HTML output. When
|
||||
# enabled you may also need to install MathJax separately and configure the path
|
||||
@@ -1504,11 +1564,11 @@ MATHJAX_FORMAT = HTML-CSS
|
||||
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
|
||||
# Content Delivery Network so you can quickly see the result without installing
|
||||
# MathJax. However, it is strongly recommended to install a local copy of
|
||||
# MathJax from http://www.mathjax.org before deployment.
|
||||
# The default value is: http://cdn.mathjax.org/mathjax/latest.
|
||||
# MathJax from https://www.mathjax.org before deployment.
|
||||
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
||||
MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/
|
||||
|
||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
||||
# extension names that should be enabled during MathJax rendering. For example
|
||||
@@ -1566,7 +1626,7 @@ SERVER_BASED_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: http://xapian.org/).
|
||||
# Xapian (see: https://xapian.org/).
|
||||
#
|
||||
# See the section "External Indexing and Searching" for details.
|
||||
# The default value is: NO.
|
||||
@@ -1579,7 +1639,7 @@ EXTERNAL_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: http://xapian.org/). See the section "External Indexing and
|
||||
# Xapian (see: https://xapian.org/). See the section "External Indexing and
|
||||
# Searching" for details.
|
||||
# This tag requires that the tag SEARCHENGINE is set to YES.
|
||||
|
||||
@@ -1631,21 +1691,35 @@ LATEX_OUTPUT = latex
|
||||
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
||||
# invoked.
|
||||
#
|
||||
# Note that when enabling USE_PDFLATEX this option is only used for generating
|
||||
# bitmaps for formulas in the HTML output, but not in the Makefile that is
|
||||
# written to the output directory.
|
||||
# The default file is: latex.
|
||||
# Note that when not enabling USE_PDFLATEX the default is latex when enabling
|
||||
# USE_PDFLATEX the default is pdflatex and when in the later case latex is
|
||||
# chosen this is overwritten by pdflatex. For specific output languages the
|
||||
# default can have been set differently, this depends on the implementation of
|
||||
# the output language.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_CMD_NAME = latex
|
||||
LATEX_CMD_NAME =
|
||||
|
||||
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
|
||||
# index for LaTeX.
|
||||
# Note: This tag is used in the Makefile / make.bat.
|
||||
# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
|
||||
# (.tex).
|
||||
# The default file is: makeindex.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
|
||||
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
|
||||
# generate index for LaTeX. In case there is no backslash (\) as first character
|
||||
# it will be automatically added in the LaTeX code.
|
||||
# Note: This tag is used in the generated output file (.tex).
|
||||
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
|
||||
# The default value is: makeindex.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_MAKEINDEX_CMD = makeindex
|
||||
|
||||
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
|
||||
# documents. This may be useful for small projects and may help to save some
|
||||
# trees in general.
|
||||
@@ -1766,7 +1840,7 @@ LATEX_SOURCE_CODE = NO
|
||||
|
||||
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
|
||||
# bibliography, e.g. plainnat, or ieeetr. See
|
||||
# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
|
||||
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
|
||||
# The default value is: plain.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
@@ -1780,6 +1854,14 @@ LATEX_BIB_STYLE = plain
|
||||
|
||||
LATEX_TIMESTAMP = NO
|
||||
|
||||
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# path from which the emoji images will be read. If a relative path is entered,
|
||||
# it will be relative to the LATEX_OUTPUT directory. If left blank the
|
||||
# LATEX_OUTPUT directory will be used.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_EMOJI_DIRECTORY =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -1819,9 +1901,9 @@ COMPACT_RTF = NO
|
||||
|
||||
RTF_HYPERLINKS = NO
|
||||
|
||||
# Load stylesheet definitions from file. Syntax is similar to doxygen's config
|
||||
# file, i.e. a series of assignments. You only have to provide replacements,
|
||||
# missing definitions are set to their default value.
|
||||
# Load stylesheet definitions from file. Syntax is similar to doxygen's
|
||||
# configuration file, i.e. a series of assignments. You only have to provide
|
||||
# replacements, missing definitions are set to their default value.
|
||||
#
|
||||
# See also section "Doxygen usage" for information on how to generate the
|
||||
# default style sheet that doxygen normally uses.
|
||||
@@ -1830,8 +1912,8 @@ RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
|
||||
# Set optional variables used in the generation of an RTF document. Syntax is
|
||||
# similar to doxygen's config file. A template extensions file can be generated
|
||||
# using doxygen -e rtf extensionFile.
|
||||
# similar to doxygen's configuration file. A template extensions file can be
|
||||
# generated using doxygen -e rtf extensionFile.
|
||||
# This tag requires that the tag GENERATE_RTF is set to YES.
|
||||
|
||||
RTF_EXTENSIONS_FILE =
|
||||
@@ -1917,6 +1999,13 @@ XML_OUTPUT = xml
|
||||
|
||||
XML_PROGRAMLISTING = YES
|
||||
|
||||
# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
|
||||
# namespace members in file scope as well, matching the HTML output.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_XML is set to YES.
|
||||
|
||||
XML_NS_MEMB_FILE_SCOPE = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the DOCBOOK output
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -1949,9 +2038,9 @@ DOCBOOK_PROGRAMLISTING = NO
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
|
||||
# AutoGen Definitions (see http://autogen.sf.net) file that captures the
|
||||
# structure of the code including all documentation. Note that this feature is
|
||||
# still experimental and incomplete at the moment.
|
||||
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
|
||||
# the structure of the code including all documentation. Note that this feature
|
||||
# is still experimental and incomplete at the moment.
|
||||
# The default value is: NO.
|
||||
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
@@ -2118,12 +2207,6 @@ EXTERNAL_GROUPS = YES
|
||||
|
||||
EXTERNAL_PAGES = YES
|
||||
|
||||
# The PERL_PATH should be the absolute path and name of the perl script
|
||||
# interpreter (i.e. the result of 'which perl').
|
||||
# The default file (with absolute path) is: /usr/bin/perl.
|
||||
|
||||
PERL_PATH = /usr/bin/perl
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -2137,15 +2220,6 @@ PERL_PATH = /usr/bin/perl
|
||||
|
||||
CLASS_DIAGRAMS = YES
|
||||
|
||||
# You can define message sequence charts within doxygen comments using the \msc
|
||||
# command. Doxygen will then run the mscgen tool (see:
|
||||
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
|
||||
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
|
||||
# the mscgen tool resides. If left empty the tool is assumed to be found in the
|
||||
# default search path.
|
||||
|
||||
MSCGEN_PATH =
|
||||
|
||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||
# then run dia to produce the diagram and insert it in the documentation. The
|
||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||
|
||||
112
docs/md/core.md
112
docs/md/core.md
@@ -12,6 +12,11 @@
|
||||
* [Wide characters](wide-characters)
|
||||
* [Conflicts](#conflicts)
|
||||
* [Monostate](#monostate)
|
||||
* [Type info](#type-info)
|
||||
* [Almost unique identifiers](#almost-unique-identifiers)
|
||||
* [Traits](#traits)
|
||||
* [Member class type](#member-class-type)
|
||||
* [Tags](#tags)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
@@ -182,3 +187,110 @@ entt::monostate<"mykey"_hs>{} = 42;
|
||||
const bool b = entt::monostate<"mykey"_hs>{};
|
||||
const int i = entt::monostate<entt::hashed_string{"mykey"}>{};
|
||||
```
|
||||
|
||||
# Type info
|
||||
|
||||
The `type_info` class template is meant to provide some basic information about
|
||||
types of all kinds.<br/>
|
||||
Currently, the only information available is the numeric identifier associated
|
||||
with a given type:
|
||||
|
||||
```cpp
|
||||
auto id = entt::type_info<my_type>::id();
|
||||
```
|
||||
|
||||
In general, the `id` function is also `constexpr` but this isn't guaranteed for
|
||||
all compilers and platforms (although it's valid with the most well-known and
|
||||
popular compilers).<br/>
|
||||
This function **can** use non-standard features of the language for its own
|
||||
purposes. This allows it to provide compile-time identifiers that remain stable
|
||||
between different runs. However, it's possible to force the use of standard
|
||||
features only by defining the macro `ENTT_STANDARD_CPP`. In this case, there is
|
||||
no guarantee that the identifiers are stable across executions though. Moreover,
|
||||
identifiers are generated at runtime and are no longer a compile-time thing.
|
||||
|
||||
An external type system can also be used if needed. In fact, `type_info` can be
|
||||
specialized by type and is also _sfinae-friendly_ in order to allow more refined
|
||||
specializations such as:
|
||||
|
||||
```cpp
|
||||
template<typename Type>
|
||||
struct entt::type_info<Type, std::void_d<decltype(Type::custom_id())>> {
|
||||
static constexpr ENTT_ID_TYPE id() ENTT_NOEXCEPT {
|
||||
return Type::custom_id();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Note that this class template and its specializations are widely used within
|
||||
`EnTT`. It also plays a very important role in making `EnTT` work transparently
|
||||
across boundaries.<br/>
|
||||
Please refer to the dedicated section for more details.
|
||||
|
||||
## Almost unique identifiers
|
||||
|
||||
Since the default non-standard, compile-time implementation makes use of hashed
|
||||
strings, it may happen that two types are assigned the same numeric
|
||||
identifier.<br/>
|
||||
In fact, although this is quite rare, it's not entirely excluded.
|
||||
|
||||
Another case where two types are assigned the same identifier is when classes
|
||||
from different contexts (for example two or more libraries loaded at runtime)
|
||||
have the same fully qualified name.<br/>
|
||||
Since the default model is based on the name of the classes, if the types belong
|
||||
to the same namespace then their identifiers _could_ be identical (they won't
|
||||
necessarily be the same though).
|
||||
|
||||
Fortunately, there are several easy ways to deal with this:
|
||||
|
||||
* The most trivial one is to define the `ENTT_STANDARD_CPP` macro. Note that
|
||||
runtime identifiers don't suffer from the sam problem. However, this solution
|
||||
doesn't work well with a plugin system, where the libraries aren't linked.
|
||||
|
||||
* Another possibility is to specialize the `type_info` class for one of the
|
||||
conflicting types, in order to assign it a custom identifier. This is probably
|
||||
the easiest solution that also preserves the feature of the tool.
|
||||
|
||||
* A fully customized identifier generation policy (based for example on enum
|
||||
classes or preprocessing steps) may represent yet another option.
|
||||
|
||||
These are just some examples of possible approaches to the problem but there are
|
||||
many others. As already mentioned above, since users have full control over
|
||||
their types, this problem is in any case easy to solve and should not worry too
|
||||
much.<br/>
|
||||
In all likelihood, it will never happen to run into a conflict anyway.
|
||||
|
||||
# Traits
|
||||
|
||||
This section contains a handful of utilities and traits not present in the
|
||||
standard template library but which can be useful in everyday life.
|
||||
|
||||
## Member class type
|
||||
|
||||
The `auto` template parameter introduced with C++17 made it possible to simplify
|
||||
many class templates and template functions but also made the class type opaque
|
||||
when members are passed as template arguments.<br/>
|
||||
The purpose of this utility is to extract the class type in a few lines of code:
|
||||
|
||||
```cpp
|
||||
template<typename Member>
|
||||
using clazz = entt::member_class_t<Member>;
|
||||
```
|
||||
|
||||
## Tags
|
||||
|
||||
Since in `EnTT` the type identified by `ENTT_ID_TYPE` is very important and
|
||||
widely used, there is a more user-friendly shortcut for the creation of integral
|
||||
constants based on it.<br/>
|
||||
This shortcut is the alias template `entt::tag`.
|
||||
|
||||
If used in combination with hashed strings, it helps to use human-readable names
|
||||
where types would be required otherwise. As an example:
|
||||
|
||||
```cpp
|
||||
registry.assign<entt::tag<"enemy"_hs>>(entity);
|
||||
```
|
||||
|
||||
However, this isn't the only permitted use. Literally any value convertible to
|
||||
`ENTT_ID_TYPE` is a good candidate, such as the named constants of an unscoped
|
||||
enum.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,10 +50,15 @@ First of all, there are two things to do in a Windows project:
|
||||
* Set the [`_ITERATOR_DEBUG_LEVEL`](https://docs.microsoft.com/cpp/standard-library/iterator-debug-level)
|
||||
macro to 0. This will disable checked iterators and iterator debugging.
|
||||
|
||||
Moreover, the macro `ENTT_DISABLE_ASSERT` should be defined to disable internal
|
||||
checks made by `EnTT` in debug. These are asserts introduced to help the users,
|
||||
but require to access to the underlying containers and therefore risk ruining
|
||||
the performance in some cases.
|
||||
Moreover, the macro `ENTT_ASSERT` should be redefined to disable internal checks
|
||||
made by `EnTT` in debug:
|
||||
|
||||
```cpp
|
||||
#define ENTT_ASSERT(...) ((void)0)
|
||||
```
|
||||
|
||||
These asserts are introduced to help the users but they require to access to the
|
||||
underlying containers and therefore risk ruining the performance in some cases.
|
||||
|
||||
With these changes, debug performance should increase enough for most cases. If
|
||||
you want something more, you can can also switch to an optimization level `O0`
|
||||
@@ -127,13 +132,9 @@ here is a workaround in the form of a macro:
|
||||
|
||||
```cpp
|
||||
#if defined(_MSC_VER)
|
||||
#define HS(str)\
|
||||
__pragma(warning(push))\
|
||||
__pragma(warning(disable:4307))\
|
||||
entt::hashed_string{str}\
|
||||
__pragma(warning(pop))
|
||||
#define HS(str) __pragma(warning(suppress:4307)) entt::hashed_string{str}\
|
||||
#else
|
||||
#define HS(str) entt::hashed_string{str}
|
||||
#define HS(str) entt::hashed_string{str}
|
||||
#endif
|
||||
```
|
||||
|
||||
|
||||
213
docs/md/lib.md
213
docs/md/lib.md
@@ -6,12 +6,9 @@
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Named types and traits class](#named-types-and-traits-class)
|
||||
* [Do not mix types](#do-not-mix-types)
|
||||
* [Macros, macros everywhere](#macros-macros-everywhere)
|
||||
* [Conflicts](#conflicts)
|
||||
* [Runtime reflection system](#runtime-reflection-system)
|
||||
* [Allocations: the dark side of the force](#allocations-the-dark-side-of-the-force)
|
||||
* [The EnTT way](#the-entt-way)
|
||||
* [Meta context](#meta-context)
|
||||
* [Memory management](#memory-management)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
@@ -19,178 +16,88 @@
|
||||
# Introduction
|
||||
|
||||
`EnTT` has historically had a limit when used across boundaries on Windows in
|
||||
general and on GNU/Linux when default visibility was set to _hidden_. The
|
||||
limitation is due mainly to a custom utility used to assign unique, sequential
|
||||
identifiers to different types. Unfortunately, this tool is used by several core
|
||||
classes (the `registry` among the others) that are thus almost unusable across
|
||||
boundaries.<br/>
|
||||
The reasons for that are beyond the purposes of this document. However, the good
|
||||
news is that `EnTT` also offers now a way to overcome this limit and to push
|
||||
things across boundaries without problems when needed.
|
||||
general and on GNU/Linux when default visibility was set to hidden. The
|
||||
limitation was mainly due to a custom utility used to assign unique, sequential
|
||||
identifiers to different types.<br/>
|
||||
Fortunately, nowadays using `EnTT` across boundaries is straightforward. In
|
||||
fact, everything just works transparently in almost all cases. There are only a
|
||||
few exceptions, easy to deal with anyway.
|
||||
|
||||
# Named types and traits class
|
||||
# The EnTT way
|
||||
|
||||
To allow a type to work properly across boundaries when used by a class that
|
||||
requires to assign unique identifiers to types, users must specialize a class
|
||||
template to literally give a compile-time name to the type itself.<br/>
|
||||
The name of the class template is `name_type_traits` and the specialization must
|
||||
be such that it exposes a static constexpr data member named `value` having type
|
||||
either `ENTT_ID_TYPE` or `entt::hashed_string::hash_type`. Its value is the user
|
||||
defined unique identifier assigned to the specific type.<br/>
|
||||
Identifiers are not to be sequentially generated in this case.
|
||||
Many classes in `EnTT` make extensive use of type erasure for their purposes.
|
||||
This isn't a problem in itself (in fact, it's the basis of an API so convenient
|
||||
to use). However, a way is needed to recognize the objects whose type has been
|
||||
erased on the other side of a boundary.<br/>
|
||||
The `type_info` class template is how identifiers are generated and thus made
|
||||
available to the rest of the library.
|
||||
|
||||
As an example:
|
||||
In general, this class doesn't arouse much interest. The only exception is in
|
||||
case of conflicts between identifiers (definitely uncommon though) or where the
|
||||
default solution proposed by `EnTT` isn't suitable for the user's purposes.<br/>
|
||||
The section dedicated to this core class contains all the details to get around
|
||||
the problem in a concise and elegant way. Please refer to the specific
|
||||
documentation.
|
||||
|
||||
```cpp
|
||||
struct my_type { /* ... */ };
|
||||
|
||||
template<>
|
||||
struct entt::named_type_traits<my_type> {
|
||||
static constexpr auto value = "my_type"_hs;
|
||||
};
|
||||
```
|
||||
|
||||
Because of the rules of the language, the specialization must reside in the
|
||||
global namespace or in the `entt` namespace. There is no way to change this rule
|
||||
unfortunately, because it doesn't depend on the library itself.
|
||||
|
||||
The good aspect of this approach is that it's not intrusive at all. The other
|
||||
way around was in fact forcing users to inherit all their classes from a common
|
||||
base. Something to avoid, at least from my point of view.<br/>
|
||||
However, despite the fact that it's not intrusive, it would be great if it was
|
||||
also easier to use and a bit less error-prone. This is why a bunch of macros
|
||||
exist to ease defining named types.
|
||||
|
||||
## Do not mix types
|
||||
|
||||
Someone might think that this trick is valid only for the types to push across
|
||||
boundaries. This isn't how things work. In fact, the problem is more complex
|
||||
than that.<br/>
|
||||
As a rule of thumb, users should never mix named and non-named types. Whenever
|
||||
a type is given a name, all the types must be given a name. As an example,
|
||||
consider the `registry` class template: in case it is pushed across boundaries,
|
||||
all the types of components should be assigned a name to avoid subtle bugs.
|
||||
|
||||
Indeed, this constraint can be relaxed in many cases. However, it is difficult
|
||||
to define a general rule to follow that is not the most stringent, unless users
|
||||
know exactly what they are doing. Therefore, I won't elaborate on giving further
|
||||
details on the topic.
|
||||
|
||||
# Macros, macros everywhere
|
||||
|
||||
The library comes with a set of predefined macros to use to declare named types
|
||||
or export already existing ones. In particular:
|
||||
|
||||
* `ENTT_NAMED_TYPE` can be used to assign a name to already existing types. This
|
||||
macro must be used in the global namespace even when the types to be named are
|
||||
not.
|
||||
|
||||
```cpp
|
||||
ENTT_NAMED_TYPE(my_type)
|
||||
ENTT_NAMED_TYPE(ns::another_type)
|
||||
```
|
||||
|
||||
* `ENTT_NAMED_STRUCT` can be used to define and export a struct at the same
|
||||
time. It accepts also an optional namespace in which to define the given type.
|
||||
This macro must be used in the global namespace.
|
||||
|
||||
```cpp
|
||||
ENTT_NAMED_STRUCT(my_type, { /* struct definition */})
|
||||
ENTT_NAMED_STRUCT(ns, another_type, { /* struct definition */})
|
||||
```
|
||||
|
||||
* `ENTT_NAMED_CLASS` can be used to define and export a class at the same
|
||||
time. It accepts also an optional namespace in which to define the given type.
|
||||
This macro must be used in the global namespace.
|
||||
|
||||
```cpp
|
||||
ENTT_NAMED_CLASS(my_type, { /* class definition */})
|
||||
ENTT_NAMED_CLASS(ns, another_type, { /* class definition */})
|
||||
```
|
||||
|
||||
Nested namespaces are supported out of the box as well in all cases. As an
|
||||
example:
|
||||
|
||||
```cpp
|
||||
ENTT_NAMED_STRUCT(nested::ns, my_type, { /* struct definition */})
|
||||
```
|
||||
|
||||
These macros can be used to avoid specializing the `named_type_traits` class
|
||||
template. In all cases, the name of the class is used also as a seed to generate
|
||||
the compile-time unique identifier.
|
||||
|
||||
## Conflicts
|
||||
|
||||
When using macros, unique identifiers are 32/64 bit integers generated by
|
||||
hashing strings during compilation. Therefore, conflicts are rare but still
|
||||
possible. In case of conflicts, everything simply will get broken at runtime and
|
||||
the strangest things will probably take place.<br/>
|
||||
Unfortunately, there is no safe way to prevent it. If this happens, it will be
|
||||
enough to give a different value to one of the conflicting types to solve the
|
||||
problem. To do this, users can either assign a different name to the class or
|
||||
directly define a specialization for the `named_type_traits` class template.
|
||||
|
||||
# Runtime reflection system
|
||||
# Meta context
|
||||
|
||||
The runtime reflection system deserves a special mention when it comes to using
|
||||
it across boundaries.<br/>
|
||||
As in all other cases, it's necessary to give a name to the types. However, this
|
||||
time this isn't enough to get the job done.
|
||||
Since it's linked to a static context to which the visible components are
|
||||
attached and different contexts don't relate to each other, they must be
|
||||
_shared_ to allow the use of meta types across boundaries.
|
||||
|
||||
The runtime reflection system is linked to a static context to which the visible
|
||||
components are linked. A component is visible when it's given a name, so the
|
||||
named components are implicitly visible.<br/>
|
||||
Different contexts don't relate to each other. Therefore, to allow the use of
|
||||
named types across boundaries, a context must also be shared.
|
||||
Sharing a context is trivial though. First of all, the local one must be
|
||||
acquired in the main space:
|
||||
|
||||
Sharing a context is straightforward. First of all, the local one must be
|
||||
acquired:
|
||||
|
||||
```
|
||||
```cpp
|
||||
entt::meta_ctx ctx{};
|
||||
```
|
||||
|
||||
Then, it must be pushed across boundaries and the receiving space must set it as
|
||||
its global context, thus releasing the local one that remains available but is
|
||||
no longer referred to by the runtime reflection system:
|
||||
Then, it must passed to the receiving space that will set it as its global
|
||||
context, thus releasing the local one that remains available but is no longer
|
||||
referred to by the runtime reflection system:
|
||||
|
||||
```
|
||||
```cpp
|
||||
entt::meta_ctx::bind(ctx);
|
||||
```
|
||||
|
||||
From now on, both spaces will refer to the same context and on it will be
|
||||
associated the new visible meta types, no matter _where_ they are created.
|
||||
|
||||
attached the new visible meta types, no matter where they are created.<br/>
|
||||
A context can also be reset and then associated again locally as:
|
||||
|
||||
```
|
||||
```cpp
|
||||
entt::meta_ctx::bind{entt::meta_ctx{});
|
||||
```
|
||||
|
||||
This is allowed because local and global contexts are separated. Therefore, it's
|
||||
always possible to make the local context the current one again.
|
||||
|
||||
# Allocations: the dark side of the force
|
||||
Before to release a context, all locally registered types should be reset to
|
||||
avoid dangling references. Otherwise, if a type is accessed from another space
|
||||
by name, there could be an attempt to address its parts that are no longer
|
||||
available.
|
||||
|
||||
As long as `EnTT` won't support custom allocators, another problem with
|
||||
allocations will remain alive instead. This is in fact easily solved, or at
|
||||
least it is if one knows it.
|
||||
# Memory Management
|
||||
|
||||
To allow users to add types dynamically, the library makes extensive use of type
|
||||
erasure techniques and dynamic allocations for pools (whether they are for
|
||||
components, events or anything else). The problem occurs when, for example, a
|
||||
registry is created on one side of a boundary and a pool is dynamically created
|
||||
on the other side. In the best case, everything will crash at the exit, while at
|
||||
worst it will do so at runtime.<br/>
|
||||
To avoid problems, the pools must be generated from the same side of the
|
||||
boundary where the object that owns them is also created. As an example, when
|
||||
the registry is created in the main executable and used across boundaries for a
|
||||
given type of component, the pool for that type must be created before passing
|
||||
around the registry itself. To do this is fortunately quite easy, since it is
|
||||
sufficient to invoke any of the methods that involve the given type (continuing
|
||||
the example with the registry, a call to `reserve` or `size` is more than
|
||||
enough).
|
||||
There is another subtle problem due to memory management that can lead to
|
||||
headaches.<br/>
|
||||
It can occur where there are pools of objects (such as components or events)
|
||||
dynamically created on demand. This is usually not a problem when working with
|
||||
linked libraries that rely on the same dynamic runtime. However, it can occur in
|
||||
the case of plugins or statically linked runtimes.
|
||||
|
||||
Maybe one day some dedicated methods will be added that do nothing but create a
|
||||
pool for a given type. Until now it has been preferred to keep the API cleaner
|
||||
as they are not strictly necessary.
|
||||
As an example, imagine creating an instance of `registry` in the main executable
|
||||
and sharing it with a plugin. If the latter starts working with a component that
|
||||
is unknown to the former, a dedicated pool is created within the registry on
|
||||
first use.<br/>
|
||||
As one can guess, this pool is instantiated on a different side of the boundary
|
||||
from the `registry`. Therefore, the instance is now managing memory from
|
||||
different spaces and this can quickly lead to crashes if not properly addressed.
|
||||
|
||||
To overcome the risk, it's recommended to use well-defined interfaces that make
|
||||
fundamental types pass through the boundaries, isolating the instances of the
|
||||
`EnTT` classes from time to time and as appropriate.<br/>
|
||||
Refer to the test suite for some examples, read the documentation available
|
||||
online about this type of issues or consult someone who has already had such
|
||||
experiences to avoid problems.
|
||||
|
||||
@@ -46,9 +46,15 @@ I hope this list can grow much more in the future:
|
||||
made in C++ with the `SDL2` and `EnTT` libraries.
|
||||
* [Mirrors lasers and robots](https://github.com/guillaume-haerinck/imac-tower-defense):
|
||||
a small tower defense game based on mirror orientation.
|
||||
* [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead/): 2D, Zombie,
|
||||
RPG game made from scratch in C++.
|
||||
* [Robotligan](https://github.com/Trisslotten/robotligan): multiplayer
|
||||
football game.
|
||||
* [DungeonSlayer](https://github.com/alohaeee/DungeonSlayer): 2D game made
|
||||
from scratch in C++.
|
||||
|
||||
* Engines and the like:
|
||||
* [Fling Engine](https://github.com/flingengine/FlingEngine): A Vulkan game
|
||||
* [Fling Engine](https://github.com/flingengine/FlingEngine): a Vulkan game
|
||||
engine with a focus on data oriented design.
|
||||
* [Apparently](https://teamwisp.github.io/credits/)
|
||||
[Wisp](https://teamwisp.github.io/product/) by
|
||||
@@ -60,12 +66,16 @@ I hope this list can grow much more in the future:
|
||||
[Qub3d](https://qub3d.org/): because blocks should be open source.
|
||||
* [shiva](https://github.com/Milerius/shiva): modern C++ engine with
|
||||
modularity.
|
||||
* [NovusCore](https://github.com/novuscore/NovusCore): A modern take on World
|
||||
* [NovusCore](https://github.com/novuscore/NovusCore): a modern take on World
|
||||
of Warcraft emulation.
|
||||
* [ImGui/EnTT editor](https://github.com/Green-Sky/imgui_entt_entity_editor):
|
||||
A drop-in, single-file entity editor for `EnTT` that uses `ImGui` as
|
||||
a drop-in, single-file entity editor for `EnTT` that uses `ImGui` as
|
||||
graphical backend (with
|
||||
[demo code](https://github.com/Green-Sky/imgui_entt_entity_editor_demo)).
|
||||
* [SgOgl](https://github.com/stwe/SgOgl): a game engine library for OpenGL
|
||||
developed for educational purposes.
|
||||
* [Lumos](https://github.com/jmorton06/Lumos): game engine written in C++
|
||||
using OpenGL and Vulkan.
|
||||
|
||||
* Articles and blog posts:
|
||||
* [Some posts](https://skypjack.github.io/tags/#entt) on my personal
|
||||
@@ -92,6 +102,8 @@ I hope this list can grow much more in the future:
|
||||
[Collector](https://play.google.com/store/apps/details?id=com.esri.arcgis.collector)
|
||||
and
|
||||
[Navigator](https://play.google.com/store/apps/details?id=com.esri.navigator).
|
||||
* [Sequentity](https://github.com/alanjfs/sequentity): A MIDI-like
|
||||
sequencer/tracker for C++ and `ImGui` (with `Magnum` and `EnTT`).
|
||||
* [Apparently](https://www.linkedin.com/in/skypjack/)
|
||||
[NIO](https://www.nio.io/): there was a collaboration to make some changes
|
||||
to `EnTT`, at the time used for internal projects.
|
||||
@@ -99,10 +111,10 @@ I hope this list can grow much more in the future:
|
||||
[Tieto](https://www.tieto.com/): they published a job post where `EnTT` was
|
||||
listed on their software stack.
|
||||
* [Godot meets EnTT](https://github.com/portaloffreedom/godot_entt_example/):
|
||||
A simple example on how to use `EnTT` within
|
||||
a simple example on how to use `EnTT` within
|
||||
[`Godot`](https://godotengine.org/).
|
||||
* [Godot and GameNetworkingSockets meet EnTT](https://github.com/portaloffreedom/godot_entt_net_example):
|
||||
A simple example on how to use `EnTT` and
|
||||
a simple example on how to use `EnTT` and
|
||||
[`GameNetworkingSockets`](https://github.com/ValveSoftware/GameNetworkingSockets)
|
||||
within [`Godot`](https://godotengine.org/).
|
||||
* [MatchOneEntt](https://github.com/mhaemmerle/MatchOneEntt): port of
|
||||
|
||||
@@ -32,7 +32,7 @@ which it belongs and not vice versa.
|
||||
|
||||
# Names and identifiers
|
||||
|
||||
The meta system doesn't force the user to use the tools provided by the library
|
||||
The meta system doesn't force users to rely on the tools provided by the library
|
||||
when it comes to working with names and identifiers. It does this by offering an
|
||||
API that works with opaque identifiers that may or may not be generated by means
|
||||
of a hashed string.<br/>
|
||||
@@ -227,12 +227,27 @@ entt::meta_any any{std::ref(value)};
|
||||
In other words, whenever `meta_any` intercepts a `reference_wrapper`, it acts as
|
||||
a reference to the original instance rather than making a copy of it. The
|
||||
contained object is never destroyed and users must ensure that its lifetime
|
||||
exceeds that of the container.
|
||||
exceeds that of the container.<br/>
|
||||
Similarly, to create a copy that works as a light reference for the managed
|
||||
object, it's possible to dereference a given `meta_any`:
|
||||
|
||||
```cpp
|
||||
entt::meta_any ref = *any;
|
||||
```
|
||||
|
||||
It doesn't matter if the starting container actually holds an object or acts as
|
||||
a reference for unmanaged elements, the new instance thus created won't create
|
||||
copies and will only serve as a reference for the original item.<br/>
|
||||
It means that, starting from the example above, both `ref` and` any` will point
|
||||
to the same object, whether it's initially contained in `any` or already an
|
||||
unmanaged one. This is particularly useful for passing instances of `meta_any`
|
||||
belonging to the external context by reference to a function or a constructor
|
||||
rather than making copies of them.
|
||||
|
||||
The `meta_any` class has also a `type` member function that returns the meta
|
||||
type of the contained value, if any. The member functions `try_cast`, `cast` and
|
||||
`convert` are used to know if the underlying object has a given type as a base
|
||||
or if it can be converted implicitly to it.
|
||||
`convert` are then used to know if the underlying object has a given type as a
|
||||
base or if it can be converted implicitly to it.
|
||||
|
||||
## Enjoy the runtime
|
||||
|
||||
@@ -264,8 +279,8 @@ resolve([](auto type) {
|
||||
|
||||
In all cases, the returned value is an instance of `meta_type`. This kind of
|
||||
objects offer an API to know their _runtime identifiers_, to iterate all the
|
||||
meta objects associated with them and even to build or destroy instances of the
|
||||
underlying type.<br/>
|
||||
meta objects associated with them and even to build instances of the underlying
|
||||
type.<br/>
|
||||
Refer to the inline documentation for all the details.
|
||||
|
||||
The meta objects that compose a meta type are accessed in the following ways:
|
||||
@@ -279,20 +294,9 @@ The meta objects that compose a meta type are accessed in the following ways:
|
||||
The returned type is `meta_ctor` and may be invalid if there is no constructor
|
||||
that accepts the supplied arguments or at least some types from which they are
|
||||
derived or to which they can be converted.<br/>
|
||||
A meta constructor offers an API to know the number of arguments, the expected
|
||||
meta types and to invoke it, therefore to construct a new instance of the
|
||||
underlying type.
|
||||
|
||||
* _Meta destructor_. It's returned by a dedicated function:
|
||||
|
||||
```cpp
|
||||
auto dtor = entt::resolve<my_type>().dtor();
|
||||
```
|
||||
|
||||
The returned type is `meta_dtor` and may be invalid if there is no custom
|
||||
destructor set for the given meta type.<br/>
|
||||
All what a meta destructor has to offer is a way to invoke it on a given
|
||||
instance. Be aware that the result may not be what is expected.
|
||||
A meta constructor offers an API to know the number of its arguments and their
|
||||
expected meta types. Furthermor, it's possible to invoke it and therefore to
|
||||
construct new instances of the underlying type.
|
||||
|
||||
* _Meta data_. They are accessed by _name_:
|
||||
|
||||
@@ -354,9 +358,8 @@ if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
|
||||
}
|
||||
```
|
||||
|
||||
Furthermore, all meta objects with the exception of meta destructors can be
|
||||
iterated through an overload that accepts a callback through which to return
|
||||
them. As an example:
|
||||
Furthermore, all meta objects can be iterated through an overload that accepts a
|
||||
callback through which to return them. As an example:
|
||||
|
||||
```cpp
|
||||
entt::resolve<my_type>().data([](auto data) {
|
||||
@@ -364,17 +367,20 @@ entt::resolve<my_type>().data([](auto data) {
|
||||
});
|
||||
```
|
||||
|
||||
A meta type can also be used to `construct` or `destroy` actual instances of the
|
||||
underlying type.<br/>
|
||||
A meta type can be used to `construct` actual instances of the underlying
|
||||
type.<br/>
|
||||
In particular, the `construct` member function accepts a variable number of
|
||||
arguments and searches for a match. It returns a `meta_any` object that may or
|
||||
may not be initialized, depending on whether a suitable constructor has been
|
||||
found or not. On the other side, the `destroy` member function accepts instances
|
||||
of `meta_any` as well as actual objects by reference and invokes the registered
|
||||
destructor, if any.<br/>
|
||||
Be aware that the result of a call to `destroy` may not be what is expected. The
|
||||
purpose is to give users the ability to free up resources that require special
|
||||
treatment and **not** to actually destroy instances.
|
||||
arguments and searches for a match. It then returns a `meta_any` object that may
|
||||
or may not be initialized, depending on whether a suitable constructor has been
|
||||
found or not.
|
||||
|
||||
There is no object that wraps the destructor of a meta type nor a `destroy`
|
||||
member function in its API. The reason is quickly explained: destructors are
|
||||
invoked implicitly by `meta_any` behind the scenes and users have not to deal
|
||||
with them explicitly. Furthermore, they have no name, cannot be searched and
|
||||
wouldn't have member functions to expose anyway.<br/>
|
||||
Therefore, exposing destructors would be pointless and would add nothing to the
|
||||
library itself.
|
||||
|
||||
Meta types and meta objects in general contain much more than what is said: a
|
||||
plethora of functions in addition to those listed whose purposes and uses go
|
||||
@@ -417,10 +423,10 @@ There are a few alternatives available at the moment:
|
||||
```
|
||||
|
||||
* The _as-alias_ policy, associated with the type `entt::as_alias_t`.<br/>
|
||||
It allows to build wrappers that act as aliases for the objects used to
|
||||
initialize them. Modifying the object contained in the wrapper for which the
|
||||
_aliasing_ was requested will make it possible to directly modify the instance
|
||||
used to initialize the wrapper itself.<br/>
|
||||
It allows to build wrappers that act as aliases for the objects that generated
|
||||
them. Modifying the object contained in the wrapper for which the _aliasing_
|
||||
was requested will make it possible to directly modify the instance used to
|
||||
initialize the wrapper itself.<br/>
|
||||
This policy works with constructors (for example, when objects are taken from
|
||||
an external container rather than created on demand), data members and
|
||||
functions in general (as long as their return types are lvalue references).
|
||||
|
||||
@@ -74,6 +74,10 @@ Here is a minimal example for the sake of curiosity:
|
||||
struct my_process: entt::process<my_process, std::uint32_t> {
|
||||
using delta_type = std::uint32_t;
|
||||
|
||||
my_process(delta_type delay)
|
||||
: remaining{delay}
|
||||
{}
|
||||
|
||||
void update(delta_type delta, void *) {
|
||||
remaining -= std::min(remaining, delta);
|
||||
|
||||
@@ -85,7 +89,7 @@ struct my_process: entt::process<my_process, std::uint32_t> {
|
||||
}
|
||||
|
||||
private:
|
||||
delta_type remaining{1000u};
|
||||
delta_type remaining;
|
||||
};
|
||||
```
|
||||
|
||||
@@ -158,7 +162,7 @@ To attach a process to a scheduler there are mainly two ways:
|
||||
the `attach` member function:
|
||||
|
||||
```cpp
|
||||
scheduler.attach<my_process>("foobar");
|
||||
scheduler.attach<my_process>(1000u);
|
||||
```
|
||||
|
||||
* Otherwise, in case of a lambda or a functor, it's enough to provide an
|
||||
@@ -182,7 +186,7 @@ scheduler.attach([](auto delta, void *, auto succeed, auto fail) {
|
||||
// ...
|
||||
})
|
||||
// appends a child in the form of a process class
|
||||
.then<my_process>();
|
||||
.then<my_process>(1000u);
|
||||
```
|
||||
|
||||
To update a scheduler and therefore all its processes, the `update` member
|
||||
|
||||
@@ -37,7 +37,7 @@ lightweight classes to solve the same and many other problems.
|
||||
A delegate can be used as a general purpose invoker with no memory overhead for
|
||||
free functions and members provided along with an instance on which to invoke
|
||||
them.<br/>
|
||||
It does not claim to be a drop-in replacement for an `std::function`, so do not
|
||||
It doesn't claim to be a drop-in replacement for an `std::function`, so don't
|
||||
expect to use it whenever an `std::function` fits well. That said, it's most
|
||||
likely even a better fit than an `std::function` in a lot of cases, so expect to
|
||||
use it quite a lot anyway.
|
||||
@@ -79,9 +79,9 @@ function type of the delegate is such that the parameter list is empty and the
|
||||
value of the data member is at least convertible to the return type.
|
||||
|
||||
Free functions having type equivalent to `void(T &, args...)` are accepted as
|
||||
well. In this case, `T &` is considered a payload and the function will receive
|
||||
it back every time it's invoked. In other terms, this works just fine with the
|
||||
above definition:
|
||||
well. The first argument `T &` is considered a payload and the function will
|
||||
receive it back every time it's invoked. In other terms, this works just fine
|
||||
with the above definition:
|
||||
|
||||
```cpp
|
||||
void g(const char &c, int i) { /* ... */ }
|
||||
@@ -107,7 +107,7 @@ delegate(42);
|
||||
```
|
||||
|
||||
Where the function type of the delegate is `void(int)` as above. It goes without
|
||||
saying that the extra arguments are silently discarded internally.<br/>v
|
||||
saying that the extra arguments are silently discarded internally.<br/>
|
||||
This is a nice-to-have feature in a lot of cases, as an example when the
|
||||
`delegate` class is used as a building block of a signal-slot system.
|
||||
|
||||
@@ -142,6 +142,24 @@ delegate. As long as a listener can be invoked with the given arguments to yield
|
||||
a result that is convertible to the given result type, everything works just
|
||||
fine.
|
||||
|
||||
As a side note, note that members of a class may or may not be associated with
|
||||
instances. If they are not, the first argument of the function type must be that
|
||||
of the class on which the members operate and an instance of this class must
|
||||
obviously be passed when invoking the delegate:
|
||||
|
||||
```
|
||||
entt::delegate<void(my_struct &, int)> delegate;
|
||||
delegate.connect<&my_struct::f>();
|
||||
|
||||
my_struct instance;
|
||||
delegate(instance, 42);
|
||||
```
|
||||
|
||||
In this case, it's not possible to deduce the function type since the first
|
||||
argument doesn't necessarily have to be a reference (for example, it can be a
|
||||
pointer, as well as a const reference).<br/>
|
||||
Therefore, the function type must be declared explicitly for unbound members.
|
||||
|
||||
# Signals
|
||||
|
||||
Signal handlers work with references to classes, function pointers and pointers
|
||||
@@ -199,10 +217,10 @@ sink.disconnect<&foo>();
|
||||
// disconnect a member function of an instance
|
||||
sink.disconnect<&listener::bar>(instance);
|
||||
|
||||
// disconnect all the member functions of an instance, if any
|
||||
// disconnect all member functions of an instance, if any
|
||||
sink.disconnect(instance);
|
||||
|
||||
// discards all the listeners at once
|
||||
// discards all listeners at once
|
||||
sink.disconnect();
|
||||
```
|
||||
|
||||
|
||||
@@ -3,54 +3,65 @@
|
||||
|
||||
|
||||
#ifndef ENTT_NOEXCEPT
|
||||
#define ENTT_NOEXCEPT noexcept
|
||||
#endif // ENTT_NOEXCEPT
|
||||
# define ENTT_NOEXCEPT noexcept
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_HS_SUFFIX
|
||||
#define ENTT_HS_SUFFIX _hs
|
||||
#endif // ENTT_HS_SUFFIX
|
||||
# define ENTT_HS_SUFFIX _hs
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_HWS_SUFFIX
|
||||
#define ENTT_HWS_SUFFIX _hws
|
||||
#endif // ENTT_HWS_SUFFIX
|
||||
# define ENTT_HWS_SUFFIX _hws
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_NO_ATOMIC
|
||||
#include <atomic>
|
||||
#define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
||||
#else // ENTT_NO_ATOMIC
|
||||
#define ENTT_MAYBE_ATOMIC(Type) Type
|
||||
#endif // ENTT_NO_ATOMIC
|
||||
|
||||
|
||||
#ifndef ENTT_DISABLE_ETO
|
||||
#include <type_traits>
|
||||
#define ENTT_ENABLE_ETO(Type) std::is_empty_v<Type>
|
||||
#else // ENTT_DISABLE_ETO
|
||||
// sfinae-friendly definition
|
||||
#define ENTT_ENABLE_ETO(Type) (false && std::is_empty_v<Type>)
|
||||
#endif // ENTT_DISABLE_ETO
|
||||
#ifndef ENTT_USE_ATOMIC
|
||||
# define ENTT_MAYBE_ATOMIC(Type) Type
|
||||
#else
|
||||
# include <atomic>
|
||||
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_ID_TYPE
|
||||
#include <cstdint>
|
||||
#define ENTT_ID_TYPE std::uint32_t
|
||||
#endif // ENTT_ID_TYPE
|
||||
# include <cstdint>
|
||||
# define ENTT_ID_TYPE std::uint32_t
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_PAGE_SIZE
|
||||
#define ENTT_PAGE_SIZE 32768
|
||||
#endif // ENTT_PAGE_SIZE
|
||||
# define ENTT_PAGE_SIZE 32768
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_DISABLE_ASSERT
|
||||
#include <cassert>
|
||||
#define ENTT_ASSERT(condition) assert(condition)
|
||||
#else // ENTT_DISABLE_ASSERT
|
||||
#define ENTT_ASSERT(...) ((void)0)
|
||||
#endif // ENTT_DISABLE_ASSERT
|
||||
#ifndef ENTT_ASSERT
|
||||
# include <cassert>
|
||||
# define ENTT_ASSERT(condition) assert(condition)
|
||||
#endif
|
||||
|
||||
|
||||
#endif // ENTT_CONFIG_CONFIG_H
|
||||
#ifndef ENTT_DISABLE_ETO
|
||||
# include <type_traits>
|
||||
# define ENTT_ENABLE_ETO(Type) std::is_empty_v<Type>
|
||||
#else
|
||||
# // sfinae-friendly definition
|
||||
# define ENTT_ENABLE_ETO(Type) (false && std::is_empty_v<Type>)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_STANDARD_CPP
|
||||
# if defined _MSC_VER
|
||||
# define ENTT_PRETTY_FUNCTION __FUNCSIG__
|
||||
# define ENTT_PRETTY_FUNCTION_CONSTEXPR ENTT_PRETTY_FUNCTION
|
||||
# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8)
|
||||
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
# define ENTT_PRETTY_FUNCTION_CONSTEXPR ENTT_PRETTY_FUNCTION
|
||||
# elif defined __GNUC__
|
||||
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
#define ENTT_CONFIG_VERSION_H
|
||||
|
||||
|
||||
#define ENTT_VERSION "3.2.2"
|
||||
#define ENTT_VERSION_MAJOR 3
|
||||
#define ENTT_VERSION_MINOR 2
|
||||
#define ENTT_VERSION_PATCH 2
|
||||
#define ENTT_VERSION_MINOR 3
|
||||
#define ENTT_VERSION_PATCH 0
|
||||
|
||||
|
||||
#endif // ENTT_CONFIG_VERSION_H
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define ENTT_CORE_ALGORITHM_HPP
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
@@ -140,4 +141,4 @@ struct radix_sort {
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_CORE_ALGORITHM_HPP
|
||||
#endif
|
||||
|
||||
33
src/entt/core/attribute.h
Normal file
33
src/entt/core/attribute.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef ENTT_CORE_ATTRIBUTE_H
|
||||
#define ENTT_CORE_ATTRIBUTE_H
|
||||
|
||||
|
||||
#ifndef ENTT_EXPORT
|
||||
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
|
||||
# define ENTT_EXPORT __declspec(dllexport)
|
||||
# define ENTT_IMPORT __declspec(dllimport)
|
||||
# define ENTT_HIDDEN
|
||||
# elif defined __GNUC__ && __GNUC__ >= 4
|
||||
# define ENTT_EXPORT __attribute__((visibility("default")))
|
||||
# define ENTT_IMPORT __attribute__((visibility("default")))
|
||||
# define ENTT_HIDDEN __attribute__((visibility("hidden")))
|
||||
# else /* Unsupported compiler */
|
||||
# define ENTT_EXPORT
|
||||
# define ENTT_IMPORT
|
||||
# define ENTT_HIDDEN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_API
|
||||
# if defined ENTT_API_EXPORT
|
||||
# define ENTT_API ENTT_EXPORT
|
||||
# elif defined ENTT_API_IMPORT
|
||||
# define ENTT_API ENTT_IMPORT
|
||||
# else /* No API */
|
||||
# define ENTT_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,6 @@
|
||||
#define ENTT_CORE_FAMILY_HPP
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
@@ -34,4 +33,4 @@ public:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_CORE_FAMILY_HPP
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
@@ -24,6 +25,7 @@ struct fnv1a_traits;
|
||||
|
||||
template<>
|
||||
struct fnv1a_traits<std::uint32_t> {
|
||||
using type = std::uint32_t;
|
||||
static constexpr std::uint32_t offset = 2166136261;
|
||||
static constexpr std::uint32_t prime = 16777619;
|
||||
};
|
||||
@@ -31,6 +33,7 @@ struct fnv1a_traits<std::uint32_t> {
|
||||
|
||||
template<>
|
||||
struct fnv1a_traits<std::uint64_t> {
|
||||
using type = std::uint64_t;
|
||||
static constexpr std::uint64_t offset = 14695981039346656037ull;
|
||||
static constexpr std::uint64_t prime = 1099511628211ull;
|
||||
};
|
||||
@@ -67,8 +70,14 @@ class basic_hashed_string {
|
||||
};
|
||||
|
||||
// Fowler–Noll–Vo hash function v. 1a - the good
|
||||
static constexpr ENTT_ID_TYPE helper(ENTT_ID_TYPE partial, const Char *curr) ENTT_NOEXCEPT {
|
||||
return curr[0] == 0 ? partial : helper((partial^curr[0])*traits_type::prime, curr+1);
|
||||
static constexpr ENTT_ID_TYPE helper(const Char *curr) ENTT_NOEXCEPT {
|
||||
auto value = traits_type::offset;
|
||||
|
||||
while(*curr != 0) {
|
||||
value = (value ^ static_cast<traits_type::type>(*(curr++))) * traits_type::prime;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -93,8 +102,8 @@ public:
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
static constexpr hash_type to_value(const value_type (&str)[N]) ENTT_NOEXCEPT {
|
||||
return helper(traits_type::offset, str);
|
||||
static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT {
|
||||
return helper(str);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,8 +111,8 @@ public:
|
||||
* @param wrapper Helps achieving the purpose by relying on overloading.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
static hash_type to_value(const_wrapper wrapper) ENTT_NOEXCEPT {
|
||||
return helper(traits_type::offset, wrapper.str);
|
||||
static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT {
|
||||
return helper(wrapper.str);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +121,7 @@ public:
|
||||
* @param size Length of the string to hash.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
static hash_type to_value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
|
||||
static hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
|
||||
ENTT_ID_TYPE partial{traits_type::offset};
|
||||
while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
|
||||
return partial;
|
||||
@@ -139,7 +148,7 @@ public:
|
||||
*/
|
||||
template<std::size_t N>
|
||||
constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT
|
||||
: str{curr}, hash{helper(traits_type::offset, curr)}
|
||||
: str{curr}, hash{helper(curr)}
|
||||
{}
|
||||
|
||||
/**
|
||||
@@ -148,7 +157,7 @@ public:
|
||||
* @param wrapper Helps achieving the purpose by relying on overloading.
|
||||
*/
|
||||
explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
|
||||
: str{wrapper.str}, hash{helper(traits_type::offset, wrapper.str)}
|
||||
: str{wrapper.str}, hash{helper(wrapper.str)}
|
||||
{}
|
||||
|
||||
/**
|
||||
@@ -167,14 +176,14 @@ public:
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the human-readable representation of a hashed string.
|
||||
* @return The string used to initialize the instance.
|
||||
*/
|
||||
constexpr operator const value_type *() const ENTT_NOEXCEPT { return str; }
|
||||
/*! @copydoc data */
|
||||
constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); }
|
||||
|
||||
/*! @copydoc value */
|
||||
constexpr operator hash_type() const ENTT_NOEXCEPT { return hash; }
|
||||
/**
|
||||
* @brief Returns the numeric representation of a hashed string.
|
||||
* @return The numeric representation of the instance.
|
||||
*/
|
||||
constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); }
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
@@ -250,4 +259,4 @@ constexpr entt::hashed_wstring operator"" ENTT_HWS_SUFFIX(const wchar_t *str, st
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_CORE_HASHED_STRING_HPP
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#include <tuple>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
@@ -43,7 +44,7 @@ class identifier {
|
||||
using tuple_type = std::tuple<std::decay_t<Types>...>;
|
||||
|
||||
template<typename Type, std::size_t... Indexes>
|
||||
static constexpr ENTT_ID_TYPE get(std::index_sequence<Indexes...>) ENTT_NOEXCEPT {
|
||||
static constexpr ENTT_ID_TYPE get(std::index_sequence<Indexes...>) {
|
||||
static_assert(std::disjunction_v<std::is_same<Type, Types>...>);
|
||||
return (0 + ... + (std::is_same_v<Type, std::tuple_element_t<Indexes, tuple_type>> ? ENTT_ID_TYPE(Indexes) : ENTT_ID_TYPE{}));
|
||||
}
|
||||
@@ -61,4 +62,4 @@ public:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_CORE_IDENT_HPP
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define ENTT_CORE_MONOSTATE_HPP
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
@@ -59,4 +58,4 @@ inline monostate<Value> monostate_v = {};
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_CORE_MONOSTATE_HPP
|
||||
#endif
|
||||
|
||||
80
src/entt/core/type_info.hpp
Normal file
80
src/entt/core/type_info.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef ENTT_CORE_TYPE_INFO_HPP
|
||||
#define ENTT_CORE_TYPE_INFO_HPP
|
||||
|
||||
|
||||
#include "../config/config.h"
|
||||
#include "../core/attribute.h"
|
||||
#include "hashed_string.hpp"
|
||||
|
||||
|
||||
#ifndef ENTT_PRETTY_FUNCTION
|
||||
# define ENTT_TYPE_ID_API ENTT_API
|
||||
#else
|
||||
# define ENTT_TYPE_ID_API
|
||||
#endif
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
#ifndef ENTT_PRETTY_FUNCTION
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
struct ENTT_API type_id_generator {
|
||||
static ENTT_ID_TYPE next() ENTT_NOEXCEPT {
|
||||
static ENTT_ID_TYPE value{};
|
||||
return value++;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond TURN_OFF_DOXYGEN
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Types identifiers.
|
||||
* @tparam Type Type for which to generate an identifier.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct ENTT_TYPE_ID_API type_info {
|
||||
/**
|
||||
* @brief Returns the numeric representation of a given type.
|
||||
* @return The numeric representation of the given type.
|
||||
*/
|
||||
#if defined ENTT_PRETTY_FUNCTION_CONSTEXPR
|
||||
static constexpr ENTT_ID_TYPE id() ENTT_NOEXCEPT {
|
||||
constexpr auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION_CONSTEXPR);
|
||||
return value;
|
||||
}
|
||||
#elif defined ENTT_PRETTY_FUNCTION
|
||||
static ENTT_ID_TYPE id() ENTT_NOEXCEPT {
|
||||
static const auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION);
|
||||
return value;
|
||||
}
|
||||
#else
|
||||
static ENTT_ID_TYPE id() ENTT_NOEXCEPT {
|
||||
static const ENTT_ID_TYPE value = internal::type_id_generator::next();
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/hashed_string.hpp"
|
||||
@@ -169,57 +170,46 @@ template<class Type>
|
||||
constexpr auto is_equality_comparable_v = is_equality_comparable<Type>::value;
|
||||
|
||||
|
||||
/*! @brief Traits class used mainly to push things across boundaries. */
|
||||
template<typename>
|
||||
struct named_type_traits;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Specialization used to get rid of constness.
|
||||
* @tparam Type Named type.
|
||||
* @brief Extracts the class of a non-static member object or function.
|
||||
* @tparam Member A pointer to a non-static member object or function.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct named_type_traits<const Type>
|
||||
: named_type_traits<Type>
|
||||
{};
|
||||
template<typename Member>
|
||||
class member_class {
|
||||
static_assert(std::is_member_pointer_v<Member>);
|
||||
|
||||
template<typename Class, typename Ret, typename... Args>
|
||||
static Class * clazz(Ret(Class:: *)(Args...));
|
||||
|
||||
template<typename Class, typename Ret, typename... Args>
|
||||
static Class * clazz(Ret(Class:: *)(Args...) const);
|
||||
|
||||
template<typename Class, typename Type>
|
||||
static Class * clazz(Type Class:: *);
|
||||
|
||||
public:
|
||||
/*! @brief The class of the given non-static member object or function. */
|
||||
using type = std::remove_pointer_t<decltype(clazz(std::declval<Member>()))>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type Potentially named type.
|
||||
* @tparam Member A pointer to a non-static member object or function.
|
||||
*/
|
||||
template<typename Type>
|
||||
using named_type_traits_t = typename named_type_traits<Type>::type;
|
||||
template<typename Member>
|
||||
using member_class_t = typename member_class<Member>::type;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Potentially named type.
|
||||
* @brief Alias template to ease the creation of named values.
|
||||
* @tparam Value A constant value at least convertible to `ENTT_ID_TYPE`.
|
||||
*/
|
||||
template<class Type>
|
||||
constexpr auto named_type_traits_v = named_type_traits<Type>::value;
|
||||
template<ENTT_ID_TYPE Value>
|
||||
using tag = std::integral_constant<ENTT_ID_TYPE, Value>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type has a
|
||||
* name. In all other cases, `value` is false.
|
||||
* @tparam Type Potentially named type.
|
||||
*/
|
||||
template<typename Type, typename = std::void_t<>>
|
||||
struct is_named_type: std::false_type {};
|
||||
|
||||
|
||||
/*! @copydoc is_named_type */
|
||||
template<typename Type>
|
||||
struct is_named_type<Type, std::void_t<named_type_traits_t<std::decay_t<Type>>>>: std::true_type {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Potentially named type.
|
||||
*/
|
||||
template<class Type>
|
||||
constexpr auto is_named_type_v = is_named_type<Type>::value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -230,104 +220,10 @@ constexpr auto is_named_type_v = is_named_type<Type>::value;
|
||||
*/
|
||||
#define ENTT_OPAQUE_TYPE(clazz, type)\
|
||||
enum class clazz: type {};\
|
||||
constexpr auto to_integer(const clazz id) ENTT_NOEXCEPT {\
|
||||
return std::underlying_type_t<clazz>(id);\
|
||||
constexpr auto to_integral(const clazz id) ENTT_NOEXCEPT {\
|
||||
return static_cast<std::underlying_type_t<clazz>>(id);\
|
||||
}\
|
||||
static_assert(true)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility macro to deal with an issue of MSVC.
|
||||
*
|
||||
* See _msvc-doesnt-expand-va-args-correctly_ on SO for all the details.
|
||||
*
|
||||
* @param args Argument to expand.
|
||||
*/
|
||||
#define ENTT_EXPAND(args) args
|
||||
|
||||
|
||||
/**
|
||||
* @brief Makes an already existing type a named type.
|
||||
*
|
||||
* The current definition contains a workaround for Clang 6 because it fails to
|
||||
* deduce correctly the type to use to specialize the class template.<br/>
|
||||
* With a compiler that fully supports C++17 and works fine with deduction
|
||||
* guides, the following should be fine instead:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* std::integral_constant<ENTT_ID_TYPE, entt::basic_hashed_string{#type}>
|
||||
* @endcode
|
||||
*
|
||||
* In order to support even sligthly older compilers, I prefer to stick to the
|
||||
* implementation below.
|
||||
*
|
||||
* @param type Type to assign a name to.
|
||||
*/
|
||||
#define ENTT_NAMED_TYPE(type)\
|
||||
template<>\
|
||||
struct entt::named_type_traits<type>\
|
||||
: std::integral_constant<ENTT_ID_TYPE, entt::basic_hashed_string<std::remove_cv_t<std::remove_pointer_t<std::decay_t<decltype(#type)>>>>{#type}>\
|
||||
{\
|
||||
static_assert(std::is_same_v<std::remove_cv_t<type>, type>);\
|
||||
static_assert(std::is_object_v<type>);\
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Defines a named type (to use for structs).
|
||||
* @param clazz Name of the type to define.
|
||||
* @param body Body of the type to define.
|
||||
*/
|
||||
#define ENTT_NAMED_STRUCT_ONLY(clazz, body)\
|
||||
struct clazz body;\
|
||||
ENTT_NAMED_TYPE(clazz)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Defines a named type (to use for structs).
|
||||
* @param ns Namespace where to define the named type.
|
||||
* @param clazz Name of the type to define.
|
||||
* @param body Body of the type to define.
|
||||
*/
|
||||
#define ENTT_NAMED_STRUCT_WITH_NAMESPACE(ns, clazz, body)\
|
||||
namespace ns { struct clazz body; }\
|
||||
ENTT_NAMED_TYPE(ns::clazz)
|
||||
|
||||
|
||||
/*! @brief Utility function to simulate macro overloading. */
|
||||
#define ENTT_NAMED_STRUCT_OVERLOAD(_1, _2, _3, FUNC, ...) FUNC
|
||||
/*! @brief Defines a named type (to use for structs). */
|
||||
#define ENTT_NAMED_STRUCT(...) ENTT_EXPAND(ENTT_NAMED_STRUCT_OVERLOAD(__VA_ARGS__, ENTT_NAMED_STRUCT_WITH_NAMESPACE, ENTT_NAMED_STRUCT_ONLY,)(__VA_ARGS__))
|
||||
|
||||
|
||||
/**
|
||||
* @brief Defines a named type (to use for classes).
|
||||
* @param clazz Name of the type to define.
|
||||
* @param body Body of the type to define.
|
||||
*/
|
||||
#define ENTT_NAMED_CLASS_ONLY(clazz, body)\
|
||||
class clazz body;\
|
||||
ENTT_NAMED_TYPE(clazz)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Defines a named type (to use for classes).
|
||||
* @param ns Namespace where to define the named type.
|
||||
* @param clazz Name of the type to define.
|
||||
* @param body Body of the type to define.
|
||||
*/
|
||||
#define ENTT_NAMED_CLASS_WITH_NAMESPACE(ns, clazz, body)\
|
||||
namespace ns { class clazz body; }\
|
||||
ENTT_NAMED_TYPE(ns::clazz)
|
||||
|
||||
|
||||
/*! @brief Utility function to simulate macro overloading. */
|
||||
#define ENTT_NAMED_CLASS_MACRO(_1, _2, _3, FUNC, ...) FUNC
|
||||
/*! @brief Defines a named type (to use for classes). */
|
||||
#define ENTT_NAMED_CLASS(...) ENTT_EXPAND(ENTT_NAMED_CLASS_MACRO(__VA_ARGS__, ENTT_NAMED_CLASS_WITH_NAMESPACE, ENTT_NAMED_CLASS_ONLY,)(__VA_ARGS__))
|
||||
|
||||
|
||||
#endif // ENTT_CORE_TYPE_TRAITS_HPP
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define ENTT_CORE_UTILITY_HPP
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
@@ -24,11 +25,11 @@ struct identity {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constant utility to disambiguate overloaded member functions.
|
||||
* @tparam Type Function type of the desired overload.
|
||||
* @tparam Class Type of class to which the member functions belong.
|
||||
* @param member A valid pointer to a member function.
|
||||
* @return Pointer to the member function.
|
||||
* @brief Constant utility to disambiguate overloaded members of a class.
|
||||
* @tparam Type Type of the desired overload.
|
||||
* @tparam Class Type of class to which the member belongs.
|
||||
* @param member A valid pointer to a member.
|
||||
* @return Pointer to the member.
|
||||
*/
|
||||
template<typename Type, typename Class>
|
||||
constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; }
|
||||
@@ -36,12 +37,12 @@ constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; }
|
||||
|
||||
/**
|
||||
* @brief Constant utility to disambiguate overloaded functions.
|
||||
* @tparam Type Function type of the desired overload.
|
||||
* @tparam Func Function type of the desired overload.
|
||||
* @param func A valid pointer to a function.
|
||||
* @return Pointer to the function.
|
||||
*/
|
||||
template<typename Type>
|
||||
constexpr auto overload(Type *func) ENTT_NOEXCEPT { return func; }
|
||||
template<typename Func>
|
||||
constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; }
|
||||
|
||||
|
||||
/**
|
||||
@@ -58,8 +59,8 @@ struct overloaded: Func... {
|
||||
* @brief Deduction guide.
|
||||
* @tparam Func Types of function objects.
|
||||
*/
|
||||
template<class... Type>
|
||||
overloaded(Type...) -> overloaded<Type...>;
|
||||
template<class... Func>
|
||||
overloaded(Func...) -> overloaded<Func...>;
|
||||
|
||||
|
||||
/**
|
||||
@@ -101,4 +102,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_CORE_UTILITY_HPP
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define ENTT_ENTITY_ACTOR_HPP
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
@@ -35,6 +34,21 @@ struct basic_actor {
|
||||
: entt{entt::null}, reg{nullptr}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
*
|
||||
* After actor move construction, instances that have been moved from are
|
||||
* placed in a valid but unspecified state. It's highly discouraged to
|
||||
* continue using them.
|
||||
*
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_actor(basic_actor &&other) ENTT_NOEXCEPT
|
||||
: entt{other.entt}, reg{other.reg}
|
||||
{
|
||||
other.entt = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an actor from a given registry.
|
||||
* @param ref An instance of the registry class.
|
||||
@@ -48,7 +62,7 @@ struct basic_actor {
|
||||
* @param entity A valid entity identifier.
|
||||
* @param ref An instance of the registry class.
|
||||
*/
|
||||
explicit basic_actor(entity_type entity, registry_type &ref)
|
||||
explicit basic_actor(entity_type entity, registry_type &ref) ENTT_NOEXCEPT
|
||||
: entt{entity}, reg{&ref}
|
||||
{
|
||||
ENTT_ASSERT(ref.valid(entity));
|
||||
@@ -61,21 +75,6 @@ struct basic_actor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
*
|
||||
* After actor move construction, instances that have been moved from are
|
||||
* placed in a valid but unspecified state. It's highly discouraged to
|
||||
* continue using them.
|
||||
*
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_actor(basic_actor &&other)
|
||||
: entt{other.entt}, reg{other.reg}
|
||||
{
|
||||
other.entt = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
*
|
||||
@@ -86,7 +85,7 @@ struct basic_actor {
|
||||
* @param other The instance to move from.
|
||||
* @return This actor.
|
||||
*/
|
||||
basic_actor & operator=(basic_actor &&other) {
|
||||
basic_actor & operator=(basic_actor &&other) ENTT_NOEXCEPT {
|
||||
if(this != &other) {
|
||||
auto tmp{std::move(other)};
|
||||
std::swap(reg, tmp.reg);
|
||||
@@ -130,7 +129,7 @@ struct basic_actor {
|
||||
* @return True if the actor has all the components, false otherwise.
|
||||
*/
|
||||
template<typename... Component>
|
||||
bool has() const ENTT_NOEXCEPT {
|
||||
bool has() const {
|
||||
return (reg->template has<Component>(entt) && ...);
|
||||
}
|
||||
|
||||
@@ -140,13 +139,13 @@ struct basic_actor {
|
||||
* @return References to the components owned by the actor.
|
||||
*/
|
||||
template<typename... Component>
|
||||
decltype(auto) get() const ENTT_NOEXCEPT {
|
||||
decltype(auto) get() const {
|
||||
return std::as_const(*reg).template get<Component...>(entt);
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
template<typename... Component>
|
||||
decltype(auto) get() ENTT_NOEXCEPT {
|
||||
decltype(auto) get() {
|
||||
return reg->template get<Component...>(entt);
|
||||
}
|
||||
|
||||
@@ -156,13 +155,13 @@ struct basic_actor {
|
||||
* @return Pointers to the components owned by the actor.
|
||||
*/
|
||||
template<typename... Component>
|
||||
auto try_get() const ENTT_NOEXCEPT {
|
||||
auto try_get() const {
|
||||
return std::as_const(*reg).template try_get<Component...>(entt);
|
||||
}
|
||||
|
||||
/*! @copydoc try_get */
|
||||
template<typename... Component>
|
||||
auto try_get() ENTT_NOEXCEPT {
|
||||
auto try_get() {
|
||||
return reg->template try_get<Component...>(entt);
|
||||
}
|
||||
|
||||
@@ -191,7 +190,7 @@ struct basic_actor {
|
||||
* @brief Checks if an actor refers to a valid entity or not.
|
||||
* @return True if the actor refers to a valid entity, false otherwise.
|
||||
*/
|
||||
explicit operator bool() const ENTT_NOEXCEPT {
|
||||
explicit operator bool() const {
|
||||
return reg && reg->valid(entt);
|
||||
}
|
||||
|
||||
@@ -204,4 +203,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_ACTOR_HPP
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
@@ -127,7 +128,7 @@ public:
|
||||
|
||||
template<typename Entity>
|
||||
constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
|
||||
return (to_integer(entity) & traits_type<Entity>::entity_mask) == to_integer(static_cast<Entity>(*this));
|
||||
return (to_integral(entity) & traits_type<Entity>::entity_mask) == to_integral(static_cast<Entity>(*this));
|
||||
}
|
||||
|
||||
template<typename Entity>
|
||||
@@ -171,4 +172,4 @@ constexpr auto null = internal::null{};
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_ENTITY_HPP
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,39 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct exclude_t: type_list<Type...> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Variable template for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
constexpr exclude_t<Type...> exclude{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias for lists of observed components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct get_t: type_list<Type...>{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Variable template for lists of observed components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
constexpr get_t<Type...> get{};
|
||||
|
||||
|
||||
/*! @class basic_registry */
|
||||
template <typename>
|
||||
class basic_registry;
|
||||
@@ -47,9 +80,6 @@ class basic_continuous_loader;
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
ENTT_OPAQUE_TYPE(entity, ENTT_ID_TYPE);
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
ENTT_OPAQUE_TYPE(component, ENTT_ID_TYPE);
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using registry = basic_registry<entity>;
|
||||
|
||||
@@ -89,4 +119,4 @@ using group = basic_group<entity, Types...>;
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_FWD_HPP
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "sparse_set.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
@@ -29,11 +28,9 @@ class basic_group;
|
||||
/**
|
||||
* @brief Non-owning group.
|
||||
*
|
||||
* A non-owning group returns all the entities and only the entities that have
|
||||
* at least the given components. Moreover, it's guaranteed that the entity list
|
||||
* is tightly packed in memory for fast iterations.<br/>
|
||||
* In general, non-owning groups don't stay true to the order of any set of
|
||||
* components unless users explicitly sort them.
|
||||
* A non-owning group returns all entities and only the entities that have at
|
||||
* least the given components. Moreover, it's guaranteed that the entity list
|
||||
* is tightly packed in memory for fast iterations.
|
||||
*
|
||||
* @b Important
|
||||
*
|
||||
@@ -44,18 +41,17 @@ class basic_group;
|
||||
* given components is removed from the entity to which the iterator points).
|
||||
* * The entity currently pointed is destroyed.
|
||||
*
|
||||
* In all the other cases, modifying the pools of the given components in any
|
||||
* way invalidates all the iterators and using them results in undefined
|
||||
* behavior.
|
||||
* In all other cases, modifying the pools iterated by the group in any way
|
||||
* invalidates all the iterators and using them results in undefined behavior.
|
||||
*
|
||||
* @note
|
||||
* Groups share references to the underlying data structures of the registry
|
||||
* that generated them. Therefore any change to the entities and to the
|
||||
* components made by means of the registry are immediately reflected by all the
|
||||
* groups.<br/>
|
||||
* Moreover, sorting a non-owning group affects all the instance of the same
|
||||
* Moreover, sorting a non-owning group affects all the instances of the same
|
||||
* group (it means that users don't have to call `sort` on each instance to sort
|
||||
* all of them because they share the set of entities).
|
||||
* all of them because they _share_ entities and components).
|
||||
*
|
||||
* @warning
|
||||
* Lifetime of a group must overcome the one of the registry that generated it.
|
||||
@@ -73,10 +69,10 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> {
|
||||
template<typename Component>
|
||||
using pool_type = std::conditional_t<std::is_const_v<Component>, const storage<Entity, std::remove_const_t<Component>>, storage<Entity, Component>>;
|
||||
|
||||
// we could use pool_type<Type> *..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug)
|
||||
basic_group(sparse_set<Entity> *ref, storage<Entity, std::remove_const_t<Get>> *... gpool) ENTT_NOEXCEPT
|
||||
: handler{ref},
|
||||
pools{gpool...}
|
||||
// we could use pool_type<Type> &..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug)
|
||||
basic_group(sparse_set<Entity> &ref, storage<Entity, std::remove_const_t<Get>> &... gpool) ENTT_NOEXCEPT
|
||||
: handler{&ref},
|
||||
pools{&gpool...}
|
||||
{}
|
||||
|
||||
template<typename Func, typename... Weak>
|
||||
@@ -131,11 +127,9 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether the group or the pools of the given components are
|
||||
* empty.
|
||||
* @brief Checks whether a group or some pools are empty.
|
||||
* @tparam Component Types of components in which one is interested.
|
||||
* @return True if the group or the pools of the given components are empty,
|
||||
* false otherwise.
|
||||
* @return True if the group or the pools are empty, false otherwise.
|
||||
*/
|
||||
template<typename... Component>
|
||||
bool empty() const ENTT_NOEXCEPT {
|
||||
@@ -237,13 +231,33 @@ public:
|
||||
return handler->end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the first entity that has the given components, if any.
|
||||
* @return The first entity that has the given components if one exists, the
|
||||
* null entity otherwise.
|
||||
*/
|
||||
entity_type front() const {
|
||||
const auto it = begin();
|
||||
return it != end() ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last entity that has the given components, if any.
|
||||
* @return The last entity that has the given components if one exists, the
|
||||
* null entity otherwise.
|
||||
*/
|
||||
entity_type back() const {
|
||||
const auto it = std::make_reverse_iterator(end());
|
||||
return it != std::make_reverse_iterator(begin()) ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an entity.
|
||||
* @param entt A valid entity identifier.
|
||||
* @return An iterator to the given entity if it's found, past the end
|
||||
* iterator otherwise.
|
||||
*/
|
||||
iterator_type find(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
iterator_type find(const entity_type entt) const {
|
||||
const auto it = handler->find(entt);
|
||||
return it != end() && *it == entt ? it : end();
|
||||
}
|
||||
@@ -253,7 +267,7 @@ public:
|
||||
* @param pos Position of the element to return.
|
||||
* @return The identifier that occupies the given position.
|
||||
*/
|
||||
entity_type operator[](const size_type pos) const ENTT_NOEXCEPT {
|
||||
entity_type operator[](const size_type pos) const {
|
||||
return begin()[pos];
|
||||
}
|
||||
|
||||
@@ -262,15 +276,15 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return True if the group contains the given entity, false otherwise.
|
||||
*/
|
||||
bool contains(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
return find(entt) != end();
|
||||
bool contains(const entity_type entt) const {
|
||||
return handler->has(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the components assigned to the given entity.
|
||||
*
|
||||
* Prefer this function instead of `registry::get` during iterations. It has
|
||||
* far better performance than its companion function.
|
||||
* far better performance than its counterpart.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an invalid component type results in a compilation
|
||||
@@ -284,7 +298,7 @@ public:
|
||||
* @return The components assigned to the entity.
|
||||
*/
|
||||
template<typename... Component>
|
||||
decltype(auto) get([[maybe_unused]] const entity_type entt) const ENTT_NOEXCEPT {
|
||||
decltype(auto) get([[maybe_unused]] const entity_type entt) const {
|
||||
ENTT_ASSERT(contains(entt));
|
||||
|
||||
if constexpr(sizeof...(Component) == 1) {
|
||||
@@ -409,7 +423,7 @@ public:
|
||||
* @brief Sort the shared pool of entities according to the given component.
|
||||
*
|
||||
* Non-owning groups of the same type share with the registry a pool of
|
||||
* entities with its own order that doesn't depend on the order of any pool
|
||||
* entities with its own order that doesn't depend on the order of any pool
|
||||
* of components. Users can order the underlying data structure so that it
|
||||
* respects the order of the pool of the given component.
|
||||
*
|
||||
@@ -435,15 +449,15 @@ private:
|
||||
/**
|
||||
* @brief Owning group.
|
||||
*
|
||||
* Owning groups return all the entities and only the entities that have at
|
||||
* least the given components. Moreover:
|
||||
* Owning groups return all entities and only the entities that have at least
|
||||
* the given components. Moreover:
|
||||
*
|
||||
* * It's guaranteed that the entity list is tightly packed in memory for fast
|
||||
* iterations.
|
||||
* * It's guaranteed that the lists of owned components are tightly packed in
|
||||
* memory for even faster iterations and to allow direct access.
|
||||
* * They stay true to the order of the owned components and all the owned
|
||||
* components have the same order in memory.
|
||||
* * They stay true to the order of the owned components and all instances have
|
||||
* the same order in memory.
|
||||
*
|
||||
* The more types of components are owned by a group, the faster it is to
|
||||
* iterate them.
|
||||
@@ -457,9 +471,8 @@ private:
|
||||
* given components is removed from the entity to which the iterator points).
|
||||
* * The entity currently pointed is destroyed.
|
||||
*
|
||||
* In all the other cases, modifying the pools of the given components in any
|
||||
* way invalidates all the iterators and using them results in undefined
|
||||
* behavior.
|
||||
* In all other cases, modifying the pools iterated by the group in any way
|
||||
* invalidates all the iterators and using them results in undefined behavior.
|
||||
*
|
||||
* @note
|
||||
* Groups share references to the underlying data structures of the registry
|
||||
@@ -490,11 +503,11 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> {
|
||||
template<typename Component>
|
||||
using component_iterator_type = decltype(std::declval<pool_type<Component>>().begin());
|
||||
|
||||
// we could use pool_type<Type> *..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug)
|
||||
basic_group(const std::size_t *ref, const std::size_t *extent, storage<Entity, std::remove_const_t<Owned>> *... opool, storage<Entity, std::remove_const_t<Get>> *... gpool) ENTT_NOEXCEPT
|
||||
: pools{opool..., gpool...},
|
||||
length{extent},
|
||||
super{ref}
|
||||
// we could use pool_type<Type> &..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug)
|
||||
basic_group(const std::size_t &ref, const std::size_t &extent, storage<Entity, std::remove_const_t<Owned>> &... opool, storage<Entity, std::remove_const_t<Get>> &... gpool) ENTT_NOEXCEPT
|
||||
: pools{&opool..., &gpool...},
|
||||
length{&extent},
|
||||
super{&ref}
|
||||
{}
|
||||
|
||||
template<typename Func, typename... Strong, typename... Weak>
|
||||
@@ -544,11 +557,9 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether the group or the pools of the given components are
|
||||
* empty.
|
||||
* @brief Checks whether a group or some pools are empty.
|
||||
* @tparam Component Types of components in which one is interested.
|
||||
* @return True if the group or the pools of the given components are empty,
|
||||
* false otherwise.
|
||||
* @return True if the group or the pools are empty, false otherwise.
|
||||
*/
|
||||
template<typename... Component>
|
||||
bool empty() const ENTT_NOEXCEPT {
|
||||
@@ -656,13 +667,33 @@ public:
|
||||
return std::get<0>(pools)->sparse_set<entity_type>::end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the first entity that has the given components, if any.
|
||||
* @return The first entity that has the given components if one exists, the
|
||||
* null entity otherwise.
|
||||
*/
|
||||
entity_type front() const {
|
||||
const auto it = begin();
|
||||
return it != end() ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last entity that has the given components, if any.
|
||||
* @return The last entity that has the given components if one exists, the
|
||||
* null entity otherwise.
|
||||
*/
|
||||
entity_type back() const {
|
||||
const auto it = std::make_reverse_iterator(end());
|
||||
return it != std::make_reverse_iterator(begin()) ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an entity.
|
||||
* @param entt A valid entity identifier.
|
||||
* @return An iterator to the given entity if it's found, past the end
|
||||
* iterator otherwise.
|
||||
*/
|
||||
iterator_type find(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
iterator_type find(const entity_type entt) const {
|
||||
const auto it = std::get<0>(pools)->find(entt);
|
||||
return it != end() && it >= begin() && *it == entt ? it : end();
|
||||
}
|
||||
@@ -672,7 +703,7 @@ public:
|
||||
* @param pos Position of the element to return.
|
||||
* @return The identifier that occupies the given position.
|
||||
*/
|
||||
entity_type operator[](const size_type pos) const ENTT_NOEXCEPT {
|
||||
entity_type operator[](const size_type pos) const {
|
||||
return begin()[pos];
|
||||
}
|
||||
|
||||
@@ -681,15 +712,15 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return True if the group contains the given entity, false otherwise.
|
||||
*/
|
||||
bool contains(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
return find(entt) != end();
|
||||
bool contains(const entity_type entt) const {
|
||||
return std::get<0>(pools)->has(entt) && (std::get<0>(pools)->index(entt) < (*length));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the components assigned to the given entity.
|
||||
*
|
||||
* Prefer this function instead of `registry::get` during iterations. It has
|
||||
* far better performance than its companion function.
|
||||
* far better performance than its counterpart.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an invalid component type results in a compilation
|
||||
@@ -703,7 +734,7 @@ public:
|
||||
* @return The components assigned to the entity.
|
||||
*/
|
||||
template<typename... Component>
|
||||
decltype(auto) get([[maybe_unused]] const entity_type entt) const ENTT_NOEXCEPT {
|
||||
decltype(auto) get([[maybe_unused]] const entity_type entt) const {
|
||||
ENTT_ASSERT(contains(entt));
|
||||
|
||||
if constexpr(sizeof...(Component) == 1) {
|
||||
@@ -856,4 +887,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_GROUP_HPP
|
||||
#endif
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../config/config.h"
|
||||
#include "../signal/sigh.hpp"
|
||||
#include "registry.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
@@ -110,30 +111,7 @@ template<typename Entity>
|
||||
as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<true, Entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias template to ease the assignment of tags to entities.
|
||||
*
|
||||
* If used in combination with hashed strings, it simplifies the assignment of
|
||||
* tags to entities and the use of tags 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::registry registry;
|
||||
* registry.assign<entt::tag<"enemy"_hs>>(entity);
|
||||
* @endcode
|
||||
*
|
||||
* @note
|
||||
* Tags are empty components and therefore candidates for the empty component
|
||||
* optimization.
|
||||
*
|
||||
* @tparam Value The numeric representation of an instance of hashed string.
|
||||
*/
|
||||
template<ENTT_ID_TYPE Value>
|
||||
using tag = std::integral_constant<ENTT_ID_TYPE, Value>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_HELPER_HPP
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/type_traits.hpp"
|
||||
@@ -177,15 +176,18 @@ class basic_observer {
|
||||
template<typename... Reject, typename... Require, typename AnyOf>
|
||||
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 Entity entt, const basic_registry<Entity> ®) {
|
||||
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> ®, const Entity entt) {
|
||||
if(reg.template has<Require...>(entt) && !(reg.template has<Reject>(entt) || ...)) {
|
||||
auto *comp = obs.view.try_get(entt);
|
||||
(comp ? *comp : obs.view.construct(entt)) |= (1 << Index);
|
||||
if(auto *comp = obs.view.try_get(entt); !comp) {
|
||||
obs.view.construct(entt);
|
||||
}
|
||||
|
||||
obs.view.get(entt) |= (1 << Index);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, const Entity entt) {
|
||||
static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
|
||||
if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
|
||||
obs.view.destroy(entt);
|
||||
}
|
||||
@@ -210,15 +212,18 @@ class basic_observer {
|
||||
template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
|
||||
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 Entity entt, const basic_registry<Entity> ®) {
|
||||
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> ®, const Entity entt) {
|
||||
if(reg.template has<AllOf..., Require...>(entt) && !(reg.template has<NoneOf>(entt) || ...) && !(reg.template has<Reject>(entt) || ...)) {
|
||||
auto *comp = obs.view.try_get(entt);
|
||||
(comp ? *comp : obs.view.construct(entt)) |= (1 << Index);
|
||||
if(auto *comp = obs.view.try_get(entt); !comp) {
|
||||
obs.view.construct(entt);
|
||||
}
|
||||
|
||||
obs.view.get(entt) |= (1 << Index);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, const Entity entt) {
|
||||
static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
|
||||
if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
|
||||
obs.view.destroy(entt);
|
||||
}
|
||||
@@ -265,7 +270,7 @@ public:
|
||||
using iterator_type = typename sparse_set<Entity>::iterator_type;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_observer() ENTT_NOEXCEPT
|
||||
basic_observer()
|
||||
: target{}, release{}, view{}
|
||||
{}
|
||||
|
||||
@@ -280,7 +285,7 @@ public:
|
||||
* @param reg A valid reference to a registry.
|
||||
*/
|
||||
template<typename... Matcher>
|
||||
basic_observer(basic_registry<entity_type> ®, basic_collector<Matcher...>) ENTT_NOEXCEPT
|
||||
basic_observer(basic_registry<entity_type> ®, basic_collector<Matcher...>)
|
||||
: target{®},
|
||||
release{},
|
||||
view{}
|
||||
@@ -313,7 +318,7 @@ public:
|
||||
disconnect();
|
||||
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
|
||||
target = ®
|
||||
view.reset();
|
||||
view.clear();
|
||||
}
|
||||
|
||||
/*! @brief Disconnects an observer from the registry it keeps track of. */
|
||||
@@ -382,14 +387,13 @@ public:
|
||||
return view.sparse_set<entity_type>::end();
|
||||
}
|
||||
|
||||
/*! @brief Resets the underlying container. */
|
||||
void clear() {
|
||||
view.reset();
|
||||
/*! @brief Clears the underlying container. */
|
||||
void clear() ENTT_NOEXCEPT {
|
||||
view.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates entities and applies the given function object to them,
|
||||
* then clears the observer.
|
||||
* @brief Iterates entities and applies the given function object to them.
|
||||
*
|
||||
* The function object is invoked for each entity.<br/>
|
||||
* The signature of the function must be equivalent to the following form:
|
||||
@@ -404,19 +408,17 @@ public:
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
static_assert(std::is_invocable_v<Func, entity_type>);
|
||||
std::for_each(begin(), end(), std::move(func));
|
||||
|
||||
for(const auto entity: *this) {
|
||||
func(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates entities and applies the given function object to them,
|
||||
* then clears the observer.
|
||||
*
|
||||
* The function object is invoked for each entity.<br/>
|
||||
* The signature of the function must be equivalent to the following form:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(const entity_type);
|
||||
* @endcode
|
||||
* @sa each
|
||||
*
|
||||
* @tparam Func Type of the function object to invoke.
|
||||
* @param func A valid function object.
|
||||
@@ -437,4 +439,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_OBSERVER_HPP
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,6 @@
|
||||
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
@@ -65,20 +64,20 @@ class basic_runtime_view {
|
||||
class iterator {
|
||||
friend class basic_runtime_view<Entity>;
|
||||
|
||||
iterator(underlying_iterator_type first, underlying_iterator_type last, const sparse_set<Entity> * const *others, const sparse_set<Entity> * const *length) ENTT_NOEXCEPT
|
||||
: begin{first},
|
||||
end{last},
|
||||
from{others},
|
||||
to{length}
|
||||
using direct_type = std::vector<const sparse_set<Entity> *>;
|
||||
|
||||
iterator(const direct_type *all, underlying_iterator_type curr) ENTT_NOEXCEPT
|
||||
: pools{all},
|
||||
it{curr}
|
||||
{
|
||||
if(begin != end && !valid()) {
|
||||
if(it != (*pools)[0]->end() && !valid()) {
|
||||
++(*this);
|
||||
}
|
||||
}
|
||||
|
||||
bool valid() const ENTT_NOEXCEPT {
|
||||
return std::all_of(from, to, [entt = *begin](const auto *view) {
|
||||
return view->has(entt);
|
||||
bool valid() const {
|
||||
return std::all_of(pools->begin()++, pools->end(), [entt = *it](const auto *curr) {
|
||||
return curr->has(entt);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,40 +86,49 @@ class basic_runtime_view {
|
||||
using value_type = typename underlying_iterator_type::value_type;
|
||||
using pointer = typename underlying_iterator_type::pointer;
|
||||
using reference = typename underlying_iterator_type::reference;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
|
||||
iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
iterator & operator++() ENTT_NOEXCEPT {
|
||||
return (++begin != end && !valid()) ? ++(*this) : *this;
|
||||
iterator & operator++() {
|
||||
while(++it != (*pools)[0]->end() && !valid());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) ENTT_NOEXCEPT {
|
||||
iterator operator++(int) {
|
||||
iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
return operator++(), orig;
|
||||
}
|
||||
|
||||
iterator & operator--() ENTT_NOEXCEPT {
|
||||
while(--it != (*pools)[0]->begin() && !valid());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator--(int) ENTT_NOEXCEPT {
|
||||
iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
bool operator==(const iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.begin == begin;
|
||||
return other.it == it;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
pointer operator->() const ENTT_NOEXCEPT {
|
||||
return begin.operator->();
|
||||
pointer operator->() const {
|
||||
return it.operator->();
|
||||
}
|
||||
|
||||
reference operator*() const ENTT_NOEXCEPT {
|
||||
reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
underlying_iterator_type begin;
|
||||
underlying_iterator_type end;
|
||||
const sparse_set<Entity> * const *from;
|
||||
const sparse_set<Entity> * const *to;
|
||||
const direct_type *pools;
|
||||
underlying_iterator_type it;
|
||||
};
|
||||
|
||||
basic_runtime_view(std::vector<const sparse_set<Entity> *> others) ENTT_NOEXCEPT
|
||||
@@ -134,7 +142,7 @@ class basic_runtime_view {
|
||||
std::rotate(pools.begin(), it, pools.end());
|
||||
}
|
||||
|
||||
bool valid() const ENTT_NOEXCEPT {
|
||||
bool valid() const {
|
||||
return !pools.empty() && pools.front();
|
||||
}
|
||||
|
||||
@@ -150,7 +158,7 @@ public:
|
||||
* @brief Estimates the number of entities that have the given components.
|
||||
* @return Estimated number of entities that have the given components.
|
||||
*/
|
||||
size_type size() const ENTT_NOEXCEPT {
|
||||
size_type size() const {
|
||||
return valid() ? pools.front()->size() : size_type{};
|
||||
}
|
||||
|
||||
@@ -158,7 +166,7 @@ public:
|
||||
* @brief Checks if the view is definitely empty.
|
||||
* @return True if the view is definitely empty, false otherwise.
|
||||
*/
|
||||
bool empty() const ENTT_NOEXCEPT {
|
||||
bool empty() const {
|
||||
return !valid() || pools.front()->empty();
|
||||
}
|
||||
|
||||
@@ -176,13 +184,11 @@ public:
|
||||
*
|
||||
* @return An iterator to the first entity that has the given components.
|
||||
*/
|
||||
iterator_type begin() const ENTT_NOEXCEPT {
|
||||
iterator_type begin() const {
|
||||
iterator_type it{};
|
||||
|
||||
if(valid()) {
|
||||
const auto &pool = *pools.front();
|
||||
const auto * const *data = pools.data();
|
||||
it = { pool.begin(), pool.end(), data + 1, data + pools.size() };
|
||||
it = { &pools, pools[0]->begin() };
|
||||
}
|
||||
|
||||
return it;
|
||||
@@ -203,12 +209,11 @@ public:
|
||||
* @return An iterator to the entity following the last entity that has the
|
||||
* given components.
|
||||
*/
|
||||
iterator_type end() const ENTT_NOEXCEPT {
|
||||
iterator_type end() const {
|
||||
iterator_type it{};
|
||||
|
||||
if(valid()) {
|
||||
const auto &pool = *pools.front();
|
||||
it = { pool.end(), pool.end(), nullptr, nullptr };
|
||||
it = { &pools, pools[0]->end() };
|
||||
}
|
||||
|
||||
return it;
|
||||
@@ -219,7 +224,7 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return True if the view contains the given entity, false otherwise.
|
||||
*/
|
||||
bool contains(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
bool contains(const entity_type entt) const {
|
||||
return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *view) {
|
||||
return view->find(entt) != view->end();
|
||||
});
|
||||
@@ -242,7 +247,9 @@ public:
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
std::for_each(begin(), end(), func);
|
||||
for(const auto entity: *this) {
|
||||
func(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -253,4 +260,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_RUNTIME_VIEW_HPP
|
||||
#endif
|
||||
|
||||
@@ -388,7 +388,7 @@ class basic_continuous_loader {
|
||||
}
|
||||
|
||||
template<typename Other, typename Type, typename Member>
|
||||
void update(Other &instance, Member Type:: *member) {
|
||||
void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type:: *member) {
|
||||
if constexpr(!std::is_same_v<Other, Type>) {
|
||||
return;
|
||||
} else if constexpr(std::is_same_v<Member, Entity>) {
|
||||
@@ -417,7 +417,7 @@ class basic_continuous_loader {
|
||||
const auto local = ref.second.first;
|
||||
|
||||
if(reg->valid(local)) {
|
||||
reg->template reset<Component>(local);
|
||||
reg->template remove_if_exists<Component>(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -602,4 +602,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_SNAPSHOT_HPP
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstddef>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/algorithm.hpp"
|
||||
@@ -56,10 +55,10 @@ class sparse_set {
|
||||
class iterator {
|
||||
friend class sparse_set<Entity>;
|
||||
|
||||
using direct_type = const std::vector<Entity>;
|
||||
using direct_type = std::vector<Entity>;
|
||||
using index_type = typename traits_type::difference_type;
|
||||
|
||||
iterator(direct_type *ref, const index_type idx) ENTT_NOEXCEPT
|
||||
iterator(const direct_type *ref, const index_type idx) ENTT_NOEXCEPT
|
||||
: direct{ref}, index{idx}
|
||||
{}
|
||||
|
||||
@@ -78,7 +77,7 @@ class sparse_set {
|
||||
|
||||
iterator operator++(int) ENTT_NOEXCEPT {
|
||||
iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
return operator++(), orig;
|
||||
}
|
||||
|
||||
iterator & operator--() ENTT_NOEXCEPT {
|
||||
@@ -87,7 +86,7 @@ class sparse_set {
|
||||
|
||||
iterator operator--(int) ENTT_NOEXCEPT {
|
||||
iterator orig = *this;
|
||||
return --(*this), orig;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
|
||||
@@ -111,7 +110,7 @@ class sparse_set {
|
||||
return other.index - index;
|
||||
}
|
||||
|
||||
reference operator[](const difference_type value) const ENTT_NOEXCEPT {
|
||||
reference operator[](const difference_type value) const {
|
||||
const auto pos = size_type(index-value-1);
|
||||
return (*direct)[pos];
|
||||
}
|
||||
@@ -140,37 +139,40 @@ class sparse_set {
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
pointer operator->() const ENTT_NOEXCEPT {
|
||||
pointer operator->() const {
|
||||
const auto pos = size_type(index-1);
|
||||
return &(*direct)[pos];
|
||||
}
|
||||
|
||||
reference operator*() const ENTT_NOEXCEPT {
|
||||
reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
direct_type *direct;
|
||||
const direct_type *direct;
|
||||
index_type index;
|
||||
};
|
||||
|
||||
void assure(const std::size_t page) {
|
||||
if(!(page < reverse.size())) {
|
||||
reverse.resize(page+1);
|
||||
}
|
||||
|
||||
if(!reverse[page]) {
|
||||
reverse[page] = std::make_unique<entity_type[]>(entt_per_page);
|
||||
// null is safe in all cases for our purposes
|
||||
std::fill_n(reverse[page].get(), entt_per_page, null);
|
||||
}
|
||||
auto page(const Entity entt) const ENTT_NOEXCEPT {
|
||||
return std::size_t{(to_integral(entt) & traits_type::entity_mask) / entt_per_page};
|
||||
}
|
||||
|
||||
auto map(const Entity entt) const ENTT_NOEXCEPT {
|
||||
const auto identifier = to_integer(entt) & traits_type::entity_mask;
|
||||
const auto page = size_type(identifier / entt_per_page);
|
||||
const auto offset = size_type(identifier & (entt_per_page - 1));
|
||||
return std::make_pair(page, offset);
|
||||
auto offset(const Entity entt) const ENTT_NOEXCEPT {
|
||||
return std::size_t{to_integral(entt) & (entt_per_page - 1)};
|
||||
}
|
||||
|
||||
Entity * assure(const std::size_t pos) {
|
||||
if(!(pos < reverse.size())) {
|
||||
reverse.resize(pos+1);
|
||||
}
|
||||
|
||||
if(!reverse[pos]) {
|
||||
reverse[pos] = std::make_unique<entity_type[]>(entt_per_page);
|
||||
// null is safe in all cases for our purposes
|
||||
std::fill_n(reverse[pos].get(), entt_per_page, null);
|
||||
}
|
||||
|
||||
return reverse[pos].get();
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -194,8 +196,7 @@ public:
|
||||
{
|
||||
for(size_type pos{}, last = other.reverse.size(); pos < last; ++pos) {
|
||||
if(other.reverse[pos]) {
|
||||
assure(pos);
|
||||
std::copy_n(other.reverse[pos].get(), entt_per_page, reverse[pos].get());
|
||||
std::copy_n(other.reverse[pos].get(), entt_per_page, assure(pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,7 +205,7 @@ public:
|
||||
sparse_set(sparse_set &&) = default;
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
virtual ~sparse_set() ENTT_NOEXCEPT = default;
|
||||
virtual ~sparse_set() = default;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
@@ -352,7 +353,7 @@ public:
|
||||
* @return An iterator to the given entity if it's found, past the end
|
||||
* iterator otherwise.
|
||||
*/
|
||||
iterator_type find(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
iterator_type find(const entity_type entt) const {
|
||||
return has(entt) ? --(end() - index(entt)) : end();
|
||||
}
|
||||
|
||||
@@ -361,10 +362,10 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return True if the sparse set contains the entity, false otherwise.
|
||||
*/
|
||||
bool has(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
auto [page, offset] = map(entt);
|
||||
bool has(const entity_type entt) const {
|
||||
const auto curr = page(entt);
|
||||
// testing against null permits to avoid accessing the direct vector
|
||||
return (page < reverse.size() && reverse[page] && reverse[page][offset] != null);
|
||||
return (curr < reverse.size() && reverse[curr] && reverse[curr][offset(entt)] != null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -379,10 +380,9 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return The position of the entity in the sparse set.
|
||||
*/
|
||||
size_type index(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
size_type index(const entity_type entt) const {
|
||||
ENTT_ASSERT(has(entt));
|
||||
auto [page, offset] = map(entt);
|
||||
return size_type(reverse[page][offset]);
|
||||
return size_type(reverse[page(entt)][offset(entt)]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -398,9 +398,7 @@ public:
|
||||
*/
|
||||
void construct(const entity_type entt) {
|
||||
ENTT_ASSERT(!has(entt));
|
||||
auto [page, offset] = map(entt);
|
||||
assure(page);
|
||||
reverse[page][offset] = entity_type(direct.size());
|
||||
assure(page(entt))[offset(entt)] = entity_type(direct.size());
|
||||
direct.push_back(entt);
|
||||
}
|
||||
|
||||
@@ -413,17 +411,15 @@ public:
|
||||
* An assertion will abort the execution at runtime in debug mode if the
|
||||
* sparse set already contains the given entity.
|
||||
*
|
||||
* @tparam It Type of forward iterator.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
*/
|
||||
template<typename It>
|
||||
void batch(It first, It last) {
|
||||
void construct(It first, It last) {
|
||||
std::for_each(first, last, [this, next = direct.size()](const auto entt) mutable {
|
||||
ENTT_ASSERT(!has(entt));
|
||||
auto [page, offset] = map(entt);
|
||||
assure(page);
|
||||
reverse[page][offset] = entity_type(next++);
|
||||
assure(page(entt))[offset(entt)] = entity_type(next++);
|
||||
});
|
||||
|
||||
direct.insert(direct.end(), first, last);
|
||||
@@ -442,11 +438,11 @@ public:
|
||||
*/
|
||||
void destroy(const entity_type entt) {
|
||||
ENTT_ASSERT(has(entt));
|
||||
auto [from_page, from_offset] = map(entt);
|
||||
auto [to_page, to_offset] = map(direct.back());
|
||||
direct[size_type(reverse[from_page][from_offset])] = entity_type(direct.back());
|
||||
reverse[to_page][to_offset] = reverse[from_page][from_offset];
|
||||
reverse[from_page][from_offset] = null;
|
||||
const auto curr = page(entt);
|
||||
const auto pos = offset(entt);
|
||||
direct[size_type(reverse[curr][pos])] = entity_type(direct.back());
|
||||
reverse[page(direct.back())][offset(direct.back())] = reverse[curr][pos];
|
||||
reverse[curr][pos] = null;
|
||||
direct.pop_back();
|
||||
}
|
||||
|
||||
@@ -465,11 +461,9 @@ public:
|
||||
* @param lhs A valid entity identifier.
|
||||
* @param rhs A valid entity identifier.
|
||||
*/
|
||||
virtual void swap(const entity_type lhs, const entity_type rhs) ENTT_NOEXCEPT {
|
||||
auto [src_page, src_offset] = map(lhs);
|
||||
auto [dst_page, dst_offset] = map(rhs);
|
||||
auto &from = reverse[src_page][src_offset];
|
||||
auto &to = reverse[dst_page][dst_offset];
|
||||
virtual void swap(const entity_type lhs, const entity_type rhs) {
|
||||
auto &from = reverse[page(lhs)][offset(lhs)];
|
||||
auto &to = reverse[page(rhs)][offset(rhs)];
|
||||
std::swap(direct[size_type(from)], direct[size_type(to)]);
|
||||
std::swap(from, to);
|
||||
}
|
||||
@@ -526,8 +520,7 @@ public:
|
||||
algo(from, to, std::move(compare), std::forward<Args>(args)...);
|
||||
|
||||
for(size_type pos = skip, end = skip+length; pos < end; ++pos) {
|
||||
auto [page, offset] = map(direct[pos]);
|
||||
reverse[page][offset] = entity_type(pos);
|
||||
reverse[page(direct[pos])][offset(direct[pos])] = entity_type(pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,8 +569,7 @@ public:
|
||||
|
||||
while(curr != next) {
|
||||
apply(direct[curr], direct[next]);
|
||||
auto [page, offset] = map(direct[curr]);
|
||||
reverse[page][offset] = entity_type(curr);
|
||||
reverse[page(direct[curr])][offset(direct[curr])] = entity_type(curr);
|
||||
|
||||
curr = next;
|
||||
next = index(direct[curr]);
|
||||
@@ -605,7 +597,7 @@ public:
|
||||
*
|
||||
* @param other The sparse sets that imposes the order of the entities.
|
||||
*/
|
||||
void respect(const sparse_set &other) ENTT_NOEXCEPT {
|
||||
void respect(const sparse_set &other) {
|
||||
const auto to = other.end();
|
||||
auto from = other.begin();
|
||||
|
||||
@@ -625,9 +617,9 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets a sparse set.
|
||||
* @brief Clears a sparse set.
|
||||
*/
|
||||
void reset() {
|
||||
void clear() ENTT_NOEXCEPT {
|
||||
reverse.clear();
|
||||
direct.clear();
|
||||
}
|
||||
@@ -641,4 +633,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_SPARSE_SET_HPP
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
@@ -48,13 +47,13 @@ namespace entt {
|
||||
* @tparam Type Type of objects assigned to the entities.
|
||||
*/
|
||||
template<typename Entity, typename Type, typename = std::void_t<>>
|
||||
class basic_storage: public sparse_set<Entity> {
|
||||
class storage: public sparse_set<Entity> {
|
||||
using underlying_type = sparse_set<Entity>;
|
||||
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
|
||||
|
||||
template<bool Const>
|
||||
class iterator {
|
||||
friend class basic_storage<Entity, Type>;
|
||||
friend class storage<Entity, Type>;
|
||||
|
||||
using instance_type = std::conditional_t<Const, const std::vector<Type>, std::vector<Type>>;
|
||||
using index_type = typename traits_type::difference_type;
|
||||
@@ -78,7 +77,7 @@ class basic_storage: public sparse_set<Entity> {
|
||||
|
||||
iterator operator++(int) ENTT_NOEXCEPT {
|
||||
iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
return operator++(), orig;
|
||||
}
|
||||
|
||||
iterator & operator--() ENTT_NOEXCEPT {
|
||||
@@ -87,7 +86,7 @@ class basic_storage: public sparse_set<Entity> {
|
||||
|
||||
iterator operator--(int) ENTT_NOEXCEPT {
|
||||
iterator orig = *this;
|
||||
return --(*this), orig;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
|
||||
@@ -277,12 +276,12 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return The object associated with the entity.
|
||||
*/
|
||||
const object_type & get(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
const object_type & get(const entity_type entt) const {
|
||||
return instances[underlying_type::index(entt)];
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
object_type & get(const entity_type entt) ENTT_NOEXCEPT {
|
||||
object_type & get(const entity_type entt) {
|
||||
return const_cast<object_type &>(std::as_const(*this).get(entt));
|
||||
}
|
||||
|
||||
@@ -291,12 +290,12 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return The object associated with the entity, if any.
|
||||
*/
|
||||
const object_type * try_get(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
const object_type * try_get(const entity_type entt) const {
|
||||
return underlying_type::has(entt) ? (instances.data() + underlying_type::index(entt)) : nullptr;
|
||||
}
|
||||
|
||||
/*! @copydoc try_get */
|
||||
object_type * try_get(const entity_type entt) ENTT_NOEXCEPT {
|
||||
object_type * try_get(const entity_type entt) {
|
||||
return const_cast<object_type *>(std::as_const(*this).try_get(entt));
|
||||
}
|
||||
|
||||
@@ -316,27 +315,22 @@ public:
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param entt A valid entity identifier.
|
||||
* @param args Parameters to use to construct an object for the entity.
|
||||
* @return The object associated with the entity.
|
||||
*/
|
||||
template<typename... Args>
|
||||
object_type & construct(const entity_type entt, Args &&... args) {
|
||||
void construct(const entity_type entt, Args &&... args) {
|
||||
if constexpr(std::is_aggregate_v<object_type>) {
|
||||
instances.emplace_back(Type{std::forward<Args>(args)...});
|
||||
instances.push_back(Type{std::forward<Args>(args)...});
|
||||
} else {
|
||||
instances.emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// entity goes after component in case constructor throws
|
||||
underlying_type::construct(entt);
|
||||
return instances.back();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns one or more entities to a storage and default constructs
|
||||
* or copy constructs their objects.
|
||||
*
|
||||
* The object type must be at least move and default insertable if no
|
||||
* arguments are provided, move and copy insertable otherwise.
|
||||
* @brief Assigns one or more entities to a storage and constructs their
|
||||
* objects with from a given instance.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to assign an entity that already belongs to the storage
|
||||
@@ -344,25 +338,37 @@ public:
|
||||
* An assertion will abort the execution at runtime in debug mode if the
|
||||
* storage already contains the given entity.
|
||||
*
|
||||
* @tparam It Type of forward iterator.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @param args Parameters to use to construct an object for the entities.
|
||||
* @return An iterator to the list of instances just created and sorted the
|
||||
* same of the entities.
|
||||
* @param value An instance of the object to construct.
|
||||
*/
|
||||
template<typename It, typename... Args>
|
||||
iterator_type batch(It first, It last, Args &&... args) {
|
||||
if constexpr(sizeof...(Args) == 0) {
|
||||
instances.resize(instances.size() + std::distance(first, last));
|
||||
} else {
|
||||
instances.resize(instances.size() + std::distance(first, last), Type{std::forward<Args>(args)...});
|
||||
}
|
||||
template<typename It>
|
||||
std::enable_if_t<std::is_same_v<typename std::iterator_traits<It>::value_type, entity_type>, void>
|
||||
construct(It first, It last, const object_type &value = {}) {
|
||||
instances.insert(instances.end(), std::distance(first, last), value);
|
||||
// entities go after components in case constructors throw
|
||||
underlying_type::construct(first, last);
|
||||
}
|
||||
|
||||
// entity goes after component in case constructor throws
|
||||
underlying_type::batch(first, last);
|
||||
return begin();
|
||||
/**
|
||||
* @brief Assigns one or more entities to a storage and constructs their
|
||||
* objects from a given range.
|
||||
*
|
||||
* @sa construct
|
||||
*
|
||||
* @tparam EIt Type of input iterator.
|
||||
* @tparam CIt Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @param value An iterator to the first element of the range of objects.
|
||||
*/
|
||||
template<typename EIt, typename CIt>
|
||||
std::enable_if_t<std::is_same_v<typename std::iterator_traits<EIt>::value_type, entity_type>, void>
|
||||
construct(EIt first, EIt last, CIt value) {
|
||||
instances.insert(instances.end(), value, value + std::distance(first, last));
|
||||
// entities go after components in case constructors throw
|
||||
underlying_type::construct(first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,7 +401,7 @@ public:
|
||||
* @param lhs A valid entity identifier.
|
||||
* @param rhs A valid entity identifier.
|
||||
*/
|
||||
void swap(const entity_type lhs, const entity_type rhs) ENTT_NOEXCEPT override {
|
||||
void swap(const entity_type lhs, const entity_type rhs) override {
|
||||
std::swap(instances[underlying_type::index(lhs)], instances[underlying_type::index(rhs)]);
|
||||
underlying_type::swap(lhs, rhs);
|
||||
}
|
||||
@@ -466,9 +472,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Resets a storage. */
|
||||
void reset() {
|
||||
underlying_type::reset();
|
||||
/*! @brief Clears a storage. */
|
||||
void clear() {
|
||||
underlying_type::clear();
|
||||
instances.clear();
|
||||
}
|
||||
|
||||
@@ -477,14 +483,14 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/*! @copydoc basic_storage */
|
||||
/*! @copydoc storage */
|
||||
template<typename Entity, typename Type>
|
||||
class basic_storage<Entity, Type, std::enable_if_t<ENTT_ENABLE_ETO(Type)>>: public sparse_set<Entity> {
|
||||
class storage<Entity, Type, std::enable_if_t<ENTT_ENABLE_ETO(Type)>>: public sparse_set<Entity> {
|
||||
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
|
||||
using underlying_type = sparse_set<Entity>;
|
||||
|
||||
class iterator {
|
||||
friend class basic_storage<Entity, Type>;
|
||||
friend class storage<Entity, Type>;
|
||||
|
||||
using index_type = typename traits_type::difference_type;
|
||||
|
||||
@@ -507,7 +513,7 @@ class basic_storage<Entity, Type, std::enable_if_t<ENTT_ENABLE_ETO(Type)>>: publ
|
||||
|
||||
iterator operator++(int) ENTT_NOEXCEPT {
|
||||
iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
return operator++(), orig;
|
||||
}
|
||||
|
||||
iterator & operator--() ENTT_NOEXCEPT {
|
||||
@@ -516,7 +522,7 @@ class basic_storage<Entity, Type, std::enable_if_t<ENTT_ENABLE_ETO(Type)>>: publ
|
||||
|
||||
iterator operator--(int) ENTT_NOEXCEPT {
|
||||
iterator orig = *this;
|
||||
return --(*this), orig;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
|
||||
@@ -651,15 +657,30 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return The object associated with the entity.
|
||||
*/
|
||||
object_type get([[maybe_unused]] const entity_type entt) const ENTT_NOEXCEPT {
|
||||
object_type get([[maybe_unused]] const entity_type entt) const {
|
||||
ENTT_ASSERT(underlying_type::has(entt));
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns one or more entities to a storage.
|
||||
* @brief Assigns an entity to a storage and constructs its object.
|
||||
*
|
||||
* The object type must be at least default constructible.
|
||||
* @warning
|
||||
* Attempting to use an entity that already belongs to the storage results
|
||||
* in undefined behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode if the
|
||||
* storage already contains the given entity.
|
||||
*
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param entt A valid entity identifier.
|
||||
*/
|
||||
template<typename... Args>
|
||||
void construct(const entity_type entt, Args &&...) {
|
||||
underlying_type::construct(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns one or more entities to a storage.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to assign an entity that already belongs to the storage
|
||||
@@ -667,16 +688,14 @@ public:
|
||||
* An assertion will abort the execution at runtime in debug mode if the
|
||||
* storage already contains the given entity.
|
||||
*
|
||||
* @tparam It Type of forward iterator.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @return An iterator to the list of instances just created and sorted the
|
||||
* same of the entities.
|
||||
*/
|
||||
template<typename It>
|
||||
iterator_type batch(It first, It last, const object_type & = {}) {
|
||||
underlying_type::batch(first, last);
|
||||
return begin();
|
||||
std::enable_if_t<std::is_same_v<typename std::iterator_traits<It>::value_type, entity_type>, void>
|
||||
construct(It first, It last, const object_type & = {}) {
|
||||
underlying_type::construct(first, last);
|
||||
}
|
||||
|
||||
/*! @copydoc storage::sort */
|
||||
@@ -692,12 +711,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/*! @copydoc basic_storage */
|
||||
template<typename Entity, typename Type>
|
||||
struct storage: basic_storage<Entity, Type> {};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_STORAGE_HPP
|
||||
#endif
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#ifndef ENTT_ENTITY_UTILITY_HPP
|
||||
#define ENTT_ENTITY_UTILITY_HPP
|
||||
|
||||
|
||||
#include "../core/type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct exclude_t: type_list<Type...> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Variable template for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
constexpr exclude_t<Type...> exclude{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias for lists of observed components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct get_t: type_list<Type...>{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Variable template for lists of observed components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
constexpr get_t<Type...> get{};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_UTILITY_HPP
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "sparse_set.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
@@ -35,11 +34,8 @@ class basic_view;
|
||||
*
|
||||
* Multi component views iterate over those entities that have at least all the
|
||||
* given components in their bags. During initialization, a multi component view
|
||||
* looks at the number of entities available for each component and picks up a
|
||||
* reference to the smallest set of candidate entities in order to get a
|
||||
* performance boost when iterate.<br/>
|
||||
* Order of elements during iterations are highly dependent on the order of the
|
||||
* underlying data structures. See sparse_set for more details.
|
||||
* looks at the number of entities available for each component and uses the
|
||||
* smallest set in order to get a performance boost when iterate.
|
||||
*
|
||||
* @b Important
|
||||
*
|
||||
@@ -50,9 +46,8 @@ class basic_view;
|
||||
* given components is removed from the entity to which the iterator points).
|
||||
* * The entity currently pointed is destroyed.
|
||||
*
|
||||
* In all the other cases, modifying the pools of the given components in any
|
||||
* way invalidates all the iterators and using them results in undefined
|
||||
* behavior.
|
||||
* In all other cases, modifying the pools iterated by the view in any way
|
||||
* invalidates all the iterators and using them results in undefined behavior.
|
||||
*
|
||||
* @note
|
||||
* Views share references to the underlying data structures of the registry that
|
||||
@@ -81,24 +76,25 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
using underlying_iterator_type = typename sparse_set<Entity>::iterator_type;
|
||||
using unchecked_type = std::array<const sparse_set<Entity> *, (sizeof...(Component) - 1)>;
|
||||
using filter_type = std::array<const sparse_set<Entity> *, sizeof...(Exclude)>;
|
||||
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
|
||||
|
||||
class iterator {
|
||||
friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
|
||||
|
||||
iterator(underlying_iterator_type first, underlying_iterator_type last, unchecked_type other, filter_type ignore) ENTT_NOEXCEPT
|
||||
: begin{first},
|
||||
end{last},
|
||||
iterator(const sparse_set<Entity> *candidate, unchecked_type other, filter_type ignore, underlying_iterator_type curr) ENTT_NOEXCEPT
|
||||
: view{candidate},
|
||||
unchecked{other},
|
||||
filter{ignore}
|
||||
filter{ignore},
|
||||
it{curr}
|
||||
{
|
||||
if(begin != end && !valid()) {
|
||||
if(it != view->end() && !valid()) {
|
||||
++(*this);
|
||||
}
|
||||
}
|
||||
|
||||
bool valid() const ENTT_NOEXCEPT {
|
||||
return std::all_of(unchecked.cbegin(), unchecked.cend(), [this](const sparse_set<Entity> *view) { return view->has(*begin); })
|
||||
&& std::none_of(filter.cbegin(), filter.cend(), [this](const sparse_set<Entity> *view) { return view->has(*begin); });
|
||||
bool valid() const {
|
||||
return std::all_of(unchecked.cbegin(), unchecked.cend(), [entt = *it](const sparse_set<Entity> *curr) { return curr->has(entt); })
|
||||
&& std::none_of(filter.cbegin(), filter.cend(), [entt = *it](const sparse_set<Entity> *curr) { return curr->has(entt); });
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -106,46 +102,56 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
using value_type = typename underlying_iterator_type::value_type;
|
||||
using pointer = typename underlying_iterator_type::pointer;
|
||||
using reference = typename underlying_iterator_type::reference;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
|
||||
iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
iterator & operator++() ENTT_NOEXCEPT {
|
||||
return (++begin != end && !valid()) ? ++(*this) : *this;
|
||||
iterator & operator++() {
|
||||
while(++it != view->end() && !valid());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) ENTT_NOEXCEPT {
|
||||
iterator operator++(int) {
|
||||
iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
return operator++(), orig;
|
||||
}
|
||||
|
||||
iterator & operator--() ENTT_NOEXCEPT {
|
||||
while(--it != view->begin() && !valid());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator--(int) ENTT_NOEXCEPT {
|
||||
iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
bool operator==(const iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.begin == begin;
|
||||
return other.it == it;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
pointer operator->() const ENTT_NOEXCEPT {
|
||||
return begin.operator->();
|
||||
pointer operator->() const {
|
||||
return it.operator->();
|
||||
}
|
||||
|
||||
reference operator*() const ENTT_NOEXCEPT {
|
||||
reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
underlying_iterator_type begin;
|
||||
underlying_iterator_type end;
|
||||
const sparse_set<Entity> *view;
|
||||
unchecked_type unchecked;
|
||||
filter_type filter;
|
||||
underlying_iterator_type it;
|
||||
};
|
||||
|
||||
// we could use pool_type<Component> *..., but vs complains about it and refuses to compile for unknown reasons (likely a bug)
|
||||
basic_view(storage<Entity, std::remove_const_t<Component>> *... component, storage<Entity, std::remove_const_t<Exclude>> *... epool) ENTT_NOEXCEPT
|
||||
: pools{component...},
|
||||
filter{epool...}
|
||||
// we could use pool_type<Component> &..., but vs complains about it and refuses to compile for unknown reasons (likely a bug)
|
||||
basic_view(storage<Entity, std::remove_const_t<Component>> &... component, storage<Entity, std::remove_const_t<Exclude>> &... epool) ENTT_NOEXCEPT
|
||||
: pools{&component..., &epool...}
|
||||
{}
|
||||
|
||||
const sparse_set<Entity> * candidate() const ENTT_NOEXCEPT {
|
||||
@@ -154,7 +160,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
});
|
||||
}
|
||||
|
||||
unchecked_type unchecked(const sparse_set<Entity> *view) const ENTT_NOEXCEPT {
|
||||
unchecked_type unchecked(const sparse_set<Entity> *view) const {
|
||||
std::size_t pos{};
|
||||
unchecked_type other{};
|
||||
((std::get<pool_type<Component> *>(pools) == view ? nullptr : (other[pos++] = std::get<pool_type<Component> *>(pools))), ...);
|
||||
@@ -162,7 +168,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
}
|
||||
|
||||
template<typename Comp, typename Other>
|
||||
decltype(auto) get([[maybe_unused]] component_iterator_type<Comp> it, [[maybe_unused]] pool_type<Other> *cpool, [[maybe_unused]] const Entity entt) const ENTT_NOEXCEPT {
|
||||
decltype(auto) get([[maybe_unused]] component_iterator_type<Comp> it, [[maybe_unused]] pool_type<Other> *cpool, [[maybe_unused]] const Entity entt) const {
|
||||
if constexpr(std::is_same_v<Comp, Other>) {
|
||||
return *it;
|
||||
} else {
|
||||
@@ -170,33 +176,32 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Comp, typename Func, typename... Other, typename... Type>
|
||||
void traverse(Func func, type_list<Other...>, type_list<Type...>) const {
|
||||
const auto end = std::get<pool_type<Comp> *>(pools)->sparse_set<Entity>::end();
|
||||
auto begin = std::get<pool_type<Comp> *>(pools)->sparse_set<Entity>::begin();
|
||||
|
||||
template<typename Comp, typename Func, typename... Type>
|
||||
void traverse(Func func, type_list<Type...>) const {
|
||||
if constexpr(std::disjunction_v<std::is_same<Comp, Type>...>) {
|
||||
std::for_each(begin, end, [this, raw = std::get<pool_type<Comp> *>(pools)->begin(), &func](const auto entity) mutable {
|
||||
auto curr = raw++;
|
||||
auto it = std::get<pool_type<Comp> *>(pools)->begin();
|
||||
|
||||
if((std::get<pool_type<Other> *>(pools)->has(entity) && ...) && (!std::get<pool_type<Exclude> *>(filter)->has(entity) && ...)) {
|
||||
for(const auto entt: static_cast<const sparse_set<entity_type> &>(*std::get<pool_type<Comp> *>(pools))) {
|
||||
auto curr = it++;
|
||||
|
||||
if(((std::is_same_v<Comp, Component> || std::get<pool_type<Component> *>(pools)->has(entt)) && ...) && (!std::get<pool_type<Exclude> *>(pools)->has(entt) && ...)) {
|
||||
if constexpr(std::is_invocable_v<Func, decltype(get<Type>({}))...>) {
|
||||
func(get<Comp, Type>(curr, std::get<pool_type<Type> *>(pools), entity)...);
|
||||
func(get<Comp, Type>(curr, std::get<pool_type<Type> *>(pools), entt)...);
|
||||
} else {
|
||||
func(entity, get<Comp, Type>(curr, std::get<pool_type<Type> *>(pools), entity)...);
|
||||
func(entt, get<Comp, Type>(curr, std::get<pool_type<Type> *>(pools), entt)...);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
std::for_each(begin, end, [this, &func](const auto entity) {
|
||||
if((std::get<pool_type<Other> *>(pools)->has(entity) && ...) && (!std::get<pool_type<Exclude> *>(filter)->has(entity) && ...)) {
|
||||
for(const auto entt: static_cast<const sparse_set<entity_type> &>(*std::get<pool_type<Comp> *>(pools))) {
|
||||
if(((std::is_same_v<Comp, Component> || std::get<pool_type<Component> *>(pools)->has(entt)) && ...) && (!std::get<pool_type<Exclude> *>(pools)->has(entt) && ...)) {
|
||||
if constexpr(std::is_invocable_v<Func, decltype(get<Type>({}))...>) {
|
||||
func(std::get<pool_type<Type> *>(pools)->get(entity)...);
|
||||
func(std::get<pool_type<Type> *>(pools)->get(entt)...);
|
||||
} else {
|
||||
func(entity, std::get<pool_type<Type> *>(pools)->get(entity)...);
|
||||
func(entt, std::get<pool_type<Type> *>(pools)->get(entt)...);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,16 +235,14 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether the view or the pools of the given components are
|
||||
* empty.
|
||||
* @brief Checks whether a view or some pools are empty.
|
||||
*
|
||||
* The view is definitely empty if one of the pools of the given components
|
||||
* is empty. In all other cases, the view may be empty and not return
|
||||
* entities even if this function returns false.
|
||||
* The view is definitely empty if one of the pools it uses is empty. In all
|
||||
* other cases, the view may be empty and not return entities even if this
|
||||
* function returns false.
|
||||
*
|
||||
* @tparam Comp Types of components in which one is interested.
|
||||
* @return True if the view or the pools of the given components are empty,
|
||||
* false otherwise.
|
||||
* @return True if the view or the pools are empty, false otherwise.
|
||||
*/
|
||||
template<typename... Comp>
|
||||
bool empty() const ENTT_NOEXCEPT {
|
||||
@@ -302,10 +305,10 @@ public:
|
||||
*
|
||||
* @return An iterator to the first entity that has the given components.
|
||||
*/
|
||||
iterator_type begin() const ENTT_NOEXCEPT {
|
||||
iterator_type begin() const {
|
||||
const auto *view = candidate();
|
||||
const filter_type ignore{std::get<pool_type<Exclude> *>(filter)...};
|
||||
return iterator_type{view->begin(), view->end(), unchecked(view), ignore};
|
||||
const filter_type ignore{std::get<pool_type<Exclude> *>(pools)...};
|
||||
return iterator_type{view, unchecked(view), ignore, view->begin()};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,10 +326,30 @@ public:
|
||||
* @return An iterator to the entity following the last entity that has the
|
||||
* given components.
|
||||
*/
|
||||
iterator_type end() const ENTT_NOEXCEPT {
|
||||
iterator_type end() const {
|
||||
const auto *view = candidate();
|
||||
const filter_type ignore{std::get<pool_type<Exclude> *>(filter)...};
|
||||
return iterator_type{view->end(), view->end(), unchecked(view), ignore};
|
||||
const filter_type ignore{std::get<pool_type<Exclude> *>(pools)...};
|
||||
return iterator_type{view, unchecked(view), ignore, view->end()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the first entity that has the given components, if any.
|
||||
* @return The first entity that has the given components if one exists, the
|
||||
* null entity otherwise.
|
||||
*/
|
||||
entity_type front() const {
|
||||
const auto it = begin();
|
||||
return it != end() ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last entity that has the given components, if any.
|
||||
* @return The last entity that has the given components if one exists, the
|
||||
* null entity otherwise.
|
||||
*/
|
||||
entity_type back() const {
|
||||
const auto it = std::make_reverse_iterator(end());
|
||||
return it != std::make_reverse_iterator(begin()) ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,10 +358,10 @@ public:
|
||||
* @return An iterator to the given entity if it's found, past the end
|
||||
* iterator otherwise.
|
||||
*/
|
||||
iterator_type find(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
iterator_type find(const entity_type entt) const {
|
||||
const auto *view = candidate();
|
||||
const filter_type ignore{std::get<pool_type<Exclude> *>(filter)...};
|
||||
iterator_type it{view->find(entt), view->end(), unchecked(view), ignore};
|
||||
const filter_type ignore{std::get<pool_type<Exclude> *>(pools)...};
|
||||
iterator_type it{view, unchecked(view), ignore, view->find(entt)};
|
||||
return (it != end() && *it == entt) ? it : end();
|
||||
}
|
||||
|
||||
@@ -347,15 +370,16 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return True if the view contains the given entity, false otherwise.
|
||||
*/
|
||||
bool contains(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
return find(entt) != end();
|
||||
bool contains(const entity_type entt) const {
|
||||
return (std::get<pool_type<Component> *>(pools)->has(entt) && ...)
|
||||
&& (!std::get<pool_type<Exclude> *>(pools)->has(entt) && ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the components assigned to the given entity.
|
||||
*
|
||||
* Prefer this function instead of `registry::get` during iterations. It has
|
||||
* far better performance than its companion function.
|
||||
* far better performance than its counterpart.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an invalid component type results in a compilation
|
||||
@@ -369,7 +393,7 @@ public:
|
||||
* @return The components assigned to the entity.
|
||||
*/
|
||||
template<typename... Comp>
|
||||
decltype(auto) get([[maybe_unused]] const entity_type entt) const ENTT_NOEXCEPT {
|
||||
decltype(auto) get([[maybe_unused]] const entity_type entt) const {
|
||||
ENTT_ASSERT(contains(entt));
|
||||
|
||||
if constexpr(sizeof...(Comp) == 0) {
|
||||
@@ -443,8 +467,7 @@ public:
|
||||
*/
|
||||
template<typename Comp, typename Func>
|
||||
void each(Func func) const {
|
||||
using other_type = type_list_cat_t<std::conditional_t<std::is_same_v<Comp, Component>, type_list<>, type_list<Component>>...>;
|
||||
traverse<Comp>(std::move(func), other_type{}, type_list<Component...>{});
|
||||
traverse<Comp>(std::move(func), type_list<Component...>{});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -502,14 +525,12 @@ public:
|
||||
*/
|
||||
template<typename Comp, typename Func>
|
||||
void less(Func func) const {
|
||||
using other_type = type_list_cat_t<std::conditional_t<std::is_same_v<Comp, Component>, type_list<>, type_list<Component>>...>;
|
||||
using non_empty_type = type_list_cat_t<std::conditional_t<ENTT_ENABLE_ETO(Component), type_list<>, type_list<Component>>...>;
|
||||
traverse<Comp>(std::move(func), other_type{}, non_empty_type{});
|
||||
traverse<Comp>(std::move(func), non_empty_type{});
|
||||
}
|
||||
|
||||
private:
|
||||
const std::tuple<pool_type<Component> *...> pools;
|
||||
const std::tuple<pool_type<Exclude> *...> filter;
|
||||
const std::tuple<pool_type<Component> *..., pool_type<Exclude> *...> pools;
|
||||
};
|
||||
|
||||
|
||||
@@ -518,9 +539,7 @@ private:
|
||||
*
|
||||
* Single component views are specialized in order to get a boost in terms of
|
||||
* performance. This kind of views can access the underlying data structure
|
||||
* directly and avoid superfluous checks.<br/>
|
||||
* Order of elements during iterations are highly dependent on the order of the
|
||||
* underlying data structure. See sparse_set for more details.
|
||||
* directly and avoid superfluous checks.
|
||||
*
|
||||
* @b Important
|
||||
*
|
||||
@@ -531,7 +550,7 @@ private:
|
||||
* component is removed from the entity to which the iterator points).
|
||||
* * The entity currently pointed is destroyed.
|
||||
*
|
||||
* In all the other cases, modifying the pool of the given component in any way
|
||||
* In all other cases, modifying the pool iterated by the view in any way
|
||||
* invalidates all the iterators and using them results in undefined behavior.
|
||||
*
|
||||
* @note
|
||||
@@ -553,8 +572,8 @@ class basic_view<Entity, exclude_t<>, Component> {
|
||||
|
||||
using pool_type = std::conditional_t<std::is_const_v<Component>, const storage<Entity, std::remove_const_t<Component>>, storage<Entity, Component>>;
|
||||
|
||||
basic_view(pool_type *ref) ENTT_NOEXCEPT
|
||||
: pool{ref}
|
||||
basic_view(pool_type &ref) ENTT_NOEXCEPT
|
||||
: pool{&ref}
|
||||
{}
|
||||
|
||||
public:
|
||||
@@ -576,7 +595,7 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether the view is empty.
|
||||
* @brief Checks whether a view is empty.
|
||||
* @return True if the view is empty, false otherwise.
|
||||
*/
|
||||
bool empty() const ENTT_NOEXCEPT {
|
||||
@@ -652,13 +671,33 @@ public:
|
||||
return pool->sparse_set<Entity>::end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the first entity that has the given component, if any.
|
||||
* @return The first entity that has the given component if one exists, the
|
||||
* null entity otherwise.
|
||||
*/
|
||||
entity_type front() const {
|
||||
const auto it = begin();
|
||||
return it != end() ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last entity that has the given component, if any.
|
||||
* @return The last entity that has the given component if one exists, the
|
||||
* null entity otherwise.
|
||||
*/
|
||||
entity_type back() const {
|
||||
const auto it = std::make_reverse_iterator(end());
|
||||
return it != std::make_reverse_iterator(begin()) ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an entity.
|
||||
* @param entt A valid entity identifier.
|
||||
* @return An iterator to the given entity if it's found, past the end
|
||||
* iterator otherwise.
|
||||
*/
|
||||
iterator_type find(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
iterator_type find(const entity_type entt) const {
|
||||
const auto it = pool->find(entt);
|
||||
return it != end() && *it == entt ? it : end();
|
||||
}
|
||||
@@ -668,7 +707,7 @@ public:
|
||||
* @param pos Position of the element to return.
|
||||
* @return The identifier that occupies the given position.
|
||||
*/
|
||||
entity_type operator[](const size_type pos) const ENTT_NOEXCEPT {
|
||||
entity_type operator[](const size_type pos) const {
|
||||
return begin()[pos];
|
||||
}
|
||||
|
||||
@@ -677,15 +716,15 @@ public:
|
||||
* @param entt A valid entity identifier.
|
||||
* @return True if the view contains the given entity, false otherwise.
|
||||
*/
|
||||
bool contains(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
return find(entt) != end();
|
||||
bool contains(const entity_type entt) const {
|
||||
return pool->has(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the component assigned to the given entity.
|
||||
*
|
||||
* Prefer this function instead of `registry::get` during iterations. It has
|
||||
* far better performance than its companion function.
|
||||
* far better performance than its counterpart.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an entity that doesn't belong to the view results in
|
||||
@@ -697,7 +736,7 @@ public:
|
||||
* @return The component assigned to the entity.
|
||||
*/
|
||||
template<typename Comp = Component>
|
||||
decltype(auto) get(const entity_type entt) const ENTT_NOEXCEPT {
|
||||
decltype(auto) get(const entity_type entt) const {
|
||||
static_assert(std::is_same_v<Comp, Component>);
|
||||
ENTT_ASSERT(contains(entt));
|
||||
return pool->get(entt);
|
||||
@@ -729,11 +768,15 @@ public:
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
if constexpr(std::is_invocable_v<Func, decltype(get({}))>) {
|
||||
std::for_each(pool->begin(), pool->end(), std::move(func));
|
||||
for(auto &&component: *pool) {
|
||||
func(component);
|
||||
}
|
||||
} else {
|
||||
std::for_each(pool->sparse_set<Entity>::begin(), pool->sparse_set<Entity>::end(), [&func, raw = pool->begin()](const auto entt) mutable {
|
||||
auto raw = pool->begin();
|
||||
|
||||
for(const auto entt: *this) {
|
||||
func(entt, *(raw++));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -773,7 +816,9 @@ public:
|
||||
func();
|
||||
}
|
||||
} else {
|
||||
std::for_each(pool->sparse_set<Entity>::begin(), pool->sparse_set<Entity>::end(), std::move(func));
|
||||
for(const auto entt: *this) {
|
||||
func(entt);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
each(std::move(func));
|
||||
@@ -788,4 +833,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_VIEW_HPP
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "core/algorithm.hpp"
|
||||
#include "core/attribute.h"
|
||||
#include "core/family.hpp"
|
||||
#include "core/hashed_string.hpp"
|
||||
#include "core/ident.hpp"
|
||||
#include "core/monostate.hpp"
|
||||
#include "core/type_info.hpp"
|
||||
#include "core/type_traits.hpp"
|
||||
#include "core/utility.hpp"
|
||||
#include "entity/actor.hpp"
|
||||
@@ -15,7 +17,6 @@
|
||||
#include "entity/snapshot.hpp"
|
||||
#include "entity/sparse_set.hpp"
|
||||
#include "entity/storage.hpp"
|
||||
#include "entity/utility.hpp"
|
||||
#include "entity/view.hpp"
|
||||
#include "locator/locator.hpp"
|
||||
#include "meta/factory.hpp"
|
||||
|
||||
@@ -108,4 +108,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_LOCATOR_LOCATOR_HPP
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "meta.hpp"
|
||||
|
||||
@@ -86,7 +87,7 @@ meta_any construct(meta_any * const args, std::index_sequence<Indexes...>) {
|
||||
|
||||
|
||||
template<bool Const, typename Type, auto Data>
|
||||
bool setter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index, [[maybe_unused]] meta_any value) {
|
||||
bool setter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any index, [[maybe_unused]] meta_any value) {
|
||||
bool accepted = false;
|
||||
|
||||
if constexpr(!Const) {
|
||||
@@ -94,7 +95,7 @@ bool setter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index
|
||||
using helper_type = meta_function_helper_t<decltype(Data)>;
|
||||
using data_type = std::tuple_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>;
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type &, data_type>);
|
||||
auto * const clazz = meta_any{handle}.try_cast<Type>();
|
||||
auto * const clazz = instance.try_cast<Type>();
|
||||
auto * const direct = value.try_cast<data_type>();
|
||||
|
||||
if(clazz && (direct || value.convert<data_type>())) {
|
||||
@@ -104,7 +105,7 @@ bool setter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type *>);
|
||||
auto * const clazz = meta_any{handle}.try_cast<Type>();
|
||||
auto * const clazz = instance.try_cast<Type>();
|
||||
|
||||
if constexpr(std::is_array_v<data_type>) {
|
||||
using underlying_type = std::remove_extent_t<data_type>;
|
||||
@@ -152,10 +153,10 @@ bool setter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index
|
||||
|
||||
|
||||
template<typename Type, auto Data, typename Policy>
|
||||
meta_any getter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index) {
|
||||
meta_any getter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any index) {
|
||||
auto dispatch = [](auto &&value) {
|
||||
if constexpr(std::is_same_v<Policy, as_void_t>) {
|
||||
return meta_any{std::in_place_type<void>};
|
||||
return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
|
||||
} else if constexpr(std::is_same_v<Policy, as_alias_t>) {
|
||||
return meta_any{std::ref(std::forward<decltype(value)>(value))};
|
||||
} else {
|
||||
@@ -166,12 +167,12 @@ meta_any getter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any i
|
||||
|
||||
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type &>);
|
||||
auto * const clazz = meta_any{handle}.try_cast<Type>();
|
||||
auto * const clazz = instance.try_cast<Type>();
|
||||
return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type *>);
|
||||
auto * const clazz = meta_any{handle}.try_cast<Type>();
|
||||
auto * const clazz = instance.try_cast<Type>();
|
||||
|
||||
if constexpr(std::is_array_v<data_type>) {
|
||||
auto * const idx = index.try_cast<std::size_t>();
|
||||
@@ -193,7 +194,7 @@ meta_any getter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any i
|
||||
|
||||
|
||||
template<typename Type, auto Candidate, typename Policy, std::size_t... Indexes>
|
||||
meta_any invoke([[maybe_unused]] meta_handle handle, meta_any *args, std::index_sequence<Indexes...>) {
|
||||
meta_any invoke([[maybe_unused]] meta_any instance, meta_any *args, std::index_sequence<Indexes...>) {
|
||||
using helper_type = meta_function_helper_t<decltype(Candidate)>;
|
||||
|
||||
auto dispatch = [](auto *... params) {
|
||||
@@ -208,20 +209,20 @@ meta_any invoke([[maybe_unused]] meta_handle handle, meta_any *args, std::index_
|
||||
}
|
||||
};
|
||||
|
||||
[[maybe_unused]] const auto direct = std::make_tuple([](meta_any *any, auto *instance) {
|
||||
using arg_type = std::remove_reference_t<decltype(*instance)>;
|
||||
[[maybe_unused]] const auto direct = std::make_tuple([](meta_any *any, auto *value) {
|
||||
using arg_type = std::remove_reference_t<decltype(*value)>;
|
||||
|
||||
if(!instance && any->convert<arg_type>()) {
|
||||
instance = any->try_cast<arg_type>();
|
||||
if(!value && any->convert<arg_type>()) {
|
||||
value = any->try_cast<arg_type>();
|
||||
}
|
||||
|
||||
return instance;
|
||||
return value;
|
||||
}(args+Indexes, (args+Indexes)->try_cast<std::tuple_element_t<Indexes, typename helper_type::args_type>>())...);
|
||||
|
||||
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Candidate)>>>) {
|
||||
return (std::get<Indexes>(direct) && ...) ? dispatch(std::get<Indexes>(direct)...) : meta_any{};
|
||||
} else {
|
||||
auto * const clazz = meta_any{handle}.try_cast<Type>();
|
||||
auto * const clazz = instance.try_cast<Type>();
|
||||
return (clazz && (std::get<Indexes>(direct) && ...)) ? dispatch(clazz, std::get<Indexes>(direct)...) : meta_any{};
|
||||
}
|
||||
}
|
||||
@@ -236,68 +237,173 @@ meta_any invoke([[maybe_unused]] meta_handle handle, meta_any *args, std::index_
|
||||
*/
|
||||
|
||||
|
||||
template<typename, typename...>
|
||||
class extended_meta_factory;
|
||||
/**
|
||||
* @brief Meta factory to be used for reflection purposes.
|
||||
*
|
||||
* The meta factory is an utility class used to reflect types, data members and
|
||||
* functions of all sorts. This class ensures that the underlying web of types
|
||||
* is built correctly and performs some checks in debug mode to ensure that
|
||||
* there are no subtle errors at runtime.
|
||||
*/
|
||||
template<typename...>
|
||||
class meta_factory;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A meta factory to be used for reflection purposes.
|
||||
*
|
||||
* A meta factory is an utility class used to reflect types, data and functions
|
||||
* of all sorts. This class ensures that the underlying web of types is built
|
||||
* correctly and performs some checks in debug mode to ensure that there are no
|
||||
* subtle errors at runtime.
|
||||
*
|
||||
* @brief Extended meta factory to be used for reflection purposes.
|
||||
* @tparam Type Reflected type for which the factory was created.
|
||||
* @tparam Spec Property specialization pack used to disambiguate overloads.
|
||||
*/
|
||||
template<typename Type>
|
||||
class meta_factory {
|
||||
template<typename Node>
|
||||
bool duplicate(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
|
||||
return node && (node == candidate || duplicate(candidate, node->next));
|
||||
template<typename Type, typename... Spec>
|
||||
class meta_factory<Type, Spec...>: public meta_factory<Type> {
|
||||
bool exists(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
|
||||
return node && (node->key() == key || exists(key, node->next));
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
bool duplicate(const ENTT_ID_TYPE identifier, const Node *node) ENTT_NOEXCEPT {
|
||||
return node && (node->identifier == identifier || duplicate(identifier, node->next));
|
||||
template<std::size_t Step = 0, std::size_t... Index, typename... Property, typename... Other>
|
||||
void unpack(std::index_sequence<Index...>, std::tuple<Property...> property, Other &&... other) {
|
||||
unroll<Step>(choice<3>, std::move(std::get<Index>(property))..., std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
auto record(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
|
||||
auto * const node = internal::meta_info<Type>::resolve();
|
||||
template<std::size_t Step = 0, typename... Property, typename... Other>
|
||||
void unroll(choice_t<3>, std::tuple<Property...> property, Other &&... other) {
|
||||
unpack<Step>(std::index_sequence_for<Property...>{}, std::move(property), std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
ENTT_ASSERT(!duplicate(identifier, *internal::meta_info<>::global));
|
||||
ENTT_ASSERT(!duplicate(node, *internal::meta_info<>::global));
|
||||
node->identifier = identifier;
|
||||
node->next = *internal::meta_info<>::global;
|
||||
*internal::meta_info<>::global = node;
|
||||
template<std::size_t Step = 0, typename... Property, typename... Other>
|
||||
void unroll(choice_t<2>, std::pair<Property...> property, Other &&... other) {
|
||||
assign<Step>(std::move(property.first), std::move(property.second));
|
||||
unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
return extended_meta_factory<Type>{&node->prop};
|
||||
template<std::size_t Step = 0, typename Property, typename... Other>
|
||||
std::enable_if_t<!std::is_invocable_v<Property>>
|
||||
unroll(choice_t<1>, Property &&property, Other &&... other) {
|
||||
assign<Step>(std::forward<Property>(property));
|
||||
unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, typename Func, typename... Other>
|
||||
void unroll(choice_t<0>, Func &&invocable, Other &&... other) {
|
||||
unroll<Step>(choice<3>, std::forward<Func>(invocable)(), std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t>
|
||||
void unroll(choice_t<0>) {}
|
||||
|
||||
template<std::size_t = 0, typename Key, typename... Value>
|
||||
void assign(Key &&key, Value &&... value) {
|
||||
static const auto property{std::make_tuple(std::forward<Key>(key), std::forward<Value>(value)...)};
|
||||
|
||||
static internal::meta_prop_node node{
|
||||
nullptr,
|
||||
[]() -> meta_any {
|
||||
return std::get<0>(property);
|
||||
},
|
||||
[]() -> meta_any {
|
||||
if constexpr(sizeof...(Value) == 0) {
|
||||
return {};
|
||||
} else {
|
||||
return std::get<1>(property);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!exists(node.key(), *curr));
|
||||
node.next = *curr;
|
||||
*curr = &node;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Extends a meta type by assigning it an identifier.
|
||||
*
|
||||
* This function is intended only for unnamed types.
|
||||
*
|
||||
* @param identifier Unique identifier.
|
||||
* @return An extended meta factory for the parent type.
|
||||
* @brief Constructs an extended factory from a given node.
|
||||
* @param target The underlying node to which to assign the properties.
|
||||
*/
|
||||
auto type(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
|
||||
static_assert(!is_named_type_v<Type>);
|
||||
return record(identifier);
|
||||
meta_factory(entt::internal::meta_prop_node **target) ENTT_NOEXCEPT
|
||||
: curr{target}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Assigns a property to the last meta object created.
|
||||
*
|
||||
* Both the key and the value (if any) must be at least copy constructible.
|
||||
*
|
||||
* @tparam PropertyOrKey Type of the property or property key.
|
||||
* @tparam Value Optional type of the property value.
|
||||
* @param property_or_key Property or property key.
|
||||
* @param value Optional property value.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename PropertyOrKey, typename... Value>
|
||||
auto prop(PropertyOrKey &&property_or_key, Value &&... value) && {
|
||||
if constexpr(sizeof...(Value) == 0) {
|
||||
unroll(choice<3>, std::forward<PropertyOrKey>(property_or_key));
|
||||
} else {
|
||||
assign(std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
|
||||
}
|
||||
|
||||
return meta_factory<Type, Spec..., PropertyOrKey, Value...>{curr};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extends a meta type by assigning it an identifier.
|
||||
* @brief Assigns properties to the last meta object created.
|
||||
*
|
||||
* This function is intended only for named types
|
||||
* Both the keys and the values (if any) must be at least copy
|
||||
* constructible.
|
||||
*
|
||||
* @return An extended meta factory for the parent type.
|
||||
* @tparam Property Types of the properties.
|
||||
* @param property Properties to assign to the last meta object created.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
auto type() ENTT_NOEXCEPT {
|
||||
static_assert(is_named_type_v<Type>);
|
||||
return record(named_type_traits_t<Type>::value);
|
||||
template <typename... Property>
|
||||
auto props(Property... property) && {
|
||||
unroll(choice<3>, std::forward<Property>(property)...);
|
||||
return meta_factory<Type, Spec..., Property...>{curr};
|
||||
}
|
||||
|
||||
private:
|
||||
entt::internal::meta_prop_node **curr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic meta factory to be used for reflection purposes.
|
||||
* @tparam Type Reflected type for which the factory was created.
|
||||
*/
|
||||
template<typename Type>
|
||||
class meta_factory<Type> {
|
||||
template<typename Node>
|
||||
bool exists(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
|
||||
return node && (node == candidate || exists(candidate, node->next));
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
bool exists(const ENTT_ID_TYPE alias, const Node *node) ENTT_NOEXCEPT {
|
||||
return node && (node->alias == alias || exists(alias, node->next));
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Extends a meta type by assigning it an alias.
|
||||
* @param value Unique identifier.
|
||||
* @return An extended meta factory for the given type.
|
||||
*/
|
||||
auto alias(const ENTT_ID_TYPE value) ENTT_NOEXCEPT {
|
||||
auto * const node = internal::meta_info<Type>::resolve();
|
||||
|
||||
ENTT_ASSERT(!exists(value, *internal::meta_info<>::global));
|
||||
ENTT_ASSERT(!exists(node, *internal::meta_info<>::global));
|
||||
node->alias = value;
|
||||
node->next = *internal::meta_info<>::global;
|
||||
*internal::meta_info<>::global = node;
|
||||
|
||||
return meta_factory<Type, Type>{&node->prop};
|
||||
}
|
||||
|
||||
/*! @copydoc alias */
|
||||
[[deprecated("Use ::alias instead")]]
|
||||
auto type(const ENTT_ID_TYPE value) ENTT_NOEXCEPT {
|
||||
return alias(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,7 +428,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!duplicate(&node, type->base));
|
||||
ENTT_ASSERT(!exists(&node, type->base));
|
||||
node.next = type->base;
|
||||
type->base = &node;
|
||||
|
||||
@@ -352,7 +458,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!duplicate(&node, type->conv));
|
||||
ENTT_ASSERT(!exists(&node, type->conv));
|
||||
node.next = type->conv;
|
||||
type->conv = &node;
|
||||
|
||||
@@ -385,7 +491,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!duplicate(&node, type->conv));
|
||||
ENTT_ASSERT(!exists(&node, type->conv));
|
||||
node.next = type->conv;
|
||||
type->conv = &node;
|
||||
|
||||
@@ -422,11 +528,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!duplicate(&node, type->ctor));
|
||||
ENTT_ASSERT(!exists(&node, type->ctor));
|
||||
node.next = type->ctor;
|
||||
type->ctor = &node;
|
||||
|
||||
return extended_meta_factory<Type, std::integral_constant<decltype(Func), Func>>{&node.prop};
|
||||
return meta_factory<Type, std::integral_constant<decltype(Func), Func>>{&node.prop};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -455,11 +561,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!duplicate(&node, type->ctor));
|
||||
ENTT_ASSERT(!exists(&node, type->ctor));
|
||||
node.next = type->ctor;
|
||||
type->ctor = &node;
|
||||
|
||||
return extended_meta_factory<Type, Type(Args...)>{&node.prop};
|
||||
return meta_factory<Type, Type(Args...)>{&node.prop};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,14 +591,10 @@ public:
|
||||
|
||||
static internal::meta_dtor_node node{
|
||||
type,
|
||||
[](meta_handle handle) {
|
||||
const auto valid = (handle.type() == internal::meta_info<Type>::resolve());
|
||||
|
||||
if(valid) {
|
||||
std::invoke(Func, *meta_any{handle}.try_cast<Type>());
|
||||
[](void *instance) {
|
||||
if(instance) {
|
||||
std::invoke(Func, *static_cast<Type *>(instance));
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -512,11 +614,11 @@ public:
|
||||
*
|
||||
* @tparam Data The actual variable to attach to the meta type.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param identifier Unique identifier.
|
||||
* @param alias Unique identifier.
|
||||
* @return An extended meta factory for the parent type.
|
||||
*/
|
||||
template<auto Data, typename Policy = as_is_t>
|
||||
auto data(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
|
||||
auto data(const ENTT_ID_TYPE alias) ENTT_NOEXCEPT {
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
internal::meta_data_node *curr = nullptr;
|
||||
|
||||
@@ -531,8 +633,8 @@ public:
|
||||
true,
|
||||
true,
|
||||
&internal::meta_info<Type>::resolve,
|
||||
[](meta_handle, meta_any, meta_any) { return false; },
|
||||
[](meta_handle, meta_any) -> meta_any { return Data; }
|
||||
[](meta_any, meta_any, meta_any) { return false; },
|
||||
[](meta_any, meta_any) -> meta_any { return Data; }
|
||||
};
|
||||
|
||||
curr = &node;
|
||||
@@ -571,13 +673,13 @@ public:
|
||||
curr = &node;
|
||||
}
|
||||
|
||||
ENTT_ASSERT(!duplicate(identifier, type->data));
|
||||
ENTT_ASSERT(!duplicate(curr, type->data));
|
||||
curr->identifier = identifier;
|
||||
ENTT_ASSERT(!exists(alias, type->data));
|
||||
ENTT_ASSERT(!exists(curr, type->data));
|
||||
curr->alias = alias;
|
||||
curr->next = type->data;
|
||||
type->data = curr;
|
||||
|
||||
return extended_meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&curr->prop};
|
||||
return meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&curr->prop};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -597,11 +699,11 @@ public:
|
||||
* @tparam Setter The actual function to use as a setter.
|
||||
* @tparam Getter The actual function to use as a getter.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param identifier Unique identifier.
|
||||
* @param alias Unique identifier.
|
||||
* @return An extended meta factory for the parent type.
|
||||
*/
|
||||
template<auto Setter, auto Getter, typename Policy = as_is_t>
|
||||
auto data(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
|
||||
auto data(const ENTT_ID_TYPE alias) ENTT_NOEXCEPT {
|
||||
using underlying_type = std::invoke_result_t<decltype(Getter), Type &>;
|
||||
static_assert(std::is_invocable_v<decltype(Setter), Type &, underlying_type>);
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
@@ -618,13 +720,13 @@ public:
|
||||
&internal::getter<Type, Getter, Policy>
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!duplicate(identifier, type->data));
|
||||
ENTT_ASSERT(!duplicate(&node, type->data));
|
||||
node.identifier = identifier;
|
||||
ENTT_ASSERT(!exists(alias, type->data));
|
||||
ENTT_ASSERT(!exists(&node, type->data));
|
||||
node.alias = alias;
|
||||
node.next = type->data;
|
||||
type->data = &node;
|
||||
|
||||
return extended_meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
|
||||
return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -637,11 +739,11 @@ public:
|
||||
*
|
||||
* @tparam Candidate The actual function to attach to the meta type.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param identifier Unique identifier.
|
||||
* @param alias Unique identifier.
|
||||
* @return An extended meta factory for the parent type.
|
||||
*/
|
||||
template<auto Candidate, typename Policy = as_is_t>
|
||||
auto func(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
|
||||
auto func(const ENTT_ID_TYPE alias) ENTT_NOEXCEPT {
|
||||
using helper_type = internal::meta_function_helper_t<decltype(Candidate)>;
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
|
||||
@@ -655,18 +757,18 @@ public:
|
||||
!std::is_member_function_pointer_v<decltype(Candidate)>,
|
||||
&internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename helper_type::return_type>>::resolve,
|
||||
&helper_type::arg,
|
||||
[](meta_handle handle, meta_any *any) {
|
||||
return internal::invoke<Type, Candidate, Policy>(handle, any, helper_type::index_sequence);
|
||||
[](meta_any instance, meta_any *args) {
|
||||
return internal::invoke<Type, Candidate, Policy>(std::move(instance), args, helper_type::index_sequence);
|
||||
}
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!duplicate(identifier, type->func));
|
||||
ENTT_ASSERT(!duplicate(&node, type->func));
|
||||
node.identifier = identifier;
|
||||
ENTT_ASSERT(!exists(alias, type->func));
|
||||
ENTT_ASSERT(!exists(&node, type->func));
|
||||
node.alias = alias;
|
||||
node.next = type->func;
|
||||
type->func = &node;
|
||||
|
||||
return extended_meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
|
||||
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -676,127 +778,45 @@ public:
|
||||
* functions and properties, as well as its constructors, destructors and
|
||||
* conversion functions if any.<br/>
|
||||
* Base classes aren't reset but the link between the two types is removed.
|
||||
*
|
||||
* @return An extended meta factory for the given type.
|
||||
*/
|
||||
void reset() ENTT_NOEXCEPT {
|
||||
internal::meta_info<Type>::reset();
|
||||
}
|
||||
};
|
||||
auto reset() ENTT_NOEXCEPT {
|
||||
auto * const node = internal::meta_info<Type>::resolve();
|
||||
auto **it = internal::meta_info<>::global;
|
||||
|
||||
while(*it && *it != node) {
|
||||
it = &(*it)->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extended meta factory to be used for reflection purposes.
|
||||
* @tparam Type Reflected type for which the factory was created.
|
||||
* @tparam Spec Property specialization pack used to disambiguate overloads.
|
||||
*/
|
||||
template<typename Type, typename... Spec>
|
||||
class extended_meta_factory: public meta_factory<Type> {
|
||||
bool duplicate(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
|
||||
return node && (node->key() == key || duplicate(key, node->next));
|
||||
}
|
||||
if(*it) {
|
||||
*it = (*it)->next;
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, std::size_t... Index, typename... Property, typename... Other>
|
||||
void unpack(std::index_sequence<Index...>, std::tuple<Property...> property, Other &&... other) {
|
||||
unroll<Step>(choice<3>, std::move(std::get<Index>(property))..., std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, typename... Property, typename... Other>
|
||||
void unroll(choice_t<3>, std::tuple<Property...> property, Other &&... other) {
|
||||
unpack<Step>(std::index_sequence_for<Property...>{}, std::move(property), std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, typename... Property, typename... Other>
|
||||
void unroll(choice_t<2>, std::pair<Property...> property, Other &&... other) {
|
||||
assign<Step>(std::move(property.first), std::move(property.second));
|
||||
unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, typename Property, typename... Other>
|
||||
std::enable_if_t<!std::is_invocable_v<Property>>
|
||||
unroll(choice_t<1>, Property &&property, Other &&... other) {
|
||||
assign<Step>(std::forward<Property>(property));
|
||||
unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, typename Func, typename... Other>
|
||||
void unroll(choice_t<0>, Func &&invocable, Other &&... other) {
|
||||
unroll<Step>(choice<3>, std::forward<Func>(invocable)(), std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t>
|
||||
void unroll(choice_t<0>) {}
|
||||
|
||||
template<std::size_t = 0, typename Key, typename... Value>
|
||||
void assign(Key &&key, Value &&... value) {
|
||||
static auto property{std::make_tuple(std::forward<Key>(key), std::forward<Value>(value)...)};
|
||||
|
||||
static internal::meta_prop_node node{
|
||||
nullptr,
|
||||
[]() -> meta_any {
|
||||
return std::get<0>(property);
|
||||
},
|
||||
[]() -> meta_any {
|
||||
if constexpr(sizeof...(Value) == 0) {
|
||||
return {};
|
||||
} else {
|
||||
return std::get<1>(property);
|
||||
const auto unregister_all = y_combinator{
|
||||
[](auto &&self, auto **curr, auto... member) {
|
||||
while(*curr) {
|
||||
auto *prev = *curr;
|
||||
(self(&(prev->*member)), ...);
|
||||
*curr = prev->next;
|
||||
prev->next = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!duplicate(node.key(), *curr));
|
||||
node.next = *curr;
|
||||
*curr = &node;
|
||||
unregister_all(&node->prop);
|
||||
unregister_all(&node->base);
|
||||
unregister_all(&node->conv);
|
||||
unregister_all(&node->ctor, &internal::meta_ctor_node::prop);
|
||||
unregister_all(&node->data, &internal::meta_data_node::prop);
|
||||
unregister_all(&node->func, &internal::meta_func_node::prop);
|
||||
|
||||
node->alias = {};
|
||||
node->next = nullptr;
|
||||
node->dtor = nullptr;
|
||||
|
||||
return meta_factory<Type, Type>{&node->prop};
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs an extended factory from a given node.
|
||||
* @param target The underlying node to which to assign the properties.
|
||||
*/
|
||||
extended_meta_factory(entt::internal::meta_prop_node **target)
|
||||
: curr{target}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Assigns a property to the last meta object created.
|
||||
*
|
||||
* Both the key and the value (if any) must be at least copy constructible.
|
||||
*
|
||||
* @tparam PropertyOrKey Type of the property or property key.
|
||||
* @tparam Value Optional type of the property value.
|
||||
* @param property_or_key Property or property key.
|
||||
* @param value Optional property value.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename PropertyOrKey, typename... Value>
|
||||
auto prop(PropertyOrKey &&property_or_key, Value &&... value) && {
|
||||
if constexpr(sizeof...(Value) == 0) {
|
||||
unroll(choice<3>, std::forward<PropertyOrKey>(property_or_key));
|
||||
} else {
|
||||
assign(std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
|
||||
}
|
||||
|
||||
return extended_meta_factory<Type, Spec..., PropertyOrKey, Value...>{curr};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns properties to the last meta object created.
|
||||
*
|
||||
* Both the keys and the values (if any) must be at least copy
|
||||
* constructible.
|
||||
*
|
||||
* @tparam Property Types of the properties.
|
||||
* @param property Properties to assign to the last meta object created.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template <typename... Property>
|
||||
auto props(Property... property) && {
|
||||
unroll(choice<3>, std::forward<Property>(property)...);
|
||||
return extended_meta_factory<Type, Spec..., Property...>{curr};
|
||||
}
|
||||
|
||||
private:
|
||||
entt::internal::meta_prop_node **curr{nullptr};
|
||||
};
|
||||
|
||||
|
||||
@@ -809,11 +829,13 @@ private:
|
||||
* dedicated factory.
|
||||
*
|
||||
* @tparam Type Type to reflect.
|
||||
* @return A meta factory for the given type.
|
||||
* @return An meta factory for the given type.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline meta_factory<Type> meta() ENTT_NOEXCEPT {
|
||||
return meta_factory<Type>{};
|
||||
auto * const node = internal::meta_info<Type>::resolve();
|
||||
// extended meta factory to allow assigning properties to opaque meta types
|
||||
return meta_factory<Type, Type>{&node->prop};
|
||||
}
|
||||
|
||||
|
||||
@@ -829,13 +851,13 @@ inline meta_type resolve() ENTT_NOEXCEPT {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the meta type associated with a given identifier.
|
||||
* @param identifier Unique identifier.
|
||||
* @return The meta type associated with the given identifier, if any.
|
||||
* @brief Returns the meta type associated with a given alias.
|
||||
* @param alias Unique identifier.
|
||||
* @return The meta type associated with the given alias, if any.
|
||||
*/
|
||||
inline meta_type resolve(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
|
||||
return internal::find_if([identifier](auto *node) {
|
||||
return node->identifier == identifier;
|
||||
inline meta_type resolve(const ENTT_ID_TYPE alias) ENTT_NOEXCEPT {
|
||||
return internal::find_if([alias](const auto *curr) {
|
||||
return curr->alias == alias;
|
||||
}, *internal::meta_info<>::global);
|
||||
}
|
||||
|
||||
@@ -847,12 +869,12 @@ inline meta_type resolve(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
|
||||
*/
|
||||
template<typename Op>
|
||||
inline std::enable_if_t<std::is_invocable_v<Op, meta_type>, void>
|
||||
resolve(Op op) ENTT_NOEXCEPT {
|
||||
internal::iterate<meta_type>(std::move(op), *internal::meta_info<>::global);
|
||||
resolve(Op op) {
|
||||
internal::visit<meta_type>(std::move(op), *internal::meta_info<>::global);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_META_FACTORY_HPP
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,4 +24,4 @@ struct as_void_t {};
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_META_POLICY_HPP
|
||||
#endif
|
||||
|
||||
@@ -171,7 +171,7 @@ public:
|
||||
using delta_type = Delta;
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
virtual ~process() ENTT_NOEXCEPT {
|
||||
virtual ~process() {
|
||||
static_assert(std::is_base_of_v<process, Derived>);
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ public:
|
||||
*
|
||||
* @param immediately Requests an immediate operation.
|
||||
*/
|
||||
void abort(const bool immediately = false) ENTT_NOEXCEPT {
|
||||
void abort(const bool immediately = false) {
|
||||
if(alive()) {
|
||||
current = state::ABORTED;
|
||||
|
||||
@@ -337,4 +337,4 @@ struct process_adaptor: process<process_adaptor<Func, Delta>, Delta>, private Fu
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_PROCESS_PROCESS_HPP
|
||||
#endif
|
||||
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
using size_type = std::size_t;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
scheduler() ENTT_NOEXCEPT = default;
|
||||
scheduler() = default;
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
scheduler(scheduler &&) = default;
|
||||
@@ -281,9 +281,9 @@ public:
|
||||
decltype(handlers) exec;
|
||||
exec.swap(handlers);
|
||||
|
||||
std::for_each(exec.begin(), exec.end(), [immediately](auto &handler) {
|
||||
for(auto &&handler: exec) {
|
||||
handler.abort(handler, immediately);
|
||||
});
|
||||
}
|
||||
|
||||
std::move(handlers.begin(), handlers.end(), std::back_inserter(exec));
|
||||
handlers.swap(exec);
|
||||
@@ -297,4 +297,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_PROCESS_SCHEDULER_HPP
|
||||
#endif
|
||||
|
||||
@@ -176,7 +176,7 @@ struct cache {
|
||||
* @param id Unique resource identifier.
|
||||
* @return True if the cache contains the resource, false otherwise.
|
||||
*/
|
||||
bool contains(const id_type id) const ENTT_NOEXCEPT {
|
||||
bool contains(const id_type id) const {
|
||||
return (resources.find(id) != resources.cend());
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ struct cache {
|
||||
*
|
||||
* @param id Unique resource identifier.
|
||||
*/
|
||||
void discard(const id_type id) ENTT_NOEXCEPT {
|
||||
void discard(const id_type id) {
|
||||
if(auto it = resources.find(id); it != resources.end()) {
|
||||
resources.erase(it);
|
||||
}
|
||||
@@ -237,4 +237,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_RESOURCE_CACHE_HPP
|
||||
#endif
|
||||
|
||||
@@ -21,4 +21,4 @@ class loader;
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_RESOURCE_FWD_HPP
|
||||
#endif
|
||||
|
||||
@@ -93,7 +93,9 @@ public:
|
||||
* @brief Returns true if a handle contains a resource, false otherwise.
|
||||
* @return True if the handle contains a resource, false otherwise.
|
||||
*/
|
||||
explicit operator bool() const { return static_cast<bool>(resource); }
|
||||
explicit operator bool() const ENTT_NOEXCEPT {
|
||||
return static_cast<bool>(resource);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Resource> resource;
|
||||
@@ -103,4 +105,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_RESOURCE_HANDLE_HPP
|
||||
#endif
|
||||
|
||||
@@ -62,4 +62,4 @@ class loader {
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_RESOURCE_LOADER_HPP
|
||||
#endif
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
|
||||
|
||||
#include <tuple>
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
@@ -24,36 +23,32 @@ namespace internal {
|
||||
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
|
||||
auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
|
||||
|
||||
|
||||
template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<const Payload *, const Type *>>>
|
||||
auto to_function_pointer(Ret(*)(Type &, Args...), const Payload *) -> Ret(*)(Args...);
|
||||
template<typename Ret, typename Type, typename... Args, typename Other>
|
||||
auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);
|
||||
|
||||
|
||||
template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<const Payload *, const Type *>>>
|
||||
auto to_function_pointer(Ret(*)(Type *, Args...), const Payload *) -> Ret(*)(Args...);
|
||||
template<typename Class, typename Ret, typename... Args, typename... Other>
|
||||
auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);
|
||||
|
||||
|
||||
template<typename Class, typename Ret, typename... Args>
|
||||
auto to_function_pointer(Ret(Class:: *)(Args...), const Class *) -> Ret(*)(Args...);
|
||||
template<typename Class, typename Ret, typename... Args, typename... Other>
|
||||
auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...);
|
||||
|
||||
|
||||
template<typename Class, typename Ret, typename... Args>
|
||||
auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class *) -> Ret(*)(Args...);
|
||||
|
||||
|
||||
template<typename Class, typename Type>
|
||||
auto to_function_pointer(Type Class:: *, const Class *) -> Type(*)();
|
||||
template<typename Class, typename Type, typename... Other>
|
||||
auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();
|
||||
|
||||
|
||||
template<typename... Type>
|
||||
using to_function_pointer_t = decltype(internal::to_function_pointer(std::declval<Type>()...));
|
||||
using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));
|
||||
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
template<typename... Class, typename Ret, typename... Args>
|
||||
constexpr auto index_sequence_for(Ret(*)(Args...)) {
|
||||
return std::index_sequence_for<Args...>{};
|
||||
return std::index_sequence_for<Class..., Args...>{};
|
||||
}
|
||||
|
||||
|
||||
@@ -92,49 +87,39 @@ class delegate;
|
||||
* Unmanaged delegate for function pointers and members. Users of this class are
|
||||
* in charge of disconnecting instances before deleting them.
|
||||
*
|
||||
* A delegate can be used as general purpose invoker with no memory overhead for
|
||||
* free functions (with or without payload) and members provided along with an
|
||||
* instance on which to invoke them.
|
||||
* A delegate can be used as a general purpose invoker without memory overhead
|
||||
* for free functions possibly with payloads and bound or unbound members.
|
||||
*
|
||||
* @tparam Ret Return type of a function type.
|
||||
* @tparam Args Types of arguments of a function type.
|
||||
*/
|
||||
template<typename Ret, typename... Args>
|
||||
class delegate<Ret(Args...)> {
|
||||
using proto_fn_type = Ret(const void *, std::tuple<Args &&...>);
|
||||
using proto_fn_type = Ret(const void *, Args...);
|
||||
|
||||
template<auto Function, std::size_t... Index>
|
||||
void connect(std::index_sequence<Index...>) ENTT_NOEXCEPT {
|
||||
static_assert(std::is_invocable_r_v<Ret, decltype(Function), std::tuple_element_t<Index, std::tuple<Args...>>...>);
|
||||
data = nullptr;
|
||||
|
||||
fn = [](const void *, std::tuple<Args &&...> args) -> Ret {
|
||||
// Ret(...) makes void(...) eat the return values to avoid errors
|
||||
return Ret(std::invoke(Function, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
|
||||
template<auto Candidate, std::size_t... Index>
|
||||
auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
|
||||
return [](const void *, Args... args) -> Ret {
|
||||
const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
|
||||
return Ret(std::invoke(Candidate, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
|
||||
};
|
||||
}
|
||||
|
||||
template<auto Candidate, typename Type, std::size_t... Index>
|
||||
void connect(Type &value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
|
||||
static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, std::tuple_element_t<Index, std::tuple<Args...>>...>);
|
||||
data = &value_or_instance;
|
||||
|
||||
fn = [](const void *payload, std::tuple<Args &&...> args) -> Ret {
|
||||
auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
|
||||
return [](const void *payload, Args... args) -> Ret {
|
||||
const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
|
||||
Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
|
||||
// Ret(...) makes void(...) eat the return values to avoid errors
|
||||
return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
|
||||
return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
|
||||
};
|
||||
}
|
||||
|
||||
template<auto Candidate, typename Type, std::size_t... Index>
|
||||
void connect(Type *value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
|
||||
static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, std::tuple_element_t<Index, std::tuple<Args...>>...>);
|
||||
data = value_or_instance;
|
||||
|
||||
fn = [](const void *payload, std::tuple<Args &&...> args) -> Ret {
|
||||
auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
|
||||
return [](const void *payload, Args... args) -> Ret {
|
||||
const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
|
||||
Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
|
||||
// Ret(...) makes void(...) eat the return values to avoid errors
|
||||
return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
|
||||
return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -148,56 +133,53 @@ public:
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Constructs a delegate and connects a free function to it.
|
||||
* @tparam Function A valid free function pointer.
|
||||
* @brief Constructs a delegate and connects a free function or an unbound
|
||||
* member.
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
*/
|
||||
template<auto Function>
|
||||
delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
|
||||
template<auto Candidate>
|
||||
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
|
||||
: delegate{}
|
||||
{
|
||||
connect<Function>();
|
||||
connect<Candidate>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a delegate and connects a member for a given instance
|
||||
* or a free function with payload.
|
||||
* @tparam Candidate Member or free function to connect to the delegate.
|
||||
* @brief Constructs a delegate and connects a free function with payload or
|
||||
* a bound member.
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid reference that fits the purpose.
|
||||
* @param value_or_instance A valid object that fits the purpose.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
delegate(connect_arg_t<Candidate>, Type &value_or_instance) ENTT_NOEXCEPT
|
||||
delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
|
||||
: delegate{}
|
||||
{
|
||||
connect<Candidate>(value_or_instance);
|
||||
connect<Candidate>(std::forward<Type>(value_or_instance));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a delegate and connects a member for a given instance
|
||||
* or a free function with payload.
|
||||
* @tparam Candidate Member or free function to connect to the delegate.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid pointer that fits the purpose.
|
||||
* @brief Connects a free function or an unbound member to a delegate.
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
delegate(connect_arg_t<Candidate>, Type *value_or_instance) ENTT_NOEXCEPT
|
||||
: delegate{}
|
||||
{
|
||||
connect<Candidate>(value_or_instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects a free function to a delegate.
|
||||
* @tparam Function A valid free function pointer.
|
||||
*/
|
||||
template<auto Function>
|
||||
template<auto Candidate>
|
||||
void connect() ENTT_NOEXCEPT {
|
||||
connect<Function>(internal::index_sequence_for(internal::to_function_pointer_t<decltype(Function)>{}));
|
||||
data = nullptr;
|
||||
|
||||
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
|
||||
fn = [](const void *, Args... args) -> Ret {
|
||||
return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
|
||||
};
|
||||
} else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
|
||||
fn = wrap<Candidate>(internal::index_sequence_for<std::tuple_element_t<0, std::tuple<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
|
||||
} else {
|
||||
fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects a member function for a given instance or a free function
|
||||
* with payload to a delegate.
|
||||
* @brief Connects a free function with payload or a bound member to a
|
||||
* delegate.
|
||||
*
|
||||
* The delegate isn't responsible for the connected object or the payload.
|
||||
* Users must always guarantee that the lifetime of the instance overcomes
|
||||
@@ -206,33 +188,46 @@ public:
|
||||
* such that the instance is the first argument before the ones used to
|
||||
* define the delegate itself.
|
||||
*
|
||||
* @tparam Candidate Member or free function to connect to the delegate.
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid reference that fits the purpose.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
void connect(Type &value_or_instance) ENTT_NOEXCEPT {
|
||||
connect<Candidate>(value_or_instance, internal::index_sequence_for(internal::to_function_pointer_t<decltype(Candidate), Type *>{}));
|
||||
data = &value_or_instance;
|
||||
|
||||
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
|
||||
fn = [](const void *payload, Args... args) -> Ret {
|
||||
Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
|
||||
return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
|
||||
};
|
||||
} else {
|
||||
fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects a member function for a given instance or a free function
|
||||
* with payload to a delegate.
|
||||
* @brief Connects a free function with payload or a bound member to a
|
||||
* delegate.
|
||||
*
|
||||
* The delegate 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.<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.
|
||||
* @sa connect(Type &)
|
||||
*
|
||||
* @tparam Candidate Member or free function to connect to the delegate.
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid pointer that fits the purpose.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
void connect(Type *value_or_instance) ENTT_NOEXCEPT {
|
||||
connect<Candidate>(value_or_instance, internal::index_sequence_for(internal::to_function_pointer_t<decltype(Candidate), Type *>{}));
|
||||
data = value_or_instance;
|
||||
|
||||
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
|
||||
fn = [](const void *payload, Args... args) -> Ret {
|
||||
Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
|
||||
return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
|
||||
};
|
||||
} else {
|
||||
fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +264,7 @@ public:
|
||||
*/
|
||||
Ret operator()(Args... args) const {
|
||||
ENTT_ASSERT(fn);
|
||||
return fn(data, std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
return fn(data, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,7 +273,7 @@ public:
|
||||
*/
|
||||
explicit operator bool() const ENTT_NOEXCEPT {
|
||||
// no need to test also data
|
||||
return fn;
|
||||
return !(fn == nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,46 +307,24 @@ bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)>
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
*
|
||||
* It allows to deduce the function type of the delegate directly from a
|
||||
* function provided to the constructor.
|
||||
*
|
||||
* @tparam Function A valid free function pointer.
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
*/
|
||||
template<auto Function>
|
||||
delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
|
||||
-> delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Function)>>>;
|
||||
template<auto Candidate>
|
||||
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
|
||||
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
*
|
||||
* It allows to deduce the function type of the delegate directly from a member
|
||||
* or a free function with payload provided to the constructor.
|
||||
*
|
||||
* @tparam Candidate Member or free function to connect to the delegate.
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
delegate(connect_arg_t<Candidate>, Type &) ENTT_NOEXCEPT
|
||||
-> delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Candidate), Type *>>>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
*
|
||||
* It allows to deduce the function type of the delegate directly from a member
|
||||
* or a free function with payload provided to the constructor.
|
||||
*
|
||||
* @tparam Candidate Member or free function to connect to the delegate.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
delegate(connect_arg_t<Candidate>, Type *) ENTT_NOEXCEPT
|
||||
-> delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Candidate), Type *>>>;
|
||||
delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
|
||||
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_SIGNAL_DELEGATE_HPP
|
||||
#endif
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
#include <memory>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/family.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "sigh.hpp"
|
||||
|
||||
|
||||
@@ -31,19 +29,15 @@ namespace entt {
|
||||
* crashes.
|
||||
*/
|
||||
class dispatcher {
|
||||
using event_family = family<struct internal_dispatcher_event_family>;
|
||||
|
||||
template<typename Class, typename Event>
|
||||
using instance_type = typename sigh<void(const Event &)>::template instance_type<Class>;
|
||||
|
||||
struct base_wrapper {
|
||||
virtual ~base_wrapper() = default;
|
||||
struct basic_pool {
|
||||
virtual ~basic_pool() = default;
|
||||
virtual void publish() = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual void clear() ENTT_NOEXCEPT = 0;
|
||||
virtual ENTT_ID_TYPE type_id() const ENTT_NOEXCEPT = 0;
|
||||
};
|
||||
|
||||
template<typename Event>
|
||||
struct signal_wrapper: base_wrapper {
|
||||
struct pool_handler: basic_pool {
|
||||
using signal_type = sigh<void(const Event &)>;
|
||||
using sink_type = typename signal_type::sink_type;
|
||||
|
||||
@@ -57,7 +51,7 @@ class dispatcher {
|
||||
events.erase(events.cbegin(), events.cbegin()+length);
|
||||
}
|
||||
|
||||
void clear() override {
|
||||
void clear() ENTT_NOEXCEPT override {
|
||||
events.clear();
|
||||
}
|
||||
|
||||
@@ -67,7 +61,7 @@ class dispatcher {
|
||||
|
||||
template<typename... Args>
|
||||
void trigger(Args &&... args) {
|
||||
signal.publish({ std::forward<Args>(args)... });
|
||||
signal.publish(Event{std::forward<Args>(args)...});
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
@@ -75,63 +69,32 @@ class dispatcher {
|
||||
events.emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
ENTT_ID_TYPE type_id() const ENTT_NOEXCEPT override {
|
||||
return type_info<Event>::id();
|
||||
}
|
||||
|
||||
private:
|
||||
signal_type signal{};
|
||||
std::vector<Event> events;
|
||||
};
|
||||
|
||||
struct wrapper_data {
|
||||
std::unique_ptr<base_wrapper> wrapper;
|
||||
ENTT_ID_TYPE runtime_type;
|
||||
};
|
||||
|
||||
template<typename Event>
|
||||
static auto type() ENTT_NOEXCEPT {
|
||||
if constexpr(is_named_type_v<Event>) {
|
||||
return named_type_traits_v<Event>;
|
||||
} else {
|
||||
return event_family::type<std::decay_t<Event>>;
|
||||
}
|
||||
}
|
||||
pool_handler<Event> & assure() {
|
||||
static_assert(std::is_same_v<Event, std::decay_t<Event>>);
|
||||
static std::size_t index{pools.size()};
|
||||
|
||||
template<typename Event>
|
||||
signal_wrapper<Event> & assure() {
|
||||
const auto wtype = type<Event>();
|
||||
wrapper_data *wdata = nullptr;
|
||||
if(const auto length = pools.size(); !(index < length) || pools[index]->type_id() != type_info<Event>::id()) {
|
||||
for(index = {}; index < length && pools[index]->type_id() != type_info<Event>::id(); ++index);
|
||||
|
||||
if constexpr(is_named_type_v<Event>) {
|
||||
const auto it = std::find_if(wrappers.begin(), wrappers.end(), [wtype](const auto &candidate) {
|
||||
return candidate.wrapper && candidate.runtime_type == wtype;
|
||||
});
|
||||
|
||||
wdata = (it == wrappers.cend() ? &wrappers.emplace_back() : &(*it));
|
||||
} else {
|
||||
if(!(wtype < wrappers.size())) {
|
||||
wrappers.resize(wtype+1);
|
||||
}
|
||||
|
||||
wdata = &wrappers[wtype];
|
||||
|
||||
if(wdata->wrapper && wdata->runtime_type != wtype) {
|
||||
wrappers.emplace_back();
|
||||
std::swap(wrappers[wtype], wrappers.back());
|
||||
wdata = &wrappers[wtype];
|
||||
if(index == pools.size()) {
|
||||
pools.emplace_back(new pool_handler<Event>{});
|
||||
}
|
||||
}
|
||||
|
||||
if(!wdata->wrapper) {
|
||||
wdata->wrapper = std::make_unique<signal_wrapper<Event>>();
|
||||
wdata->runtime_type = wtype;
|
||||
}
|
||||
|
||||
return static_cast<signal_wrapper<Event> &>(*wdata->wrapper);
|
||||
return static_cast<pool_handler<Event> &>(*pools[index]);
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Type of sink for the given event. */
|
||||
template<typename Event>
|
||||
using sink_type = typename signal_wrapper<Event>::sink_type;
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object for the given event.
|
||||
*
|
||||
@@ -150,7 +113,7 @@ public:
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
template<typename Event>
|
||||
sink_type<Event> sink() ENTT_NOEXCEPT {
|
||||
auto sink() {
|
||||
return assure<Event>().sink();
|
||||
}
|
||||
|
||||
@@ -221,15 +184,13 @@ public:
|
||||
* @tparam Event Type of events to discard.
|
||||
*/
|
||||
template<typename... Event>
|
||||
void discard() {
|
||||
void clear() {
|
||||
if constexpr(sizeof...(Event) == 0) {
|
||||
std::for_each(wrappers.begin(), wrappers.end(), [](auto &&wdata) {
|
||||
if(wdata.wrapper) {
|
||||
wdata.wrapper->clear();
|
||||
}
|
||||
});
|
||||
for(auto &&cpool: pools) {
|
||||
cpool->clear();
|
||||
}
|
||||
} else {
|
||||
(assure<std::decay_t<Event>>().clear(), ...);
|
||||
(assure<Event>().clear(), ...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,19 +216,17 @@ public:
|
||||
* to reduce at a minimum the time spent in the bodies of the listeners.
|
||||
*/
|
||||
void update() const {
|
||||
for(auto pos = wrappers.size(); pos; --pos) {
|
||||
if(auto &wdata = wrappers[pos-1]; wdata.wrapper) {
|
||||
wdata.wrapper->publish();
|
||||
}
|
||||
for(auto pos = pools.size(); pos; --pos) {
|
||||
pools[pos-1]->publish();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<wrapper_data> wrappers;
|
||||
std::vector<std::unique_ptr<basic_pool>> pools;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_SIGNAL_DISPATCHER_HPP
|
||||
#endif
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include "../config/config.h"
|
||||
#include "../core/family.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
@@ -29,7 +29,7 @@ namespace entt {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* Handlers for the type of events are created internally on the fly. It's not
|
||||
* Pools for the type of events are created internally on the fly. It's not
|
||||
* required to specify in advance the full list of accepted types.<br/>
|
||||
* Moreover, whenever an event is published, an emitter provides the listeners
|
||||
* with a reference to itself along with a const reference to the event.
|
||||
@@ -40,16 +40,15 @@ namespace entt {
|
||||
*/
|
||||
template<typename Derived>
|
||||
class emitter {
|
||||
using handler_family = family<struct internal_emitter_handler_family>;
|
||||
|
||||
struct base_handler {
|
||||
virtual ~base_handler() = default;
|
||||
struct basic_pool {
|
||||
virtual ~basic_pool() = default;
|
||||
virtual bool empty() const ENTT_NOEXCEPT = 0;
|
||||
virtual void clear() ENTT_NOEXCEPT = 0;
|
||||
virtual ENTT_ID_TYPE type_id() const ENTT_NOEXCEPT = 0;
|
||||
};
|
||||
|
||||
template<typename Event>
|
||||
struct event_handler: base_handler {
|
||||
struct pool_handler: basic_pool {
|
||||
using listener_type = std::function<void(const Event &, Derived &)>;
|
||||
using element_type = std::pair<bool, listener_type>;
|
||||
using container_type = std::list<element_type>;
|
||||
@@ -64,9 +63,13 @@ class emitter {
|
||||
|
||||
void clear() ENTT_NOEXCEPT override {
|
||||
if(publishing) {
|
||||
auto func = [](auto &&element) { element.first = true; };
|
||||
std::for_each(once_list.begin(), once_list.end(), func);
|
||||
std::for_each(on_list.begin(), on_list.end(), func);
|
||||
for(auto &&element: once_list) {
|
||||
element.first = true;
|
||||
}
|
||||
|
||||
for(auto &&element: on_list) {
|
||||
element.first = true;
|
||||
}
|
||||
} else {
|
||||
once_list.clear();
|
||||
on_list.clear();
|
||||
@@ -81,7 +84,7 @@ class emitter {
|
||||
return on_list.emplace(on_list.cend(), false, std::move(listener));
|
||||
}
|
||||
|
||||
void erase(connection_type conn) ENTT_NOEXCEPT {
|
||||
void erase(connection_type conn) {
|
||||
conn->first = true;
|
||||
|
||||
if(!publishing) {
|
||||
@@ -95,77 +98,56 @@ class emitter {
|
||||
container_type swap_list;
|
||||
once_list.swap(swap_list);
|
||||
|
||||
auto func = [&event, &ref](auto &&element) {
|
||||
return element.first ? void() : element.second(event, ref);
|
||||
};
|
||||
|
||||
publishing = true;
|
||||
|
||||
std::for_each(on_list.rbegin(), on_list.rend(), func);
|
||||
std::for_each(swap_list.rbegin(), swap_list.rend(), func);
|
||||
for(auto &&element: on_list) {
|
||||
element.first ? void() : element.second(event, ref);
|
||||
}
|
||||
|
||||
for(auto &&element: swap_list) {
|
||||
element.first ? void() : element.second(event, ref);
|
||||
}
|
||||
|
||||
publishing = false;
|
||||
|
||||
on_list.remove_if([](auto &&element) { return element.first; });
|
||||
}
|
||||
|
||||
ENTT_ID_TYPE type_id() const ENTT_NOEXCEPT override {
|
||||
return type_info<Event>::id();
|
||||
}
|
||||
|
||||
private:
|
||||
bool publishing{false};
|
||||
container_type once_list{};
|
||||
container_type on_list{};
|
||||
};
|
||||
|
||||
struct handler_data {
|
||||
std::unique_ptr<base_handler> handler;
|
||||
ENTT_ID_TYPE runtime_type;
|
||||
};
|
||||
|
||||
template<typename Event>
|
||||
static auto type() ENTT_NOEXCEPT {
|
||||
if constexpr(is_named_type_v<Event>) {
|
||||
return named_type_traits_v<Event>;
|
||||
} else {
|
||||
return handler_family::type<std::decay_t<Event>>;
|
||||
const pool_handler<Event> & assure() const {
|
||||
static_assert(std::is_same_v<Event, std::decay_t<Event>>);
|
||||
static std::size_t index{pools.size()};
|
||||
|
||||
if(const auto length = pools.size(); !(index < length) || pools[index]->type_id() != type_info<Event>::id()) {
|
||||
for(index = {}; index < length && pools[index]->type_id() != type_info<Event>::id(); ++index);
|
||||
|
||||
if(index == pools.size()) {
|
||||
pools.emplace_back(new pool_handler<Event>{});
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<pool_handler<Event> &>(*pools[index]);
|
||||
}
|
||||
|
||||
template<typename Event>
|
||||
event_handler<Event> * assure() const ENTT_NOEXCEPT {
|
||||
const auto htype = type<Event>();
|
||||
handler_data *hdata = nullptr;
|
||||
|
||||
if constexpr(is_named_type_v<Event>) {
|
||||
const auto it = std::find_if(handlers.begin(), handlers.end(), [htype](const auto &candidate) {
|
||||
return candidate.handler && candidate.runtime_type == htype;
|
||||
});
|
||||
|
||||
hdata = (it == handlers.cend() ? &handlers.emplace_back() : &(*it));
|
||||
} else {
|
||||
if(!(htype < handlers.size())) {
|
||||
handlers.resize(htype+1);
|
||||
}
|
||||
|
||||
hdata = &handlers[htype];
|
||||
|
||||
if(hdata->handler && hdata->runtime_type != htype) {
|
||||
handlers.emplace_back();
|
||||
std::swap(handlers[htype], handlers.back());
|
||||
hdata = &handlers[htype];
|
||||
}
|
||||
}
|
||||
|
||||
if(!hdata->handler) {
|
||||
hdata->handler = std::make_unique<event_handler<Event>>();
|
||||
hdata->runtime_type = htype;
|
||||
}
|
||||
|
||||
return static_cast<event_handler<Event> *>(hdata->handler.get());
|
||||
pool_handler<Event> & assure() {
|
||||
return const_cast<pool_handler<Event> &>(std::as_const(*this).template assure<Event>());
|
||||
}
|
||||
|
||||
public:
|
||||
/** @brief Type of listeners accepted for the given event. */
|
||||
template<typename Event>
|
||||
using listener = typename event_handler<Event>::listener_type;
|
||||
using listener = typename pool_handler<Event>::listener_type;
|
||||
|
||||
/**
|
||||
* @brief Generic connection type for events.
|
||||
@@ -177,27 +159,27 @@ public:
|
||||
* @tparam Event Type of event for which the connection is created.
|
||||
*/
|
||||
template<typename Event>
|
||||
struct connection: private event_handler<Event>::connection_type {
|
||||
struct connection: private pool_handler<Event>::connection_type {
|
||||
/** @brief Event emitters are friend classes of connections. */
|
||||
friend class emitter;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
connection() ENTT_NOEXCEPT = default;
|
||||
connection() = default;
|
||||
|
||||
/**
|
||||
* @brief Creates a connection that wraps its underlying instance.
|
||||
* @param conn A connection object to wrap.
|
||||
*/
|
||||
connection(typename event_handler<Event>::connection_type conn)
|
||||
: event_handler<Event>::connection_type{std::move(conn)}
|
||||
connection(typename pool_handler<Event>::connection_type conn)
|
||||
: pool_handler<Event>::connection_type{std::move(conn)}
|
||||
{}
|
||||
};
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
emitter() ENTT_NOEXCEPT = default;
|
||||
emitter() = default;
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
virtual ~emitter() ENTT_NOEXCEPT {
|
||||
virtual ~emitter() {
|
||||
static_assert(std::is_base_of_v<emitter<Derived>, Derived>);
|
||||
}
|
||||
|
||||
@@ -220,7 +202,7 @@ public:
|
||||
*/
|
||||
template<typename Event, typename... Args>
|
||||
void publish(Args &&... args) {
|
||||
assure<Event>()->publish({ std::forward<Args>(args)... }, *static_cast<Derived *>(this));
|
||||
assure<Event>().publish(Event{std::forward<Args>(args)...}, *static_cast<Derived *>(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,7 +227,7 @@ public:
|
||||
*/
|
||||
template<typename Event>
|
||||
connection<Event> on(listener<Event> instance) {
|
||||
return assure<Event>()->on(std::move(instance));
|
||||
return assure<Event>().on(std::move(instance));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,7 +252,7 @@ public:
|
||||
*/
|
||||
template<typename Event>
|
||||
connection<Event> once(listener<Event> instance) {
|
||||
return assure<Event>()->once(std::move(instance));
|
||||
return assure<Event>().once(std::move(instance));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,8 +265,8 @@ public:
|
||||
* @param conn A valid connection.
|
||||
*/
|
||||
template<typename Event>
|
||||
void erase(connection<Event> conn) ENTT_NOEXCEPT {
|
||||
assure<Event>()->erase(std::move(conn));
|
||||
void erase(connection<Event> conn) {
|
||||
assure<Event>().erase(std::move(conn));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,8 +278,8 @@ public:
|
||||
* @tparam Event Type of event to reset.
|
||||
*/
|
||||
template<typename Event>
|
||||
void clear() ENTT_NOEXCEPT {
|
||||
assure<Event>()->clear();
|
||||
void clear() {
|
||||
assure<Event>().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,9 +289,9 @@ public:
|
||||
* results in undefined behavior.
|
||||
*/
|
||||
void clear() ENTT_NOEXCEPT {
|
||||
std::for_each(handlers.begin(), handlers.end(), [](auto &&hdata) {
|
||||
return hdata.handler ? hdata.handler->clear() : void();
|
||||
});
|
||||
for(auto &&cpool: pools) {
|
||||
cpool->clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -318,8 +300,8 @@ public:
|
||||
* @return True if there are no listeners registered, false otherwise.
|
||||
*/
|
||||
template<typename Event>
|
||||
bool empty() const ENTT_NOEXCEPT {
|
||||
return assure<Event>()->empty();
|
||||
bool empty() const {
|
||||
return assure<Event>().empty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,17 +309,17 @@ public:
|
||||
* @return True if there are no listeners registered, false otherwise.
|
||||
*/
|
||||
bool empty() const ENTT_NOEXCEPT {
|
||||
return std::all_of(handlers.cbegin(), handlers.cend(), [](auto &&hdata) {
|
||||
return !hdata.handler || hdata.handler->empty();
|
||||
return std::all_of(pools.cbegin(), pools.cend(), [](auto &&cpool) {
|
||||
return cpool->empty();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::vector<handler_data> handlers{};
|
||||
mutable std::vector<std::unique_ptr<basic_pool>> pools{};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_SIGNAL_EMITTER_HPP
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,19 @@ namespace entt {
|
||||
template<typename>
|
||||
class delegate;
|
||||
|
||||
/*! @class dispatcher */
|
||||
class dispatcher;
|
||||
|
||||
/*! @class emitter */
|
||||
template<typename>
|
||||
class emitter;
|
||||
|
||||
/*! @class connection */
|
||||
class connection;
|
||||
|
||||
/*! @class scoped_connection */
|
||||
struct scoped_connection;
|
||||
|
||||
/*! @class sink */
|
||||
template<typename>
|
||||
class sink;
|
||||
@@ -21,4 +34,4 @@ class sigh;
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_SIGNAL_FWD_HPP
|
||||
#endif
|
||||
|
||||
@@ -97,9 +97,9 @@ public:
|
||||
* @param args Arguments to use to invoke listeners.
|
||||
*/
|
||||
void publish(Args... args) const {
|
||||
std::for_each(calls.cbegin(), calls.cend(), [&args...](auto &&call) {
|
||||
for(auto &&call: std::as_const(calls)) {
|
||||
call(args...);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,38 +162,6 @@ public:
|
||||
/*! @brief Default constructor. */
|
||||
connection() = default;
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
connection(const connection &) = default;
|
||||
|
||||
/**
|
||||
* @brief Default move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
connection(connection &&other)
|
||||
: connection{}
|
||||
{
|
||||
std::swap(disconnect, other.disconnect);
|
||||
std::swap(signal, other.signal);
|
||||
}
|
||||
|
||||
/*! @brief Default copy assignment operator. @return This connection. */
|
||||
connection & operator=(const connection &) = default;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This connection.
|
||||
*/
|
||||
connection & operator=(connection &&other) {
|
||||
if(this != &other) {
|
||||
auto tmp{std::move(other)};
|
||||
disconnect = tmp.disconnect;
|
||||
signal = tmp.signal;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a connection is properly initialized.
|
||||
* @return True if the connection is properly initialized, false otherwise.
|
||||
@@ -225,30 +193,24 @@ private:
|
||||
* A scoped connection automatically breaks the link between the two objects
|
||||
* when it goes out of scope.
|
||||
*/
|
||||
struct scoped_connection: private connection {
|
||||
using connection::operator bool;
|
||||
using connection::release;
|
||||
|
||||
struct scoped_connection {
|
||||
/*! @brief Default constructor. */
|
||||
scoped_connection() = default;
|
||||
|
||||
/**
|
||||
* @brief Constructs a scoped connection from a basic connection.
|
||||
* @param conn A valid connection object.
|
||||
* @param other A valid connection object.
|
||||
*/
|
||||
scoped_connection(const connection &conn)
|
||||
: connection{conn}
|
||||
scoped_connection(const connection &other)
|
||||
: conn{other}
|
||||
{}
|
||||
|
||||
/*! @brief Default copy constructor, deleted on purpose. */
|
||||
scoped_connection(const scoped_connection &) = delete;
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
scoped_connection(scoped_connection &&) = default;
|
||||
|
||||
/*! @brief Automatically breaks the link on destruction. */
|
||||
~scoped_connection() {
|
||||
connection::release();
|
||||
conn.release();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,30 +220,30 @@ struct scoped_connection: private connection {
|
||||
scoped_connection & operator=(const scoped_connection &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @brief Acquires a connection.
|
||||
* @param other The connection object to acquire.
|
||||
* @return This scoped connection.
|
||||
*/
|
||||
scoped_connection & operator=(scoped_connection &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Copies a connection.
|
||||
* @param other The connection object to copy.
|
||||
* @return This scoped connection.
|
||||
*/
|
||||
scoped_connection & operator=(const connection &other) {
|
||||
static_cast<connection &>(*this) = other;
|
||||
scoped_connection & operator=(connection other) {
|
||||
conn = std::move(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Moves a connection.
|
||||
* @param other The connection object to move.
|
||||
* @return This scoped connection.
|
||||
* @brief Checks whether a scoped connection is properly initialized.
|
||||
* @return True if the connection is properly initialized, false otherwise.
|
||||
*/
|
||||
scoped_connection & operator=(connection &&other) {
|
||||
static_cast<connection &>(*this) = std::move(other);
|
||||
return *this;
|
||||
explicit operator bool() const ENTT_NOEXCEPT {
|
||||
return static_cast<bool>(conn);
|
||||
}
|
||||
|
||||
/*! @brief Breaks the connection. */
|
||||
void release() {
|
||||
conn.release();
|
||||
}
|
||||
|
||||
private:
|
||||
connection conn;
|
||||
};
|
||||
|
||||
|
||||
@@ -309,9 +271,9 @@ class sink<Ret(Args...)> {
|
||||
sink{*static_cast<signal_type *>(signal)}.disconnect<Candidate>(value_or_instance);
|
||||
}
|
||||
|
||||
template<auto Function>
|
||||
template<auto Candidate>
|
||||
static void release(void *signal) {
|
||||
sink{*static_cast<signal_type *>(signal)}.disconnect<Function>();
|
||||
sink{*static_cast<signal_type *>(signal)}.disconnect<Candidate>();
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -333,7 +295,8 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink that connects before a given function.
|
||||
* @brief Returns a sink that connects before a given free function or an
|
||||
* unbound member.
|
||||
* @tparam Function A valid free function pointer.
|
||||
* @return A properly initialized sink object.
|
||||
*/
|
||||
@@ -351,38 +314,17 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink that connects before a given member function or
|
||||
* free function with payload.
|
||||
* @brief Returns a sink that connects before a free function with payload
|
||||
* or a bound member.
|
||||
* @tparam Candidate Member or free function to look for.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid reference that fits the purpose.
|
||||
* @param value_or_instance A valid object that fits the purpose.
|
||||
* @return A properly initialized sink object.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
sink before(Type &value_or_instance) {
|
||||
sink before(Type &&value_or_instance) {
|
||||
delegate<Ret(Args...)> call{};
|
||||
call.template connect<Candidate>(value_or_instance);
|
||||
|
||||
const auto &calls = signal->calls;
|
||||
const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call));
|
||||
|
||||
sink other{*this};
|
||||
other.offset = std::distance(it, calls.cend());
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink that connects before a given member function or
|
||||
* free function with payload.
|
||||
* @tparam Candidate Member or free function to look for.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid pointer that fits the purpose.
|
||||
* @return A properly initialized sink object.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
sink before(Type *value_or_instance) {
|
||||
delegate<Ret(Args...)> call{};
|
||||
call.template connect<Candidate>(value_or_instance);
|
||||
call.template connect<Candidate>(std::forward<Type>(value_or_instance));
|
||||
|
||||
const auto &calls = signal->calls;
|
||||
const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call));
|
||||
@@ -438,29 +380,29 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects a free function to a signal.
|
||||
* @brief Connects a free function or an unbound member to a signal.
|
||||
*
|
||||
* The signal handler performs checks to avoid multiple connections for free
|
||||
* functions.
|
||||
* The signal handler performs checks to avoid multiple connections for the
|
||||
* same function.
|
||||
*
|
||||
* @tparam Function A valid free function pointer.
|
||||
* @tparam Candidate Function or member to connect to the signal.
|
||||
* @return A properly initialized connection object.
|
||||
*/
|
||||
template<auto Function>
|
||||
template<auto Candidate>
|
||||
connection connect() {
|
||||
disconnect<Function>();
|
||||
disconnect<Candidate>();
|
||||
|
||||
delegate<Ret(Args...)> call{};
|
||||
call.template connect<Function>();
|
||||
call.template connect<Candidate>();
|
||||
signal->calls.insert(signal->calls.end() - offset, std::move(call));
|
||||
|
||||
delegate<void(void *)> conn{};
|
||||
conn.template connect<&release<Function>>();
|
||||
conn.template connect<&release<Candidate>>();
|
||||
return { std::move(conn), signal };
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects a member function or a free function with payload to a
|
||||
* @brief Connects a free function with payload or a bound member to a
|
||||
* signal.
|
||||
*
|
||||
* The signal isn't responsible for the connected object or the payload.
|
||||
@@ -471,13 +413,13 @@ public:
|
||||
* such that the instance is the first argument before the ones used to
|
||||
* define the delegate itself.
|
||||
*
|
||||
* @tparam Candidate Member or free function to connect to the signal.
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid reference that fits the purpose.
|
||||
* @param value_or_instance A valid object that fits the purpose.
|
||||
* @return A properly initialized connection object.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
connection connect(Type &value_or_instance) {
|
||||
connection connect(Type &&value_or_instance) {
|
||||
disconnect<Candidate>(value_or_instance);
|
||||
|
||||
delegate<Ret(Args...)> call{};
|
||||
@@ -485,85 +427,40 @@ public:
|
||||
signal->calls.insert(signal->calls.end() - offset, std::move(call));
|
||||
|
||||
delegate<void(void *)> conn{};
|
||||
conn.template connect<&release<Candidate, Type &>>(value_or_instance);
|
||||
conn.template connect<&release<Candidate, Type>>(value_or_instance);
|
||||
return { std::move(conn), signal };
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects a member function or a free function with payload to a
|
||||
* signal.
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* @tparam Candidate Member or free function to connect to the signal.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid pointer that fits the purpose.
|
||||
* @return A properly initialized connection object.
|
||||
* @brief Disconnects a free function or an unbound member from a signal.
|
||||
* @tparam Candidate Function or member to disconnect from the delegate.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
connection connect(Type *value_or_instance) {
|
||||
disconnect<Candidate>(value_or_instance);
|
||||
|
||||
delegate<Ret(Args...)> call{};
|
||||
call.template connect<Candidate>(value_or_instance);
|
||||
signal->calls.insert(signal->calls.end() - offset, std::move(call));
|
||||
|
||||
delegate<void(void *)> conn{};
|
||||
conn.template connect<&release<Candidate, Type *>>(value_or_instance);
|
||||
return { std::move(conn), signal };
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnects a free function from a signal.
|
||||
* @tparam Function A valid free function pointer.
|
||||
*/
|
||||
template<auto Function>
|
||||
template<auto Candidate>
|
||||
void disconnect() {
|
||||
auto &calls = signal->calls;
|
||||
delegate<Ret(Args...)> call{};
|
||||
call.template connect<Function>();
|
||||
call.template connect<Candidate>();
|
||||
calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnects a member function or a free function with payload from
|
||||
* a signal.
|
||||
* @tparam Candidate Member or free function to disconnect from the signal.
|
||||
* @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 Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid reference that fits the purpose.
|
||||
* @param value_or_instance A valid object that fits the purpose.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
void disconnect(Type &value_or_instance) {
|
||||
void disconnect(Type &&value_or_instance) {
|
||||
auto &calls = signal->calls;
|
||||
delegate<Ret(Args...)> call{};
|
||||
call.template connect<Candidate>(value_or_instance);
|
||||
call.template connect<Candidate>(std::forward<Type>(value_or_instance));
|
||||
calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnects a member function or a free function with payload from
|
||||
* a signal.
|
||||
* @tparam Candidate Member or free function to disconnect from the signal.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid pointer that fits the purpose.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
void disconnect(Type *value_or_instance) {
|
||||
auto &calls = signal->calls;
|
||||
delegate<Ret(Args...)> call{};
|
||||
call.template connect<Candidate>(value_or_instance);
|
||||
calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnects member functions or free functions based on an
|
||||
* instance or specific payload.
|
||||
* @brief Disconnects free functions with payload or bound members from a
|
||||
* signal.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid object that fits the purpose.
|
||||
*/
|
||||
@@ -573,10 +470,10 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnects member functions or free functions based on an
|
||||
* instance or specific payload.
|
||||
* @brief Disconnects free functions with payload or bound members from a
|
||||
* signal.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid pointer that fits the purpose.
|
||||
* @param value_or_instance A valid object that fits the purpose.
|
||||
*/
|
||||
template<typename Type>
|
||||
void disconnect(Type *value_or_instance) {
|
||||
@@ -615,4 +512,4 @@ sink(sigh<Ret(Args...)> &) ENTT_NOEXCEPT -> sink<Ret(Args...)>;
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_SIGNAL_SIGH_HPP
|
||||
#endif
|
||||
|
||||
@@ -2,128 +2,201 @@
|
||||
# Tests configuration
|
||||
#
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(FIND_GTEST_PACKAGE)
|
||||
find_package(GTest REQUIRED)
|
||||
else()
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
FetchContent_GetProperties(googletest)
|
||||
|
||||
if(NOT googletest_POPULATED)
|
||||
FetchContent_Populate(googletest)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
add_library(GTest::Main ALIAS gtest_main)
|
||||
|
||||
target_compile_features(gtest PUBLIC cxx_std_17)
|
||||
target_compile_features(gtest_main PUBLIC cxx_std_17)
|
||||
target_compile_features(gmock PUBLIC cxx_std_17)
|
||||
target_compile_features(gmock_main PUBLIC cxx_std_17)
|
||||
endif()
|
||||
|
||||
include_directories($<TARGET_PROPERTY:EnTT,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
add_compile_options($<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_OPTIONS>)
|
||||
|
||||
macro(SETUP_LIBRARY_TARGET LIB_TARGET)
|
||||
set_target_properties(${LIB_TARGET} PROPERTIES CXX_EXTENSIONS OFF)
|
||||
target_compile_definitions(${LIB_TARGET} PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_DEFINITIONS>)
|
||||
target_compile_features(${LIB_TARGET} PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>)
|
||||
target_compile_options(${LIB_TARGET} PRIVATE $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-pedantic -Wall -Wshadow>)
|
||||
target_compile_options(${LIB_TARGET} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/EHsc /W2>)
|
||||
endmacro()
|
||||
function(SETUP_TARGET TARGET_NAME)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES CXX_EXTENSIONS OFF)
|
||||
target_link_libraries(${TARGET_NAME} PRIVATE EnTT)
|
||||
|
||||
target_compile_options(
|
||||
${TARGET_NAME}
|
||||
PRIVATE
|
||||
$<$<NOT:$<PLATFORM_ID:Windows>>:-pedantic -fvisibility=hidden -Wall -Wshadow -Wno-deprecated-declarations>
|
||||
$<$<PLATFORM_ID:Windows>:/EHsc /W1 /wd4996 /w14800>
|
||||
)
|
||||
|
||||
target_compile_options(
|
||||
${TARGET_NAME}
|
||||
PRIVATE
|
||||
$<$<AND:$<CONFIG:Debug>,$<NOT:$<PLATFORM_ID:Windows>>>:-O0 -g>
|
||||
$<$<AND:$<CONFIG:Release>,$<NOT:$<PLATFORM_ID:Windows>>>:-O2>
|
||||
$<$<AND:$<CONFIG:Debug>,$<PLATFORM_ID:Windows>>:/Od>
|
||||
$<$<AND:$<CONFIG:Release>,$<PLATFORM_ID:Windows>>:/O2>
|
||||
)
|
||||
endfunction()
|
||||
|
||||
add_library(odr OBJECT odr.cpp)
|
||||
SETUP_LIBRARY_TARGET(odr)
|
||||
SETUP_TARGET(odr)
|
||||
|
||||
macro(SETUP_AND_ADD_TEST TEST_NAME TEST_SOURCE)
|
||||
add_executable(${TEST_NAME} $<TARGET_OBJECTS:odr> ${TEST_SOURCE})
|
||||
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 -Wshadow>)
|
||||
target_compile_options(${TEST_NAME} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/EHsc /W2>)
|
||||
function(SETUP_BASIC_TEST TEST_NAME TEST_SOURCES)
|
||||
add_executable(${TEST_NAME} $<TARGET_OBJECTS:odr> ${TEST_SOURCES})
|
||||
target_link_libraries(${TEST_NAME} PRIVATE GTest::Main Threads::Threads)
|
||||
SETUP_TARGET(${TEST_NAME})
|
||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
function(SETUP_LIB_TEST TEST_NAME)
|
||||
add_library(_${TEST_NAME} SHARED lib/${TEST_NAME}/lib.cpp)
|
||||
SETUP_TARGET(_${TEST_NAME})
|
||||
SETUP_BASIC_TEST(lib_${TEST_NAME} lib/${TEST_NAME}/main.cpp)
|
||||
target_compile_definitions(_${TEST_NAME} PRIVATE ENTT_API_EXPORT ${ARGV1})
|
||||
target_compile_definitions(lib_${TEST_NAME} PRIVATE ENTT_API_IMPORT ${ARGV1})
|
||||
target_link_libraries(lib_${TEST_NAME} PRIVATE _${TEST_NAME})
|
||||
endfunction()
|
||||
|
||||
function(SETUP_PLUGIN_TEST TEST_NAME)
|
||||
add_library(_${TEST_NAME} MODULE lib/${TEST_NAME}/plugin.cpp)
|
||||
SETUP_TARGET(_${TEST_NAME})
|
||||
SETUP_BASIC_TEST(lib_${TEST_NAME} lib/${TEST_NAME}/main.cpp)
|
||||
target_include_directories(_${TEST_NAME} PRIVATE ${cr_INCLUDE_DIR})
|
||||
target_include_directories(lib_${TEST_NAME} PRIVATE ${cr_INCLUDE_DIR})
|
||||
target_compile_definitions(lib_${TEST_NAME} PRIVATE NOMINMAX PLUGIN="$<TARGET_FILE:_${TEST_NAME}>" ${ARGV1})
|
||||
target_compile_definitions(_${TEST_NAME} PRIVATE NOMINMAX ${ARGV1})
|
||||
target_link_libraries(lib_${TEST_NAME} PRIVATE ${CMAKE_DL_LIBS})
|
||||
endfunction()
|
||||
|
||||
# Test benchmark
|
||||
|
||||
if(BUILD_BENCHMARK)
|
||||
SETUP_AND_ADD_TEST(benchmark benchmark/benchmark.cpp)
|
||||
SETUP_BASIC_TEST(benchmark benchmark/benchmark.cpp)
|
||||
endif()
|
||||
|
||||
# Test lib
|
||||
|
||||
if(BUILD_LIB)
|
||||
add_library(a_module_shared SHARED lib/a_module.cpp)
|
||||
add_library(a_module_static STATIC lib/a_module.cpp)
|
||||
add_library(another_module_shared SHARED lib/another_module.cpp)
|
||||
add_library(another_module_static STATIC lib/another_module.cpp)
|
||||
FetchContent_Declare(
|
||||
cr
|
||||
GIT_REPOSITORY https://github.com/fungos/cr.git
|
||||
GIT_TAG master
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
SETUP_LIBRARY_TARGET(a_module_shared)
|
||||
SETUP_LIBRARY_TARGET(a_module_static)
|
||||
SETUP_LIBRARY_TARGET(another_module_shared)
|
||||
SETUP_LIBRARY_TARGET(another_module_static)
|
||||
FetchContent_GetProperties(cr)
|
||||
|
||||
SETUP_AND_ADD_TEST(lib_shared lib/lib.cpp)
|
||||
target_link_libraries(lib_shared PRIVATE a_module_shared another_module_shared)
|
||||
if(NOT cr_POPULATED)
|
||||
FetchContent_Populate(cr)
|
||||
set(cr_INCLUDE_DIR ${cr_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
SETUP_AND_ADD_TEST(lib_static lib/lib.cpp)
|
||||
target_link_libraries(lib_static PRIVATE a_module_static another_module_static)
|
||||
endif()
|
||||
SETUP_LIB_TEST(dispatcher)
|
||||
SETUP_LIB_TEST(emitter)
|
||||
SETUP_LIB_TEST(meta)
|
||||
SETUP_LIB_TEST(registry)
|
||||
|
||||
# Test mod
|
||||
SETUP_LIB_TEST(dispatcher_std ENTT_STANDARD_CPP)
|
||||
SETUP_LIB_TEST(emitter_std ENTT_STANDARD_CPP)
|
||||
SETUP_LIB_TEST(meta_std ENTT_STANDARD_CPP)
|
||||
SETUP_LIB_TEST(registry_std ENTT_STANDARD_CPP)
|
||||
|
||||
if(BUILD_MOD)
|
||||
set(DUKTAPE_DEPS_DIR ${EnTT_SOURCE_DIR}/deps/duktape)
|
||||
configure_file(${EnTT_SOURCE_DIR}/cmake/in/duktape.in ${DUKTAPE_DEPS_DIR}/CMakeLists.txt)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${DUKTAPE_DEPS_DIR})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${DUKTAPE_DEPS_DIR})
|
||||
set(DUKTAPE_SRC_DIR ${DUKTAPE_DEPS_DIR}/src/src)
|
||||
SETUP_PLUGIN_TEST(dispatcher_plugin)
|
||||
SETUP_PLUGIN_TEST(emitter_plugin)
|
||||
SETUP_PLUGIN_TEST(meta_plugin)
|
||||
SETUP_PLUGIN_TEST(registry_plugin)
|
||||
|
||||
set(MOD_TEST_SOURCE ${DUKTAPE_SRC_DIR}/duktape.c mod/mod.cpp)
|
||||
SETUP_AND_ADD_TEST(mod "${MOD_TEST_SOURCE}")
|
||||
target_include_directories(mod PRIVATE ${DUKTAPE_SRC_DIR})
|
||||
SETUP_PLUGIN_TEST(dispatcher_plugin_std ENTT_STANDARD_CPP)
|
||||
SETUP_PLUGIN_TEST(emitter_plugin_std ENTT_STANDARD_CPP)
|
||||
SETUP_PLUGIN_TEST(meta_plugin_std ENTT_STANDARD_CPP)
|
||||
SETUP_PLUGIN_TEST(registry_plugin_std ENTT_STANDARD_CPP)
|
||||
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)
|
||||
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)
|
||||
FetchContent_Declare(
|
||||
cereal
|
||||
GIT_REPOSITORY https://github.com/USCiLab/cereal.git
|
||||
GIT_TAG v1.2.2
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
SETUP_AND_ADD_TEST(cereal snapshot/snapshot.cpp)
|
||||
target_include_directories(cereal PRIVATE ${CEREAL_SRC_DIR})
|
||||
FetchContent_GetProperties(cereal)
|
||||
|
||||
if(NOT cereal_POPULATED)
|
||||
FetchContent_Populate(cereal)
|
||||
set(cereal_INCLUDE_DIR ${cereal_SOURCE_DIR}/include)
|
||||
endif()
|
||||
|
||||
SETUP_BASIC_TEST(cereal snapshot/snapshot.cpp)
|
||||
target_include_directories(cereal PRIVATE ${cereal_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
# Test core
|
||||
|
||||
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)
|
||||
SETUP_AND_ADD_TEST(type_traits entt/core/type_traits.cpp)
|
||||
SETUP_AND_ADD_TEST(utility entt/core/utility.cpp)
|
||||
SETUP_BASIC_TEST(algorithm entt/core/algorithm.cpp)
|
||||
SETUP_BASIC_TEST(family entt/core/family.cpp)
|
||||
SETUP_BASIC_TEST(hashed_string entt/core/hashed_string.cpp)
|
||||
SETUP_BASIC_TEST(ident entt/core/ident.cpp)
|
||||
SETUP_BASIC_TEST(monostate entt/core/monostate.cpp)
|
||||
SETUP_BASIC_TEST(type_info entt/core/type_info.cpp)
|
||||
SETUP_BASIC_TEST(type_traits entt/core/type_traits.cpp)
|
||||
SETUP_BASIC_TEST(utility entt/core/utility.cpp)
|
||||
|
||||
# Test entity
|
||||
|
||||
SETUP_AND_ADD_TEST(actor entt/entity/actor.cpp)
|
||||
SETUP_AND_ADD_TEST(entity entt/entity/entity.cpp)
|
||||
SETUP_AND_ADD_TEST(group entt/entity/group.cpp)
|
||||
SETUP_AND_ADD_TEST(helper entt/entity/helper.cpp)
|
||||
SETUP_AND_ADD_TEST(observer entt/entity/observer.cpp)
|
||||
SETUP_AND_ADD_TEST(registry entt/entity/registry.cpp)
|
||||
SETUP_AND_ADD_TEST(runtime_view entt/entity/runtime_view.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(storage entt/entity/storage.cpp)
|
||||
SETUP_AND_ADD_TEST(view entt/entity/view.cpp)
|
||||
SETUP_BASIC_TEST(actor entt/entity/actor.cpp)
|
||||
SETUP_BASIC_TEST(entity entt/entity/entity.cpp)
|
||||
SETUP_BASIC_TEST(group entt/entity/group.cpp)
|
||||
SETUP_BASIC_TEST(helper entt/entity/helper.cpp)
|
||||
SETUP_BASIC_TEST(observer entt/entity/observer.cpp)
|
||||
SETUP_BASIC_TEST(registry entt/entity/registry.cpp)
|
||||
SETUP_BASIC_TEST(runtime_view entt/entity/runtime_view.cpp)
|
||||
SETUP_BASIC_TEST(snapshot entt/entity/snapshot.cpp)
|
||||
SETUP_BASIC_TEST(sparse_set entt/entity/sparse_set.cpp)
|
||||
SETUP_BASIC_TEST(storage entt/entity/storage.cpp)
|
||||
SETUP_BASIC_TEST(view entt/entity/view.cpp)
|
||||
|
||||
# Test locator
|
||||
|
||||
SETUP_AND_ADD_TEST(locator entt/locator/locator.cpp)
|
||||
SETUP_BASIC_TEST(locator entt/locator/locator.cpp)
|
||||
|
||||
# Test meta
|
||||
|
||||
SETUP_AND_ADD_TEST(meta entt/meta/meta.cpp)
|
||||
SETUP_BASIC_TEST(meta entt/meta/meta.cpp)
|
||||
|
||||
# Test process
|
||||
|
||||
SETUP_AND_ADD_TEST(process entt/process/process.cpp)
|
||||
SETUP_AND_ADD_TEST(scheduler entt/process/scheduler.cpp)
|
||||
SETUP_BASIC_TEST(process entt/process/process.cpp)
|
||||
SETUP_BASIC_TEST(scheduler entt/process/scheduler.cpp)
|
||||
|
||||
# Test resource
|
||||
|
||||
SETUP_AND_ADD_TEST(resource entt/resource/resource.cpp)
|
||||
SETUP_BASIC_TEST(resource entt/resource/resource.cpp)
|
||||
|
||||
# Test signal
|
||||
|
||||
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)
|
||||
SETUP_BASIC_TEST(delegate entt/signal/delegate.cpp)
|
||||
SETUP_BASIC_TEST(dispatcher entt/signal/dispatcher.cpp)
|
||||
SETUP_BASIC_TEST(emitter entt/signal/emitter.cpp)
|
||||
SETUP_BASIC_TEST(sigh entt/signal/sigh.cpp)
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_binary(
|
||||
name = "benchmark",
|
||||
srcs = ["benchmark.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <chrono>
|
||||
#include <iterator>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
struct position {
|
||||
@@ -44,9 +45,9 @@ void pathological(Func func) {
|
||||
|
||||
for(auto i = 0; i < 10; ++i) {
|
||||
registry.each([i = 0, ®istry](const auto entity) mutable {
|
||||
if(!(++i % 7)) { registry.reset<position>(entity); }
|
||||
if(!(++i % 11)) { registry.reset<velocity>(entity); }
|
||||
if(!(++i % 13)) { registry.reset<comp<0>>(entity); }
|
||||
if(!(++i % 7)) { registry.remove_if_exists<position>(entity); }
|
||||
if(!(++i % 11)) { registry.remove_if_exists<velocity>(entity); }
|
||||
if(!(++i % 13)) { registry.remove_if_exists<comp<0>>(entity); }
|
||||
if(!(++i % 17)) { registry.destroy(entity); }
|
||||
});
|
||||
|
||||
@@ -113,7 +114,9 @@ TEST(Benchmark, ConstructManyWithComponents) {
|
||||
std::cout << "Constructing 1000000 entities at once with components" << std::endl;
|
||||
|
||||
timer timer;
|
||||
registry.create<position, velocity>(entities.begin(), entities.end());
|
||||
registry.create(entities.begin(), entities.end());
|
||||
registry.assign<position>(entities.begin(), entities.end());
|
||||
registry.assign<velocity>(entities.begin(), entities.end());
|
||||
timer.elapsed();
|
||||
}
|
||||
|
||||
@@ -167,7 +170,7 @@ TEST(Benchmark, IterateSingleComponentRuntime1M) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = { registry.type<position>() };
|
||||
ENTT_ID_TYPE types[] = { entt::type_info<position>::id() };
|
||||
|
||||
timer timer;
|
||||
registry.runtime_view(std::begin(types), std::end(types)).each(func);
|
||||
@@ -332,7 +335,10 @@ TEST(Benchmark, IterateTwoComponentsRuntime1M) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
|
||||
ENTT_ID_TYPE types[] = {
|
||||
entt::type_info<position>::id(),
|
||||
entt::type_info<velocity>::id()
|
||||
};
|
||||
|
||||
timer timer;
|
||||
registry.runtime_view(std::begin(types), std::end(types)).each(func);
|
||||
@@ -360,7 +366,10 @@ TEST(Benchmark, IterateTwoComponentsRuntime1MHalf) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
|
||||
ENTT_ID_TYPE types[] = {
|
||||
entt::type_info<position>::id(),
|
||||
entt::type_info<velocity>::id()
|
||||
};
|
||||
|
||||
timer timer;
|
||||
registry.runtime_view(std::begin(types), std::end(types)).each(func);
|
||||
@@ -388,7 +397,10 @@ TEST(Benchmark, IterateTwoComponentsRuntime1MOne) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
|
||||
ENTT_ID_TYPE types[] = {
|
||||
entt::type_info<position>::id(),
|
||||
entt::type_info<velocity>::id()
|
||||
};
|
||||
|
||||
timer timer;
|
||||
registry.runtime_view(std::begin(types), std::end(types)).each(func);
|
||||
@@ -561,7 +573,11 @@ TEST(Benchmark, IterateThreeComponentsRuntime1M) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = { registry.type<position>(), registry.type<velocity>(), registry.type<comp<0>>() };
|
||||
ENTT_ID_TYPE types[] = {
|
||||
entt::type_info<position>::id(),
|
||||
entt::type_info<velocity>::id(),
|
||||
entt::type_info<comp<0>>::id()
|
||||
};
|
||||
|
||||
timer timer;
|
||||
registry.runtime_view(std::begin(types), std::end(types)).each(func);
|
||||
@@ -591,7 +607,11 @@ TEST(Benchmark, IterateThreeComponentsRuntime1MHalf) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = { registry.type<position>(), registry.type<velocity>(), registry.type<comp<0>>() };
|
||||
ENTT_ID_TYPE types[] = {
|
||||
entt::type_info<position>::id(),
|
||||
entt::type_info<velocity>::id(),
|
||||
entt::type_info<comp<0>>::id()
|
||||
};
|
||||
|
||||
timer timer;
|
||||
registry.runtime_view(std::begin(types), std::end(types)).each(func);
|
||||
@@ -621,7 +641,11 @@ TEST(Benchmark, IterateThreeComponentsRuntime1MOne) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = { registry.type<position>(), registry.type<velocity>(), registry.type<comp<0>>() };
|
||||
ENTT_ID_TYPE types[] = {
|
||||
entt::type_info<position>::id(),
|
||||
entt::type_info<velocity>::id(),
|
||||
entt::type_info<comp<0>>::id()
|
||||
};
|
||||
|
||||
timer timer;
|
||||
registry.runtime_view(std::begin(types), std::end(types)).each(func);
|
||||
@@ -835,12 +859,12 @@ TEST(Benchmark, IterateFiveComponentsRuntime1M) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = {
|
||||
registry.type<position>(),
|
||||
registry.type<velocity>(),
|
||||
registry.type<comp<0>>(),
|
||||
registry.type<comp<1>>(),
|
||||
registry.type<comp<2>>()
|
||||
ENTT_ID_TYPE types[] = {
|
||||
entt::type_info<position>::id(),
|
||||
entt::type_info<velocity>::id(),
|
||||
entt::type_info<comp<0>>::id(),
|
||||
entt::type_info<comp<1>>::id(),
|
||||
entt::type_info<comp<2>>::id()
|
||||
};
|
||||
|
||||
timer timer;
|
||||
@@ -875,12 +899,12 @@ TEST(Benchmark, IterateFiveComponentsRuntime1MHalf) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = {
|
||||
registry.type<position>(),
|
||||
registry.type<velocity>(),
|
||||
registry.type<comp<0>>(),
|
||||
registry.type<comp<1>>(),
|
||||
registry.type<comp<2>>()
|
||||
ENTT_ID_TYPE types[] = {
|
||||
entt::type_info<position>::id(),
|
||||
entt::type_info<velocity>::id(),
|
||||
entt::type_info<comp<0>>::id(),
|
||||
entt::type_info<comp<1>>::id(),
|
||||
entt::type_info<comp<2>>::id()
|
||||
};
|
||||
|
||||
timer timer;
|
||||
@@ -915,12 +939,12 @@ TEST(Benchmark, IterateFiveComponentsRuntime1MOne) {
|
||||
}
|
||||
|
||||
auto test = [®istry](auto func) {
|
||||
entt::component types[] = {
|
||||
registry.type<position>(),
|
||||
registry.type<velocity>(),
|
||||
registry.type<comp<0>>(),
|
||||
registry.type<comp<1>>(),
|
||||
registry.type<comp<2>>()
|
||||
ENTT_ID_TYPE types[] = {
|
||||
entt::type_info<position>::id(),
|
||||
entt::type_info<velocity>::id(),
|
||||
entt::type_info<comp<0>>::id(),
|
||||
entt::type_info<comp<1>>::id(),
|
||||
entt::type_info<comp<2>>::id()
|
||||
};
|
||||
|
||||
timer timer;
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_test(
|
||||
name = "algorithm",
|
||||
srcs = ["algorithm.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "family",
|
||||
srcs = ["family.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "hashed_string",
|
||||
srcs = ["hashed_string.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "ident",
|
||||
srcs = ["ident.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "monostate",
|
||||
srcs = ["monostate.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "type_traits",
|
||||
srcs = ["type_traits.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "utility",
|
||||
srcs = ["utility.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -52,15 +52,15 @@ TEST(HashedString, ToValue) {
|
||||
|
||||
const char *foobar = "foobar";
|
||||
|
||||
ASSERT_EQ(entt::hashed_string::to_value(foobar), 0xbf9cf968);
|
||||
ASSERT_EQ(entt::hashed_string::value(foobar), 0xbf9cf968);
|
||||
// how would you test a constexpr otherwise?
|
||||
(void)std::integral_constant<hash_type, entt::hashed_string::to_value("quux")>{};
|
||||
(void)std::integral_constant<hash_type, entt::hashed_string::value("quux")>{};
|
||||
}
|
||||
|
||||
TEST(HashedString, StringView) {
|
||||
std::string str{"__foobar__"};
|
||||
std::string_view view{str.data()+2, 6};
|
||||
ASSERT_EQ(entt::hashed_string::to_value(view.data(), view.size()), 0xbf9cf968);
|
||||
ASSERT_EQ(entt::hashed_string::value(view.data(), view.size()), 0xbf9cf968);
|
||||
}
|
||||
|
||||
TEST(HashedWString, Functionalities) {
|
||||
@@ -111,15 +111,15 @@ TEST(HashedWString, ToValue) {
|
||||
|
||||
const wchar_t *foobar = L"foobar";
|
||||
|
||||
ASSERT_EQ(entt::hashed_wstring::to_value(foobar), 0xbf9cf968);
|
||||
ASSERT_EQ(entt::hashed_wstring::value(foobar), 0xbf9cf968);
|
||||
// how would you test a constexpr otherwise?
|
||||
(void)std::integral_constant<hash_type, entt::hashed_wstring::to_value(L"quux")>{};
|
||||
(void)std::integral_constant<hash_type, entt::hashed_wstring::value(L"quux")>{};
|
||||
}
|
||||
|
||||
TEST(HashedWString, StringView) {
|
||||
std::wstring str{L"__foobar__"};
|
||||
std::wstring_view view{str.data()+2, 6};
|
||||
ASSERT_EQ(entt::hashed_wstring::to_value(view.data(), view.size()), 0xbf9cf968);
|
||||
ASSERT_EQ(entt::hashed_wstring::value(view.data(), view.size()), 0xbf9cf968);
|
||||
}
|
||||
|
||||
TEST(BasicHashedString, DeductionGuide) {
|
||||
|
||||
9
test/entt/core/type_info.cpp
Normal file
9
test/entt/core/type_info.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/type_info.hpp>
|
||||
|
||||
TEST(TypeId, Functionalities) {
|
||||
ASSERT_NE(entt::type_info<int>::id(), entt::type_info<const int>::id());
|
||||
ASSERT_NE(entt::type_info<int>::id(), entt::type_info<char>::id());
|
||||
ASSERT_EQ(entt::type_info<int>::id(), entt::type_info<int>::id());
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/config/config.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
|
||||
ENTT_NAMED_TYPE(int);
|
||||
ENTT_NAMED_STRUCT(named_struct, {});
|
||||
ENTT_NAMED_CLASS(named_class, {});
|
||||
|
||||
TEST(Choice, Functionalities) {
|
||||
ASSERT_TRUE((std::is_base_of_v<entt::choice_t<0>, entt::choice_t<1>>));
|
||||
ASSERT_FALSE((std::is_base_of_v<entt::choice_t<1>, entt::choice_t<0>>));
|
||||
@@ -27,13 +25,19 @@ TEST(IsEqualityComparable, Functionalities) {
|
||||
ASSERT_FALSE(entt::is_equality_comparable_v<void>);
|
||||
}
|
||||
|
||||
TEST(NamedTypes, Functionalities) {
|
||||
ASSERT_TRUE(entt::is_named_type_v<int>);
|
||||
ASSERT_TRUE(entt::is_named_type_v<named_struct>);
|
||||
ASSERT_TRUE(entt::is_named_type_v<named_class>);
|
||||
ASSERT_FALSE(entt::is_named_type_v<char>);
|
||||
TEST(MemberClass, Functionalities) {
|
||||
struct clazz {
|
||||
char foo(int) { return {}; }
|
||||
int bar(double, float) const { return {}; }
|
||||
bool quux;
|
||||
};
|
||||
|
||||
ASSERT_EQ(entt::named_type_traits_t<int>::value, "int"_hs);
|
||||
ASSERT_EQ(entt::named_type_traits_t<named_struct>::value, "named_struct"_hs);
|
||||
ASSERT_EQ(entt::named_type_traits_t<named_class>::value, "named_class"_hs);
|
||||
ASSERT_TRUE((std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::foo)>>));
|
||||
ASSERT_TRUE((std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::bar)>>));
|
||||
ASSERT_TRUE((std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::quux)>>));
|
||||
}
|
||||
|
||||
TEST(Tag, Functionalities) {
|
||||
ASSERT_EQ(entt::tag<"foobar"_hs>::value, entt::hashed_string::value("foobar"));
|
||||
ASSERT_TRUE((std::is_same_v<typename entt::tag<"foobar"_hs>::value_type, ENTT_ID_TYPE>));
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_test(
|
||||
name = "actor",
|
||||
copts = entt_copts,
|
||||
srcs = ["actor.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "entity",
|
||||
copts = entt_copts,
|
||||
srcs = ["entity.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "group",
|
||||
copts = entt_copts,
|
||||
srcs = ["group.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "helper",
|
||||
copts = entt_copts,
|
||||
srcs = ["helper.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "observer",
|
||||
copts = entt_copts,
|
||||
srcs = ["observer.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "prototype",
|
||||
copts = entt_copts,
|
||||
srcs = ["prototype.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "registry",
|
||||
copts = entt_copts,
|
||||
srcs = ["registry.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "runtime_view",
|
||||
copts = entt_copts,
|
||||
srcs = ["runtime_view.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "snapshot",
|
||||
copts = entt_copts,
|
||||
srcs = ["snapshot.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "sparse_set",
|
||||
copts = entt_copts,
|
||||
srcs = ["sparse_set.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "storage",
|
||||
copts = entt_copts,
|
||||
srcs = ["storage.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "view",
|
||||
copts = entt_copts,
|
||||
srcs = ["view.cpp"],
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -12,6 +12,7 @@ TEST(Entity, Null) {
|
||||
|
||||
registry.assign<int>(entity, 42);
|
||||
|
||||
ASSERT_FALSE(entt::entity{} == entt::null);
|
||||
ASSERT_TRUE(entt::entity{traits_type::entity_mask} == entt::null);
|
||||
ASSERT_TRUE(entt::entity{~typename traits_type::entity_type{}} == entt::null);
|
||||
|
||||
|
||||
@@ -468,7 +468,11 @@ TEST(NonOwningGroup, TrackEntitiesOnComponentDestruction) {
|
||||
|
||||
TEST(NonOwningGroup, Less) {
|
||||
entt::registry registry;
|
||||
const auto entity = std::get<0>(registry.create<int, char, entt::tag<"empty"_hs>>());
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.assign<int>(entity);
|
||||
registry.assign<char>(entity);
|
||||
registry.assign<entt::tag<"empty"_hs>>(entity);
|
||||
|
||||
registry.group(entt::get<int, char, entt::tag<"empty"_hs>>).less([entity](const auto entt, int, char) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
@@ -486,9 +490,31 @@ TEST(NonOwningGroup, Less) {
|
||||
registry.group(entt::get<int, char, double>).less([](const auto, int, char, double) { FAIL(); });
|
||||
}
|
||||
|
||||
TEST(NonOwningGroup, FrontBack) {
|
||||
entt::registry registry;
|
||||
auto group = registry.group<>(entt::get<const int, const char>);
|
||||
|
||||
ASSERT_EQ(group.front(), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(group.back(), static_cast<entt::entity>(entt::null));
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.assign<int>(e0);
|
||||
registry.assign<char>(e0);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
registry.assign<int>(e1);
|
||||
registry.assign<char>(e1);
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.assign<char>(entity);
|
||||
|
||||
ASSERT_EQ(group.front(), e1);
|
||||
ASSERT_EQ(group.back(), e0);
|
||||
}
|
||||
|
||||
TEST(NonOwningGroup, SignalRace) {
|
||||
entt::registry registry;
|
||||
registry.on_construct<double>().connect<&entt::registry::assign_or_replace<int>>(registry);
|
||||
registry.on_construct<double>().connect<&entt::registry::assign_or_replace<int>>();
|
||||
registry.group(entt::get<int, double>);
|
||||
|
||||
auto entity = registry.create();
|
||||
@@ -1040,7 +1066,11 @@ TEST(OwningGroup, TrackEntitiesOnComponentDestruction) {
|
||||
|
||||
TEST(OwningGroup, Less) {
|
||||
entt::registry registry;
|
||||
const auto entity = std::get<0>(registry.create<int, char, entt::tag<"empty"_hs>>());
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.assign<int>(entity);
|
||||
registry.assign<char>(entity);
|
||||
registry.assign<entt::tag<"empty"_hs>>(entity);
|
||||
|
||||
registry.group<int>(entt::get<char, entt::tag<"empty"_hs>>).less([entity](const auto entt, int, char) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
@@ -1058,9 +1088,31 @@ TEST(OwningGroup, Less) {
|
||||
registry.group<double>(entt::get<int, char>).less([](const auto, double, int, char) { FAIL(); });
|
||||
}
|
||||
|
||||
TEST(OwningGroup, FrontBack) {
|
||||
entt::registry registry;
|
||||
auto group = registry.group<const char>(entt::get<const int>);
|
||||
|
||||
ASSERT_EQ(group.front(), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(group.back(), static_cast<entt::entity>(entt::null));
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.assign<int>(e0);
|
||||
registry.assign<char>(e0);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
registry.assign<int>(e1);
|
||||
registry.assign<char>(e1);
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.assign<char>(entity);
|
||||
|
||||
ASSERT_EQ(group.front(), e1);
|
||||
ASSERT_EQ(group.back(), e0);
|
||||
}
|
||||
|
||||
TEST(OwningGroup, SignalRace) {
|
||||
entt::registry registry;
|
||||
registry.on_construct<double>().connect<&entt::registry::assign_or_replace<int>>(registry);
|
||||
registry.on_construct<double>().connect<&entt::registry::assign_or_replace<int>>();
|
||||
registry.group<int>(entt::get<double>);
|
||||
|
||||
auto entity = registry.create();
|
||||
|
||||
@@ -10,9 +10,8 @@ TEST(Helper, AsView) {
|
||||
|
||||
([](entt::view<entt::exclude_t<>, int>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::exclude_t<int>, char, double>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::exclude_t<const int>, char, double>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::exclude_t<const int>, const char, double>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::exclude_t<const int>, const char, const double>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::exclude_t<int>, const char, double>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::exclude_t<int>, const char, const double>) {})(entt::as_view{registry});
|
||||
}
|
||||
|
||||
TEST(Helper, AsGroup) {
|
||||
@@ -20,32 +19,6 @@ TEST(Helper, AsGroup) {
|
||||
const entt::registry cregistry;
|
||||
|
||||
([](entt::group<entt::exclude_t<int>, entt::get_t<char>, double>) {})(entt::as_group{registry});
|
||||
([](entt::group<entt::exclude_t<const int>, entt::get_t<char>, double>) {})(entt::as_group{registry});
|
||||
([](entt::group<entt::exclude_t<const int>, entt::get_t<const char>, double>) {})(entt::as_group{registry});
|
||||
([](entt::group<entt::exclude_t<const int>, entt::get_t<const char>, const double>) {})(entt::as_group{registry});
|
||||
}
|
||||
|
||||
TEST(Helper, Tag) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
registry.assign<entt::tag<"foobar"_hs>>(entity);
|
||||
registry.assign<int>(entity, 42);
|
||||
int counter{};
|
||||
|
||||
ASSERT_FALSE(registry.has<entt::tag<"barfoo"_hs>>(entity));
|
||||
ASSERT_TRUE(registry.has<entt::tag<"foobar"_hs>>(entity));
|
||||
|
||||
for(auto entt: registry.view<int, entt::tag<"foobar"_hs>>()) {
|
||||
(void)entt;
|
||||
++counter;
|
||||
}
|
||||
|
||||
ASSERT_NE(counter, 0);
|
||||
|
||||
for(auto entt: registry.view<entt::tag<"foobar"_hs>>()) {
|
||||
(void)entt;
|
||||
--counter;
|
||||
}
|
||||
|
||||
ASSERT_EQ(counter, 0);
|
||||
([](entt::group<entt::exclude_t<int>, entt::get_t<const char>, double>) {})(entt::as_group{registry});
|
||||
([](entt::group<entt::exclude_t<int>, entt::get_t<const char>, const double>) {})(entt::as_group{registry});
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ TEST(Observer, Functionalities) {
|
||||
ASSERT_EQ(observer.data(), nullptr);
|
||||
ASSERT_EQ(observer.begin(), observer.end());
|
||||
|
||||
const auto entity = std::get<0>(registry.create<int>());
|
||||
const auto entity = registry.create();
|
||||
registry.assign<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
@@ -80,7 +81,7 @@ TEST(Observer, AllOf) {
|
||||
observer.disconnect();
|
||||
registry.assign_or_replace<int>(entity);
|
||||
registry.assign_or_replace<char>(entity);
|
||||
registry.reset<float>(entity);
|
||||
registry.remove_if_exists<float>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
@@ -263,7 +264,8 @@ TEST(Observer, CrossRulesCornerCase) {
|
||||
TEST(Observer, Each) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, entt::collector.group<int>()};
|
||||
const auto entity = std::get<0>(registry.create<int>());
|
||||
const auto entity = registry.create();
|
||||
registry.assign<int>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/runtime_view.hpp>
|
||||
|
||||
@@ -11,7 +12,7 @@ TEST(RuntimeView, Functionalities) {
|
||||
registry.reserve<int>(0);
|
||||
registry.reserve<char>(0);
|
||||
|
||||
entt::component types[] = { registry.type<int>(), registry.type<char>() };
|
||||
ENTT_ID_TYPE types[] = { entt::type_info<int>::id(), entt::type_info<char>::id() };
|
||||
auto view = registry.runtime_view(std::begin(types), std::end(types));
|
||||
|
||||
ASSERT_TRUE(view.empty());
|
||||
@@ -26,13 +27,13 @@ TEST(RuntimeView, Functionalities) {
|
||||
|
||||
registry.assign<char>(e1);
|
||||
|
||||
auto it = registry.runtime_view(std::begin(types), std::end(types)).begin();
|
||||
auto it = view.begin();
|
||||
|
||||
ASSERT_EQ(*it, e1);
|
||||
ASSERT_EQ(++it, (registry.runtime_view(std::begin(types), std::end(types)).end()));
|
||||
ASSERT_EQ(++it, (view.end()));
|
||||
|
||||
ASSERT_NO_THROW((registry.runtime_view(std::begin(types), std::end(types)).begin()++));
|
||||
ASSERT_NO_THROW((++registry.runtime_view(std::begin(types), std::end(types)).begin()));
|
||||
ASSERT_NO_THROW((view.begin()++));
|
||||
ASSERT_NO_THROW((++view.begin()));
|
||||
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(view.size(), decltype(view.size()){1});
|
||||
@@ -54,7 +55,7 @@ TEST(RuntimeView, Iterator) {
|
||||
registry.assign<int>(entity);
|
||||
registry.assign<char>(entity);
|
||||
|
||||
entt::component types[] = { registry.type<int>(), registry.type<char>() };
|
||||
ENTT_ID_TYPE types[] = { entt::type_info<int>::id(), entt::type_info<char>::id() };
|
||||
auto view = registry.runtime_view(std::begin(types), std::end(types));
|
||||
using iterator_type = typename decltype(view)::iterator_type;
|
||||
|
||||
@@ -67,8 +68,14 @@ TEST(RuntimeView, Iterator) {
|
||||
ASSERT_EQ(end, view.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(view.begin()++, view.begin());
|
||||
ASSERT_EQ(++view.begin(), view.end());
|
||||
ASSERT_EQ(begin++, view.begin());
|
||||
ASSERT_EQ(begin--, view.end());
|
||||
|
||||
ASSERT_EQ(++begin, view.end());
|
||||
ASSERT_EQ(--begin, view.begin());
|
||||
|
||||
ASSERT_EQ(*begin, entity);
|
||||
ASSERT_EQ(*begin.operator->(), entity);
|
||||
}
|
||||
|
||||
TEST(RuntimeView, Contains) {
|
||||
@@ -84,7 +91,7 @@ TEST(RuntimeView, Contains) {
|
||||
|
||||
registry.destroy(e0);
|
||||
|
||||
entt::component types[] = { registry.type<int>(), registry.type<char>() };
|
||||
ENTT_ID_TYPE types[] = { entt::type_info<int>::id(), entt::type_info<char>::id() };
|
||||
auto view = registry.runtime_view(std::begin(types), std::end(types));
|
||||
|
||||
ASSERT_FALSE(view.contains(e0));
|
||||
@@ -103,7 +110,7 @@ TEST(RuntimeView, Empty) {
|
||||
registry.assign<char>(e1);
|
||||
registry.assign<float>(e1);
|
||||
|
||||
entt::component types[] = { registry.type<char>(), registry.type<int>(), registry.type<float>() };
|
||||
ENTT_ID_TYPE types[] = { entt::type_info<int>::id(), entt::type_info<char>::id(), entt::type_info<float>::id() };
|
||||
auto view = registry.runtime_view(std::begin(types), std::end(types));
|
||||
|
||||
view.each([](auto) { FAIL(); });
|
||||
@@ -123,7 +130,7 @@ TEST(RuntimeView, Each) {
|
||||
registry.assign<int>(e1);
|
||||
registry.assign<char>(e1);
|
||||
|
||||
entt::component types[] = { registry.type<int>(), registry.type<char>() };
|
||||
ENTT_ID_TYPE types[] = { entt::type_info<int>::id(), entt::type_info<char>::id() };
|
||||
auto view = registry.runtime_view(std::begin(types), std::end(types));
|
||||
std::size_t cnt = 0;
|
||||
|
||||
@@ -145,7 +152,7 @@ TEST(RuntimeView, EachWithHoles) {
|
||||
registry.assign<int>(e0, 0);
|
||||
registry.assign<int>(e2, 2);
|
||||
|
||||
entt::component types[] = { registry.type<int>(), registry.type<char>() };
|
||||
ENTT_ID_TYPE types[] = { entt::type_info<int>::id(), entt::type_info<char>::id() };
|
||||
auto view = registry.runtime_view(std::begin(types), std::end(types));
|
||||
|
||||
view.each([e0](auto entity) {
|
||||
@@ -159,7 +166,7 @@ TEST(RuntimeView, MissingPool) {
|
||||
const auto e0 = registry.create();
|
||||
registry.assign<int>(e0);
|
||||
|
||||
entt::component types[] = { registry.type<int>(), registry.type<char>() };
|
||||
ENTT_ID_TYPE types[] = { entt::type_info<int>::id(), entt::type_info<char>::id() };
|
||||
auto view = registry.runtime_view(std::begin(types), std::end(types));
|
||||
|
||||
ASSERT_TRUE(view.empty());
|
||||
@@ -182,7 +189,7 @@ TEST(RuntimeView, EmptyRange) {
|
||||
const auto e0 = registry.create();
|
||||
registry.assign<int>(e0);
|
||||
|
||||
const entt::component *ptr = nullptr;
|
||||
const ENTT_ID_TYPE *ptr = nullptr;
|
||||
auto view = registry.runtime_view(ptr, ptr);
|
||||
|
||||
ASSERT_TRUE(view.empty());
|
||||
|
||||
@@ -102,7 +102,7 @@ TEST(Snapshot, Dump) {
|
||||
.destroyed(output)
|
||||
.component<int, char, double, a_component, another_component>(output);
|
||||
|
||||
registry.reset();
|
||||
registry.clear();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
@@ -173,7 +173,7 @@ TEST(Snapshot, Partial) {
|
||||
.destroyed(output)
|
||||
.component<char, int>(output);
|
||||
|
||||
registry.reset();
|
||||
registry.clear();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
@@ -201,7 +201,7 @@ TEST(Snapshot, Partial) {
|
||||
.entities(output)
|
||||
.destroyed(output);
|
||||
|
||||
registry.reset();
|
||||
registry.clear();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
@@ -247,13 +247,13 @@ TEST(Snapshot, Iterator) {
|
||||
const auto size = view.size();
|
||||
|
||||
registry.snapshot().component<another_component>(output, view.begin(), view.end());
|
||||
registry.reset();
|
||||
registry.clear();
|
||||
registry.loader().component<another_component>(input);
|
||||
|
||||
ASSERT_EQ(registry.view<another_component>().size(), size);
|
||||
|
||||
registry.view<another_component>().each([](const auto entity, const auto &) {
|
||||
ASSERT_TRUE(entt::to_integer(entity) % 2);
|
||||
ASSERT_TRUE(entt::to_integral(entity) % 2);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ TEST(Snapshot, Continuous) {
|
||||
src.create();
|
||||
}
|
||||
|
||||
src.reset();
|
||||
src.clear();
|
||||
|
||||
for(int i = 0; i < 5; ++i) {
|
||||
entity = src.create();
|
||||
@@ -470,7 +470,7 @@ TEST(Snapshot, Continuous) {
|
||||
component.bar = entity;
|
||||
});
|
||||
|
||||
dst.reset<a_component>();
|
||||
dst.clear<a_component>();
|
||||
a_component_cnt = src.size<a_component>();
|
||||
|
||||
src.snapshot()
|
||||
@@ -491,7 +491,7 @@ TEST(Snapshot, Continuous) {
|
||||
|
||||
ASSERT_EQ(dst.size<a_component>(), a_component_cnt);
|
||||
|
||||
src.reset<a_component>();
|
||||
src.clear<a_component>();
|
||||
a_component_cnt = {};
|
||||
|
||||
src.snapshot()
|
||||
@@ -563,7 +563,7 @@ TEST(Snapshot, SyncDataMembers) {
|
||||
src.create();
|
||||
src.create();
|
||||
|
||||
src.reset();
|
||||
src.clear();
|
||||
|
||||
auto parent = src.create();
|
||||
auto child = src.create();
|
||||
|
||||
@@ -70,7 +70,7 @@ TEST(SparseSet, Functionalities) {
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_EQ(other.index(entt::entity{42}), 0u);
|
||||
|
||||
other.reset();
|
||||
other.clear();
|
||||
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_EQ(other.size(), 0u);
|
||||
@@ -124,7 +124,7 @@ TEST(SparseSet, BatchAdd) {
|
||||
entities[1] = entt::entity{42};
|
||||
|
||||
set.construct(entt::entity{12});
|
||||
set.batch(std::begin(entities), std::end(entities));
|
||||
set.construct(std::begin(entities), std::end(entities));
|
||||
set.construct(entt::entity{24});
|
||||
|
||||
ASSERT_TRUE(set.has(entities[0]));
|
||||
@@ -414,7 +414,7 @@ TEST(SparseSet, SortRange) {
|
||||
TEST(SparseSet, ArrangOrdered) {
|
||||
entt::sparse_set<entt::entity> set;
|
||||
entt::entity entities[5]{entt::entity{42}, entt::entity{12}, entt::entity{9}, entt::entity{7}, entt::entity{3}};
|
||||
set.batch(std::begin(entities), std::end(entities));
|
||||
set.construct(std::begin(entities), std::end(entities));
|
||||
|
||||
set.arrange(set.begin(), set.end(), [](auto...) { FAIL(); }, std::less{});
|
||||
|
||||
@@ -436,7 +436,7 @@ TEST(SparseSet, ArrangOrdered) {
|
||||
TEST(SparseSet, ArrangeReverse) {
|
||||
entt::sparse_set<entt::entity> set;
|
||||
entt::entity entities[5]{entt::entity{3}, entt::entity{7}, entt::entity{9}, entt::entity{12}, entt::entity{42}};
|
||||
set.batch(std::begin(entities), std::end(entities));
|
||||
set.construct(std::begin(entities), std::end(entities));
|
||||
|
||||
set.arrange(set.begin(), set.end(), [&set, &entities](const auto lhs, const auto rhs) {
|
||||
std::swap(entities[set.index(lhs)], entities[set.index(rhs)]);
|
||||
@@ -460,7 +460,7 @@ TEST(SparseSet, ArrangeReverse) {
|
||||
TEST(SparseSet, ArrangeUnordered) {
|
||||
entt::sparse_set<entt::entity> set;
|
||||
entt::entity entities[5]{entt::entity{9}, entt::entity{7}, entt::entity{3}, entt::entity{12}, entt::entity{42}};
|
||||
set.batch(std::begin(entities), std::end(entities));
|
||||
set.construct(std::begin(entities), std::end(entities));
|
||||
|
||||
set.arrange(set.begin(), set.end(), [&set, &entities](const auto lhs, const auto rhs) {
|
||||
std::swap(entities[set.index(lhs)], entities[set.index(rhs)]);
|
||||
@@ -484,7 +484,7 @@ TEST(SparseSet, ArrangeUnordered) {
|
||||
TEST(SparseSet, ArrangeRange) {
|
||||
entt::sparse_set<entt::entity> set;
|
||||
entt::entity entities[5]{entt::entity{9}, entt::entity{7}, entt::entity{3}, entt::entity{12}, entt::entity{42}};
|
||||
set.batch(std::begin(entities), std::end(entities));
|
||||
set.construct(std::begin(entities), std::end(entities));
|
||||
|
||||
set.arrange(set.end(), set.end(), [](const auto, const auto) { FAIL(); }, std::less{});
|
||||
|
||||
@@ -530,7 +530,7 @@ TEST(SparseSet, ArrangeRange) {
|
||||
TEST(SparseSet, ArrangeCornerCase) {
|
||||
entt::sparse_set<entt::entity> set;
|
||||
entt::entity entities[5]{entt::entity{0}, entt::entity{1}, entt::entity{4}, entt::entity{3}, entt::entity{2}};
|
||||
set.batch(std::begin(entities), std::end(entities));
|
||||
set.construct(std::begin(entities), std::end(entities));
|
||||
|
||||
set.arrange(++set.begin(), set.end(), [&set, &entities](const auto lhs, const auto rhs) {
|
||||
std::swap(entities[set.index(lhs)], entities[set.index(rhs)]);
|
||||
|
||||
@@ -60,7 +60,7 @@ TEST(Storage, Functionalities) {
|
||||
ASSERT_EQ(*pool.try_get(entt::entity{41}), 12);
|
||||
ASSERT_EQ(pool.try_get(entt::entity{99}), nullptr);
|
||||
|
||||
pool.reset();
|
||||
pool.clear();
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
@@ -100,7 +100,7 @@ TEST(Storage, BatchAdd) {
|
||||
|
||||
entities[0] = entt::entity{3};
|
||||
entities[1] = entt::entity{42};
|
||||
auto it = pool.batch(std::begin(entities), std::end(entities));
|
||||
pool.construct(std::begin(entities), std::end(entities), {});
|
||||
|
||||
ASSERT_TRUE(pool.has(entities[0]));
|
||||
ASSERT_TRUE(pool.has(entities[1]));
|
||||
@@ -109,35 +109,6 @@ TEST(Storage, BatchAdd) {
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(pool.get(entities[0]), 0);
|
||||
ASSERT_EQ(pool.get(entities[1]), 0);
|
||||
|
||||
it[0] = 1;
|
||||
it[1] = 2;
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0]), 2);
|
||||
ASSERT_EQ(pool.get(entities[1]), 1);
|
||||
}
|
||||
|
||||
TEST(Storage, BatchAddByCopy) {
|
||||
entt::storage<entt::entity, int> pool;
|
||||
entt::entity entities[2];
|
||||
|
||||
entities[0] = entt::entity{3};
|
||||
entities[1] = entt::entity{42};
|
||||
auto it = pool.batch(std::begin(entities), std::end(entities), 3);
|
||||
|
||||
ASSERT_TRUE(pool.has(entities[0]));
|
||||
ASSERT_TRUE(pool.has(entities[1]));
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(pool.get(entities[0]), 3);
|
||||
ASSERT_EQ(pool.get(entities[1]), 3);
|
||||
|
||||
it[0] = 1;
|
||||
it[1] = 2;
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0]), 2);
|
||||
ASSERT_EQ(pool.get(entities[1]), 1);
|
||||
}
|
||||
|
||||
TEST(Storage, BatchAddEmptyType) {
|
||||
@@ -147,7 +118,7 @@ TEST(Storage, BatchAddEmptyType) {
|
||||
entities[0] = entt::entity{3};
|
||||
entities[1] = entt::entity{42};
|
||||
|
||||
pool.batch(std::begin(entities), std::end(entities));
|
||||
pool.construct(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_TRUE(pool.has(entities[0]));
|
||||
ASSERT_TRUE(pool.has(entities[1]));
|
||||
@@ -169,7 +140,8 @@ TEST(Storage, AggregatesMustWork) {
|
||||
TEST(Storage, TypesFromStandardTemplateLibraryMustWork) {
|
||||
// see #37 - this test shouldn't crash, that's all
|
||||
entt::storage<entt::entity, std::unordered_set<int>> pool;
|
||||
pool.construct(entt::entity{0}).insert(42);
|
||||
pool.construct(entt::entity{0});
|
||||
pool.get(entt::entity{0}).insert(42);
|
||||
pool.destroy(entt::entity{0});
|
||||
}
|
||||
|
||||
|
||||
@@ -192,8 +192,14 @@ TEST(SingleComponentView, Find) {
|
||||
|
||||
TEST(SingleComponentView, Less) {
|
||||
entt::registry registry;
|
||||
const auto entity = std::get<0>(registry.create<int, entt::tag<"empty"_hs>>());
|
||||
registry.create<char>();
|
||||
auto create = [&](auto... component) {
|
||||
const auto entt = registry.create();
|
||||
(registry.assign<decltype(component)>(entt, component), ...);
|
||||
return entt;
|
||||
};
|
||||
|
||||
const auto entity = create(0, entt::tag<"empty"_hs>{});
|
||||
create('c');
|
||||
|
||||
registry.view<entt::tag<"empty"_hs>>().less([entity](const auto entt) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
@@ -214,6 +220,23 @@ TEST(SingleComponentView, Less) {
|
||||
});
|
||||
}
|
||||
|
||||
TEST(SingleComponentView, FrontBack) {
|
||||
entt::registry registry;
|
||||
auto view = registry.view<const int>();
|
||||
|
||||
ASSERT_EQ(view.front(), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(view.back(), static_cast<entt::entity>(entt::null));
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.assign<int>(e0);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
registry.assign<int>(e1);
|
||||
|
||||
ASSERT_EQ(view.front(), e1);
|
||||
ASSERT_EQ(view.back(), e0);
|
||||
}
|
||||
|
||||
TEST(MultiComponentView, Functionalities) {
|
||||
entt::registry registry;
|
||||
auto view = registry.view<int, char>();
|
||||
@@ -286,8 +309,14 @@ TEST(MultiComponentView, Iterator) {
|
||||
ASSERT_EQ(end, view.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(view.begin()++, view.begin());
|
||||
ASSERT_EQ(++view.begin(), view.end());
|
||||
ASSERT_EQ(begin++, view.begin());
|
||||
ASSERT_EQ(begin--, view.end());
|
||||
|
||||
ASSERT_EQ(++begin, view.end());
|
||||
ASSERT_EQ(--begin, view.begin());
|
||||
|
||||
ASSERT_EQ(*begin, entity);
|
||||
ASSERT_EQ(*begin.operator->(), entity);
|
||||
}
|
||||
|
||||
TEST(MultiComponentView, Contains) {
|
||||
@@ -520,8 +549,16 @@ TEST(MultiComponentView, ExcludedComponents) {
|
||||
|
||||
TEST(MultiComponentView, Less) {
|
||||
entt::registry registry;
|
||||
const auto entity = std::get<0>(registry.create<int, char, double, entt::tag<"empty"_hs>>());
|
||||
registry.create<int, char>();
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.assign<int>(entity);
|
||||
registry.assign<char>(entity);
|
||||
registry.assign<double>(entity);
|
||||
registry.assign<entt::tag<"empty"_hs>>(entity);
|
||||
|
||||
const auto other = registry.create();
|
||||
registry.assign<int>(other);
|
||||
registry.assign<char>(other);
|
||||
|
||||
registry.view<int, char, entt::tag<"empty"_hs>>().less([entity](const auto entt, int, char) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
@@ -549,3 +586,25 @@ TEST(MultiComponentView, Less) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(MultiComponentView, FrontBack) {
|
||||
entt::registry registry;
|
||||
auto view = registry.view<const int, const char>();
|
||||
|
||||
ASSERT_EQ(view.front(), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(view.back(), static_cast<entt::entity>(entt::null));
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.assign<int>(e0);
|
||||
registry.assign<char>(e0);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
registry.assign<int>(e1);
|
||||
registry.assign<char>(e1);
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.assign<char>(entity);
|
||||
|
||||
ASSERT_EQ(view.front(), e1);
|
||||
ASSERT_EQ(view.back(), e0);
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_test(
|
||||
name = "locator",
|
||||
srcs = ["locator.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_test(
|
||||
name = "meta",
|
||||
srcs = ["meta.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_test(
|
||||
name = "process",
|
||||
srcs = ["process.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "scheduler",
|
||||
srcs = ["scheduler.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_test(
|
||||
name = "resource",
|
||||
srcs = ["resource.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -1,41 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_test(
|
||||
name = "delegate",
|
||||
srcs = ["delegate.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "dispatcher",
|
||||
srcs = ["dispatcher.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "emitter",
|
||||
srcs = ["emitter.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "sigh",
|
||||
srcs = ["sigh.cpp"],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -352,3 +352,19 @@ TEST(Delegate, TheLessTheBetter) {
|
||||
|
||||
ASSERT_EQ(delegate(3, 'c'), 6);
|
||||
}
|
||||
|
||||
TEST(Delegate, UnboundDataMember) {
|
||||
entt::delegate<int(const delegate_functor &)> delegate;
|
||||
delegate.connect<&delegate_functor::data_member>();
|
||||
delegate_functor functor;
|
||||
|
||||
ASSERT_EQ(delegate(functor), 42);
|
||||
}
|
||||
|
||||
TEST(Delegate, UnboundMemberFunction) {
|
||||
entt::delegate<int(delegate_functor *, const int &i)> delegate;
|
||||
delegate.connect<&delegate_functor::operator()>();
|
||||
delegate_functor functor;
|
||||
|
||||
ASSERT_EQ(delegate(&functor, 3), 6);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ struct an_event {};
|
||||
struct another_event {};
|
||||
struct one_more_event {};
|
||||
|
||||
ENTT_NAMED_TYPE(an_event);
|
||||
|
||||
struct receiver {
|
||||
static void forward(entt::dispatcher &dispatcher, const an_event &event) {
|
||||
dispatcher.enqueue(event);
|
||||
@@ -44,11 +42,11 @@ TEST(Dispatcher, Functionalities) {
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
|
||||
dispatcher.enqueue<an_event>();
|
||||
dispatcher.discard<an_event>();
|
||||
dispatcher.clear<an_event>();
|
||||
dispatcher.update();
|
||||
|
||||
dispatcher.enqueue<an_event>();
|
||||
dispatcher.discard();
|
||||
dispatcher.clear();
|
||||
dispatcher.update();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
|
||||
@@ -8,30 +8,31 @@ struct foo_event { int i; char c; };
|
||||
struct bar_event {};
|
||||
struct quux_event {};
|
||||
|
||||
ENTT_NAMED_TYPE(foo_event);
|
||||
|
||||
TEST(Emitter, Clear) {
|
||||
test_emitter emitter;
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.empty<quux_event>());
|
||||
|
||||
emitter.on<foo_event>([](const auto &, const auto &){});
|
||||
emitter.once<quux_event>([](const auto &, const auto &){});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.empty<foo_event>());
|
||||
ASSERT_FALSE(emitter.empty<quux_event>());
|
||||
ASSERT_TRUE(emitter.empty<bar_event>());
|
||||
|
||||
emitter.clear<bar_event>();
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.empty<foo_event>());
|
||||
ASSERT_FALSE(emitter.empty<quux_event>());
|
||||
ASSERT_TRUE(emitter.empty<bar_event>());
|
||||
|
||||
emitter.clear<foo_event>();
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.empty<foo_event>());
|
||||
ASSERT_FALSE(emitter.empty<quux_event>());
|
||||
ASSERT_TRUE(emitter.empty<bar_event>());
|
||||
|
||||
emitter.on<foo_event>([](const auto &, const auto &){});
|
||||
@@ -39,6 +40,7 @@ TEST(Emitter, Clear) {
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.empty<foo_event>());
|
||||
ASSERT_FALSE(emitter.empty<quux_event>());
|
||||
ASSERT_FALSE(emitter.empty<bar_event>());
|
||||
|
||||
emitter.clear();
|
||||
@@ -50,19 +52,25 @@ TEST(Emitter, Clear) {
|
||||
|
||||
TEST(Emitter, ClearPublishing) {
|
||||
test_emitter emitter;
|
||||
bool invoked = false;
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
|
||||
emitter.on<bar_event>([&invoked](const auto &, auto &em){
|
||||
invoked = true;
|
||||
em.clear();
|
||||
emitter.once<foo_event>([](const auto &, auto &em){
|
||||
em.template once<foo_event>([](const auto &, auto &){});
|
||||
em.template clear<foo_event>();
|
||||
});
|
||||
|
||||
emitter.on<bar_event>([](const auto &, auto &em){
|
||||
em.template once<bar_event>([](const auto &, auto &){});
|
||||
em.template clear<bar_event>();
|
||||
});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
|
||||
emitter.publish<foo_event>();
|
||||
emitter.publish<bar_event>();
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_TRUE(invoked);
|
||||
}
|
||||
|
||||
TEST(Emitter, On) {
|
||||
|
||||
@@ -281,13 +281,14 @@ TEST_F(SigH, ScopedConnectionConstructorsAndOperators) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
entt::scoped_connection conn;
|
||||
|
||||
{
|
||||
ASSERT_FALSE(listener.k);
|
||||
ASSERT_FALSE(conn);
|
||||
|
||||
entt::scoped_connection inner{};
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_FALSE(listener.k);
|
||||
ASSERT_FALSE(inner);
|
||||
|
||||
inner = sink.connect<&sigh_listener::g>(listener);
|
||||
sigh.publish(42);
|
||||
|
||||
@@ -307,16 +308,8 @@ TEST_F(SigH, ScopedConnectionConstructorsAndOperators) {
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_FALSE(listener.k);
|
||||
ASSERT_TRUE(inner);
|
||||
|
||||
conn = std::move(inner);
|
||||
|
||||
ASSERT_FALSE(inner);
|
||||
ASSERT_TRUE(conn);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(conn);
|
||||
|
||||
conn.release();
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
@@ -423,3 +416,29 @@ TEST_F(SigH, BeforeListenerNotPresent) {
|
||||
|
||||
ASSERT_EQ(functor.value, 2);
|
||||
}
|
||||
|
||||
TEST_F(SigH, UnboundDataMember) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<bool &(sigh_listener &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
ASSERT_FALSE(listener.k);
|
||||
|
||||
sink.connect<&sigh_listener::k>();
|
||||
sigh.collect([](bool &value) { value = !value; }, listener);
|
||||
|
||||
ASSERT_TRUE(listener.k);
|
||||
}
|
||||
|
||||
TEST_F(SigH, UnboundMemberFunction) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(sigh_listener *, int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
ASSERT_FALSE(listener.k);
|
||||
|
||||
sink.connect<&sigh_listener::g>();
|
||||
sigh.publish(&listener, 42);
|
||||
|
||||
ASSERT_TRUE(listener.k);
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
load("//bazel:copts.bzl", "entt_copts")
|
||||
|
||||
cc_test(
|
||||
name = "lib",
|
||||
srcs = [
|
||||
"types.h",
|
||||
"a_module.cpp",
|
||||
"another_module.cpp",
|
||||
"lib.cpp",
|
||||
],
|
||||
copts = entt_copts,
|
||||
deps = [
|
||||
"//:entt",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -1,60 +0,0 @@
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/signal/dispatcher.hpp>
|
||||
#include <entt/signal/emitter.hpp>
|
||||
#include "types.h"
|
||||
|
||||
#ifndef LIB_EXPORT
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
#define LIB_EXPORT __declspec(dllexport)
|
||||
#elif defined __GNUC__
|
||||
#define LIB_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define LIB_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LIB_EXPORT typename entt::component a_module_int_type() {
|
||||
entt::registry registry;
|
||||
|
||||
(void)registry.type<double>();
|
||||
(void)registry.type<float>();
|
||||
|
||||
return registry.type<int>();
|
||||
}
|
||||
|
||||
LIB_EXPORT typename entt::component a_module_char_type() {
|
||||
entt::registry registry;
|
||||
|
||||
(void)registry.type<double>();
|
||||
(void)registry.type<float>();
|
||||
|
||||
return registry.type<char>();
|
||||
}
|
||||
|
||||
LIB_EXPORT void update_position(int delta, entt::registry ®istry) {
|
||||
registry.view<position, velocity>().each([delta](auto &pos, auto &vel) {
|
||||
pos.x += delta * vel.dx;
|
||||
pos.y += delta * vel.dy;
|
||||
});
|
||||
}
|
||||
|
||||
LIB_EXPORT void trigger_another_event(entt::dispatcher &dispatcher) {
|
||||
dispatcher.trigger<another_event>();
|
||||
}
|
||||
|
||||
LIB_EXPORT void emit_another_event(test_emitter &emitter) {
|
||||
emitter.publish<another_event>();
|
||||
}
|
||||
|
||||
LIB_EXPORT void a_module_bind_ctx(entt::meta_ctx context) {
|
||||
entt::meta_ctx::bind(context);
|
||||
}
|
||||
|
||||
LIB_EXPORT void a_module_meta_init() {
|
||||
entt::meta<char>().type().data<'c'>("c"_hs);
|
||||
}
|
||||
|
||||
LIB_EXPORT void a_module_meta_deinit() {
|
||||
entt::meta<char>().reset();
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/signal/dispatcher.hpp>
|
||||
#include <entt/signal/emitter.hpp>
|
||||
#include "types.h"
|
||||
|
||||
#ifndef LIB_EXPORT
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
#define LIB_EXPORT __declspec(dllexport)
|
||||
#elif defined __GNUC__
|
||||
#define LIB_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define LIB_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LIB_EXPORT typename entt::component another_module_int_type() {
|
||||
entt::registry registry;
|
||||
|
||||
(void)registry.type<char>();
|
||||
(void)registry.type<double>();
|
||||
(void)registry.type<const int>();
|
||||
(void)registry.type<const char>();
|
||||
(void)registry.type<float>();
|
||||
|
||||
return registry.type<int>();
|
||||
}
|
||||
|
||||
LIB_EXPORT typename entt::component another_module_char_type() {
|
||||
entt::registry registry;
|
||||
|
||||
(void)registry.type<int>();
|
||||
(void)registry.type<float>();
|
||||
(void)registry.type<const char>();
|
||||
(void)registry.type<const int>();
|
||||
(void)registry.type<double>();
|
||||
|
||||
return registry.type<char>();
|
||||
}
|
||||
|
||||
LIB_EXPORT void assign_velocity(int vel, entt::registry ®istry) {
|
||||
for(auto entity: registry.view<position>()) {
|
||||
registry.assign<velocity>(entity, vel, vel);
|
||||
}
|
||||
}
|
||||
|
||||
LIB_EXPORT void trigger_an_event(int payload, entt::dispatcher &dispatcher) {
|
||||
dispatcher.trigger<an_event>(payload);
|
||||
}
|
||||
|
||||
LIB_EXPORT void emit_an_event(int payload, test_emitter &emitter) {
|
||||
emitter.publish<an_event>(payload);
|
||||
}
|
||||
|
||||
LIB_EXPORT void another_module_bind_ctx(entt::meta_ctx context) {
|
||||
entt::meta_ctx::bind(context);
|
||||
}
|
||||
|
||||
LIB_EXPORT void another_module_meta_init() {
|
||||
entt::meta<int>().type().data<0>("0"_hs);
|
||||
}
|
||||
|
||||
LIB_EXPORT void another_module_meta_deinit() {
|
||||
entt::meta<int>().reset();
|
||||
}
|
||||
8
test/lib/dispatcher/lib.cpp
Normal file
8
test/lib/dispatcher/lib.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <entt/core/attribute.h>
|
||||
#include <entt/signal/dispatcher.hpp>
|
||||
#include "types.h"
|
||||
|
||||
ENTT_API void trigger(entt::dispatcher &dispatcher) {
|
||||
dispatcher.trigger<event>();
|
||||
dispatcher.trigger<message>(42);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user