aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-09-09 21:35:42 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-09-09 21:35:42 +0000
commit0a11ed5d1a5b79eaa676fe5aa21dd0b4dcd05ad8 (patch)
treed4d2a0725498686c4d4c4632e671617ebda315f2
parent908f3e12eef5eb200a01fde58b7578672f9b6bef (diff)
downloadpaludis-0a11ed5d1a5b79eaa676fe5aa21dd0b4dcd05ad8.tar.gz
paludis-0a11ed5d1a5b79eaa676fe5aa21dd0b4dcd05ad8.tar.xz
Extend singleton capabilities
-rw-r--r--paludis/util/instantiation_policy.hh58
-rw-r--r--paludis/util/instantiation_policy_TEST.cc55
2 files changed, 110 insertions, 3 deletions
diff --git a/paludis/util/instantiation_policy.hh b/paludis/util/instantiation_policy.hh
index 7c0d8be..060b2df 100644
--- a/paludis/util/instantiation_policy.hh
+++ b/paludis/util/instantiation_policy.hh
@@ -201,7 +201,33 @@ namespace paludis
const InstantiationPolicy & operator= (const InstantiationPolicy &);
- static OurType_ * _instance;
+ static OurType_ * * _get_instance_ptr();
+
+ class DeleteOnDestruction;
+ friend class DeleteOnDestruction;
+
+ static void _delete(OurType_ * const p)
+ {
+ delete p;
+ }
+
+ class DeleteOnDestruction
+ {
+ private:
+ OurType_ * * const _ptr;
+
+ public:
+ DeleteOnDestruction(OurType_ * * const p) :
+ _ptr(p)
+ {
+ }
+
+ ~DeleteOnDestruction()
+ {
+ InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>::_delete(* _ptr);
+ * _ptr = 0;
+ }
+ };
protected:
///\name Basic operations
@@ -222,15 +248,41 @@ namespace paludis
*/
static OurType_ * get_instance();
+ /**
+ * Destroy our instance.
+ */
+ static void destroy_instance();
+
///\}
};
template<typename OurType_>
+ OurType_ * *
+ InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>::_get_instance_ptr()
+ {
+ static OurType_ * instance(0);
+ static DeleteOnDestruction delete_instance(&instance);
+
+ return &instance;
+ }
+
+ template<typename OurType_>
OurType_ *
InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>::get_instance()
{
- static OurType_ instance;
- return &instance;
+ OurType_ * * i(_get_instance_ptr());
+ if (0 == *i)
+ *i = new OurType_;
+ return *i;
+ }
+
+ template<typename OurType_>
+ void
+ InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>::destroy_instance()
+ {
+ OurType_ * * i(_get_instance_ptr());
+ delete *i;
+ *i = 0;
}
}
diff --git a/paludis/util/instantiation_policy_TEST.cc b/paludis/util/instantiation_policy_TEST.cc
index d5ac52b..6c8aa34 100644
--- a/paludis/util/instantiation_policy_TEST.cc
+++ b/paludis/util/instantiation_policy_TEST.cc
@@ -57,6 +57,30 @@ namespace
int MyClass::instances = 0;
+ class MyClassTwo :
+ public InstantiationPolicy<MyClassTwo, instantiation_method::SingletonAsNeededTag>
+ {
+ friend class InstantiationPolicy<MyClassTwo, instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ MyClassTwo()
+ {
+ ++instances;
+ }
+
+ ~MyClassTwo()
+ {
+ --instances;
+ }
+
+ public:
+ std::string s;
+
+ static int instances;
+ };
+
+ int MyClassTwo::instances = 0;
+
struct MyLoadAtStartupClass :
public InstantiationPolicy<MyLoadAtStartupClass, instantiation_method::SingletonAtStartupTag>
{
@@ -106,6 +130,37 @@ namespace test_cases
} test_singleton_pattern;
/**
+ * \test Test singleton behaviour.
+ *
+ * \ingroup grptestcases
+ */
+ struct SingletonPatternDeleteTest : TestCase
+ {
+ SingletonPatternDeleteTest() : TestCase("singleton delete test") { }
+
+ bool repeatable() const
+ {
+ return false;
+ }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(MyClassTwo::instances, 0);
+ TEST_CHECK(0 != MyClassTwo::get_instance());
+ TEST_CHECK_EQUAL(MyClassTwo::instances, 1);
+ TEST_CHECK(MyClassTwo::get_instance() == MyClassTwo::get_instance());
+ TEST_CHECK(MyClassTwo::get_instance()->s.empty());
+ MyClassTwo::get_instance()->s = "foo";
+ TEST_CHECK_EQUAL(MyClassTwo::get_instance()->s, "foo");
+ MyClassTwo::destroy_instance();
+ TEST_CHECK_EQUAL(MyClassTwo::instances, 0);
+ TEST_CHECK(0 != MyClassTwo::get_instance());
+ TEST_CHECK_EQUAL(MyClassTwo::instances, 1);
+ TEST_CHECK(MyClassTwo::get_instance()->s.empty());
+ }
+ } test_singleton_pattern_delete;
+
+ /**
* \test Test singleton create at startup behaviour.
*
* \ingroup grptestcases