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  
19  package org.apache.hadoop.hbase.util;
20  
21  import java.nio.ByteBuffer;
22  
23  import org.apache.hadoop.classification.InterfaceAudience;
24  import org.apache.hadoop.classification.InterfaceStability;
25  
26  import com.google.common.annotations.VisibleForTesting;
27  
28  /**
29   * Extends the basic {@link SimpleByteRange} implementation with position
30   * support. {@code position} is considered transient, not fundamental to the
31   * definition of the range, and does not participate in comparison or copy
32   * operations.
33   */
34  @InterfaceAudience.Public
35  @InterfaceStability.Evolving
36  public class SimplePositionedByteRange extends SimpleByteRange implements PositionedByteRange {
37  
38    /**
39     * The current index into the range. Like {@link ByteBuffer} position, it
40     * points to the next value that will be read/written in the array. It
41     * provides the appearance of being 0-indexed, even though its value is
42     * calculated according to offset.
43     * <p>
44     * Position is considered transient and does not participate in
45     * {@link #equals(Object)} or {@link #hashCode()} comparisons.
46     * </p>
47     */
48    private int position = 0;
49  
50    /**
51     * Create a new {@code PositionedByteRange} lacking a backing array and with
52     * an undefined viewport.
53     */
54    public SimplePositionedByteRange() {
55      super();
56    }
57  
58    /**
59     * Create a new {@code PositionedByteRange} over a new backing array of
60     * size {@code capacity}. The range's offset and length are 0 and
61     * {@code capacity}, respectively.
62     * @param capacity the size of the backing array.
63     */
64    public SimplePositionedByteRange(int capacity) {
65      super(capacity);
66    }
67  
68    /**
69     * Create a new {@code PositionedByteRange} over the provided {@code bytes}.
70     * @param bytes The array to wrap.
71     */
72    public SimplePositionedByteRange(byte[] bytes) {
73      super(bytes);
74    }
75  
76    /**
77     * Create a new {@code PositionedByteRange} over the provided {@code bytes}.
78     * @param bytes The array to wrap.
79     * @param offset The offset into {@code bytes} considered the beginning
80     *          of this range.
81     * @param length The length of this range.
82     */
83    public SimplePositionedByteRange(byte[] bytes, int offset, int length) {
84      super(bytes, offset, length);
85    }
86  
87    @Override
88    public PositionedByteRange unset() {
89      this.position = 0;
90      super.unset();
91      return this;
92    }
93  
94    @Override
95    public PositionedByteRange set(int capacity) {
96      this.position = 0;
97      super.set(capacity);
98      return this;
99    }
100 
101   @Override
102   public PositionedByteRange set(byte[] bytes) {
103     this.position = 0;
104     super.set(bytes);
105     return this;
106   }
107 
108   @Override
109   public PositionedByteRange set(byte[] bytes, int offset, int length) {
110     this.position = 0;
111     super.set(bytes, offset, length);
112     return this;
113   }
114 
115   /**
116    * Update the beginning of this range. {@code offset + length} may not be greater than
117    * {@code bytes.length}. Resets {@code position} to 0.
118    * @param offset the new start of this range.
119    * @return this.
120    */
121   @Override
122   public PositionedByteRange setOffset(int offset) {
123     this.position = 0;
124     super.setOffset(offset);
125     return this;
126   }
127 
128   /**
129    * Update the length of this range. {@code offset + length} should not be
130    * greater than {@code bytes.length}. If {@code position} is greater than
131    * the new {@code length}, sets {@code position} to {@code length}.
132    * @param length The new length of this range.
133    * @return this.
134    */
135   @Override
136   public PositionedByteRange setLength(int length) {
137     this.position = Math.min(position, length);
138     super.setLength(length);
139     return this;
140   }
141 
142   @Override
143   public int getPosition() { return position; }
144 
145   @Override
146   public PositionedByteRange setPosition(int position) { this.position = position; return this; }
147 
148   @Override
149   public int getRemaining() { return length - position; }
150 
151   @Override
152   public byte peek() { return bytes[offset + position]; }
153 
154   @Override
155   public byte get() { return get(position++); }
156 
157   @Override
158   public PositionedByteRange get(byte[] dst) {
159     if (0 == dst.length) return this;
160     return this.get(dst, 0, dst.length); // be clear we're calling self, not super
161   }
162 
163   @Override
164   public PositionedByteRange get(byte[] dst, int offset, int length) {
165     if (0 == length) return this;
166     super.get(this.position, dst, offset, length);
167     this.position += length;
168     return this;
169   }
170 
171   @Override
172   public PositionedByteRange put(byte val) {
173     put(position++, val);
174     return this;
175   }
176 
177   @Override
178   public PositionedByteRange put(byte[] val) {
179     if (0 == val.length) return this;
180     return this.put(val, 0, val.length);
181   }
182 
183   @Override
184   public PositionedByteRange put(byte[] val, int offset, int length) {
185     if (0 == length) return this;
186     super.put(position, val, offset, length);
187     this.position += length;
188     return this;
189   }
190 
191   /**
192    * Similar to {@link ByteBuffer#flip()}. Sets length to position, position
193    * to offset.
194    */
195   @VisibleForTesting
196   PositionedByteRange flip() {
197     clearHashCache();
198     length = position;
199     position = offset;
200     return this;
201   }
202 
203   /**
204    * Similar to {@link ByteBuffer#clear()}. Sets position to 0, length to
205    * capacity.
206    */
207   @VisibleForTesting
208   PositionedByteRange clear() {
209     clearHashCache();
210     position = 0;
211     length = bytes.length - offset;
212     return this;
213   }
214 
215   // java boilerplate
216 
217   @Override
218   public PositionedByteRange get(int index, byte[] dst) { super.get(index, dst); return this; }
219 
220   @Override
221   public PositionedByteRange get(int index, byte[] dst, int offset, int length) {
222     super.get(index, dst, offset, length);
223     return this;
224   }
225 
226   @Override
227   public PositionedByteRange put(int index, byte val) { super.put(index, val); return this; }
228 
229   @Override
230   public PositionedByteRange put(int index, byte[] val) { super.put(index, val); return this; }
231 
232   @Override
233   public PositionedByteRange put(int index, byte[] val, int offset, int length) {
234     super.put(index, val, offset, length);
235     return this;
236   }
237 
238   @Override
239   public PositionedByteRange deepCopy() {
240     SimplePositionedByteRange clone = new SimplePositionedByteRange(deepCopyToNewArray());
241     clone.position = this.position;
242     return clone;
243   }
244 
245   @Override
246   public PositionedByteRange shallowCopy() {
247     SimplePositionedByteRange clone = new SimplePositionedByteRange(bytes, offset, length);
248     clone.position = this.position;
249     return clone;
250   }
251 
252   @Override
253   public PositionedByteRange shallowCopySubRange(int innerOffset, int copyLength) {
254     SimplePositionedByteRange clone =
255         new SimplePositionedByteRange(bytes, offset + innerOffset, copyLength);
256     clone.position = this.position;
257     return clone;
258   }
259 }