From dad637cdec9c24b34ad430aee0e55553d6ea238d Mon Sep 17 00:00:00 2001
From: Alec Thomas <alec@swapoff.org>
Date: Tue, 17 Dec 2013 23:46:43 -0500
Subject: Fix unpack and entities_with_components with > 2 args.

---
 entityx/Entity.h       | 46 ++++++++++++++--------------------------------
 entityx/Entity_test.cc | 45 ++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 56 insertions(+), 35 deletions(-)

diff --git a/entityx/Entity.h b/entityx/Entity.h
index 6b37ed2..ba1822a 100644
--- a/entityx/Entity.h
+++ b/entityx/Entity.h
@@ -121,10 +121,8 @@ public:
   template <typename C>
   ptr<C> component();
 
-  template <typename A>
-  void unpack(ptr<A> &a);
-  template <typename A, typename B, typename ... Args>
-  void unpack(ptr<A> &a, ptr<B> &b, Args && ... args);
+  template <typename A, typename ... Args>
+  void unpack(ptr<A> &a, ptr<Args> & ... args);
 
   /**
    * Destroy and invalidate this Entity.
@@ -347,7 +345,7 @@ class EntityManager : entityx::help::NonCopyable, public enable_shared_from_this
     }
 
     template <typename A, typename B, typename ... Args>
-    View &unpack_to(ptr<A> &a, ptr<B> &b, Args && ... args) {
+    View &unpack_to(ptr<A> &a, ptr<B> &b, ptr<Args> & ... args) {
       unpack_to<A>(a);
       return unpack_to<B, Args ...>(b, args ...);
     }
@@ -515,27 +513,17 @@ class EntityManager : entityx::help::NonCopyable, public enable_shared_from_this
   }
 
   /**
-   * Find Entities that have all of the specified Components.
+   * Find Entities that have all of the specified Components and assign them
+   * to the given parameters.
    */
   template <typename C, typename ... Components>
