Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d15a3d69f | ||
|
|
94292872dc | ||
|
|
5c8a1e7d10 | ||
|
|
e98d8426bb | ||
|
|
77f80cecf9 | ||
|
|
bce26a1499 | ||
|
|
453f1c6edc | ||
|
|
9f8a36f2c9 | ||
|
|
e6a5945463 | ||
|
|
60393fbc5f | ||
|
|
b9a925dbd4 | ||
|
|
5dbdb1bcb5 | ||
|
|
d55cefc086 | ||
|
|
5380e6d98b | ||
|
|
45cc24e0b8 | ||
|
|
76bf1791eb | ||
|
|
7e9a4c4b16 | ||
|
|
75cd5f169f | ||
|
|
10636c82a2 | ||
|
|
04a6729963 | ||
|
|
b5617398ad | ||
|
|
da14641ccb | ||
|
|
3997bd2396 | ||
|
|
c876350e05 |
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@@ -20,13 +20,19 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install g++-7
|
||||
if: ${{ matrix.compiler == 'g++-7' }}
|
||||
run: sudo apt install g++-7
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install g++-7 -y
|
||||
- name: Install g++-8
|
||||
if: ${{ matrix.compiler == 'g++-8' }}
|
||||
run: sudo apt install g++-8
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install g++-8 -y
|
||||
- name: Install clang-8
|
||||
if: ${{ matrix.compiler == 'clang++-8' }}
|
||||
run: sudo apt install clang-8
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-8 -y
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
|
||||
3
TODO
3
TODO
@@ -7,7 +7,9 @@
|
||||
* custom pools example (multi instance, tables, enable/disable, and so on...)
|
||||
|
||||
WIP:
|
||||
* HP: see msvc only issue at https://godbolt.org/z/8KW9PhG4c
|
||||
* HP: scheduler, use any (or poly?) instead of unique_ptr
|
||||
* HP: any and the like: remove constructor that accepts reference wrapper, allow only in-place T& and entt::make_any<T>(...)
|
||||
* HP: resource, forward the id to the loader from the cache and if constexpr the call to load, update doc and describe customization points
|
||||
* HP: make it possible to create views of the type `view<T, T>`, add get by index and such, allow to register custom pools by name with the registry
|
||||
* HP: add user data to type_info
|
||||
@@ -22,7 +24,6 @@ WIP:
|
||||
* HP: make runtime views use opaque storage and therefore return also elements.
|
||||
* HP: add exclude-only views to combine with packs
|
||||
* HP: entity-aware observer, add observer functions aside observer class
|
||||
* HP: any and the like: remove constructor that accepts reference wrapper, allow only in-place T&?
|
||||
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
|
||||
* pagination doesn't work nicely across boundaries probably, give it a look. RO operations are fine, adding components maybe not.
|
||||
* snapshot: support for range-based archives
|
||||
|
||||
@@ -278,7 +278,7 @@ registry.emplace_or_replace<position>(entity, 0., 0.);
|
||||
This is a slightly faster alternative for the following snippet:
|
||||
|
||||
```cpp
|
||||
if(registry.has<velocity>(entity)) {
|
||||
if(registry.all_of<velocity>(entity)) {
|
||||
registry.replace<velocity>(entity, 0., 0.);
|
||||
} else {
|
||||
registry.emplace<velocity>(entity, 0., 0.);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
|
||||
#define ENTT_VERSION_MAJOR 3
|
||||
#define ENTT_VERSION_MINOR 7
|
||||
#define ENTT_VERSION_PATCH 0
|
||||
#define ENTT_VERSION_PATCH 1
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -48,117 +48,151 @@ class basic_any {
|
||||
|
||||
template<typename Type>
|
||||
static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) {
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
if constexpr(std::is_lvalue_reference_v<Type>) {
|
||||
using base_type = std::remove_const_t<std::remove_reference_t<Type>>;
|
||||
if constexpr(std::is_void_v<Type>) {
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
case operation::MOVE:
|
||||
case operation::REF:
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if constexpr(std::is_lvalue_reference_v<Type>) {
|
||||
using base_type = std::decay_t<Type>;
|
||||
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
if constexpr(std::is_copy_constructible_v<base_type>) {
|
||||
as<basic_any>(to).template emplace<base_type>(*static_cast<const base_type *>(from.instance));
|
||||
}
|
||||
break;
|
||||
case operation::MOVE:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
[[fallthrough]];
|
||||
case operation::DTOR:
|
||||
break;
|
||||
case operation::COMP:
|
||||
return compare<base_type>(from.instance, to) ? to : nullptr;
|
||||
case operation::ADDR:
|
||||
return std::is_const_v<std::remove_reference_t<Type>> ? nullptr : from.instance;
|
||||
case operation::CADDR:
|
||||
return from.instance;
|
||||
case operation::REF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<Type>;
|
||||
break;
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<const base_type &>;
|
||||
break;
|
||||
case operation::TYPE:
|
||||
as<type_info>(to) = type_id<base_type>();
|
||||
break;
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
if constexpr(std::is_copy_constructible_v<base_type>) {
|
||||
as<basic_any>(to) = *static_cast<const base_type *>(from.instance);
|
||||
}
|
||||
} else if constexpr(in_situ<Type>) {
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
|
||||
auto *instance = const_cast<Type *>(std::launder(reinterpret_cast<const Type *>(&from.storage)));
|
||||
#else
|
||||
auto *instance = const_cast<Type *>(reinterpret_cast<const Type *>(&from.storage));
|
||||
#endif
|
||||
break;
|
||||
case operation::MOVE:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
[[fallthrough]];
|
||||
case operation::DTOR:
|
||||
break;
|
||||
case operation::COMP:
|
||||
return compare<base_type>(from.instance, to) ? to : nullptr;
|
||||
case operation::ADDR:
|
||||
return std::is_const_v<std::remove_reference_t<Type>> ? nullptr : from.instance;
|
||||
case operation::CADDR:
|
||||
return from.instance;
|
||||
case operation::REF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<Type>;
|
||||
break;
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<const base_type &>;
|
||||
break;
|
||||
case operation::TYPE:
|
||||
as<type_info>(to) = type_id<base_type>();
|
||||
break;
|
||||
}
|
||||
} else if constexpr(in_situ<Type>) {
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
|
||||
auto *instance = const_cast<Type *>(std::launder(reinterpret_cast<const Type *>(&from.storage)));
|
||||
#else
|
||||
auto *instance = const_cast<Type *>(reinterpret_cast<const Type *>(&from.storage));
|
||||
#endif
|
||||
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
new (&as<basic_any>(to).storage) Type{std::as_const(*instance)};
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
}
|
||||
break;
|
||||
case operation::MOVE:
|
||||
new (&as<basic_any>(to).storage) Type{std::move(*instance)};
|
||||
[[fallthrough]];
|
||||
case operation::DTOR:
|
||||
instance->~Type();
|
||||
break;
|
||||
case operation::COMP:
|
||||
return compare<Type>(instance, to) ? to : nullptr;
|
||||
case operation::ADDR:
|
||||
case operation::CADDR:
|
||||
return instance;
|
||||
case operation::REF:
|
||||
as<basic_any>(to).instance = instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<Type &>;
|
||||
break;
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).instance = instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<const Type &>;
|
||||
break;
|
||||
case operation::TYPE:
|
||||
as<type_info>(to) = type_id<Type>();
|
||||
break;
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
new (&as<basic_any>(to).storage) Type{std::as_const(*instance)};
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
}
|
||||
} else {
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
as<basic_any>(to).instance = new Type{*static_cast<const Type *>(from.instance)};
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
}
|
||||
break;
|
||||
case operation::MOVE:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
break;
|
||||
case operation::DTOR:
|
||||
if constexpr(std::is_array_v<Type>) {
|
||||
delete[] static_cast<const Type *>(from.instance);
|
||||
} else {
|
||||
delete static_cast<const Type *>(from.instance);
|
||||
}
|
||||
break;
|
||||
case operation::COMP:
|
||||
return compare<Type>(from.instance, to) ? to : nullptr;
|
||||
case operation::ADDR:
|
||||
case operation::CADDR:
|
||||
return from.instance;
|
||||
case operation::REF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<Type &>;
|
||||
break;
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<const Type &>;
|
||||
break;
|
||||
case operation::TYPE:
|
||||
as<type_info>(to) = type_id<Type>();
|
||||
break;
|
||||
break;
|
||||
case operation::MOVE:
|
||||
new (&as<basic_any>(to).storage) Type{std::move(*instance)};
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
break;
|
||||
case operation::DTOR:
|
||||
instance->~Type();
|
||||
break;
|
||||
case operation::COMP:
|
||||
return compare<Type>(instance, to) ? to : nullptr;
|
||||
case operation::ADDR:
|
||||
case operation::CADDR:
|
||||
return instance;
|
||||
case operation::REF:
|
||||
as<basic_any>(to).instance = instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<Type &>;
|
||||
break;
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).instance = instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<const Type &>;
|
||||
break;
|
||||
case operation::TYPE:
|
||||
as<type_info>(to) = type_id<Type>();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
as<basic_any>(to).instance = new Type{*static_cast<const Type *>(from.instance)};
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
}
|
||||
break;
|
||||
case operation::MOVE:
|
||||
as<basic_any>(to).instance = std::exchange(as<basic_any>(&from).instance, nullptr);
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
break;
|
||||
case operation::DTOR:
|
||||
if constexpr(std::is_array_v<Type>) {
|
||||
delete[] static_cast<const Type *>(from.instance);
|
||||
} else {
|
||||
delete static_cast<const Type *>(from.instance);
|
||||
}
|
||||
break;
|
||||
case operation::COMP:
|
||||
return compare<Type>(from.instance, to) ? to : nullptr;
|
||||
case operation::ADDR:
|
||||
case operation::CADDR:
|
||||
return from.instance;
|
||||
case operation::REF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<Type &>;
|
||||
break;
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<const Type &>;
|
||||
break;
|
||||
case operation::TYPE:
|
||||
as<type_info>(to) = type_id<Type>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args>
|
||||
void initialize([[maybe_unused]] Args &&... args) {
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
if constexpr(std::is_lvalue_reference_v<Type>) {
|
||||
static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments");
|
||||
instance = (std::addressof(args), ...);
|
||||
} else if constexpr(in_situ<Type>) {
|
||||
if constexpr(std::is_aggregate_v<Type>) {
|
||||
new (&storage) Type{std::forward<Args>(args)...};
|
||||
} else {
|
||||
new (&storage) Type(std::forward<Args>(args)...);
|
||||
}
|
||||
} else {
|
||||
if constexpr(std::is_aggregate_v<Type>) {
|
||||
instance = new Type{std::forward<Args>(args)...};
|
||||
} else {
|
||||
instance = new Type(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Default constructor. */
|
||||
basic_any() ENTT_NOEXCEPT
|
||||
@@ -172,20 +206,11 @@ public:
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
explicit basic_any(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
|
||||
explicit basic_any(std::in_place_type_t<Type>, Args &&... args)
|
||||
: instance{},
|
||||
vtable{&basic_vtable<Type>}
|
||||
{
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
if constexpr(std::is_lvalue_reference_v<Type>) {
|
||||
static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments");
|
||||
instance = (std::addressof(args), ...);
|
||||
} else if constexpr(in_situ<Type>) {
|
||||
new (&storage) Type(std::forward<Args>(args)...);
|
||||
} else {
|
||||
instance = new Type(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +238,7 @@ public:
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
basic_any(const basic_any &other)
|
||||
: basic_any{}
|
||||
: basic_any{std::in_place_type<void>}
|
||||
{
|
||||
other.vtable(operation::COPY, other, this);
|
||||
}
|
||||
@@ -223,10 +248,9 @@ public:
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_any(basic_any &&other) ENTT_NOEXCEPT
|
||||
: basic_any{}
|
||||
: basic_any{std::in_place_type<void>}
|
||||
{
|
||||
other.vtable(operation::MOVE, other, this);
|
||||
vtable = std::exchange(other.vtable, &basic_vtable<void>);
|
||||
}
|
||||
|
||||
/*! @brief Frees the internal storage, whatever it means. */
|
||||
@@ -235,12 +259,49 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param other The instance to assign from.
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This any object.
|
||||
*/
|
||||
basic_any & operator=(basic_any other) {
|
||||
swap(*this, other);
|
||||
basic_any & operator=(const basic_any &other) {
|
||||
vtable(operation::DTOR, *this, nullptr);
|
||||
other.vtable(operation::COPY, other, this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This any object.
|
||||
*/
|
||||
basic_any & operator=(basic_any &&other) {
|
||||
vtable(operation::DTOR, *this, nullptr);
|
||||
other.vtable(operation::MOVE, other, this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Value assignment operator.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
* @return This any object.
|
||||
*/
|
||||
template<typename Type>
|
||||
basic_any & operator=(std::reference_wrapper<Type> value) ENTT_NOEXCEPT {
|
||||
emplace<Type &>(value.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Value assignment operator.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
* @return This any object.
|
||||
*/
|
||||
template<typename Type>
|
||||
std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>, basic_any &>
|
||||
operator=(Type &&value) {
|
||||
emplace<std::decay_t<Type>>(std::forward<Type>(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -249,7 +310,7 @@ public:
|
||||
* @return The type of the contained object, if any.
|
||||
*/
|
||||
[[nodiscard]] type_info type() const ENTT_NOEXCEPT {
|
||||
type_info info;
|
||||
type_info info{};
|
||||
vtable(operation::TYPE, *this, &info);
|
||||
return info;
|
||||
}
|
||||
@@ -275,12 +336,13 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
void emplace(Args &&... args) {
|
||||
*this = basic_any{std::in_place_type<Type>, std::forward<Args>(args)...};
|
||||
std::exchange(vtable, &basic_vtable<Type>)(operation::DTOR, *this, nullptr);
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! @brief Destroys contained object */
|
||||
void reset() {
|
||||
*this = basic_any{};
|
||||
std::exchange(vtable, &basic_vtable<void>)(operation::DTOR, *this, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,19 +362,6 @@ public:
|
||||
return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swaps two any objects.
|
||||
* @param lhs A valid any object.
|
||||
* @param rhs A valid any object.
|
||||
*/
|
||||
friend void swap(basic_any &lhs, basic_any &rhs) {
|
||||
basic_any tmp{};
|
||||
lhs.vtable(operation::MOVE, lhs, &tmp);
|
||||
rhs.vtable(operation::MOVE, rhs, &lhs);
|
||||
lhs.vtable(operation::MOVE, tmp, &rhs);
|
||||
std::swap(lhs.vtable, rhs.vtable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Aliasing constructor.
|
||||
* @return An any that shares a reference to an unmanaged object.
|
||||
@@ -370,7 +419,7 @@ Type any_cast(const basic_any<Len, Align> &data) ENTT_NOEXCEPT {
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type any_cast(basic_any<Len, Align> &data) ENTT_NOEXCEPT {
|
||||
// forces const on non-reference types to make them work also with wrappers for const references
|
||||
auto * const instance = any_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>(&data);
|
||||
auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
|
||||
ENTT_ASSERT(instance);
|
||||
return static_cast<Type>(*instance);
|
||||
}
|
||||
@@ -380,7 +429,7 @@ Type any_cast(basic_any<Len, Align> &data) ENTT_NOEXCEPT {
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type any_cast(basic_any<Len, Align> &&data) ENTT_NOEXCEPT {
|
||||
// forces const on non-reference types to make them work also with wrappers for const references
|
||||
auto * const instance = any_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>(&data);
|
||||
auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
|
||||
ENTT_ASSERT(instance);
|
||||
return static_cast<Type>(std::move(*instance));
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ private:
|
||||
* @param str Human-readable identifer.
|
||||
*/
|
||||
template<typename Char, std::size_t N>
|
||||
basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT
|
||||
basic_hashed_string(const Char (&str)[N])
|
||||
-> basic_hashed_string<Char>;
|
||||
|
||||
|
||||
|
||||
@@ -562,30 +562,6 @@ template<typename Type>
|
||||
inline constexpr auto is_complete_v = is_complete<Type>::value;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is
|
||||
* hashable, false otherwise.
|
||||
* @tparam Type Potentially hashable type.
|
||||
*/
|
||||
template <typename Type, typename = void>
|
||||
struct is_std_hashable: std::false_type {};
|
||||
|
||||
|
||||
/*! @copydoc is_std_hashable */
|
||||
template <typename Type>
|
||||
struct is_std_hashable<Type, std::enable_if_t<std::is_convertible_v<decltype(std::declval<std::hash<Type>>()(std::declval<Type>())), std::size_t>>>
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Potentially hashable type.
|
||||
*/
|
||||
template <typename Type>
|
||||
inline constexpr auto is_std_hashable_v = is_std_hashable<Type>::value;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is empty
|
||||
* and the empty type optimization is enabled, false otherwise.
|
||||
|
||||
@@ -60,7 +60,8 @@ struct overloaded: Func... {
|
||||
* @tparam Func Types of function objects.
|
||||
*/
|
||||
template<class... Func>
|
||||
overloaded(Func...) -> overloaded<Func...>;
|
||||
overloaded(Func...)
|
||||
-> overloaded<Func...>;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -115,7 +115,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
|
||||
|
||||
private:
|
||||
It it;
|
||||
const std::tuple<storage_type<Get> *...> pools;
|
||||
std::tuple<storage_type<Get> *...> pools;
|
||||
};
|
||||
|
||||
iterable_group(basic_sparse_set<Entity> * const ref, const std::tuple<storage_type<Get> *...> &cpools)
|
||||
|
||||
@@ -324,7 +324,8 @@ bool operator!=(const basic_handle<Type> &lhs, const basic_handle<Other> &rhs) E
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
basic_handle(basic_registry<Entity> &, Entity) -> basic_handle<Entity>;
|
||||
basic_handle(basic_registry<Entity> &, Entity)
|
||||
-> basic_handle<Entity>;
|
||||
|
||||
|
||||
/**
|
||||
@@ -332,7 +333,8 @@ basic_handle(basic_registry<Entity> &, Entity) -> basic_handle<Entity>;
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
basic_handle(const basic_registry<Entity> &, Entity) -> basic_handle<const Entity>;
|
||||
basic_handle(const basic_registry<Entity> &, Entity)
|
||||
-> basic_handle<const Entity>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -48,19 +48,18 @@ private:
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
*
|
||||
* It allows to deduce the constness of a registry directly from the instance
|
||||
* provided to the constructor.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
as_view(basic_registry<Entity> &) ENTT_NOEXCEPT -> as_view<Entity>;
|
||||
as_view(basic_registry<Entity> &) -> as_view<Entity>;
|
||||
|
||||
|
||||
/*! @copydoc as_view */
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
as_view(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_view<const Entity>;
|
||||
as_view(const basic_registry<Entity> &) -> as_view<const Entity>;
|
||||
|
||||
|
||||
/**
|
||||
@@ -103,19 +102,18 @@ private:
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
*
|
||||
* It allows to deduce the constness of a registry directly from the instance
|
||||
* provided to the constructor.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
as_group(basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<Entity>;
|
||||
as_group(basic_registry<Entity> &) -> as_group<Entity>;
|
||||
|
||||
|
||||
/*! @copydoc as_group */
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<const Entity>;
|
||||
as_group(const basic_registry<Entity> &) -> as_group<const Entity>;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
|
||||
class iterable_view_iterator final {
|
||||
friend class iterable_view;
|
||||
|
||||
iterable_view_iterator(It from, const basic_view &parent) ENTT_NOEXCEPT
|
||||
iterable_view_iterator(It from, const basic_view *parent) ENTT_NOEXCEPT
|
||||
: it{from},
|
||||
view{parent}
|
||||
{}
|
||||
@@ -177,7 +177,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
||||
return std::tuple_cat(std::make_tuple(*it), view.get(*it));
|
||||
return std::tuple_cat(std::make_tuple(*it), view->get(*it));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT {
|
||||
@@ -190,7 +190,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
|
||||
|
||||
private:
|
||||
It it;
|
||||
const basic_view view;
|
||||
const basic_view *view;
|
||||
};
|
||||
|
||||
iterable_view(const basic_view &parent)
|
||||
@@ -202,19 +202,19 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
|
||||
using reverse_iterator = iterable_view_iterator<view_iterator<typename basic_sparse_set<Entity>::reverse_iterator>>;
|
||||
|
||||
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
|
||||
return { view.begin(), view };
|
||||
return { view.begin(), &view };
|
||||
}
|
||||
|
||||
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
|
||||
return { view.end(), view };
|
||||
return { view.end(), &view };
|
||||
}
|
||||
|
||||
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
|
||||
return { view.rbegin(), view };
|
||||
return { view.rbegin(), &view };
|
||||
}
|
||||
|
||||
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
|
||||
return { view.rend(), view };
|
||||
return { view.rend(), &view };
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -230,7 +230,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> final {
|
||||
[[nodiscard]] unchecked_type unchecked(const basic_sparse_set<Entity> *cpool) const {
|
||||
std::size_t pos{};
|
||||
unchecked_type other{};
|
||||
(static_cast<void>(std::get<storage_type<Component> *>(pools) == cpool ? nullptr : (other[pos] = std::get<storage_type<Component> *>(pools), other[pos++])), ...);
|
||||
(static_cast<void>(std::get<storage_type<Component> *>(pools) == cpool ? void() : void(other[pos++] = std::get<storage_type<Component> *>(pools))), ...);
|
||||
return other;
|
||||
}
|
||||
|
||||
@@ -681,7 +681,8 @@ public:
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid views. */
|
||||
basic_view() ENTT_NOEXCEPT
|
||||
: pools{}
|
||||
: pools{},
|
||||
filter{}
|
||||
{}
|
||||
|
||||
/**
|
||||
@@ -689,7 +690,8 @@ public:
|
||||
* @param ref The storage for the type to iterate.
|
||||
*/
|
||||
basic_view(storage_type &ref) ENTT_NOEXCEPT
|
||||
: pools{&ref}
|
||||
: pools{&ref},
|
||||
filter{}
|
||||
{}
|
||||
|
||||
/**
|
||||
@@ -956,7 +958,7 @@ private:
|
||||
* @param storage The storage for the types to iterate.
|
||||
*/
|
||||
template<typename... Storage>
|
||||
basic_view(Storage &... storage) ENTT_NOEXCEPT
|
||||
basic_view(Storage &... storage)
|
||||
-> basic_view<std::common_type_t<typename Storage::entity_type...>, entt::exclude_t<>, constness_as_t<typename Storage::value_type, Storage>...>;
|
||||
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ private:
|
||||
|
||||
static internal::meta_prop_node node{
|
||||
nullptr,
|
||||
property,
|
||||
property + 1u
|
||||
property[0u],
|
||||
property[1u]
|
||||
};
|
||||
|
||||
entt::meta_any instance{std::forward<Key>(key)};
|
||||
@@ -313,7 +313,7 @@ struct meta_factory<Type> {
|
||||
template<auto Candidate, typename Policy = as_is_t>
|
||||
auto ctor() ENTT_NOEXCEPT {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
|
||||
static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>, Type>, "The function doesn't return an object of the required type");
|
||||
static_assert(std::is_same_v<std::decay_t<typename descriptor::return_type>, Type>, "The function doesn't return an object of the required type");
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
|
||||
static internal::meta_ctor_node node{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define ENTT_META_META_HPP
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
@@ -164,8 +163,6 @@ class meta_any {
|
||||
template<typename Type>
|
||||
static void basic_vtable(const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) {
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
using base_type = std::remove_const_t<std::remove_reference_t<Type>>;
|
||||
|
||||
switch(op) {
|
||||
case operation::DTOR:
|
||||
if constexpr(!std::is_lvalue_reference_v<Type>) {
|
||||
@@ -176,39 +173,37 @@ class meta_any {
|
||||
break;
|
||||
case operation::REF:
|
||||
case operation::CREF:
|
||||
*static_cast<meta_any *>(to) = (op == operation::REF ? meta_any{std::ref(any_cast<Type &>(const_cast<any &>(from)))} : meta_any{std::cref(any_cast<const base_type &>(from))});
|
||||
*static_cast<meta_any *>(to) = (op == operation::REF ? meta_any{std::ref(any_cast<Type &>(const_cast<any &>(from)))} : meta_any{std::cref(any_cast<const std::decay_t<Type> &>(from))});
|
||||
break;
|
||||
case operation::DEREF:
|
||||
case operation::CDEREF:
|
||||
if constexpr(is_meta_pointer_like_v<base_type>) {
|
||||
// for some reason vs2017 doesn't compile when using alias declarations with pointer_traits to get the element type
|
||||
using element_type = std::remove_const_t<typename std::pointer_traits<std::remove_const_t<std::remove_reference_t<Type>>>::element_type>;
|
||||
if constexpr(is_meta_pointer_like_v<std::decay_t<Type>>) {
|
||||
using element_type = std::remove_const_t<typename std::pointer_traits<std::decay_t<Type>>::element_type>;
|
||||
|
||||
if constexpr(std::is_function_v<element_type>) {
|
||||
*static_cast<meta_any *>(to) = any_cast<base_type>(from);
|
||||
*static_cast<meta_any *>(to) = any_cast<std::decay_t<Type>>(from);
|
||||
} else if constexpr(!std::is_same_v<element_type, void>) {
|
||||
// for some reason vs2017 doesn't compile when using alias declarations with adl_meta_pointer_like
|
||||
using adl_meta_pointer_like_type = adl_meta_pointer_like<std::remove_const_t<std::remove_reference_t<Type>>>;
|
||||
using adl_meta_pointer_like_type = adl_meta_pointer_like<std::decay_t<Type>>;
|
||||
|
||||
if constexpr(std::is_lvalue_reference_v<decltype(adl_meta_pointer_like_type::dereference(std::declval<const base_type &>()))>) {
|
||||
auto &&obj = adl_meta_pointer_like_type::dereference(any_cast<const base_type &>(from));
|
||||
if constexpr(std::is_lvalue_reference_v<decltype(adl_meta_pointer_like_type::dereference(std::declval<const std::decay_t<Type> &>()))>) {
|
||||
auto &&obj = adl_meta_pointer_like_type::dereference(any_cast<const std::decay_t<Type> &>(from));
|
||||
*static_cast<meta_any *>(to) = (op == operation::DEREF ? meta_any{std::ref(obj)} : meta_any{std::cref(obj)});
|
||||
} else {
|
||||
*static_cast<meta_any *>(to) = adl_meta_pointer_like_type::dereference(any_cast<const base_type &>(from));
|
||||
*static_cast<meta_any *>(to) = adl_meta_pointer_like_type::dereference(any_cast<const std::decay_t<Type> &>(from));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case operation::SEQ:
|
||||
case operation::CSEQ:
|
||||
if constexpr(is_complete_v<meta_sequence_container_traits<base_type>>) {
|
||||
*static_cast<meta_sequence_container *>(to) = { std::in_place_type<base_type>, (op == operation::SEQ ? const_cast<any &>(from).as_ref() : from.as_ref()) };
|
||||
if constexpr(is_complete_v<meta_sequence_container_traits<std::decay_t<Type>>>) {
|
||||
*static_cast<meta_sequence_container *>(to) = { std::in_place_type<std::decay_t<Type>>, (op == operation::SEQ ? const_cast<any &>(from).as_ref() : from.as_ref()) };
|
||||
}
|
||||
break;
|
||||
case operation::ASSOC:
|
||||
case operation::CASSOC:
|
||||
if constexpr(is_complete_v<meta_associative_container_traits<base_type>>) {
|
||||
*static_cast<meta_associative_container *>(to) = { std::in_place_type<base_type>, (op == operation::ASSOC ? const_cast<any &>(from).as_ref() : from.as_ref()) };
|
||||
if constexpr(is_complete_v<meta_associative_container_traits<std::decay_t<Type>>>) {
|
||||
*static_cast<meta_associative_container *>(to) = { std::in_place_type<std::decay_t<Type>>, (op == operation::ASSOC ? const_cast<any &>(from).as_ref() : from.as_ref()) };
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -231,7 +226,7 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
explicit meta_any(std::in_place_type_t<Type>, Args &&... args)
|
||||
: storage(std::in_place_type<Type>, std::forward<Args>(args)...),
|
||||
: storage{std::in_place_type<Type>, std::forward<Args>(args)...},
|
||||
node{internal::meta_info<Type>::resolve()},
|
||||
vtable{&basic_vtable<Type>}
|
||||
{}
|
||||
@@ -251,9 +246,9 @@ public:
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_any>>>
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
|
||||
meta_any(Type &&value)
|
||||
: meta_any{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
|
||||
: meta_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)}
|
||||
{}
|
||||
|
||||
/**
|
||||
@@ -267,25 +262,62 @@ public:
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
meta_any(meta_any &&other) ENTT_NOEXCEPT
|
||||
: meta_any{}
|
||||
{
|
||||
swap(*this, other);
|
||||
}
|
||||
: storage{std::move(other.storage)},
|
||||
node{std::exchange(other.node, nullptr)},
|
||||
vtable{std::exchange(other.vtable, &basic_vtable<void>)}
|
||||
{}
|
||||
|
||||
/*! @brief Frees the internal storage, whatever it means. */
|
||||
~meta_any() {
|
||||
if(vtable) {
|
||||
vtable(operation::DTOR, storage, node);
|
||||
}
|
||||
vtable(operation::DTOR, storage, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param other The instance to assign from.
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This meta any object.
|
||||
*/
|
||||
meta_any & operator=(meta_any other) {
|
||||
swap(other, *this);
|
||||
meta_any & operator=(const meta_any &other) {
|
||||
std::exchange(vtable, other.vtable)(operation::DTOR, storage, node);
|
||||
storage = other.storage;
|
||||
node = other.node;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This meta any object.
|
||||
*/
|
||||
meta_any & operator=(meta_any &&other) {
|
||||
std::exchange(vtable, std::exchange(other.vtable, &basic_vtable<void>))(operation::DTOR, storage, node);
|
||||
storage = std::move(other.storage);
|
||||
node = std::exchange(other.node, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Value assignment operator.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
* @return This meta any object.
|
||||
*/
|
||||
template<typename Type>
|
||||
meta_any & operator=(std::reference_wrapper<Type> value) {
|
||||
emplace<Type &>(value.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Value assignment operator.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
* @return This meta any object.
|
||||
*/
|
||||
template<typename Type>
|
||||
std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>, meta_any &>
|
||||
operator=(Type &&value) {
|
||||
emplace<std::decay_t<Type>>(std::forward<Type>(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -403,9 +435,9 @@ public:
|
||||
template<typename Type>
|
||||
[[nodiscard]] Type cast() {
|
||||
// forces const on non-reference types to make them work also with wrappers for const references
|
||||
auto * const actual = try_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>();
|
||||
ENTT_ASSERT(actual);
|
||||
return static_cast<Type>(*actual);
|
||||
auto * const instance = try_cast<std::remove_reference_t<const Type>>();
|
||||
ENTT_ASSERT(instance);
|
||||
return static_cast<Type>(*instance);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,7 +466,8 @@ public:
|
||||
*/
|
||||
template<typename Type>
|
||||
bool allow_cast() {
|
||||
if(try_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>() != nullptr) {
|
||||
// forces const on non-reference types to make them work also with wrappers for const references
|
||||
if(try_cast<std::remove_reference_t<const Type>>() != nullptr) {
|
||||
return true;
|
||||
} else if(node) {
|
||||
if(const auto * const conv = internal::meta_visit<&internal::meta_type_node::conv>([info = type_id<Type>()](const auto *curr) { return curr->type()->info == info; }, node); conv) {
|
||||
@@ -454,12 +487,16 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
void emplace(Args &&... args) {
|
||||
*this = meta_any{std::in_place_type<Type>, std::forward<Args>(args)...};
|
||||
std::exchange(vtable, &basic_vtable<Type>)(operation::DTOR, storage, node);
|
||||
storage.emplace<Type>(std::forward<Args>(args)...);
|
||||
node = internal::meta_info<Type>::resolve();
|
||||
}
|
||||
|
||||
/*! @brief Destroys contained object */
|
||||
void reset() {
|
||||
*this = meta_any{};
|
||||
std::exchange(vtable, &basic_vtable<void>)(operation::DTOR, storage, node);
|
||||
storage.reset();
|
||||
node = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -531,18 +568,6 @@ public:
|
||||
return (!node && !other.node) || (node && other.node && node->info == other.node->info && storage == other.storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swaps two meta any objects.
|
||||
* @param lhs A valid meta any object.
|
||||
* @param rhs A valid meta any object.
|
||||
*/
|
||||
friend void swap(meta_any &lhs, meta_any &rhs) {
|
||||
using std::swap;
|
||||
swap(lhs.storage, rhs.storage);
|
||||
swap(lhs.vtable, rhs.vtable);
|
||||
swap(lhs.node, rhs.node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Aliasing constructor.
|
||||
* @return A meta any that shares a reference to an unmanaged object.
|
||||
@@ -613,11 +638,11 @@ struct meta_handle {
|
||||
* @tparam Type Type of object to use to initialize the handle.
|
||||
* @param value An instance of an object to use to initialize the handle.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_handle>>>
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
|
||||
meta_handle(Type &value) ENTT_NOEXCEPT
|
||||
: meta_handle{}
|
||||
{
|
||||
if constexpr(std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_any>) {
|
||||
if constexpr(std::is_same_v<std::decay_t<Type>, meta_any>) {
|
||||
any = value.as_ref();
|
||||
} else {
|
||||
any.emplace<Type &>(value);
|
||||
@@ -668,7 +693,7 @@ struct meta_prop {
|
||||
* @return A meta any containing the key stored with the property.
|
||||
*/
|
||||
[[nodiscard]] meta_any key() const {
|
||||
return node->id->as_ref();
|
||||
return node->id.as_ref();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -676,7 +701,7 @@ struct meta_prop {
|
||||
* @return A meta any containing the value stored with the property.
|
||||
*/
|
||||
[[nodiscard]] meta_any value() const {
|
||||
return *node->value;
|
||||
return node->value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -750,8 +775,8 @@ struct meta_ctor {
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] meta_any invoke([[maybe_unused]] Args &&... args) const {
|
||||
std::array<meta_any, sizeof...(Args)> arguments{std::forward<Args>(args)...};
|
||||
return invoke(arguments.data(), sizeof...(Args));
|
||||
meta_any arguments[sizeof...(Args) + 1u]{std::forward<Args>(args)...};
|
||||
return invoke(arguments, sizeof...(Args));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -768,7 +793,7 @@ struct meta_ctor {
|
||||
* @return The property associated with the given key, if any.
|
||||
*/
|
||||
[[nodiscard]] meta_prop prop(meta_any key) const {
|
||||
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node);
|
||||
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -864,7 +889,7 @@ struct meta_data {
|
||||
* @return The property associated with the given key, if any.
|
||||
*/
|
||||
[[nodiscard]] meta_prop prop(meta_any key) const {
|
||||
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node);
|
||||
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -968,8 +993,8 @@ struct meta_func {
|
||||
*/
|
||||
template<typename... Args>
|
||||
meta_any invoke(meta_handle instance, Args &&... args) const {
|
||||
std::array<meta_any, sizeof...(Args)> arguments{std::forward<Args>(args)...};
|
||||
return invoke(std::move(instance), arguments.data(), sizeof...(Args));
|
||||
meta_any arguments[sizeof...(Args) + 1u]{std::forward<Args>(args)...};
|
||||
return invoke(std::move(instance), arguments, sizeof...(Args));
|
||||
}
|
||||
|
||||
/*! @copydoc meta_ctor::prop */
|
||||
@@ -983,7 +1008,7 @@ struct meta_func {
|
||||
* @return The property associated with the given key, if any.
|
||||
*/
|
||||
[[nodiscard]] meta_prop prop(meta_any key) const {
|
||||
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node);
|
||||
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1373,8 +1398,8 @@ public:
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] meta_any construct(Args &&... args) const {
|
||||
std::array<meta_any, sizeof...(Args)> arguments{std::forward<Args>(args)...};
|
||||
return construct(arguments.data(), sizeof...(Args));
|
||||
meta_any arguments[sizeof...(Args) + 1u]{std::forward<Args>(args)...};
|
||||
return construct(arguments, sizeof...(Args));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1434,8 +1459,8 @@ public:
|
||||
*/
|
||||
template<typename... Args>
|
||||
meta_any invoke(const id_type id, meta_handle instance, Args &&... args) const {
|
||||
std::array<meta_any, sizeof...(Args)> arguments{std::forward<Args>(args)...};
|
||||
return invoke(id, std::move(instance), arguments.data(), sizeof...(Args));
|
||||
meta_any arguments[sizeof...(Args) + 1u]{std::forward<Args>(args)...};
|
||||
return invoke(id, std::move(instance), arguments, sizeof...(Args));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1491,7 +1516,7 @@ public:
|
||||
* @return The property associated with the given key, if any.
|
||||
*/
|
||||
[[nodiscard]] meta_prop prop(meta_any key) const {
|
||||
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node);
|
||||
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define ENTT_META_NODE_HPP
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -36,8 +35,8 @@ struct meta_type_node;
|
||||
|
||||
struct meta_prop_node {
|
||||
meta_prop_node * next;
|
||||
const meta_any * const id;
|
||||
meta_any * const value;
|
||||
const meta_any &id;
|
||||
meta_any &value;
|
||||
};
|
||||
|
||||
|
||||
@@ -234,7 +233,7 @@ public:
|
||||
meta_template_descriptor(),
|
||||
std::rank_v<Type>,
|
||||
[](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence<std::rank_v<Type>>{}); },
|
||||
&meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
|
||||
&meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<Type>>>>::resolve,
|
||||
&meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_extent_t<Type>>>>::resolve,
|
||||
meta_default_constructor(&node),
|
||||
meta_default_constructor(&node)
|
||||
@@ -251,7 +250,8 @@ struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>> {};
|
||||
|
||||
template<typename... Args>
|
||||
meta_type_node * meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
|
||||
return std::array<meta_type_node *, sizeof...(Args)>{{internal::meta_info<Args>::resolve()...}}[index];
|
||||
meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info<Args>::resolve()...};
|
||||
return args[index + 1u];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,17 @@ struct is_meta_pointer_like<Type *>
|
||||
{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Partial specialization used to reject pointers to arrays.
|
||||
* @tparam Type Type of elements of the array.
|
||||
* @tparam N Number of elements of the array.
|
||||
*/
|
||||
template<typename Type, std::size_t N>
|
||||
struct is_meta_pointer_like<Type(*)[N]>
|
||||
: std::false_type
|
||||
{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta
|
||||
* system.
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define ENTT_META_UTILITY_HPP
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -335,7 +335,7 @@ template<typename Ret, typename... Args>
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
*/
|
||||
template<auto Candidate>
|
||||
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
|
||||
delegate(connect_arg_t<Candidate>)
|
||||
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
|
||||
|
||||
|
||||
@@ -345,7 +345,7 @@ delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
|
||||
* @tparam Type Type of class or type of payload.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
|
||||
delegate(connect_arg_t<Candidate>, Type &&)
|
||||
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
|
||||
|
||||
|
||||
@@ -355,7 +355,7 @@ delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
|
||||
* @tparam Args Types of arguments of a function type.
|
||||
*/
|
||||
template<typename Ret, typename... Args>
|
||||
delegate(Ret(*)(const void *, Args...), const void * = nullptr) ENTT_NOEXCEPT
|
||||
delegate(Ret(*)(const void *, Args...), const void * = nullptr)
|
||||
-> delegate<Ret(Args...)>;
|
||||
|
||||
|
||||
|
||||
@@ -510,7 +510,8 @@ private:
|
||||
* @tparam Args Types of arguments of a function type.
|
||||
*/
|
||||
template<typename Ret, typename... Args>
|
||||
sink(sigh<Ret(Args...)> &) ENTT_NOEXCEPT -> sink<Ret(Args...)>;
|
||||
sink(sigh<Ret(Args...)> &)
|
||||
-> sink<Ret(Args...)>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/any.hpp>
|
||||
|
||||
struct empty {
|
||||
~empty() { ++counter; }
|
||||
inline static int counter = 0;
|
||||
};
|
||||
|
||||
struct fat {
|
||||
fat(double v1, double v2, double v3, double v4)
|
||||
: value{v1, v2, v3, v4}
|
||||
{}
|
||||
|
||||
double value[4];
|
||||
inline static int counter{0};
|
||||
|
||||
~fat() { ++counter; }
|
||||
|
||||
bool operator==(const fat &other) const {
|
||||
return std::equal(std::begin(value), std::end(value), std::begin(other.value), std::end(other.value));
|
||||
}
|
||||
};
|
||||
|
||||
struct empty {
|
||||
inline static int counter = 0;
|
||||
~empty() { ++counter; }
|
||||
inline static int counter{0};
|
||||
double value[4];
|
||||
};
|
||||
|
||||
struct not_comparable {
|
||||
@@ -40,7 +41,14 @@ struct not_copyable {
|
||||
|
||||
struct alignas(64u) over_aligned {};
|
||||
|
||||
TEST(Any, SBO) {
|
||||
struct Any: ::testing::Test {
|
||||
void SetUp() override {
|
||||
fat::counter = 0;
|
||||
empty::counter = 0;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Any, SBO) {
|
||||
entt::any any{'c'};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
@@ -49,7 +57,7 @@ TEST(Any, SBO) {
|
||||
ASSERT_EQ(entt::any_cast<char>(any), 'c');
|
||||
}
|
||||
|
||||
TEST(Any, NoSBO) {
|
||||
TEST_F(Any, NoSBO) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{instance};
|
||||
|
||||
@@ -59,7 +67,7 @@ TEST(Any, NoSBO) {
|
||||
ASSERT_EQ(entt::any_cast<fat>(any), instance);
|
||||
}
|
||||
|
||||
TEST(Any, Empty) {
|
||||
TEST_F(Any, Empty) {
|
||||
entt::any any{};
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
@@ -68,7 +76,7 @@ TEST(Any, Empty) {
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
}
|
||||
|
||||
TEST(Any, SBOInPlaceTypeConstruction) {
|
||||
TEST_F(Any, SBOInPlaceTypeConstruction) {
|
||||
entt::any any{std::in_place_type<int>, 42};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
@@ -84,7 +92,7 @@ TEST(Any, SBOInPlaceTypeConstruction) {
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST(Any, SBOAsRefConstruction) {
|
||||
TEST_F(Any, SBOAsRefConstruction) {
|
||||
int value = 42;
|
||||
entt::any any{std::ref(value)};
|
||||
|
||||
@@ -103,6 +111,12 @@ TEST(Any, SBOAsRefConstruction) {
|
||||
ASSERT_EQ(any.data(), &value);
|
||||
ASSERT_EQ(std::as_const(any).data(), &value);
|
||||
|
||||
any = std::ref(value);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(entt::any_cast<int>(&any), &value);
|
||||
|
||||
auto other = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
@@ -111,7 +125,7 @@ TEST(Any, SBOAsRefConstruction) {
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST(Any, SBOAsConstRefConstruction) {
|
||||
TEST_F(Any, SBOAsConstRefConstruction) {
|
||||
int value = 42;
|
||||
entt::any any{std::cref(value)};
|
||||
|
||||
@@ -130,6 +144,12 @@ TEST(Any, SBOAsConstRefConstruction) {
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
ASSERT_EQ(std::as_const(any).data(), &value);
|
||||
|
||||
any = std::cref(value);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(entt::any_cast<const int>(&any), &value);
|
||||
|
||||
auto other = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
@@ -138,7 +158,7 @@ TEST(Any, SBOAsConstRefConstruction) {
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST(Any, SBOCopyConstruction) {
|
||||
TEST_F(Any, SBOCopyConstruction) {
|
||||
entt::any any{42};
|
||||
entt::any other{any};
|
||||
|
||||
@@ -150,7 +170,7 @@ TEST(Any, SBOCopyConstruction) {
|
||||
ASSERT_EQ(entt::any_cast<int>(other), 42);
|
||||
}
|
||||
|
||||
TEST(Any, SBOCopyAssignment) {
|
||||
TEST_F(Any, SBOCopyAssignment) {
|
||||
entt::any any{42};
|
||||
entt::any other{3};
|
||||
|
||||
@@ -164,33 +184,35 @@ TEST(Any, SBOCopyAssignment) {
|
||||
ASSERT_EQ(entt::any_cast<int>(other), 42);
|
||||
}
|
||||
|
||||
TEST(Any, SBOMoveConstruction) {
|
||||
TEST_F(Any, SBOMoveConstruction) {
|
||||
entt::any any{42};
|
||||
entt::any other{std::move(any)};
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(any.type());
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_EQ(any.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<int>(other), 42);
|
||||
}
|
||||
|
||||
TEST(Any, SBOMoveAssignment) {
|
||||
TEST_F(Any, SBOMoveAssignment) {
|
||||
entt::any any{42};
|
||||
entt::any other{3};
|
||||
|
||||
other = std::move(any);
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(any.type());
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_EQ(any.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<int>(other), 42);
|
||||
}
|
||||
|
||||
TEST(Any, SBODirectAssignment) {
|
||||
TEST_F(Any, SBODirectAssignment) {
|
||||
entt::any any{};
|
||||
any = 42;
|
||||
|
||||
@@ -200,7 +222,7 @@ TEST(Any, SBODirectAssignment) {
|
||||
ASSERT_EQ(entt::any_cast<int>(any), 42);
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOInPlaceTypeConstruction) {
|
||||
TEST_F(Any, NoSBOInPlaceTypeConstruction) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{std::in_place_type<fat>, instance};
|
||||
|
||||
@@ -217,7 +239,7 @@ TEST(Any, NoSBOInPlaceTypeConstruction) {
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOAsRefConstruction) {
|
||||
TEST_F(Any, NoSBOAsRefConstruction) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{std::ref(instance)};
|
||||
|
||||
@@ -236,6 +258,12 @@ TEST(Any, NoSBOAsRefConstruction) {
|
||||
ASSERT_EQ(any.data(), &instance);
|
||||
ASSERT_EQ(std::as_const(any).data(), &instance);
|
||||
|
||||
any = std::ref(instance);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::type_id<fat>());
|
||||
ASSERT_EQ(entt::any_cast<fat>(&any), &instance);
|
||||
|
||||
auto other = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
@@ -244,7 +272,7 @@ TEST(Any, NoSBOAsRefConstruction) {
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOAsConstRefConstruction) {
|
||||
TEST_F(Any, NoSBOAsConstRefConstruction) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{std::cref(instance)};
|
||||
|
||||
@@ -263,6 +291,12 @@ TEST(Any, NoSBOAsConstRefConstruction) {
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
ASSERT_EQ(std::as_const(any).data(), &instance);
|
||||
|
||||
any = std::cref(instance);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::type_id<fat>());
|
||||
ASSERT_EQ(entt::any_cast<const fat>(&any), &instance);
|
||||
|
||||
auto other = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
@@ -271,7 +305,7 @@ TEST(Any, NoSBOAsConstRefConstruction) {
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOCopyConstruction) {
|
||||
TEST_F(Any, NoSBOCopyConstruction) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{instance};
|
||||
entt::any other{any};
|
||||
@@ -284,7 +318,7 @@ TEST(Any, NoSBOCopyConstruction) {
|
||||
ASSERT_EQ(entt::any_cast<fat>(other), instance);
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOCopyAssignment) {
|
||||
TEST_F(Any, NoSBOCopyAssignment) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{instance};
|
||||
entt::any other{3};
|
||||
@@ -299,19 +333,21 @@ TEST(Any, NoSBOCopyAssignment) {
|
||||
ASSERT_EQ(entt::any_cast<fat>(other), instance);
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOMoveConstruction) {
|
||||
TEST_F(Any, NoSBOMoveConstruction) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{instance};
|
||||
entt::any other{std::move(any)};
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
ASSERT_EQ(any.type(), entt::type_id<fat>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<fat>());
|
||||
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<fat>(other), instance);
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOMoveAssignment) {
|
||||
TEST_F(Any, NoSBOMoveAssignment) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{instance};
|
||||
entt::any other{3};
|
||||
@@ -320,12 +356,14 @@ TEST(Any, NoSBOMoveAssignment) {
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
ASSERT_EQ(any.type(), entt::type_id<fat>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<fat>());
|
||||
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<fat>(other), instance);
|
||||
}
|
||||
|
||||
TEST(Any, NoSBODirectAssignment) {
|
||||
TEST_F(Any, NoSBODirectAssignment) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{};
|
||||
any = instance;
|
||||
@@ -336,7 +374,7 @@ TEST(Any, NoSBODirectAssignment) {
|
||||
ASSERT_EQ(entt::any_cast<fat>(any), instance);
|
||||
}
|
||||
|
||||
TEST(Any, VoidInPlaceTypeConstruction) {
|
||||
TEST_F(Any, VoidInPlaceTypeConstruction) {
|
||||
entt::any any{std::in_place_type<void>};
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
@@ -344,7 +382,7 @@ TEST(Any, VoidInPlaceTypeConstruction) {
|
||||
ASSERT_EQ(entt::any_cast<int>(&any), nullptr);
|
||||
}
|
||||
|
||||
TEST(Any, VoidCopyConstruction) {
|
||||
TEST_F(Any, VoidCopyConstruction) {
|
||||
entt::any any{std::in_place_type<void>};
|
||||
entt::any other{any};
|
||||
|
||||
@@ -356,9 +394,9 @@ TEST(Any, VoidCopyConstruction) {
|
||||
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
|
||||
}
|
||||
|
||||
TEST(Any, VoidCopyAssignment) {
|
||||
TEST_F(Any, VoidCopyAssignment) {
|
||||
entt::any any{std::in_place_type<void>};
|
||||
entt::any other{std::in_place_type<void>};
|
||||
entt::any other{42};
|
||||
|
||||
other = any;
|
||||
|
||||
@@ -370,7 +408,7 @@ TEST(Any, VoidCopyAssignment) {
|
||||
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
|
||||
}
|
||||
|
||||
TEST(Any, VoidMoveConstruction) {
|
||||
TEST_F(Any, VoidMoveConstruction) {
|
||||
entt::any any{std::in_place_type<void>};
|
||||
entt::any other{std::move(any)};
|
||||
|
||||
@@ -382,9 +420,9 @@ TEST(Any, VoidMoveConstruction) {
|
||||
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
|
||||
}
|
||||
|
||||
TEST(Any, VoidMoveAssignment) {
|
||||
TEST_F(Any, VoidMoveAssignment) {
|
||||
entt::any any{std::in_place_type<void>};
|
||||
entt::any other{std::in_place_type<void>};
|
||||
entt::any other{42};
|
||||
|
||||
other = std::move(any);
|
||||
|
||||
@@ -396,17 +434,17 @@ TEST(Any, VoidMoveAssignment) {
|
||||
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
|
||||
}
|
||||
|
||||
TEST(Any, SBOMoveInvalidate) {
|
||||
TEST_F(Any, SBOMoveValidButUnspecifiedState) {
|
||||
entt::any any{42};
|
||||
entt::any other{std::move(any)};
|
||||
entt::any valid = std::move(other);
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_FALSE(other);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_TRUE(valid);
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOMoveInvalidate) {
|
||||
TEST_F(Any, NoSBOMoveValidButUnspecifiedState) {
|
||||
fat instance{.1, .2, .3, .4};
|
||||
entt::any any{instance};
|
||||
entt::any other{std::move(any)};
|
||||
@@ -417,7 +455,7 @@ TEST(Any, NoSBOMoveInvalidate) {
|
||||
ASSERT_TRUE(valid);
|
||||
}
|
||||
|
||||
TEST(Any, VoidMoveInvalidate) {
|
||||
TEST_F(Any, VoidMoveValidButUnspecifiedState) {
|
||||
entt::any any{std::in_place_type<void>};
|
||||
entt::any other{std::move(any)};
|
||||
entt::any valid = std::move(other);
|
||||
@@ -427,30 +465,36 @@ TEST(Any, VoidMoveInvalidate) {
|
||||
ASSERT_FALSE(valid);
|
||||
}
|
||||
|
||||
TEST(Any, SBODestruction) {
|
||||
TEST_F(Any, SBODestruction) {
|
||||
{
|
||||
entt::any any{empty{}};
|
||||
empty::counter = 0;
|
||||
entt::any any{std::in_place_type<empty>};
|
||||
any.emplace<empty>();
|
||||
any = empty{};
|
||||
entt::any other{std::move(any)};
|
||||
any = std::move(other);
|
||||
}
|
||||
|
||||
ASSERT_EQ(empty::counter, 1);
|
||||
ASSERT_EQ(empty::counter, 6);
|
||||
}
|
||||
|
||||
TEST(Any, NoSBODestruction) {
|
||||
TEST_F(Any, NoSBODestruction) {
|
||||
{
|
||||
entt::any any{fat{1., 2., 3., 4.}};
|
||||
fat::counter = 0;
|
||||
entt::any any{std::in_place_type<fat>, 1., 2., 3., 4.};
|
||||
any.emplace<fat>(1., 2., 3., 4.);
|
||||
any = fat{1., 2., 3., 4.};
|
||||
entt::any other{std::move(any)};
|
||||
any = std::move(other);
|
||||
}
|
||||
|
||||
ASSERT_EQ(fat::counter, 1);
|
||||
ASSERT_EQ(fat::counter, 4);
|
||||
}
|
||||
|
||||
TEST(Any, VoidDestruction) {
|
||||
TEST_F(Any, VoidDestruction) {
|
||||
// just let asan tell us if everything is ok here
|
||||
[[maybe_unused]] entt::any any{std::in_place_type<void>};
|
||||
}
|
||||
|
||||
TEST(Any, Emplace) {
|
||||
TEST_F(Any, Emplace) {
|
||||
entt::any any{};
|
||||
any.emplace<int>(42);
|
||||
|
||||
@@ -460,7 +504,7 @@ TEST(Any, Emplace) {
|
||||
ASSERT_EQ(entt::any_cast<int>(any), 42);
|
||||
}
|
||||
|
||||
TEST(Any, EmplaceVoid) {
|
||||
TEST_F(Any, EmplaceVoid) {
|
||||
entt::any any{};
|
||||
any.emplace<void>();
|
||||
|
||||
@@ -468,7 +512,7 @@ TEST(Any, EmplaceVoid) {
|
||||
ASSERT_FALSE(any.type());
|
||||
}
|
||||
|
||||
TEST(Any, Reset) {
|
||||
TEST_F(Any, Reset) {
|
||||
entt::any any{42};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
@@ -480,7 +524,7 @@ TEST(Any, Reset) {
|
||||
ASSERT_EQ(any.type(), entt::type_info{});
|
||||
}
|
||||
|
||||
TEST(Any, SBOSwap) {
|
||||
TEST_F(Any, SBOSwap) {
|
||||
entt::any lhs{'c'};
|
||||
entt::any rhs{42};
|
||||
|
||||
@@ -494,7 +538,7 @@ TEST(Any, SBOSwap) {
|
||||
ASSERT_EQ(entt::any_cast<char>(rhs), 'c');
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOSwap) {
|
||||
TEST_F(Any, NoSBOSwap) {
|
||||
entt::any lhs{fat{.1, .2, .3, .4}};
|
||||
entt::any rhs{fat{.4, .3, .2, .1}};
|
||||
|
||||
@@ -504,7 +548,7 @@ TEST(Any, NoSBOSwap) {
|
||||
ASSERT_EQ(entt::any_cast<fat>(rhs), (fat{.1, .2, .3, .4}));
|
||||
}
|
||||
|
||||
TEST(Any, VoidSwap) {
|
||||
TEST_F(Any, VoidSwap) {
|
||||
entt::any lhs{std::in_place_type<void>};
|
||||
entt::any rhs{std::in_place_type<void>};
|
||||
const auto *pre = lhs.data();
|
||||
@@ -514,7 +558,7 @@ TEST(Any, VoidSwap) {
|
||||
ASSERT_EQ(pre, lhs.data());
|
||||
}
|
||||
|
||||
TEST(Any, SBOWithNoSBOSwap) {
|
||||
TEST_F(Any, SBOWithNoSBOSwap) {
|
||||
entt::any lhs{fat{.1, .2, .3, .4}};
|
||||
entt::any rhs{'c'};
|
||||
|
||||
@@ -528,7 +572,7 @@ TEST(Any, SBOWithNoSBOSwap) {
|
||||
ASSERT_EQ(entt::any_cast<fat>(rhs), (fat{.1, .2, .3, .4}));
|
||||
}
|
||||
|
||||
TEST(Any, SBOWithRefSwap) {
|
||||
TEST_F(Any, SBOWithRefSwap) {
|
||||
int value = 3;
|
||||
entt::any lhs{std::ref(value)};
|
||||
entt::any rhs{'c'};
|
||||
@@ -544,7 +588,7 @@ TEST(Any, SBOWithRefSwap) {
|
||||
ASSERT_EQ(rhs.data(), &value);
|
||||
}
|
||||
|
||||
TEST(Any, SBOWithConstRefSwap) {
|
||||
TEST_F(Any, SBOWithConstRefSwap) {
|
||||
int value = 3;
|
||||
entt::any lhs{std::cref(value)};
|
||||
entt::any rhs{'c'};
|
||||
@@ -561,7 +605,7 @@ TEST(Any, SBOWithConstRefSwap) {
|
||||
ASSERT_EQ(std::as_const(rhs).data(), &value);
|
||||
}
|
||||
|
||||
TEST(Any, SBOWithEmptySwap) {
|
||||
TEST_F(Any, SBOWithEmptySwap) {
|
||||
entt::any lhs{'c'};
|
||||
entt::any rhs{};
|
||||
|
||||
@@ -582,7 +626,7 @@ TEST(Any, SBOWithEmptySwap) {
|
||||
ASSERT_EQ(entt::any_cast<char>(lhs), 'c');
|
||||
}
|
||||
|
||||
TEST(Any, SBOWithVoidSwap) {
|
||||
TEST_F(Any, SBOWithVoidSwap) {
|
||||
entt::any lhs{'c'};
|
||||
entt::any rhs{std::in_place_type<void>};
|
||||
|
||||
@@ -603,7 +647,7 @@ TEST(Any, SBOWithVoidSwap) {
|
||||
ASSERT_EQ(entt::any_cast<char>(lhs), 'c');
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOWithRefSwap) {
|
||||
TEST_F(Any, NoSBOWithRefSwap) {
|
||||
int value = 3;
|
||||
entt::any lhs{std::ref(value)};
|
||||
entt::any rhs{fat{.1, .2, .3, .4}};
|
||||
@@ -619,7 +663,7 @@ TEST(Any, NoSBOWithRefSwap) {
|
||||
ASSERT_EQ(rhs.data(), &value);
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOWithConstRefSwap) {
|
||||
TEST_F(Any, NoSBOWithConstRefSwap) {
|
||||
int value = 3;
|
||||
entt::any lhs{std::cref(value)};
|
||||
entt::any rhs{fat{.1, .2, .3, .4}};
|
||||
@@ -636,7 +680,7 @@ TEST(Any, NoSBOWithConstRefSwap) {
|
||||
ASSERT_EQ(std::as_const(rhs).data(), &value);
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOWithEmptySwap) {
|
||||
TEST_F(Any, NoSBOWithEmptySwap) {
|
||||
entt::any lhs{fat{.1, .2, .3, .4}};
|
||||
entt::any rhs{};
|
||||
|
||||
@@ -657,7 +701,7 @@ TEST(Any, NoSBOWithEmptySwap) {
|
||||
ASSERT_EQ(entt::any_cast<fat>(lhs), (fat{.1, .2, .3, .4}));
|
||||
}
|
||||
|
||||
TEST(Any, NoSBOWithVoidSwap) {
|
||||
TEST_F(Any, NoSBOWithVoidSwap) {
|
||||
entt::any lhs{fat{.1, .2, .3, .4}};
|
||||
entt::any rhs{std::in_place_type<void>};
|
||||
|
||||
@@ -678,7 +722,7 @@ TEST(Any, NoSBOWithVoidSwap) {
|
||||
ASSERT_EQ(entt::any_cast<fat>(lhs), (fat{.1, .2, .3, .4}));
|
||||
}
|
||||
|
||||
TEST(Any, AsRef) {
|
||||
TEST_F(Any, AsRef) {
|
||||
entt::any any{42};
|
||||
auto ref = any.as_ref();
|
||||
auto cref = std::as_const(any).as_ref();
|
||||
@@ -744,7 +788,7 @@ TEST(Any, AsRef) {
|
||||
ASSERT_NE(entt::any_cast<int>(&cref), any.data());
|
||||
}
|
||||
|
||||
TEST(Any, Comparable) {
|
||||
TEST_F(Any, Comparable) {
|
||||
auto test = [](entt::any any, entt::any other) {
|
||||
ASSERT_EQ(any, any);
|
||||
ASSERT_NE(other, any);
|
||||
@@ -764,7 +808,7 @@ TEST(Any, Comparable) {
|
||||
test(3, std::cref(value));
|
||||
}
|
||||
|
||||
TEST(Any, NotComparable) {
|
||||
TEST_F(Any, NotComparable) {
|
||||
auto test = [](const auto &instance) {
|
||||
entt::any any{std::cref(instance)};
|
||||
|
||||
@@ -782,7 +826,7 @@ TEST(Any, NotComparable) {
|
||||
test(std::vector<not_comparable>{});
|
||||
}
|
||||
|
||||
TEST(Any, CompareVoid) {
|
||||
TEST_F(Any, CompareVoid) {
|
||||
entt::any any{std::in_place_type<void>};
|
||||
|
||||
ASSERT_EQ(any, any);
|
||||
@@ -797,7 +841,7 @@ TEST(Any, CompareVoid) {
|
||||
ASSERT_FALSE(entt::any{} != any);
|
||||
}
|
||||
|
||||
TEST(Any, AnyCast) {
|
||||
TEST_F(Any, AnyCast) {
|
||||
entt::any any{42};
|
||||
const auto &cany = any;
|
||||
|
||||
@@ -813,7 +857,7 @@ TEST(Any, AnyCast) {
|
||||
ASSERT_DEATH(entt::any_cast<double>(entt::any{42}), "");
|
||||
}
|
||||
|
||||
TEST(Any, NotCopyableType) {
|
||||
TEST_F(Any, NotCopyableType) {
|
||||
auto test = [](entt::any any) {
|
||||
entt::any copy{any};
|
||||
|
||||
@@ -830,7 +874,7 @@ TEST(Any, NotCopyableType) {
|
||||
test(entt::any{std::in_place_type<not_copyable<4>>});
|
||||
}
|
||||
|
||||
TEST(Any, Array) {
|
||||
TEST_F(Any, Array) {
|
||||
entt::any any{std::in_place_type<int[1]>};
|
||||
entt::any copy{any};
|
||||
|
||||
@@ -847,7 +891,7 @@ TEST(Any, Array) {
|
||||
ASSERT_EQ(entt::any_cast<const int(&)[1]>(std::as_const(any))[0], 42);
|
||||
}
|
||||
|
||||
TEST(Any, CopyMoveReference) {
|
||||
TEST_F(Any, CopyMoveReference) {
|
||||
int value{};
|
||||
|
||||
auto test = [&](auto ref) {
|
||||
@@ -857,7 +901,7 @@ TEST(Any, CopyMoveReference) {
|
||||
entt::any move = std::move(any);
|
||||
entt::any copy = move;
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(move);
|
||||
ASSERT_TRUE(copy);
|
||||
|
||||
@@ -880,7 +924,7 @@ TEST(Any, CopyMoveReference) {
|
||||
test(std::cref(value));
|
||||
}
|
||||
|
||||
TEST(Any, SBOVsZeroedSBOSize) {
|
||||
TEST_F(Any, SBOVsZeroedSBOSize) {
|
||||
entt::any sbo{42};
|
||||
const auto *broken = sbo.data();
|
||||
entt::any other = std::move(sbo);
|
||||
@@ -894,7 +938,7 @@ TEST(Any, SBOVsZeroedSBOSize) {
|
||||
ASSERT_EQ(valid, same.data());
|
||||
}
|
||||
|
||||
TEST(Any, Alignment) {
|
||||
TEST_F(Any, Alignment) {
|
||||
static constexpr auto alignment = alignof(over_aligned);
|
||||
|
||||
auto test = [](auto *target, auto cb) {
|
||||
@@ -917,3 +961,23 @@ TEST(Any, Alignment) {
|
||||
entt::basic_any<alignment, alignment> sbo[2] = { over_aligned{}, over_aligned{} };
|
||||
test(sbo, [](auto *pre, auto *post) { ASSERT_NE(pre, post); });
|
||||
}
|
||||
|
||||
TEST_F(Any, AggregatesMustWork) {
|
||||
struct aggregate_type { int value; };
|
||||
// the goal of this test is to enforce the requirements for aggregate types
|
||||
entt::any{std::in_place_type<aggregate_type>, 42}.emplace<aggregate_type>(42);
|
||||
}
|
||||
|
||||
TEST_F(Any, DeducedArrayType) {
|
||||
entt::any any{"array of char"};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::type_id<const char *>());
|
||||
ASSERT_EQ((strcmp("array of char", entt::any_cast<const char *>(any))), 0);
|
||||
|
||||
any = "another array of char";
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::type_id<const char *>());
|
||||
ASSERT_EQ((strcmp("another array of char", entt::any_cast<const char *>(any))), 0);
|
||||
}
|
||||
|
||||
@@ -119,11 +119,6 @@ TEST(TypeTraits, IsComplete) {
|
||||
static_assert(!entt::is_complete_v<void>);
|
||||
}
|
||||
|
||||
TEST(TypeTraits, IsStdHashable) {
|
||||
static_assert(entt::is_std_hashable_v<int>);
|
||||
static_assert(!entt::is_std_hashable_v<not_comparable>);
|
||||
}
|
||||
|
||||
TEST(TypeTraits, ConstnessAs) {
|
||||
static_assert(std::is_same_v<entt::constness_as_t<int, char>, int>);
|
||||
static_assert(std::is_same_v<entt::constness_as_t<const int, char>, int>);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/group.hpp>
|
||||
@@ -101,15 +101,6 @@ TEST(NonOwningGroup, Invalid) {
|
||||
ASSERT_EQ(group.find(entity), group.end());
|
||||
ASSERT_EQ(group.front(), entt::entity{entt::null});
|
||||
ASSERT_EQ(group.back(), entt::entity{entt::null});
|
||||
|
||||
group.each([](const auto, const auto &) { FAIL(); });
|
||||
group.each([](const auto &) { FAIL(); });
|
||||
|
||||
for([[maybe_unused]] auto all: group.each()) { FAIL(); }
|
||||
for(auto first = group.each().rbegin(), last = group.each().rend(); first != last; ++first) { FAIL(); }
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(group.sort([](const auto, const auto) { FAIL(), true; }));
|
||||
ASSERT_NO_FATAL_FAILURE(group.sort<const empty_type>());
|
||||
}
|
||||
|
||||
TEST(NonOwningGroup, ElementAccess) {
|
||||
@@ -168,6 +159,7 @@ TEST(NonOwningGroup, Empty) {
|
||||
TEST(NonOwningGroup, Each) {
|
||||
entt::registry registry;
|
||||
auto group = registry.group(entt::get<int, char>);
|
||||
auto iterable = group.each();
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.emplace<int>(e0, 0);
|
||||
@@ -178,9 +170,10 @@ TEST(NonOwningGroup, Each) {
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
auto cgroup = std::as_const(registry).group_if_exists(entt::get<const int, const char>);
|
||||
auto citerable = cgroup.each();
|
||||
std::size_t cnt = 0;
|
||||
|
||||
for(auto first = cgroup.each().rbegin(), last = cgroup.each().rend(); first != last; ++first) {
|
||||
for(auto first = citerable.rbegin(), last = citerable.rend(); first != last; ++first) {
|
||||
static_assert(std::is_same_v<decltype(*first), std::tuple<entt::entity, const int &, const char &>>);
|
||||
ASSERT_EQ(std::get<1>(*first), cnt++);
|
||||
}
|
||||
@@ -193,7 +186,8 @@ TEST(NonOwningGroup, Each) {
|
||||
cgroup.each([&cnt](const int &, const char &) { --cnt; });
|
||||
cgroup.each([&cnt](auto, const int &, const char &) { --cnt; });
|
||||
|
||||
for(auto [entt, iv, cv]: group.each()) {
|
||||
// do not use iterable, make sure an iterable group works when created from a temporary
|
||||
for(auto [entt, iv, cv]: registry.group(entt::get<int, char>).each()) {
|
||||
static_assert(std::is_same_v<decltype(entt), entt::entity>);
|
||||
static_assert(std::is_same_v<decltype(iv), int &>);
|
||||
static_assert(std::is_same_v<decltype(cv), char &>);
|
||||
@@ -202,11 +196,11 @@ TEST(NonOwningGroup, Each) {
|
||||
|
||||
ASSERT_EQ(cnt, std::size_t{0});
|
||||
|
||||
auto it = group.each().begin();
|
||||
auto rit = group.each().rbegin();
|
||||
auto it = iterable.begin();
|
||||
auto rit = iterable.rbegin();
|
||||
|
||||
ASSERT_EQ((it++, ++it), group.each().end());
|
||||
ASSERT_EQ((rit++, ++rit), group.each().rend());
|
||||
ASSERT_EQ((it++, ++it), iterable.end());
|
||||
ASSERT_EQ((rit++, ++rit), iterable.rend());
|
||||
}
|
||||
|
||||
TEST(NonOwningGroup, Sort) {
|
||||
@@ -566,8 +560,9 @@ TEST(NonOwningGroup, EmptyTypes) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
}
|
||||
|
||||
registry.group(entt::get<int, char, double>).each([](const auto, int, char, double) { FAIL(); });
|
||||
ASSERT_EQ(registry.group(entt::get<int, char, double>).each().begin(), registry.group(entt::get<int, char, double>).each().end());
|
||||
auto iterable = registry.group(entt::get<int, char, double>).each();
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
}
|
||||
|
||||
TEST(NonOwningGroup, FrontBack) {
|
||||
@@ -622,6 +617,20 @@ TEST(NonOwningGroup, ExtendedGet) {
|
||||
ASSERT_EQ(std::get<1>(tup), 'c');
|
||||
}
|
||||
|
||||
TEST(NonOwningGroup, IterableGroupAlgorithmCompatibility) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
const auto group = registry.group(entt::get<int, char>);
|
||||
const auto iterable = group.each();
|
||||
const auto it = std::find_if(iterable.begin(), iterable.end(), [entity](auto args) { return std::get<0>(args) == entity; });
|
||||
|
||||
ASSERT_EQ(std::get<0>(*it), entity);
|
||||
}
|
||||
|
||||
TEST(OwningGroup, Functionalities) {
|
||||
entt::registry registry;
|
||||
auto group = registry.group<int>(entt::get<char>);
|
||||
@@ -707,12 +716,6 @@ TEST(OwningGroup, Invalid) {
|
||||
ASSERT_EQ(group.find(entity), group.end());
|
||||
ASSERT_EQ(group.front(), entt::entity{entt::null});
|
||||
ASSERT_EQ(group.back(), entt::entity{entt::null});
|
||||
|
||||
group.each([](const auto, const auto &) { FAIL(); });
|
||||
group.each([](const auto &) { FAIL(); });
|
||||
|
||||
for([[maybe_unused]] auto all: group.each()) { FAIL(); }
|
||||
for(auto first = group.each().rbegin(), last = group.each().rend(); first != last; ++first) { FAIL(); }
|
||||
}
|
||||
|
||||
TEST(OwningGroup, ElementAccess) {
|
||||
@@ -771,6 +774,7 @@ TEST(OwningGroup, Empty) {
|
||||
TEST(OwningGroup, Each) {
|
||||
entt::registry registry;
|
||||
auto group = registry.group<int>(entt::get<char>);
|
||||
auto iterable = group.each();
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.emplace<int>(e0, 0);
|
||||
@@ -781,9 +785,10 @@ TEST(OwningGroup, Each) {
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
auto cgroup = std::as_const(registry).group_if_exists<const int>(entt::get<const char>);
|
||||
auto citerable = cgroup.each();
|
||||
std::size_t cnt = 0;
|
||||
|
||||
for(auto first = cgroup.each().rbegin(), last = cgroup.each().rend(); first != last; ++first) {
|
||||
for(auto first = citerable.rbegin(), last = citerable.rend(); first != last; ++first) {
|
||||
static_assert(std::is_same_v<decltype(*first), std::tuple<entt::entity, const int &, const char &>>);
|
||||
ASSERT_EQ(std::get<1>(*first), cnt++);
|
||||
}
|
||||
@@ -796,7 +801,8 @@ TEST(OwningGroup, Each) {
|
||||
cgroup.each([&cnt](const int &, const char &) { --cnt; });
|
||||
cgroup.each([&cnt](auto, const int &, const char &) { --cnt; });
|
||||
|
||||
for(auto [entt, iv, cv]: group.each()) {
|
||||
// do not use iterable, make sure an iterable group works when created from a temporary
|
||||
for(auto [entt, iv, cv]: registry.group<int>(entt::get<char>).each()) {
|
||||
static_assert(std::is_same_v<decltype(entt), entt::entity>);
|
||||
static_assert(std::is_same_v<decltype(iv), int &>);
|
||||
static_assert(std::is_same_v<decltype(cv), char &>);
|
||||
@@ -805,11 +811,11 @@ TEST(OwningGroup, Each) {
|
||||
|
||||
ASSERT_EQ(cnt, std::size_t{0});
|
||||
|
||||
auto it = group.each().begin();
|
||||
auto rit = group.each().rbegin();
|
||||
auto it = iterable.begin();
|
||||
auto rit = iterable.rbegin();
|
||||
|
||||
ASSERT_EQ((it++, ++it), group.each().end());
|
||||
ASSERT_EQ((rit++, ++rit), group.each().rend());
|
||||
ASSERT_EQ((it++, ++it), iterable.end());
|
||||
ASSERT_EQ((rit++, ++rit), iterable.rend());
|
||||
}
|
||||
|
||||
TEST(OwningGroup, SortOrdered) {
|
||||
@@ -1259,8 +1265,9 @@ TEST(OwningGroup, EmptyTypes) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
}
|
||||
|
||||
registry.group<double>(entt::get<int, char>).each([](const auto, double, int, char) { FAIL(); });
|
||||
ASSERT_EQ(registry.group<double>(entt::get<int, char>).each().begin(), registry.group<double>(entt::get<int, char>).each().end());
|
||||
auto iterable = registry.group<double>(entt::get<int, char>).each();
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
}
|
||||
|
||||
TEST(OwningGroup, FrontBack) {
|
||||
@@ -1362,3 +1369,17 @@ TEST(OwningGroup, ExtendedGet) {
|
||||
ASSERT_EQ(std::get<0>(tup), 42);
|
||||
ASSERT_EQ(std::get<1>(tup), 'c');
|
||||
}
|
||||
|
||||
TEST(OwningGroup, IterableGroupAlgorithmCompatibility) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
const auto group = registry.group<int>(entt::get<char>);
|
||||
const auto iterable = group.each();
|
||||
const auto it = std::find_if(iterable.begin(), iterable.end(), [entity](auto args) { return std::get<0>(args) == entity; });
|
||||
|
||||
ASSERT_EQ(std::get<0>(*it), entity);
|
||||
}
|
||||
|
||||
@@ -140,8 +140,6 @@ TEST(Organizer, EmplaceFreeFunctionWithPayload) {
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
// TODO
|
||||
|
||||
organizer.emplace<&clazz::ro_int_char_double>(instance, "t1");
|
||||
organizer.emplace<&clazz::ro_int_with_payload>(instance, "t2");
|
||||
organizer.emplace<&clazz::ro_char_with_payload, const clazz>(instance, "t3");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
@@ -176,10 +177,14 @@ TEST(SingleComponentView, Each) {
|
||||
registry.emplace<int>(registry.create(), 1);
|
||||
|
||||
auto view = registry.view<int>();
|
||||
auto iterable = view.each();
|
||||
|
||||
auto cview = std::as_const(registry).view<const int>();
|
||||
auto citerable = cview.each();
|
||||
|
||||
std::size_t cnt = 0;
|
||||
|
||||
for(auto first = cview.each().rbegin(), last = cview.each().rend(); first != last; ++first) {
|
||||
for(auto first = citerable.rbegin(), last = citerable.rend(); first != last; ++first) {
|
||||
static_assert(std::is_same_v<decltype(*first), std::tuple<entt::entity, const int &>>);
|
||||
ASSERT_EQ(std::get<1>(*first), cnt++);
|
||||
}
|
||||
@@ -192,7 +197,8 @@ TEST(SingleComponentView, Each) {
|
||||
cview.each([&cnt](const int &) { --cnt; });
|
||||
cview.each([&cnt](auto, const int &) { --cnt; });
|
||||
|
||||
for(auto [entt, iv]: view.each()) {
|
||||
// do not use iterable, make sure an iterable view works when created from a temporary
|
||||
for(auto [entt, iv]: registry.view<int>().each()) {
|
||||
static_assert(std::is_same_v<decltype(entt), entt::entity>);
|
||||
static_assert(std::is_same_v<decltype(iv), int &>);
|
||||
ASSERT_EQ(iv, --cnt);
|
||||
@@ -200,11 +206,11 @@ TEST(SingleComponentView, Each) {
|
||||
|
||||
ASSERT_EQ(cnt, std::size_t{0});
|
||||
|
||||
auto it = view.each().begin();
|
||||
auto rit = view.each().rbegin();
|
||||
auto it = iterable.begin();
|
||||
auto rit = iterable.rbegin();
|
||||
|
||||
ASSERT_EQ((it++, ++it), view.each().end());
|
||||
ASSERT_EQ((rit++, ++rit), view.each().rend());
|
||||
ASSERT_EQ((it++, ++it), iterable.end());
|
||||
ASSERT_EQ((rit++, ++rit), iterable.rend());
|
||||
}
|
||||
|
||||
TEST(SingleComponentView, ConstNonConstAndAllInBetween) {
|
||||
@@ -383,6 +389,19 @@ TEST(SingleComponentView, DeductionGuide) {
|
||||
static_assert(std::is_same_v<decltype(entt::basic_view{std::as_const(storage)}), entt::basic_view<entt::entity, entt::exclude_t<>, const int>>);
|
||||
}
|
||||
|
||||
TEST(SingleComponentView, IterableViewAlgorithmCompatibility) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
const auto view = registry.view<int>();
|
||||
const auto iterable = view.each();
|
||||
const auto it = std::find_if(iterable.begin(), iterable.end(), [entity](auto args) { return std::get<0>(args) == entity; });
|
||||
|
||||
ASSERT_EQ(std::get<0>(*it), entity);
|
||||
}
|
||||
|
||||
TEST(MultiComponentView, Functionalities) {
|
||||
entt::registry registry;
|
||||
auto view = registry.view<int, char>();
|
||||
@@ -583,10 +602,14 @@ TEST(MultiComponentView, Each) {
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
auto view = registry.view<int, char>();
|
||||
auto iterable = view.each();
|
||||
|
||||
auto cview = std::as_const(registry).view<const int, const char>();
|
||||
auto citerable = cview.each();
|
||||
|
||||
std::size_t cnt = 0;
|
||||
|
||||
for(auto first = cview.each().rbegin(), last = cview.each().rend(); first != last; ++first) {
|
||||
for(auto first = citerable.rbegin(), last = citerable.rend(); first != last; ++first) {
|
||||
static_assert(std::is_same_v<decltype(*first), std::tuple<entt::entity, const int &, const char &>>);
|
||||
ASSERT_EQ(std::get<1>(*first), cnt++);
|
||||
}
|
||||
@@ -599,7 +622,8 @@ TEST(MultiComponentView, Each) {
|
||||
cview.each([&cnt](const int &, const char &) { --cnt; });
|
||||
cview.each([&cnt](auto, const int &, const char &) { --cnt; });
|
||||
|
||||
for(auto [entt, iv, cv]: view.each()) {
|
||||
// do not use iterable, make sure an iterable view works when created from a temporary
|
||||
for(auto [entt, iv, cv]: registry.view<int, char>().each()) {
|
||||
static_assert(std::is_same_v<decltype(entt), entt::entity>);
|
||||
static_assert(std::is_same_v<decltype(iv), int &>);
|
||||
static_assert(std::is_same_v<decltype(cv), char &>);
|
||||
@@ -608,11 +632,11 @@ TEST(MultiComponentView, Each) {
|
||||
|
||||
ASSERT_EQ(cnt, std::size_t{0});
|
||||
|
||||
auto it = view.each().begin();
|
||||
auto rit = view.each().rbegin();
|
||||
auto it = iterable.begin();
|
||||
auto rit = iterable.rbegin();
|
||||
|
||||
ASSERT_EQ((it++, ++it), view.each().end());
|
||||
ASSERT_EQ((rit++, ++rit), view.each().rend());
|
||||
ASSERT_EQ((it++, ++it), iterable.end());
|
||||
ASSERT_EQ((rit++, ++rit), iterable.rend());
|
||||
}
|
||||
|
||||
TEST(MultiComponentView, EachWithSuggestedType) {
|
||||
@@ -925,6 +949,20 @@ TEST(MultiComponentView, DeductionGuide) {
|
||||
static_assert(std::is_same_v<decltype(entt::basic_view{std::as_const(istorage), std::as_const(dstorage)}), entt::basic_view<entt::entity, entt::exclude_t<>, const int, const double>>);
|
||||
}
|
||||
|
||||
TEST(MultiComponentView, IterableViewAlgorithmCompatibility) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
const auto view = registry.view<int, char>();
|
||||
const auto iterable = view.each();
|
||||
const auto it = std::find_if(iterable.begin(), iterable.end(), [entity](auto args) { return std::get<0>(args) == entity; });
|
||||
|
||||
ASSERT_EQ(std::get<0>(*it), entity);
|
||||
}
|
||||
|
||||
TEST(View, Pipe) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <algorithm>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
@@ -15,28 +16,32 @@ struct clazz_t {
|
||||
};
|
||||
|
||||
struct empty_t {
|
||||
virtual ~empty_t() = default;
|
||||
static void destroy(empty_t &) {
|
||||
++counter;
|
||||
virtual ~empty_t() {
|
||||
++destructor_counter;
|
||||
}
|
||||
|
||||
inline static int counter = 0;
|
||||
static void destroy(empty_t &) {
|
||||
++destroy_counter;
|
||||
}
|
||||
|
||||
inline static int destroy_counter = 0;
|
||||
inline static int destructor_counter = 0;
|
||||
};
|
||||
|
||||
struct fat_t: empty_t {
|
||||
fat_t(): foo{}, bar{}, gnam{} {}
|
||||
fat_t()
|
||||
: value{.0, .0, .0, .0}
|
||||
{}
|
||||
|
||||
fat_t(int *value)
|
||||
: foo{value}, bar{value}, gnam{}
|
||||
fat_t(double v1, double v2, double v3, double v4)
|
||||
: value{v1, v2, v3, v4}
|
||||
{}
|
||||
|
||||
bool operator==(const fat_t &other) const {
|
||||
return foo == other.foo && bar == other.bar;
|
||||
return std::equal(std::begin(value), std::end(value), std::begin(other.value), std::end(other.value));
|
||||
}
|
||||
|
||||
int *foo;
|
||||
int *bar;
|
||||
double gnam[4];
|
||||
double value[4];
|
||||
};
|
||||
|
||||
struct not_comparable_t {
|
||||
@@ -74,7 +79,8 @@ struct MetaAny: ::testing::Test {
|
||||
.func<&clazz_t::member>("member"_hs)
|
||||
.func<&clazz_t::func>("func"_hs);
|
||||
|
||||
empty_t::counter = 0;
|
||||
empty_t::destroy_counter = 0;
|
||||
empty_t::destructor_counter = 0;
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
@@ -96,8 +102,7 @@ TEST_F(MetaAny, SBO) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBO) {
|
||||
int value = 42;
|
||||
fat_t instance{&value};
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{instance};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
@@ -141,38 +146,72 @@ TEST_F(MetaAny, SBOInPlaceTypeConstruction) {
|
||||
|
||||
TEST_F(MetaAny, SBOAsRefConstruction) {
|
||||
int value = 3;
|
||||
int other = 42;
|
||||
int compare = 42;
|
||||
entt::meta_any any{std::ref(value)};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_EQ(any.cast<int &>(), 3);
|
||||
ASSERT_EQ(any.cast<const int &>(), 3);
|
||||
ASSERT_EQ(any.cast<int>(), 3);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any.data(), &value);
|
||||
ASSERT_EQ(std::as_const(any).data(), &value);
|
||||
|
||||
ASSERT_EQ(any, (entt::meta_any{std::ref(value)}));
|
||||
ASSERT_NE(any, (entt::meta_any{std::ref(other)}));
|
||||
ASSERT_NE(any, (entt::meta_any{std::ref(compare)}));
|
||||
|
||||
ASSERT_NE(any, entt::meta_any{42});
|
||||
ASSERT_EQ(entt::meta_any{3}, any);
|
||||
|
||||
any = std::ref(value);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(std::as_const(any).data(), &value);
|
||||
|
||||
auto other = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 3);
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, SBOAsConstRefConstruction) {
|
||||
int value = 3;
|
||||
int other = 42;
|
||||
int compare = 42;
|
||||
entt::meta_any any{std::cref(value)};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_DEATH(any.cast<int &>() = 3, "");
|
||||
ASSERT_EQ(any.cast<const int &>(), 3);
|
||||
ASSERT_EQ(any.cast<int>(), 3);
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(std::as_const(any).data(), &value);
|
||||
|
||||
ASSERT_EQ(any, (entt::meta_any{std::cref(value)}));
|
||||
ASSERT_NE(any, (entt::meta_any{std::cref(other)}));
|
||||
ASSERT_NE(any, (entt::meta_any{std::cref(compare)}));
|
||||
|
||||
ASSERT_NE(any, entt::meta_any{42});
|
||||
ASSERT_EQ(entt::meta_any{3}, any);
|
||||
|
||||
any = std::cref(value);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(std::as_const(any).data(), &value);
|
||||
|
||||
auto other = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 3);
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, SBOCopyConstruction) {
|
||||
@@ -238,8 +277,7 @@ TEST_F(MetaAny, SBODirectAssignment) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOInPlaceTypeConstruction) {
|
||||
int value = 42;
|
||||
fat_t instance{&value};
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{std::in_place_type<fat_t>, instance};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
@@ -252,42 +290,73 @@ TEST_F(MetaAny, NoSBOInPlaceTypeConstruction) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOAsRefConstruction) {
|
||||
int value = 3;
|
||||
fat_t instance{&value};
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{std::ref(instance)};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<fat_t>());
|
||||
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_EQ(any.cast<fat_t &>(), instance);
|
||||
ASSERT_EQ(any.cast<const fat_t &>(), instance);
|
||||
ASSERT_EQ(any.cast<fat_t>(), instance);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any.data(), &instance);
|
||||
ASSERT_EQ(std::as_const(any).data(), &instance);
|
||||
|
||||
ASSERT_EQ(any, (entt::meta_any{std::ref(instance)}));
|
||||
|
||||
ASSERT_EQ(any, entt::meta_any{instance});
|
||||
ASSERT_NE(entt::meta_any{fat_t{}}, any);
|
||||
|
||||
any = std::ref(instance);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<fat_t>());
|
||||
ASSERT_EQ(std::as_const(any).data(), &instance);
|
||||
|
||||
auto other = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(any.type(), entt::resolve<fat_t>());
|
||||
ASSERT_EQ(any, entt::meta_any{instance});
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOAsConstRefConstruction) {
|
||||
int value = 3;
|
||||
fat_t instance{&value};
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{std::cref(instance)};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<fat_t>());
|
||||
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_DEATH(any.cast<fat_t &>() = {}, "");
|
||||
ASSERT_EQ(any.cast<const fat_t &>(), instance);
|
||||
ASSERT_EQ(any.cast<fat_t>(), instance);
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(std::as_const(any).data(), &instance);
|
||||
|
||||
ASSERT_EQ(any, (entt::meta_any{std::cref(instance)}));
|
||||
|
||||
ASSERT_EQ(any, entt::meta_any{instance});
|
||||
ASSERT_NE(entt::meta_any{fat_t{}}, any);
|
||||
|
||||
any = std::cref(instance);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<fat_t>());
|
||||
ASSERT_EQ(std::as_const(any).data(), &instance);
|
||||
|
||||
auto other = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(any.type(), entt::resolve<fat_t>());
|
||||
ASSERT_EQ(any, entt::meta_any{instance});
|
||||
ASSERT_EQ(other.data(), any.data());
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOCopyConstruction) {
|
||||
int value = 42;
|
||||
fat_t instance{&value};
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{instance};
|
||||
entt::meta_any other{any};
|
||||
|
||||
@@ -300,8 +369,7 @@ TEST_F(MetaAny, NoSBOCopyConstruction) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOCopyAssignment) {
|
||||
int value = 42;
|
||||
fat_t instance{&value};
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{instance};
|
||||
entt::meta_any other{3};
|
||||
|
||||
@@ -316,8 +384,7 @@ TEST_F(MetaAny, NoSBOCopyAssignment) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOMoveConstruction) {
|
||||
int value = 42;
|
||||
fat_t instance{&value};
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{instance};
|
||||
entt::meta_any other{std::move(any)};
|
||||
|
||||
@@ -330,8 +397,7 @@ TEST_F(MetaAny, NoSBOMoveConstruction) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOMoveAssignment) {
|
||||
int value = 42;
|
||||
fat_t instance{&value};
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{instance};
|
||||
entt::meta_any other{3};
|
||||
|
||||
@@ -346,13 +412,13 @@ TEST_F(MetaAny, NoSBOMoveAssignment) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBODirectAssignment) {
|
||||
int value = 42;
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{};
|
||||
any = fat_t{&value};
|
||||
any = instance;
|
||||
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_EQ(any.cast<fat_t>(), fat_t{&value});
|
||||
ASSERT_EQ(any, entt::meta_any{fat_t{&value}});
|
||||
ASSERT_EQ(any.cast<fat_t>(), instance);
|
||||
ASSERT_EQ(any, (entt::meta_any{fat_t{.1, .2, .3, .4}}));
|
||||
ASSERT_NE(fat_t{}, any);
|
||||
}
|
||||
|
||||
@@ -422,8 +488,7 @@ TEST_F(MetaAny, SBOMoveInvalidate) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOMoveInvalidate) {
|
||||
int value = 42;
|
||||
fat_t instance{&value};
|
||||
fat_t instance{.1, .2, .3, .4};
|
||||
entt::meta_any any{instance};
|
||||
entt::meta_any other{std::move(any)};
|
||||
entt::meta_any valid = std::move(other);
|
||||
@@ -444,15 +509,29 @@ TEST_F(MetaAny, VoidMoveInvalidate) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, SBODestruction) {
|
||||
ASSERT_EQ(empty_t::counter, 0);
|
||||
{ entt::meta_any any{empty_t{}}; }
|
||||
ASSERT_EQ(empty_t::counter, 1);
|
||||
{
|
||||
entt::meta_any any{std::in_place_type<empty_t>};
|
||||
any.emplace<empty_t>();
|
||||
any = empty_t{};
|
||||
entt::meta_any other{std::move(any)};
|
||||
any = std::move(other);
|
||||
}
|
||||
|
||||
ASSERT_EQ(empty_t::destroy_counter, 3);
|
||||
ASSERT_EQ(empty_t::destructor_counter,6);
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBODestruction) {
|
||||
ASSERT_EQ(fat_t::counter, 0);
|
||||
{ entt::meta_any any{fat_t{}}; }
|
||||
ASSERT_EQ(fat_t::counter, 1);
|
||||
{
|
||||
entt::meta_any any{std::in_place_type<fat_t>, 1., 2., 3., 4.};
|
||||
any.emplace<fat_t>(1., 2., 3., 4.);
|
||||
any = fat_t{1., 2., 3., 4.};
|
||||
entt::meta_any other{std::move(any)};
|
||||
any = std::move(other);
|
||||
}
|
||||
|
||||
ASSERT_EQ(fat_t::destroy_counter, 3);
|
||||
ASSERT_EQ(empty_t::destructor_counter, 4);
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, VoidDestruction) {
|
||||
@@ -508,14 +587,13 @@ TEST_F(MetaAny, SBOSwap) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOSwap) {
|
||||
int i{}, j{};
|
||||
entt::meta_any lhs{fat_t{&i}};
|
||||
entt::meta_any rhs{fat_t{&j}};
|
||||
entt::meta_any lhs{fat_t{.1, .2, .3, .4}};
|
||||
entt::meta_any rhs{fat_t{.4, .3, .2, .1}};
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_EQ(lhs.cast<fat_t>().foo, &j);
|
||||
ASSERT_EQ(rhs.cast<fat_t>().bar, &i);
|
||||
ASSERT_EQ(lhs.cast<fat_t>(), (fat_t{.4, .3, .2, .1}));
|
||||
ASSERT_EQ(rhs.cast<fat_t>(), (fat_t{.1, .2, .3, .4}));
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, VoidSwap) {
|
||||
@@ -529,8 +607,7 @@ TEST_F(MetaAny, VoidSwap) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, SBOWithNoSBOSwap) {
|
||||
int value = 42;
|
||||
entt::meta_any lhs{fat_t{&value}};
|
||||
entt::meta_any lhs{fat_t{.1, .2, .3, .4}};
|
||||
entt::meta_any rhs{'c'};
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
@@ -538,8 +615,7 @@ TEST_F(MetaAny, SBOWithNoSBOSwap) {
|
||||
ASSERT_FALSE(lhs.try_cast<fat_t>());
|
||||
ASSERT_EQ(lhs.cast<char>(), 'c');
|
||||
ASSERT_FALSE(rhs.try_cast<char>());
|
||||
ASSERT_EQ(rhs.cast<fat_t>().foo, &value);
|
||||
ASSERT_EQ(rhs.cast<fat_t>().bar, &value);
|
||||
ASSERT_EQ(rhs.cast<fat_t>(), (fat_t{.1, .2, .3, .4}));
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, SBOWithEmptySwap) {
|
||||
@@ -568,31 +644,33 @@ TEST_F(MetaAny, SBOWithVoidSwap) {
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOWithEmptySwap) {
|
||||
int i{};
|
||||
entt::meta_any lhs{fat_t{&i}};
|
||||
entt::meta_any lhs{fat_t{.1, .2, .3, .4}};
|
||||
entt::meta_any rhs{};
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_EQ(rhs.cast<fat_t>().bar, &i);
|
||||
ASSERT_FALSE(lhs);
|
||||
ASSERT_EQ(rhs.cast<fat_t>(), (fat_t{.1, .2, .3, .4}));
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_EQ(lhs.cast<fat_t>().bar, &i);
|
||||
ASSERT_FALSE(rhs);
|
||||
ASSERT_EQ(lhs.cast<fat_t>(), (fat_t{.1, .2, .3, .4}));
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, NoSBOWithVoidSwap) {
|
||||
int i{};
|
||||
entt::meta_any lhs{fat_t{&i}};
|
||||
entt::meta_any lhs{fat_t{.1, .2, .3, .4}};
|
||||
entt::meta_any rhs{std::in_place_type<void>};
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_EQ(rhs.cast<fat_t>().bar, &i);
|
||||
ASSERT_EQ(lhs.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(rhs.cast<fat_t>(), (fat_t{.1, .2, .3, .4}));
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_EQ(lhs.cast<fat_t>().bar, &i);
|
||||
ASSERT_EQ(rhs.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(lhs.cast<fat_t>(), (fat_t{.1, .2, .3, .4}));
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, AsRef) {
|
||||
@@ -733,11 +811,11 @@ TEST_F(MetaAny, Cast) {
|
||||
ASSERT_EQ(any.cast<fat_t &>(), fat_t{});
|
||||
ASSERT_EQ(any.cast<fat_t>(), fat_t{});
|
||||
|
||||
ASSERT_EQ(any.cast<fat_t>().gnam[0u], 0.);
|
||||
ASSERT_EQ(any.cast<fat_t>().value[0u], 0.);
|
||||
|
||||
any.cast<fat_t &>().gnam[0u] = 3.;
|
||||
any.cast<fat_t &>().value[0u] = 3.;
|
||||
|
||||
ASSERT_EQ(any.cast<fat_t>().gnam[0u], 3.);
|
||||
ASSERT_EQ(any.cast<fat_t>().value[0u], 3.);
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, Convert) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <string.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
@@ -18,7 +19,8 @@ struct MetaProp: ::testing::Test {
|
||||
|
||||
entt::meta<base_2_t>()
|
||||
.type("base_2"_hs)
|
||||
.prop("bool"_hs, false);
|
||||
.prop("bool"_hs, false)
|
||||
.prop("char[]"_hs, "char[]");
|
||||
|
||||
entt::meta<derived_t>()
|
||||
.type("derived"_hs)
|
||||
@@ -57,6 +59,17 @@ TEST_F(MetaProp, FromBase) {
|
||||
ASSERT_EQ(prop_int.value().cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaProp, DeducedArrayType) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto prop = entt::resolve<base_2_t>().prop("char[]"_hs);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_EQ(prop.key(), "char[]"_hs);
|
||||
ASSERT_EQ(prop.value().type(), entt::resolve<const char *>());
|
||||
ASSERT_EQ(strcmp(prop.value().cast<const char *>(), "char[]"), 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaProp, ReRegistration) {
|
||||
using namespace entt::literals;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user