1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 package com.google.protobuf; 9 10 import static com.google.protobuf.Internal.checkNotNull; 11 12 import java.nio.ByteBuffer; 13 14 /** 15 * A buffer that was allocated by a {@link BufferAllocator}. For every buffer, it is guaranteed that 16 * at least one of {@link #hasArray()} or {@link #hasNioBuffer()} will be {@code true}. 17 */ 18 @CheckReturnValue 19 @ExperimentalApi 20 abstract class AllocatedBuffer { 21 /** 22 * Indicates whether this buffer contains a backing {@link ByteBuffer} (i.e. it is safe to call 23 * {@link #nioBuffer()}). 24 */ hasNioBuffer()25 public abstract boolean hasNioBuffer(); 26 27 /** 28 * Indicates whether this buffer contains a backing array (i.e. it is safe to call {@link 29 * #array()}). 30 */ hasArray()31 public abstract boolean hasArray(); 32 33 /** 34 * Returns the {@link ByteBuffer} that backs this buffer <i>(optional operation)</i>. 35 * 36 * <p>Call {@link #hasNioBuffer()} before invoking this method in order to ensure that this buffer 37 * has a backing {@link ByteBuffer}. 38 * 39 * @return The {@link ByteBuffer} that backs this buffer 40 * @throws UnsupportedOperationException If this buffer is not backed by a {@link ByteBuffer}. 41 */ nioBuffer()42 public abstract ByteBuffer nioBuffer(); 43 44 /** 45 * Returns the byte array that backs this buffer <i>(optional operation)</i>. 46 * 47 * <p>Call {@link #hasArray()} before invoking this method in order to ensure that this buffer has 48 * an accessible backing array. 49 * 50 * @return The array that backs this buffer 51 * @throws java.nio.ReadOnlyBufferException If this buffer is backed by an array but is read-only 52 * @throws UnsupportedOperationException If this buffer is not backed by an accessible array 53 */ array()54 public abstract byte[] array(); 55 56 /** 57 * Returns the offset within this buffer's backing array of the first element of the buffer 58 * <i>(optional operation)</i>. 59 * 60 * <p>If this buffer is backed by an array then {@link #position()} corresponds to the array index 61 * {@link #position()} {@code +} {@link #arrayOffset()}. 62 * 63 * <p>Invoke the {@link #hasArray hasArray} method before invoking this method in order to ensure 64 * that this buffer has an accessible backing array. 65 * 66 * @return The offset within this buffer's array of the first element of the buffer 67 * @throws java.nio.ReadOnlyBufferException If this buffer is backed by an array but is read-only 68 * @throws UnsupportedOperationException If this buffer is not backed by an accessible array 69 */ arrayOffset()70 public abstract int arrayOffset(); 71 72 /** 73 * Returns this buffer's position. 74 * 75 * @return The position of this buffer 76 */ position()77 public abstract int position(); 78 79 /** 80 * Sets this buffer's position. 81 * 82 * @param position The new position value; must be non-negative and no larger than the current 83 * limit 84 * @return This buffer 85 * @throws IllegalArgumentException If the preconditions on {@code position} do not hold 86 */ 87 @CanIgnoreReturnValue position(int position)88 public abstract AllocatedBuffer position(int position); 89 90 /** 91 * Returns this buffer's limit. 92 * 93 * @return The limit of this buffer 94 */ limit()95 public abstract int limit(); 96 97 /** 98 * Returns the number of elements between the current {@link #position()} and the {@link #limit()} 99 * . 100 * 101 * @return The number of elements remaining in this buffer 102 */ remaining()103 public abstract int remaining(); 104 105 /** 106 * Creates a new {@link AllocatedBuffer} that is backed by the given array. The returned buffer 107 * will have {@link #hasArray} == {@code true}, {@link #arrayOffset()} == {@code 0}, {@link 108 * #position()} == {@code 0} and {@link #limit()} equal to the length of {@code bytes}. 109 */ wrap(byte[] bytes)110 public static AllocatedBuffer wrap(byte[] bytes) { 111 return wrapNoCheck(bytes, 0, bytes.length); 112 } 113 114 /** 115 * Creates a new {@link AllocatedBuffer} that is backed by the given array. The returned buffer 116 * will have {@link #hasArray} == {@code true}, {@link #arrayOffset()} == {@code offset}, {@link 117 * #position()} == {@code 0} and {@link #limit()} == {@code length}. 118 */ wrap(final byte[] bytes, final int offset, final int length)119 public static AllocatedBuffer wrap(final byte[] bytes, final int offset, final int length) { 120 if (offset < 0 || length < 0 || (offset + length) > bytes.length) { 121 throw new IndexOutOfBoundsException( 122 String.format("bytes.length=%d, offset=%d, length=%d", bytes.length, offset, length)); 123 } 124 125 return wrapNoCheck(bytes, offset, length); 126 } 127 128 /** 129 * Creates a new {@link AllocatedBuffer} that is backed by the given {@link ByteBuffer}. The 130 * returned buffer will have {@link #hasNioBuffer} == {@code true}. 131 */ wrap(final ByteBuffer buffer)132 public static AllocatedBuffer wrap(final ByteBuffer buffer) { 133 checkNotNull(buffer, "buffer"); 134 135 return new AllocatedBuffer() { 136 137 @Override 138 public boolean hasNioBuffer() { 139 return true; 140 } 141 142 @Override 143 public ByteBuffer nioBuffer() { 144 return buffer; 145 } 146 147 @Override 148 public boolean hasArray() { 149 return buffer.hasArray(); 150 } 151 152 @Override 153 public byte[] array() { 154 return buffer.array(); 155 } 156 157 @Override 158 public int arrayOffset() { 159 return buffer.arrayOffset(); 160 } 161 162 @Override 163 public int position() { 164 return buffer.position(); 165 } 166 167 @Override 168 public AllocatedBuffer position(int position) { 169 Java8Compatibility.position(buffer, position); 170 return this; 171 } 172 173 @Override 174 public int limit() { 175 return buffer.limit(); 176 } 177 178 @Override 179 public int remaining() { 180 return buffer.remaining(); 181 } 182 }; 183 } 184 185 private static AllocatedBuffer wrapNoCheck( 186 final byte[] bytes, final int offset, final int length) { 187 return new AllocatedBuffer() { 188 // Relative to offset. 189 private int position; 190 191 @Override 192 public boolean hasNioBuffer() { 193 return false; 194 } 195 196 @Override 197 public ByteBuffer nioBuffer() { 198 throw new UnsupportedOperationException(); 199 } 200 201 @Override 202 public boolean hasArray() { 203 return true; 204 } 205 206 @Override 207 public byte[] array() { 208 return bytes; 209 } 210 211 @Override 212 public int arrayOffset() { 213 return offset; 214 } 215 216 @Override 217 public int position() { 218 return position; 219 } 220 221 @Override 222 public AllocatedBuffer position(int position) { 223 if (position < 0 || position > length) { 224 throw new IllegalArgumentException("Invalid position: " + position); 225 } 226 this.position = position; 227 return this; 228 } 229 230 @Override 231 public int limit() { 232 // Relative to offset. 233 return length; 234 } 235 236 @Override 237 public int remaining() { 238 return length - position; 239 } 240 }; 241 } 242 } 243