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