summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-08-29 01:21:12 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2015-08-29 01:21:12 +0100
commit15e24ff7021ecb9646a55d11edef96061e846491 (patch)
treeee869562fbaea267dff4bc39c5e9d120f01236b8
parentMove and test lock helpers (diff)
downloadlibadhocutil-15e24ff7021ecb9646a55d11edef96061e846491.tar.bz2
libadhocutil-15e24ff7021ecb9646a55d11edef96061e846491.tar.xz
libadhocutil-15e24ff7021ecb9646a55d11edef96061e846491.zip
Move and test lazy pointer
-rw-r--r--libadhocutil/lazyPointer.h126
-rw-r--r--libadhocutil/unittests/Jamfile.jam10
-rw-r--r--libadhocutil/unittests/testLazyPointer.cpp77
3 files changed, 213 insertions, 0 deletions
diff --git a/libadhocutil/lazyPointer.h b/libadhocutil/lazyPointer.h
new file mode 100644
index 0000000..23058c7
--- /dev/null
+++ b/libadhocutil/lazyPointer.h
@@ -0,0 +1,126 @@
+#ifndef LIBADHOC_LAZYPOINTER_H
+#define LIBADHOC_LAZYPOINTER_H
+
+#include <boost/function.hpp>
+#include <boost/variant.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+template <typename T, typename P = boost::intrusive_ptr<T>>
+class LazyPointer {
+ public:
+ typedef T element_type;
+ typedef P pointer_type;
+ typedef boost::function0<P> Factory;
+ typedef boost::variant<P, Factory> Source;
+
+ // Constructors
+ LazyPointer(const Factory & f) :
+ source(f)
+ {
+ }
+
+ LazyPointer(const P & p) :
+ source(p)
+ {
+ }
+
+ LazyPointer(T * p) :
+ source(P(p))
+ {
+ }
+
+ LazyPointer() :
+ source(P(NULL))
+ {
+ }
+
+ // Getters
+ operator P() const
+ {
+ return deref();
+ }
+
+ T * operator->() const
+ {
+ return get();
+ }
+
+ T & operator*() const
+ {
+ return *get();
+ }
+
+ T * get() const
+ {
+ return deref().get();
+ }
+
+ P deref() const
+ {
+ if (Factory * f = boost::get<Factory>(&source)) {
+ P p = (*f)();
+ source = p;
+ return p;
+ }
+ else {
+ return boost::get<P>(source);
+ }
+ }
+
+ bool operator!() const
+ {
+ return get() == nullptr;
+ }
+
+ operator bool() const
+ {
+ return get() != nullptr;
+ }
+
+ bool operator==(const P & o) const
+ {
+ return (deref() == o);
+ }
+
+ bool operator==(const T * o) const
+ {
+ return (deref().get() == o);
+ }
+
+ // Setters
+ LazyPointer<T, P> & operator=(const P & p)
+ {
+ source = p;
+ return *this;
+ }
+
+ LazyPointer<T, P> & operator=(T * t)
+ {
+ source = P(t);
+ return *this;
+ }
+
+ LazyPointer<T, P> & operator=(const Factory & f)
+ {
+ source = f;
+ return *this;
+ }
+
+ bool hasValue() const
+ {
+ return boost::get<P>(&source);
+ }
+
+ private:
+ mutable Source source;
+};
+
+namespace boost {
+ template <typename R, typename T, typename P>
+ R * dynamic_pointer_cast(const LazyPointer<T, P> & p) {
+ return dynamic_cast<R *>(p.get());
+ }
+}
+
+#endif
+
diff --git a/libadhocutil/unittests/Jamfile.jam b/libadhocutil/unittests/Jamfile.jam
index e26825a..4a6b430 100644
--- a/libadhocutil/unittests/Jamfile.jam
+++ b/libadhocutil/unittests/Jamfile.jam
@@ -86,3 +86,13 @@ run
testLocks
;
+run
+ testLazyPointer.cpp
+ : : :
+ <define>BOOST_TEST_DYN_LINK
+ <library>..//adhocutil
+ <library>boost_utf
+ :
+ testLazyPointer
+ ;
+
diff --git a/libadhocutil/unittests/testLazyPointer.cpp b/libadhocutil/unittests/testLazyPointer.cpp
new file mode 100644
index 0000000..6c4ddcd
--- /dev/null
+++ b/libadhocutil/unittests/testLazyPointer.cpp
@@ -0,0 +1,77 @@
+#define BOOST_TEST_MODULE LazyPointer
+#include <boost/test/unit_test.hpp>
+
+#include <boost/bind.hpp>
+#include "intrusivePtrBase.h"
+#include "lazyPointer.h"
+
+class Test : public IntrusivePtrBase {
+ public:
+ Test(int v) :
+ val(v)
+ {
+ }
+ const int val;
+};
+
+typedef LazyPointer<Test> TestLazyPointer;
+
+static
+TestLazyPointer::pointer_type
+factory()
+{
+ return new Test(3);
+}
+
+static
+TestLazyPointer::pointer_type
+paramFactory(const std::string & str)
+{
+ return new Test(str.length());
+}
+
+BOOST_AUTO_TEST_CASE ( islazy )
+{
+ TestLazyPointer p(boost::bind(&factory));
+ BOOST_REQUIRE_EQUAL(false, p.hasValue());
+ Test * t = p.get();
+ BOOST_REQUIRE(t);
+ BOOST_REQUIRE_EQUAL(true, p.hasValue());
+ BOOST_REQUIRE_EQUAL(p, t);
+ BOOST_REQUIRE_EQUAL(3, t->val);
+ BOOST_REQUIRE_EQUAL(3, p->val);
+}
+
+BOOST_AUTO_TEST_CASE ( preinit )
+{
+ Test * t = new Test(4);
+ TestLazyPointer p(t);
+ BOOST_REQUIRE_EQUAL(true, p.hasValue());
+ BOOST_REQUIRE_EQUAL(p, t);
+ BOOST_REQUIRE_EQUAL(4, p->val);
+}
+
+BOOST_AUTO_TEST_CASE ( reset )
+{
+ Test * t = new Test(4);
+ TestLazyPointer p(t);
+ BOOST_REQUIRE_EQUAL(true, p.hasValue());
+ BOOST_REQUIRE_EQUAL(4, p->val);
+ p = nullptr;
+ BOOST_REQUIRE_EQUAL(true, p.hasValue());
+ BOOST_REQUIRE_EQUAL(true, !p);
+ p = boost::bind(&factory);
+ BOOST_REQUIRE_EQUAL(false, p.hasValue());
+ p.get();
+ BOOST_REQUIRE_EQUAL(true, p.hasValue());
+ BOOST_REQUIRE_EQUAL(3, p->val);
+}
+
+BOOST_AUTO_TEST_CASE ( nondefault )
+{
+ TestLazyPointer p(boost::bind(&paramFactory, "some string"));
+ BOOST_REQUIRE_EQUAL(false, p.hasValue());
+ BOOST_REQUIRE_EQUAL(11, (*p).val);
+ BOOST_REQUIRE_EQUAL(true, p.hasValue());
+}
+