blob: c6d007ddfac079b20041a40c280bf7aa6d470df3 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package internal
import (
"encoding/binary"
)
// Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer interface {
ReadableBytes() uint32
WritableBytes() uint32
// Capacity returns the capacity of the buffer's underlying byte slice,
// that is, the total space allocated for the buffer's data.
Capacity() uint32
IsWritable() bool
Read(size uint32) []byte
Get(readerIndex uint32, size uint32) []byte
ReadableSlice() []byte
WritableSlice() []byte
// WrittenBytes advance the writer index when data was written in a slice
WrittenBytes(size uint32)
// MoveToFront copy the available portion of data at the beginning of the buffer
MoveToFront()
ReadUint16() uint16
ReadUint32() uint32
WriteUint16(n uint16)
WriteUint32(n uint32)
WriterIndex() uint32
ReaderIndex() uint32
Write(s []byte)
Put(writerIdx uint32, s []byte)
PutUint32(n uint32, writerIdx uint32)
Resize(newSize uint32)
ResizeIfNeeded(spaceNeeded uint32)
// Clear will clear the current buffer data.
Clear()
}
type buffer struct {
data []byte
readerIdx uint32
writerIdx uint32
}
// NewBuffer creates and initializes a new Buffer using buf as its initial contents.
func NewBuffer(size int) Buffer {
return &buffer{
data: make([]byte, size),
readerIdx: 0,
writerIdx: 0,
}
}
func NewBufferWrapper(buf []byte) Buffer {
return &buffer{
data: buf,
readerIdx: 0,
writerIdx: uint32(len(buf)),
}
}
func (b *buffer) ReadableBytes() uint32 {
return b.writerIdx - b.readerIdx
}
func (b *buffer) WritableBytes() uint32 {
return uint32(cap(b.data)) - b.writerIdx
}
func (b *buffer) Capacity() uint32 {
return uint32(cap(b.data))
}
func (b *buffer) IsWritable() bool {
return b.WritableBytes() > 0
}
func (b *buffer) Read(size uint32) []byte {
res := b.data[b.readerIdx : b.readerIdx+size]
b.readerIdx += size
return res
}
func (b *buffer) Get(readerIdx uint32, size uint32) []byte {
return b.data[readerIdx : readerIdx+size]
}
func (b *buffer) ReadableSlice() []byte {
return b.data[b.readerIdx:b.writerIdx]
}
func (b *buffer) WritableSlice() []byte {
return b.data[b.writerIdx:]
}
func (b *buffer) WrittenBytes(size uint32) {
b.writerIdx += size
}
func (b *buffer) WriterIndex() uint32 {
return b.writerIdx
}
func (b *buffer) ReaderIndex() uint32 {
return b.readerIdx
}
func (b *buffer) MoveToFront() {
size := b.ReadableBytes()
copy(b.data, b.Read(size))
b.readerIdx = 0
b.writerIdx = size
}
func (b *buffer) Resize(newSize uint32) {
newData := make([]byte, newSize)
size := b.ReadableBytes()
copy(newData, b.Read(size))
b.data = newData
b.readerIdx = 0
b.writerIdx = size
}
func (b *buffer) ResizeIfNeeded(spaceNeeded uint32) {
if b.WritableBytes() < spaceNeeded {
capacityNeeded := uint32(cap(b.data)) + spaceNeeded
minCapacityIncrease := uint32(cap(b.data) * 3 / 2)
if capacityNeeded < minCapacityIncrease {
capacityNeeded = minCapacityIncrease
}
b.Resize(capacityNeeded)
}
}
func (b *buffer) ReadUint32() uint32 {
return binary.BigEndian.Uint32(b.Read(4))
}
func (b *buffer) ReadUint16() uint16 {
return binary.BigEndian.Uint16(b.Read(2))
}
func (b *buffer) WriteUint32(n uint32) {
b.ResizeIfNeeded(4)
binary.BigEndian.PutUint32(b.WritableSlice(), n)
b.writerIdx += 4
}
func (b *buffer) PutUint32(n uint32, idx uint32) {
binary.BigEndian.PutUint32(b.data[idx:], n)
}
func (b *buffer) WriteUint16(n uint16) {
b.ResizeIfNeeded(2)
binary.BigEndian.PutUint16(b.WritableSlice(), n)
b.writerIdx += 2
}
func (b *buffer) Write(s []byte) {
b.ResizeIfNeeded(uint32(len(s)))
copy(b.WritableSlice(), s)
b.writerIdx += uint32(len(s))
}
func (b *buffer) Put(writerIdx uint32, s []byte) {
copy(b.data[writerIdx:], s)
}
func (b *buffer) Clear() {
b.readerIdx = 0
b.writerIdx = 0
}