ByteBuffer
ByteBuffer
stores contiguously allocated raw bytes. It is a random and sequential accessible sequence of zero or more bytes (octets).
struct ByteBuffer
Overview
Allocation
Use allocator.buffer(capacity: desiredCapacity)
to allocate a new ByteBuffer
.
Supported types
A variety of types can be read/written from/to a ByteBuffer
. Using Swift’s extension
mechanism you can easily create ByteBuffer
support for your own data types. Out of the box, ByteBuffer
supports for example the following types (non-exhaustive list):
String
/StaticString
Swift’s various (unsigned) integer types
Foundation
’sData
[UInt8]
and generally anyCollection
ofUInt8
Random Access
For every supported type ByteBuffer
usually contains two methods for random access:
get<Type>(at: Int, length: Int)
where<type>
is for exampleString
,Data
,Bytes
(for[UInt8]
)set<Type>(at: Int)
Example:
var buf = ...
buf.setString("Hello World", at: 0)
buf.moveWriterIndex(to: 11)
let helloWorld = buf.getString(at: 0, length: 11)
let written = buf.setInteger(17 as Int, at: 11)
buf.moveWriterIndex(forwardBy: written)
let seventeen: Int? = buf.getInteger(at: 11)
If needed, ByteBuffer
will automatically resize its storage to accommodate your set
request.
Sequential Access
ByteBuffer
provides two properties which are indices into the ByteBuffer
to support sequential access:
readerIndex
, the index of the next readable bytewriterIndex
, the index of the next byte to write
For every supported type ByteBuffer
usually contains two methods for sequential access:
read<Type>(length: Int)
to readlength
bytes from the currentreaderIndex
(and then advance the reader index bylength
bytes)write<Type>(Type)
to write, advancing thewriterIndex
by the appropriate amount
Example:
var buf = ...
buf.writeString("Hello World")
buf.writeInteger(17 as Int)
let helloWorld = buf.readString(length: 11)
let seventeen: Int = buf.readInteger()
Layout
+-------------------+------------------+------------------+
| discardable bytes | readable bytes | writable bytes |
| | (CONTENT) | |
+-------------------+------------------+------------------+
| | | |
0 <= readerIndex <= writerIndex <= capacity
The ‘discardable bytes’ are usually bytes that have already been read, they can however still be accessed using the random access methods. ‘Readable bytes’ are the bytes currently available to be read using the sequential access interface (read<Type>
/write<Type>
). Getting writableBytes
(bytes beyond the writer index) is undefined behaviour and might yield arbitrary bytes (not 0
initialised).
Slicing
ByteBuffer
supports slicing a ByteBuffer
without copying the underlying storage.
Example:
var buf = ...
let dataBytes: [UInt8] = [0xca, 0xfe, 0xba, 0xbe]
let dataBytesLength = UInt32(dataBytes.count)
buf.writeInteger(dataBytesLength) /* the header */
buf.writeBytes(dataBytes) /* the data */
let bufDataBytesOnly = buf.getSlice(at: 4, length: dataBytes.count)
/* `bufDataByteOnly` and `buf` will share their storage */
Notes
All ByteBuffer
methods that don’t contain the word ‘unsafe’ will only allow you to access the ‘readable bytes’.