1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package org.apache.hadoop.hbase.util; 20 21 import org.apache.hadoop.hbase.classification.InterfaceAudience; 22 import org.apache.hadoop.hbase.classification.InterfaceStability; 23 24 /** 25 * Lightweight, reusable class for specifying ranges of byte[]'s. 26 * <p> 27 * {@code ByteRange} maintains an underlying byte[] and a viewport into that 28 * byte[] as a range of bytes. The {@code ByteRange} is a mutable, reusable 29 * object, so the underlying byte[] can be modified after instantiation. This 30 * is done using the {@link #set(byte[])} and {@link #unset()} methods. Direct 31 * access to the byte[] is also available via {@link #getBytes()}. The viewport 32 * is defined by an {@code offset} into the byte[] and a {@code length}. The 33 * range of bytes is 0-indexed, and is accessed by index via the 34 * {@link #get(int)} and {@link #put(int, byte)} methods. 35 * </p> 36 * <p> 37 * This interface differs from ByteBuffer: 38 * <li>On-heap bytes only</li> 39 * <li>Raw {@code byte} access only; does not encode other primitives.</li> 40 * <li>Implements {@code equals(Object)}, {@code #hashCode()}, and 41 * {@code #compareTo(ByteRange)} so that it can be used in standard java 42 * Collections. Comparison operations are lexicographic, which is native to 43 * HBase.</li> 44 * <li>Allows the addition of simple core methods like the deep and shallow 45 * copy methods.</li> 46 * <li>Can be reused in tight loops like a major compaction which can save 47 * significant amounts of garbage. (Without reuse, we throw off garbage like 48 * <a href="http://www.youtube.com/watch?v=lkmBH-MjZF4">this thing</a>.)</li> 49 * </p> 50 * <p> 51 * Mutable, and always evaluates {@code #equals(Object)}, {@code #hashCode()}, 52 * and {@code #compareTo(ByteRange)} based on the current contents. 53 * </p> 54 * <p> 55 * Can contain convenience methods for comparing, printing, cloning, spawning 56 * new arrays, copying to other arrays, etc. Please place non-core methods into 57 * {@link ByteRangeUtils}. 58 * </p> 59 */ 60 @InterfaceAudience.Public 61 @InterfaceStability.Evolving 62 public interface ByteRange extends Comparable<ByteRange> { 63 64 /** 65 * The underlying byte[]. 66 */ 67 public byte[] getBytes(); 68 69 /** 70 * Nullifies this ByteRange. That is, it becomes a husk, being a range over 71 * no byte[] whatsoever. 72 * @return this 73 */ 74 public ByteRange unset(); 75 76 /** 77 * Reuse this {@code ByteRange} over a new byte[]. {@code offset} is set to 78 * 0 and {@code length} is set to {@code capacity}. 79 * @param capacity the size of a new byte[]. 80 * @return this 81 */ 82 public ByteRange set(int capacity); 83 84 /** 85 * Reuse this {@code ByteRange} over a new byte[]. {@code offset} is set to 86 * 0 and {@code length} is set to {@code bytes.length}. A null {@code bytes} 87 * IS supported, in which case this method will behave equivalently to 88 * {@link #unset()}. 89 * @param bytes the array to wrap. 90 * @return this 91 */ 92 public ByteRange set(byte[] bytes); 93 94 /** 95 * Reuse this {@code ByteRange} over a new byte[]. A null {@code bytes} IS 96 * supported, in which case this method will behave equivalently to 97 * {@link #unset()}, regardless of the values of {@code offset} and 98 * {@code length}. 99 * @param bytes The array to wrap. 100 * @param offset The offset into {@code bytes} considered the beginning of 101 * this range. 102 * @param length The length of this range. 103 * @return this. 104 */ 105 public ByteRange set(byte[] bytes, int offset, int length); 106 107 /** 108 * The offset, the index into the underlying byte[] at which this range 109 * begins. 110 * @see #getBytes() 111 */ 112 public int getOffset(); 113 114 /** 115 * Update the beginning of this range. {@code offset + length} may not be 116 * greater than {@code bytes.length}. 117 * @param offset the new start of this range. 118 * @return this. 119 */ 120 public ByteRange setOffset(int offset); 121 122 /** 123 * The length of the range. 124 */ 125 public int getLength(); 126 127 /** 128 * Update the length of this range. {@code offset + length} should not be 129 * greater than {@code bytes.length}. 130 * @param length The new length of this range. 131 * @return this. 132 */ 133 public ByteRange setLength(int length); 134 135 /** 136 * @return true when this range is of zero length, false otherwise. 137 */ 138 public boolean isEmpty(); 139 140 /** 141 * Retrieve the byte at {@code index}. 142 * @param index zero-based index into this range. 143 * @return single byte at index. 144 */ 145 public byte get(int index); 146 147 /** 148 * Fill {@code dst} with bytes from the range, starting from {@code index}. 149 * @param index zero-based index into this range. 150 * @param dst the destination of the copy. 151 * @return this. 152 */ 153 public ByteRange get(int index, byte[] dst); 154 155 /** 156 * Fill {@code dst} with bytes from the range, starting from {@code index}. 157 * {@code length} bytes are copied into {@code dst}, starting at {@code offset}. 158 * @param index zero-based index into this range. 159 * @param dst the destination of the copy. 160 * @param offset the offset into {@code dst} to start the copy. 161 * @param length the number of bytes to copy into {@code dst}. 162 * @return this. 163 */ 164 public ByteRange get(int index, byte[] dst, int offset, int length); 165 166 /** 167 * Store {@code val} at {@code index}. 168 * @param index the index in the range where {@code val} is stored. 169 * @param val the value to store. 170 * @return this. 171 */ 172 public ByteRange put(int index, byte val); 173 174 /** 175 * Store {@code val} at {@code index}. 176 * @param index the index in the range where {@code val} is stored. 177 * @param val the value to store. 178 * @return this. 179 */ 180 public ByteRange put(int index, byte[] val); 181 182 /** 183 * Store {@code length} bytes from {@code val} into this range, starting at 184 * {@code index}. Bytes from {@code val} are copied starting at {@code offset} 185 * into the range. 186 * @param index position in this range to start the copy. 187 * @param val the value to store. 188 * @param offset the offset in {@code val} from which to start copying. 189 * @param length the number of bytes to copy from {@code val}. 190 * @return this. 191 */ 192 public ByteRange put(int index, byte[] val, int offset, int length); 193 194 /** 195 * Instantiate a new byte[] with exact length, which is at least 24 bytes + 196 * length. Copy the contents of this range into it. 197 * @return The newly cloned byte[]. 198 */ 199 public byte[] deepCopyToNewArray(); 200 201 /** 202 * Create a new {@code ByteRange} with new backing byte[] containing a copy 203 * of the content from {@code this} range's window. 204 * @return Deep copy 205 */ 206 public ByteRange deepCopy(); 207 208 /** 209 * Wrapper for System.arraycopy. Copy the contents of this range into the 210 * provided array. 211 * @param destination Copy to this array 212 * @param destinationOffset First index in the destination array. 213 */ 214 public void deepCopyTo(byte[] destination, int destinationOffset); 215 216 /** 217 * Wrapper for System.arraycopy. Copy the contents of this range into the 218 * provided array. 219 * @param innerOffset Start copying from this index in this source 220 * ByteRange. First byte copied is bytes[offset + innerOffset] 221 * @param copyLength Copy this many bytes 222 * @param destination Copy to this array 223 * @param destinationOffset First index in the destination array. 224 */ 225 public void deepCopySubRangeTo(int innerOffset, int copyLength, byte[] destination, 226 int destinationOffset); 227 228 /** 229 * Create a new {@code ByteRange} that points at this range's byte[]. 230 * Modifying the shallowCopy will modify the bytes in this range's array. 231 * Pass over the hash code if it is already cached. 232 * @return new {@code ByteRange} object referencing this range's byte[]. 233 */ 234 public ByteRange shallowCopy(); 235 236 /** 237 * Create a new {@code ByteRange} that points at this range's byte[]. The new 238 * range can have different values for offset and length, but modifying the 239 * shallowCopy will modify the bytes in this range's array. Pass over the 240 * hash code if it is already cached. 241 * @param innerOffset First byte of clone will be this.offset + copyOffset. 242 * @param copyLength Number of bytes in the clone. 243 * @return new {@code ByteRange} object referencing this range's byte[]. 244 */ 245 public ByteRange shallowCopySubRange(int innerOffset, int copyLength); 246 }