Boost logo

Boost :

From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2007-08-25 21:30:39


AMDG

Phil Endecott <spam_from_boost_dev <at> chezphil.org> writes:

>
> Hi Frank,
>
> Thanks; yes, I think this sort of thing would also be a useful addition
> to Boost. The syntax that I presented had the advantage that
>
> a.push_back(123);
> a.push_back(321);
>
> can have a single lock around both operations, while Bjarne's wrapper
> would lock and unlock for each one. Also, I'm not sure whether his
> could be extended to offer read locks for some operations and write
> locks for others.
>

Here's something along these lines that I wrote a while
back.

In Christ,
Steven Watanabe


// locked_object.hpp
//
// Copyright (c) 2006-2007
// Steven Watanabe
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef LOCKED_OBJECT_H_INCLUDED
#define LOCKED_OBJECT_H_INCLUDED

#include <cassert>
#include <iterator>
#include <algorithm>
#include <vector>
#include <deque>
#include <list>

namespace providere_consulting {

    namespace iterators {

        class checked_container;

        class checked_iterator {
            friend class checked_container;
        public:
            checked_iterator() : prior(0), next(0), container(0) {}
            checked_iterator(const checked_iterator& other) : container(other.container) {
                if(other.is_valid()) {
                    next = other.next;
                    prior = &other;
                    if(next != 0) {
                        next->prior = this;
                    }
                    other.next = this;
                } else {
                    next = 0;
                    prior = 0;
                }
            }
            checked_iterator(const checked_container& container);
            ~checked_iterator() {
                if(is_valid()) {
                    prior->next = next;
                    if(next != 0) {
                        next->prior = prior;
                    }
                }
            }
            checked_iterator& operator=(checked_iterator other) {
                swap(other);
                return(*this);
            }
            bool is_valid() const {
                return(container != 0);
            }
            void swap(checked_iterator& other) {
                if(container != other.container) {
                    std::swap(next, other.next);
                    std::swap(prior, other.prior);
                    set_other_pointers();
                    other.set_other_pointers();
                }
            }
            void invalidate() const {
                if(next != 0) {
                    next->prior = prior;
                }
                if(prior != 0) {
                    prior->next = next;
                }
                container = 0;
            }
        private:
            static void invalidate_all(const checked_iterator* begin) {
                for(; begin != 0; begin = begin->next) {
                    begin->container = 0;
                }
            }
            void set_other_pointers() {
                if(next != 0) {
                    next->prior = this;
                }
                if(prior != 0) {
                    prior->next = this;
                }
            }
            mutable const checked_iterator* next;
            mutable const checked_iterator* prior;
            mutable const checked_container* container;
        };

        class checked_container {
            friend class checked_iterator;
        public:
            checked_container() : list() {}
            ~checked_container() {
                checked_iterator::invalidate_all(&list);
            }
            void invalidate_iterators() const {
                checked_iterator::invalidate_all(&list);
            }
        private:
            checked_iterator list;
        };

        inline checked_iterator::checked_iterator(const checked_container& c) : container(&c) {
            next = container->list.next;
            prior = &container->list;
            set_other_pointers();
        }
        
        template<class Iterator>
        class iterator_template;

        template<class Iterator>
        typename std::iterator_traits<Iterator>::difference_type operator-(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second);
        template<class Iterator>
        bool operator==(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second);
        template<class Iterator>
        bool operator<(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second);

        template<class Iterator>
        class iterator_template : public checked_iterator {
            typedef ::std::iterator_traits<Iterator> traits;
            template<class Iter>
            friend class iterator_template;
        public:
            typedef typename traits::value_type value_type;
            typedef typename traits::reference reference;
            typedef typename traits::pointer pointer;
            typedef typename traits::difference_type difference_type;
            typedef typename traits::iterator_category iterator_category;
            iterator_template() {}
            iterator_template(const Iterator& iter, const checked_container& container) : checked_iterator(container), impl(iter) {}
            //iterator_template(const iterator_template& other);
            template<class Iter>
            iterator_template(const iterator_template<Iter>& other) : checked_iterator(static_cast<const checked_iterator&>(other)), impl(other.impl) {}
            iterator_template& operator=(iterator_template other) {
                swap(other);
                return(*this);
            }
            ~iterator_template() {
            }
            reference operator*() {
                check_invariants();
                return(*impl);
            }
            Iterator operator->() {
                check_invariants();
                return(impl);
            }
            iterator_template& operator++() {
                check_invariants();
                ++impl;
                return(*this);
            }
            iterator_template operator++(int) {
                iterator_template temp(*this);
                ++*this;
                return(temp);
            }
            iterator_template& operator--() {
                check_invariants();
                --impl;
                return(*this);
            }
            iterator_template operator--(int) {
                iterator_template temp(*this);
                --*this;
                return(temp);
            }
            iterator_template& operator+=(difference_type difference) {
                check_invariants();
                impl += difference;
                return(*this);
            }
            iterator_template& operator-=(difference_type difference) {
                check_invariants();
                impl -= difference;
                return(*this);
            }
            friend typename traits::difference_type operator-<Iterator>(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second);
            friend bool operator== <>(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second);
            friend bool operator< <>(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second);
            void swap(iterator_template& other) {
                using std::swap;
                swap(impl, other.impl);
                checked_iterator::swap(static_cast<checked_iterator&>(other));
            }
            Iterator get() {
                return(impl);
            }
        private:
            void check_invariants() const {
                assert(is_valid());
            }
            Iterator impl;
        };

