github
Advanced Search
  • Home
  • Pricing and Signup
  • Explore GitHub
  • Blog
  • Login

alex14n / CompactHashMap

  • Admin
  • Watch Unwatch
  • Fork
  • Your Fork
  • Pull Request
  • Download Source
    • 6
    • 1
  • Source
  • Commits
  • Network (1)
  • Issues (0)
  • Downloads (0)
  • Wiki (1)
  • Graphs
  • Tree: 8f935e1

click here to add a description

click here to add a homepage

  • Branches (5)
    • bloom-filter
    • defrag
    • hybrid
    • master
    • unsafe
  • Tags (0)
Sending Request…
Enable Donations

Pledgie Donations

Once activated, we'll place the following badge in your repository's detail box:
Pledgie_example
This service is courtesy of Pledgie.

Fast and memory-compact (especially on primitive types) scala HashMap and HashSet — Read more

  cancel

  cancel
  • Private
  • Read-Only
  • HTTP Read-Only

This URL has Read+Write access

proof-of-concept Hybrid map 
alex14n (author)
Tue Jun 09 07:13:54 -0700 2009
commit  8f935e1b5fc7c673e04c93eca2402aada5137b39
tree    31ca6a0fd7b421a657f08450d3c852fcf67be96c
parent  cfc9b2d7062e44e98665dfd1a1c61d6d98a64ad1
CompactHashMap / java / HybridHashMap.java java/HybridHashMap.java
100644 213 lines (203 sloc) 6.23 kb
edit raw blame history
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/**
* Improvement for FastHashMap based on discussion in
* http://mail.openjdk.java.net/pipermail/core-libs-dev/2009-June/001788.html
*
* 1) We don't store null keys in table and handle null keys specially
* thus if keyValueTable entry is null => it's empty
* 2)
*
* @author Doug Lea
* @author Alex Yakovlev
*
* @param <K>
* @param <V>
*/
public class HybridHashMap<K,V>
// implements Cloneable, Serializable, Map<K,V>
{
  boolean hasNullKey;
  V nullValue;
 
  int [] indexTable;
  Object [] keyValueTable;
 
  transient int size;
  public int size() { return size; }
  transient int firstEmptyIndex;
  // transient int firstDeletedIndex;
  int threshold;
  final float loadFactor = FastHashMap.DEFAULT_LOAD_FACTOR;
  transient int hashLen = FastHashMap.DEFAULT_INITIAL_CAPACITY;
 
  /**
* We don't need `deleted' bit here
*/
  final static int AVAILABLE_BITS = 0x7FFFFFFF;
 
  /**
*
*/
  final static int END_OF_LIST = 0x80000000;
 
  void init() {
    threshold = (int)(hashLen * loadFactor);
    // ToDo: separate main and overflow (collisions) parts
    // and allocate them separately or even store it
    // in HashEntry-like structure? or ternary tries?
    indexTable = new int [(hashLen + threshold)];
    keyValueTable = new Object [(hashLen + threshold)<<1];
    firstEmptyIndex = 0;
    // firstDeletedIndex = -1;
    size = hasNullKey ? 1 : 0;
  }
 
  public HybridHashMap() {
    init();
  }
 
  public V get (K key) {
    // Null special case
    if (key == null) {
      return nullValue;
    }
    // Hash index for this key
    int hc = FastHashMap.hash(key);
    int index = hc & (hashLen - 1);
    // Try direct lookup
    Object key1 = keyValueTable[index<<1];
    if (key1 == null) return null;
    if (key1 == key || key.equals(key1))
      return (V)keyValueTable[(index<<1)+1];
    // Look for collisions
    int mask = AVAILABLE_BITS ^ (hashLen-1);
    int i = indexTable[index];
    do {
      if ((i & END_OF_LIST) != 0) return null;
      index = i & (hashLen - 1);
      i = indexTable[hashLen + index];
      if ((i & mask) == (hc & mask)) {
        key1 = keyValueTable[(hashLen + index)<<1];
        if (key1 == key || key.equals(key1)) {
          return (V)keyValueTable[((hashLen + index)<<1)+1];
        }
      }
    } while(true);
  }
 
  public boolean containsKey (K key) {
    if (key == null)
      return hasNullKey;
    else
      // ToDo: null value case?
      return get(key) != null;
  }
 
  public V put (K key, V value) {
    // Null special case
    if (key == null) {
      if (!hasNullKey) {
        hasNullKey = true;
        size++;
      }
      V oldValue = nullValue;
      nullValue = value;
      return oldValue;
    }
    // Hash index
    int hc = FastHashMap.hash(key);
    int index0 = hc & (hashLen - 1);
    // Try direct lookup
    Object key1 = keyValueTable[index0<<1];
    if (key1 == null) {
      keyValueTable[index0<<1] = key;
      keyValueTable[(index0<<1)+1] = value;
      indexTable[index0] = hc | END_OF_LIST; // & AVAILABLE_BITS
      size++;
      // validate();
      return null;
    }
    if (key1 == key || key.equals(key1)) {
      V oldValue = (V)keyValueTable[(index0<<1)+1];
      keyValueTable[(index0<<1)+1] = value;
      return oldValue;
    }
    // Look for collisions
    int mask = AVAILABLE_BITS ^ (hashLen-1);
    int i0 = indexTable[index0];
    int i = i0;
    int index = index0;
    do {
      if ((i & END_OF_LIST) != 0) {
        if (size >= threshold) { // firstEmptyIndex >= threshold ?
          resize();
          return put (key, value);
        }
        // ToDo: deleted index ...
        indexTable[hashLen + firstEmptyIndex] = (hc & mask) | (i0 & ~mask);
        indexTable[index0] = (i0 & mask) | firstEmptyIndex;
        keyValueTable[(hashLen + firstEmptyIndex)<<1] = key;
        keyValueTable[((hashLen + firstEmptyIndex)<<1)+1] = value;
        size++;
        firstEmptyIndex++;
        // validate();
        return null;
      }
      index = i & (hashLen - 1);
      i = indexTable[hashLen + index];
      if ((i & mask) == (hc & mask)) {
        key1 = keyValueTable[(hashLen + index)<<1];
        if (key1 == key || key.equals(key1)) {
          V oldValue = (V)keyValueTable[((hashLen + index)<<1)+1];
          keyValueTable[((hashLen + index)<<1)+1] = value;
          return oldValue;
        }
      }
    } while(true);
  }
/*
V remove (K key) {
// ToDo: implement
return null;
}
*/
  void resize() {
    // ToDo: optimize, current version is very slow
    Object[] oldTable = keyValueTable;
    int len = hashLen + firstEmptyIndex;
    hashLen <<= 1;
    init();
    for (int i = 0; i < len; i++) {
      K key = (K)oldTable[i<<1];
      if (key != null) {
        V value = (V)oldTable[(i<<1)+1];
        put (key, value);
      }
    }
    // validate();
  }
/*
void validate() {
int n = hasNullKey ? 1 : 0;
int mask = AVAILABLE_BITS ^ (hashLen-1);
for (int i = 0; i < hashLen; i++) {
Object key = keyValueTable[i<<1];
if (key != null) {
// Object value = keyValueTable[(i<<1)+1];
// System.out.println("Basket "+key+"="+value);
n++;
int hc = FastHashMap.hash(key);
if ((hc & (hashLen-1)) != i)
throw new RuntimeException("Key "+key+" in wrong hash basket");
int index = indexTable[i];
if((index & mask) != (hc & mask))
throw new RuntimeException("Key "+key+" has wrong hashcode bits");
while ((index & END_OF_LIST) == 0) {
n++;
key = keyValueTable[(hashLen + (index & (hashLen-1)))<<1];
// value = keyValueTable[((hashLen + (index & (hashLen-1)))<<1)+1];
// System.out.println("Overflow "+key+"="+value);
index = indexTable[hashLen + (index & (hashLen-1))];
hc = FastHashMap.hash(key);
if ((hc & (hashLen-1)) != i)
throw new RuntimeException("Overflow key "+key+" in wrong hash basket");
if((index & mask) != (hc & mask))
throw new RuntimeException("Overflow key "+key+" has wrong hashcode bits");
}
}
}
if (n != size)
throw new RuntimeException("Size="+size+", elements="+n+", hasNullKey="+hasNullKey);
}
*/
}
 
Blog | Support | Training | Contact | API | Status | Twitter | Help | Security
© 2010 GitHub Inc. All rights reserved. | Terms of Service | Privacy Policy
Powered by the Dedicated Servers and
Cloud Computing of Rackspace Hosting®
Dedicated Server