Browse Source

ENTT_DISABLE_ETO to disable empty type optimization (close #330)

Michele Caini 6 years ago
parent
commit
ad5651ffb2

+ 3 - 1
docs/md/entity.md

@@ -1683,7 +1683,9 @@ it cannot be caught by a non-const reference. Capture it by copy or by const
 reference instead.
 reference instead.
 
 
 More in general, none of the features offered by the library is affected, but
 More in general, none of the features offered by the library is affected, but
-for the ones that require to return actual instances.
+for the ones that require to return actual instances.<br/>
+This optimization can be disabled by defining the `ENTT_DISABLE_ETO` macro. In
+this case, the empty types will be treated like all other types, no matter what.
 
 
 # Multithreading
 # Multithreading
 
 

+ 9 - 0
src/entt/config/config.h

@@ -25,6 +25,15 @@
 #endif // ENTT_NO_ATOMIC
 #endif // ENTT_NO_ATOMIC
 
 
 
 
+#ifndef ENTT_DISABLE_ETO
+#include <type_traits>
+#define ENTT_ENABLE_ETO(Type) std::is_empty_v<Type>
+#else // ENTT_DISABLE_ETO
+// sfinae-friendly definition
+#define ENTT_ENABLE_ETO(Type) (false && std::is_empty_v<Type>)
+#endif // ENTT_DISABLE_ETO
+
+
 #ifndef ENTT_ID_TYPE
 #ifndef ENTT_ID_TYPE
 #include <cstdint>
 #include <cstdint>
 #define ENTT_ID_TYPE std::uint32_t
 #define ENTT_ID_TYPE std::uint32_t

+ 3 - 3
src/entt/entity/group.hpp

@@ -344,7 +344,7 @@ public:
      */
      */
     template<typename Func>
     template<typename Func>
     void less(Func func) const {
     void less(Func func) const {
-        using get_type_list = type_list_cat_t<std::conditional_t<std::is_empty_v<Get>, type_list<>, type_list<Get>>...>;
+        using get_type_list = type_list_cat_t<std::conditional_t<ENTT_ENABLE_ETO(Get), type_list<>, type_list<Get>>...>;
         traverse(std::move(func), get_type_list{});
         traverse(std::move(func), get_type_list{});
     }
     }
 
 
@@ -763,8 +763,8 @@ public:
      */
      */
     template<typename Func>
     template<typename Func>
     void less(Func func) const {
     void less(Func func) const {
-        using owned_type_list = type_list_cat_t<std::conditional_t<std::is_empty_v<Owned>, type_list<>, type_list<Owned>>...>;
-        using get_type_list = type_list_cat_t<std::conditional_t<std::is_empty_v<Get>, type_list<>, type_list<Get>>...>;
+        using owned_type_list = type_list_cat_t<std::conditional_t<ENTT_ENABLE_ETO(Owned), type_list<>, type_list<Owned>>...>;
+        using get_type_list = type_list_cat_t<std::conditional_t<ENTT_ENABLE_ETO(Get), type_list<>, type_list<Get>>...>;
         traverse(std::move(func), owned_type_list{}, get_type_list{});
         traverse(std::move(func), owned_type_list{}, get_type_list{});
     }
     }
 
 

+ 3 - 3
src/entt/entity/registry.hpp

@@ -70,7 +70,7 @@ class basic_registry {
 
 
         template<typename... Args>
         template<typename... Args>
         decltype(auto) assign(basic_registry &registry, const Entity entt, Args &&... args) {
         decltype(auto) assign(basic_registry &registry, const Entity entt, Args &&... args) {
-            if constexpr(std::is_empty_v<Component>) {
+            if constexpr(ENTT_ENABLE_ETO(Component)) {
                 storage<Entity, Component>::construct(entt);
                 storage<Entity, Component>::construct(entt);
                 construction.publish(entt, registry, Component{});
                 construction.publish(entt, registry, Component{});
                 return Component{std::forward<Args>(args)...};
                 return Component{std::forward<Args>(args)...};
@@ -101,7 +101,7 @@ class basic_registry {
 
 
         template<typename... Args>
         template<typename... Args>
         decltype(auto) replace(basic_registry &registry, const Entity entt, Args &&... args) {
         decltype(auto) replace(basic_registry &registry, const Entity entt, Args &&... args) {
-            if constexpr(std::is_empty_v<Component>) {
+            if constexpr(ENTT_ENABLE_ETO(Component)) {
                 ENTT_ASSERT((storage<Entity, Component>::has(entt)));
                 ENTT_ASSERT((storage<Entity, Component>::has(entt)));
                 update.publish(entt, registry, Component{});
                 update.publish(entt, registry, Component{});
                 return Component{std::forward<Args>(args)...};
                 return Component{std::forward<Args>(args)...};
@@ -113,7 +113,7 @@ class basic_registry {
         }
         }
 
 
     private:
     private:
-        using reference_type = std::conditional_t<std::is_empty_v<Component>, const Component &, Component &>;
+        using reference_type = std::conditional_t<ENTT_ENABLE_ETO(Component), const Component &, Component &>;
         sigh<void(const Entity, basic_registry &, reference_type)> construction{};
         sigh<void(const Entity, basic_registry &, reference_type)> construction{};
         sigh<void(const Entity, basic_registry &, reference_type)> update{};
         sigh<void(const Entity, basic_registry &, reference_type)> update{};
         sigh<void(const Entity, basic_registry &)> destruction{};
         sigh<void(const Entity, basic_registry &)> destruction{};

+ 1 - 3
src/entt/entity/storage.hpp

@@ -453,8 +453,6 @@ public:
         };
         };
 
 
         if constexpr(std::is_invocable_v<Compare, const object_type &, const object_type &>) {
         if constexpr(std::is_invocable_v<Compare, const object_type &, const object_type &>) {
-            static_assert(!std::is_empty_v<object_type>);
-
             underlying_type::arrange(from, to, std::move(apply), [this, compare = std::move(compare)](const auto lhs, const auto rhs) {
             underlying_type::arrange(from, to, std::move(apply), [this, compare = std::move(compare)](const auto lhs, const auto rhs) {
                 return compare(std::as_const(instances[underlying_type::index(lhs)]), std::as_const(instances[underlying_type::index(rhs)]));
                 return compare(std::as_const(instances[underlying_type::index(lhs)]), std::as_const(instances[underlying_type::index(rhs)]));
             }, std::move(algo), std::forward<Args>(args)...);
             }, std::move(algo), std::forward<Args>(args)...);
@@ -476,7 +474,7 @@ private:
 
 
 /*! @copydoc basic_storage */
 /*! @copydoc basic_storage */
 template<typename Entity, typename Type>
 template<typename Entity, typename Type>
-class basic_storage<Entity, Type, std::enable_if_t<std::is_empty_v<Type>>>: public sparse_set<Entity> {
+class basic_storage<Entity, Type, std::enable_if_t<ENTT_ENABLE_ETO(Type)>>: public sparse_set<Entity> {
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;
     using underlying_type = sparse_set<Entity>;
     using underlying_type = sparse_set<Entity>;
 
 

+ 2 - 2
src/entt/entity/view.hpp

@@ -503,7 +503,7 @@ public:
     template<typename Comp, typename Func>
     template<typename Comp, typename Func>
     void less(Func func) const {
     void less(Func func) const {
         using other_type = type_list_cat_t<std::conditional_t<std::is_same_v<Comp, Component>, type_list<>, type_list<Component>>...>;
         using other_type = type_list_cat_t<std::conditional_t<std::is_same_v<Comp, Component>, type_list<>, type_list<Component>>...>;
-        using non_empty_type = type_list_cat_t<std::conditional_t<std::is_empty_v<Component>, type_list<>, type_list<Component>>...>;
+        using non_empty_type = type_list_cat_t<std::conditional_t<ENTT_ENABLE_ETO(Component), type_list<>, type_list<Component>>...>;
         traverse<Comp>(std::move(func), other_type{}, non_empty_type{});
         traverse<Comp>(std::move(func), other_type{}, non_empty_type{});
     }
     }
 
 
@@ -767,7 +767,7 @@ public:
      */
      */
     template<typename Func>
     template<typename Func>
     void less(Func func) const {
     void less(Func func) const {
-        if constexpr(std::is_empty_v<Component>) {
+        if constexpr(ENTT_ENABLE_ETO(Component)) {
             if constexpr(std::is_invocable_v<Func>) {
             if constexpr(std::is_invocable_v<Func>) {
                 for(auto pos = pool->size(); pos; --pos) {
                 for(auto pos = pool->size(); pos; --pos) {
                     func();
                     func();

+ 3 - 3
test/snapshot/snapshot.cpp

@@ -21,17 +21,17 @@ struct relationship {
 
 
 template<typename Archive>
 template<typename Archive>
 void serialize(Archive &archive, position &position) {
 void serialize(Archive &archive, position &position) {
-  archive(position.x, position.y);
+    archive(position.x, position.y);
 }
 }
 
 
 template<typename Archive>
 template<typename Archive>
 void serialize(Archive &archive, timer &timer) {
 void serialize(Archive &archive, timer &timer) {
-  archive(timer.duration);
+    archive(timer.duration);
 }
 }
 
 
 template<typename Archive>
 template<typename Archive>
 void serialize(Archive &archive, relationship &relationship) {
 void serialize(Archive &archive, relationship &relationship) {
-  archive(relationship.parent);
+    archive(relationship.parent);
 }
 }
 
 
 TEST(Snapshot, Full) {
 TEST(Snapshot, Full) {