-
- All Implemented Interfaces:
-
com.mobwith.httpmodule.BufferedSink,com.mobwith.httpmodule.BufferedSource,com.mobwith.httpmodule.Sink,com.mobwith.httpmodule.Source,java.io.Closeable,java.io.Flushable,java.lang.AutoCloseable,java.lang.Cloneable,java.nio.channels.ByteChannel,java.nio.channels.Channel,java.nio.channels.ReadableByteChannel,java.nio.channels.WritableByteChannel
public final class Buffer implements BufferedSource, BufferedSink, Cloneable, ByteChannel
A collection of bytes in memory.
Moving data from one buffer to another is fast. Instead of copying bytes from one place in memory to another, this class just changes ownership of the underlying byte arrays.
This buffer grows with your data. Just like ArrayList, each buffer starts small. It consumes only the memory it needs to.
This buffer pools its byte arrays. When you allocate a byte array in Java, the runtime must zero-fill the requested array before returning it to you. Even if you're going to write over that space anyway. This class avoids zero-fill and GC churn by pooling byte arrays.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description public final classBuffer.UnsafeCursorA handle to the underlying data in a buffer. This handle is unsafe because it does not enforceits own invariants. Instead, it assumes a careful user who has studied MobonOkio's implementationdetails and their consequences.
Buffer InternalsMost code should use
{@code Buffer}as a black box: a class that holds 0 or more bytes ofdata with efficient APIs to append data to the end and to consume data from the front. Usuallythis is also the most efficient way to use buffers because it allows MobonOkio to employ severaloptimizations, including:- Fast Allocation: Buffers use a shared pool of memory that is notzero-filled before use.
- Fast Resize: A buffer's capacity can change without copying itscontents.
- Fast Move: Memory ownership can be reassigned from one buffer toanother.
- Fast Copy: Multiple buffers can share the same underlying memory.
- Fast Encoding and Decoding: Common operations like UTF-8 encoding anddecimal decoding do not require intermediate objects to be allocated.
These optimizations all leverage the way MobonOkio stores data internally. MobonOkio Buffers areimplemented using a doubly-linked list of segments. Each segment is a contiguous range within a8 KiB
{@code byte[]}. Each segment has two indexes,{@code start}, the offset of the firstbyte of the array containing application data, and{@code end}, the offset of the first bytebeyond{@code start}whose data is undefined.New buffers are empty and have no segments:
We append 7 bytes of data to the end of our empty buffer. Internally, the buffer allocates asegment and writes its new data there. The lone segment has an 8 KiB byte array but only 7bytes of data:{@code * * Buffer buffer = new Buffer(); * }
When we read 4 bytes of data from the buffer, it finds its first segment and returns that datato us. As bytes are read the data is consumed. The segment tracks this by adjusting itsinternal indices.{@code * * buffer.writeUtf8("sealion"); * * // [ 's', 'e', 'a', 'l', 'i', 'o', 'n', '?', '?', '?', ...] * // ^ ^ * // start = 0 end = 7 * }
As we write data into a buffer we fill up its internal segments. When a write doesn't fit intoa buffer's last segment, additional segments are allocated and appended to the linked list ofsegments. Each segment has its own start and end indexes tracking where the user's data beginsand ends.{@code * * buffer.readUtf8(4); // "seal" * * // [ 's', 'e', 'a', 'l', 'i', 'o', 'n', '?', '?', '?', ...] * // ^ ^ * // start = 4 end = 7 * }
The start index is always inclusive and the end index is alwaysexclusive. The data preceding the start index is undefined, and the dataat and following the end index is undefined.{@code * * Buffer xoxo = new Buffer(); * xoxo.writeUtf8(Strings.repeat("xo", 5_000)); * * // [ 'x', 'o', 'x', 'o', 'x', 'o', 'x', 'o', ..., 'x', 'o', 'x', 'o'] * // ^ ^ * // start = 0 end = 8192 * // * // [ 'x', 'o', 'x', 'o', ..., 'x', 'o', 'x', 'o', '?', '?', '?', ...] * // ^ ^ * // start = 0 end = 1808 * }After the last byte of a segment has been read, that segment may be returned to an internalsegment pool. In addition to reducing the need to do garbage collection, segment pooling alsosaves the JVM from needing to zero-fill byte arrays. MobonOkio doesn't need to zero-fill its arraysbecause it always writes memory before it reads it. But if you look at a segment in a debuggeryou may see its effects. In this example, one of the "xoxo" segments above is reused in anunrelated buffer:
There is an optimization in{@code * * Buffer abc = new Buffer(); * abc.writeUtf8("abc"); * * // [ 'a', 'b', 'c', 'o', 'x', 'o', 'x', 'o', ...] * // ^ ^ * // start = 0 end = 3 * }{@code Buffer.clone()}and other methods that allows two segmentsto share the same underlying byte array. Clones can't write to the shared byte array; insteadthey allocate a new (private) segment early.
Segments are not shared when the shared region is small (ie. less than 1 KiB). This is intendedto prevent fragmentation in sharing-heavy use cases.Unsafe Cursor API{@code * * Buffer nana = new Buffer(); * nana.writeUtf8(Strings.repeat("na", 2_500)); * nana.readUtf8(2); // "na" * * // [ 'n', 'a', 'n', 'a', ..., 'n', 'a', 'n', 'a', '?', '?', '?', ...] * // ^ ^ * // start = 0 end = 5000 * * nana2 = nana.clone(); * nana2.writeUtf8("batman"); * * // [ 'n', 'a', 'n', 'a', ..., 'n', 'a', 'n', 'a', '?', '?', '?', ...] * // ^ ^ * // start = 0 end = 5000 * // * // [ 'b', 'a', 't', 'm', 'a', 'n', '?', '?', '?', ...] * // ^ ^ * // start = 0 end = 7 * }This class exposes privileged access to the internal byte arrays of a buffer. A cursoreither references the data of a single segment, it is before the first segment (
{@code * offset == -1}), or it is after the last segment ({@code offset == buffer.size}).Call seek to move the cursor to the segment that contains a specified offset. Afterseeking, data references the segment's internal byte array, start is thesegment's start and end is its end.
Call next to advance the cursor to the next segment. This returns -1 if there areno further segments in the buffer.
Use readUnsafe to create a cursor to read buffer data and to create a cursor to read and write buffer data. In either case,always call close when done with a cursor. This is convenient with Java 7'stry-with-resources syntax. In this example we read all of the bytes in a buffer into a bytearray:
{@code * * byte[] bufferBytes = new byte[(int) buffer.size()]; * * try (UnsafeCursor cursor = buffer.readUnsafe()) { * while (cursor.next() != -1) { * System.arraycopy(cursor.data, cursor.start, * bufferBytes, (int) cursor.offset, cursor.end - cursor.start); * } * } * }Change the capacity of a buffer with resizeBuffer. This is only permitted forread+write cursors. The buffer's size always changes from the end: shrinking it removes bytesfrom the end; growing it adds capacity to the end.
WarningsMost application developers should avoid this API. Those that must use this API shouldrespect these warnings.
Don't mutate a cursor. This class has public, non-final fields because thatis convenient for low-level I/O frameworks. Never assign values to these fields; instead usethe cursor API to adjust these.
Never mutate
{@code data}unless you have read+write access. You are on thehonor system to never write the buffer in read-only mode. Read-only mode may be more efficientthan read+write mode because it does not need to make private copies of shared segments.Only access data in
{@code [start..end)}. Other data in the byte arrayis undefined! It may contain private or sensitive data from other parts of your process.Always fill the new capacity when you grow a buffer. New capacity is notzero-filled and may contain data from other parts of your process. Avoid leaking thisinformation by always writing something to the newly-allocated capacity. Do not assume thatnew capacity will be filled with
{@code 0}; it will not be.Do not access a buffer while is being accessed by a cursor. Even simpleread-only operations like clone are unsafe because they mark segments as shared.
Do not hard-code the segment size in your application. It is possible thatsegment sizes will change with advances in hardware. Future versions of MobonOkio may even haveheterogeneous segment sizes.
These warnings are intended to help you to use this API safely. It's here for developersthat need absolutely the most throughput. Since that's you, here's one final performance tip.You can reuse instances of this class if you like. Use the overloads of readUnsafe and readAndWriteUnsafe that take a cursor and close it after use.
-
Constructor Summary
Constructors Constructor Description Buffer()
-
Method Summary
Modifier and Type Method Description final longsize()Returns the number of bytes currently in this buffer. Bufferbuffer()Returns this source's internal buffer. OutputStreamoutputStream()Returns an output stream that writes to this sink. BufferemitCompleteSegments()Writes complete segments to the underlying sink, if one exists. BufferedSinkemit()Writes all buffered data to the underlying sink, if one exists. booleanexhausted()Returns true if there are no more bytes in this source. voidrequire(long byteCount)Returns when the buffer contains at least {@code byteCount}bytes.booleanrequest(long byteCount)Returns true when the buffer contains at least {@code byteCount}bytes, expanding it asnecessary.InputStreaminputStream()Returns an input stream that reads from this source. final BuffercopyTo(OutputStream out)Copy the contents of this to {@code out}.final BuffercopyTo(OutputStream out, long offset, long byteCount)Copy {@code byteCount}bytes from this, starting at{@code offset}, to{@code out}.final BuffercopyTo(Buffer out, long offset, long byteCount)Copy {@code byteCount}bytes from this, starting at{@code offset}, to{@code out}.final BufferwriteTo(OutputStream out)Write the contents of this to {@code out}.final BufferwriteTo(OutputStream out, long byteCount)Write {@code byteCount}bytes from this to{@code out}.final BufferreadFrom(InputStream in)Read and exhaust bytes from {@code in}to this.final BufferreadFrom(InputStream in, long byteCount)Read {@code byteCount}bytes from{@code in}to this.final longcompleteSegmentByteCount()Returns the number of bytes in segments that are not writable. bytereadByte()Removes a byte from this source and returns it. final bytegetByte(long pos)Returns the byte at {@code pos}.shortreadShort()Removes two bytes from this source and returns a big-endian short. intreadInt()Removes four bytes from this source and returns a big-endian int. longreadLong()Removes eight bytes from this source and returns a big-endian long. shortreadShortLe()Removes two bytes from this source and returns a little-endian short. intreadIntLe()Removes four bytes from this source and returns a little-endian int. longreadLongLe()Removes eight bytes from this source and returns a little-endian long. longreadDecimalLong()Reads a long from this source in signed decimal form (i.e., as a string in base 10 withoptional leading '-'). longreadHexadecimalUnsignedLong()Reads a long form this source in hexadecimal form (i.e., as a string in base 16). ByteStringreadByteString()Removes all bytes bytes from this and returns them as a byte string. ByteStringreadByteString(long byteCount)Removes {@code byteCount}bytes from this and returns them as a byte string.intselect(Options options)Finds the first string in {@code options}that is a prefix of this buffer, consumes it fromthis buffer, and returns its index.voidreadFully(Buffer sink, long byteCount)Removes exactly {@code byteCount}bytes from this and appends them to{@code sink}.longreadAll(Sink sink)Removes all bytes from this and appends them to {@code sink}.StringreadUtf8()Removes all bytes from this, decodes them as UTF-8, and returns the string. StringreadUtf8(long byteCount)Removes {@code byteCount}bytes from this, decodes them as UTF-8, and returns the string.StringreadString(Charset charset)Removes all bytes from this, decodes them as {@code charset}, and returns the string.StringreadString(long byteCount, Charset charset)Removes {@code byteCount}bytes from this, decodes them as{@code charset}, and returns thestring.StringreadUtf8Line()Removes and returns characters up to but not including the next line break. StringreadUtf8LineStrict()Removes and returns characters up to but not including the next line break. StringreadUtf8LineStrict(long limit)Like readUtf8LineStrict, except this allows the caller to specify the longestallowed match. intreadUtf8CodePoint()Removes and returns a single UTF-8 code point, reading between 1 and 4 bytes as necessary. Array<byte>readByteArray()Removes all bytes from this and returns them as a byte array. Array<byte>readByteArray(long byteCount)Removes {@code byteCount}bytes from this and returns them as a byte array.intread(Array<byte> sink)Removes up to {@code sink.length}bytes from this and copies them into{@code sink}.voidreadFully(Array<byte> sink)Removes exactly {@code sink.length}bytes from this and copies them into{@code sink}.intread(Array<byte> sink, int offset, int byteCount)Removes up to {@code byteCount}bytes from this and copies them into{@code sink}at{@code * offset}.intread(ByteBuffer sink)final voidclear()Discards all bytes in this buffer. voidskip(long byteCount)Discards {@code byteCount}bytes from the head of this buffer.Bufferwrite(ByteString byteString)BufferwriteUtf8(String string)Encodes {@code string}in UTF-8 and writes it to this sink.BufferwriteUtf8(String string, int beginIndex, int endIndex)Encodes the characters at {@code beginIndex}up to{@code endIndex}from{@code string}inUTF-8 and writes it to this sink.BufferwriteUtf8CodePoint(int codePoint)Encodes {@code codePoint}in UTF-8 and writes it to this sink.BufferwriteString(String string, Charset charset)Encodes {@code string}in{@code charset}and writes it to this sink.BufferwriteString(String string, int beginIndex, int endIndex, Charset charset)Encodes the characters at {@code beginIndex}up to{@code endIndex}from{@code string}in{@code charset}and writes it to this sink.Bufferwrite(Array<byte> source)Like write, this writes a complete byte array tothis sink. Bufferwrite(Array<byte> source, int offset, int byteCount)Like write, this writes {@code byteCount}bytes of{@code source}, starting at{@code offset}.intwrite(ByteBuffer source)longwriteAll(Source source)Removes all bytes from {@code source}and appends them to this sink.BufferedSinkwrite(Source source, long byteCount)Removes {@code byteCount}bytes from{@code source}and appends them to this sink.BufferwriteByte(int b)Writes a byte to this sink. BufferwriteShort(int s)Writes a big-endian short to this sink using two bytes. BufferwriteShortLe(int s)Writes a little-endian short to this sink using two bytes. BufferwriteInt(int i)Writes a big-endian int to this sink using four bytes. BufferwriteIntLe(int i)Writes a little-endian int to this sink using four bytes. BufferwriteLong(long v)Writes a big-endian long to this sink using eight bytes. BufferwriteLongLe(long v)Writes a little-endian long to this sink using eight bytes. BufferwriteDecimalLong(long v)Writes a long to this sink in signed decimal form (i.e., as a string in base 10). BufferwriteHexadecimalUnsignedLong(long v)Writes a long to this sink in hexadecimal form (i.e., as a string in base 16). voidwrite(Buffer source, long byteCount)Removes {@code byteCount}bytes from{@code source}and appends them to this.longread(Buffer sink, long byteCount)Removes at least 1, and up to {@code byteCount}bytes from this and appendsthem to{@code sink}.longindexOf(byte b)Equivalent to indexOf(b, 0). longindexOf(byte b, long fromIndex)Returns the index of {@code b}in this at or beyond{@code fromIndex}, or-1 if this buffer does not contain{@code b}in that range.longindexOf(byte b, long fromIndex, long toIndex)Returns the index of {@code b}if it is found in the range of{@code fromIndex}inclusiveto{@code toIndex}exclusive.longindexOf(ByteString bytes)Equivalent to indexOf(bytes, 0). longindexOf(ByteString bytes, long fromIndex)Returns the index of the first match for {@code bytes}in the buffer at or after{@code * fromIndex}.longindexOfElement(ByteString targetBytes)Equivalent to indexOfElement(targetBytes, 0). longindexOfElement(ByteString targetBytes, long fromIndex)Returns the first index in this buffer that is at or after {@code fromIndex}and that containsany of the bytes in{@code targetBytes}.booleanrangeEquals(long offset, ByteString bytes)Returns true if the bytes at {@code offset}in this source equal{@code bytes}.booleanrangeEquals(long offset, ByteString bytes, int bytesOffset, int byteCount)Returns true if {@code byteCount}bytes at{@code offset}in this source equal{@code bytes}at{@code bytesOffset}.voidflush()Writes all buffered data to the underlying sink, if one exists. booleanisOpen()voidclose()Closes this source and releases the resources held by this source. Timeouttimeout()Returns the timeout for this source. final ByteStringmd5()Returns the 128-bit MD5 hash of this buffer. final ByteStringsha1()Returns the 160-bit SHA-1 hash of this buffer. final ByteStringsha256()Returns the 256-bit SHA-256 hash of this buffer. final ByteStringsha512()Returns the 512-bit SHA-512 hash of this buffer. final ByteStringhmacSha1(ByteString key)Returns the 160-bit SHA-1 HMAC of this buffer. final ByteStringhmacSha256(ByteString key)Returns the 256-bit SHA-256 HMAC of this buffer. final ByteStringhmacSha512(ByteString key)Returns the 512-bit SHA-512 HMAC of this buffer. booleanequals(Object o)inthashCode()StringtoString()Returns a human-readable string that describes the contents of this buffer. Bufferclone()Returns a deep copy of this buffer. final ByteStringsnapshot()Returns an immutable copy of this buffer as a byte string. final ByteStringsnapshot(int byteCount)Returns an immutable copy of the first {@code byteCount}bytes of this buffer as a byte string.final Buffer.UnsafeCursorreadUnsafe()final Buffer.UnsafeCursorreadUnsafe(Buffer.UnsafeCursor unsafeCursor)final Buffer.UnsafeCursorreadAndWriteUnsafe()final Buffer.UnsafeCursorreadAndWriteUnsafe(Buffer.UnsafeCursor unsafeCursor)-
Methods inherited from class com.mobwith.httpmodule.BufferedSource
rangeEquals -
Methods inherited from class java.io.Closeable
close -
Methods inherited from class java.nio.channels.ReadableByteChannel
read -
Methods inherited from class java.nio.channels.Channel
isOpen -
Methods inherited from class com.mobwith.httpmodule.BufferedSink
emitCompleteSegments, write, write, write, writeByte, writeDecimalLong, writeHexadecimalUnsignedLong, writeInt, writeIntLe, writeLong, writeLongLe, writeShort, writeShortLe, writeString, writeString, writeUtf8, writeUtf8, writeUtf8CodePoint -
Methods inherited from class java.io.Flushable
flush -
Methods inherited from class java.nio.channels.WritableByteChannel
write -
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
-
-
Method Detail
-
size
final long size()
Returns the number of bytes currently in this buffer.
-
outputStream
OutputStream outputStream()
Returns an output stream that writes to this sink.
-
emitCompleteSegments
Buffer emitCompleteSegments()
Writes complete segments to the underlying sink, if one exists. Like flush, butweaker. Use this to limit the memory held in the buffer to a single segment. Typicallyapplication code will not need to call this: it is only necessary when application code writesdirectly to this sink's buffer.
{@code * * BufferedSink b0 = new Buffer(); * BufferedSink b1 = MobonOkio.buffer(b0); * BufferedSink b2 = MobonOkio.buffer(b1); * * b2.buffer().write(new byte[20_000]); * assertEquals(20_000, b2.buffer().size()); * assertEquals( 0, b1.buffer().size()); * assertEquals( 0, b0.buffer().size()); * * b2.emitCompleteSegments(); * assertEquals( 3_616, b2.buffer().size()); * assertEquals( 0, b1.buffer().size()); * assertEquals(16_384, b0.buffer().size()); // This example assumes 8192 byte segments. * }
-
emit
BufferedSink emit()
Writes all buffered data to the underlying sink, if one exists. Like flush, butweaker. Call this before this buffered sink goes out of scope so that its data can reach itsdestination.
{@code * * BufferedSink b0 = new Buffer(); * BufferedSink b1 = MobonOkio.buffer(b0); * BufferedSink b2 = MobonOkio.buffer(b1); * * b2.writeUtf8("hello"); * assertEquals(5, b2.buffer().size()); * assertEquals(0, b1.buffer().size()); * assertEquals(0, b0.buffer().size()); * * b2.emit(); * assertEquals(0, b2.buffer().size()); * assertEquals(5, b1.buffer().size()); * assertEquals(0, b0.buffer().size()); * * b1.emit(); * assertEquals(0, b2.buffer().size()); * assertEquals(0, b1.buffer().size()); * assertEquals(5, b0.buffer().size()); * }
-
exhausted
boolean exhausted()
Returns true if there are no more bytes in this source. This will block until there are bytesto read or the source is definitely exhausted.
-
require
void require(long byteCount)
Returns when the buffer contains at least
{@code byteCount}bytes. Throws an java.io.EOFException if the source is exhausted before the required bytes can be read.
-
request
boolean request(long byteCount)
Returns true when the buffer contains at least
{@code byteCount}bytes, expanding it asnecessary. Returns false if the source is exhausted before the requested bytes can be read.
-
inputStream
InputStream inputStream()
Returns an input stream that reads from this source.
-
copyTo
final Buffer copyTo(OutputStream out)
Copy the contents of this to
{@code out}.
-
copyTo
final Buffer copyTo(OutputStream out, long offset, long byteCount)
Copy
{@code byteCount}bytes from this, starting at{@code offset}, to{@code out}.
-
copyTo
final Buffer copyTo(Buffer out, long offset, long byteCount)
Copy
{@code byteCount}bytes from this, starting at{@code offset}, to{@code out}.
-
writeTo
final Buffer writeTo(OutputStream out)
Write the contents of this to
{@code out}.
-
writeTo
final Buffer writeTo(OutputStream out, long byteCount)
Write
{@code byteCount}bytes from this to{@code out}.
-
readFrom
final Buffer readFrom(InputStream in)
Read and exhaust bytes from
{@code in}to this.
-
readFrom
final Buffer readFrom(InputStream in, long byteCount)
Read
{@code byteCount}bytes from{@code in}to this.
-
completeSegmentByteCount
final long completeSegmentByteCount()
Returns the number of bytes in segments that are not writable. This is thenumber of bytes that can be flushed immediately to an underlying sinkwithout harming throughput.
-
readByte
byte readByte()
Removes a byte from this source and returns it.
-
getByte
final byte getByte(long pos)
Returns the byte at
{@code pos}.
-
readShort
short readShort()
Removes two bytes from this source and returns a big-endian short.
{@code * * Buffer buffer = new Buffer() * .writeByte(0x7f) * .writeByte(0xff) * .writeByte(0x00) * .writeByte(0x0f); * assertEquals(4, buffer.size()); * * assertEquals(32767, buffer.readShort()); * assertEquals(2, buffer.size()); * * assertEquals(15, buffer.readShort()); * assertEquals(0, buffer.size()); * }
-
readInt
int readInt()
Removes four bytes from this source and returns a big-endian int.
{@code * * Buffer buffer = new Buffer() * .writeByte(0x7f) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x0f); * assertEquals(8, buffer.size()); * * assertEquals(2147483647, buffer.readInt()); * assertEquals(4, buffer.size()); * * assertEquals(15, buffer.readInt()); * assertEquals(0, buffer.size()); * }
-
readLong
long readLong()
Removes eight bytes from this source and returns a big-endian long.
{@code * * Buffer buffer = new Buffer() * .writeByte(0x7f) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x0f); * assertEquals(16, buffer.size()); * * assertEquals(9223372036854775807L, buffer.readLong()); * assertEquals(8, buffer.size()); * * assertEquals(15, buffer.readLong()); * assertEquals(0, buffer.size()); * }
-
readShortLe
short readShortLe()
Removes two bytes from this source and returns a little-endian short.
{@code * * Buffer buffer = new Buffer() * .writeByte(0xff) * .writeByte(0x7f) * .writeByte(0x0f) * .writeByte(0x00); * assertEquals(4, buffer.size()); * * assertEquals(32767, buffer.readShortLe()); * assertEquals(2, buffer.size()); * * assertEquals(15, buffer.readShortLe()); * assertEquals(0, buffer.size()); * }
-
readIntLe
int readIntLe()
Removes four bytes from this source and returns a little-endian int.
{@code * * Buffer buffer = new Buffer() * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0x7f) * .writeByte(0x0f) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00); * assertEquals(8, buffer.size()); * * assertEquals(2147483647, buffer.readIntLe()); * assertEquals(4, buffer.size()); * * assertEquals(15, buffer.readIntLe()); * assertEquals(0, buffer.size()); * }
-
readLongLe
long readLongLe()
Removes eight bytes from this source and returns a little-endian long.
{@code * * Buffer buffer = new Buffer() * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0xff) * .writeByte(0x7f) * .writeByte(0x0f) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00) * .writeByte(0x00); * assertEquals(16, buffer.size()); * * assertEquals(9223372036854775807L, buffer.readLongLe()); * assertEquals(8, buffer.size()); * * assertEquals(15, buffer.readLongLe()); * assertEquals(0, buffer.size()); * }
-
readDecimalLong
long readDecimalLong()
Reads a long from this source in signed decimal form (i.e., as a string in base 10 withoptional leading '-'). This will iterate until a non-digit character is found.
{@code * * Buffer buffer = new Buffer() * .writeUtf8("8675309 -123 00001"); * * assertEquals(8675309L, buffer.readDecimalLong()); * assertEquals(' ', buffer.readByte()); * assertEquals(-123L, buffer.readDecimalLong()); * assertEquals(' ', buffer.readByte()); * assertEquals(1L, buffer.readDecimalLong()); * }
-
readHexadecimalUnsignedLong
long readHexadecimalUnsignedLong()
Reads a long form this source in hexadecimal form (i.e., as a string in base 16). This williterate until a non-hexadecimal character is found.
{@code * * Buffer buffer = new Buffer() * .writeUtf8("ffff CAFEBABE 10"); * * assertEquals(65535L, buffer.readHexadecimalUnsignedLong()); * assertEquals(' ', buffer.readByte()); * assertEquals(0xcafebabeL, buffer.readHexadecimalUnsignedLong()); * assertEquals(' ', buffer.readByte()); * assertEquals(0x10L, buffer.readHexadecimalUnsignedLong()); * }
-
readByteString
ByteString readByteString()
Removes all bytes bytes from this and returns them as a byte string.
-
readByteString
ByteString readByteString(long byteCount)
Removes
{@code byteCount}bytes from this and returns them as a byte string.
-
select
int select(Options options)
Finds the first string in
{@code options}that is a prefix of this buffer, consumes it fromthis buffer, and returns its index. If no byte string in{@code options}is a prefix of thisbuffer this returns -1 and no bytes are consumed.This can be used as an alternative to readByteString or even readUtf8 ifthe set of expected values is known in advance.
{@code * * Options FIELDS = Options.of( * ByteString.encodeUtf8("depth="), * ByteString.encodeUtf8("height="), * ByteString.encodeUtf8("width=")); * * Buffer buffer = new Buffer() * .writeUtf8("width=640\n") * .writeUtf8("height=480\n"); * * assertEquals(2, buffer.select(FIELDS)); * assertEquals(640, buffer.readDecimalLong()); * assertEquals('\n', buffer.readByte()); * assertEquals(1, buffer.select(FIELDS)); * assertEquals(480, buffer.readDecimalLong()); * assertEquals('\n', buffer.readByte()); * }
-
readFully
void readFully(Buffer sink, long byteCount)
Removes exactly
{@code byteCount}bytes from this and appends them to{@code sink}. Throws an java.io.EOFException if the requested number of bytes cannot be read.
-
readAll
long readAll(Sink sink)
Removes all bytes from this and appends them to
{@code sink}. Returns the total number of byteswritten to{@code sink}which will be 0 if this is exhausted.
-
readUtf8
String readUtf8()
Removes all bytes from this, decodes them as UTF-8, and returns the string. Returns the emptystring if this source is empty.
{@code * * Buffer buffer = new Buffer() * .writeUtf8("Uh uh uh!") * .writeByte(' ') * .writeUtf8("You didn't say the magic word!"); * * assertEquals("Uh uh uh! You didn't say the magic word!", buffer.readUtf8()); * assertEquals(0, buffer.size()); * * assertEquals("", buffer.readUtf8()); * assertEquals(0, buffer.size()); * }
-
readUtf8
String readUtf8(long byteCount)
Removes
{@code byteCount}bytes from this, decodes them as UTF-8, and returns the string.{@code * * Buffer buffer = new Buffer() * .writeUtf8("Uh uh uh!") * .writeByte(' ') * .writeUtf8("You didn't say the magic word!"); * assertEquals(40, buffer.size()); * * assertEquals("Uh uh uh! You ", buffer.readUtf8(14)); * assertEquals(26, buffer.size()); * * assertEquals("didn't say the", buffer.readUtf8(14)); * assertEquals(12, buffer.size()); * * assertEquals(" magic word!", buffer.readUtf8(12)); * assertEquals(0, buffer.size()); * }
-
readString
String readString(Charset charset)
Removes all bytes from this, decodes them as
{@code charset}, and returns the string.
-
readString
String readString(long byteCount, Charset charset)
Removes
{@code byteCount}bytes from this, decodes them as{@code charset}, and returns thestring.
-
readUtf8Line
@Nullable() String readUtf8Line()
Removes and returns characters up to but not including the next line break. A line break iseither
{@code "\n"}or{@code "\r\n"}; these characters are not included in the result.{@code * * Buffer buffer = new Buffer() * .writeUtf8("I'm a hacker!\n") * .writeUtf8("That's what I said: you're a nerd.\n") * .writeUtf8("I prefer to be called a hacker!\n"); * assertEquals(81, buffer.size()); * * assertEquals("I'm a hacker!", buffer.readUtf8Line()); * assertEquals(67, buffer.size()); * * assertEquals("That's what I said: you're a nerd.", buffer.readUtf8Line()); * assertEquals(32, buffer.size()); * * assertEquals("I prefer to be called a hacker!", buffer.readUtf8Line()); * assertEquals(0, buffer.size()); * * assertEquals(null, buffer.readUtf8Line()); * assertEquals(0, buffer.size()); * }On the end of the stream this method returns null, just like . If the source doesn't end with a line break then an implicit linebreak is assumed. Null is returned once the source is exhausted. Use this for human-generateddata, where a trailing line break is optional.
-
readUtf8LineStrict
String readUtf8LineStrict()
Removes and returns characters up to but not including the next line break. A line break iseither
{@code "\n"}or{@code "\r\n"}; these characters are not included in the result.On the end of the stream this method throws. Every call must consume either'\r\n' or '\n'. If these characters are absent in the stream, an java.io.EOFException is thrown. Use this for machine-generated data where a missing line break implies truncatedinput.
-
readUtf8LineStrict
String readUtf8LineStrict(long limit)
Like readUtf8LineStrict, except this allows the caller to specify the longestallowed match. Use this to protect against streams that may not include
{@code "\n"}or{@code "\r\n"}.The returned string will have at most
{@code limit}UTF-8 bytes, and the maximum numberof bytes scanned is{@code limit + 2}. If{@code limit == 0}this will always throwan{@code EOFException}because no bytes will be scanned.This method is safe. No bytes are discarded if the match fails, and the caller is freeto try another match:
{@code * * Buffer buffer = new Buffer(); * buffer.writeUtf8("12345\r\n"); * * // This will throw! There must be \r\n or \n at the limit or before it. * buffer.readUtf8LineStrict(4); * * // No bytes have been consumed so the caller can retry. * assertEquals("12345", buffer.readUtf8LineStrict(5)); * }
-
readUtf8CodePoint
int readUtf8CodePoint()
Removes and returns a single UTF-8 code point, reading between 1 and 4 bytes as necessary.
If this source is exhausted before a complete code point can be read, this throws an and consumes no input.
If this source doesn't start with a properly-encoded UTF-8 code point, this method willremove 1 or more non-UTF-8 bytes and return the replacement character (
{@code U+FFFD}). Thiscovers encoding problems (the input is not properly-encoded UTF-8), characters out of range(beyond the 0x10ffff limit of Unicode), code points for UTF-16 surrogates (U+d800..U+dfff) andoverlong encodings (such as{@code 0xc080}for the NUL character in modified UTF-8).
-
readByteArray
Array<byte> readByteArray()
Removes all bytes from this and returns them as a byte array.
-
readByteArray
Array<byte> readByteArray(long byteCount)
Removes
{@code byteCount}bytes from this and returns them as a byte array.
-
read
int read(Array<byte> sink)
Removes up to
{@code sink.length}bytes from this and copies them into{@code sink}. Returnsthe number of bytes read, or -1 if this source is exhausted.
-
readFully
void readFully(Array<byte> sink)
Removes exactly
{@code sink.length}bytes from this and copies them into{@code sink}. Throwsan java.io.EOFException if the requested number of bytes cannot be read.
-
read
int read(Array<byte> sink, int offset, int byteCount)
Removes up to
{@code byteCount}bytes from this and copies them into{@code sink}at{@code * offset}. Returns the number of bytes read, or -1 if this source is exhausted.
-
read
int read(ByteBuffer sink)
-
clear
final void clear()
Discards all bytes in this buffer. Calling this method when you're donewith a buffer will return its segments to the pool.
-
skip
void skip(long byteCount)
Discards
{@code byteCount}bytes from the head of this buffer.
-
write
Buffer write(ByteString byteString)
-
writeUtf8
Buffer writeUtf8(String string)
Encodes
{@code string}in UTF-8 and writes it to this sink.{@code * * Buffer buffer = new Buffer(); * buffer.writeUtf8("Uh uh uh!"); * buffer.writeByte(' '); * buffer.writeUtf8("You didn't say the magic word!"); * * assertEquals("Uh uh uh! You didn't say the magic word!", buffer.readUtf8()); * }
-
writeUtf8
Buffer writeUtf8(String string, int beginIndex, int endIndex)
Encodes the characters at
{@code beginIndex}up to{@code endIndex}from{@code string}inUTF-8 and writes it to this sink.{@code * * Buffer buffer = new Buffer(); * buffer.writeUtf8("I'm a hacker!\n", 6, 12); * buffer.writeByte(' '); * buffer.writeUtf8("That's what I said: you're a nerd.\n", 29, 33); * buffer.writeByte(' '); * buffer.writeUtf8("I prefer to be called a hacker!\n", 24, 31); * * assertEquals("hacker nerd hacker!", buffer.readUtf8()); * }
-
writeUtf8CodePoint
Buffer writeUtf8CodePoint(int codePoint)
Encodes
{@code codePoint}in UTF-8 and writes it to this sink.
-
writeString
Buffer writeString(String string, Charset charset)
Encodes
{@code string}in{@code charset}and writes it to this sink.
-
writeString
Buffer writeString(String string, int beginIndex, int endIndex, Charset charset)
Encodes the characters at
{@code beginIndex}up to{@code endIndex}from{@code string}in{@code charset}and writes it to this sink.
-
write
Buffer write(Array<byte> source, int offset, int byteCount)
Like write, this writes
{@code byteCount}bytes of{@code source}, starting at{@code offset}.
-
write
int write(ByteBuffer source)
-
writeAll
long writeAll(Source source)
Removes all bytes from
{@code source}and appends them to this sink. Returns thenumber of bytes read which will be 0 if{@code source}is exhausted.
-
write
BufferedSink write(Source source, long byteCount)
Removes
{@code byteCount}bytes from{@code source}and appends them to this sink.
-
writeShort
Buffer writeShort(int s)
Writes a big-endian short to this sink using two bytes.
{@code * * Buffer buffer = new Buffer(); * buffer.writeShort(32767); * buffer.writeShort(15); * * assertEquals(4, buffer.size()); * assertEquals((byte) 0x7f, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x0f, buffer.readByte()); * assertEquals(0, buffer.size()); * }
-
writeShortLe
Buffer writeShortLe(int s)
Writes a little-endian short to this sink using two bytes.
{@code * * Buffer buffer = new Buffer(); * buffer.writeShortLe(32767); * buffer.writeShortLe(15); * * assertEquals(4, buffer.size()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0x7f, buffer.readByte()); * assertEquals((byte) 0x0f, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals(0, buffer.size()); * }
-
writeInt
Buffer writeInt(int i)
Writes a big-endian int to this sink using four bytes.
{@code * * Buffer buffer = new Buffer(); * buffer.writeInt(2147483647); * buffer.writeInt(15); * * assertEquals(8, buffer.size()); * assertEquals((byte) 0x7f, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x0f, buffer.readByte()); * assertEquals(0, buffer.size()); * }
-
writeIntLe
Buffer writeIntLe(int i)
Writes a little-endian int to this sink using four bytes.
{@code * * Buffer buffer = new Buffer(); * buffer.writeIntLe(2147483647); * buffer.writeIntLe(15); * * assertEquals(8, buffer.size()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0x7f, buffer.readByte()); * assertEquals((byte) 0x0f, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals(0, buffer.size()); * }
-
writeLong
Buffer writeLong(long v)
Writes a big-endian long to this sink using eight bytes.
{@code * * Buffer buffer = new Buffer(); * buffer.writeLong(9223372036854775807L); * buffer.writeLong(15); * * assertEquals(16, buffer.size()); * assertEquals((byte) 0x7f, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x0f, buffer.readByte()); * assertEquals(0, buffer.size()); * }
-
writeLongLe
Buffer writeLongLe(long v)
Writes a little-endian long to this sink using eight bytes.
{@code * * Buffer buffer = new Buffer(); * buffer.writeLongLe(9223372036854775807L); * buffer.writeLongLe(15); * * assertEquals(16, buffer.size()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0xff, buffer.readByte()); * assertEquals((byte) 0x7f, buffer.readByte()); * assertEquals((byte) 0x0f, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals((byte) 0x00, buffer.readByte()); * assertEquals(0, buffer.size()); * }
-
writeDecimalLong
Buffer writeDecimalLong(long v)
Writes a long to this sink in signed decimal form (i.e., as a string in base 10).
{@code * * Buffer buffer = new Buffer(); * buffer.writeDecimalLong(8675309L); * buffer.writeByte(' '); * buffer.writeDecimalLong(-123L); * buffer.writeByte(' '); * buffer.writeDecimalLong(1L); * * assertEquals("8675309 -123 1", buffer.readUtf8()); * }
-
writeHexadecimalUnsignedLong
Buffer writeHexadecimalUnsignedLong(long v)
Writes a long to this sink in hexadecimal form (i.e., as a string in base 16).
{@code * * Buffer buffer = new Buffer(); * buffer.writeHexadecimalUnsignedLong(65535L); * buffer.writeByte(' '); * buffer.writeHexadecimalUnsignedLong(0xcafebabeL); * buffer.writeByte(' '); * buffer.writeHexadecimalUnsignedLong(0x10L); * * assertEquals("ffff cafebabe 10", buffer.readUtf8()); * }
-
write
void write(Buffer source, long byteCount)
Removes
{@code byteCount}bytes from{@code source}and appends them to this.
-
read
long read(Buffer sink, long byteCount)
Removes at least 1, and up to
{@code byteCount}bytes from this and appendsthem to{@code sink}. Returns the number of bytes read, or -1 if thissource is exhausted.
-
indexOf
long indexOf(byte b)
Equivalent to indexOf(b, 0).
-
indexOf
long indexOf(byte b, long fromIndex)
Returns the index of
{@code b}in this at or beyond{@code fromIndex}, or-1 if this buffer does not contain{@code b}in that range.
-
indexOf
long indexOf(byte b, long fromIndex, long toIndex)
Returns the index of
{@code b}if it is found in the range of{@code fromIndex}inclusiveto{@code toIndex}exclusive. If{@code b}isn't found, or if{@code fromIndex == toIndex},then -1 is returned.The scan terminates at either
{@code toIndex}or the end of the buffer, whichever comesfirst. The maximum number of bytes scanned is{@code toIndex-fromIndex}.
-
indexOf
long indexOf(ByteString bytes)
Equivalent to indexOf(bytes, 0).
-
indexOf
long indexOf(ByteString bytes, long fromIndex)
Returns the index of the first match for
{@code bytes}in the buffer at or after{@code * fromIndex}. This expands the buffer as necessary until{@code bytes}is found. This reads anunbounded number of bytes into the buffer. Returns -1 if the stream is exhausted before therequested bytes are found.{@code * * ByteString MOVE = ByteString.encodeUtf8("move"); * * Buffer buffer = new Buffer(); * buffer.writeUtf8("Don't move! He can't see us if we don't move."); * * assertEquals(6, buffer.indexOf(MOVE)); * assertEquals(40, buffer.indexOf(MOVE, 12)); * }
-
indexOfElement
long indexOfElement(ByteString targetBytes)
Equivalent to indexOfElement(targetBytes, 0).
-
indexOfElement
long indexOfElement(ByteString targetBytes, long fromIndex)
Returns the first index in this buffer that is at or after
{@code fromIndex}and that containsany of the bytes in{@code targetBytes}. This expands the buffer as necessary until a targetbyte is found. This reads an unbounded number of bytes into the buffer. Returns -1 if thestream is exhausted before the requested byte is found.{@code * * ByteString ANY_VOWEL = ByteString.encodeUtf8("AEOIUaeoiu"); * * Buffer buffer = new Buffer(); * buffer.writeUtf8("Dr. Alan Grant"); * * assertEquals(4, buffer.indexOfElement(ANY_VOWEL)); // 'A' in 'Alan'. * assertEquals(11, buffer.indexOfElement(ANY_VOWEL, 9)); // 'a' in 'Grant'. * }
-
rangeEquals
boolean rangeEquals(long offset, ByteString bytes)
Returns true if the bytes at
{@code offset}in this source equal{@code bytes}. This expandsthe buffer as necessary until a byte does not match, all bytes are matched, or if the streamis exhausted before enough bytes could determine a match.{@code * * ByteString simonSays = ByteString.encodeUtf8("Simon says:"); * * Buffer standOnOneLeg = new Buffer().writeUtf8("Simon says: Stand on one leg."); * assertTrue(standOnOneLeg.rangeEquals(0, simonSays)); * * Buffer payMeMoney = new Buffer().writeUtf8("Pay me $1,000,000."); * assertFalse(payMeMoney.rangeEquals(0, simonSays)); * }
-
rangeEquals
boolean rangeEquals(long offset, ByteString bytes, int bytesOffset, int byteCount)
Returns true if
{@code byteCount}bytes at{@code offset}in this source equal{@code bytes}at{@code bytesOffset}. This expands the buffer as necessary until a byte does not match, allbytes are matched, or if the stream is exhausted before enough bytes could determine a match.
-
flush
void flush()
Writes all buffered data to the underlying sink, if one exists. Then that sink is recursivelyflushed which pushes data as far as possible towards its ultimate destination. Typically thatdestination is a network socket or file.
{@code * * BufferedSink b0 = new Buffer(); * BufferedSink b1 = MobonOkio.buffer(b0); * BufferedSink b2 = MobonOkio.buffer(b1); * * b2.writeUtf8("hello"); * assertEquals(5, b2.buffer().size()); * assertEquals(0, b1.buffer().size()); * assertEquals(0, b0.buffer().size()); * * b2.flush(); * assertEquals(0, b2.buffer().size()); * assertEquals(0, b1.buffer().size()); * assertEquals(5, b0.buffer().size()); * }
-
isOpen
boolean isOpen()
-
close
void close()
Closes this source and releases the resources held by this source. It is anerror to read a closed source. It is safe to close a source more than once.
-
md5
final ByteString md5()
Returns the 128-bit MD5 hash of this buffer.
-
sha1
final ByteString sha1()
Returns the 160-bit SHA-1 hash of this buffer.
-
sha256
final ByteString sha256()
Returns the 256-bit SHA-256 hash of this buffer.
-
sha512
final ByteString sha512()
Returns the 512-bit SHA-512 hash of this buffer.
-
hmacSha1
final ByteString hmacSha1(ByteString key)
Returns the 160-bit SHA-1 HMAC of this buffer.
-
hmacSha256
final ByteString hmacSha256(ByteString key)
Returns the 256-bit SHA-256 HMAC of this buffer.
-
hmacSha512
final ByteString hmacSha512(ByteString key)
Returns the 512-bit SHA-512 HMAC of this buffer.
-
hashCode
int hashCode()
-
toString
String toString()
Returns a human-readable string that describes the contents of this buffer. Typically thisis a string like
{@code [text=Hello]}or{@code [hex=0000ffff]}.
-
snapshot
final ByteString snapshot()
Returns an immutable copy of this buffer as a byte string.
-
snapshot
final ByteString snapshot(int byteCount)
Returns an immutable copy of the first
{@code byteCount}bytes of this buffer as a byte string.
-
readUnsafe
final Buffer.UnsafeCursor readUnsafe()
-
readUnsafe
final Buffer.UnsafeCursor readUnsafe(Buffer.UnsafeCursor unsafeCursor)
-
readAndWriteUnsafe
final Buffer.UnsafeCursor readAndWriteUnsafe()
-
readAndWriteUnsafe
final Buffer.UnsafeCursor readAndWriteUnsafe(Buffer.UnsafeCursor unsafeCursor)
-
-
-
-