        template<class Iterator>
        iterator_template<Iterator> operator+(iterator_template<Iterator> iter, typename std::iterator_traits<Iterator>::difference_type difference) {
            iter += difference;
            return(iter);
        }
        template<class Iterator>
        iterator_template<Iterator> operator+(typename std::iterator_traits<Iterator>::difference_type difference, iterator_template<Iterator> iter) {
            iter += difference;
            return(iter);
        }
        template<class Iterator>
        iterator_template<Iterator> operator-(iterator_template<Iterator> iter, typename std::iterator_traits<Iterator>::difference_type difference) {
            iter -= difference;
            return(iter);
        }
        template<class Iterator>
        typename std::iterator_traits<Iterator>::difference_type operator-(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second) {
            first.check_invariants();
            second.check_invariants();
            return(first.impl - second.impl);
        }
        template<class Iterator>
        bool operator==(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second) {
            first.check_invariants();
            second.check_invariants();
            return(first.impl == second.impl);
        }
        template<class Iterator>
        bool operator!=(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second) {
            return(!(first == second));
        }
        template<class Iterator>
        bool operator<(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second) {
            first.check_invariants();
            second.check_invariants();
            return(first.impl < second.impl);
        }
        template<class Iterator>
        bool operator>(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second) {
            return(second < first);
        }
        template<class Iterator>
        bool operator<=(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second) {
            return(!(first > second));
        }
        template<class Iterator>
        bool operator>=(const iterator_template<Iterator>& first, const iterator_template<Iterator>& second) {
            return(!(first < second));
        }

    }

    template<class T, class Mutex>
    class locked_object;

    template<class T>
    struct locked_object_value {
        typedef T type;
        static void on_release(const T& t) {}
    };

    template<class T>
    struct wrap_sequential_container : T, iterators::checked_container {
        typedef T base;
        typedef iterators::iterator_template<typename base::iterator> iterator;
        typedef iterators::iterator_template<typename base::const_iterator> const_iterator;
        typedef iterators::iterator_template<typename base::reverse_iterator> reverse_iterator;
        typedef iterators::iterator_template<typename base::const_reverse_iterator> const_reverse_iterator;
        using typename base::size_type;
        using typename base::const_reference;
        iterator begin() {
            iterator result(base::begin(), *this);
            return(result);
        }
        iterator end() {
            iterator result(base::end(), *this);
            return(result);
        }
        reverse_iterator rbegin() {
            reverse_iterator result(base::rbegin(), *this);
            return(result);
        }
        reverse_iterator rend() {
            reverse_iterator result(base::rend(), *this);
            return(result);
        }
        const_iterator begin() const {
            const_iterator result(base::begin(), *this);
            return(result);
        }
        const_iterator end() const {
            const_iterator result(base::end(), *this);
            return(result);
        }
        const_reverse_iterator rbegin() const {
            const_reverse_iterator result(base::rbegin(), *this);
            return(result);
        }
        const_reverse_iterator rend() const {
            const_reverse_iterator result(base::rend(), *this);
            return(result);
        }
        iterator insert(iterator pos, const_reference value) const {
            iterator result(base::insert(pos.get(), value), *this);
            return(result);
        }
        iterator insert(iterator pos, size_type size, const_reference value) const {
            iterator result(base::insert(pos.get(), size, value), *this);
            return(result);
        }
        template<class Iter>
        iterator insert(iterator pos, Iter begin, Iter end) const {
            iterator result(base::insert(pos.get(), begin, end), *this);
            return(result);
        }
        iterator erase(iterator pos) {
            iterator result(base::erase(pos.get()), *this);
            return(result);
        }
        iterator erase(iterator begin, iterator end) {
            iterator result(base::erase(begin.get(), end.get()), *this);
            return(result);
        }
    };

    template<class T, class Allocator>
    struct locked_object_value<std::vector<T, Allocator> > {
        typedef wrap_sequential_container<std::vector<T, Allocator> > type;
        static void on_release(const type& t) {
            t.invalidate_iterators();
        }
    };

    template<class T, class Allocator>
    struct locked_object_value<std::deque<T, Allocator> > {
        typedef wrap_sequential_container<std::deque<T, Allocator> > type;
        static void on_release(const type& t) {
            t.invalidate_iterators();
        }
    };

