diff --git a/Makefile.am b/Makefile.am
index e21b97d0..6050a553 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,6 +19,7 @@ UTIL_INCLUDE = \
matrix.hpp \
nocopy.hpp \
point.hpp \
+ pool.hpp \
range.hpp \
region.hpp \
signal.hpp \
@@ -37,6 +38,7 @@ UTIL_FILES = \
maths.cpp \
matrix.cpp \
point.cpp \
+ pool.cpp \
range.cpp \
region.cpp \
signal.cpp \
diff --git a/pool.cpp b/pool.cpp
new file mode 100644
index 00000000..faaeb10b
--- /dev/null
+++ b/pool.cpp
@@ -0,0 +1,25 @@
+/*
+ * This file is part of libgim.
+ *
+ * libgim is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * libgim is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libgim. If not, see .
+ *
+ * Copyright 2010 Danny Robson
+ */
+
+
+#include "pool.hpp"
+
+
+// Explicitly instance a possibly useful specialisation so that we can more easily catch linker errors.
+template class pool;
diff --git a/pool.hpp b/pool.hpp
new file mode 100644
index 00000000..491b80f2
--- /dev/null
+++ b/pool.hpp
@@ -0,0 +1,99 @@
+/*
+ * This file is part of libgim.
+ *
+ * libgim is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * libgim is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libgim. If not, see .
+ *
+ * Copyright 2010 Danny Robson
+ */
+
+#ifndef __UTIL_POOL_HPP
+#define __UTIL_POOL_HPP
+
+#include "nocopy.hpp"
+
+
+template
+class pool : public nocopy {
+ protected:
+ union node {
+ char _data[sizeof (T)];
+ node *_chain;
+ };
+
+ node *m_head;
+ node *m_next;
+ unsigned int m_capacity;
+
+ public:
+ pool (unsigned int _capacity):
+ m_capacity (_capacity)
+ {
+ static_assert (sizeof (T) >= sizeof (uintptr_t),
+ "pool's chained block system requires that T be at least pointer sized");
+
+ m_head = (node *)operator new (sizeof (T) * m_capacity);
+ m_next = m_head;
+
+ for (unsigned int i = 0; i < m_capacity - 1; ++i)
+ m_next[i]._chain = &m_next[i + 1];
+ m_next[m_capacity - 1]._chain = NULL;
+ }
+
+
+ ~pool () {
+ check (m_next != NULL);
+
+ unsigned int doomed_count = 0;
+ for (node *cursor = m_next; cursor != NULL; cursor = cursor->_chain)
+ ++doomed_count;
+
+ check_eq (doomed_count, m_capacity);
+ operator delete (m_head);
+ }
+
+
+ unsigned int capacity (void) const
+ { return m_capacity; }
+
+
+ template
+ T* acquire (Args&... args) {
+ if (!m_next)
+ throw std::bad_alloc ();
+
+ node *newnext = m_next->_chain;
+ T *data = (T*)&m_next->_data;
+
+ try {
+ new (data) T (args...);
+ } catch (...) {
+ m_next->_chain = newnext;
+ throw;
+ }
+
+ m_next = newnext;
+ return data;
+ }
+
+
+ void release (T *data) {
+ node *newnode = (node *)data;
+
+ newnode->_chain = m_next;
+ m_next = newnode;
+ }
+};
+
+
+#endif // __UTIL_POOL_HPP
diff --git a/test/.gitignore b/test/.gitignore
index a82d7fb0..82caddcb 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -5,6 +5,7 @@
/json-check
/maths
/matrix
+/pool
/range
/signal
/version
diff --git a/test/Makefile.am b/test/Makefile.am
index efccdd5b..f9b97c77 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -14,6 +14,7 @@ TEST_BIN = \
ip \
maths \
matrix \
+ pool \
range \
signal \
version
@@ -44,6 +45,9 @@ maths_SOURCES = maths.cpp
matrix_LDADD = $(builddir)/../libutil.la
matrix_SOURCES = matrix.cpp
+pool_LDADD = $(builddir)/../libutil.la
+pool_SOURCES = pool.cpp
+
range_LDADD = $(builddir)/../libutil.la
range_SOURCES = range.cpp
diff --git a/test/pool.cpp b/test/pool.cpp
new file mode 100644
index 00000000..ab9ed577
--- /dev/null
+++ b/test/pool.cpp
@@ -0,0 +1,86 @@
+
+#include "debug.hpp"
+#include "pool.hpp"
+
+#include
+#include
+#include
+
+using namespace std;
+
+
+void
+check_single (void) {
+ // Ensure a single element doesn't break the circular linked list
+ pool single(1);
+ single.release (single.acquire ());
+}
+
+
+void
+check_unique_ptr (void) {
+ pool uintpool (1025);
+ set uintset;
+
+ // Take all pointers out, checking they are unique, then replace for destruction.
+ for (unsigned int i = 0; i < uintpool.capacity (); ++i) {
+ bool success = uintset.insert (uintpool.acquire ()).second;
+ check_hard (success);
+ }
+
+ for (auto i = uintset.begin (); i != uintset.end (); ++i)
+ uintpool.release (*i);
+ uintset.clear ();
+
+ // Do the above one more time to ensure that releasing works right
+ for (unsigned int i = 0; i < uintpool.capacity (); ++i) {
+ bool success = uintset.insert (uintpool.acquire ()).second;
+ check_hard (success);
+ }
+
+ for (auto i = uintset.begin (); i != uintset.end (); ++i)
+ uintpool.release (*i);
+}
+
+
+void
+check_keep_value (void) {
+ // Ensure that items keep their values.
+ pool uintpool(256);
+ std::vector uintvector;
+ uintvector.reserve(uintpool.capacity ());
+
+ // Give every item a unique value
+ for (unsigned int i = 0; i < uintpool.capacity (); ++i) {
+ uint64_t *uint = uintpool.acquire ();
+ *uint = i;
+
+ uintvector.push_back(uint);
+ }
+ check (uintvector.size () == uintpool.capacity ());
+
+ // Ensure they're all still present
+ vector present(uintpool.capacity (), false);
+ for (auto i = uintvector.begin (); i != uintvector.end (); ++i) {
+ check_hard (**i < uintpool.capacity ());
+ check_hard (present[**i] != true);
+
+ present[**i] = true;
+ }
+
+ // All must have been marked as present...
+ check_hard (find (present.begin (), present.end (), false) == present.end ());
+
+ // Release all back into the pool for destruction
+ for (auto i = uintvector.begin (); i != uintvector.end (); ++i)
+ uintpool.release (*i);
+ uintvector.clear ();
+}
+
+
+int
+main (int argc, char **argv) {
+ check_single ();
+ check_unique_ptr ();
+ check_keep_value ();
+}