001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.util;
019
020
021import org.apache.yetus.audience.InterfaceAudience;
022import org.apache.yetus.audience.InterfaceStability;
023
024import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
025
026/**
027 * Extends the basic {@link SimpleByteRange} implementation with position
028 * support. {@code position} is considered transient, not fundamental to the
029 * definition of the range, and does not participate in
030 * {@link #compareTo(ByteRange)}, {@link #hashCode()}, or
031 * {@link #equals(Object)}. {@code Position} is retained by copy operations.
032 */
033@InterfaceAudience.Private
034@InterfaceStability.Evolving
035public abstract class AbstractPositionedByteRange extends AbstractByteRange implements
036    PositionedByteRange {
037  /**
038   * The current index into the range. Like {@link java.nio.ByteBuffer} position, it
039   * points to the next value that will be read/written in the array. It
040   * provides the appearance of being 0-indexed, even though its value is
041   * calculated according to offset.
042   * <p>
043   * Position is considered transient and does not participate in
044   * {@link #equals(Object)} or {@link #hashCode()} comparisons.
045   * </p>
046   */
047  protected int position = 0;
048
049  protected int limit = 0;
050
051  @Override
052  public abstract PositionedByteRange unset();
053
054  @Override
055  public PositionedByteRange set(int capacity) {
056    this.position = 0;
057    super.set(capacity);
058    this.limit = capacity;
059    return this;
060  }
061
062  @Override
063  public PositionedByteRange set(byte[] bytes) {
064    this.position = 0;
065    super.set(bytes);
066    this.limit = bytes.length;
067    return this;
068  }
069
070  @Override
071  public PositionedByteRange set(byte[] bytes, int offset, int length) {
072    this.position = 0;
073    super.set(bytes, offset, length);
074    limit = length;
075    return this;
076  }
077
078  /**
079   * Update the beginning of this range. {@code offset + length} may not be
080   * greater than {@code bytes.length}. Resets {@code position} to 0.
081   *
082   * @param offset
083   *          the new start of this range.
084   * @return this.
085   */
086  @Override
087  public PositionedByteRange setOffset(int offset) {
088    this.position = 0;
089    super.setOffset(offset);
090    return this;
091  }
092
093  /**
094   * Update the length of this range. {@code offset + length} should not be
095   * greater than {@code bytes.length}. If {@code position} is greater than the
096   * new {@code length}, sets {@code position} to {@code length}.
097   *
098   * @param length
099   *          The new length of this range.
100   * @return this.
101   */
102  @Override
103  public PositionedByteRange setLength(int length) {
104    this.position = Math.min(position, length);
105    super.setLength(length);
106    return this;
107  }
108
109  @Override
110  public int getPosition() {
111    return position;
112  }
113
114  @Override
115  public PositionedByteRange setPosition(int position) {
116    this.position = position;
117    return this;
118  }
119
120  @Override
121  public int getRemaining() {
122    return length - position;
123  }
124
125  @Override
126  public byte peek() {
127    return bytes[offset + position];
128  }
129
130  @Override
131  public byte get() {
132    return get(position++);
133  }
134
135  @Override
136  public PositionedByteRange get(byte[] dst) {
137    if (0 == dst.length)
138      return this;
139    return this.get(dst, 0, dst.length); // be clear we're calling self, not
140                                         // super
141  }
142
143  @Override
144  public PositionedByteRange get(byte[] dst, int offset, int length) {
145    if (0 == length)
146      return this;
147    super.get(this.position, dst, offset, length);
148    this.position += length;
149    return this;
150  }
151
152  @Override
153  public abstract PositionedByteRange put(byte val);
154
155  @Override
156  public abstract PositionedByteRange put(byte[] val);
157
158  @Override
159  public abstract PositionedByteRange put(byte[] val, int offset, int length);
160
161  @Override
162  public abstract PositionedByteRange putInt(int index, int val);
163
164  @Override
165  public abstract PositionedByteRange putLong(int index, long val);
166
167  @Override
168  public abstract PositionedByteRange putShort(int index, short val);
169
170  @Override
171  public abstract PositionedByteRange putInt(int val);
172
173  @Override
174  public abstract PositionedByteRange putLong(long val);
175
176  @Override
177  public abstract PositionedByteRange putShort(short val);
178
179  @Override
180  public abstract int putVLong(int index, long val);
181
182  @Override
183  public abstract int putVLong(long val);
184  /**
185   * Similar to {@link java.nio.ByteBuffer#flip()}. Sets length to position, position to
186   * offset.
187   */
188  @VisibleForTesting
189  PositionedByteRange flip() {
190    clearHashCache();
191    length = position;
192    position = offset;
193    return this;
194  }
195
196  /**
197   * Similar to {@link java.nio.ByteBuffer#clear()}. Sets position to 0, length to
198   * capacity.
199   */
200  @VisibleForTesting
201  PositionedByteRange clear() {
202    clearHashCache();
203    position = 0;
204    length = bytes.length - offset;
205    return this;
206  }
207
208  // java boilerplate
209
210  @Override
211  public PositionedByteRange get(int index, byte[] dst) {
212    super.get(index, dst);
213    return this;
214  }
215
216  @Override
217  public PositionedByteRange get(int index, byte[] dst, int offset, int length) {
218    super.get(index, dst, offset, length);
219    return this;
220  }
221
222  @Override
223  public short getShort() {
224    short s = getShort(position);
225    position += Bytes.SIZEOF_SHORT;
226    return s;
227  }
228
229  @Override
230  public int getInt() {
231    int i = getInt(position);
232    position += Bytes.SIZEOF_INT;
233    return i;
234  }
235
236  @Override
237  public long getLong() {
238    long l = getLong(position);
239    position += Bytes.SIZEOF_LONG;
240    return l;
241  }
242
243  @Override
244  public long getVLong() {
245    long p = getVLong(position);
246    position += getVLongSize(p);
247    return p;
248  }
249
250  @Override
251  public abstract PositionedByteRange put(int index, byte val);
252
253  @Override
254  public abstract PositionedByteRange put(int index, byte[] val);
255
256  @Override
257  public abstract PositionedByteRange put(int index, byte[] val, int offset, int length);
258
259  @Override
260  public abstract PositionedByteRange deepCopy();
261
262  @Override
263  public abstract PositionedByteRange shallowCopy();
264
265  @Override
266  public abstract PositionedByteRange shallowCopySubRange(int innerOffset, int copyLength);
267
268  @Override
269  public PositionedByteRange setLimit(int limit) {
270    this.limit = limit;
271    return this;
272  }
273
274  @Override
275  public int getLimit() {
276    return this.limit;
277  }
278}