#if defined _MSC_VER && _MSC_VER >= 1700L || (defined(__cplusplus) && __cplusplus >= 201103L)
# define COMPILER_HAS_CPP11_SUPPORT
#endif
#define __STDC_LIMIT_MACROS
#include <iostream>
#include <memory>
#include <functional>
#include <algorithm>
#ifdef COMPILER_HAS_CPP11_SUPPORT
#include <array>
#endif
namespace syncope {
class pool_guard_base {};
typedef const pool_guard_base& pool_guard;
// default hash function
template<typename T>
inline size_t lock_hash(const T& obj) {
return (reinterpret_cast<size_t>(&obj) / sizeof(T));
}
template<bool> class t_bool {};
typedef t_bool<true> t_true;
typedef t_bool<false> t_false;
template<typename T>
class has_rdlock {
private:
typedef char Yes;
typedef char No[2];
template <typename U, U> struct really_has;
template <typename C> static Yes& Test(really_has <void(C::*)() const, &C::rdlock>*);
template <typename C> static Yes& Test(really_has <void(C::*)(), &C::rdlock>*);
template <typename> static No& Test(...);
public:
static bool const value = sizeof(Test<T>(0)) == sizeof(Yes);
};
template<typename Pool, bool Read>
class pool_guard_one : public pool_guard_base {
typedef Pool pool_type;
pool_type& pool_;
const size_t hash_;
mutable bool owns_lock_;
void lock() const {
if(Read) pool_.rdlock(hash_);
else pool_.lock(hash_);
owns_lock_ = true;
}
public:
void unlock() const {
pool_.unlock(hash_);
owns_lock_ = false;
}
template<typename T>
pool_guard_one(pool_type& pool, T const& obj)
: pool_(pool)
, hash_(pool_type::hash(obj))
, owns_lock_(false)
{
lock();
}
#ifdef COMPILER_HAS_CPP11_SUPPORT
pool_guard_one(pool_guard_one const&) = delete;
pool_guard_one& operator = (pool_guard_one const&) = delete;
pool_guard_one(pool_guard_one&& other)
: pool_(other.pool_)
, hash_(other.hash_)
, owns_lock_(other.owns_lock_)
{
other.owns_lock_ = false;
}
pool_guard_one& operator = (pool_guard_one&& other) {
hash_ = other.hash_;
other.owns_lock_ = false;
assert(&pool_ == &other.pool_);
}
#else
pool_guard_one(pool_guard_one const& other)
: pool_(other.pool_)
, hash_(other.hash_)
, owns_lock_(other.owns_lock_)
{
other.owns_lock_ = false;
}
pool_guard_one& operator = (pool_guard_one const& other) {
hash_ = other.hash_;
other.owns_lock_ = false;
assert(&pool_ == &other.pool_);
}
#endif
~pool_guard_one() {
if(owns_lock_) {
unlock();
}
}
};
template<class Pool, bool Read, size_t H>
class pool_guard_many : public pool_guard_base {
typedef Pool pool_type;
template<typename Lock, size_t LockCount> friend class lock_pool;
pool_type& pool_;
size_t hashes_[H];
mutable size_t hash_count_;
#ifdef COMPILER_HAS_CPP11_SUPPORT
template<size_t I, typename ...T>
typename std::enable_if<I < H, void>::type add_hashes(std::tuple<T const&...> const& items) {
add_hash(std::get<I>(items));
add_hashes<I + 1>(items);
};
template<size_t I, typename ...T>
typename std::enable_if < I == H, void>::type add_hashes(std::tuple<T const&...> const& items) {
};
#endif
template<typename T>
pool_guard_many& add_hash(const T& obj) {
hashes_[hash_count_] = pool_type::hash(obj);
++hash_count_;
return *this;
}
pool_guard_many& sort_hashes_and_lock() {
std::sort(&hashes_[0], &hashes_[hash_count_]);
size_t* it = std::unique(&hashes_[0], &hashes_[hash_count_]);
hash_count_ = it - &hashes_[0];
lock();
return *this;
}
void lock() {
for(size_t i = 0; i < hash_count_; ++i) {
if(Read) pool_.rdlock(hashes_[i]);
else pool_.lock(hashes_[i]);
}
}
public:
void unlock() {
while(hash_count_) {
pool_.unlock(hashes_[--hash_count_]);
}
}
#ifdef COMPILER_HAS_CPP11_SUPPORT
template<typename ...T>
pool_guard_many(pool_type& pool, T const&... objects)
: pool_(pool)
, hash_count_(0)
{
add_hashes<0>(std::tie(objects...));
sort_hashes_and_lock();
}
pool_guard_many(pool_guard_many const&) = delete;
pool_guard_many& operator = (pool_guard_many const&) = delete;
pool_guard_many(pool_guard_many&& other)
: pool_(other.pool_)
, hash_count_(other.hash_count_)
{
std::copy(&other.hashes_[0], &other.hashes_[hash_count_], hashes_);
other.hash_count_ = 0;
}
pool_guard_many& operator = (pool_guard_many&& other) {
assert(&other.pool_ == &pool_);
hash_count_ = other.hash_count_;
std::copy(&other.hashes_[0], &other.hashes_[hash_count_], hashes_);
other.hash_count_ = 0;
}
#else
pool_guard_many(pool_type& pool)
: pool_(pool)
, hash_count_(0)
{}
pool_guard_many(pool_guard_many const& other)
: pool_(other.pool_)
, hash_count_(other.hash_count_)
{
std::copy(&other.hashes_[0], &other.hashes_[hash_count_], hashes_);
other.hash_count_ = 0;
}
pool_guard_many& operator = (pool_guard_many const& other) {
assert(&other.pool_ == &pool_);
hash_count_ = other.hash_count_;
std::copy(&other.hashes_[0], &other.hashes_[hash_count_], hashes_);
other.hash_count_ = 0;
}
#endif
~pool_guard_many() {
if(hash_count_) {
unlock();
}
}
};
template<typename Lock, size_t LockCount>
class lock_pool {
typedef Lock lock_type;
mutable lock_type locks_[LockCount];
const char* name_;
#ifdef COMPILER_HAS_CPP11_SUPPORT
public:
lock_pool(lock_pool const&) = delete;
lock_pool& operator = (lock_pool const&) = delete;
#else
lock_pool(lock_pool const&);
lock_pool& operator = (lock_pool const&);
public:
#endif
const static size_t lock_count = LockCount;
lock_pool(const char* name) : name_(name) {}
template<typename T>
static size_t hash(const T& obj) {
using namespace syncope;
return lock_hash(obj) % LockCount;
}
void lock(size_t ix) const {
std::cout << name_ << " lock " << ix << std::endl;
locks_[ix].lock();
}
void rdlock(size_t ix, t_true) const {
std::cout << name_ << " read lock " << ix << std::endl;
locks_[ix].rdlock();
}
void rdlock(size_t ix, t_false) const {
std::cout << name_ << " lock " << ix << std::endl;
locks_[ix].lock();
}
void rdlock(size_t ix) const {
rdlock(ix, t_bool<has_rdlock<Lock>::value>());
}
void unlock(size_t hash) const {
std::cout << name_ << " unlock " << hash << std::endl;
locks_[hash].unlock();
}
typedef pool_guard_one<lock_pool, false> write_guard;
typedef pool_guard_one<lock_pool, true> read_guard;
#ifdef COMPILER_HAS_CPP11_SUPPORT
template<typename T>
pool_guard_one<lock_pool, false> synchronize(T const& arg) {
return std::move(pool_guard_one<lock_pool, false, T>(*this, arg));
}
template<typename T>
pool_guard_one<lock_pool, true> synchronize_read(T const& arg) {
return std::move(pool_guard_one<lock_pool, true, T>(*this, arg));
}
template<typename... T>
pool_guard_many<lock_pool, false, sizeof...(T)> synchronize(T const&... args) {
return std::move(pool_guard_many<lock_pool, false, sizeof...(T)>(*this, args...));
}
template<typename... T>
pool_guard_many<lock_pool, true, sizeof...(T)> synchronize_read(T const&... args) {
return std::move(pool_guard_many<lock_pool, true, sizeof...(T)>(*this, args...));
}
#else
template<typename T>
pool_guard_one<lock_pool, false> synchronize(T const& arg) {
return pool_guard_one<lock_pool, false>(*this, arg);
}
template<typename T1, typename T2>
pool_guard_many<lock_pool, false, 2> synchronize(T1 const& a1, T2 const& a2) {
return pool_guard_many<lock_pool, false, 2>(*this)
.add_hash(a1).add_hash(a2).sort_hashes_and_lock();
}
template<typename T1, typename T2, typename T3>
pool_guard_many<lock_pool, false, 3> synchronize(T1 const& a1, T2 const& a2, T3 const& a3) {
return pool_guard_many<lock_pool, false, 3>(*this)
.add_hash(a1).add_hash(a2).add_hash(a3).sort_hashes_and_lock();
}
template<typename T1, typename T2, typename T3, typename T4>
pool_guard_many<lock_pool, false, 4> synchronize(T1 const& a1, T2 const& a2, T3 const& a3, T4 const& a4) {
return pool_guard_many<lock_pool, false, 4>(*this)
.add_hash(a1).add_hash(a2).add_hash(a3).add_hash(a4).sort_hashes_and_lock();
}
template<typename T>
pool_guard_one<lock_pool, true> synchronize_read(T const& arg) {
return pool_guard_one<lock_pool, true>(*this, arg);
}
template<typename T1, typename T2>
pool_guard_many<lock_pool, true, 2> synchronize_read(T1 const& a1, T2 const& a2) {
return pool_guard_many<lock_pool, true, 2>(*this)
.add_hash(a1).add_hash(a2).sort_hashes_and_lock();
}
template<typename T1, typename T2, typename T3>
pool_guard_many<lock_pool, true, 3> synchronize_read(T1 const& a1, T2 const& a2, T3 const& a3) {
return pool_guard_many<lock_pool, true, 3>(*this)
.add_hash(a1).add_hash(a2).add_hash(a3).sort_hashes_and_lock();
}
template<typename T1, typename T2, typename T3, typename T4>
pool_guard_many<lock_pool, true, 4> synchronize(T1 const& a1, T2 const& a2, T3 const& a3, T4 const& a4) {
return pool_guard_many<lock_pool, true, 4>(*this)
.add_hash(a1).add_hash(a2).add_hash(a3).add_hash(a4).sort_hashes_and_lock();
}
#endif
};
} // namespace syncope
struct my_rwlock { void rdlock() {}; void lock() {} void unlock() {} };
typedef syncope::lock_pool<my_rwlock, 256> test_pool;
test_pool foo_sync("foo sync");
struct foo { foo(int id) : id(id) {} int id; };
inline size_t lock_hash(const foo& obj) {
return obj.id;
}
int main()
{
#ifdef COMPILER_HAS_CPP11_SUPPORT
std::cout << "C++11" << std::endl;
#endif
foo a(1), b(2), c(3);
{
syncope::pool_guard guard1 = foo_sync.synchronize_read(a, b);
std::cout << "read locked 1" << std::endl;
}
{
syncope::pool_guard guard = foo_sync.synchronize(a, b, c);
std::cout << "write locked" << std::endl;
}
return 0;
}