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
30template<typename K> struct ResourceHashtableFns {
31    typedef unsigned (*hash_fn)(K const&);
32    typedef bool (*equals_fn)(K const&, K const&);
33};
34
35template<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
40template<typename K> bool primitive_equals(const K& k0, const K& k1) {
41  return k0 == k1;
42}
43
44template<
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    >
56class 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
180