diff --git a/Makefile.am b/Makefile.am
index de292f44..e21b97d0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -21,6 +21,7 @@ UTIL_INCLUDE = \
point.hpp \
range.hpp \
region.hpp \
+ signal.hpp \
stream.hpp \
types.hpp \
vector.hpp \
@@ -38,6 +39,7 @@ UTIL_FILES = \
point.cpp \
range.cpp \
region.cpp \
+ signal.cpp \
stream.cpp \
types.cpp \
vector.cpp \
diff --git a/signal.cpp b/signal.cpp
new file mode 100644
index 00000000..d9e293b4
--- /dev/null
+++ b/signal.cpp
@@ -0,0 +1,22 @@
+/*
+ * 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 2011 Danny Robson
+ */
+
+
+#include "signal.hpp"
+
diff --git a/signal.hpp b/signal.hpp
new file mode 100644
index 00000000..b6a480e9
--- /dev/null
+++ b/signal.hpp
@@ -0,0 +1,70 @@
+/*
+ * 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 2011 Danny Robson
+ */
+
+#ifndef __SIGNAL_HPP
+#define __SIGNAL_HPP
+
+#include
+#include
+#include
+
+
+template
+class signal {
+ public:
+ typedef Ret (*callback_function)(Args...);
+ typedef std::function callback_object;
+
+ protected:
+ std::vector m_children;
+
+ public:
+ signal ()
+ { m_children.reserve (16); }
+
+ /// Add a callback to list.
+ void connect (callback_object _cb)
+ { m_children.push_back (_cb); }
+ void connect (callback_function _cb)
+ { m_children.push_back (_cb); }
+
+ /// Remove all instances of callback `cb'
+ void disconnect (callback_function _cb)
+ { disconnect (callback_object (_cb)); }
+
+ /// Remove all instances of callback `cb'
+ void disconnect (callback_object _cb) {
+ m_children.erase (std::remove (m_children.begin (),
+ m_children.end (),
+ _cb),
+ m_children.end ());
+ }
+
+ /// Remove all callbacks
+ void clear (void)
+ { m_children.clear (); }
+
+ /// Execute all callbacks. Does not combine results.
+ void operator () (Args&... tail) {
+ for (auto i = m_children.begin (), end = m_children.end (); i != end; ++i)
+ (*i)(tail...);
+ }
+};
+
+#endif // __SIGNAL_HPP
diff --git a/test/.gitignore b/test/.gitignore
index 5407c90c..a82d7fb0 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -6,4 +6,5 @@
/maths
/matrix
/range
+/signal
/version
diff --git a/test/Makefile.am b/test/Makefile.am
index d3887ac0..efccdd5b 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -7,35 +7,48 @@ AM_CPPFLAGS = \
AM_LDFLAGS = $(COMMON_LDFLAGS)
-TEST_BIN = backtrace float range maths matrix version ip hton
+TEST_BIN = \
+ backtrace \
+ float \
+ hton \
+ ip \
+ maths \
+ matrix \
+ range \
+ signal \
+ version
+
TESTS = $(TEST_BIN) json.pl
check_PROGRAMS = $(TEST_BIN) json-check
EXTRA_DIST = json.pl
-backtrace_SOURCES = backtrace.cpp
backtrace_CPPFLAGS = $(COMMON_CXXFLAGS)
-backtrace_LDADD = $(builddir)/../libutil.la $(BOOST_SYSTEM_LIB)
+backtrace_LDADD = $(builddir)/../libutil.la
+backtrace_SOURCES = backtrace.cpp
+float_LDADD = $(builddir)/../libutil.la
float_SOURCES = float.cpp
-float_LDADD = $(builddir)/../libutil.la $(BOOST_SYSTEM_LIB)
-
-range_SOURCES = range.cpp
-range_LDADD = $(builddir)/../libutil.la $(BOOST_SYSTEM_LIB)
-
-maths_SOURCES = maths.cpp
-maths_LDADD = $(builddir)/../libutil.la $(BOOST_SYSTEM_LIB)
-
-matrix_SOURCES = matrix.cpp
-matrix_LDADD = $(builddir)/../libutil.la $(BOOST_SYSTEM_LIB)
-
-version_SOURCES = version.cpp
-version_LDADD = $(builddir)/../libutil.la $(BOOST_SYSTEM_LIB)
-
-ip_SOURCES = ip.cpp
-ip_LDADD = $(builddir)/../libutil.la $(BOOST_SYSTEM_LIB)
+hton_LDADD = $(builddir)/../libutil.la
hton_SOURCES = hton.cpp
-hton_LDADD = $(builddir)/../libutil.la $(BOOST_SYSTEM_LIB)
-json_check_SOURCES = json-check.cpp
+ip_LDADD = $(builddir)/../libutil.la
+ip_SOURCES = ip.cpp
+
json_check_LDADD = $(builddir)/../libutil.la $(BOOST_FILESYSTEM_LIB)
+json_check_SOURCES = json-check.cpp
+
+maths_LDADD = $(builddir)/../libutil.la
+maths_SOURCES = maths.cpp
+
+matrix_LDADD = $(builddir)/../libutil.la
+matrix_SOURCES = matrix.cpp
+
+range_LDADD = $(builddir)/../libutil.la
+range_SOURCES = range.cpp
+
+signal_LDADD = $(builddir)/../libutil.la
+signal_SOURCES = signal.cpp
+
+version_LDADD = $(builddir)/../libutil.la
+version_SOURCES = version.cpp
diff --git a/test/signal.cpp b/test/signal.cpp
new file mode 100644
index 00000000..89fa04b7
--- /dev/null
+++ b/test/signal.cpp
@@ -0,0 +1,50 @@
+#include
+
+#include "../signal.hpp"
+#include "../debug.hpp"
+
+void
+increment_uint (unsigned int &val)
+ { ++val; }
+
+
+void
+test_null (void) {
+ signal void_signal;
+ void_signal ();
+}
+
+
+void
+test_single (void) {
+ unsigned int val = 0;
+ signal void_signal;
+
+ void_signal.connect (increment_uint);
+ void_signal (val);
+
+ check_eq (val, 1);
+}
+
+
+void
+test_double (void) {
+ unsigned int val = 0;
+ signal void_signal;
+
+ void_signal.connect (increment_uint);
+ void_signal.connect (increment_uint);
+ void_signal (val);
+
+ check_eq (val, 2);
+}
+
+
+int
+main (int, char **) {
+ test_null ();
+ test_single ();
+ test_double ();
+
+ return EXIT_SUCCESS;
+}