code_junkie

2-D (concurrent) HashMap: 2-property key type hashmap of hashmaps [update]

Nov 14th, 2011
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.75 KB | None | 0 0
  1. import java.io.*;
  2. import java.util.*;
  3.  
  4. public class Int2DMap implements Map, Serializable {
  5. private static final int DEFAULT_INITIAL_CAPACITY = 16;
  6. private static final int MAXIMUM_CAPACITY = 1 << 30;
  7. private static final float DEFAULT_LOAD_FACTOR = 0.75f;
  8. protected Entry[] table;
  9. protected int size;
  10. protected int threshold;
  11. protected float loadFactor;
  12. protected transient volatile int modCount;
  13.  
  14. public Int2DMap(int initialCapacity, float loadFactor) {
  15. if (initialCapacity < 0)
  16. throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
  17. if (initialCapacity > MAXIMUM_CAPACITY)
  18. initialCapacity = MAXIMUM_CAPACITY;
  19. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  20. throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
  21. // Find a power of 2 >= initialCapacity
  22. int capacity = 1;
  23. while (capacity < initialCapacity) {
  24. capacity <<= 1;
  25. }
  26. this.loadFactor = loadFactor;
  27. this.threshold = (int) (capacity * loadFactor);
  28. this.table = new Entry[capacity];
  29. }
  30.  
  31. public Int2DMap(int initialCapacity) {
  32. this(initialCapacity, DEFAULT_LOAD_FACTOR);
  33. }
  34.  
  35. public Int2DMap() {
  36. this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
  37. }
  38.  
  39. public boolean containsKey(Object key) {
  40. int[] xy = (int[]) key;
  41. return containsKey(xy[0], xy[1]);
  42. }
  43.  
  44. public Object get(Object key) {
  45. int[] xy = (int[]) key;
  46. return get(xy[0], xy[1]);
  47. }
  48.  
  49. public Object put(Object key, Object value) {
  50. int[] xy = (int[]) key;
  51. return put(xy[0], xy[1], value);
  52. }
  53.  
  54. public Object remove(Object key) {
  55. int[] xy = (int[]) key;
  56. return remove(xy[0], xy[1]);
  57. }
  58.  
  59. public int size() {
  60. return size;
  61. }
  62.  
  63. public boolean isEmpty() {
  64. return size == 0;
  65. }
  66.  
  67. protected static final int indexFor(int x, int y, int length) {
  68. return (x * 31 + y) & (length - 1);
  69. }
  70.  
  71. public Object get(int x, int y) {
  72. for (Entry e = table[indexFor(x, y, table.length)]; e != null; e = e.next) {
  73. if (e.x == x && e.y == y) {
  74. return e.value;
  75. }
  76. }
  77. return null;
  78. }
  79.  
  80. public boolean containsKey(int x, int y) {
  81. return getEntry(x, y) != null;
  82. }
  83.  
  84. protected Entry getEntry(int x, int y) {
  85. for (Entry e = table[indexFor(x, y, table.length)]; e != null; e = e.next) {
  86. if (e.x == x && e.y == y) {
  87. return e;
  88. }
  89. }
  90. return null;
  91. }
  92.  
  93. public Object put(int x, int y, Object value) {
  94. int i = indexFor(x, y, table.length);
  95. for (Entry e = table[i]; e != null; e = e.next) {
  96. if (e.x == x && e.y == y) {
  97. Object oldValue = e.value;
  98. e.value = value;
  99. e.recordAccess(this);
  100. return oldValue;
  101. }
  102. }
  103. modCount++;
  104. addEntry(x, y, value, i);
  105. return null;
  106. }
  107.  
  108. protected void resize(int newCapacity) {
  109. Entry[] oldTable = table;
  110. int oldCapacity = oldTable.length;
  111. if (oldCapacity == MAXIMUM_CAPACITY) {
  112. threshold = Integer.MAX_VALUE;
  113. return;
  114. }
  115. Entry[] newTable = new Entry[newCapacity];
  116. transfer(newTable);
  117. table = newTable;
  118. threshold = (int) (newCapacity * loadFactor);
  119. }
  120.  
  121. protected void transfer(Entry[] newTable) {
  122. Entry[] src = table;
  123. int newCapacity = newTable.length;
  124. for (int j = 0; j < src.length; j++) {
  125. Entry e = src[j];
  126. if (e != null) {
  127. src[j] = null;
  128. do {
  129. Entry next = e.next;
  130. int i = indexFor(e.x, e.y, newCapacity);
  131. e.next = newTable[i];
  132. newTable[i] = e;
  133. e = next;
  134. } while (e != null);
  135. }
  136. }
  137. }
  138.  
  139. public void putAll(Map m) {
  140. int numKeysToBeAdded = m.size();
  141. if (numKeysToBeAdded == 0) {
  142. return;
  143. }
  144. if (numKeysToBeAdded > threshold) {
  145. int targetCapacity = (int) (numKeysToBeAdded / loadFactor + 1);
  146. if (targetCapacity > MAXIMUM_CAPACITY)
  147. targetCapacity = MAXIMUM_CAPACITY;
  148. int newCapacity = table.length;
  149. while (newCapacity < targetCapacity)
  150. newCapacity <<= 1;
  151. if (newCapacity > table.length)
  152. resize(newCapacity);
  153. }
  154. for (Iterator i = m.entrySet().iterator(); i.hasNext();) {
  155. Map.Entry e = (Map.Entry) i.next();
  156. put(e.getKey(), e.getValue());
  157. }
  158. }
  159.  
  160. public Object remove(int x, int y) {
  161. Entry e = removeEntryForKey(x, y);
  162. return (e == null ? null : e.value);
  163. }
  164.  
  165. protected Entry removeEntryForKey(int x, int y) {
  166. int i = indexFor(x, y, table.length);
  167. Entry prev = table[i];
  168. Entry e = prev;
  169. while (e != null) {
  170. Entry next = e.next;
  171. Object k;
  172. if (e.x == x && e.y == y) {
  173. modCount++;
  174. size--;
  175. if (prev == e)
  176. table[i] = next;
  177. else
  178. prev.next = next;
  179. e.recordRemoval(this);
  180. return e;
  181. }
  182. prev = e;
  183. e = next;
  184. }
  185. return e;
  186. }
  187.  
  188. protected Entry removeMapping(Object o) {
  189. if (!(o instanceof Entry))
  190. return null;
  191. Entry entry = (Entry) o;
  192. int x = entry.x;
  193. int y = entry.y;
  194. int i = indexFor(x, y, table.length);
  195. Entry prev = table[i];
  196. Entry e = prev;
  197. while (e != null) {
  198. Entry next = e.next;
  199. if (e.x == x && e.y == y) {
  200. modCount++;
  201. size--;
  202. if (prev == e)
  203. table[i] = next;
  204. else
  205. prev.next = next;
  206. e.recordRemoval(this);
  207. return e;
  208. }
  209. prev = e;
  210. e = next;
  211. }
  212. return e;
  213. }
  214.  
  215. public void clear() {
  216. modCount++;
  217. Entry[] tab = table;
  218. for (int i = 0; i < tab.length; i++)
  219. tab[i] = null;
  220. size = 0;
  221. }
  222.  
  223. public boolean containsValue(Object value) {
  224. Entry[] tab = table;
  225. for (int i = 0; i < tab.length; i++)
  226. for (Entry e = tab[i]; e != null; e = e.next)
  227. if (value.equals(e.value))
  228. return true;
  229. return false;
  230. }
  231.  
  232. static class Entry implements Map.Entry {
  233. final int x;
  234. final int y;
  235. Object value;
  236. Entry next;
  237.  
  238. Entry(int x, int y, Object value, Entry next) {
  239. this.x = x;
  240. this.y = y;
  241. this.value = value;
  242. this.next = next;
  243. }
  244.  
  245. public final Object getKey() {
  246. return new int[] { x, y };
  247. }
  248.  
  249. public final Object getValue() {
  250. return value;
  251. }
  252.  
  253. public final Object setValue(Object newValue) {
  254. Object oldValue = value;
  255. value = newValue;
  256. return oldValue;
  257. }
  258.  
  259. public final boolean equals(Object o) {
  260. if (!(o instanceof Map.Entry))
  261. return false;
  262. Map.Entry e = (Map.Entry) o;
  263. int[] xy = (int[])e.getKey();
  264. if (x == xy[0] && y == xy[1]) {
  265. Object v1 = getValue();
  266. Object v2 = e.getValue();
  267. if (v1 == v2 || (v1 != null && v1.equals(v2)))
  268. return true;
  269. }
  270. return false;
  271. }
  272.  
  273. public final int hashCode() {
  274. return ((31 + x) * 31 + y);
  275. }
  276.  
  277. public final String toString() {
  278. return "[" + x + ", " + y + "]=" + value;
  279. }
  280.  
  281. /**
  282. * This method is invoked whenever the value in an entry is overwritten by
  283. * an invocation of put(k,v) for a key k that's already in the HashMap.
  284. */
  285. void recordAccess(Int2DMap m) {
  286. }
  287.  
  288. /**
  289. * This method is invoked whenever the entry is removed from the table.
  290. */
  291. void recordRemoval(Int2DMap m) {
  292. }
  293. }
  294.  
  295. void addEntry(int x, int y, Object value, int bucketIndex) {
  296. Entry e = table[bucketIndex];
  297. table[bucketIndex] = new Entry(x, y, value, e);
  298. if (size++ >= threshold)
  299. resize(2 * table.length);
  300. }
  301.  
  302.  
  303. private abstract class HashIterator implements Iterator {
  304. Entry next; // next entry to return
  305. int expectedModCount; // For fast-fail
  306. int index; // current slot
  307. Entry current; // current entry
  308.  
  309. HashIterator() {
  310. expectedModCount = modCount;
  311. if (size > 0) { // advance to first entry
  312. Entry[] t = table;
  313. while (index < t.length && (next = t[index++]) == null)
  314. ;
  315. }
  316. }
  317.  
  318. public final boolean hasNext() {
  319. return next != null;
  320. }
  321.  
  322. final Entry nextEntry() {
  323. if (modCount != expectedModCount)
  324. throw new ConcurrentModificationException();
  325. Entry e = current = next;
  326. if (e == null)
  327. throw new NoSuchElementException();
  328. if ((next = e.next) == null) {
  329. Entry[] t = table;
  330. while (index < t.length && (next = t[index++]) == null)
  331. ;
  332. }
  333. return e;
  334. }
  335.  
  336. public void remove() {
  337. if (current == null)
  338. throw new IllegalStateException();
  339. if (modCount != expectedModCount)
  340. throw new ConcurrentModificationException();
  341. int x = current.x;
  342. int y = current.y;
  343. current = null;
  344. Int2DMap.this.removeEntryForKey(x, y);
  345. expectedModCount = modCount;
  346. }
  347. }
  348.  
  349. private final class ValueIterator extends HashIterator {
  350. public Object next() {
  351. return nextEntry().value;
  352. }
  353. }
  354.  
  355. private final class KeyIterator extends HashIterator {
  356. public Object next() {
  357. return nextEntry().getKey();
  358. }
  359. }
  360.  
  361. private final class EntryIterator extends HashIterator {
  362. public Map.Entry next() {
  363. return nextEntry();
  364. }
  365. }
  366.  
  367. // Subclass overrides these to alter behavior of views' iterator() method
  368. Iterator newKeyIterator() {
  369. return new KeyIterator();
  370. }
  371.  
  372. Iterator newValueIterator() {
  373. return new ValueIterator();
  374. }
  375.  
  376. Iterator newEntryIterator() {
  377. return new EntryIterator();
  378. }
  379.  
  380. public Set keySet() {
  381. return new KeySet();
  382. }
  383.  
  384. private final class KeySet extends AbstractSet {
  385. public Iterator iterator() {
  386. return newKeyIterator();
  387. }
  388.  
  389. public int size() {
  390. return size;
  391. }
  392.  
  393. public boolean contains(Object o) {
  394. return containsKey(o);
  395. }
  396.  
  397. public boolean remove(Object o) {
  398. int[] xy = (int[]) o;
  399. return Int2DMap.this.removeEntryForKey(xy[0], xy[1]) != null;
  400. }
  401.  
  402. public void clear() {
  403. Int2DMap.this.clear();
  404. }
  405. }
  406.  
  407. public Collection values() {
  408. return new Values();
  409. }
  410.  
  411. private final class Values extends AbstractCollection {
  412. public Iterator iterator() {
  413. return newValueIterator();
  414. }
  415.  
  416. public int size() {
  417. return size;
  418. }
  419.  
  420. public boolean contains(Object o) {
  421. return containsValue(o);
  422. }
  423.  
  424. public void clear() {
  425. Int2DMap.this.clear();
  426. }
  427. }
  428.  
  429. public Set entrySet() {
  430. return new EntrySet();
  431. }
  432.  
  433. private final class EntrySet extends AbstractSet {
  434.  
  435. public Iterator iterator() {
  436. return newEntryIterator();
  437. }
  438.  
  439. public boolean contains(Object o) {
  440. if (!(o instanceof Map.Entry))
  441. return false;
  442. Entry e = (Entry) o;
  443. Entry candidate = getEntry(e.x, e.y);
  444. return candidate != null && candidate.equals(e);
  445. }
  446.  
  447. public boolean remove(Object o) {
  448. return removeMapping(o) != null;
  449. }
  450.  
  451. public int size() {
  452. return size;
  453. }
  454.  
  455. public void clear() {
  456. Int2DMap.this.clear();
  457. }
  458. }
  459.  
  460. public static void main(String[] args) {
  461. try {
  462.  
  463. Int2DMap map = new Int2DMap();
  464.  
  465. map.put(20, 6000, "Test");
  466. System.out.println(map.size() == 1);
  467.  
  468. System.out.println(map.get(20, 6000) != null);
  469.  
  470. System.out.println("Test".equals(map.get(20, 6000)));
  471.  
  472. for (Iterator iter = map.values().iterator(); iter.hasNext();) {
  473. System.out.println("Test".equals(iter.next()));
  474. }
  475.  
  476. for (Iterator iter = map.keySet().iterator(); iter.hasNext();) {
  477. int[] key = (int[])iter.next();
  478. System.out.println(key[0] == 20 && key[1] == 6000);
  479. }
  480.  
  481. for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
  482. Map.Entry e = (Map.Entry)iter.next();
  483. System.out.println(e.toString().equals("[20, 6000]=Test"));
  484. }
  485.  
  486. map.remove(20, 6000);
  487. System.out.println(map.size() == 0 && map.get(20, 6000) == null);
  488.  
  489.  
  490. long start = System.nanoTime();
  491. int max = 40000000;
  492. for (int i = 0; i < 500000; i++) {
  493. int x = (int)(Math.random() * max);
  494. int y = (int)(Math.random() * max);
  495. map.put(x, y, "");
  496.  
  497. int x2 = (int)(Math.random() * max);
  498. int y2 = (int)(Math.random() * max);
  499. Object o = map.get(x2, y2);
  500.  
  501. }
  502. System.out.println(map.size());
  503. System.out.println((System.nanoTime() - start) / 1000000);
  504.  
  505.  
  506. Map map2 = new HashMap();
  507. start = System.nanoTime();
  508.  
  509. for (int i = 0; i < 500000; i++) {
  510. String key = "" + (int)(Math.random() * max) + "," + (int)(Math.random() * max);
  511. map2.put(key, "");
  512.  
  513. String key2 = "" + (int)(Math.random() * max) + "," + (int)(Math.random() * max);
  514. Object o = map2.get(key2);
  515.  
  516. }
  517. System.out.println(map2.size());
  518. System.out.println((System.nanoTime() - start) / 1000000);
  519.  
  520.  
  521. } catch (Throwable t) {
  522. t.printStackTrace();
  523. }
  524. }
  525. }
Add Comment
Please, Sign In to add comment