Skip to content

Commit 062ee88

Browse files
committed
remove nodeType from Branch nodes (its hardly used)
this reduces the retained memory of nodes (4 or 8 bytes per Mode)
1 parent 5489517 commit 062ee88

10 files changed

Lines changed: 141 additions & 144 deletions

File tree

roaringbitmap/src/main/java/org/roaringbitmap/art/Art.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,9 @@ private Node insert(Node node, byte[] key, int depth, long containerIdx) {
227227
node4.prefixLength = (byte) commonPrefix;
228228
System.arraycopy(key, depth, node4.prefix, 0, commonPrefix);
229229
// generate two leaf nodes as the children of the fresh node4
230-
Node4.insert(node4, leafNode, prefix[depth + commonPrefix]);
230+
node4.insert(leafNode, prefix[depth + commonPrefix]);
231231
LeafNode anotherLeaf = new LeafNode(key, containerIdx);
232-
Node4.insert(node4, anotherLeaf, key[depth + commonPrefix]);
232+
node4.insert(anotherLeaf, key[depth + commonPrefix]);
233233
// replace the current node with this internal node4
234234
return node4;
235235
}
@@ -246,7 +246,7 @@ private Node insert(Node node, byte[] key, int depth, long containerIdx) {
246246
System.arraycopy(branchNode.prefix, 0, node4.prefix, 0, mismatchPos);
247247
// split the current internal node, spawn a fresh node4 and let the
248248
// current internal node as its children.
249-
Node4.insert(node4, branchNode, branchNode.prefix[mismatchPos]);
249+
node4.insert(branchNode, branchNode.prefix[mismatchPos]);
250250
int nodeOriginalPrefixLength = branchNode.prefixLength;
251251
branchNode.prefixLength = (byte) (nodeOriginalPrefixLength - (mismatchPos + (byte) 1));
252252
// move the remained common prefix of the initial internal node
@@ -256,7 +256,7 @@ private Node insert(Node node, byte[] key, int depth, long containerIdx) {
256256
branchNode.prefix = EMPTY_BYTES;
257257
}
258258
LeafNode leafNode = new LeafNode(key, containerIdx);
259-
Node4.insert(node4, leafNode, key[mismatchPos + depth]);
259+
node4.insert(leafNode, key[mismatchPos + depth]);
260260
return node4;
261261
}
262262
depth += branchNode.prefixLength;
@@ -273,8 +273,7 @@ private Node insert(Node node, byte[] key, int depth, long containerIdx) {
273273
}
274274
// insert the key as a child leaf node of the current internal node
275275
LeafNode leafNode = new LeafNode(key, containerIdx);
276-
Node freshOne = BranchNode.insertLeaf(branchNode, leafNode, key[depth]);
277-
return freshOne;
276+
return branchNode.insert(leafNode, key[depth]);
278277
}
279278

280279
// find common prefix length

