]> code.bitgloo.com Git - clyne/entityx.git/commitdiff
Use raw pointers for components, allocated from pools.
authorAlec Thomas <alec@swapoff.org>
Sun, 2 Mar 2014 11:49:41 +0000 (22:49 +1100)
committerAlec Thomas <alec@swapoff.org>
Sun, 2 Mar 2014 11:49:41 +0000 (22:49 +1100)
14 files changed:
CHANGES.md
CMakeLists.txt
entityx/3rdparty/simplesignal.h
entityx/Benchmarks_test.cc
entityx/Entity.cc
entityx/Entity.h
entityx/Entity_test.cc
entityx/Event.h
entityx/Event_test.cc
entityx/System_test.cc
entityx/help/Pool.cc [new file with mode: 0644]
entityx/help/Pool.h [new file with mode: 0644]
entityx/help/Pool_test.cc [new file with mode: 0644]
entityx/quick.h [new file with mode: 0644]

index 92583624577c34d1ae2000e00b9c40177bf78f28..f071241ed4b0c901299dfa409759fdcb0811138f 100644 (file)
@@ -1,5 +1,9 @@
 # Change Log
 
+## 2014-03-02 - Version 1.0.0alpha1 - Removed most uses of shared_ptr
+
+I've been slightly discontent with the use of `std::shared_ptr` in EntityX since soon after release, but didn't want to break the API immediately after releasing it. But I've decided that it's time.
+
 ## 2014-02-13 - Support for Visual C++
 
 [Jarrett Chisholm](https://github.com/jarrettchisholm) has added conditional compilation support for VC++ and fixed some issues that prevented compilation, so EntityX now fully supports Visual C++!
index 1b6efb65429bda7a3537a205a72bdbd04f2bf5bb..fc394404c89122e2e180321b83e2a8b83a97bfe4 100644 (file)
@@ -122,7 +122,7 @@ endif()
 # Things to install
 set(install_libs entityx)
 
-set(sources entityx/System.cc entityx/Event.cc entityx/Entity.cc entityx/help/Timer.cc)
+set(sources entityx/System.cc entityx/Event.cc entityx/Entity.cc entityx/help/Timer.cc entityx/help/Pool.cc)
 add_library(entityx STATIC ${sources})
 
 if (ENTITYX_BUILD_SHARED)
@@ -140,6 +140,7 @@ if (ENTITYX_BUILD_TESTING)
     add_subdirectory(gtest-1.6.0)
     include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
     enable_testing()
+    create_test(pool_test entityx/help/Pool_test.cc)
     create_test(entity_test entityx/Entity_test.cc)
     create_test(event_test entityx/Event_test.cc)
     create_test(system_test entityx/System_test.cc)
index 39bb2fb17813f22cf8a23e130e642ec8171d2564..c0eb4f0eb522ca3fec98ca8e4f37356b899d2cd7 100644 (file)
@@ -12,307 +12,310 @@ namespace Simple {
 namespace Lib {
 
 /// ProtoSignal is the template implementation for callback list.
-template<typename,typename> class ProtoSignal;   // undefined
+template <typename, typename>
+class ProtoSignal;  // undefined
 
-/// CollectorInvocation invokes signal handlers differently depending on return type.
-template<typename,typename> struct CollectorInvocation;
+/// CollectorInvocation invokes signal handlers differently depending on return
+/// type.
+template <typename, typename>
+struct CollectorInvocation;
 
-/// CollectorLast returns the result of the last signal handler from a signal emission.
-template<typename Result>
+/// CollectorLast returns the result of the last signal handler from a signal
+/// emission.
+template <typename Result>
 struct CollectorLast {
   typedef Result CollectorResult;
-  explicit        CollectorLast ()              : last_() {}
-  inline bool     operator()    (Result r)      { last_ = r; return true; }
-  CollectorResult result        ()              { return last_; }
-private:
+  explicit CollectorLast() : last_() {}
+  inline bool operator()(Result r) {
+    last_ = r;
+    return true;
+  }
+  CollectorResult result() { return last_; }
+
+ private:
   Result last_;
 };
 
 /// CollectorDefault implements the default signal handler collection behaviour.
-template<typename Result>
-struct CollectorDefault : CollectorLast<Result>
-{};
+template <typename Result>
+struct CollectorDefault : CollectorLast<Result> {};
 
 /// CollectorDefault specialisation for signals with void return type.
-template<>
+template <>
 struct CollectorDefault<void> {
   typedef void CollectorResult;
-  void                  result     ()           {}
-  inline bool           operator() (void)       { return true; }
+  void result() {}
+  inline bool operator()(void) { return true; }
 };
 
 /// CollectorInvocation specialisation for regular signals.
-template<class Collector, class R, class... Args>
-struct CollectorInvocation<Collector, R (Args...)> {
-  inline bool
-  invoke (Collector &collector, const std::function<R (Args...)> &cbf, Args... args)
-  {
-    return collector (cbf (args...));
+template <class Collector, class R, class... Args>
+struct CollectorInvocation<Collector, R(Args...)> {
+  inline bool invoke(Collector &collector, const std::function<R(Args...)> &cbf,
+                     Args... args) {
+    return collector(cbf(args...));
   }
 };
 
 /// CollectorInvocation specialisation for signals with void return type.
-template<class Collector, class... Args>
-struct CollectorInvocation<Collector, void (Args...)> {
-  inline bool
-  invoke (Collector &collector, const std::function<void (Args...)> &cbf, Args... args)
-  {
-    cbf (args...); return collector();
+template <class Collector, class... Args>
+struct CollectorInvocation<Collector, void(Args...)> {
+  inline bool invoke(Collector &collector,
+                     const std::function<void(Args...)> &cbf, Args... args) {
+    cbf(args...);
+    return collector();
   }
 };
 
 /// ProtoSignal template specialised for the callback signature and collector.
-template<class Collector, class R, class... Args>
-class ProtoSignal<R (Args...), Collector> : private CollectorInvocation<Collector, R (Args...)> {
-protected:
-  typedef std::function<R (Args...)> CbFunction;
+template <class Collector, class R, class... Args>
+class ProtoSignal<R(Args...), Collector> : private CollectorInvocation<
+                                               Collector, R(Args...)> {
+ protected:
+  typedef std::function<R(Args...)> CbFunction;
   typedef typename CbFunction::result_type Result;
   typedef typename Collector::CollectorResult CollectorResult;
-private:
-  /// SignalLink implements a doubly-linked ring with ref-counted nodes containing the signal handlers.
+
+ private:
+  /// SignalLink implements a doubly-linked ring with ref-counted nodes
+  /// containing the signal handlers.
   struct SignalLink {
     SignalLink *next, *prev;
-    CbFunction  function;
-    int         ref_count;
-    explicit    SignalLink (const CbFunction &cbf) : next (0), prev (0), function (cbf), ref_count (1) {}
-    /*dtor*/   ~SignalLink ()           { assert (ref_count == 0); }
-    void        incref     ()           { ref_count += 1; assert (ref_count > 0); }
-    void        decref     ()           { ref_count -= 1; if (!ref_count) delete this; else assert (ref_count > 0); }
-    void
-    unlink ()
-    {
+    CbFunction function;
+    int ref_count;
+    explicit SignalLink(const CbFunction &cbf)
+        : next(0), prev(0), function(cbf), ref_count(1) {}
+    /*dtor*/ ~SignalLink() { assert(ref_count == 0); }
+    void incref() {
+      ref_count += 1;
+      assert(ref_count > 0);
+    }
+    void decref() {
+      ref_count -= 1;
+      if (!ref_count)
+        delete this;
+      else
+        assert(ref_count > 0);
+    }
+    void unlink() {
       function = nullptr;
-      if (next)
-        next->prev = prev;
-      if (prev)
-        prev->next = next;
+      if (next) next->prev = prev;
+      if (prev) prev->next = next;
       decref();
       // leave intact ->next, ->prev for stale iterators
     }
-    size_t
-    add_before (const CbFunction &cb)
-    {
-      SignalLink *link = new SignalLink (cb);
-      link->prev = prev; // link to last
+    size_t add_before(const CbFunction &cb) {
+      SignalLink *link = new SignalLink(cb);
+      link->prev = prev;  // link to last
       link->next = this;
-      prev->next = link; // link from last
+      prev->next = link;  // link from last
       prev = link;
-      static_assert (sizeof (link) == sizeof (size_t), "sizeof size_t");
-      return size_t (link);
+      static_assert(sizeof(link) == sizeof(size_t), "sizeof size_t");
+      return size_t(link);
     }
-    bool
-    deactivate (const CbFunction &cbf)
-    {
-      if (cbf == function)
-        {
-          function = 0;      // deactivate static head
+    bool deactivate(const CbFunction &cbf) {
+      if (cbf == function) {
+        function = 0;  // deactivate static head
+        return true;
+      }
+      for (SignalLink *link = this->next ? this->next : this; link != this;
+           link = link->next)
+        if (cbf == link->function) {
+          link->unlink();  // deactivate and unlink sibling
           return true;
         }
-      for (SignalLink *link = this->next ? this->next : this; link != this; link = link->next)
-        if (cbf == link->function)
-          {
-            link->unlink();     // deactivate and unlink sibling
-            return true;
-          }
       return false;
     }
-    bool
-    remove_sibling (size_t id)
-    {
-      for (SignalLink *link = this->next ? this->next : this; link != this; link = link->next)
-        if (id == size_t (link))
-          {
-            link->unlink();     // deactivate and unlink sibling
-            return true;
-          }
+    bool remove_sibling(size_t id) {
+      for (SignalLink *link = this->next ? this->next : this; link != this;
+           link = link->next)
+        if (id == size_t(link)) {
+          link->unlink();  // deactivate and unlink sibling
+          return true;
+        }
       return false;
     }
   };
-  SignalLink   *callback_ring_; // linked ring of callback nodes
-  /*copy-ctor*/ ProtoSignal (const ProtoSignal&) = delete;
-  ProtoSignal&  operator=   (const ProtoSignal&) = delete;
-  void
-  ensure_ring ()
-  {
-    if (!callback_ring_)
-      {
-        callback_ring_ = new SignalLink (CbFunction()); // ref_count = 1
-        callback_ring_->incref(); // ref_count = 2, head of ring, can be deactivated but not removed
-        callback_ring_->next = callback_ring_; // ring head initialization
-        callback_ring_->prev = callback_ring_; // ring tail initialization
-      }
+  SignalLink *callback_ring_;  // linked ring of callback nodes
+  /*copy-ctor*/ ProtoSignal(const ProtoSignal &) = delete;
+  ProtoSignal &operator=(const ProtoSignal &) = delete;
+  void ensure_ring() {
+    if (!callback_ring_) {
+      callback_ring_ = new SignalLink(CbFunction());  // ref_count = 1
+      callback_ring_->incref();  // ref_count = 2, head of ring, can be
+                                 // deactivated but not removed
+      callback_ring_->next = callback_ring_;  // ring head initialization
+      callback_ring_->prev = callback_ring_;  // ring tail initialization
+    }
   }
-public:
+
+ public:
   /// ProtoSignal constructor, connects default callback if non-0.
-  ProtoSignal (const CbFunction &method) :
-    callback_ring_ (0)
-  {
-    if (method != 0)
-      {
-        ensure_ring();
-        callback_ring_->function = method;
-      }
+  ProtoSignal(const CbFunction &method) : callback_ring_(0) {
+    if (method != 0) {
+      ensure_ring();
+      callback_ring_->function = method;
+    }
   }
   /// ProtoSignal destructor releases all resources associated with this signal.
-  ~ProtoSignal ()
-  {
-    if (callback_ring_)
-      {
-        while (callback_ring_->next != callback_ring_)
-          callback_ring_->next->unlink();
-        assert (callback_ring_->ref_count >= 2);
-        callback_ring_->decref();
-        callback_ring_->decref();
-      }
+  ~ProtoSignal() {
+    if (callback_ring_) {
+      while (callback_ring_->next != callback_ring_)
+        callback_ring_->next->unlink();
+      assert(callback_ring_->ref_count >= 2);
+      callback_ring_->decref();
+      callback_ring_->decref();
+    }
+  }
+  /// Operator to add a new function or lambda as signal handler, returns a
+  /// handler connection ID.
+  size_t connect(const CbFunction &cb) {
+    ensure_ring();
+    return callback_ring_->add_before(cb);
+  }
+  /// Operator to remove a signal handler through it connection ID, returns if a
+  /// handler was removed.
+  bool disconnect(size_t connection) {
+    return callback_ring_ ? callback_ring_->remove_sibling(connection) : false;
   }
-  /// Operator to add a new function or lambda as signal handler, returns a handler connection ID.
-  size_t connect (const CbFunction &cb)      { ensure_ring(); return callback_ring_->add_before (cb); }
-  /// Operator to remove a signal handler through it connection ID, returns if a handler was removed.
-  bool   disconnect (size_t connection)         { return callback_ring_ ? callback_ring_->remove_sibling (connection) : false; }
-  /// Emit a signal, i.e. invoke all its callbacks and collect return types with the Collector.
-  CollectorResult
-  emit (Args... args)
-  {
+  /// Emit a signal, i.e. invoke all its callbacks and collect return types with
+  /// the Collector.
+  CollectorResult emit(Args... args) {
     Collector collector;
-    if (!callback_ring_)
-      return collector.result();
+    if (!callback_ring_) return collector.result();
     SignalLink *link = callback_ring_;
     link->incref();
-    do
-      {
-        if (link->function != 0)
-          {
-            const bool continue_emission = this->invoke (collector, link->function, args...);
-            if (!continue_emission)
-              break;
-          }
-        SignalLink *old = link;
-        link = old->next;
-        link->incref();
-        old->decref();
+    do {
+      if (link->function != 0) {
+        const bool continue_emission =
+            this->invoke(collector, link->function, args...);
+        if (!continue_emission) break;
       }
-    while (link != callback_ring_);
+      SignalLink *old = link;
+      link = old->next;
+      link->incref();
+      old->decref();
+    } while (link != callback_ring_);
     link->decref();
     return collector.result();
   }
   // Number of connected slots.
-  int
-  size ()
-  {
+  int size() {
     int size = 0;
     SignalLink *link = callback_ring_;
     link->incref();
-    do
-      {
-        if (link->function != 0)
-          {
-            size++;
-          }
-        SignalLink *old = link;
-        link = old->next;
-        link->incref();
-        old->decref();
+    do {
+      if (link->function != 0) {
+        size++;
       }
-    while (link != callback_ring_);
+      SignalLink *old = link;
+      link = old->next;
+      link->incref();
+      old->decref();
+    } while (link != callback_ring_);
     return size;
   }
 };
 
-} // Lib
-// namespace Simple
+}  // Lib
+   // namespace Simple
 
 /**
- * Signal is a template type providing an interface for arbitrary callback lists.
- * A signal type needs to be declared with the function signature of its callbacks,
+ * Signal is a template type providing an interface for arbitrary callback
+ * lists.
+ * A signal type needs to be declared with the function signature of its
+ * callbacks,
  * and optionally a return result collector class type.
- * Signal callbacks can be added with operator+= to a signal and removed with operator-=, using
+ * Signal callbacks can be added with operator+= to a signal and removed with
+ * operator-=, using
  * a callback connection ID return by operator+= as argument.
- * The callbacks of a signal are invoked with the emit() method and arguments according to the signature.
- * The result returned by emit() depends on the signal collector class. By default, the result of
- * the last callback is returned from emit(). Collectors can be implemented to accumulate callback
+ * The callbacks of a signal are invoked with the emit() method and arguments
+ * according to the signature.
+ * The result returned by emit() depends on the signal collector class. By
+ * default, the result of
+ * the last callback is returned from emit(). Collectors can be implemented to
+ * accumulate callback
  * results or to halt a running emissions in correspondance to callback results.
- * The signal implementation is safe against recursion, so callbacks may be removed and
+ * The signal implementation is safe against recursion, so callbacks may be
+ * removed and
  * added during a signal emission and recursive emit() calls are also safe.
- * The overhead of an unused signal is intentionally kept very low, around the size of a single pointer.
+ * The overhead of an unused signal is intentionally kept very low, around the
+ * size of a single pointer.
  * Note that the Signal template types is non-copyable.
  */
-template <typename SignalSignature, class Collector = Lib::CollectorDefault<typename std::function<SignalSignature>::result_type> >
-struct Signal /*final*/ :
-    Lib::ProtoSignal<SignalSignature, Collector>
-{
+template <typename SignalSignature,
+          class Collector = Lib::CollectorDefault<
+              typename std::function<SignalSignature>::result_type>>
+struct Signal /*final*/ : Lib::ProtoSignal<SignalSignature, Collector> {
   typedef Lib::ProtoSignal<SignalSignature, Collector> ProtoSignal;
-  typedef typename ProtoSignal::CbFunction             CbFunction;
+  typedef typename ProtoSignal::CbFunction CbFunction;
   /// Signal constructor, supports a default callback as argument.
-  Signal (const CbFunction &method = CbFunction()) : ProtoSignal (method) {}
+  Signal(const CbFunction &method = CbFunction()) : ProtoSignal(method) {}
 };
 
-/// This function creates a std::function by binding @a object to the member function pointer @a method.
-template<class Instance, class Class, class R, class... Args> std::function<R (Args...)>
-slot (Instance &object, R (Class::*method) (Args...))
-{
-  return [&object, method] (Args... args) { return (object .* method) (args...); };
+/// This function creates a std::function by binding @a object to the member
+/// function pointer @a method.
+template <class Instance, class Class, class R, class... Args>
+std::function<R(Args...)> slot(Instance &object, R (Class::*method)(Args...)) {
+  return [&object, method](Args... args) { return (object.*method)(args...); };
 }
 
-/// This function creates a std::function by binding @a object to the member function pointer @a method.
-template<class Class, class R, class... Args> std::function<R (Args...)>
-slot (Class *object, R (Class::*method) (Args...))
-{
-  return [object, method] (Args... args) { return (object ->* method) (args...); };
+/// This function creates a std::function by binding @a object to the member
+/// function pointer @a method.
+template <class Class, class R, class... Args>
+std::function<R(Args...)> slot(Class *object, R (Class::*method)(Args...)) {
+  return [object, method](Args... args) { return (object->*method)(args...); };
 }
 
 /// Keep signal emissions going while all handlers return !0 (true).
-template<typename Result>
+template <typename Result>
 struct CollectorUntil0 {
   typedef Result CollectorResult;
-  explicit                      CollectorUntil0 ()      : result_() {}
-  const CollectorResult&        result          ()      { return result_; }
-  inline bool
-  operator() (Result r)
-  {
+  explicit CollectorUntil0() : result_() {}
+  const CollectorResult &result() { return result_; }
+  inline bool operator()(Result r) {
     result_ = r;
     return result_ ? true : false;
   }
-private:
+
+ private:
   CollectorResult result_;
 };
 
 /// Keep signal emissions going while all handlers return 0 (false).
-template<typename Result>
+template <typename Result>
 struct CollectorWhile0 {
   typedef Result CollectorResult;
-  explicit                      CollectorWhile0 ()      : result_() {}
-  const CollectorResult&        result          ()      { return result_; }
-  inline bool
-  operator() (Result r)
-  {
+  explicit CollectorWhile0() : result_() {}
+  const CollectorResult &result() { return result_; }
+  inline bool operator()(Result r) {
     result_ = r;
     return result_ ? false : true;
   }
-private:
+
+ private:
   CollectorResult result_;
 };
 
-/// CollectorVector returns the result of the all signal handlers from a signal emission in a std::vector.
-template<typename Result>
+/// CollectorVector returns the result of the all signal handlers from a signal
+/// emission in a std::vector.
+template <typename Result>
 struct CollectorVector {
   typedef std::vector<Result> CollectorResult;
-  const CollectorResult&        result ()       { return result_; }
-  inline bool
-  operator() (Result r)
-  {
-    result_.push_back (r);
+  const CollectorResult &result() { return result_; }
+  inline bool operator()(Result r) {
+    result_.push_back(r);
     return true;
   }
-private:
+
+ private:
   CollectorResult result_;
 };
 
-} // Simple
-
+}  // Simple
 
 #endif  // SIMPLE_SIGNAL_H__
 
-
 #ifdef ENABLE_SIMPLE_SIGNAL_TESTS
 
 #include <string>
@@ -325,32 +328,23 @@ private:
 #include <mach/mach.h>
 #endif
 
-
-
-
-
-static std::string string_printf (const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
-static std::string
-string_printf (const char *format, ...)
-{
+static std::string string_printf(const char *format, ...)
+    __attribute__((__format__(__printf__, 1, 2)));
+static std::string string_printf(const char *format, ...) {
   std::string result;
   char *str = 0;
   va_list args;
-  va_start (args, format);
-  if (vasprintf (&str, format, args) >= 0)
-    result = str;
-  va_end (args);
-  if (str)
-    free (str);
+  va_start(args, format);
+  if (vasprintf(&str, format, args) >= 0) result = str;
+  va_end(args);
+  if (str) free(str);
   return result;
 }
 
-static uint64_t
-timestamp_benchmark ()
-{
-  struct timespec tp = { 0, 0 };
+static uint64_t timestamp_benchmark() {
+  struct timespec tp = {0, 0};
 
-#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
+#ifdef __MACH__  // OS X does not have clock_gettime, use clock_get_time
   clock_serv_t cclock;
   mach_timespec_t mts;
   host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
@@ -366,219 +360,221 @@ timestamp_benchmark ()
 }
 
 struct TestCounter {
-  static uint64_t get     ();
-  static void     set     (uint64_t);
-  static void     add2    (void*, uint64_t);
+  static uint64_t get();
+  static void set(uint64_t);
+  static void add2(void *, uint64_t);
 };
 
-namespace { // Anon
-void        (*test_counter_add2) (void*, uint64_t) = TestCounter::add2; // external symbol to prevent easy inlining
+namespace {  // Anon
+void (*test_counter_add2)(void *, uint64_t) =
+    TestCounter::add2;  // external symbol to prevent easy inlining
 static uint64_t test_counter_var = 0;
-} // Anon
+}  // Anon
 
 class BasicSignalTests {
   static std::string accu;
   struct Foo {
-    char
-    foo_bool (float f, int i, std::string s)
-    {
-      accu += string_printf ("Foo: %.2f\n", f + i + s.size());
+    char foo_bool(float f, int i, std::string s) {
+      accu += string_printf("Foo: %.2f\n", f + i + s.size());
       return true;
     }
   };
-  static char
-  float_callback (float f, int, std::string)
-  {
-    accu += string_printf ("float: %.2f\n", f);
+  static char float_callback(float f, int, std::string) {
+    accu += string_printf("float: %.2f\n", f);
     return 0;
   }
-public:
-  static void
-  run()
-  {
+
+ public:
+  static void run() {
     accu = "";
-    Simple::Signal<char (float, int, std::string)> sig1;
+    Simple::Signal<char(float, int, std::string)> sig1;
     size_t id1 = sig1.connect(float_callback);
-    size_t id2 = sig1.connect([] (float, int i, std::string) { accu += string_printf ("int: %d\n", i); return 0; });
-    size_t id3 = sig1.connect([] (float, int, const std::string &s) { accu += string_printf ("string: %s\n", s.c_str()); return 0; });
-    sig1.emit (.3, 4, "huhu");
+    size_t id2 = sig1.connect([](float, int i, std::string) {
+      accu += string_printf("int: %d\n", i);
+      return 0;
+    });
+    size_t id3 = sig1.connect([](float, int, const std::string &s) {
+      accu += string_printf("string: %s\n", s.c_str());
+      return 0;
+    });
+    sig1.emit(.3, 4, "huhu");
     bool success;
-    success = sig1.disconnect(id1); assert (success == true);  success = sig1.disconnect(id1); assert (success == false);
-    success = sig1.disconnect(id2); assert (success == true);  success = sig1.disconnect(id3); assert (success == true);
-    success = sig1.disconnect(id3); assert (success == false); success = sig1.disconnect(id2); assert (success == false);
+    success = sig1.disconnect(id1);
+    assert(success == true);
+    success = sig1.disconnect(id1);
+    assert(success == false);
+    success = sig1.disconnect(id2);
+    assert(success == true);
+    success = sig1.disconnect(id3);
+    assert(success == true);
+    success = sig1.disconnect(id3);
+    assert(success == false);
+    success = sig1.disconnect(id2);
+    assert(success == false);
     Foo foo;
-    sig1.connect(Simple::slot (foo, &Foo::foo_bool));
-    sig1.connect(Simple::slot (&foo, &Foo::foo_bool));
-    sig1.emit (.5, 1, "12");
+    sig1.connect(Simple::slot(foo, &Foo::foo_bool));
+    sig1.connect(Simple::slot(&foo, &Foo::foo_bool));
+    sig1.emit(.5, 1, "12");
 
-    Simple::Signal<void (std::string, int)> sig2;
-    sig2.connect([] (std::string msg, int) { accu += string_printf ("msg: %s", msg.c_str()); });
-    sig2.connect([] (std::string, int d)   { accu += string_printf (" *%d*\n", d); });
-    sig2.emit ("in sig2", 17);
+    Simple::Signal<void(std::string, int)> sig2;
+    sig2.connect([](std::string msg,
+                    int) { accu += string_printf("msg: %s", msg.c_str()); });
+    sig2.connect([](std::string,
+                    int d) { accu += string_printf(" *%d*\n", d); });
+    sig2.emit("in sig2", 17);
 
     accu += "DONE";
 
     const char *expected =
-      "float: 0.30\n"
-      "int: 4\n"
-      "string: huhu\n"
-      "Foo: 3.50\n"
-      "Foo: 3.50\n"
-      "msg: in sig2 *17*\n"
-      "DONE";
-    assert (accu == expected);
+        "float: 0.30\n"
+        "int: 4\n"
+        "string: huhu\n"
+        "Foo: 3.50\n"
+        "Foo: 3.50\n"
+        "msg: in sig2 *17*\n"
+        "DONE";
+    assert(accu == expected);
   }
 };
 std::string BasicSignalTests::accu;
 
-
 class TestCollectorVector {
-  static int handler1   ()  { return 1; }
-  static int handler42  ()  { return 42; }
-  static int handler777 ()  { return 777; }
-  public:
-  static void
-  run ()
-  {
-    Simple::Signal<int (), Simple::CollectorVector<int>> sig_vector;
+  static int handler1() { return 1; }
+  static int handler42() { return 42; }
+  static int handler777() { return 777; }
+
+ public:
+  static void run() {
+    Simple::Signal<int(), Simple::CollectorVector<int>> sig_vector;
     sig_vector.connect(handler777);
     sig_vector.connect(handler42);
     sig_vector.connect(handler1);
     sig_vector.connect(handler42);
     sig_vector.connect(handler777);
     std::vector<int> results = sig_vector.emit();
-    const std::vector<int> reference = { 777, 42, 1, 42, 777, };
-    assert (results == reference);
+    const std::vector<int> reference = {777, 42, 1, 42, 777, };
+    assert(results == reference);
   }
 };
 
 class TestCollectorUntil0 {
   bool check1, check2;
-  TestCollectorUntil0() : check1 (0), check2 (0) {}
-  bool handler_true  ()  { check1 = true; return true; }
-  bool handler_false ()  { check2 = true; return false; }
-  bool handler_abort ()  { abort(); }
-  public:
-  static void
-  run ()
-  {
+  TestCollectorUntil0() : check1(0), check2(0) {}
+  bool handler_true() {
+    check1 = true;
+    return true;
+  }
+  bool handler_false() {
+    check2 = true;
+    return false;
+  }
+  bool handler_abort() { abort(); }
+
+ public:
+  static void run() {
     TestCollectorUntil0 self;
-    Simple::Signal<bool (), Simple::CollectorUntil0<bool>> sig_until0;
-    sig_until0.connect(Simple::slot (self, &TestCollectorUntil0::handler_true));
-    sig_until0.connect(Simple::slot (self, &TestCollectorUntil0::handler_false));
-    sig_until0.connect(Simple::slot (self, &TestCollectorUntil0::handler_abort));
-    assert (!self.check1 && !self.check2);
+    Simple::Signal<bool(), Simple::CollectorUntil0<bool>> sig_until0;
+    sig_until0.connect(Simple::slot(self, &TestCollectorUntil0::handler_true));
+    sig_until0.connect(Simple::slot(self, &TestCollectorUntil0::handler_false));
+    sig_until0.connect(Simple::slot(self, &TestCollectorUntil0::handler_abort));
+    assert(!self.check1 && !self.check2);
     const bool result = sig_until0.emit();
-    assert (!result && self.check1 && self.check2);
+    assert(!result && self.check1 && self.check2);
   }
 };
 
 class TestCollectorWhile0 {
   bool check1, check2;
-  TestCollectorWhile0() : check1 (0), check2 (0) {}
-  bool handler_0     ()  { check1 = true; return false; }
-  bool handler_1     ()  { check2 = true; return true; }
-  bool handler_abort ()  { abort(); }
-  public:
-  static void
-  run ()
-  {
+  TestCollectorWhile0() : check1(0), check2(0) {}
+  bool handler_0() {
+    check1 = true;
+    return false;
+  }
+  bool handler_1() {
+    check2 = true;
+    return true;
+  }
+  bool handler_abort() { abort(); }
+
+ public:
+  static void run() {
     TestCollectorWhile0 self;
-    Simple::Signal<bool (), Simple::CollectorWhile0<bool>> sig_while0;
-    sig_while0.connect(Simple::slot (self, &TestCollectorWhile0::handler_0));
-    sig_while0.connect(Simple::slot (self, &TestCollectorWhile0::handler_1));
-    sig_while0.connect(Simple::slot (self, &TestCollectorWhile0::handler_abort));
-    assert (!self.check1 && !self.check2);
+    Simple::Signal<bool(), Simple::CollectorWhile0<bool>> sig_while0;
+    sig_while0.connect(Simple::slot(self, &TestCollectorWhile0::handler_0));
+    sig_while0.connect(Simple::slot(self, &TestCollectorWhile0::handler_1));
+    sig_while0.connect(Simple::slot(self, &TestCollectorWhile0::handler_abort));
+    assert(!self.check1 && !self.check2);
     const bool result = sig_while0.emit();
-    assert (result == true && self.check1 && self.check2);
+    assert(result == true && self.check1 && self.check2);
   }
 };
 
-static void
-bench_simple_signal()
-{
-  Simple::Signal<void (void*, uint64_t)> sig_increment;
+static void bench_simple_signal() {
+  Simple::Signal<void(void *, uint64_t)> sig_increment;
   sig_increment.connect(test_counter_add2);
   const uint64_t start_counter = TestCounter::get();
   const uint64_t benchstart = timestamp_benchmark();
   uint64_t i;
-  for (i = 0; i < 999999; i++)
-    {
-      sig_increment.emit (0, 1);
-    }
+  for (i = 0; i < 999999; i++) {
+    sig_increment.emit(0, 1);
+  }
   const uint64_t benchdone = timestamp_benchmark();
   const uint64_t end_counter = TestCounter::get();
-  assert (end_counter - start_counter == i);
-  printf ("OK\n  Benchmark: Simple::Signal: %fns per emission (size=%zu): ", size_t (benchdone - benchstart) * 1.0 / size_t (i),
-          sizeof (sig_increment));
+  assert(end_counter - start_counter == i);
+  printf("OK\n  Benchmark: Simple::Signal: %fns per emission (size=%zu): ",
+         size_t(benchdone - benchstart) * 1.0 / size_t(i),
+         sizeof(sig_increment));
 }
 
-static void
-bench_callback_loop()
-{
-  void (*counter_increment) (void*, uint64_t) = test_counter_add2;
+static void bench_callback_loop() {
+  void (*counter_increment)(void *, uint64_t) = test_counter_add2;
   const uint64_t start_counter = TestCounter::get();
   const uint64_t benchstart = timestamp_benchmark();
   uint64_t i;
-  for (i = 0; i < 999999; i++)
-    {
-      counter_increment (0, 1);
-    }
+  for (i = 0; i < 999999; i++) {
+    counter_increment(0, 1);
+  }
   const uint64_t benchdone = timestamp_benchmark();
   const uint64_t end_counter = TestCounter::get();
-  assert (end_counter - start_counter == i);
-  printf ("OK\n  Benchmark: callback loop: %fns per round: ", size_t (benchdone - benchstart) * 1.0 / size_t (i));
+  assert(end_counter - start_counter == i);
+  printf("OK\n  Benchmark: callback loop: %fns per round: ",
+         size_t(benchdone - benchstart) * 1.0 / size_t(i));
 }
 
-uint64_t
-TestCounter::get ()
-{
-  return test_counter_var;
-}
+uint64_t TestCounter::get() { return test_counter_var; }
 
-void
-TestCounter::set (uint64_t v)
-{
-  test_counter_var = v;
-}
+void TestCounter::set(uint64_t v) { test_counter_var = v; }
 
-void
-TestCounter::add2 (void*, uint64_t v)
-{
-  test_counter_var += v;
-}
+void TestCounter::add2(void *, uint64_t v) { test_counter_var += v; }
 
-int
-main (int   argc,
-      char *argv[])
-{
-  printf ("Signal/Basic Tests: ");
+int main(int argc, char *argv[]) {
+  printf("Signal/Basic Tests: ");
   BasicSignalTests::run();
-  printf ("OK\n");
+  printf("OK\n");
 
-  printf ("Signal/CollectorVector: ");
+  printf("Signal/CollectorVector: ");
   TestCollectorVector::run();
-  printf ("OK\n");
+  printf("OK\n");
 
-  printf ("Signal/CollectorUntil0: ");
+  printf("Signal/CollectorUntil0: ");
   TestCollectorUntil0::run();
-  printf ("OK\n");
+  printf("OK\n");
 
-  printf ("Signal/CollectorWhile0: ");
+  printf("Signal/CollectorWhile0: ");
   TestCollectorWhile0::run();
-  printf ("OK\n");
+  printf("OK\n");
 
-  printf ("Signal/Benchmark: Simple::Signal: ");
+  printf("Signal/Benchmark: Simple::Signal: ");
   bench_simple_signal();
-  printf ("OK\n");
+  printf("OK\n");
 
-  printf ("Signal/Benchmark: callback loop: ");
+  printf("Signal/Benchmark: callback loop: ");
   bench_callback_loop();
-  printf ("OK\n");
+  printf("OK\n");
 
   return 0;
 }
 
-#endif // DISABLE_TESTS
+#endif  // DISABLE_TESTS
 
 // g++ -Wall -O2 -std=gnu++0x -pthread simplesignal.cc -lrt && ./a.out
index 084b7bdb2435df660d05eb8647b247dbadf824fe..72ae92691e9875b3a2d0df2c40a76d6a59dc653c 100644 (file)
@@ -107,7 +107,7 @@ TEST_F(BenchmarksTest, TestEntityIteration) {
   cout << "iterating over " << count << " entities with a component 10 times" << endl;
 
   for (int i = 0; i < 10; ++i) {
-    ComponentPtr<Position> position;
+    Position *position;
     for (auto e : em.entities_with_components<Position>(position)) {
     }
   }
index ffdfbeeabd1a5062108928fdd11d3983aed39ed3..e81ae802bd47bd3f25e99b8ebe0a3da28c2adac2 100644 (file)
@@ -39,10 +39,10 @@ EntityManager::~EntityManager() {
 }
 
 void EntityManager::reset() {
-  for (auto allocator : component_allocators_) {
-    if (allocator) delete allocator;
+  for (BasePool *pool : component_pools_) {
+    if (pool) delete pool;
   }
-  component_allocators_.clear();
+  component_pools_.clear();
   entity_component_mask_.clear();
   entity_version_.clear();
   free_list_.clear();
index 18f04b858913ec15a6d17fb66e87ef2c2278a998..2556caa24260f4a8471ed432b324b081638e98a6 100644 (file)
@@ -12,6 +12,7 @@
 
 
 #include <stdint.h>
+#include <new>
 #include <cstdlib>
 #include <algorithm>
 #include <bitset>
@@ -25,6 +26,7 @@
 #include <utility>
 #include <vector>
 
+#include "entityx/help/Pool.h"
 #include "entityx/config.h"
 #include "entityx/Event.h"
 #include "entityx/help/NonCopyable.h"
@@ -35,10 +37,6 @@ namespace entityx {
 class EntityManager;
 
 
-template <typename T>
-class ComponentPtr;
-
-
 /** A convenience handle around an Entity::Id.
  *
  * If an entity is destroyed, any copies will be invalidated. Use valid() to
@@ -121,19 +119,17 @@ public:
 
   Id id() const { return id_; }
 
-  template <typename C>
-  ComponentPtr<C> assign(ComponentPtr<C> component);
   template <typename C, typename ... Args>
-  ComponentPtr<C> assign(Args && ... args);
+  C *assign(Args && ... args);
 
   template <typename C>
   void remove();
 
   template <typename C>
-  ComponentPtr<C> component();
+  C *component();
 
   template <typename A, typename ... Args>
-  void unpack(ComponentPtr<A> &a, ComponentPtr<Args> & ... args);
+  void unpack(A *&a, Args *& ... args);
 
   /**
    * Destroy and invalidate this Entity.
@@ -169,6 +165,12 @@ struct BaseComponent {
  public:
   typedef uint64_t Family;
 
+  // NOTE: Component memory is *always* managed by the EntityManager.
+  // Use Entity::destroy() instead.
+  void operator delete(void *p) { throw std::bad_alloc(); }
+  void operator delete[](void *p) { throw std::bad_alloc(); }
+
+
  protected:
   static Family family_counter_;
 };
@@ -200,43 +202,6 @@ struct Component : public BaseComponent {
 };
 
 
-/**
- * Managed pointer for components.
- */
-template <typename T>
-class ComponentPtr {
-public:
-  ComponentPtr() : id_(0), manager_(nullptr) {}
-
-  T *operator -> ();
-  const T *operator -> () const;
-
-  operator bool () const { return valid(); }
-  bool valid() const;
-
-  bool operator == (const ComponentPtr<T> &other) const {
-    return other.id_ == id_ && other.manager_ == manager_;
-  }
-
-private:
-  friend class EntityManager;
-
-  ComponentPtr(Entity::Id id, EntityManager *manager) : id_(id), manager_(manager) {}
-  ComponentPtr(Entity::Id id, const EntityManager *manager) :
-      id_(id), manager_(const_cast<EntityManager*>(manager)) {}
-
-  T *get_component_ptr();
-  const T *get_component_ptr() const;
-
-  template <typename R>
-  friend inline std::ostream &operator << (std::ostream &out, const ComponentPtr<R> &ptr);
-
-  Entity::Id id_;
-  EntityManager *manager_;
-};
-
-
-
 /**
  * Emitted when an entity is added to the system.
  */
@@ -260,94 +225,25 @@ struct EntityDestroyedEvent : public Event<EntityDestroyedEvent> {
 /**
  * Emitted when any component is added to an entity.
  */
-template <typename T>
-struct ComponentAddedEvent : public Event<ComponentAddedEvent<T>> {
-  ComponentAddedEvent(Entity entity, ComponentPtr<T> component) :
+template <typename C>
+struct ComponentAddedEvent : public Event<ComponentAddedEvent<C>> {
+  ComponentAddedEvent(Entity entity, C *component) :
       entity(entity), component(component) {}
 
   Entity entity;
-  ComponentPtr<T> component;
+  C *component;
 };
 
 /**
  * Emitted when any component is removed from an entity.
  */
-template <typename T>
-struct ComponentRemovedEvent : public Event<ComponentRemovedEvent<T>> {
-  ComponentRemovedEvent(Entity entity, ComponentPtr<T> component) :
+template <typename C>
+struct ComponentRemovedEvent : public Event<ComponentRemovedEvent<C>> {
+  ComponentRemovedEvent(Entity entity, C *component) :
       entity(entity), component(component) {}
 
   Entity entity;
-  ComponentPtr<T> component;
-};
-
-
-/**
- * Cache-friendly component allocator.
- */
-class BaseComponentAllocator {
-public:
-  BaseComponentAllocator(int sizeof_element, int size = 0) :
-      sizeof_(sizeof_element), size_(0), capacity_(32),
-      components_(static_cast<char*>(malloc(sizeof_ * 32))) {
-    reserve(size);
-  }
-
-  virtual ~BaseComponentAllocator() {
-    free(components_);
-  }
-
-  /**
-   * Get a pointer to the nth element.
-   */
-  void *get(int n) {
-    assert(n < size_);
-    return static_cast<void*>(components_ + n * sizeof_);
-  }
-
-  const void *get(int n) const {
-    assert(n < size_);
-    return static_cast<const void*>(components_ + n * sizeof_);
-  }
-
-  /**
-   * Resize the underlying array so it fits *at least* n elements.
-   */
-  void reserve(int n) {
-    if (n >= size_) {
-      // Resize underlying array.
-      if (n >= capacity_) {
-        while (n >= capacity_)
-          capacity_ *= 2;
-        components_ = static_cast<char*>(realloc(components_, capacity_ * sizeof_));
-        assert(components_);
-      }
-      size_ = n + 1;
-    }
-  }
-
-  /**
-   * Call the destructor of the object at slot n.
-   */
-  virtual void destroy(int n) = 0;
-
-private:
-  int sizeof_;
-  int size_;
-  int capacity_;
-  char *components_;
-};
-
-
-template <typename T>
-class ComponentAllocator : public BaseComponentAllocator {
-public:
-  explicit ComponentAllocator(int size = 0) : BaseComponentAllocator(sizeof(T), size) {}
-
-  virtual void destroy(int n) {
-    T *ptr = static_cast<T*>(get(n));
-    ptr->~T();
-  }
+  C *component;
 };
 
 
@@ -435,13 +331,13 @@ class EntityManager : entityx::help::NonCopyable {
     const Iterator end() const { return Iterator(manager_, predicates_, unpackers_, manager_->capacity()); }
 
     template <typename A>
-    View &unpack_to(ComponentPtr<A> &a) {
+    View &unpack_to(A *&a) {
       unpackers_.push_back(std::shared_ptr<Unpacker<A>>(new Unpacker<A>(manager_, a)));
       return *this;
     }
 
     template <typename A, typename B, typename ... Args>
-    View &unpack_to(ComponentPtr<A> &a, ComponentPtr<B> &b, ComponentPtr<Args> & ... args) {
+    View &unpack_to(A *&a, B *&b, Args *& ... args) {
       unpack_to<A>(a);
       return unpack_to<B, Args ...>(b, args ...);
     }
@@ -449,17 +345,17 @@ class EntityManager : entityx::help::NonCopyable {
    private:
     friend class EntityManager;
 
-    template <typename T>
+    template <typename C>
     struct Unpacker : BaseUnpacker {
-      Unpacker(EntityManager *manager, ComponentPtr<T> &c) : manager_(manager), c(c) {}
+      Unpacker(EntityManager *manager, C *&c) : manager_(manager), c(c) {}
 
       void unpack(const Entity::Id &id) {
-        c = manager_->component<T>(id);
+        c = manager_->component<C>(id);
       }
 
      private:
       EntityManager *manager_;
-      ComponentPtr<T> &c;
+      C *&c;
     };
 
     View(EntityManager *manager, Predicate predicate) : manager_(manager) {
@@ -518,8 +414,8 @@ class EntityManager : entityx::help::NonCopyable {
     assert_valid(entity);
     int index = entity.index();
     event_manager_.emit<EntityDestroyedEvent>(Entity(this, entity));
-    for (BaseComponentAllocator *allocator : component_allocators_) {
-      if (allocator) allocator->destroy(index);
+    for (BasePool *pool : component_pools_) {
+      if (pool) pool->destroy(index);
     }
     entity_component_mask_[index] = 0;
     entity_version_[index]++;
@@ -544,20 +440,20 @@ class EntityManager : entityx::help::NonCopyable {
   /**
    * Assign a Component to an Entity::Id, passing through Component constructor arguments.
    *
-   *     ComponentPtr<Position> position = em.assign<Position>(e, x, y);
+   *     Position &position = em.assign<Position>(e, x, y);
    *
    * @returns Smart pointer to newly created component.
    */
   template <typename C, typename ... Args>
-  ComponentPtr<C> assign(Entity::Id id, Args && ... args) {
+  C *assign(Entity::Id id, Args && ... args) {
     assert_valid(id);
     const int family = C::family();
-    ComponentAllocator<C> *allocator = accomodate_component<C>();
-    new(allocator->get(id.index())) C(std::forward<Args>(args) ...);
+    // Placement new into the component pool.
+    Pool<C> *pool = accomodate_component<C>();
+    C *component = new(pool->get(id.index())) C(std::forward<Args>(args) ...);
     entity_component_mask_[id.index()] |= uint64_t(1) << family;
-    ComponentPtr<C> component(id, this);
     event_manager_.emit<ComponentAddedEvent<C>>(Entity(this, id), component);
-    return ComponentPtr<C>(id, this);
+    return component;
   }
 
   /**
@@ -570,48 +466,47 @@ class EntityManager : entityx::help::NonCopyable {
     assert_valid(id);
     const int family = C::family();
     const int index = id.index();
-    BaseComponentAllocator *allocator = component_allocators_[family];
-    assert(allocator);
+    BasePool *pool = component_pools_[family];
+    C *component = static_cast<C*>(pool->get(id.index()));
     entity_component_mask_[id.index()] &= ~(uint64_t(1) << family);
-    ComponentPtr<C> component(id, this);
     event_manager_.emit<ComponentRemovedEvent<C>>(Entity(this, id), component);
-    allocator->destroy(index);
+    pool->destroy(index);
   }
 
   /**
    * Retrieve a Component assigned to an Entity::Id.
    *
-   * @returns Component instance, or empty ComponentPtr<> if the Entity::Id does not have that Component.
+   * @returns Pointer to an instance of C, or nullptr if the Entity::Id does not have that Component.
    */
   template <typename C>
-  ComponentPtr<C> component(Entity::Id id) {
+  C *component(Entity::Id id) {
     assert_valid(id);
     size_t family = C::family();
     // We don't bother checking the component mask, as we return a nullptr anyway.
-    if (family >= component_allocators_.size())
-      return ComponentPtr<C>();
-    BaseComponentAllocator *allocator = component_allocators_[family];
-    if (!allocator || !entity_component_mask_[id.index()][family])
-      return ComponentPtr<C>();
-    return ComponentPtr<C>(id, this);
+    if (family >= component_pools_.size())
+      return nullptr;
+    BasePool *pool = component_pools_[family];
+    if (!pool || !entity_component_mask_[id.index()][family])
+      return nullptr;
+    return static_cast<C*>(pool->get(id.index()));
   }
 
   /**
    * Retrieve a Component assigned to an Entity::Id.
    *
-   * @returns Component instance, or empty ComponentPtr<> if the Entity::Id does not have that Component.
+   * @returns Component instance, or nullptr if the Entity::Id does not have that Component.
    */
   template <typename C>
-  ComponentPtr<const C> component(Entity::Id id) const {
+  const C *component(Entity::Id id) const {
     assert_valid(id);
     size_t family = C::family();
     // We don't bother checking the component mask, as we return a nullptr anyway.
-    if (family >= component_allocators_.size())
-      return ComponentPtr<const C>();
-    BaseComponentAllocator *allocator = component_allocators_[family];
-    if (!allocator || !entity_component_mask_[id.index()][family])
-      return ComponentPtr<const C>();
-    return ComponentPtr<const C>(id, this);
+    if (family >= component_pools_.size())
+      return nullptr;
+    BasePool *pool = component_pools_[family];
+    if (!pool || !entity_component_mask_[id.index()][family])
+      return nullptr;
+    return static_cast<const C*>(pool->get(id.index()));
   }
 
   /**
@@ -619,8 +514,8 @@ class EntityManager : entityx::help::NonCopyable {
    *
    * @code
    * for (Entity entity : entity_manager.entities_with_components<Position, Direction>()) {
-   *   ComponentPtr<Position> position = entity.component<Position>();
-   *   ComponentPtr<Direction> direction = entity.component<Direction>();
+   *   Position *position = entity.component<Position>();
+   *   Direction *direction = entity.component<Direction>();
    *
    *   ...
    * }
@@ -637,15 +532,15 @@ class EntityManager : entityx::help::NonCopyable {
    * to the given parameters.
    *
    * @code
-   * ComponentPtr<Position> position;
-   * ComponentPtr<Direction> direction;
+   * Position *position;
+   * Direction *direction;
    * for (Entity entity : entity_manager.entities_with_components(position, direction)) {
    *   // Use position and component here.
    * }
    * @endcode
    */
   template <typename C, typename ... Components>
-  View entities_with_components(ComponentPtr<C> &c, ComponentPtr<Components> & ... args) {
+  View entities_with_components(C *&c, Components *& ... args) {
     auto mask = component_mask(c, args ...);
     return
         View(this, ComponentMaskPredicate(entity_component_mask_, mask))
@@ -653,7 +548,7 @@ class EntityManager : entityx::help::NonCopyable {
   }
 
   template <typename A>
-  void unpack(Entity::Id id, ComponentPtr<A> &a) {
+  void unpack(Entity::Id id, A *&a) {
     assert_valid(id);
     a = component<A>(id);
   }
@@ -670,7 +565,7 @@ class EntityManager : entityx::help::NonCopyable {
    * unpack<Position, Direction>(e, p, d);
    */
   template <typename A, typename ... Args>
-  void unpack(Entity::Id id, ComponentPtr<A> &a, ComponentPtr<Args> & ... args) {
+  void unpack(Entity::Id id, A *&a, Args *& ... args) {
     assert_valid(id);
     a = component<A>(id);
     unpack<Args ...>(id, args ...);
@@ -682,8 +577,6 @@ class EntityManager : entityx::help::NonCopyable {
   void reset();
 
  private:
-  template <typename C>
-  friend class ComponentPtr;
   friend class Entity;
 
   /// A predicate that matches valid entities with the given component mask.
@@ -710,17 +603,17 @@ class EntityManager : entityx::help::NonCopyable {
   template <typename C>
   C *get_component_ptr(Entity::Id id) {
     assert(valid(id));
-    BaseComponentAllocator *allocator = component_allocators_[C::family()];
-    assert(allocator);
-    return static_cast<C*>(allocator->get(id.index()));
+    BasePool *pool = component_pools_[C::family()];
+    assert(pool);
+    return static_cast<C*>(pool->get(id.index()));
   }
 
   template <typename C>
   const C *get_component_ptr(Entity::Id id) const {
     assert_valid(id);
-    BaseComponentAllocator *allocator = component_allocators_[C::family()];
-    assert(allocator);
-    return static_cast<const C*>(allocator->get(id.index()));
+    BasePool *pool = component_pools_[C::family()];
+    assert(pool);
+    return static_cast<const C*>(pool->get(id.index()));
   }
 
   ComponentMask component_mask(Entity::Id id) {
@@ -741,12 +634,12 @@ class EntityManager : entityx::help::NonCopyable {
   }
 
   template <typename C>
-  ComponentMask component_mask(const ComponentPtr<C> &c) {
+  ComponentMask component_mask(const C *c) {
     return component_mask<C>();
   }
 
   template <typename C1, typename C2, typename ... Components>
-  ComponentMask component_mask(const ComponentPtr<C1> &c1, const ComponentPtr<C2> &c2, ComponentPtr<Components> & ... args) {
+  ComponentMask component_mask(const C1 *c1, const C2 *c2, Components * ... args) {
     return component_mask<C1>(c1) | component_mask<C2, Components ...>(c2, args...);
   }
 
@@ -754,30 +647,31 @@ class EntityManager : entityx::help::NonCopyable {
     if (entity_component_mask_.size() <= index) {
       entity_component_mask_.resize(index + 1);
       entity_version_.resize(index + 1);
-      for (BaseComponentAllocator *allocator : component_allocators_) {
-          if (allocator) allocator->reserve(index);
-      }
+      for (BasePool *pool : component_pools_)
+        if (pool) pool->expand(index + 1);
     }
   }
 
   template <typename T>
-  ComponentAllocator<T> *accomodate_component() {
+  Pool<T> *accomodate_component() {
     BaseComponent::Family family = T::family();
-    if (component_allocators_.size() <= family) {
-      component_allocators_.resize(family + 1, nullptr);
+    if (component_pools_.size() <= family) {
+      component_pools_.resize(family + 1, nullptr);
     }
-    if (!component_allocators_[family]) {
-      component_allocators_[family] = new ComponentAllocator<T>(index_counter_);
+    if (!component_pools_[family]) {
+      Pool<T> *pool = new Pool<T>();
+      pool->expand(index_counter_);
+      component_pools_[family] = pool;
     }
-    return static_cast<ComponentAllocator<T>*>(component_allocators_[family]);
+    return static_cast<Pool<T>*>(component_pools_[family]);
   }
 
 
   uint32_t index_counter_ = 0;
 
   EventManager &event_manager_;
-  // Each element in component_allocators_ corresponds to a Component::family().
-  std::vector<BaseComponentAllocator*> component_allocators_;
+  // Each element in component_pools_ corresponds to a Component::family().
+  std::vector<BasePool*> component_pools_;
   // Bitmask of components associated with each entity. Index into the vector is the Entity::Id.
   std::vector<ComponentMask> entity_component_mask_;
   // Vector of entity version numbers. Incremented each time an entity is destroyed
@@ -796,7 +690,7 @@ BaseComponent::Family Component<C>::family() {
 
 
 template <typename C, typename ... Args>
-ComponentPtr<C> Entity::assign(Args && ... args) {
+C *Entity::assign(Args && ... args) {
   assert(valid());
   return manager_->assign<C>(id_, std::forward<Args>(args) ...);
 }
@@ -808,13 +702,13 @@ void Entity::remove() {
 }
 
 template <typename C>
-ComponentPtr<C> Entity::component() {
+C *Entity::component() {
   assert(valid());
   return manager_->component<C>(id_);
 }
 
 template <typename A, typename ... Args>
-void Entity::unpack(ComponentPtr<A> &a, ComponentPtr<Args> & ... args) {
+void Entity::unpack(A *&a, Args *& ... args) {
   assert(valid());
   manager_->unpack(id_, a, args ...);
 }
@@ -824,34 +718,4 @@ inline bool Entity::valid() const {
 }
 
 
-template <typename T>
-inline T *ComponentPtr<T>::operator -> () {
-  return manager_->get_component_ptr<T>(id_);
-}
-
-template <typename T>
-inline const T *ComponentPtr<T>::operator -> () const {
-  return manager_->get_component_ptr<T>(id_);
-}
-
-template <typename T>
-inline bool ComponentPtr<T>::valid() const {
-  return manager_ && manager_->valid(id_);
-}
-
-template <typename T>
-inline T *ComponentPtr<T>::get_component_ptr() {
-  return manager_->get_component_ptr<T>(id_);
-}
-
-template <typename T>
-inline const T *ComponentPtr<T>::get_component_ptr() const {
-  return manager_->get_component_ptr<T>(id_);
-}
-
-
-template <typename T>
-inline std::ostream &operator << (std::ostream &out, const ComponentPtr<T> &ptr) {
-  return out << *(ptr.get_component_ptr());
-}
 }  // namespace entityx
index 2caf8f4f2bd7df71953fe0960888827476e43f39..e6d3d7062746bdc5cebf32cade8c180c3366eb41 100644 (file)
@@ -36,28 +36,29 @@ int size(const T &t) {
 struct Position : Component<Position> {
   Position(float x = 0.0f, float y = 0.0f) : x(x), y(y) {}
 
-  bool operator == (const Position &other) const { return x == other.x && y == other.y; }
+  bool operator==(const Position &other) const {
+    return x == other.x && y == other.y;
+  }
 
   float x, y;
 };
 
-
-ostream &operator << (ostream &out, const Position &position) {
+ostream &operator<<(ostream &out, const Position &position) {
   out << "Position(" << position.x << ", " << position.y << ")";
   return out;
 }
 
-
 struct Direction : Component<Direction> {
   Direction(float x = 0.0f, float y = 0.0f) : x(x), y(y) {}
 
-  bool operator == (const Direction &other) const { return x == other.x && y == other.y; }
+  bool operator==(const Direction &other) const {
+    return x == other.x && y == other.y;
+  }
 
   float x, y;
 };
 
-
-ostream &operator << (ostream &out, const Direction &direction) {
+ostream &operator<<(ostream &out, const Direction &direction) {
   out << "Direction(" << direction.x << ", " << direction.y << ")";
   return out;
 }
@@ -65,12 +66,12 @@ ostream &operator << (ostream &out, const Direction &direction) {
 struct Tag : Component<Tag> {
   explicit Tag(string tag) : tag(tag) {}
 
-  bool operator == (const Tag &other) const { return tag == other.tag; }
+  bool operator==(const Tag &other) const { return tag == other.tag; }
 
   string tag;
 };
 
-ostream &operator << (ostream &out, const Tag &tag) {
+ostream &operator<<(ostream &out, const Tag &tag) {
   out << "Tag(" << tag.tag << ")";
   return out;
 }
@@ -82,11 +83,9 @@ class EntityManagerTest : public ::testing::Test {
   EventManager ev;
   EntityManager em;
 
-  virtual void SetUp() {
-  }
+  virtual void SetUp() {}
 };
 
-
 TEST_F(EntityManagerTest, TestCreateEntity) {
   ASSERT_EQ(em.size(), 0UL);
 
@@ -184,10 +183,8 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithIntersectionOfComponents) {
   for (int i = 0; i < 150; ++i) {
     Entity e = em.create();
     entities.push_back(e);
-    if (i % 2 == 0)
-      e.assign<Position>();
-    if (i % 3 == 0)
-      e.assign<Direction>();
+    if (i % 2 == 0) e.assign<Position>();
+    if (i % 3 == 0) e.assign<Direction>();
   }
   ASSERT_EQ(50, size(em.entities_with_components<Direction>()));
   ASSERT_EQ(75, size(em.entities_with_components<Position>()));
@@ -199,22 +196,19 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
   Entity e = em.create();
   Entity f = em.create();
   Entity g = em.create();
-  std::vector<std::pair<ComponentPtr<Position>, ComponentPtr<Direction>>> position_directions;
+  std::vector<std::pair<Position *, Direction *>> position_directions;
   position_directions.push_back(std::make_pair(
-          e.assign<Position>(1.0f, 2.0f),
-          e.assign<Direction>(3.0f, 4.0f)));
+      e.assign<Position>(1.0f, 2.0f), e.assign<Direction>(3.0f, 4.0f)));
   position_directions.push_back(std::make_pair(
-          f.assign<Position>(7.0f, 8.0f),
-          f.assign<Direction>(9.0f, 10.0f)));
+      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;
 
-
-  ComponentPtr<Position> position;
+  Position *position;
   ASSERT_EQ(3, size(em.entities_with_components(position)));
 
-  ComponentPtr<Direction> direction;
+  Direction *direction;
   for (auto unused_entity : em.entities_with_components(position, direction)) {
     (void)unused_entity;
     ASSERT_TRUE(static_cast<bool>(position));
@@ -225,9 +219,10 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
     ++i;
   }
   ASSERT_EQ(2, i);
-  ComponentPtr<Tag> tag;
+  Tag *tag;
   i = 0;
-  for (auto unused_entity : em.entities_with_components(position, direction, tag)) {
+  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));
@@ -247,9 +242,9 @@ TEST_F(EntityManagerTest, TestUnpack) {
   auto d = e.assign<Direction>(3.0, 4.0);
   auto t = e.assign<Tag>("tag");
 
-  ComponentPtr<Position> up;
-  ComponentPtr<Direction> ud;
-  ComponentPtr<Tag> ut;
+  Position *up;
+  Direction *ud;
+  Tag *ut;
   e.unpack(up);
   ASSERT_EQ(p, up);
   e.unpack(up, ud);
@@ -261,14 +256,17 @@ TEST_F(EntityManagerTest, TestUnpack) {
   ASSERT_EQ(t, ut);
 }
 
-// gcc 4.7.2 does not allow this struct to be declared locally inside the TEST_F.
+// gcc 4.7.2 does not allow this struct to be declared locally inside the
+// TEST_F.
 
 // TEST_F(EntityManagerTest, TestUnpackNullMissing) {
 //   Entity e = em.create();
 //   auto p = e.assign<Position>();
 
-//   std::shared_ptr<Position> up(reinterpret_cast<Position*>(0Xdeadbeef), NullDeleter());
-//   std::shared_ptr<Direction> ud(reinterpret_cast<Direction*>(0Xdeadbeef), NullDeleter());
+//   std::shared_ptr<Position> up(reinterpret_cast<Position*>(0Xdeadbeef),
+// NullDeleter());
+//   std::shared_ptr<Direction> ud(reinterpret_cast<Direction*>(0Xdeadbeef),
+// NullDeleter());
 //   e.unpack<Position, Direction>(up, ud);
 //   ASSERT_EQ(p, up);
 //   ASSERT_EQ(std::shared_ptr<Direction>(), ud);
@@ -279,7 +277,8 @@ TEST_F(EntityManagerTest, TestComponentIdsDiffer) {
 }
 
 TEST_F(EntityManagerTest, TestEntityCreatedEvent) {
-  struct EntityCreatedEventReceiver : public Receiver<EntityCreatedEventReceiver> {
+  struct EntityCreatedEventReceiver
+      : public Receiver<EntityCreatedEventReceiver> {
     void receive(const EntityCreatedEvent &event) {
       created.push_back(event.entity);
     }
@@ -298,7 +297,8 @@ TEST_F(EntityManagerTest, TestEntityCreatedEvent) {
 }
 
 TEST_F(EntityManagerTest, TestEntityDestroyedEvent) {
-  struct EntityDestroyedEventReceiver : public Receiver<EntityDestroyedEventReceiver> {
+  struct EntityDestroyedEventReceiver
+      : public Receiver<EntityDestroyedEventReceiver> {
     void receive(const EntityDestroyedEvent &event) {
       destroyed.push_back(event.entity);
     }
@@ -322,7 +322,8 @@ TEST_F(EntityManagerTest, TestEntityDestroyedEvent) {
 }
 
 TEST_F(EntityManagerTest, TestComponentAddedEvent) {
-  struct ComponentAddedEventReceiver : public Receiver<ComponentAddedEventReceiver> {
+  struct ComponentAddedEventReceiver
+      : public Receiver<ComponentAddedEventReceiver> {
     void receive(const ComponentAddedEvent<Position> &event) {
       auto p = event.component;
       float n = static_cast<float>(position_events);
@@ -361,13 +362,14 @@ TEST_F(EntityManagerTest, TestComponentAddedEvent) {
   ASSERT_EQ(10, receiver.direction_events);
 }
 
+
 TEST_F(EntityManagerTest, TestComponentRemovedEvent) {
   struct ComponentRemovedReceiver : public Receiver<ComponentRemovedReceiver> {
     void receive(const ComponentRemovedEvent<Direction> &event) {
       removed = event.component;
     }
 
-    ComponentPtr<Direction> removed;
+    Direction *removed = nullptr;
   };
 
   ComponentRemovedReceiver receiver;
@@ -375,7 +377,7 @@ TEST_F(EntityManagerTest, TestComponentRemovedEvent) {
 
   ASSERT_FALSE(receiver.removed);
   Entity e = em.create();
-  auto p = e.assign<Direction>(1.0, 2.0);
+  Direction *p = e.assign<Direction>(1.0, 2.0);
   e.remove<Direction>();
   ASSERT_EQ(receiver.removed, p);
   ASSERT_FALSE(e.component<Direction>());
@@ -398,13 +400,13 @@ TEST_F(EntityManagerTest, TestEntityDestroyAll) {
   ASSERT_FALSE(b.valid());
 }
 
-
 TEST_F(EntityManagerTest, TestEntityDestroyHole) {
   std::vector<Entity> entities;
 
-  auto count = [this]() -> int {
+  auto count = [this]()->int {
     auto e = em.entities_with_components<Position>();
-    return std::count_if(e.begin(), e.end(), [] (const Entity &) { return true; });
+    return std::count_if(e.begin(), e.end(),
+                         [](const Entity &) { return true; });
   };
 
   for (int i = 0; i < 5000; i++) {
index a4b3e5db9947bd2ef4789853913ecedade63f2b3..d2a2bb28e559491380b5ceda796f57d0cba72dd7 100644 (file)
@@ -124,13 +124,13 @@ class EventManager : entityx::help::NonCopyable {
    *     em.subscribe<Explosion>(receiver);
    */
   template <typename E, typename Receiver>
-  void subscribe(Receiver &receiver) {  //NOLINT
+  void subscribe(Receiver &receiver) {
     void (Receiver::*receive)(const E &) = &Receiver::receive;
     auto sig = signal_for(E::family());
     auto wrapper = EventCallbackWrapper<E>(std::bind(receive, &receiver, std::placeholders::_1));
     auto connection = sig->connect(wrapper);
-    static_cast<BaseReceiver&>(receiver).connections_.push_back(
-      std::make_pair(EventSignalWeakPtr(sig), connection));
+    BaseReceiver &base = receiver;
+    base.connections_.push_back(std::make_pair(EventSignalWeakPtr(sig), connection));
   }
 
   void emit(const BaseEvent &event);
@@ -141,7 +141,8 @@ class EventManager : entityx::help::NonCopyable {
   template <typename E>
   void emit(std::unique_ptr<E> event) {
     auto sig = signal_for(E::family());
-    sig->emit(static_cast<BaseEvent*>(event.get()));
+    BaseEvent *base = event.get();
+    sig->emit(base);
   }
 
   /**
@@ -157,9 +158,10 @@ class EventManager : entityx::help::NonCopyable {
    */
   template <typename E, typename ... Args>
   void emit(Args && ... args) {
-    E event = E(std::forward<Args>(args) ...);
+    E event(std::forward<Args>(args) ...);
     auto sig = signal_for(E::family());
-    sig->emit(static_cast<BaseEvent*>(&event));
+    BaseEvent *base = &event;
+    sig->emit(base);
   }
 
   int connected_receivers() const {
index 362d361c2f09a475e48adc8a86eb20a913723301..1433a0a94b6a8f379e0c14803b63a7e87fcb93ea 100644 (file)
@@ -41,7 +41,6 @@ TEST(EventManagerTest, TestEmitReceive) {
   ASSERT_EQ(10, explosion_system.damage_received);
 }
 
-
 TEST(EventManagerTest, TestUntypedEmitReceive) {
   EventManager em;
   ExplosionSystem explosion_system;
index 16f7372161683efe5658fed501359f17db4277fa..ccb3c310354f778db560e886857d0bf36c7da163 100644 (file)
@@ -14,7 +14,6 @@
 #include "entityx/System.h"
 #include "entityx/quick.h"
 
-
 // using namespace std;
 using namespace entityx;
 using std::string;
@@ -31,15 +30,15 @@ struct Direction : Component<Direction> {
   float x, y;
 };
 
-
 class MovementSystem : public System<MovementSystem> {
  public:
   explicit MovementSystem(string label = "") : label(label) {}
 
   void update(EntityManager &es, EventManager &events, double) override {
-    EntityManager::View entities = es.entities_with_components<Position, Direction>();
-    ComponentPtr<Position> position;
-    ComponentPtr<Direction> direction;
+    EntityManager::View entities =
+        es.entities_with_components<Position, Direction>();
+    Position *position;
+    Direction *direction;
     for (auto entity : entities) {
       entity.unpack<Position, Direction>(position, direction);
       position->x += direction->x;
@@ -50,7 +49,6 @@ class MovementSystem : public System<MovementSystem> {
   string label;
 };
 
-
 class TestContainer : public EntityX {
  public:
   std::vector<Entity> created_entities;
@@ -59,25 +57,19 @@ class TestContainer : public EntityX {
     for (int i = 0; i < 150; ++i) {
       Entity e = entities.create();
       created_entities.push_back(e);
-      if (i % 2 == 0)
-        e.assign<Position>(1, 2);
-      if (i % 3 == 0)
-        e.assign<Direction>(1, 1);
+      if (i % 2 == 0) e.assign<Position>(1, 2);
+      if (i % 3 == 0) e.assign<Direction>(1, 1);
     }
   }
 };
 
-
 class SystemManagerTest : public ::testing::Test {
  protected:
   TestContainer manager;
 
-  virtual void SetUp() override {
-    manager.initialize();
-  }
+  virtual void SetUp() override { manager.initialize(); }
 };
 
-
 TEST_F(SystemManagerTest, TestConstructSystemWithArgs) {
   manager.systems.add<MovementSystem>("movement");
   manager.systems.configure();
@@ -85,14 +77,13 @@ TEST_F(SystemManagerTest, TestConstructSystemWithArgs) {
   ASSERT_EQ("movement", manager.systems.system<MovementSystem>()->label);
 }
 
-
 TEST_F(SystemManagerTest, TestApplySystem) {
   manager.systems.add<MovementSystem>();
   manager.systems.configure();
 
   manager.systems.update<MovementSystem>(0.0);
-  ComponentPtr<Position> position;
-  ComponentPtr<Direction> direction;
+  Position *position;
+  Direction *direction;
   for (auto entity : manager.created_entities) {
     entity.unpack<Position, Direction>(position, direction);
     if (position && direction) {
diff --git a/entityx/help/Pool.cc b/entityx/help/Pool.cc
new file mode 100644 (file)
index 0000000..c710887
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012-2014 Alec Thomas <alec@swapoff.org>
+ * All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.
+ *
+ * Author: Alec Thomas <alec@swapoff.org>
+ */
+
+#include "entityx/help/Pool.h"
+
+namespace entityx {
+
+BasePool::~BasePool() {
+  for (char *ptr : blocks_) {
+    delete[] ptr;
+  }
+}
+
+}  // namespace entityx
diff --git a/entityx/help/Pool.h b/entityx/help/Pool.h
new file mode 100644 (file)
index 0000000..f7b33d5
--- /dev/null
@@ -0,0 +1,89 @@
+#pragma once
+
+/*
+ * Copyright (C) 2012-2014 Alec Thomas <alec@swapoff.org>
+ * All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.
+ *
+ * Author: Alec Thomas <alec@swapoff.org>
+ */
+
+#include <cassert>
+#include <vector>
+
+namespace entityx {
+
+/**
+ * Provides a resizable, semi-contiguous pool of memory for constructing
+ * objects in. Pointers into the pool will be invalided only when the pool is
+ * destroyed.
+ *
+ * The semi-contiguous nature aims to provide cache-friendly iteration.
+ */
+class BasePool {
+ public:
+  explicit BasePool(int element_size, int chunk_size = 8192)
+      : element_size_(element_size), chunk_size_(chunk_size), capacity_(0) {}
+  virtual ~BasePool();
+
+  int size() const { return size_; }
+  int capacity() const { return capacity_; }
+  int chunks() const { return blocks_.size(); }
+
+  /// Ensure at least n elements will fit in the pool.
+  inline void expand(int n) {
+    if (n >= size_) {
+      if (n >= capacity_) reserve(n);
+      size_ = n;
+    }
+  }
+
+  inline void reserve(int n) {
+    while (capacity_ < n) {
+      char *chunk = new char[element_size_ * chunk_size_];
+      blocks_.push_back(chunk);
+      capacity_ += chunk_size_;
+    }
+  }
+
+  inline void *get(int n) {
+    assert(n < size_);
+    return blocks_[n / chunk_size_] + (n % chunk_size_) * element_size_;
+  }
+
+  inline const void *get(int n) const {
+    assert(n < size_);
+    return blocks_[n / chunk_size_] + (n % chunk_size_) * element_size_;
+  }
+
+  virtual void destroy(int n) = 0;
+
+ protected:
+  std::vector<char *> blocks_;
+  int element_size_;
+  int chunk_size_;
+  int size_ = 0;
+  int capacity_;
+};
+
+
+/**
+ * Implementation of BasePool that provides type-"safe" deconstruction of
+ * elements in the pool.
+ */
+template <typename T, int ChunkSize = 8192>
+class Pool : public BasePool {
+ public:
+  Pool() : BasePool(sizeof(T), ChunkSize) {}
+  virtual ~Pool() {}
+
+  virtual void destroy(int n) override {
+    assert(n < size_);
+    T *ptr = static_cast<T*>(get(n));
+    ptr->~T();
+  }
+};
+
+}  // namespace entityx
diff --git a/entityx/help/Pool_test.cc b/entityx/help/Pool_test.cc
new file mode 100644 (file)
index 0000000..c214b3b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012-2014 Alec Thomas <alec@swapoff.org>
+ * All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.
+ *
+ * Author: Alec Thomas <alec@swapoff.org>
+ */
+
+
+#include <gtest/gtest.h>
+#include <vector>
+#include "entityx/help/Pool.h"
+
+struct Position {
+  explicit Position(int *ptr = nullptr) : ptr(ptr) {
+    if (ptr) (*ptr)++;
+  }
+  ~Position() {
+    if (ptr) (*ptr)++;
+  }
+
+  float x, y;
+  int *ptr;
+};
+
+
+TEST(PoolTest, TestPoolReserve) {
+  entityx::Pool<Position, 8> pool;
+  ASSERT_EQ(0, pool.capacity());
+  ASSERT_EQ(0, pool.chunks());
+  pool.reserve(8);
+  ASSERT_EQ(0, pool.size());
+  ASSERT_EQ(8, pool.capacity());
+  ASSERT_EQ(1, pool.chunks());
+  pool.reserve(16);
+  ASSERT_EQ(0, pool.size());
+  ASSERT_EQ(16, pool.capacity());
+  ASSERT_EQ(2, pool.chunks());
+}
+
+TEST(PoolTest, TestPoolPointers) {
+  entityx::Pool<Position, 8> pool;
+  std::vector<char*> ptrs;
+  for (int i = 0; i < 4; i++) {
+    pool.expand(i * 8 + 8);
+    // NOTE: This is an attempt to ensure non-contiguous allocations from
+    // arena allocators.
+    ptrs.push_back(new char[8 * sizeof(Position)]);
+  }
+  char *p0 = static_cast<char*>(pool.get(0));
+  char *p7 = static_cast<char*>(pool.get(7));
+  char *p8 = static_cast<char*>(pool.get(8));
+  char *p16 = static_cast<char*>(pool.get(16));
+  char *p24 = static_cast<char*>(pool.get(24));
+
+  ASSERT_EQ(p0 + 7 * sizeof(Position), p7);
+  ASSERT_NE(p0 + 8 * sizeof(Position), p8);
+  ASSERT_NE(p8 + 8 * sizeof(Position), p16);
+  ASSERT_NE(p16 + 8 * sizeof(Position), p24);
+}
+
+TEST(PoolTest, TestDeconstruct) {
+  entityx::Pool<Position, 8> pool;
+  pool.expand(8);
+
+  void *p0 = pool.get(0);
+
+  int counter = 0;
+  new(p0) Position(&counter);
+  ASSERT_EQ(1, counter);
+  pool.destroy(0);
+  ASSERT_EQ(2, counter);
+}
diff --git a/entityx/quick.h b/entityx/quick.h
new file mode 100644 (file)
index 0000000..d52656b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Alec Thomas <alec@swapoff.org>
+ * All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.
+ *
+ * Author: Alec Thomas <alec@swapoff.org>
+ */
+
+#pragma once
+
+
+#include "entityx/config.h"
+
+
+namespace entityx {
+
+/**
+ * A convenience class for instantiating an EventManager, EntityManager and
+ * SystemManager.
+ */
+class EntityX {
+public:
+  EntityX() : entities(events), systems(entities, events) {}
+
+  EventManager events;
+  EntityManager entities;
+  SystemManager systems;
+};
+
+}  // namespace entityx