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