    template<class T, class Allocator>
    struct locked_object_value<std::list<T, Allocator> > {
        struct type : wrap_sequential_container<std::list<T, Allocator> > {
            typedef wrap_sequential_container<std::list<T, Allocator> > base;
            void splice(typename base::iterator pos, std::list<T, Allocator>& other) {
                base::splice(pos.get(), other);
            }
            void splice(typename base::iterator pos, std::list<T, Allocator>& other, typename std::list<T, Allocator>::iterator begin) {
                base::splice(pos.get(), other, begin);
            }
            void splice(typename base::iterator pos, std::list<T, Allocator>& other, typename std::list<T, Allocator>::iterator begin, typename std::list<T, Allocator>::iterator end) {
                base::splice(pos.get(), other, begin, end);
            }
        };
        static void on_release(const type& t) {
            t.invalidate_iterators();
        }
    };

    namespace scoped_lock_pointer_adl_barrier {

        template<class T>
        inline typename T::element_type& operator*(T& t) {
            return(*t.tptr);
        }

        template<class T, class Mutex>
        class scoped_lock_pointer {
        public:
            typedef T element_type;
            scoped_lock_pointer(locked_object<T, Mutex>& object) : tptr(&object.t), lock(object.mutex) {}
            ~scoped_lock_pointer() {
                locked_object_value<T>::on_release(*tptr);
            }
            template<class P>
            friend typename P::element_type& operator*(P&);
            T* operator->() {
                return(tptr);
            }
        private:
            scoped_lock_pointer(const scoped_lock_pointer&);
            scoped_lock_pointer& operator=(const scoped_lock_pointer&);
            typename locked_object_value<T>::type* tptr;
            typename Mutex::scoped_lock lock;
        };

        template<class T, class Mutex>
        class const_scoped_lock_pointer {
        public:
            typedef const T element_type;
            const_scoped_lock_pointer(const locked_object<T, Mutex>& object) : tptr(&object.t), lock(object.mutex) {}
            ~const_scoped_lock_pointer() {
                locked_object_value<T>::on_release(*tptr);
            }
            template<class P>
            friend typename P::element_type& operator*(P&);
            const T* operator->() {
                return(tptr);
            }
        private:
            const_scoped_lock_pointer(const const_scoped_lock_pointer&);
            const_scoped_lock_pointer& operator=(const const_scoped_lock_pointer&);
            const typename locked_object_value<T>::type* tptr;
            typename Mutex::scoped_lock lock;
        };

    }

    template<class T, class Mutex>
    class locked_object {
    public:
        friend class scoped_lock_pointer_adl_barrier::scoped_lock_pointer<T, Mutex>;
        typedef scoped_lock_pointer_adl_barrier::scoped_lock_pointer<T, Mutex> scoped_lock_pointer;
        friend class scoped_lock_pointer_adl_barrier::const_scoped_lock_pointer<T, Mutex>;
        typedef scoped_lock_pointer_adl_barrier::const_scoped_lock_pointer<T, Mutex> const_scoped_lock_pointer;

        locked_object() : t() {}
        locked_object(const T& arg) : t(t) {}
        template<class U>
        locked_object(U& u) : t(u) {}
        template<class U>
        locked_object(const U& u) : t(u) {}
        template<class U1, class U2>
        locked_object(U1& u1, U2& u2) : t(u1, u2) {}
        template<class U1, class U2>
        locked_object(const U1& u1, U2& u2) : t(u1, u2) {}
        template<class U1, class U2>
        locked_object(U1& u1, const U2& u2) : t(u1, u2) {}
        template<class U1, class U2>
        locked_object(const U1& u1, const U2& u2) : t(u1, u2) {}
        template<class U1, class U2, class U3>
        locked_object(U1& u1, U2& u2, U3& u3) : t(u1, u2) {}
        template<class U1, class U2, class U3>
        locked_object(const U1& u1, U2& u2, U3& u3) : t(u1, u2) {}
        template<class U1, class U2, class U3>
        locked_object(U1& u1, const U2& u2, U3& u3) : t(u1, u2) {}
        template<class U1, class U2, class U3>
        locked_object(U1& u1, U2& u2, const U3& u3) : t(u1, u2) {}
        template<class U1, class U2, class U3>
        locked_object(const U1& u1, const U2& u2, U3& u3) : t(u1, u2) {}
        template<class U1, class U2, class U3>
        locked_object(const U1& u1, U2& u2, const U3& u3) : t(u1, u2) {}
        template<class U1, class U2, class U3>
        locked_object(U1& u1, const U2& u2, const U3& u3) : t(u1, u2) {}
        template<class U1, class U2, class U3>
        locked_object(const U1& u1, const U2& u2, const U3& u3) : t(u1, u2) {}
    private:
        typename locked_object_value<T>::type t;
        mutable Mutex mutex;
    };

}

#endif


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk