Fork of Poseidon providing Bukkit #1060 to older Beta versions (b1.0-b1.7.3)
1package org.bukkit.craftbukkit.util;
2
3import static org.bukkit.craftbukkit.util.Java15Compat.Arrays_copyOf;
4
5import java.util.ArrayList;
6
7import net.minecraft.server.Chunk;
8import net.minecraft.server.MinecraftServer;
9
10import uk.betacraft.uberbukkit.UberbukkitConfig;
11
12public class LongHashtable<V> extends LongHash {
13 Object[][][] values = new Object[256][][];
14 Entry cache = null;
15
16 public void put(int msw, int lsw, V value) {
17 put(toLong(msw, lsw), value);
18 if (value instanceof Chunk) {
19 Chunk c = (Chunk) value;
20 if (msw != c.x || lsw != c.z) {
21 MinecraftServer.log.info("Chunk (" + c.x + ", " + c.z + ") stored at (" + msw + ", " + lsw + ")");
22 Throwable x = new Throwable();
23 x.fillInStackTrace();
24 x.printStackTrace();
25 }
26 }
27 }
28
29 public V get(int msw, int lsw) {
30 V value = get(toLong(msw, lsw));
31 if (value instanceof Chunk) {
32 Chunk c = (Chunk) value;
33 if (msw != c.x || lsw != c.z) {
34 MinecraftServer.log.info("Chunk (" + c.x + ", " + c.z + ") stored at (" + msw + ", " + lsw + ")");
35
36 if (UberbukkitConfig.getInstance().getBoolean("experimental.force_fix_chunk_coords_corruption", false)) {
37 c.x = msw;
38 c.z = lsw;
39 } else {
40 Throwable x = new Throwable();
41 x.fillInStackTrace();
42 x.printStackTrace();
43 }
44 }
45 }
46 return value;
47 }
48
49 public synchronized void put(long key, V value) {
50 int mainIdx = (int) (key & 255);
51 Object[][] outer = this.values[mainIdx];
52 if (outer == null) this.values[mainIdx] = outer = new Object[256][];
53
54 int outerIdx = (int) ((key >> 32) & 255);
55 Object[] inner = outer[outerIdx];
56
57 if (inner == null) {
58 outer[outerIdx] = inner = new Object[5];
59 inner[0] = this.cache = new Entry(key, value);
60 } else {
61 int i;
62 for (i = 0; i < inner.length; i++) {
63 if (inner[i] == null || ((Entry) inner[i]).key == key) {
64 inner[i] = this.cache = new Entry(key, value);
65 return;
66 }
67 }
68
69 outer[outerIdx] = inner = Arrays_copyOf(inner, i + i);
70 inner[i] = new Entry(key, value);
71 }
72 }
73
74 public synchronized V get(long key) {
75 return containsKey(key) ? (V) cache.value : null;
76 }
77
78 public synchronized boolean containsKey(long key) {
79 if (this.cache != null && cache.key == key) return true;
80
81 int outerIdx = (int) ((key >> 32) & 255);
82 Object[][] outer = this.values[(int) (key & 255)];
83 if (outer == null) return false;
84
85 Object[] inner = outer[outerIdx];
86 if (inner == null) return false;
87
88 for (int i = 0; i < inner.length; i++) {
89 Entry e = (Entry) inner[i];
90 if (e == null) {
91 return false;
92 } else if (e.key == key) {
93 this.cache = e;
94 return true;
95 }
96 }
97 return false;
98 }
99
100 public synchronized void remove(long key) {
101 Object[][] outer = this.values[(int) (key & 255)];
102 if (outer == null) return;
103
104 Object[] inner = outer[(int) ((key >> 32) & 255)];
105 if (inner == null) return;
106
107 for (int i = 0; i < inner.length; i++) {
108 if (inner[i] == null) continue;
109
110 if (((Entry) inner[i]).key == key) {
111 for (i++; i < inner.length; i++) {
112 if (inner[i] == null) break;
113 inner[i - 1] = inner[i];
114 }
115
116 inner[i - 1] = null;
117 this.cache = null;
118 return;
119 }
120 }
121 }
122
123 public synchronized ArrayList<V> values() {
124 ArrayList<V> ret = new ArrayList<V>();
125
126 for (Object[][] outer : this.values) {
127 if (outer == null) continue;
128
129 for (Object[] inner : outer) {
130 if (inner == null) continue;
131
132 for (Object entry : inner) {
133 if (entry == null) break;
134
135 ret.add((V) ((Entry) entry).value);
136 }
137 }
138 }
139 return ret;
140 }
141
142 private class Entry {
143 long key;
144 Object value;
145
146 Entry(long k, Object v) {
147 this.key = k;
148 this.value = v;
149 }
150 }
151}