diff options
author | 2011-03-11 20:21:58 +0000 | |
---|---|---|
committer | 2011-03-11 20:21:58 +0000 | |
commit | 6dc6fabb8a074fcef35cd9ac409245702f3e386d (patch) | |
tree | 8de6d09c7583f90f352a9e9d38ee4156f1bf2307 | |
parent | 70560bba33ae694031068b245efd2f49caadb341 (diff) | |
download | paludis-6dc6fabb8a074fcef35cd9ac409245702f3e386d.tar.gz paludis-6dc6fabb8a074fcef35cd9ac409245702f3e386d.tar.xz |
Pool
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | paludis/util/files.m4 | 1 | ||||
-rw-r--r-- | paludis/util/pool-impl.hh | 120 | ||||
-rw-r--r-- | paludis/util/pool.cc | 124 | ||||
-rw-r--r-- | paludis/util/pool.hh | 132 | ||||
-rw-r--r-- | paludis/util/pool_TEST.cc | 102 |
6 files changed, 480 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore index d17ef6afb..b71a35942 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 4f4e82382..1a84de7d0 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 000000000..ac40c6516 --- /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 000000000..6ad46fd29 --- /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 000000000..58e919b38 --- /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 000000000..c4b802d68 --- /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; +} + |