[ create a new paste ] login | about

Link: http://codepad.org/hWhPrqdK    [ raw code | output | fork ]

C++, pasted on Jun 30:
#if defined _MSC_VER && _MSC_VER >= 1800L || (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(T const& obj, size_t lock_count) {
        return (reinterpret_cast<size_t>(&obj) / sizeof(T)) % lock_count;
    }


    template<typename pool_type, bool read>
    class pool_guard_one : public pool_guard_base {
        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;
        }
        void unlock() const {
            pool_.unlock(hash_);
            owns_lock_ = false;
        }
    public:
        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_type, bool read, size_t H>
    class pool_guard_many : public pool_guard_base {
        template<typename t_lock, size_t lock_count> 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]);
            }
        }
        void unlock() {
            while(hash_count_) {
                pool_.unlock(hashes_[--hash_count_]);
            }
        }
    public:
#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 t_lock, size_t lock_count>
    class lock_pool {
        typedef lock_pool<t_lock, lock_count> pool_type;
        mutable t_lock locks_[lock_count];
        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
        lock_pool(const char* name) : name_(name) {}
        template<typename T>
        static size_t hash(const T& obj) {
            using namespace syncope;
            return lock_hash(obj, lock_count);
        }
        void lock(size_t hash) const {
            std::cout << name_ << " lock " << hash << std::endl;
            locks_[hash].lock();
        }
        void rdlock(size_t hash) const {
            std::cout << name_ << " read lock " << hash << std::endl;
            using namespace syncope;
            lock_for_reading(locks_[hash]);
        }
        void unlock(size_t hash) const {
            std::cout << name_ << " unlock " << hash << std::endl;
            locks_[hash].unlock();
        }
#ifdef COMPILER_HAS_CPP11_SUPPORT
        template<typename T>
        pool_guard_one<pool_type, false> synchronize(T const& arg) {
            return std::move(pool_guard_one<pool_type, false, T>(*this, arg));
        }
        template<typename T>
        pool_guard_one<pool_type, true> synchronize_read(T const& arg) {
            return std::move(pool_guard_one<pool_type, true, T>(*this, arg));
        }
        template<typename... T>
        pool_guard_many<pool_type, false, sizeof...(T)> synchronize(T const&... args) {
            return std::move(pool_guard_many<pool_type, false, sizeof...(T)>(*this, args...));
        }
        template<typename... T>
        pool_guard_many<pool_type, true, sizeof...(T)> synchronize_read(T const&... args) {
            return std::move(pool_guard_many<pool_type, true, sizeof...(T)>(*this, args...));
        }
#else
        template<typename T>
        pool_guard_one<pool_type, false> synchronize(T const& arg) {
            return pool_guard_one<pool_type, false>(*this, arg);
        }
        template<typename T1, typename T2>
        pool_guard_many<pool_type, false, 2> synchronize(T1 const& a1, T2 const& a2) {
            return pool_guard_many<pool_type, false, 2>(*this)
                .add_hash(a1).add_hash(a2).sort_hashes_and_lock();
        }
        template<typename T1, typename T2, typename T3>
        pool_guard_many<pool_type, false, 3> synchronize(T1 const& a1, T2 const& a2, T3 const& a3) {
            return pool_guard_many<pool_type, 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<pool_type, false, 4> synchronize(T1 const& a1, T2 const& a2, T3 const& a3, T4 const& a4) {
            return pool_guard_many<pool_type, 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<pool_type, true> synchronize_read(T const& arg) {
            return pool_guard_one<pool_type, true>(*this, arg);
        }
        template<typename T1, typename T2>
        pool_guard_many<pool_type, true, 2> synchronize_read(T1 const& a1, T2 const& a2) {
            return pool_guard_many<pool_type, true, 2>(*this)
                .add_hash(a1).add_hash(a2).sort_hashes_and_lock();
        }
        template<typename T1, typename T2, typename T3>
        pool_guard_many<pool_type, true, 3> synchronize_read(T1 const& a1, T2 const& a2, T3 const& a3) {
            return pool_guard_many<pool_type, 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<pool_type, true, 4> synchronize(T1 const& a1, T2 const& a2, T3 const& a3, T4 const& a4) {
            return pool_guard_many<pool_type, 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() {} };
inline void lock_for_reading(my_rwlock& mtx) { mtx.rdlock(); }

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, size_t lock_count) {
    return obj.id%lock_count;
}

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;
}


Output:
1
2
3
4
5
6
7
8
9
10
11
12
foo sync read lock 1
foo sync read lock 2
read locked 1
foo sync unlock 2
foo sync unlock 1
foo sync lock 1
foo sync lock 2
foo sync lock 3
write locked
foo sync unlock 3
foo sync unlock 2
foo sync unlock 1


Create a new paste based on this one


Comments: