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 * 018 * The portion of this file denoted by 'Copied from com.google.protobuf.CodedInputStream' 019 * is from Protocol Buffers v2.5.0 under the following license 020 * 021 * Copyright 2008 Google Inc. All rights reserved. 022 * http://code.google.com/p/protobuf/ 023 * 024 * Redistribution and use in source and binary forms, with or without 025 * modification, are permitted provided that the following conditions are 026 * met: 027 * 028 * * Redistributions of source code must retain the above copyright 029 * notice, this list of conditions and the following disclaimer. 030 * * Redistributions in binary form must reproduce the above 031 * copyright notice, this list of conditions and the following disclaimer 032 * in the documentation and/or other materials provided with the 033 * distribution. 034 * * Neither the name of Google Inc. nor the names of its 035 * contributors may be used to endorse or promote products derived from 036 * this software without specific prior written permission. 037 * 038 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 039 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 040 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 041 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 042 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 043 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 044 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 045 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 046 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 047 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 048 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 049 * 050 */ 051package org.apache.hadoop.hbase.util; 052 053import org.apache.yetus.audience.InterfaceAudience; 054import org.apache.yetus.audience.InterfaceStability; 055 056/** 057 * An abstract implementation of the ByteRange API 058 */ 059@InterfaceAudience.Private 060@InterfaceStability.Evolving 061public abstract class AbstractByteRange implements ByteRange { 062 063 public static final int UNSET_HASH_VALUE = -1; 064 065 // Note to maintainers: Do not make these final, as the intention is to 066 // reuse objects of this class 067 068 /** 069 * The array containing the bytes in this range. It will be >= length. 070 */ 071 protected byte[] bytes; 072 073 /** 074 * The index of the first byte in this range. {@code ByteRange.get(0)} will 075 * return bytes[offset]. 076 */ 077 protected int offset; 078 079 /** 080 * The number of bytes in the range. Offset + length must be <= bytes.length 081 */ 082 protected int length; 083 084 /** 085 * Variable for lazy-caching the hashCode of this range. Useful for frequently 086 * used ranges, long-lived ranges, or long ranges. 087 */ 088 protected int hash = UNSET_HASH_VALUE; 089 090 // 091 // methods for managing the backing array and range viewport 092 // 093 @Override 094 public byte[] getBytes() { 095 return bytes; 096 } 097 098 @Override 099 public abstract ByteRange unset(); 100 101 @Override 102 public ByteRange set(int capacity) { 103 return set(new byte[capacity]); 104 } 105 106 @Override 107 public ByteRange set(byte[] bytes) { 108 if (null == bytes) 109 return unset(); 110 clearHashCache(); 111 this.bytes = bytes; 112 this.offset = 0; 113 this.length = bytes.length; 114 return this; 115 } 116 117 @Override 118 public ByteRange set(byte[] bytes, int offset, int length) { 119 if (null == bytes) 120 return unset(); 121 clearHashCache(); 122 this.bytes = bytes; 123 this.offset = offset; 124 this.length = length; 125 return this; 126 } 127 128 @Override 129 public int getOffset() { 130 return offset; 131 } 132 133 @Override 134 public ByteRange setOffset(int offset) { 135 clearHashCache(); 136 this.offset = offset; 137 return this; 138 } 139 140 @Override 141 public int getLength() { 142 return length; 143 } 144 145 @Override 146 public ByteRange setLength(int length) { 147 clearHashCache(); 148 this.length = length; 149 return this; 150 } 151 152 @Override 153 public boolean isEmpty() { 154 return isEmpty(this); 155 } 156 157 /** 158 * @return true when {@code range} is of zero length, false otherwise. 159 */ 160 public static boolean isEmpty(ByteRange range) { 161 return range == null || range.getLength() == 0; 162 } 163 164 // 165 // methods for retrieving data 166 // 167 168 @Override 169 public byte get(int index) { 170 return bytes[offset + index]; 171 } 172 173 @Override 174 public ByteRange get(int index, byte[] dst) { 175 if (0 == dst.length) 176 return this; 177 return get(index, dst, 0, dst.length); 178 } 179 180 @Override 181 public ByteRange get(int index, byte[] dst, int offset, int length) { 182 if (0 == length) 183 return this; 184 System.arraycopy(this.bytes, this.offset + index, dst, offset, length); 185 return this; 186 } 187 188 @Override 189 public short getShort(int index) { 190 int offset = this.offset + index; 191 short n = 0; 192 n = (short) ((n ^ bytes[offset]) & 0xFF); 193 n = (short) (n << 8); 194 n = (short) ((n ^ bytes[offset + 1]) & 0xFF); 195 return n; 196 } 197 198 @Override 199 public int getInt(int index) { 200 int offset = this.offset + index; 201 int n = 0; 202 for (int i = offset; i < (offset + Bytes.SIZEOF_INT); i++) { 203 n <<= 8; 204 n ^= bytes[i] & 0xFF; 205 } 206 return n; 207 } 208 209 @Override 210 public long getLong(int index) { 211 int offset = this.offset + index; 212 long l = 0; 213 for (int i = offset; i < offset + Bytes.SIZEOF_LONG; i++) { 214 l <<= 8; 215 l ^= bytes[i] & 0xFF; 216 } 217 return l; 218 } 219 220 // Copied from com.google.protobuf.CodedInputStream v2.5.0 readRawVarint64 221 @Override 222 public long getVLong(int index) { 223 int shift = 0; 224 long result = 0; 225 while (shift < 64) { 226 final byte b = get(index++); 227 result |= (long) (b & 0x7F) << shift; 228 if ((b & 0x80) == 0) { 229 break; 230 } 231 shift += 7; 232 } 233 return result; 234 } 235 // end of copied from protobuf 236 237 public static int getVLongSize(long val) { 238 int rPos = 0; 239 while ((val & ~0x7F) != 0) { 240 val >>>= 7; 241 rPos++; 242 } 243 return rPos + 1; 244 } 245 246 @Override 247 public abstract ByteRange put(int index, byte val); 248 249 @Override 250 public abstract ByteRange put(int index, byte[] val); 251 252 @Override 253 public abstract ByteRange put(int index, byte[] val, int offset, int length); 254 255 @Override 256 public abstract ByteRange putInt(int index, int val); 257 258 @Override 259 public abstract ByteRange putLong(int index, long val); 260 261 @Override 262 public abstract ByteRange putShort(int index, short val); 263 264 @Override 265 public abstract int putVLong(int index, long val); 266 267 // 268 // methods for duplicating the current instance 269 // 270 271 @Override 272 public byte[] deepCopyToNewArray() { 273 byte[] result = new byte[length]; 274 System.arraycopy(bytes, offset, result, 0, length); 275 return result; 276 } 277 278 @Override 279 public void deepCopyTo(byte[] destination, int destinationOffset) { 280 System.arraycopy(bytes, offset, destination, destinationOffset, length); 281 } 282 283 @Override 284 public void deepCopySubRangeTo(int innerOffset, int copyLength, byte[] destination, 285 int destinationOffset) { 286 System.arraycopy(bytes, offset + innerOffset, destination, destinationOffset, copyLength); 287 } 288 289 // 290 // methods used for comparison 291 // 292 293 @Override 294 public int hashCode() { 295 if (isHashCached()) {// hash is already calculated and cached 296 return hash; 297 } 298 if (this.isEmpty()) {// return 0 for empty ByteRange 299 hash = 0; 300 return hash; 301 } 302 int off = offset; 303 hash = 0; 304 for (int i = 0; i < length; i++) { 305 hash = 31 * hash + bytes[off++]; 306 } 307 return hash; 308 } 309 310 protected boolean isHashCached() { 311 return hash != UNSET_HASH_VALUE; 312 } 313 314 protected void clearHashCache() { 315 hash = UNSET_HASH_VALUE; 316 } 317 318 /** 319 * Bitwise comparison of each byte in the array. Unsigned comparison, not 320 * paying attention to java's signed bytes. 321 */ 322 @Override 323 public int compareTo(ByteRange other) { 324 return Bytes.compareTo(bytes, offset, length, other.getBytes(), other.getOffset(), 325 other.getLength()); 326 } 327 328 @Override 329 public String toString() { 330 return Bytes.toStringBinary(bytes, offset, length); 331 } 332}