pva2pva  1.4.1
 All Classes Functions Variables Pages
weakmap.h
1 #ifndef WEAKMAP_H
2 #define WEAKMAP_H
3 
4 #include <map>
5 #include <set>
6 #include <vector>
7 #include <stdexcept>
8 
9 #include <pv/sharedPtr.h>
10 #include <epicsMutex.h>
11 #include <epicsGuard.h>
12 
58 template<typename K, typename V, typename C = std::less<K> >
60 {
61 public:
62  typedef K key_type;
63  typedef V value_type;
64  typedef std::tr1::shared_ptr<V> value_pointer;
65  typedef std::tr1::weak_ptr<V> value_weak_pointer;
66  typedef std::set<value_pointer> set_type;
67 
68  typedef epicsMutex mutex_type;
69  typedef epicsGuard<epicsMutex> guard_type;
70  typedef epicsGuardRelease<epicsMutex> release_type;
71 private:
72  typedef std::map<K, value_weak_pointer, C> store_t;
73 
74  struct data {
75  mutex_type mutex;
76  store_t store;
77  };
78  std::tr1::shared_ptr<data> _data;
79 
80  struct dtor {
81  std::tr1::weak_ptr<data> container;
82  K key;
83  value_pointer realself;
84  dtor(const std::tr1::weak_ptr<data>& d,
85  const K& k,
86  const value_pointer& w)
87  :container(d), key(k), realself(w)
88  {}
89  void operator()(value_type *)
90  {
91  value_pointer R;
92  R.swap(realself);
93  std::tr1::shared_ptr<data> cont(container.lock());
94  if(cont) {
95  guard_type G(cont->mutex);
96  cont->store.erase(key);
97  }
98 
99  /* A subtle gotcha may exist since this struct
100  * may not be destructed until the *weak*
101  * count of the enclosing shared_ptr goes
102  * to zero. Which won't happen
103  * as long as we hold a weak ref to the
104  * container holding a weak ref to us.
105  * It is *essential* that we break this
106  * "weak ref. loop" explicitly
107  */
108  container.reset();
109  }
110  };
111 public:
113  weak_value_map() :_data(new data) {}
114 
115 private:
117  weak_value_map(const weak_value_map& O);
119  weak_value_map& operator=(const weak_value_map& O);
120 public:
121 
124  void swap(weak_value_map& O) {
125  _data.swap(O._data);
126  }
127 
130  void clear() {
131  guard_type G(_data->mutex);
132  return _data->store.clear();
133  }
134 
138  bool empty() const {
139  guard_type G(_data->mutex);
140  return _data->store.empty();
141  }
142 
147  size_t size() const {
148  guard_type G(_data->mutex);
149  return _data->store.size();
150  }
151 
156  weak_value_map& M;
157  const key_type& k;
158  friend class weak_value_map;
159  element_proxy(weak_value_map& m, const key_type& k)
160  :M(m), k(k) {}
161  public:
162  ~element_proxy() {}
166  value_pointer& operator=(value_pointer& v)
167  {
168  if(!v.unique())
169  throw std::invalid_argument("Only unique() references may be inserted");
170  value_pointer chainptr(v.get(), dtor(M._data, k, v));
171  M._data->store[k] = chainptr;
172  v.swap(chainptr);
173  return v;
174  }
176  inline V& operator*() const {
177  return *value_pointer(*this);
178  }
180  inline V* operator->() const {
181  return value_pointer(*this).get();
182  }
184  operator value_pointer() const
185  {
186  value_pointer ret = M.find(k);
187  if(!ret)
188  throw std::runtime_error("Bad key");
189  return ret;
190  }
191  bool operator==(const value_pointer& v) const
192  {
193  return M.find(k)==v;
194  }
195  bool operator!=(const value_pointer& v) const
196  {
197  return !(*this==v);
198  }
199  };
200 
201  inline element_proxy operator[](const K& k)
202  {
203  return element_proxy(*this, k);
204  }
205 
206  value_pointer operator[](const K& k) const
207  {
208  value_pointer ret = find(k);
209  if(!ret)
210  throw std::runtime_error("Bad key");
211  }
212 
215  value_pointer find(const K& k) const
216  {
217  value_pointer ret;
218  guard_type G(_data->mutex);
219  typename store_t::const_iterator it(_data->store.find(k));
220  if(it!=_data->store.end()) {
221  // may be nullptr if we race destruction
222  // as ref. count falls to zero before we can remove it
223  ret = it->second.lock();
224  }
225  return ret;
226  }
227 
230  value_pointer insert(const K& k, value_pointer& v)
231  {
232  value_pointer ret;
233  guard_type G(_data->mutex);
234  typename store_t::const_iterator it = _data->store.find(k);
235  if(it!=_data->store.end())
236  ret = it->second.lock();
237  (*this)[k] = v;
238  return ret;
239  }
240 
241  typedef std::map<K, value_pointer, C> lock_map_type;
243  lock_map_type lock_map() const
244  {
245  lock_map_type ret;
246  guard_type G(_data->mutex);
247  for(typename store_t::const_iterator it = _data->store.begin(),
248  end = _data->store.end(); it!=end; ++it)
249  {
250  value_pointer P(it->second.lock);
251  if(P) ret[it->first] = P;
252  }
253  return ret;
254  }
255 
256  typedef std::vector<std::pair<K, value_pointer> > lock_vector_type;
259  lock_vector_type lock_vector() const
260  {
261  lock_vector_type ret;
262  guard_type G(_data->mutex);
263  ret.reserve(_data->store.size());
264  for(typename store_t::const_iterator it = _data->store.begin(),
265  end = _data->store.end(); it!=end; ++it)
266  {
267  value_pointer P(it->second.lock());
268  if(P) ret.push_back(std::make_pair(it->first, P));
269  }
270  return ret;
271  }
272 
276  inline epicsMutex& mutex() const {
277  return _data->mutex;
278  }
279 };
280 
281 #endif // WEAKMAP_H
void clear()
Definition: weakmap.h:130
V * operator->() const
Support: map[k]-&gt;mem.
Definition: weakmap.h:180
size_t size() const
Definition: weakmap.h:147
lock_vector_type lock_vector() const
Definition: weakmap.h:259
void swap(weak_value_map &O)
Definition: weakmap.h:124
weak_value_map()
Construct a new empty set.
Definition: weakmap.h:113
epicsMutex & mutex() const
Definition: weakmap.h:276
value_pointer find(const K &k) const
Definition: weakmap.h:215
lock_map_type lock_map() const
Return an equivalent map with strong value references.
Definition: weakmap.h:243
V & operator*() const
Support: *map[k].
Definition: weakmap.h:176
value_pointer & operator=(value_pointer &v)
Definition: weakmap.h:166
value_pointer insert(const K &k, value_pointer &v)
Definition: weakmap.h:230
An associative map where a weak_ptr to the value is stored.
Definition: weakmap.h:59
bool empty() const
Definition: weakmap.h:138