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.classification.InterfaceAudience;
22 import org.apache.hadoop.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 }