pva2pva  1.4.1
 All Classes Functions Variables Pages
weakset.h
1 #ifndef WEAKSET_H
2 #define WEAKSET_H
3 
4 #include <set>
5 #include <vector>
6 #include <stdexcept>
7 
8 #include <pv/sharedPtr.h>
9 #include <epicsMutex.h>
10 #include <epicsGuard.h>
11 
56 template<typename T>
57 class weak_set
58 {
59 public:
60  typedef T value_type;
61  typedef std::tr1::shared_ptr<T> value_pointer;
62  typedef std::tr1::weak_ptr<T> value_weak_pointer;
63  typedef std::set<value_pointer> set_type;
64  typedef std::vector<value_pointer> vector_type;
65 
66  typedef epicsMutex mutex_type;
67  typedef epicsGuard<epicsMutex> guard_type;
68  typedef epicsGuardRelease<epicsMutex> release_type;
69 private:
70  struct weak_less {
71  bool operator()(const value_weak_pointer& lhs,
72  const value_weak_pointer& rhs) const
73  {
74  value_pointer LHS(lhs.lock()), RHS(rhs.lock());
75  return LHS && RHS && LHS.get() < RHS.get();
76  }
77  bool operator()(const value_pointer& lhs,
78  const value_weak_pointer& rhs) const
79  {
80  value_pointer RHS(rhs.lock());
81  return RHS && lhs.get() < RHS.get();
82  }
83  bool operator()(const value_weak_pointer& lhs,
84  const value_pointer& rhs) const
85  {
86  value_pointer LHS(lhs.lock());
87  return LHS && LHS.get() < rhs.get();
88  }
89  };
90 
91  typedef std::set<value_weak_pointer, weak_less> store_t;
92 
93  struct data {
94  mutex_type mutex;
95  store_t store;
96  };
97  std::tr1::shared_ptr<data> _data;
98 
102  struct dtor {
103  std::tr1::weak_ptr<data> container;
104  value_pointer realself;
105  dtor(const std::tr1::weak_ptr<data>& d,
106  const value_pointer& w)
107  :container(d), realself(w)
108  {}
109  void operator()(value_type *)
110  {
111  value_pointer R;
112  R.swap(realself);
113  assert(R.unique());
114  std::tr1::shared_ptr<data> C(container.lock());
115  if(C) {
116  guard_type G(C->mutex);
117  C->store.erase(R);
118  }
119 
120  /* A subtle gotcha may exist since this struct
121  * may not be destructed until the *weak*
122  * count of the enclosing shared_ptr goes
123  * to zero. Which won't happen
124  * as long as we hold a weak ref to the
125  * container holding a weak ref to us.
126  * It is *essential* that we break this
127  * "weak ref. loop" explicitly
128  */
129  container.reset();
130  }
131  };
132 public:
134  weak_set() :_data(new data) {}
135 
136 private:
138  weak_set(const weak_set& O);
140  weak_set& operator=(const weak_set& O);
141 public:
142 
145  void swap(weak_set& O) {
146  _data.swap(O._data);
147  }
148 
151  void clear() {
152  guard_type G(_data->mutex);
153  return _data->store.clear();
154  }
155 
159  bool empty() const {
160  guard_type G(_data->mutex);
161  return _data->store.empty();
162  }
163 
168  size_t size() const {
169  guard_type G(_data->mutex);
170  return _data->store.size();
171  }
172 
176  void insert(value_pointer&);
177 
180  size_t erase(value_pointer& v) {
181  guard_type G(_data->mutex);
182  return _data->store.erase(v);
183  }
184 
187  set_type lock_set() const;
188 
192  vector_type lock_vector() const;
193 
194  void lock_vector(vector_type&) const;
195 
199  inline epicsMutex& mutex() const {
200  return _data->mutex;
201  }
202 
204  struct XIterator {
205  weak_set& set;
206  epicsGuard<epicsMutex> guard;
207  typename store_t::iterator it, end;
208  XIterator(weak_set& S) :set(S), guard(S.mutex()), it(S._data->store.begin()), end(S._data->store.end()) {}
210  value_pointer next() {
211  value_pointer ret;
212  while(it!=end) {
213  ret = (it++)->lock();
214  if(ret) break;
215  }
216  return ret;
217  }
218  private:
219  XIterator(const XIterator&);
220  XIterator& operator=(const XIterator&);
221  };
222 
223  typedef XIterator iterator;
224 };
225 
226 template<typename T>
227 void weak_set<T>::insert(value_pointer &v)
228 {
229  if(!v.unique())
230  throw std::invalid_argument("Only unique() references may be inserted");
231 
232  guard_type G(_data->mutex);
233  typename store_t::const_iterator it = _data->store.find(v);
234  if(it==_data->store.end()) { // new object
235 
236  // wrapped strong ref. which removes from our map
237  value_pointer chainptr(v.get(), dtor(_data, v));
238 
239  _data->store.insert(chainptr);
240 
241  v.swap(chainptr); // we only keep the chained pointer
242  } else {
243  // already stored, no-op
244 
245  // paranoia, if already inserted then this should be a wrapped ref.
246  // but not sure how to check this so update arg. with known wrapped ref.
247  v = value_pointer(*it); // could throw bad_weak_ptr, but really never should
248  }
249 }
250 
251 template<typename T>
252 typename weak_set<T>::set_type
254 {
255  set_type ret;
256  guard_type G(_data->mutex);
257  for(typename store_t::const_iterator it=_data->store.begin(),
258  end=_data->store.end(); it!=end; ++it)
259  {
260  value_pointer P(it->lock());
261  if(P) ret.insert(P);
262  }
263  return ret;
264 }
265 
266 template<typename T>
267 typename weak_set<T>::vector_type
269 {
270  vector_type ret;
271  lock_vector(ret);
272  return ret;
273 }
274 
275 template<typename T>
276 void weak_set<T>::lock_vector(vector_type& ret) const
277 {
278  guard_type G(_data->mutex);
279  ret.reserve(_data->store.size());
280  for(typename store_t::const_iterator it=_data->store.begin(),
281  end=_data->store.end(); it!=end; ++it)
282  {
283  value_pointer P(it->lock());
284  if(P) ret.push_back(P);
285  }
286 }
287 
288 #endif // WEAKSET_H
set_type lock_set() const
Definition: weakset.h:253
size_t erase(value_pointer &v)
Definition: weakset.h:180
bool empty() const
Definition: weakset.h:159
epicsMutex & mutex() const
Definition: weakset.h:199
value_pointer next()
yield the next live entry
Definition: weakset.h:210
weak_set()
Construct a new empty set.
Definition: weakset.h:134
void swap(weak_set &O)
Definition: weakset.h:145
a std::set-ish container where entries are removed when ref. counts fall to zero
Definition: weakset.h:57
vector_type lock_vector() const
Definition: weakset.h:268
void clear()
Definition: weakset.h:151
size_t size() const
Definition: weakset.h:168
an iterator-ish object which also locks the set during iteration
Definition: weakset.h:204
void insert(value_pointer &)
Definition: weakset.h:227