Coverage Summary for Class: TrieKeySlice (co.rsk.trie)
Class |
Class, %
|
Method, %
|
Line, %
|
TrieKeySlice |
100%
(1/1)
|
81.8%
(9/11)
|
60.5%
(26/43)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2019 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 package co.rsk.trie;
19
20 import java.util.Arrays;
21
22 /**
23 * An immutable slice of a trie key.
24 * Sub-slices share array references, so external sources are copied and the internal array is not exposed.
25 */
26 public class TrieKeySlice {
27 private final byte[] expandedKey;
28 private final int offset;
29 private final int limit;
30
31 private TrieKeySlice(byte[] expandedKey, int offset, int limit) {
32 this.expandedKey = expandedKey;
33 this.offset = offset;
34 this.limit = limit;
35 }
36
37 public int length() {
38 return limit - offset;
39 }
40
41 public byte get(int i) {
42 return expandedKey[offset + i];
43 }
44
45 public byte[] encode() {
46 // TODO(mc) avoid copying by passing the indices to PathEncoder.encode
47 return PathEncoder.encode(Arrays.copyOfRange(expandedKey, offset, limit));
48 }
49
50 public TrieKeySlice slice(int from, int to) {
51 if (from < 0) {
52 throw new IllegalArgumentException("The start position must not be lower than 0");
53 }
54
55 if (from > to) {
56 throw new IllegalArgumentException("The start position must not be greater than the end position");
57 }
58
59 int newOffset = offset + from;
60 if (newOffset > limit) {
61 throw new IllegalArgumentException("The start position must not exceed the key length");
62 }
63
64 int newLimit = offset + to;
65 if (newLimit > limit) {
66 throw new IllegalArgumentException("The end position must not exceed the key length");
67 }
68
69 return new TrieKeySlice(expandedKey, newOffset, newLimit);
70 }
71
72 public TrieKeySlice commonPath(TrieKeySlice other) {
73 int maxCommonLengthPossible = Math.min(length(), other.length());
74 for (int i = 0; i < maxCommonLengthPossible; i++) {
75 if (get(i) != other.get(i)) {
76 return slice(0, i);
77 }
78 }
79
80 return slice(0, maxCommonLengthPossible);
81 }
82
83 /**
84 * Rebuild a shared path as [...this, implicitByte, ...childSharedPath]
85 */
86 public TrieKeySlice rebuildSharedPath(byte implicitByte, TrieKeySlice childSharedPath) {
87 int length = length();
88 int childSharedPathLength = childSharedPath.length();
89 int newLength = length + 1 + childSharedPathLength;
90 byte[] newExpandedKey = Arrays.copyOfRange(expandedKey, offset, offset + newLength);
91 newExpandedKey[length] = implicitByte;
92 System.arraycopy(
93 childSharedPath.expandedKey, childSharedPath.offset,
94 newExpandedKey, length + 1, childSharedPathLength
95 );
96 return new TrieKeySlice(newExpandedKey, 0, newExpandedKey.length);
97 }
98
99 public TrieKeySlice leftPad(int paddingLength) {
100 if (paddingLength == 0) {
101 return this;
102 }
103 int currentLength = length();
104 byte[] paddedExpandedKey = new byte[currentLength + paddingLength];
105 System.arraycopy(expandedKey, offset, paddedExpandedKey, paddingLength, currentLength);
106 return new TrieKeySlice(paddedExpandedKey, 0, paddedExpandedKey.length);
107 }
108
109 public static TrieKeySlice fromKey(byte[] key) {
110 byte[] expandedKey = PathEncoder.decode(key, key.length * 8);
111 return new TrieKeySlice(expandedKey, 0, expandedKey.length);
112 }
113
114 public static TrieKeySlice fromEncoded(byte[] src, int offset, int keyLength, int encodedLength) {
115 // TODO(mc) avoid copying by passing the indices to PathEncoder.decode
116 byte[] encodedKey = Arrays.copyOfRange(src, offset, offset + encodedLength);
117 byte[] expandedKey = PathEncoder.decode(encodedKey, keyLength);
118 return new TrieKeySlice(expandedKey, 0, expandedKey.length);
119 }
120
121 public static TrieKeySlice empty() {
122 return new TrieKeySlice(new byte[0], 0, 0);
123 }
124 }