2 * Copyright 2015-present Open Networking Foundation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package io.atomix.storage.buffer;
18 import io.atomix.utils.concurrent.ReferenceManager;
19 import io.atomix.utils.memory.Memory;
21 import java.nio.BufferOverflowException;
22 import java.nio.BufferUnderflowException;
23 import java.nio.ByteOrder;
24 import java.nio.InvalidMarkException;
25 import java.nio.charset.Charset;
26 import java.nio.charset.StandardCharsets;
27 import java.util.concurrent.atomic.AtomicInteger;
29 import static io.atomix.storage.buffer.Bytes.BOOLEAN;
30 import static io.atomix.storage.buffer.Bytes.BYTE;
31 import static io.atomix.storage.buffer.Bytes.SHORT;
34 * Abstract buffer implementation.
36 * @author <a href="http://github.com/kuujo">Jordan Halterman</a>
38 public abstract class AbstractBuffer implements Buffer {
39 static final int DEFAULT_INITIAL_CAPACITY = 4096;
40 static final int MAX_SIZE = Integer.MAX_VALUE - 5;
42 protected final Bytes bytes;
44 private int initialCapacity;
46 private int maxCapacity;
48 private int limit = -1;
49 private int mark = -1;
50 private final AtomicInteger references = new AtomicInteger();
51 protected final ReferenceManager<Buffer> referenceManager;
52 private SwappedBuffer swap;
54 protected AbstractBuffer(Bytes bytes, ReferenceManager<Buffer> referenceManager) {
55 this(bytes, 0, 0, 0, referenceManager);
58 protected AbstractBuffer(Bytes bytes, int offset, int initialCapacity, int maxCapacity, ReferenceManager<Buffer> referenceManager) {
60 throw new NullPointerException("bytes cannot be null");
63 throw new IndexOutOfBoundsException("offset out of bounds of the underlying byte array");
68 this.initialCapacity = initialCapacity;
69 this.maxCapacity = maxCapacity;
70 capacity(initialCapacity);
71 this.referenceManager = referenceManager;
76 * Resets the buffer's internal offset and capacity.
78 protected AbstractBuffer reset(int offset, int capacity, int maxCapacity) {
81 this.initialCapacity = capacity;
82 this.maxCapacity = maxCapacity;
83 capacity(initialCapacity);
90 public Buffer acquire() {
91 references.incrementAndGet();
96 public boolean release() {
97 if (references.decrementAndGet() == 0) {
98 if (referenceManager != null) {
99 referenceManager.release(this);
109 public int references() {
110 return references.get();
114 public Bytes bytes() {
119 public ByteOrder order() {
120 return bytes.order();
124 public Buffer order(ByteOrder order) {
126 throw new NullPointerException("order cannot be null");
128 if (order == order()) {
134 swap = new SwappedBuffer(this, offset, capacity, maxCapacity, referenceManager);
139 public boolean isDirect() {
140 return bytes.isDirect();
144 public boolean isFile() {
145 return bytes.isFile();
149 public boolean isReadOnly() {
154 public Buffer asReadOnlyBuffer() {
155 return new ReadOnlyBuffer(this, referenceManager)
156 .reset(offset, capacity, maxCapacity)
162 public Buffer compact() {
163 compact(offset(position), offset, (limit != -1 ? limit : capacity) - offset(position));
168 * Compacts the given bytes.
170 protected abstract void compact(int from, int to, int length);
173 public Buffer slice() {
174 int maxCapacity = this.maxCapacity - position;
175 int capacity = Math.min(Math.min(initialCapacity, maxCapacity), bytes.size() - offset(position));
177 capacity = maxCapacity = limit - position;
179 return new SlicedBuffer(this, bytes, offset(position), capacity, maxCapacity);
183 public Buffer slice(int length) {
184 checkSlice(position, length);
185 return new SlicedBuffer(this, bytes, offset(position), length, length);
189 public Buffer slice(int offset, int length) {
190 checkSlice(offset, length);
191 return new SlicedBuffer(this, bytes, offset(offset), length, length);
195 public int offset() {
200 public int capacity() {
205 * Updates the buffer capacity.
207 public Buffer capacity(int capacity) {
208 if (capacity > maxCapacity) {
209 throw new IllegalArgumentException("capacity cannot be greater than maximum capacity");
210 } else if (capacity < this.capacity) {
211 throw new IllegalArgumentException("capacity cannot be decreased");
212 } else if (capacity != this.capacity) {
213 // It's possible that the bytes could already meet the requirements of the capacity.
214 if (offset(capacity) > bytes.size()) {
215 bytes.resize((int) Math.min(Memory.Util.toPow2(offset(capacity)), Integer.MAX_VALUE));
217 this.capacity = capacity;
223 public int maxCapacity() {
228 public int position() {
233 public Buffer position(int position) {
234 if (limit != -1 && position > limit) {
235 throw new IllegalArgumentException("position cannot be greater than limit");
236 } else if (limit == -1 && position > maxCapacity) {
237 throw new IllegalArgumentException("position cannot be greater than capacity");
239 if (position > capacity) {
240 capacity((int) Math.min(maxCapacity, Memory.Util.toPow2(position)));
242 this.position = position;
247 * Returns the real offset of the given relative offset.
249 private int offset(int offset) {
250 return this.offset + offset;
259 public Buffer limit(int limit) {
260 if (limit > maxCapacity) {
261 throw new IllegalArgumentException("limit cannot be greater than buffer capacity");
264 throw new IllegalArgumentException("limit cannot be negative");
266 if (limit != -1 && offset(limit) > bytes.size()) {
267 bytes.resize(offset(limit));
274 public int remaining() {
275 return (limit == -1 ? maxCapacity : limit) - position;
279 public boolean hasRemaining() {
280 return remaining() > 0;
284 public Buffer flip() {
292 public Buffer mark() {
293 this.mark = position;
298 public Buffer rewind() {
305 public Buffer reset() {
307 throw new InvalidMarkException();
314 public Buffer skip(int length) {
315 if (length > remaining()) {
316 throw new IndexOutOfBoundsException("length cannot be greater than remaining bytes in the buffer");
323 public Buffer clear() {
331 * Checks that the offset is within the bounds of the buffer.
333 protected void checkOffset(int offset) {
334 if (offset(offset) < this.offset) {
335 throw new IndexOutOfBoundsException();
336 } else if (limit == -1) {
337 if (offset > maxCapacity) {
338 throw new IndexOutOfBoundsException();
341 if (offset > limit) {
342 throw new IndexOutOfBoundsException();
348 * Checks bounds for a slice.
350 protected int checkSlice(int offset, int length) {
353 if (offset + length > capacity) {
354 if (capacity < maxCapacity) {
355 capacity(calculateCapacity(offset + length));
357 throw new BufferUnderflowException();
361 if (offset + length > limit) {
362 throw new BufferUnderflowException();
365 return offset(offset);
369 * Checks bounds for a read for the given length.
371 protected int checkRead(int length) {
372 checkRead(position, length);
373 int previousPosition = this.position;
374 this.position = previousPosition + length;
375 return offset(previousPosition);
379 * Checks bounds for a read.
381 protected int checkRead(int offset, int length) {
384 if (offset + length > capacity) {
385 if (capacity < maxCapacity) {
386 if (this.offset + offset + length <= bytes.size()) {
387 capacity = bytes.size() - this.offset;
389 capacity(calculateCapacity(offset + length));
392 throw new BufferUnderflowException();
396 if (offset + length > limit) {
397 throw new BufferUnderflowException();
400 return offset(offset);
404 * Checks bounds for a write of the given length.
406 protected int checkWrite(int length) {
407 checkWrite(position, length);
408 int previousPosition = this.position;
409 this.position = previousPosition + length;
410 return offset(previousPosition);
414 * Checks bounds for a write.
416 protected int checkWrite(int offset, int length) {
419 if (offset + length > capacity) {
420 if (capacity < maxCapacity) {
421 capacity(calculateCapacity(offset + length));
423 throw new BufferOverflowException();
427 if (offset + length > limit) {
428 throw new BufferOverflowException();
431 return offset(offset);
435 * Calculates the next capacity that meets the given minimum capacity.
437 private int calculateCapacity(int minimumCapacity) {
438 int newCapacity = Math.min(Math.max(capacity, 2), minimumCapacity);
439 while (newCapacity < Math.min(minimumCapacity, maxCapacity)) {
442 return Math.min(newCapacity, maxCapacity);
446 public Buffer zero() {
452 public Buffer zero(int offset) {
454 bytes.zero(offset(offset));
459 public Buffer zero(int offset, int length) {
461 bytes.zero(offset(offset), length);
466 public Buffer read(Buffer buffer) {
467 int length = Math.min(buffer.remaining(), remaining());
468 read(buffer.bytes(), buffer.offset() + buffer.position(), length);
469 buffer.position(buffer.position() + length);
474 public Buffer read(Bytes bytes) {
475 this.bytes.read(checkRead(bytes.size()), bytes, 0, bytes.size());
480 public Buffer read(Bytes bytes, int offset, int length) {
481 this.bytes.read(checkRead(length), bytes, offset, length);
486 public Buffer read(int srcOffset, Bytes bytes, int dstOffset, int length) {
487 this.bytes.read(checkRead(srcOffset, length), bytes, dstOffset, length);
492 public Buffer read(byte[] bytes) {
493 this.bytes.read(checkRead(bytes.length), bytes, 0, bytes.length);
498 public Buffer read(byte[] bytes, int offset, int length) {
499 this.bytes.read(checkRead(length), bytes, offset, length);
504 public Buffer read(int srcOffset, byte[] bytes, int dstOffset, int length) {
505 this.bytes.read(checkRead(srcOffset, length), bytes, dstOffset, length);
510 public int readByte() {
511 return bytes.readByte(checkRead(BYTE));
515 public int readByte(int offset) {
516 return bytes.readByte(checkRead(offset, BYTE));
520 public int readUnsignedByte() {
521 return bytes.readUnsignedByte(checkRead(BYTE));
525 public int readUnsignedByte(int offset) {
526 return bytes.readUnsignedByte(checkRead(offset, BYTE));
530 public char readChar() {
531 return bytes.readChar(checkRead(Bytes.CHARACTER));
535 public char readChar(int offset) {
536 return bytes.readChar(checkRead(offset, Bytes.CHARACTER));
540 public short readShort() {
541 return bytes.readShort(checkRead(SHORT));
545 public short readShort(int offset) {
546 return bytes.readShort(checkRead(offset, SHORT));
550 public int readUnsignedShort() {
551 return bytes.readUnsignedShort(checkRead(SHORT));
555 public int readUnsignedShort(int offset) {
556 return bytes.readUnsignedShort(checkRead(offset, SHORT));
560 public int readMedium() {
561 return bytes.readMedium(checkRead(3));
565 public int readMedium(int offset) {
566 return bytes.readMedium(checkRead(offset, 3));
570 public int readUnsignedMedium() {
571 return bytes.readUnsignedMedium(checkRead(3));
575 public int readUnsignedMedium(int offset) {
576 return bytes.readUnsignedMedium(checkRead(offset, 3));
580 public int readInt() {
581 return bytes.readInt(checkRead(Bytes.INTEGER));
585 public int readInt(int offset) {
586 return bytes.readInt(checkRead(offset, Bytes.INTEGER));
590 public long readUnsignedInt() {
591 return bytes.readUnsignedInt(checkRead(Bytes.INTEGER));
595 public long readUnsignedInt(int offset) {
596 return bytes.readUnsignedInt(checkRead(offset, Bytes.INTEGER));
600 public long readLong() {
601 return bytes.readLong(checkRead(Bytes.LONG));
605 public long readLong(int offset) {
606 return bytes.readLong(checkRead(offset, Bytes.LONG));
610 public float readFloat() {
611 return bytes.readFloat(checkRead(Bytes.FLOAT));
615 public float readFloat(int offset) {
616 return bytes.readFloat(checkRead(offset, Bytes.FLOAT));
620 public double readDouble() {
621 return bytes.readDouble(checkRead(Bytes.DOUBLE));
625 public double readDouble(int offset) {
626 return bytes.readDouble(checkRead(offset, Bytes.DOUBLE));
630 public boolean readBoolean() {
631 return bytes.readBoolean(checkRead(BYTE));
635 public boolean readBoolean(int offset) {
636 return bytes.readBoolean(checkRead(offset, BYTE));
640 public String readString(Charset charset) {
641 if (readBoolean(position)) {
642 byte[] bytes = new byte[readUnsignedShort(position + BOOLEAN)];
643 read(position + BOOLEAN + SHORT, bytes, 0, bytes.length);
644 this.position += BOOLEAN + SHORT + bytes.length;
645 return new String(bytes, charset);
647 this.position += BOOLEAN;
653 public String readString(int offset, Charset charset) {
654 if (readBoolean(offset)) {
655 byte[] bytes = new byte[readUnsignedShort(offset + BOOLEAN)];
656 read(offset + BOOLEAN + SHORT, bytes, 0, bytes.length);
657 return new String(bytes, charset);
663 public String readString() {
664 return readString(Charset.defaultCharset());
668 public String readString(int offset) {
669 return readString(offset, Charset.defaultCharset());
673 public String readUTF8() {
674 return readString(StandardCharsets.UTF_8);
678 public String readUTF8(int offset) {
679 return readString(offset, StandardCharsets.UTF_8);
683 public Buffer write(Buffer buffer) {
684 int length = Math.min(buffer.remaining(), remaining());
685 write(buffer.bytes(), buffer.offset() + buffer.position(), length);
686 buffer.position(buffer.position() + length);
691 public Buffer write(Bytes bytes) {
692 this.bytes.write(checkWrite(bytes.size()), bytes, 0, bytes.size());
697 public Buffer write(Bytes bytes, int offset, int length) {
698 this.bytes.write(checkWrite(length), bytes, offset, length);
703 public Buffer write(int offset, Bytes bytes, int srcOffset, int length) {
704 this.bytes.write(checkWrite(offset, length), bytes, srcOffset, length);
709 public Buffer write(byte[] bytes) {
710 this.bytes.write(checkWrite(bytes.length), bytes, 0, bytes.length);
715 public Buffer write(byte[] bytes, int offset, int length) {
716 this.bytes.write(checkWrite(length), bytes, offset, length);
721 public Buffer write(int offset, byte[] bytes, int srcOffset, int length) {
722 this.bytes.write(checkWrite(offset, length), bytes, srcOffset, length);
727 public Buffer writeByte(int b) {
728 bytes.writeByte(checkWrite(BYTE), b);
733 public Buffer writeByte(int offset, int b) {
734 bytes.writeByte(checkWrite(offset, BYTE), b);
739 public Buffer writeUnsignedByte(int b) {
740 bytes.writeUnsignedByte(checkWrite(BYTE), b);
745 public Buffer writeUnsignedByte(int offset, int b) {
746 bytes.writeUnsignedByte(checkWrite(offset, BYTE), b);
751 public Buffer writeChar(char c) {
752 bytes.writeChar(checkWrite(Bytes.CHARACTER), c);
757 public Buffer writeChar(int offset, char c) {
758 bytes.writeChar(checkWrite(offset, Bytes.CHARACTER), c);
763 public Buffer writeShort(short s) {
764 bytes.writeShort(checkWrite(SHORT), s);
769 public Buffer writeShort(int offset, short s) {
770 bytes.writeShort(checkWrite(offset, SHORT), s);
775 public Buffer writeUnsignedShort(int s) {
776 bytes.writeUnsignedShort(checkWrite(SHORT), s);
781 public Buffer writeUnsignedShort(int offset, int s) {
782 bytes.writeUnsignedShort(checkWrite(offset, SHORT), s);
787 public Buffer writeMedium(int m) {
788 bytes.writeMedium(checkWrite(3), m);
793 public Buffer writeMedium(int offset, int m) {
794 bytes.writeMedium(checkWrite(offset, 3), m);
799 public Buffer writeUnsignedMedium(int m) {
800 bytes.writeUnsignedMedium(checkWrite(3), m);
805 public Buffer writeUnsignedMedium(int offset, int m) {
806 bytes.writeUnsignedMedium(checkWrite(offset, 3), m);
811 public Buffer writeInt(int i) {
812 bytes.writeInt(checkWrite(Bytes.INTEGER), i);
817 public Buffer writeInt(int offset, int i) {
818 bytes.writeInt(checkWrite(offset, Bytes.INTEGER), i);
823 public Buffer writeUnsignedInt(long i) {
824 bytes.writeUnsignedInt(checkWrite(Bytes.INTEGER), i);
829 public Buffer writeUnsignedInt(int offset, long i) {
830 bytes.writeUnsignedInt(checkWrite(offset, Bytes.INTEGER), i);
835 public Buffer writeLong(long l) {
836 bytes.writeLong(checkWrite(Bytes.LONG), l);
841 public Buffer writeLong(int offset, long l) {
842 bytes.writeLong(checkWrite(offset, Bytes.LONG), l);
847 public Buffer writeFloat(float f) {
848 bytes.writeFloat(checkWrite(Bytes.FLOAT), f);
853 public Buffer writeFloat(int offset, float f) {
854 bytes.writeFloat(checkWrite(offset, Bytes.FLOAT), f);
859 public Buffer writeDouble(double d) {
860 bytes.writeDouble(checkWrite(Bytes.DOUBLE), d);
865 public Buffer writeDouble(int offset, double d) {
866 bytes.writeDouble(checkWrite(offset, Bytes.DOUBLE), d);
871 public Buffer writeBoolean(boolean b) {
872 bytes.writeBoolean(checkWrite(BYTE), b);
877 public Buffer writeBoolean(int offset, boolean b) {
878 bytes.writeBoolean(checkWrite(offset, BYTE), b);
883 public Buffer writeString(String s, Charset charset) {
885 return writeBoolean(checkWrite(BOOLEAN), Boolean.FALSE);
887 byte[] bytes = s.getBytes(charset);
888 checkWrite(position, BOOLEAN + SHORT + bytes.length);
889 writeBoolean(Boolean.TRUE)
890 .writeUnsignedShort(bytes.length)
891 .write(bytes, 0, bytes.length);
897 public Buffer writeString(int offset, String s, Charset charset) {
899 return writeBoolean(checkWrite(offset, BOOLEAN), Boolean.FALSE);
901 byte[] bytes = s.getBytes(charset);
902 checkWrite(offset, BOOLEAN + SHORT + bytes.length);
903 writeBoolean(offset, Boolean.TRUE)
904 .writeUnsignedShort(offset + BOOLEAN, bytes.length)
905 .write(offset + BOOLEAN + SHORT, bytes, 0, bytes.length);
911 public Buffer writeString(String s) {
912 return writeString(s, Charset.defaultCharset());
916 public Buffer writeString(int offset, String s) {
917 return writeString(offset, s, Charset.defaultCharset());
921 public Buffer writeUTF8(String s) {
922 return writeString(s, StandardCharsets.UTF_8);
926 public Buffer writeUTF8(int offset, String s) {
927 return writeString(offset, s, StandardCharsets.UTF_8);
931 public Buffer flush() {
937 public void close() {
939 if (referenceManager != null) {
940 referenceManager.release(this);