roaringbitmap/src/main/java/org/roaringbitmap/art/BranchNode.java

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
public abstract class BranchNode extends Node {
88

9-
// node type
10-
protected NodeType nodeType;
119
// length of compressed path(prefix)
1210
protected byte prefixLength;
1311
// the compressed path path (prefix)
@@ -20,16 +18,15 @@ public abstract class BranchNode extends Node {
2018
/**
2119
* constructor
2220
*
23-
* @param nodeType the node type
2421
* @param compressedPrefixSize the prefix byte array size,less than or equal to 6
2522
*/
26-
public BranchNode(NodeType nodeType, int compressedPrefixSize) {
23+
public BranchNode(int compressedPrefixSize) {
2724
super();
28-
this.nodeType = nodeType;
2925
this.prefixLength = (byte) compressedPrefixSize;
3026
prefix = new byte[prefixLength];
3127
count = 0;
3228
}
29+
protected abstract NodeType nodeType();
3330

3431
/**
3532
* search the position of the input byte key in the node's key byte array part
@@ -90,26 +87,11 @@ static SearchResult binarySearchWithResult(byte[] key, int fromIndex, int toInde
9087
/**
9188
* insert the LeafNode as a child of the current internal node
9289
*
93-
* @param current current internal node
9490
* @param childNode the leaf node
9591
* @param key the key byte reference to the child leaf node
9692
* @return an adaptive changed node of the input 'current' node
9793
*/
98-
public static BranchNode insertLeaf(BranchNode current, Node childNode, byte key) {
99-
switch (current.nodeType) {
100-
case NODE4:
101-
return Node4.insert(current, childNode, key);
102-
case NODE16:
103-
return Node16.insert(current, childNode, key);
104-
case NODE48:
105-
return Node48.insert(current, childNode, key);
106-
case NODE256:
107-
return Node256.insert(current, childNode, key);
108-
default:
109-
throw new IllegalArgumentException("Not supported node type!");
110-
}
111-
}
112-
94+
protected abstract BranchNode insert(Node childNode, byte key);
11395
/**
11496
* copy the prefix between two nodes
11597
*
@@ -213,7 +195,7 @@ public static void copyPrefix(BranchNode src, BranchNode dst) {
213195
@Override
214196
protected void serializeHeader(DataOutput dataOutput) throws IOException {
215197
// first byte: node type
216-
dataOutput.writeByte((byte) this.nodeType.ordinal());
198+
dataOutput.writeByte((byte) this.nodeType().ordinal());
217199
// non null object count
218200
dataOutput.writeShort(Short.reverseBytes(this.count));
219201
dataOutput.writeByte(this.prefixLength);
@@ -224,7 +206,7 @@ protected void serializeHeader(DataOutput dataOutput) throws IOException {
224206

225207
@Override
226208
protected void serializeHeader(ByteBuffer byteBuffer) throws IOException {
227-
byteBuffer.put((byte) this.nodeType.ordinal());
209+
byteBuffer.put((byte) this.nodeType().ordinal());
228210
byteBuffer.putShort(this.count);
229211
byteBuffer.put(this.prefixLength);
230212
if (prefixLength > 0) {

roaringbitmap/src/main/java/org/roaringbitmap/art/Node16.java

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ public class Node16 extends BranchNode {
1515
Node[] children = new Node[16];
1616

1717
public Node16(int compressionLength) {
18-
super(NodeType.NODE16, compressionLength);
18+
super(compressionLength);
19+
}
20+
21+
@Override
22+
protected NodeType nodeType() {
23+
return NodeType.NODE16;
1924
}
2025

2126
@Override
@@ -139,53 +144,52 @@ public int getNextSmallerPos(int pos) {
139144
/**
140145
* insert a child into the node with the key byte
141146
*
142-
* @param node the node16 to insert into
143147
* @param child the child node to be inserted
144148
* @param key the key byte
145149
* @return the adaptive changed node of the parent node16
146150
*/
147-
public static BranchNode insert(BranchNode node, Node child, byte key) {
148-
Node16 currentNode16 = (Node16) node;
149-
if (currentNode16.count < 8) {
151+
@Override
152+
protected BranchNode insert(Node child, byte key) {
153+
if (this.count < 8) {
150154
// first
151-
byte[] bytes = LongUtils.toBDBytes(currentNode16.firstV);
152-
bytes[currentNode16.count] = key;
153-
currentNode16.children[currentNode16.count] = child;
154-
sortSmallByteArray(bytes, currentNode16.children, 0, currentNode16.count);
155-
currentNode16.count++;
156-
currentNode16.firstV = LongUtils.fromBDBytes(bytes);
157-
return currentNode16;
158-
} else if (currentNode16.count < 16) {
155+
byte[] bytes = LongUtils.toBDBytes(this.firstV);
156+
bytes[this.count] = key;
157+
this.children[this.count] = child;
158+
sortSmallByteArray(bytes, this.children, 0, this.count);
159+
this.count++;
160+
this.firstV = LongUtils.fromBDBytes(bytes);
161+
return this;
162+
} else if (this.count < 16) {
159163
// second
160164
ByteBuffer byteBuffer = ByteBuffer.allocate(16).order(ByteOrder.BIG_ENDIAN);
161-
byteBuffer.putLong(currentNode16.firstV);
162-
byteBuffer.putLong(currentNode16.secondV);
163-
byteBuffer.put(currentNode16.count, key);
164-
currentNode16.children[currentNode16.count] = child;
165-
sortSmallByteArray(byteBuffer.array(), currentNode16.children, 0, currentNode16.count);
166-
currentNode16.count++;
167-
currentNode16.firstV = byteBuffer.getLong(0);
168-
currentNode16.secondV = byteBuffer.getLong(8);
169-
return currentNode16;
165+
byteBuffer.putLong(this.firstV);
166+
byteBuffer.putLong(this.secondV);
167+
byteBuffer.put(this.count, key);
168+
this.children[this.count] = child;
169+
sortSmallByteArray(byteBuffer.array(), this.children, 0, this.count);
170+
this.count++;
171+
this.firstV = byteBuffer.getLong(0);
172+
this.secondV = byteBuffer.getLong(8);
173+
return this;
170174
} else {
171-
Node48 node48 = new Node48(currentNode16.prefixLength);
175+
Node48 node48 = new Node48(this.prefixLength);
172176
for (int i = 0; i < 8; i++) {
173-
int unsignedIdx = Byte.toUnsignedInt((byte) (currentNode16.firstV >>> ((7 - i) << 3)));
177+
int unsignedIdx = Byte.toUnsignedInt((byte) (this.firstV >>> ((7 - i) << 3)));
174178
// i won't be beyond 48
175179
Node48.setOneByte(unsignedIdx, (byte) i, node48.childIndex);
176-
node48.children[i] = currentNode16.children[i];
180+
node48.children[i] = this.children[i];
177181
}
178-
byte[] secondBytes = LongUtils.toBDBytes(currentNode16.secondV);
179-
for (int i = 8; i < currentNode16.count; i++) {
182+
byte[] secondBytes = LongUtils.toBDBytes(this.secondV);
183+
for (int i = 8; i < this.count; i++) {
180184
byte v = secondBytes[i - 8];
181185
int unsignedIdx = Byte.toUnsignedInt(v);
182186
// i won't be beyond 48
183187
Node48.setOneByte(unsignedIdx, (byte) i, node48.childIndex);
184-
node48.children[i] = currentNode16.children[i];
188+
node48.children[i] = this.children[i];
185189
}
186-
copyPrefix(currentNode16, node48);
187-
node48.count = currentNode16.count;
188-
BranchNode freshOne = Node48.insert(node48, child, key);
190+
copyPrefix(this, node48);
191+
node48.count = this.count;
192+
BranchNode freshOne = node48.insert(child, key);
189193
return freshOne;
190194
}
191195
}

roaringbitmap/src/main/java/org/roaringbitmap/art/Node256.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ public class Node256 extends BranchNode {
1616
private static final long LONG_MASK = 0xffffffffffffffffL;
1717

1818
public Node256(int compressedPrefixSize) {
19-
super(NodeType.NODE256, compressedPrefixSize);
19+
super(compressedPrefixSize);
20+
}
21+
22+
@Override
23+
protected NodeType nodeType() {
24+
return NodeType.NODE256;
2025
}
2126

2227
@Override
@@ -126,18 +131,17 @@ public int getNextSmallerPos(int pos) {
126131
/**
127132
* insert the child node into the node256 node with the key byte
128133
*
129-
* @param currentNode the node256
130134
* @param child the child node
131135
* @param key the key byte
132136
* @return the node256 node
133137
*/
134-
public static Node256 insert(Node currentNode, Node child, byte key) {
135-
Node256 node256 = (Node256) currentNode;
136-
node256.count++;
138+
@Override
139+
protected Node256 insert(Node child, byte key) {
140+
this.count++;
137141
int i = Byte.toUnsignedInt(key);
138-
node256.children[i] = child;
139-
setBit(key, node256.bitmapMask);
140-
return node256;
142+
this.children[i] = child;
143+
setBit(key, this.bitmapMask);
144+
return this;
141145
}
142146

143147
static void setBit(byte key, long[] bitmapMask) {

roaringbitmap/src/main/java/org/roaringbitmap/art/Node4.java

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ public class Node4 extends BranchNode {
1414
Node[] children = new Node[4];
1515

1616
public Node4(int compressedPrefixSize) {
17-
super(NodeType.NODE4, compressedPrefixSize);
17+
super(compressedPrefixSize);
18+
}
19+
20+
@Override
21+
protected NodeType nodeType() {
22+
return NodeType.NODE4;
1823
}
1924

2025
@Override
@@ -81,30 +86,29 @@ public int getNextSmallerPos(int pos) {
8186
}
8287

8388
/**
84-
* insert the child node into the node4 with the key byte
89+
* insert the child node into this with the key byte
8590
*
86-
* @param node the node4 to insert into
8791
* @param childNode the child node
8892
* @param key the key byte
8993
* @return the input node4 or an adaptive generated node16
9094
*/
91-
public static BranchNode insert(BranchNode node, Node childNode, byte key) {
92-
Node4 current = (Node4) node;
93-
if (current.count < 4) {
95+
@Override
96+
protected BranchNode insert(Node childNode, byte key) {
97+
if (this.count < 4) {
9498
// insert leaf into current node
95-
current.key = IntegerUtil.setByte(current.key, key, current.count);
96-
current.children[current.count] = childNode;
97-
current.count++;
98-
insertionSort(current);
99-
return current;
99+
this.key = IntegerUtil.setByte(this.key, key, this.count);
100+
this.children[this.count] = childNode;
101+
this.count++;
102+
insertionSort(this);
103+
return this;
100104
} else {
101105
// grow to Node16
102-
Node16 node16 = new Node16(current.prefixLength);
106+
Node16 node16 = new Node16(this.prefixLength);
103107
node16.count = 4;
104-
node16.firstV = LongUtils.initWithFirst4Byte(current.key);
105-
System.arraycopy(current.children, 0, node16.children, 0, 4);
106-
copyPrefix(current, node16);
107-
BranchNode freshOne = Node16.insert(node16, childNode, key);
108+
node16.firstV = LongUtils.initWithFirst4Byte(this.key);
109+
System.arraycopy(children, 0, node16.children, 0, 4);
110+
copyPrefix(this, node16);
111+
BranchNode freshOne = node16.insert(childNode, key);
108112
return freshOne;
109113
}
110114
}

roaringbitmap/src/main/java/org/roaringbitmap/art/Node48.java

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@ public class Node48 extends BranchNode {
2222
static final long INIT_LONG_VALUE = 0xFFffFFffFFffFFffL;
2323

2424
public Node48(int compressedPrefixSize) {
25-
super(NodeType.NODE48, compressedPrefixSize);
25+
super(compressedPrefixSize);
2626
Arrays.fill(childIndex, INIT_LONG_VALUE);
2727
}
2828

29+
@Override
30+
protected NodeType nodeType() {
31+
return NodeType.NODE48;
32+
}
33+
2934
@Override
3035
public int getChildPos(byte k) {
3136
int unsignedIdx = Byte.toUnsignedInt(k);
@@ -168,39 +173,38 @@ public int getNextSmallerPos(int pos) {
168173
/**
169174
* insert a child node into the node48 node with the key byte
170175
*
171-
* @param currentNode the node4
172176
* @param child the child node
173177
* @param key the key byte
174178
* @return the node48 or an adaptive generated node256
175179
*/
176-
public static BranchNode insert(BranchNode currentNode, Node child, byte key) {
177-
Node48 node48 = (Node48) currentNode;
178-
if (node48.count < 48) {
180+
@Override
181+
protected BranchNode insert(Node child, byte key) {
182+
if (this.count < 48) {
179183
// insert leaf node into current node
180-
int pos = node48.count;
181-
if (node48.children[pos] != null) {
184+
int pos = this.count;
185+
if (this.children[pos] != null) {
182186
pos = 0;
183-
while (node48.children[pos] != null) {
187+
while (this.children[pos] != null) {
184188
pos++;
185189
}
186190
}
187-
node48.children[pos] = child;
191+
this.children[pos] = child;
188192
int unsignedByte = Byte.toUnsignedInt(key);
189-
setOneByte(unsignedByte, (byte) pos, node48.childIndex);
190-
node48.count++;
191-
return node48;
193+
setOneByte(unsignedByte, (byte) pos, this.childIndex);
194+
this.count++;
195+
return this;
192196
} else {
193197
// grow to Node256
194-
Node256 node256 = new Node256(node48.prefixLength);
198+
Node256 node256 = new Node256(this.prefixLength);
195199
int currentPos = ILLEGAL_IDX;
196-
while ((currentPos = node48.getNextLargerPos(currentPos)) != ILLEGAL_IDX) {
197-
Node childNode = node48.getChild(currentPos);
200+
while ((currentPos = this.getNextLargerPos(currentPos)) != ILLEGAL_IDX) {
201+
Node childNode = this.getChild(currentPos);
198202
node256.children[currentPos] = childNode;
199203
Node256.setBit((byte) currentPos, node256.bitmapMask);
200204
}
201-
node256.count = node48.count;
202-
copyPrefix(node48, node256);
203-
BranchNode freshOne = Node256.insert(node256, child, key);
205+
node256.count = this.count;
206+
copyPrefix(this, node256);
207+
BranchNode freshOne = node256.insert(child, key);
204208
return freshOne;
205209
}
206210
}

0 commit comments

Comments
 (0)