Predator  [unstable] git snapshot
syments.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 Kamil Dudka <kdudka@redhat.com>
3  *
4  * This file is part of predator.
5  *
6  * predator is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * any later version.
10  *
11  * predator is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with predator. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef H_GUARD_SYM_ENTS_H
21 #define H_GUARD_SYM_ENTS_H
22 
23 #include "config.h"
24 
25 #include <vector>
26 
27 #include <boost/foreach.hpp>
28 
29 #ifdef NDEBUG
30  // aggressive optimization
31 # define DCAST static_cast
32 #else
33 # define DCAST dynamic_cast
34 #endif
35 
36 #if SH_COPY_ON_WRITE
37 class RefCounter {
38  private:
39  typedef int TCnt;
41 
42  public:
43  /// initialize to 1
45  cnt_(1)
46  {
47  }
48 
49  /// initialize to 1, even if the source has another value
51  cnt_(1)
52  {
53  }
54 
55  /// initialize to 1, even if the source has another value
57  cnt_ = 1;
58  return *this;
59  }
60 
61  /// the destruction is only allowed with reference count equal to zero
64  }
65 
66  bool isShared() const {
67  CL_BREAK_IF(cnt_ < 1);
68  return (1 < cnt_);
69  }
70 
71  bool /* needCloning */ enter() {
72  CL_BREAK_IF(cnt_ < 1);
73  ++cnt_;
74  return false;
75  }
76 
77  bool /* needCloning */ requireExclusivity() {
78  if (!this->isShared())
79  return false;
80 
81  --cnt_;
82  return true;
83  }
84 
85  bool /* wasLast */ leave() {
86  return !(--cnt_);
87  }
88 
89 }; // class RefCounter
90 
91 #else // SH_COPY_ON_WRITE
92 
93 // dummy implementation, no data inside
94 class RefCounter {
95  public:
96  bool isShared() const {
97  return false;
98  }
99 
100  bool /* needCloning */ enter() {
101  return true;
102  }
103 
104  bool /* needCloning */ requireExclusivity() {
105  return false;
106  }
107 
108  bool /* wasLast */ leave() {
109  return true;
110  }
111 };
112 
113 #if SH_PREVENT_AMBIGUOUS_ENT_ID
114 #error SH_PREVENT_AMBIGUOUS_ENT_ID requires SH_COPY_ON_WRITE to be enabled
115 #endif
116 
117 #endif // SH_COPY_ON_WRITE
118 
119 
121  template <class T> static void leave(T *&ptr) {
122  if (/* wasLast */ ptr->refCnt.leave())
123  delete ptr;
124 
125  // mark the pointer accordingly (we have left, right?)
126  ptr = 0;
127  }
128 
129  protected:
130  // library classes only, no instances can be created
131  RefCntLibBase();
132 };
133 
137 };
138 
139 template <enum ERefCntObjKind TKind> struct RefCntLib;
140 
141 template <>
142 struct RefCntLib<RCO_VIRTUAL>: public RefCntLibBase {
143  template <class T> static void enter(T *&ptr) {
144  if (/* needCloning */ ptr->refCnt.enter())
145  ptr = ptr->clone();
146  }
147 
148  template <class T> static void requireExclusivity(T *&ptr) {
149  if (/* needCloning */ ptr->refCnt.requireExclusivity())
150  ptr = ptr->clone();
151  }
152 };
153 
154 template <>
155 struct RefCntLib<RCO_NON_VIRT>: public RefCntLibBase {
156  template <class T> static void enter(T *&ptr) {
157  if (/* needCloning */ ptr->refCnt.enter())
158  ptr = new T(*ptr);
159  }
160 
161  template <class T> static void requireExclusivity(T *&ptr) {
162  if (/* needCloning */ ptr->refCnt.requireExclusivity())
163  ptr = new T(*ptr);
164  }
165 };
166 
167 struct EntCounter {
168 #if SH_PREVENT_AMBIGUOUS_ENT_ID
169  long entCnt;
171 
173  entCnt(0L)
174  {
175  }
176 #endif
177 };
178 
179 template <class TBaseEnt>
180 class EntStore {
181  public:
182  EntStore();
183  inline EntStore(const EntStore &);
184  inline ~EntStore();
185 
186  template <typename TId> inline TId assignId(TBaseEnt *);
187  template <typename TId> inline void assignId(TId id, TBaseEnt *);
188  template <typename TId> inline void releaseEnt(TId id);
189  template <typename TId> inline bool isValidEnt(TId id) const;
190 
191  template <typename TId> TId lastId() const {
192  // we need to be careful with integral arithmetic on enums
193  const long last = -1L + ents_.size();
194  return static_cast<TId>(last);
195  }
196 
197  template <typename TId> bool outOfRange(const TId id) const {
198  return (this->lastId<TId>() < id) || (id < 0);
199  }
200 
201  template <typename TId> inline const TBaseEnt* getEntRO(TId id);
202  template <typename TId> inline TBaseEnt* getEntRW(TId id);
203 
204  template <class TEnt, typename TId>
205  inline void getEntRO(const TEnt **, TId id);
206 
207  template <class TEnt, typename TId>
208  inline void getEntRW(TEnt **, TId id);
209 
210  private:
211  // intentionally not implemented
212  EntStore& operator=(const EntStore &);
213 
214  std::vector<TBaseEnt *> ents_;
216 };
217 
218 
219 // /////////////////////////////////////////////////////////////////////////////
220 // implementation of EntStore
221 template <class TBaseEnt>
222 template <typename TId>
224 {
225  CL_BREAK_IF(ptr->refCnt.isShared());
226 #if SH_PREVENT_AMBIGUOUS_ENT_ID
227  const TId id = static_cast<TId>(entCnt_->entCnt);
228  this->assignId(id, ptr);
229  return id;
230 #else
231  this->ents_.push_back(ptr);
232  return this->lastId<TId>();
233 #endif
234 }
235 
236 template <class TBaseEnt>
237 template <typename TId>
238 void EntStore<TBaseEnt>::assignId(const TId id, TBaseEnt *ptr)
239 {
240  CL_BREAK_IF(ptr->refCnt.isShared());
241 
242  // make sure we have enough space allocated
243  if (this->lastId<TId>() < id)
244  ents_.resize(id + 1, 0);
245 
246  TBaseEnt *&ref = ents_[id];
247 
248  // if this fails, you wanted to overwrite pointer to a valid entity
249  CL_BREAK_IF(ref);
250 
251  ref = ptr;
252 #if SH_PREVENT_AMBIGUOUS_ENT_ID
253  const long cntNow = 1L + id;
254  if (entCnt_->entCnt < cntNow)
255  entCnt_->entCnt = cntNow;
256 #endif
257 }
258 
259 template <class TBaseEnt>
260 template <typename TId>
262 {
264 }
265 
266 template <class TBaseEnt>
267 template <typename TId>
268 bool EntStore<TBaseEnt>::isValidEnt(const TId id) const
269 {
270  if (this->outOfRange(id))
271  return false;
272 
273  return !!ents_[id];
274 }
275 
276 template <class TBaseEnt>
278 #if SH_PREVENT_AMBIGUOUS_ENT_ID
279  : entCnt_(new EntCounter)
280 #endif
281 {
282 }
283 
284 template <class TBaseEnt>
286  ents_(ref.ents_)
288  , entCnt_(ref.entCnt_)
289 #endif
290 {
291 #if SH_PREVENT_AMBIGUOUS_ENT_ID
293 #endif
294  BOOST_FOREACH(TBaseEnt *&ent, ents_)
295  if (ent)
297 }
298 
299 template <class TBaseEnt>
301 {
302 #if SH_PREVENT_AMBIGUOUS_ENT_ID
304 #endif
305  BOOST_FOREACH(TBaseEnt *ent, ents_)
306  if (ent)
308 }
309 
310 template <class TBaseEnt>
311 template <typename TId>
312 inline const TBaseEnt* EntStore<TBaseEnt>::getEntRO(const TId id)
313 {
314  // if this fails, the ID has never been valid
315  CL_BREAK_IF(this->outOfRange(id));
316 
317  // if this fails, the ID is no longer valid
318  const TBaseEnt *ptr = ents_[id];
319  CL_BREAK_IF(!ptr);
320  return ptr;
321 }
322 
323 template <class TBaseEnt>
324 template <typename TId>
325 inline TBaseEnt* EntStore<TBaseEnt>::getEntRW(const TId id)
326 {
327 #ifndef NDEBUG
328  this->getEntRO(id);
329 #endif
330  TBaseEnt *&entRW = ents_[id];
332  return entRW;
333 }
334 
335 template <class TBaseEnt>
336 template <class TEnt, typename TId>
337 inline void EntStore<TBaseEnt>::getEntRO(const TEnt **pEnt, const TId id)
338 {
339  const TBaseEnt *ptr = this->getEntRO(id);
340  const TEnt *ent = DCAST<const TEnt *>(ptr);
341 
342  // if this fails, the entity has type that is incompatible with your request
343  CL_BREAK_IF(!ent);
344 
345  // all OK!
346  *pEnt = ent;
347 }
348 
349 template <class TBaseEnt>
350 template <class TEnt, typename TId>
351 inline void EntStore<TBaseEnt>::getEntRW(TEnt **pEnt, const TId id)
352 {
353  TBaseEnt *ptr = this->getEntRW(id);
354  TEnt *ent = DCAST<TEnt *>(ptr);
355 
356  // if this fails, the entity has type that is incompatible with your request
357  CL_BREAK_IF(!ent);
358 
359  // all OK!
360  *pEnt = ent;
361 }
362 
363 #endif /* H_GUARD_SYM_ENTS_H */