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 }