1 /* 2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_VM_UTILITIES_RESOURCEHASH_HPP 26 #define SHARE_VM_UTILITIES_RESOURCEHASH_HPP 27 28 #include "memory/allocation.hpp" 29 30 template<typename K> struct ResourceHashtableFns { 31 typedef unsigned (*hash_fn)(K const&); 32 typedef bool (*equals_fn)(K const&, K const&); 33 }; 34 35 template<typename K> unsigned primitive_hash(const K& k) { 36 unsigned hash = (unsigned)((uintptr_t)k); 37 return hash ^ (hash >> 3); // just in case we're dealing with aligned ptrs 38 } 39 40 template<typename K> bool primitive_equals(const K& k0, const K& k1) { 41 return k0 == k1; 42 } 43 44 template< 45 typename K, typename V, 46 // xlC does not compile this: 47 // http://stackoverflow.com/questions/8532961/template-argument-of-type-that-is-defined-by-inner-typedef-from-other-template-c 48 //typename ResourceHashtableFns<K>::hash_fn HASH = primitive_hash<K>, 49 //typename ResourceHashtableFns<K>::equals_fn EQUALS = primitive_equals<K>, 50 unsigned (*HASH) (K const&) = primitive_hash<K>, 51 bool (*EQUALS)(K const&, K const&) = primitive_equals<K>, 52 unsigned SIZE = 256, 53 ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA, 54 MEMFLAGS MEM_TYPE = mtInternal 55 > 56 class ResourceHashtable : public ResourceObj { 57 private: 58 59 class Node : public ResourceObj { 60 public: 61 unsigned _hash; 62 K _key; 63 V _value; 64 Node* _next; 65 66 Node(unsigned hash, K const& key, V const& value) : 67 _hash(hash), _key(key), _value(value), _next(NULL) {} 68 }; 69 70 Node* _table[SIZE]; 71 72 // Returns a pointer to where the node where the value would reside if 73 // it's in the table. 74 Node** lookup_node(unsigned hash, K const& key) { 75 unsigned index = hash % SIZE; 76 Node** ptr = &_table[index]; 77 while (*ptr != NULL) { 78 Node* node = *ptr; 79 if (node->_hash == hash && EQUALS(key, node->_key)) { 80 break; 81 } 82 ptr = &(node->_next); 83 } 84 return ptr; 85 } 86 87 Node const** lookup_node(unsigned hash, K const& key) const { 88 return const_cast<Node const**>( 89 const_cast<ResourceHashtable*>(this)->lookup_node(hash, key)); 90 } 91 92 public: 93 ResourceHashtable() { memset(_table, 0, SIZE * sizeof(Node*)); } 94 95 ~ResourceHashtable() { 96 if (ALLOC_TYPE == C_HEAP) { 97 Node* const* bucket = _table; 98 while (bucket < &_table[SIZE]) { 99 Node* node = *bucket; 100 while (node != NULL) { 101 Node* cur = node; 102 node = node->_next; 103 delete cur; 104 } 105 ++bucket; 106 } 107 } 108 } 109 110 bool contains(K const& key) const { 111 return get(key) != NULL; 112 } 113 114 V* get(K const& key) const { 115 unsigned hv = HASH(key); 116 Node const** ptr = lookup_node(hv, key); 117 if (*ptr != NULL) { 118 return const_cast<V*>(&(*ptr)->_value); 119 } else { 120 return NULL; 121 } 122 } 123 124 /** 125 * Inserts or replaces a value in the table. 126 * @return: true: if a new item is added 127 * false: if the item already existed and the value is updated 128 */ 129 bool put(K const& key, V const& value) { 130 unsigned hv = HASH(key); 131 Node** ptr = lookup_node(hv, key); 132 if (*ptr != NULL) { 133 (*ptr)->_value = value; 134 return false; 135 } else { 136 *ptr = new (ALLOC_TYPE, MEM_TYPE) Node(hv, key, value); 137 return true; 138 } 139 } 140 141 bool remove(K const& key) { 142 unsigned hv = HASH(key); 143 Node** ptr = lookup_node(hv, key); 144 145 Node* node = *ptr; 146 if (node != NULL) { 147 *ptr = node->_next; 148 if (ALLOC_TYPE == C_HEAP) { 149 delete node; 150 } 151 return true; 152 } 153 return false; 154 } 155 156 // ITER contains bool do_entry(K const&, V const&), which will be 157 // called for each entry in the table. If do_entry() returns false, 158 // the iteration is cancelled. 159 template<class ITER> 160 void iterate(ITER* iter) const { 161 Node* const* bucket = _table; 162 while (bucket < &_table[SIZE]) { 163 Node* node = *bucket; 164 while (node != NULL) { 165 bool cont = iter->do_entry(node->_key, node->_value); 166 if (!cont) { return; } 167 node = node->_next; 168 } 169 ++bucket; 170 } 171 } 172 173 static size_t node_size() { 174 return sizeof(Node); 175 } 176 }; 177 178 179 #endif // SHARE_VM_UTILITIES_RESOURCEHASH_HPP