-  View entities_with_components(ptr<C> &c, Components && ... args) {
+  View entities_with_components(ptr<C> &c, ptr<Components> & ... args) {
     auto mask = component_mask(c, args ...);
     return
         View(shared_from_this(), View::ComponentMaskPredicate(entity_component_mask_, mask))
         .unpack_to(c, args ...);
   }
 
-  /**
-   * Unpack components directly into pointers.
-   *
-   * Components missing from the entity will be set to nullptr.
-   *
-   * Useful for fast bulk iterations.
-   *
-   * ptr<Position> p;
-   * ptr<Direction> d;
-   * unpack<Position, Direction>(e, p, d);
-   */
   template <typename A>
   void unpack(Entity::Id id, ptr<A> &a) {
     a = component<A>(id);
@@ -552,10 +540,10 @@ class EntityManager : entityx::help::NonCopyable, public enable_shared_from_this
    * ptr<Direction> d;
    * unpack<Position, Direction>(e, p, d);
    */
-  template <typename A, typename B, typename ... Args>
-  void unpack(Entity::Id id, ptr<A> &a, ptr<B> &b, Args && ... args) {
-    unpack<A>(id, a);
-    unpack<B, Args ...>(id, b, args ...);
+  template <typename A, typename ... Args>
+  void unpack(Entity::Id id, ptr<A> &a, ptr<Args> & ... args) {
+    a = component<A>(id);
+    unpack<Args ...>(id, args ...);
   }
 
   /**
@@ -582,7 +570,7 @@ class EntityManager : entityx::help::NonCopyable, public enable_shared_from_this
   }
 
   template <typename C1, typename C2, typename ... Components>
-  ComponentMask component_mask(const ptr<C1> &c1, const ptr<C2> &c2, Components && ... args) {
+  ComponentMask component_mask(const ptr<C1> &c1, const ptr<C2> &c2, ptr<Components> & ... args) {
     return component_mask<C1>(c1) | component_mask<C2, Components ...>(c2, args...);
   }
 
@@ -649,16 +637,10 @@ ptr<C> Entity::component() {
   return manager_.lock()->component<C>(id_);
 }
 
-template <typename A>
-void Entity::unpack(ptr<A> &a) {
-  assert(valid());
-  manager_.lock()->unpack(id_, a);
-}
-
-template <typename A, typename B, typename ... Args>
-void Entity::unpack(ptr<A> &a, ptr<B> &b, Args && ... args) {
+template <typename A, typename ... Args>
+void Entity::unpack(ptr<A> &a, ptr<Args> & ... args) {
   assert(valid());
-  manager_.lock()->unpack(id_, a, b, args ...);
+  manager_.lock()->unpack(id_, a, args ...);
 }
 
 }  // namespace entityx
diff --git a/entityx/Entity_test.cc b/entityx/Entity_test.cc
index 685a736..925b282 100644
--- a/entityx/Entity_test.cc
+++ b/entityx/Entity_test.cc
@@ -21,6 +21,7 @@ using namespace entityx;
 
 using std::ostream;
 using std::vector;
+using std::string;
 
 template <typename T>
 int size(const T &t) {
@@ -61,6 +62,18 @@ ostream &operator << (ostream &out, const Direction &direction) {
   return out;
 }
 
+struct Tag : Component<Tag> {
+  explicit Tag(string tag) : tag(tag) {}
+
+  bool operator == (const Tag &other) const { return tag == other.tag; }
+
+  string tag;
+};
+
+ostream &operator << (ostream &out, const Tag &tag) {
+  out << "Tag(" << tag.tag << ")";
+  return out;
+}
 
 class EntityManagerTest : public ::testing::Test {
  protected:
@@ -204,10 +217,14 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
   position_directions.push_back(std::make_pair(
           f.assign<Position>(7.0f, 8.0f),
           f.assign<Direction>(9.0f, 10.0f)));
+  auto thetag = f.assign<Tag>("tag");
   g.assign<Position>(5.0f, 6.0f);
   int i = 0;
 
+
   ptr<Position> position;
+  ASSERT_EQ(3, size(em->entities_with_components(position)));
+
   ptr<Direction> direction;
   for (auto unused_entity : em->entities_with_components(position, direction)) {
     (void)unused_entity;
@@ -219,18 +236,40 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
     ++i;
   }
   ASSERT_EQ(2, i);
+  ptr<Tag> tag;
+  i = 0;
+  for (auto unused_entity : em->entities_with_components(position, direction, tag)) {
+    (void)unused_entity;
+    ASSERT_TRUE(static_cast<bool>(position));
+    ASSERT_TRUE(static_cast<bool>(direction));
+    ASSERT_TRUE(static_cast<bool>(tag));
+    auto pd = position_directions.at(1);
+    ASSERT_EQ(position, pd.first);
+    ASSERT_EQ(direction, pd.second);
+    ASSERT_EQ(tag, thetag);
+    i++;
+  }
+  ASSERT_EQ(1, i);
 }
 
 TEST_F(EntityManagerTest, TestUnpack) {
   Entity e = em->create();
-  auto p = e.assign<Position>();
-  auto d = e.assign<Direction>();
+  auto p = e.assign<Position>(1.0, 2.0);
+  auto d = e.assign<Direction>(3.0, 4.0);
+  auto t = e.assign<Tag>("tag");
 
   ptr<Position> up;
   ptr<Direction> ud;
-  e.unpack<Position, Direction>(up, ud);
+  ptr<Tag> ut;
+  e.unpack(up);
+  ASSERT_EQ(p, up);
+  e.unpack(up, ud);
+  ASSERT_EQ(p, up);
+  ASSERT_EQ(d, ud);
+  e.unpack(up, ud, ut);
   ASSERT_EQ(p, up);
   ASSERT_EQ(d, ud);
+  ASSERT_EQ(t, ut);
 }
 
 // gcc 4.7.2 does not allow this struct to be declared locally inside the TEST_F.
-- 
cgit v1.2.3