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