View Javadoc

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  package org.apache.hadoop.hbase.util;
19  
20  import org.apache.hadoop.hbase.classification.InterfaceAudience;
21  import org.apache.hadoop.hbase.classification.InterfaceStability;
22  
23  /**
24   * An abstract implementation of the ByteRange API
25   */
26  @InterfaceAudience.Private
27  @InterfaceStability.Evolving
28  public abstract class AbstractByteRange implements ByteRange {
29  
30    public static final int UNSET_HASH_VALUE = -1;
31  
32    // Note to maintainers: Do not make these final, as the intention is to
33    // reuse objects of this class
34  
35    /**
36     * The array containing the bytes in this range. It will be >= length.
37     */
38    protected byte[] bytes;
39  
40    /**
41     * The index of the first byte in this range. {@code ByteRange.get(0)} will
42     * return bytes[offset].
43     */
44    protected int offset;
45  
46    /**
47     * The number of bytes in the range. Offset + length must be <= bytes.length
48     */
49    protected int length;
50  
51    /**
52     * Variable for lazy-caching the hashCode of this range. Useful for frequently
53     * used ranges, long-lived ranges, or long ranges.
54     */
55    protected int hash = UNSET_HASH_VALUE;
56  
57    //
58    // methods for managing the backing array and range viewport
59    //
60    @Override
61    public byte[] getBytes() {
62      return bytes;
63    }
64  
65    @Override
66    public abstract ByteRange unset();
67  
68    @Override
69    public ByteRange set(int capacity) {
70      return set(new byte[capacity]);
71    }
72  
73    @Override
74    public ByteRange set(byte[] bytes) {
75      if (null == bytes)
76        return unset();
77      clearHashCache();
78      this.bytes = bytes;
79      this.offset = 0;
80      this.length = bytes.length;
81      return this;
82    }
83  
84    @Override
85    public ByteRange set(byte[] bytes, int offset, int length) {
86      if (null == bytes)
87        return unset();
88      clearHashCache();
89      this.bytes = bytes;
90      this.offset = offset;
91      this.length = length;
92      return this;
93    }
94  
95    @Override
96    public int getOffset() {
97      return offset;
98    }
99  
100   @Override
101   public ByteRange setOffset(int offset) {
102     clearHashCache();
103     this.offset = offset;
104     return this;
105   }
106 
107   @Override
108   public int getLength() {
109     return length;
110   }
111 
112   @Override
113   public ByteRange setLength(int length) {
114     clearHashCache();
115     this.length = length;
116     return this;
117   }
118 
119   @Override
120   public boolean isEmpty() {
121     return isEmpty(this);
122   }
123 
124   /**
125    * @return true when {@code range} is of zero length, false otherwise.
126    */
127   public static boolean isEmpty(ByteRange range) {
128     return range == null || range.getLength() == 0;
129   }
130 
131   //
132   // methods for retrieving data
133   //
134 
135   @Override
136   public byte get(int index) {
137     return bytes[offset + index];
138   }
139 
140   @Override
141   public ByteRange get(int index, byte[] dst) {
142     if (0 == dst.length)
143       return this;
144     return get(index, dst, 0, dst.length);
145   }
146 
147   @Override
148   public ByteRange get(int index, byte[] dst, int offset, int length) {
149     if (0 == length)
150       return this;
151     System.arraycopy(this.bytes, this.offset + index, dst, offset, length);
152     return this;
153   }
154 
155   @Override
156   public short getShort(int index) {
157     int offset = this.offset + index;
158     short n = 0;
159     n ^= bytes[offset] & 0xFF;
160     n <<= 8;
161     n ^= bytes[offset + 1] & 0xFF;
162     return n;
163   }
164 
165   @Override
166   public int getInt(int index) {
167     int offset = this.offset + index;
168     int n = 0;
169     for (int i = offset; i < (offset + Bytes.SIZEOF_INT); i++) {
170       n <<= 8;
171       n ^= bytes[i] & 0xFF;
172     }
173     return n;
174   }
175 
176   @Override
177   public long getLong(int index) {
178     int offset = this.offset + index;
179     long l = 0;
180     for (int i = offset; i < offset + Bytes.SIZEOF_LONG; i++) {
181       l <<= 8;
182       l ^= bytes[i] & 0xFF;
183     }
184     return l;
185   }
186 
187   // Copied from com.google.protobuf.CodedInputStream
188   @Override
189   public long getVLong(int index) {
190     int shift = 0;
191     long result = 0;
192     while (shift < 64) {
193       final byte b = get(index++);
194       result |= (long) (b & 0x7F) << shift;
195       if ((b & 0x80) == 0) {
196         break;
197       }
198       shift += 7;
199     }
200     return result;
201   }
202 
203   public static int getVLongSize(long val) {
204     int rPos = 0;
205     while ((val & ~0x7F) != 0) {
206       val >>>= 7;
207       rPos++;
208     }
209     return rPos + 1;
210   }
211 
212   @Override
213   public abstract ByteRange put(int index, byte val);
214 
215   @Override
216   public abstract ByteRange put(int index, byte[] val);
217 
218   @Override
219   public abstract ByteRange put(int index, byte[] val, int offset, int length);
220 
221   @Override
222   public abstract ByteRange putInt(int index, int val);
223 
224   @Override
225   public abstract ByteRange putLong(int index, long val);
226 
227   @Override
228   public abstract ByteRange putShort(int index, short val);
229 
230   @Override
231   public abstract int putVLong(int index, long val);
232 
233   //
234   // methods for duplicating the current instance
235   //
236 
237   @Override
238   public byte[] deepCopyToNewArray() {
239     byte[] result = new byte[length];
240     System.arraycopy(bytes, offset, result, 0, length);
241     return result;
242   }
243 
244   @Override
245   public void deepCopyTo(byte[] destination, int destinationOffset) {
246     System.arraycopy(bytes, offset, destination, destinationOffset, length);
247   }
248 
249   @Override
250   public void deepCopySubRangeTo(int innerOffset, int copyLength, byte[] destination,
251       int destinationOffset) {
252     System.arraycopy(bytes, offset + innerOffset, destination, destinationOffset, copyLength);
253   }
254 
255   //
256   // methods used for comparison
257   //
258 
259   @Override
260   public int hashCode() {
261     if (isHashCached()) {// hash is already calculated and cached
262       return hash;
263     }
264     if (this.isEmpty()) {// return 0 for empty ByteRange
265       hash = 0;
266       return hash;
267     }
268     int off = offset;
269     hash = 0;
270     for (int i = 0; i < length; i++) {
271       hash = 31 * hash + bytes[off++];
272     }
273     return hash;
274   }
275 
276   protected boolean isHashCached() {
277     return hash != UNSET_HASH_VALUE;
278   }
279 
280   protected void clearHashCache() {
281     hash = UNSET_HASH_VALUE;
282   }
283 
284   /**
285    * Bitwise comparison of each byte in the array. Unsigned comparison, not
286    * paying attention to java's signed bytes.
287    */
288   @Override
289   public int compareTo(ByteRange other) {
290     return Bytes.compareTo(bytes, offset, length, other.getBytes(), other.getOffset(),
291         other.getLength());
292   }
293 
294   @Override
295   public String toString() {
296     return Bytes.toStringBinary(bytes, offset, length);
297   }
298 }