89 }
90 ptr = &(node->_next);
91 }
92 return ptr;
93 }
94
95 Node const** lookup_node(unsigned hash, K const& key) const {
96 return const_cast<Node const**>(
97 const_cast<ResourceHashtableBase*>(this)->lookup_node(hash, key));
98 }
99
100 protected:
101 Node** table() const { return STORAGE::table(); }
102
103 ResourceHashtableBase() : STORAGE(), _number_of_entries(0) {}
104 ResourceHashtableBase(unsigned size) : STORAGE(size), _number_of_entries(0) {}
105 NONCOPYABLE(ResourceHashtableBase);
106
107 ~ResourceHashtableBase() {
108 if (ALLOC_TYPE == AnyObj::C_HEAP) {
109 Node* const* bucket = table();
110 const unsigned sz = table_size();
111 while (bucket < bucket_at(sz)) {
112 Node* node = *bucket;
113 while (node != nullptr) {
114 Node* cur = node;
115 node = node->_next;
116 delete cur;
117 }
118 ++bucket;
119 }
120 }
121 }
122
123 public:
124 unsigned table_size() const { return STORAGE::table_size(); }
125 int number_of_entries() const { return _number_of_entries; }
126
127 bool contains(K const& key) const {
128 return get(key) != nullptr;
129 }
130
131 V* get(K const& key) const {
132 unsigned hv = HASH(key);
133 Node const** ptr = lookup_node(hv, key);
134 if (*ptr != nullptr) {
135 return const_cast<V*>(&(*ptr)->_value);
136 } else {
137 return nullptr;
138 }
139 }
278 ++bucket;
279 }
280 }
281
282 // same as above, but unconditionally iterate all entries
283 template<typename Function>
284 void iterate_all(Function function) const { // lambda enabled API
285 auto wrapper = [&] (K& k, V& v) {
286 function(k, v);
287 return true;
288 };
289 iterate(wrapper);
290 }
291
292 // ITER contains bool do_entry(K const&, V const&), which will be
293 // called for each entry in the table. If do_entry() returns true,
294 // the entry is deleted.
295 template<class ITER>
296 void unlink(ITER* iter) {
297 const unsigned sz = table_size();
298 for (unsigned index = 0; index < sz; index++) {
299 Node** ptr = bucket_at(index);
300 while (*ptr != nullptr) {
301 Node* node = *ptr;
302 // do_entry must clean up the key and value in Node.
303 bool clean = iter->do_entry(node->_key, node->_value);
304 if (clean) {
305 *ptr = node->_next;
306 if (ALLOC_TYPE == AnyObj::C_HEAP) {
307 delete node;
308 }
309 _number_of_entries --;
310 } else {
311 ptr = &(node->_next);
312 }
313 }
314 }
315 }
316
317 template<typename Function>
318 TableStatistics statistics_calculate(Function size_function) const {
319 NumberSeq summary;
320 size_t literal_bytes = 0;
321 Node* const* bucket = table();
322 const unsigned sz = table_size();
323 while (bucket < bucket_at(sz)) {
324 Node* node = *bucket;
325 int count = 0;
326 while (node != nullptr) {
327 literal_bytes += size_function(node->_key, node->_value);
328 count++;
329 node = node->_next;
330 }
331 summary.add((double)count);
332 ++bucket;
333 }
334 return TableStatistics(summary, literal_bytes, sizeof(Node*), sizeof(Node));
|
89 }
90 ptr = &(node->_next);
91 }
92 return ptr;
93 }
94
95 Node const** lookup_node(unsigned hash, K const& key) const {
96 return const_cast<Node const**>(
97 const_cast<ResourceHashtableBase*>(this)->lookup_node(hash, key));
98 }
99
100 protected:
101 Node** table() const { return STORAGE::table(); }
102
103 ResourceHashtableBase() : STORAGE(), _number_of_entries(0) {}
104 ResourceHashtableBase(unsigned size) : STORAGE(size), _number_of_entries(0) {}
105 NONCOPYABLE(ResourceHashtableBase);
106
107 ~ResourceHashtableBase() {
108 if (ALLOC_TYPE == AnyObj::C_HEAP) {
109 unlink_all();
110 }
111 }
112
113 public:
114 unsigned table_size() const { return STORAGE::table_size(); }
115 int number_of_entries() const { return _number_of_entries; }
116
117 bool contains(K const& key) const {
118 return get(key) != nullptr;
119 }
120
121 V* get(K const& key) const {
122 unsigned hv = HASH(key);
123 Node const** ptr = lookup_node(hv, key);
124 if (*ptr != nullptr) {
125 return const_cast<V*>(&(*ptr)->_value);
126 } else {
127 return nullptr;
128 }
129 }
268 ++bucket;
269 }
270 }
271
272 // same as above, but unconditionally iterate all entries
273 template<typename Function>
274 void iterate_all(Function function) const { // lambda enabled API
275 auto wrapper = [&] (K& k, V& v) {
276 function(k, v);
277 return true;
278 };
279 iterate(wrapper);
280 }
281
282 // ITER contains bool do_entry(K const&, V const&), which will be
283 // called for each entry in the table. If do_entry() returns true,
284 // the entry is deleted.
285 template<class ITER>
286 void unlink(ITER* iter) {
287 const unsigned sz = table_size();
288 int cnt = _number_of_entries;
289
290 for (unsigned index = 0; cnt > 0 && index < sz; ++index) {
291 Node** ptr = bucket_at(index);
292
293 while (*ptr != nullptr) {
294 Node* node = *ptr;
295 // do_entry must clean up the key and value in Node.
296 bool clean = iter->do_entry(node->_key, node->_value);
297 if (clean) {
298 *ptr = node->_next;
299 if (ALLOC_TYPE == AnyObj::C_HEAP) {
300 delete node;
301 }
302 _number_of_entries --;
303 } else {
304 ptr = &(node->_next);
305 }
306 if (--cnt <= 0) return;
307 }
308 }
309 }
310
311 // unlink_all() is a specialized version of unlink() when we decide to remove all elements.
312 // It can not replace unlink(ITER* iter) if user-provided iter releases key/value
313 void unlink_all() {
314 Node** bucket = table();
315 const unsigned sz = table_size();
316
317 while (_number_of_entries > 0 && bucket < bucket_at(sz)) {
318 Node* node = *bucket;
319 int n = 0;
320
321 while (node != NULL) {
322 Node* cur = node;
323 node = node->_next;
324 if (ALLOC_TYPE == AnyObj::C_HEAP) {
325 delete cur;
326 }
327 n++;
328 }
329
330 if (n > 0) {
331 *bucket = nullptr;
332 _number_of_entries -= n;
333 }
334 bucket++;
335 }
336
337 assert(_number_of_entries == 0, "sanity check");
338 }
339
340 template<typename Function>
341 TableStatistics statistics_calculate(Function size_function) const {
342 NumberSeq summary;
343 size_t literal_bytes = 0;
344 Node* const* bucket = table();
345 const unsigned sz = table_size();
346 while (bucket < bucket_at(sz)) {
347 Node* node = *bucket;
348 int count = 0;
349 while (node != nullptr) {
350 literal_bytes += size_function(node->_key, node->_value);
351 count++;
352 node = node->_next;
353 }
354 summary.add((double)count);
355 ++bucket;
356 }
357 return TableStatistics(summary, literal_bytes, sizeof(Node*), sizeof(Node));
|