DDD 1.9.0.20250409152518
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>
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
55template<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
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
176public:
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
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
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
static UniqueTableId & instance()
Definition UniqueTableId.hh:229
const T * resolve(const id_t &id) const
Definition UniqueTableId.hh:253
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
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 Wed Apr 9 2025 15:27:42 for DDD by doxygen 1.9.8