1 /*
   2  * Copyright (c) 2012, 2018, 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<
  36     typename K, typename V,
  37     // xlC does not compile this:
  38     // http://stackoverflow.com/questions/8532961/template-argument-of-type-that-is-defined-by-inner-typedef-from-other-template-c
  39     //typename ResourceHashtableFns<K>::hash_fn   HASH   = primitive_hash<K>,
  40     //typename ResourceHashtableFns<K>::equals_fn EQUALS = primitive_equals<K>,
  41     unsigned (*HASH)  (K const&)           = primitive_hash<K>,
  42     bool     (*EQUALS)(K const&, K const&) = primitive_equals<K>,
  43     unsigned SIZE = 256,
  44     ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA,
  45     MEMFLAGS MEM_TYPE = mtInternal
  46     >
  47 class ResourceHashtable : public ResourceObj {
  48  private:
  49 
  50   class Node : public ResourceObj {
  51    public:
  52     unsigned _hash;
  53     K _key;
  54     V _value;
  55     Node* _next;
  56 
  57     Node(unsigned hash, K const& key, V const& value) :
  58         _hash(hash), _key(key), _value(value), _next(NULL) {}
  59   };
  60 
  61   Node* _table[SIZE];
  62 
  63   // Returns a pointer to where the node where the value would reside if
  64   // it's in the table.
  65   Node** lookup_node(unsigned hash, K const& key) {
  66     unsigned index = hash % SIZE;
  67     Node** ptr = &_table[index];
  68     while (*ptr != NULL) {
  69       Node* node = *ptr;
  70       if (node->_hash == hash && EQUALS(key, node->_key)) {
  71         break;
  72       }
  73       ptr = &(node->_next);
  74     }
  75     return ptr;
  76   }
  77 
  78   Node const** lookup_node(unsigned hash, K const& key) const {
  79     return const_cast<Node const**>(
  80         const_cast<ResourceHashtable*>(this)->lookup_node(hash, key));
  81   }
  82 
  83  public:
  84   ResourceHashtable() { memset(_table, 0, SIZE * sizeof(Node*)); }
  85 
  86   ~ResourceHashtable() {
  87     if (ALLOC_TYPE == C_HEAP) {
  88       Node* const* bucket = _table;
  89       while (bucket < &_table[SIZE]) {
  90         Node* node = *bucket;
  91         while (node != NULL) {
  92           Node* cur = node;
  93           node = node->_next;
  94           delete cur;
  95         }
  96         ++bucket;
  97       }
  98     }
  99   }
 100 
 101   bool contains(K const& key) const {
 102     return get(key) != NULL;
 103   }
 104 
 105   V* get(K const& key) const {
 106     unsigned hv = HASH(key);
 107     Node const** ptr = lookup_node(hv, key);
 108     if (*ptr != NULL) {
 109       return const_cast<V*>(&(*ptr)->_value);
 110     } else {
 111       return NULL;
 112     }
 113   }
 114 
 115  /**
 116   * Inserts or replaces a value in the table.
 117   * @return: true:  if a new item is added
 118   *          false: if the item already existed and the value is updated
 119   */
 120   bool put(K const& key, V const& value) {
 121     unsigned hv = HASH(key);
 122     Node** ptr = lookup_node(hv, key);
 123     if (*ptr != NULL) {
 124       (*ptr)->_value = value;
 125       return false;
 126     } else {
 127       *ptr = new (ALLOC_TYPE, MEM_TYPE) Node(hv, key, value);
 128       return true;
 129     }
 130   }
 131 
 132   bool remove(K const& key) {
 133     unsigned hv = HASH(key);
 134     Node** ptr = lookup_node(hv, key);
 135 
 136     Node* node = *ptr;
 137     if (node != NULL) {
 138       *ptr = node->_next;
 139       if (ALLOC_TYPE == C_HEAP) {
 140         delete node;
 141       }
 142       return true;
 143     }
 144     return false;
 145   }
 146 
 147   // ITER contains bool do_entry(K const&, V const&), which will be
 148   // called for each entry in the table.  If do_entry() returns false,
 149   // the iteration is cancelled.
 150   template<class ITER>
 151   void iterate(ITER* iter) const {
 152     Node* const* bucket = _table;
 153     while (bucket < &_table[SIZE]) {
 154       Node* node = *bucket;
 155       while (node != NULL) {
 156         bool cont = iter->do_entry(node->_key, node->_value);
 157         if (!cont) { return; }
 158         node = node->_next;
 159       }
 160       ++bucket;
 161     }
 162   }
 163 
 164   static size_t node_size() {
 165     return sizeof(Node);
 166   }
 167 };
 168 
 169 
 170 #endif // SHARE_VM_UTILITIES_RESOURCEHASH_HPP