aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2011-03-11 20:21:58 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2011-03-11 20:21:58 +0000
commit6dc6fabb8a074fcef35cd9ac409245702f3e386d (patch)
tree8de6d09c7583f90f352a9e9d38ee4156f1bf2307
parent70560bba33ae694031068b245efd2f49caadb341 (diff)
downloadpaludis-6dc6fabb8a074fcef35cd9ac409245702f3e386d.tar.gz
paludis-6dc6fabb8a074fcef35cd9ac409245702f3e386d.tar.xz
Pool
-rw-r--r--.gitignore1
-rw-r--r--paludis/util/files.m41
-rw-r--r--paludis/util/pool-impl.hh120
-rw-r--r--paludis/util/pool.cc124
-rw-r--r--paludis/util/pool.hh132
-rw-r--r--paludis/util/pool_TEST.cc102
6 files changed, 480 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index d17ef6a..b71a359 100644
--- a/.gitignore
+++ b/.gitignore
@@ -455,6 +455,7 @@ paludis-*.*.*.tar.bz2
/paludis/util/mutex_TEST
/paludis/util/options_TEST
/paludis/util/outputwrapper
+/paludis/util/pool_TEST
/paludis/util/pretty_print_TEST
/paludis/util/process_TEST
/paludis/util/pty_TEST
diff --git a/paludis/util/files.m4 b/paludis/util/files.m4
index 4f4e823..1a84de7 100644
--- a/paludis/util/files.m4
+++ b/paludis/util/files.m4
@@ -60,6 +60,7 @@ add(`operators', `hh')
add(`options', `hh', `fwd', `cc', `test')
add(`pimp', `hh', `impl')
add(`pipe', `hh', `cc')
+add(`pool', `hh', `cc', `impl', `test')
add(`pretty_print', `hh', `cc', `test')
add(`process', `hh', `cc', `fwd', `test', `testscript')
add(`pty', `hh', `cc', `test')
diff --git a/paludis/util/pool-impl.hh b/paludis/util/pool-impl.hh
new file mode 100644
index 0000000..ac40c65
--- /dev/null
+++ b/paludis/util/pool-impl.hh
@@ -0,0 +1,120 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2011 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis 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
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_POOL_IMPL_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_POOL_IMPL_HH 1
+
+#include <paludis/util/pool.hh>
+#include <paludis/util/mutex.hh>
+#include <paludis/util/hashes.hh>
+#include <unordered_map>
+#include <memory>
+
+namespace paludis
+{
+ template <typename Arg_, typename... Args_>
+ void
+ PoolKeys::add(const Arg_ & arg, const Args_ & ... args)
+ {
+ add_one(std::make_shared<ConcretePoolKey<Arg_> >(arg));
+ add(args...);
+ }
+
+ template <typename T_>
+ struct Imp<Pool<T_> >
+ {
+ mutable Mutex mutex;
+ mutable std::unordered_map<PoolKeys, std::shared_ptr<const T_>, PoolKeysHasher, PoolKeysComparator> store;
+ };
+
+ template <typename T_>
+ Pool<T_>::Pool() :
+ _imp()
+ {
+ }
+
+ template <typename T_>
+ Pool<T_>::~Pool() = default;
+
+ template <typename T_>
+ struct PreventConversion
+ {
+ const T_ & ref;
+
+ PreventConversion(const T_ & r) :
+ ref(r)
+ {
+ }
+
+ operator const T_ & ()
+ {
+ return ref;
+ }
+ };
+
+ template <typename T_>
+ template <typename... Args_>
+ const std::shared_ptr<const T_>
+ Pool<T_>::create(Args_ ... args) const
+ {
+ PoolKeys keys;
+ keys.add(args...);
+
+ Lock lock(_imp->mutex);
+ auto i(_imp->store.find(keys));
+ if (i == _imp->store.end())
+ i = _imp->store.insert(std::make_pair(keys, std::make_shared<const T_>(PreventConversion<Args_>(args)...))).first;
+
+ return i->second;
+ }
+
+ template <typename T_>
+ ConcretePoolKey<T_>::ConcretePoolKey(const T_ & t) :
+ PoolKey(PoolKeyTypeCodes::get<T_>()),
+ _value(t)
+ {
+ }
+
+ template <typename T_>
+ ConcretePoolKey<T_>::~ConcretePoolKey() = default;
+
+ template <typename T_>
+ std::size_t
+ ConcretePoolKey<T_>::hash() const
+ {
+ return Hash<T_>()(_value);
+ }
+
+ template <typename T_>
+ bool
+ ConcretePoolKey<T_>::same_value(const PoolKey & other) const
+ {
+ return _value == static_cast<const ConcretePoolKey<T_> &>(other)._value;
+ }
+
+ template <typename T_>
+ int
+ PoolKeyTypeCodes::get()
+ {
+ static int result(next());
+ return result;
+ }
+}
+
+#endif
diff --git a/paludis/util/pool.cc b/paludis/util/pool.cc
new file mode 100644
index 0000000..6ad46fd
--- /dev/null
+++ b/paludis/util/pool.cc
@@ -0,0 +1,124 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2011 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis 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
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/pool-impl.hh>
+#include <paludis/util/pimp-impl.hh>
+#include <paludis/util/mutex.hh>
+#include <list>
+#include <memory>
+
+using namespace paludis;
+
+typedef std::list<std::shared_ptr<const PoolKey> > PoolKeyList;
+
+namespace paludis
+{
+ template <>
+ struct Imp<PoolKeys>
+ {
+ std::shared_ptr<PoolKeyList> values;
+
+ Imp() :
+ values(std::make_shared<PoolKeyList>())
+ {
+ }
+
+ Imp(const std::shared_ptr<PoolKeyList> & v) :
+ values(v)
+ {
+ }
+ };
+}
+
+PoolKeys::PoolKeys() :
+ _imp()
+{
+}
+
+PoolKeys::PoolKeys(const PoolKeys & other) :
+ _imp(other._imp->values)
+{
+}
+
+PoolKeys::~PoolKeys() = default;
+
+void
+PoolKeys::add()
+{
+}
+
+void
+PoolKeys::add_one(const std::shared_ptr<const PoolKey> & k)
+{
+ _imp->values->push_back(k);
+}
+
+PoolKey::PoolKey(int tc) :
+ _tc(tc)
+{
+}
+
+PoolKey::~PoolKey() = default;
+
+bool
+PoolKey::same_type_and_value(const PoolKey & other) const
+{
+ return _tc == other._tc && same_value(other);
+}
+
+std::size_t
+PoolKeysHasher::operator() (const PoolKeys & keys) const
+{
+ std::size_t result(0);
+
+ for (auto i(keys._imp->values->begin()), i_end(keys._imp->values->end()) ;
+ i != i_end ; ++i)
+ {
+ result <<= 4;
+ result ^= (*i)->hash();
+ }
+
+ return result;
+}
+
+bool
+PoolKeysComparator::operator() (const PoolKeys & a, const PoolKeys & b) const
+{
+ for (auto i(a._imp->values->begin()), j(b._imp->values->begin()), i_end(a._imp->values->end()), j_end(b._imp->values->end()) ;
+ (i != i_end || j != j_end) ; ++i, ++j)
+ {
+ if (i == i_end || j == j_end || ! (*i)->same_type_and_value(**j))
+ return false;
+ }
+
+ return true;
+}
+
+int
+PoolKeyTypeCodes::next()
+{
+ static Mutex mutex;
+ static int result(0);
+
+ Lock lock(mutex);
+ return ++result;
+}
+
+template class Pimp<PoolKeys>;
+
diff --git a/paludis/util/pool.hh b/paludis/util/pool.hh
new file mode 100644
index 0000000..58e919b
--- /dev/null
+++ b/paludis/util/pool.hh
@@ -0,0 +1,132 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2011 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis 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
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_POOL_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_POOL_HH 1
+
+#include <paludis/util/singleton.hh>
+#include <paludis/util/pimp.hh>
+#include <memory>
+
+namespace paludis
+{
+ class PoolKeysHasher;
+ class PoolKeysComparator;
+
+ template <typename T_>
+ class PALUDIS_VISIBLE Pool :
+ public Singleton<Pool<T_> >
+ {
+ friend class Singleton<Pool<T_> >;
+
+ private:
+ Pimp<Pool<T_> > _imp;
+
+ Pool();
+ ~Pool();
+
+ public:
+ template <typename... Args_>
+ const std::shared_ptr<const T_> create(Args_ ...) const PALUDIS_ATTRIBUTE((warn_unused_result));
+ };
+
+ class PALUDIS_VISIBLE PoolKey
+ {
+ private:
+ int _tc;
+
+ protected:
+ explicit PoolKey(int tc);
+
+ virtual bool same_value(const PoolKey &) const = 0;
+
+ public:
+ virtual ~PoolKey() = 0;
+
+ virtual std::size_t hash() const = 0;
+
+ bool same_type_and_value(const PoolKey &) const;
+ };
+
+ template <typename T_>
+ class PALUDIS_VISIBLE ConcretePoolKey :
+ public PoolKey
+ {
+ friend class PoolKeysHasher;
+ friend class PoolKeysComparator;
+
+ private:
+ T_ _value;
+
+ public:
+ explicit ConcretePoolKey(const T_ &);
+
+ virtual ~ConcretePoolKey();
+
+ virtual std::size_t hash() const;
+
+ bool same_value(const PoolKey &) const;
+ };
+
+ class PALUDIS_VISIBLE PoolKeys
+ {
+ friend class PoolKeysHasher;
+ friend class PoolKeysComparator;
+
+ private:
+ Pimp<PoolKeys> _imp;
+
+ void add_one(const std::shared_ptr<const PoolKey> &);
+ void add();
+
+ public:
+ PoolKeys();
+ PoolKeys(const PoolKeys &);
+ ~PoolKeys();
+
+ template <typename Arg_, typename... Args_>
+ void add(const Arg_ &, const Args_ & ...);
+ };
+
+ class PALUDIS_VISIBLE PoolKeysHasher
+ {
+ public:
+ std::size_t operator() (const PoolKeys &) const PALUDIS_VISIBLE;
+ };
+
+ class PALUDIS_VISIBLE PoolKeysComparator
+ {
+ public:
+ bool operator() (const PoolKeys &, const PoolKeys &) const PALUDIS_VISIBLE;
+ };
+
+ class PALUDIS_VISIBLE PoolKeyTypeCodes
+ {
+ private:
+ static int next();
+
+ public:
+ template <typename T_>
+ static int get();
+ };
+
+ extern template class Pimp<PoolKeys>;
+}
+
+#endif
diff --git a/paludis/util/pool_TEST.cc b/paludis/util/pool_TEST.cc
new file mode 100644
index 0000000..c4b802d
--- /dev/null
+++ b/paludis/util/pool_TEST.cc
@@ -0,0 +1,102 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2011 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis 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
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/pool-impl.hh>
+#include <paludis/util/singleton-impl.hh>
+#include <paludis/util/pimp-impl.hh>
+#include <test/test_runner.hh>
+#include <test/test_framework.hh>
+
+using namespace paludis;
+using namespace test;
+
+namespace
+{
+ struct Monkey
+ {
+ std::string name;
+
+ explicit Monkey(const std::string & n) :
+ name(n)
+ {
+ }
+ };
+
+ struct Weasel
+ {
+ std::string name;
+ int viciousness;
+
+ explicit Weasel(const std::string & n, int v) :
+ name(n),
+ viciousness(v)
+ {
+ }
+ };
+}
+
+namespace test_cases
+{
+ struct PoolMonkeyTest : TestCase
+ {
+ PoolMonkeyTest() : TestCase("pool monkey test") { }
+
+ void run()
+ {
+ auto a(Pool<Monkey>::get_instance()->create(std::string("alexander")));
+ auto b(Pool<Monkey>::get_instance()->create(std::string("gunther")));
+ auto c(Pool<Monkey>::get_instance()->create(std::string("alexander")));
+
+ TEST_CHECK(a->name == "alexander");
+ TEST_CHECK(b->name == "gunther");
+ TEST_CHECK(c->name == "alexander");
+
+ TEST_CHECK(a == c);
+ }
+ } test_pool_monkey;
+
+ struct PoolWeaselTest : TestCase
+ {
+ PoolWeaselTest() : TestCase("pool weasel test") { }
+
+ void run()
+ {
+ auto a(Pool<Weasel>::get_instance()->create(std::string("william"), 8));
+ auto b(Pool<Weasel>::get_instance()->create(std::string("tony"), 5));
+ auto c(Pool<Weasel>::get_instance()->create(std::string("william"), 8));
+ auto d(Pool<Weasel>::get_instance()->create(std::string("tony"), 10));
+
+ TEST_CHECK(a->name == "william");
+ TEST_CHECK(a->viciousness == 8);
+
+ TEST_CHECK(b->name == "tony");
+ TEST_CHECK(b->viciousness == 5);
+
+ TEST_CHECK(c->name == "william");
+ TEST_CHECK(c->viciousness == 8);
+
+ TEST_CHECK(d->name == "tony");
+ TEST_CHECK(d->viciousness == 10);
+
+ TEST_CHECK(a == c);
+ TEST_CHECK(b != d);
+ }
+ } test_pool_weasel;
+}
+