]> code.bitgloo.com Git - clyne/entityx.git/commitdiff
Use std::bitset, allowing for an arbitrary number of components.
authorAlec Thomas <alec@swapoff.org>
Tue, 12 Mar 2013 04:05:29 +0000 (00:05 -0400)
committerAlec Thomas <alec@swapoff.org>
Tue, 12 Mar 2013 04:05:29 +0000 (00:05 -0400)
README.md
entityx/Benchmarks_test.cc
entityx/Entity.cc
entityx/Entity.h

index a658fb79075db6a7c04216fa731d6d1fe91b6dc5..37786d3781f532295bced80a6b0d8e9a22f5135f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -104,7 +104,7 @@ if (position) {
 #### Implementation notes
 
 - Components must provide a no-argument constructor.
-- The current implementation can handle up to 64 components in total. This can be extended with little effort.
+- The default implementation can handle up to 64 components in total. This can be extended by changing the `EntityManager::MAX_COMPONENTS` constant.
 
 ### Systems (implementing behavior)
 
index 625af29152ad38353e4c969eba8924f802a174ba..bee7d15f70db084c7405d0eaa175f933a0b6f677 100644 (file)
@@ -1,3 +1,4 @@
+#include <iostream>
 #include <vector>
 #include <gtest/gtest.h>
 #include <boost/timer/timer.hpp>
@@ -19,6 +20,8 @@ TEST_F(BenchmarksTest, TestCreateEntities) {
   boost::timer::auto_cpu_timer t;
 
   uint64_t count = 10000000L;
+  cout << "creating " << count << " entities" << endl;
+
   for (uint64_t i = 0; i < count; i++) {
     em.create();
   }
@@ -33,6 +36,7 @@ TEST_F(BenchmarksTest, TestDestroyEntities) {
   }
 
   boost::timer::auto_cpu_timer t;
+  cout << "destroying " << count << " entities" << endl;
 
   for (auto e : entities) {
     e.destroy();
@@ -48,8 +52,11 @@ TEST_F(BenchmarksTest, TestCreateEntitiesWithListener) {
   Listener listen;
   ev.subscribe<EntityCreatedEvent>(listen);
 
-  boost::timer::auto_cpu_timer t;
   uint64_t count = 10000000L;
+
+  boost::timer::auto_cpu_timer t;
+  cout << "creating " << count << " entities while notifying a single EntityCreatedEvent listener" << endl;
+
   vector<Entity> entities;
   for (uint64_t i = 0; i < count; i++) {
     entities.push_back(em.create());
@@ -67,9 +74,32 @@ TEST_F(BenchmarksTest, TestDestroyEntitiesWithListener) {
   }
 
   boost::timer::auto_cpu_timer t;
+  cout << "destroying " << count << " entities" << endl;
 
   for (auto e : entities) {
     e.destroy();
   }
 }
 
+struct Position : public Component<Position> {
+};
+
+TEST_F(BenchmarksTest, TestEntityIteration) {
+  uint64_t count = 10000000L;
+  vector<Entity> entities;
+  for (uint64_t i = 0; i < count; i++) {
+    auto e = em.create();
+    e.assign<Position>();
+    entities.push_back(e);
+  }
+
+  boost::timer::auto_cpu_timer t;
+  cout << "iterating over " << count << " entities with a component 10 times" << endl;
+
+  for (int i = 0; i < 10; ++i) {
+    for (auto e : em.entities_with_components<Position>()) {
+      boost::shared_ptr<Position> position = e.component<Position>();
+    }
+  }
+}
+
index 039cc4a258ec35876156311bd1bf8b5a3356fd94..51a80ba3a28f9eb5491cafd04d88bc0358fcae02 100644 (file)
@@ -13,8 +13,6 @@
 
 namespace entityx {
 
-const Entity::Id Entity::INVALID = Entity::Id(-1);
-
 BaseComponent::Family BaseComponent::family_counter_ = 0;
 
 void Entity::invalidate() {
index 644456f364216bb9aa9b2357d096489504dc7750..76e646a1253c3f40a9b2c01e029d1617cc2a4314 100644 (file)
@@ -49,7 +49,7 @@ class Entity {
   /**
    * Id of an invalid Entity.
    */
-  static const Id INVALID;
+  static const Id INVALID = Id(-1);
 
   Entity() {}
 
@@ -212,6 +212,8 @@ struct ComponentAddedEvent : public Event<ComponentAddedEvent<T>> {
  */
 class EntityManager : boost::noncopyable {
  public:
+  static const int MAX_COMPONENTS = 64;
+
   EntityManager(EventManager &event_manager) : event_manager_(event_manager) {}
 
   class View {
@@ -221,15 +223,15 @@ class EntityManager : boost::noncopyable {
     /// A predicate that excludes entities that don't match the given component mask.
     class ComponentMaskPredicate {
      public:
-      ComponentMaskPredicate(const std::vector<uint64_t> &entity_bits, uint64_t mask) : entity_bits_(entity_bits), mask_(mask) {}
+      ComponentMaskPredicate(const std::vector<std::bitset<MAX_COMPONENTS>> &entity_bits, std::bitset<MAX_COMPONENTS> mask) : entity_bits_(entity_bits), mask_(mask) {}
 
       bool operator () (EntityManager &, Entity::Id entity) {
         return (entity_bits_.at(entity) & mask_) == mask_;
       }
 
      private:
-      const std::vector<uint64_t> &entity_bits_;
-      uint64_t mask_;
+      const std::vector<std::bitset<MAX_COMPONENTS>> &entity_bits_;
+      std::bitset<MAX_COMPONENTS> mask_;
     };
 
     /// An iterator over a view of the entities in an EntityManager.
@@ -422,7 +424,7 @@ class EntityManager : boost::noncopyable {
    */
   template <typename C, typename ... Components>
   View entities_with_components() {
-    uint64_t mask = component_mask<C, Components ...>();
+    auto mask = component_mask<C, Components ...>();
     return View(this, View::ComponentMaskPredicate(entity_component_mask_, mask));
   }
 
@@ -431,7 +433,7 @@ class EntityManager : boost::noncopyable {
    */
   template <typename C, typename ... Components>
   View entities_with_components(boost::shared_ptr<C> &c, Components && ... args) {
-    uint64_t mask = component_mask(c, args ...);
+    auto mask = component_mask(c, args ...);
     return
         View(this, View::ComponentMaskPredicate(entity_component_mask_, mask))
         .unpack_to(c, args ...);
@@ -472,22 +474,24 @@ class EntityManager : boost::noncopyable {
 
  private:
   template <typename C>
-  uint64_t component_mask() {
-    return uint64_t(1) << C::family();
+  std::bitset<MAX_COMPONENTS> component_mask() {
+    std::bitset<MAX_COMPONENTS> mask;
+    mask.set(C::family());
+    return mask;
   }
 
   template <typename C1, typename C2, typename ... Components>
-  uint64_t component_mask() {
+  std::bitset<MAX_COMPONENTS> component_mask() {
     return component_mask<C1>() | component_mask<C2, Components ...>();
   }
 
   template <typename C>
-  uint64_t component_mask(const boost::shared_ptr<C> &c) {
-    return uint64_t(1) << C::family();
+  std::bitset<MAX_COMPONENTS> component_mask(const boost::shared_ptr<C> &c) {
+    return component_mask<C>();
   }
 
   template <typename C1, typename C2, typename ... Components>
-  uint64_t component_mask(const boost::shared_ptr<C1> &c1, const boost::shared_ptr<C2> &c2, Components && ... args) {
+  std::bitset<MAX_COMPONENTS> component_mask(const boost::shared_ptr<C1> &c1, const boost::shared_ptr<C2> &c2, Components && ... args) {
     return component_mask<C1>(c1) | component_mask<C2, Components ...>(c2, args...);
   }
 
@@ -515,7 +519,7 @@ class EntityManager : boost::noncopyable {
   // A nested array of: components = entity_components_[family][entity]
   std::vector<std::vector<boost::shared_ptr<BaseComponent>>> entity_components_;
   // Bitmask of components associated with each entity. Index into the vector is the Entity::Id.
-  std::vector<uint64_t> entity_component_mask_;
+  std::vector<std::bitset<MAX_COMPONENTS>> entity_component_mask_;
   // List of available Entity::Id IDs.
   std::list<Entity::Id> free_list_;
 };