DDD  1.9.0.20240826145154
UniqueTableId.hh
Go to the documentation of this file.
1 /****************************************************************************/
2 /* */
3 /* This file is part of libDDD, a library for manipulation of DDD and SDD. */
4 /* */
5 /* Copyright (C) 2001-2008 Yann Thierry-Mieg, Jean-Michel Couvreur */
6 /* and Denis Poitrenaud */
7 /* */
8 /* This program is free software; you can redistribute it and/or modify */
9 /* it under the terms of the GNU Lesser General Public License as */
10 /* published by the Free Software Foundation; either version 3 of the */
11 /* License, or (at your option) any later version. */
12 /* This program is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
15 /* GNU LEsserGeneral Public License for more details. */
16 /* */
17 /* You should have received a copy of the GNU Lesser General Public License */
18 /* along with this program; if not, write to the Free Software */
19 /*Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
20 /* */
21 /****************************************************************************/
22 
23 /* -*- C++ -*- */
24 #ifndef UNIQUETABLE_ID_H
25 #define UNIQUETABLE_ID_H
26 
27 #include <cassert>
28 #include <vector>
30 #include "ddd/util/hash_support.hh"
31 #include "ddd/util/hash_set.hh"
32 
33 // the clone contract
34 
45 
48 // Additional contract requirements for the stored type T :
49 // it should be cloneable. Implement clone in class C by :
50 // return new C(*this);
51 
52 
53 
55 template<typename T, typename ID>
57  typedef ID id_t;
58 
59  // To hash compare id's. id 0 is used as temporary id for comparisons.
60  // hash value is given by the contents of unique object.
61  // Unique objects T must implement : size_t hash () const;
62  struct id_hash {
63  size_t operator()(const id_t & id) const{
64  if (!id) return 0;
65  return UniqueTableId::instance().resolve(id)->hash();
66  }
67  };
68 
69  // To compare id's. id 0 is used as temporary id for comparisons.
70  // compare value is given by the contents of unique object.
71  // Unique objects T must implement : bool operator == (const T & other) const;
72  struct id_compare {
73  bool operator()(const id_t & id1,const id_t & id2) const{
74  if (id1==0 || id2 == 0) {
75  // deleted key
76  return false;
77  }
79  }
80  };
81 
82 
89  typedef typename std::vector<const T*> indexes_t;
92  typedef typename google::sparsetable<id_t> refs_t;
94  typedef std::vector<bool> marks_t;
95 
97  table_t table; // Unique table of unique objects
99  indexes_t index; // Index table of unique objects
108  // basic stats counter
109  size_t peak_size_;
110 
112  void push (const id_t & id) {
113  // std::cerr << "b4 push (" <<id << ")"; print_free_list(std::cerr);
114  // chain head behind id
115  index[id] =((const T*) ((size_t)head));
116  // set head to id
117  head = id;
118  // std::cerr << "after push (" <<id << ")"; print_free_list(std::cerr);
119  }
120 
124  if (head == 0) {
125  id_t ret = index.size();
126  index.push_back(NULL);
127  marks.push_back(false);
128  return ret;
129  } else {
130  id_t ret = head;
131  head = (size_t) index[head];
132  marks[ret] = false;
133  return ret;
134  }
135  }
136 
137  void print_free_list(std::ostream & os) const {
138  id_t pos = head;
139  os << "free list ";
140  while (pos != 0) {
141  os << pos << " ";
142  pos = (size_t) index[pos];
143  if (pos != 0) {
144  os << "," ;
145  }
146  }
147  os << std::endl;
148  }
149 
150  void print_table(std::ostream & os) const {
151  os << "table ";
152  for(table_it di=begin() ; di!= end(); /* in loop */){
153  id_t id = *di;
154  ++di;
155  os << id << " ";
156  if (di != end()) {
157  os << ",";
158  } else {
159  break;
160  }
161  }
162  os << std::endl;
163  }
164 
165  void print_marked(std::ostream & os) const {
166  os << "marked : ";
167  for(size_t i = 0 ; i < index.size() ; i++) {
168  if (marks[i]) {
169  os << i << " ";
170  }
171  }
172  os << std::endl;
173  }
174 
175 
176 public:
177 
178  // mark an entry to be kept
179  void mark (const id_t & id) {
180  if (! marks[id]) {
181  marks[id] = true;
182  resolve(id)->mark();
183  }
184  }
185 
186  // reference a unique object.
187  // refs are used as heads for mark & sweep
188  void ref (const id_t & id) {
189  // make sure sparse table is large enough
190  if (refs.size() <= id) {
191  // exponential may be a bit too much
192  refs.resize((3*id)/2);
193  assert( refs.size() > id);
194  }
195 
196  // test is true if ref count != 0
197  if (refs.test(id)) {
198  // increment
199  refs.set(id,refs.get(id)+1);
200  } else {
201 // std::cerr << "ref " << id << std::endl;
202  // set to 1
203  refs.set(id,1);
204  }
205  }
206 
207  // dereference an object.
208  // when refcount is 0, the object is collectible unless it gets marked during mark&sweep.
209  void deref (const id_t & id) {
210  // assume refcount was > 0
211  assert(refs.test(id));
212  id_t refc = refs.get(id);
213  if (refc==1) {
214 // std::cerr << "deref " << id << std::endl;
215  // set to 0 = erase refcount
216  refs.erase(id);
217  } else {
218  // decrement
219  refs.set(id, refc-1);
220  }
221  }
222 
223  typedef typename table_t::const_iterator table_it;
224 
225  table_it begin() const { return table.begin() ; }
226  table_it end() const { return table.end() ; }
227 
228 
229  static UniqueTableId & instance () {
230  static UniqueTableId * const single_ = new UniqueTableId();
231  return *single_;
232  }
233 
236  UniqueTableId(size_t s=4096):
237  table (s), head(0),peak_size_(0)
238  {
239  index.reserve(s);
240  // position 0 is used for deleted key marker
241  index.push_back(NULL);
242  table.set_deleted_key(0);
243  // position 1 is reserved for hash comparisons of temporary objects.
244  index.push_back(NULL);
245  refs.resize(s);
246  // so that marks and index always have congruent sizes.
247  marks.reserve(s);
248  marks.push_back(false);
249  marks.push_back(false);
250  }
251 
252 
253  const T * resolve (const id_t & id) const {
254  return index[id];
255  }
256 
257 /* Canonical */
262  id_t
263  operator()(const T &_g)
264  {
265  const int tmpid = 1;
266  // temporary store of object at index 0
267  index[tmpid]=&_g;
268  // look for object identical to the one at id 0
269  typename table_t::const_iterator it = table.find (tmpid);
270  // whatever happens, free index 0
271  index[tmpid]=NULL;
272 
273  if (it != table.end()) {
274  // a hit, return the index found in table
275  return *it;
276  } else {
277  // copy object to unique table storage memory space.
278  // this step takes ownership for the memory, any deallocations must be done through "remove"
279  T * clone = unique::clone<T>() (_g);
280 
281  id_t id = next_id();
282  index[id] = clone;
283 
284  std::pair<typename table_t::iterator, bool> ref=table.insert(id);
285  assert(ref.second);
286  ((void)ref);
287 // access->second = id;
288  return id;
289  }
290  }
291 
293  size_t
294  size() const
295  {
296  return table.size();
297  }
298 
299  size_t peak_size () {
300  size_t siz = size();
301  if (siz > peak_size_)
302  peak_size_=siz;
303  return peak_size_;
304  }
305 
306  void garbage () {
307  peak_size();
308  // currently mark and sweep mode.
309 
310  // print_table(std::cerr);
311  // print_free_list(std::cerr);
312  // print_marked(std::cerr);
313 
314  // mark phase
315  // iterate over refcounted entries only
316  for (typename refs_t::nonempty_iterator it = refs.nonempty_begin() ; it != refs.nonempty_end() ; ++it ) {
317  id_t id = refs.get_pos(it);
318  mark(id);
319  }
320  // std::cerr << "after mark ref'd : " ; print_marked(std::cerr);
321 
322  table_t newtable (table.size()*2);
323  newtable.set_deleted_key(0);
324  // sweep phase
325  for(table_it di=begin() ; di!= end();/*++ done in loop*/ ){
326  id_t id = *di;
327  // to avoid corruption if deleted
328 // table_it ci = di;
329  ++di;
330  if (id==0) {
331  continue;
332  }
333  // if not marked
334  if (! marks[id] ) {
335  // kill it
336  // mark an entry for deletion, the id should not be used again,
337 // table.erase(ci);
338  // free memory allocated by clone
339  delete (T*) index[id];
340  // id may be recycled to designate something else.
341  push(id);
342  } else {
343  newtable.insert(id);
344  }
345  marks[id] = false;
346  }
347  // cleanup
348  table = newtable;
349 
350 // print_table(std::cerr);
351 // print_free_list(std::cerr);
352 
353  }
354 
355 
356 #ifdef HASH_STAT
357  std::map<std::string, size_t> get_hits() const { return table.get_hits(); }
358  std::map<std::string, size_t> get_misses() const { return table.get_misses(); }
359  std::map<std::string, size_t> get_bounces() const { return table.get_bounces(); }
360 #endif // HASH_STAT
361 };
362 
363 #endif
Requirements on the contained type are to be cloneable, hashable and equality comparable.
Definition: UniqueTableId.hh:56
google::sparsetable< id_t > refs_t
a sparse table holding refcounts for ref'd objects.
Definition: UniqueTableId.hh:92
const T * resolve(const id_t &id) const
Definition: UniqueTableId.hh:253
UniqueTableId(size_t s=4096)
Provide an initial size for both hash and index tables.
Definition: UniqueTableId.hh:236
d3::hash_set< id_t, id_hash, id_compare >::type table_t
Typedef helps hide implementation type.
Definition: UniqueTableId.hh:86
refs_t refs
The reference counters for ref'd nodes. It is a sparse table that only stores values for non-zero ent...
Definition: UniqueTableId.hh:105
table_it begin() const
Definition: UniqueTableId.hh:225
void ref(const id_t &id)
Definition: UniqueTableId.hh:188
size_t peak_size()
Definition: UniqueTableId.hh:299
static UniqueTableId & instance()
Definition: UniqueTableId.hh:229
size_t peak_size_
Definition: UniqueTableId.hh:109
void garbage()
Definition: UniqueTableId.hh:306
void print_table(std::ostream &os) const
Definition: UniqueTableId.hh:150
void print_marked(std::ostream &os) const
Definition: UniqueTableId.hh:165
std::vector< const T * > indexes_t
The Indexes table stores the id to (unique) T* map.
Definition: UniqueTableId.hh:89
id_t head
The free list is stored hidden in the free space of the index table.
Definition: UniqueTableId.hh:103
void mark(const id_t &id)
Definition: UniqueTableId.hh:179
id_t next_id()
return the next free id, either collected from free_list or the newly allocated last position of the ...
Definition: UniqueTableId.hh:123
indexes_t index
The actual index table, resolution of object from Id is done with this.
Definition: UniqueTableId.hh:99
marks_t marks
The marking entries, a bitset.
Definition: UniqueTableId.hh:107
table_it end() const
Definition: UniqueTableId.hh:226
table_t::const_iterator table_it
Definition: UniqueTableId.hh:223
void print_free_list(std::ostream &os) const
Definition: UniqueTableId.hh:137
ID id_t
Definition: UniqueTableId.hh:57
void deref(const id_t &id)
Definition: UniqueTableId.hh:209
id_t operator()(const T &_g)
The application operator, returns the address of the value already in the table if it exists,...
Definition: UniqueTableId.hh:263
size_t size() const
Returns the current number of filled entries in the table.
Definition: UniqueTableId.hh:294
table_t table
The actual table, operations on the UniqueTable are delegated on this.
Definition: UniqueTableId.hh:97
void push(const id_t &id)
add a node to free list
Definition: UniqueTableId.hh:112
std::vector< bool > marks_t
A bitset to store marks on objects used for mark&sweep.
Definition: UniqueTableId.hh:94
Definition: UniqueTableId.hh:72
bool operator()(const id_t &id1, const id_t &id2) const
Definition: UniqueTableId.hh:73
Definition: UniqueTableId.hh:62
size_t operator()(const id_t &id) const
Definition: UniqueTableId.hh:63
google::sparse_hash_set< Key, Hash, Compare, Allocator > type
Definition: hash_set.hh:24
Definition: hash_support.hh:230

Please comment this page and report errors about it on the RefDocComments page.
Generated on Mon Aug 26 2024 14:54:00 for DDD by doxygen 1.9.1