summaryrefslogtreecommitdiff
path: root/cpp/src/qpid/sys/RefCountedMap.h
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/qpid/sys/RefCountedMap.h')
-rw-r--r--cpp/src/qpid/sys/RefCountedMap.h171
1 files changed, 171 insertions, 0 deletions
diff --git a/cpp/src/qpid/sys/RefCountedMap.h b/cpp/src/qpid/sys/RefCountedMap.h
new file mode 100644
index 0000000000..6e5f4b80d0
--- /dev/null
+++ b/cpp/src/qpid/sys/RefCountedMap.h
@@ -0,0 +1,171 @@
+#ifndef QPID_SYS_REFCOUNTEDMAP_H
+#define QPID_SYS_REFCOUNTEDMAP_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Mutex.h"
+#include "qpid/RefCounted.h"
+
+#include <boost/call_traits.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+
+#include <map>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A thread-safe, RefCounted map of RefCounted entries. Entries are
+ * automatically erased when all iterators to them are destroyed. The
+ * entire map is released when all its entries are erased.
+ *
+ * The assumption is that some other object/thread holds an iterator
+ * to each entry for as long as it is useful.
+ *
+ * API is a subset of std::map
+ *
+ * WARNING: Modifying iterators locks the map. To avoid deadlock, you
+ * MUST NOT modify an iterator while holding another lock that could be
+ * locked as a result of erasing the entry and destroying its value.
+ *
+ */
+
+template <class K, class D>
+class RefCountedMap : public RefCounted
+{
+ typedef Mutex::ScopedLock Lock;
+
+ public:
+ typedef K key_type;
+ typedef D data_type;
+ typedef std::pair<key_type,data_type> value_type;
+
+ /** Bidirectional iterator maintains a reference count on the map entry.
+ * Provides operator!() and operator bool() to test for end() iterator.
+ */
+ class iterator :
+ public boost::iterator_facade<iterator, value_type,
+ boost::bidirectional_traversal_tag>
+ {
+ public:
+ iterator() {}
+ bool operator!() const { return !ptr; }
+ operator bool() const { return ptr; }
+ void reset() { ptr=0; }
+
+ private:
+ typedef typename RefCountedMap::Entry Entry;
+
+ iterator(intrusive_ptr<Entry> entry) : ptr(entry) {}
+
+ // boost::iterator_facade functions.
+ value_type& dereference() const { return ptr->value; }
+ bool equal(iterator j) const { return ptr==j.ptr; }
+ void increment() { assert(ptr); *this=ptr->map->next(ptr->self); }
+ void decrement() { assert(ptr); *this=ptr->map->prev(ptr->self); }
+
+ intrusive_ptr<Entry> ptr;
+
+ friend class boost::iterator_core_access;
+ friend class RefCountedMap<K,D>;
+ };
+
+ iterator begin() { Lock l(lock); return makeIterator(map.begin()); }
+
+ iterator end() { Lock l(lock); return makeIterator(map.end()); }
+
+ size_t size() { Lock l(lock); return map.size(); }
+
+ bool empty() { return size() == 0u; }
+
+ iterator find(const key_type& key) {
+ Lock l(lock); return makeIterator(map.find(key));
+ }
+
+ std::pair<iterator, bool> insert(const value_type& x) {
+ Lock l(lock);
+ std::pair<typename Map::iterator,bool> ib=
+ map.insert(make_pair(x.first, Entry(x, this)));
+ ib.first->second.self = ib.first;
+ return std::make_pair(makeIterator(ib.first), ib.second);
+ }
+
+ private:
+
+ //
+ // INVARIANT:
+ // - All entries in the map have non-0 refcounts.
+ // - Each entry holds an intrusive_ptr to the map
+ //
+
+ struct Entry : public RefCounted {
+ typedef typename RefCountedMap::Map::iterator Iterator;
+
+ Entry(const value_type& v, RefCountedMap* m) : value(v), map(m) {}
+
+ value_type value;
+ intrusive_ptr<RefCountedMap> map;
+ Iterator self;
+
+ // RefCounts are modified with map locked.
+ struct MapLock : public Lock {
+ MapLock(RefCountedMap& m) : Lock(m.lock) {}
+ };
+
+ void released() const {
+ intrusive_ptr<RefCountedMap> protect(map);
+ map->map.erase(self);
+ }
+ };
+
+ typedef std::map<K,Entry> Map;
+
+ iterator makeIterator(typename Map::iterator i) {
+ // Call with lock held.
+ return iterator(i==map.end() ? 0 : &i->second);
+ }
+
+ void erase(typename RefCountedMap::Map::iterator i) {
+ // Make sure this is not deleted till lock is released.
+ intrusive_ptr<RefCountedMap> self(this);
+ { Lock l(lock); map.erase(i); }
+ }
+
+ iterator next(typename RefCountedMap::Map::iterator i) {
+ { Lock l(lock); return makeIterator(++i); }
+ }
+
+ iterator prev(typename RefCountedMap::Map::iterator i) {
+ { Lock l(lock); return makeIterator(--i); }
+ }
+
+ Mutex lock;
+ Map map;
+
+ friend struct Entry;
+ friend class iterator;
+};
+
+
+}} // namespace qpid::sys
+
+#endif /*!QPID_SYS_REFCOUNTEDMAP_H*/