1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import static com.google.protobuf.Internal.checkNotNull; 34 35 import java.nio.ByteBuffer; 36 37 /** 38 * A buffer that was allocated by a {@link BufferAllocator}. For every buffer, it is guaranteed that 39 * at least one of {@link #hasArray()} or {@link #hasNioBuffer()} will be {@code true}. 40 */ 41 @ExperimentalApi 42 abstract class AllocatedBuffer { 43 /** 44 * Indicates whether this buffer contains a backing {@link ByteBuffer} (i.e. it is safe to call 45 * {@link #nioBuffer()}). 46 */ hasNioBuffer()47 public abstract boolean hasNioBuffer(); 48 49 /** 50 * Indicates whether this buffer contains a backing array (i.e. it is safe to call {@link 51 * #array()}). 52 */ hasArray()53 public abstract boolean hasArray(); 54 55 /** 56 * Returns the {@link ByteBuffer} that backs this buffer <i>(optional operation)</i>. 57 * 58 * <p>Call {@link #hasNioBuffer()} before invoking this method in order to ensure that this buffer 59 * has a backing {@link ByteBuffer}. 60 * 61 * @return The {@link ByteBuffer} that backs this buffer 62 * @throws UnsupportedOperationException If this buffer is not backed by a {@link ByteBuffer}. 63 */ nioBuffer()64 public abstract ByteBuffer nioBuffer(); 65 66 /** 67 * Returns the byte array that backs this buffer <i>(optional operation)</i>. 68 * 69 * <p>Call {@link #hasArray()} before invoking this method in order to ensure that this buffer has 70 * an accessible backing array. 71 * 72 * @return The array that backs this buffer 73 * @throws java.nio.ReadOnlyBufferException If this buffer is backed by an array but is read-only 74 * @throws UnsupportedOperationException If this buffer is not backed by an accessible array 75 */ array()76 public abstract byte[] array(); 77 78 /** 79 * Returns the offset within this buffer's backing array of the first element of the buffer 80 * <i>(optional operation)</i>. 81 * 82 * <p>If this buffer is backed by an array then {@link #position()} corresponds to the array index 83 * {@link #position()} {@code +} {@link #arrayOffset()}. 84 * 85 * <p>Invoke the {@link #hasArray hasArray} method before invoking this method in order to ensure 86 * that this buffer has an accessible backing array. 87 * 88 * @return The offset within this buffer's array of the first element of the buffer 89 * @throws java.nio.ReadOnlyBufferException If this buffer is backed by an array but is read-only 90 * @throws UnsupportedOperationException If this buffer is not backed by an accessible array 91 */ arrayOffset()92 public abstract int arrayOffset(); 93 94 /** 95 * Returns this buffer's position. 96 * 97 * @return The position of this buffer 98 */ position()99 public abstract int position(); 100 101 /** 102 * Sets this buffer's position. 103 * 104 * @param position The new position value; must be non-negative and no larger than the current 105 * limit 106 * @return This buffer 107 * @throws IllegalArgumentException If the preconditions on {@code position} do not hold 108 */ position(int position)109 public abstract AllocatedBuffer position(int position); 110 111 /** 112 * Returns this buffer's limit. 113 * 114 * @return The limit of this buffer 115 */ limit()116 public abstract int limit(); 117 118 /** 119 * Returns the number of elements between the current {@link #position()} and the {@link #limit()} 120 * . 121 * 122 * @return The number of elements remaining in this buffer 123 */ remaining()124 public abstract int remaining(); 125 126 /** 127 * Creates a new {@link AllocatedBuffer} that is backed by the given array. The returned buffer 128 * will have {@link #hasArray} == {@code true}, {@link #arrayOffset()} == {@code 0}, {@link 129 * #position()} == {@code 0} and {@link #limit()} equal to the length of {@code bytes}. 130 */ wrap(byte[] bytes)131 public static AllocatedBuffer wrap(byte[] bytes) { 132 return wrapNoCheck(bytes, 0, bytes.length); 133 } 134 135 /** 136 * Creates a new {@link AllocatedBuffer} that is backed by the given array. The returned buffer 137 * will have {@link #hasArray} == {@code true}, {@link #arrayOffset()} == {@code offset}, {@link 138 * #position()} == {@code 0} and {@link #limit()} == {@code length}. 139 */ wrap(final byte[] bytes, final int offset, final int length)140 public static AllocatedBuffer wrap(final byte[] bytes, final int offset, final int length) { 141 if (offset < 0 || length < 0 || (offset + length) > bytes.length) { 142 throw new IndexOutOfBoundsException( 143 String.format("bytes.length=%d, offset=%d, length=%d", bytes.length, offset, length)); 144 } 145 146 return wrapNoCheck(bytes, offset, length); 147 } 148 149 /** 150 * Creates a new {@link AllocatedBuffer} that is backed by the given {@link ByteBuffer}. The 151 * returned buffer will have {@link #hasNioBuffer} == {@code true}. 152 */ wrap(final ByteBuffer buffer)153 public static AllocatedBuffer wrap(final ByteBuffer buffer) { 154 checkNotNull(buffer, "buffer"); 155 156 return new AllocatedBuffer() { 157 158 @Override 159 public boolean hasNioBuffer() { 160 return true; 161 } 162 163 @Override 164 public ByteBuffer nioBuffer() { 165 return buffer; 166 } 167 168 @Override 169 public boolean hasArray() { 170 return buffer.hasArray(); 171 } 172 173 @Override 174 public byte[] array() { 175 return buffer.array(); 176 } 177 178 @Override 179 public int arrayOffset() { 180 return buffer.arrayOffset(); 181 } 182 183 @Override 184 public int position() { 185 return buffer.position(); 186 } 187 188 @Override 189 public AllocatedBuffer position(int position) { 190 buffer.position(position); 191 return this; 192 } 193 194 @Override 195 public int limit() { 196 return buffer.limit(); 197 } 198 199 @Override 200 public int remaining() { 201 return buffer.remaining(); 202 } 203 }; 204 } 205 206 private static AllocatedBuffer wrapNoCheck( 207 final byte[] bytes, final int offset, final int length) { 208 return new AllocatedBuffer() { 209 // Relative to offset. 210 private int position; 211 212 @Override 213 public boolean hasNioBuffer() { 214 return false; 215 } 216 217 @Override 218 public ByteBuffer nioBuffer() { 219 throw new UnsupportedOperationException(); 220 } 221 222 @Override 223 public boolean hasArray() { 224 return true; 225 } 226 227 @Override 228 public byte[] array() { 229 return bytes; 230 } 231 232 @Override 233 public int arrayOffset() { 234 return offset; 235 } 236 237 @Override 238 public int position() { 239 return position; 240 } 241 242 @Override 243 public AllocatedBuffer position(int position) { 244 if (position < 0 || position > length) { 245 throw new IllegalArgumentException("Invalid position: " + position); 246 } 247 this.position = position; 248 return this; 249 } 250 251 @Override 252 public int limit() { 253 // Relative to offset. 254 return length; 255 } 256 257 @Override 258 public int remaining() { 259 return length - position; 260 } 261 }; 262 } 263 } 264