blob: d48a463340ae72b50966cb8a3c99234dd1407576 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package iobuf
// Slice refers to an iobuf and the byte slice for the actual data.
type Slice struct {
iobuf *buf
free uint // Free area before base, if any.
base uint // Index into the underlying iobuf.
Contents []byte // iobuf.Contents[base:bound]
}
// Size returns the number of bytes in the Slice.
func (slice *Slice) Size() int {
return len(slice.Contents)
}
// FreeEntirePrefix sets the free index to zero. Be careful when using this,
// you should ensure that no Slices are using the free region.
func (slice *Slice) FreeEntirePrefix() {
slice.free = 0
}
// Release releases the slice, decrementing the reference count on the iobuf
// and destroying the slice.
func (slice *Slice) Release() {
if slice.iobuf != nil {
slice.iobuf.release()
slice.iobuf = nil
}
slice.Contents = nil
}
// ReleasePrevious releases the <prev> slice, extending the free prefix of the
// target slice if possible.
func (slice *Slice) ReleasePrevious(prev *Slice) {
if prev.iobuf == slice.iobuf && prev.base+uint(len(prev.Contents)) == slice.free {
slice.free = prev.free
}
prev.Release()
}
// TruncateFront removes <bytes> from the front of the Slice.
func (slice *Slice) TruncateFront(bytes uint) {
if bytes > uint(len(slice.Contents)) {
bytes = uint(len(slice.Contents))
}
slice.base += bytes
slice.Contents = slice.Contents[bytes:]
}
// ExpandFront tries to expand the Slice by <bytes> before the front of the Slice.
// Returns true if the Slice was expanded.
func (slice *Slice) ExpandFront(bytes uint) bool {
if slice.free+bytes > slice.base || slice.iobuf == nil {
return false
}
bound := slice.base + uint(len(slice.Contents))
slice.base -= bytes
slice.Contents = slice.iobuf.Contents[slice.base:bound]
return true
}
// Coalesce a sequence of slices. If two slices are adjacent, they are
// combined. Takes ownership of the slices, caller takes ownership of the
// result.
func Coalesce(slices []*Slice, maxSize uint) []*Slice {
if len(slices) <= 1 {
return slices
}
var result []*Slice
c := slices[0]
for i := 1; i != len(slices); i++ {
s := slices[i]
if uint(len(c.Contents)+len(s.Contents)) <= maxSize &&
c.iobuf != nil && s.iobuf == c.iobuf &&
c.base+uint(len(c.Contents)) == s.base {
// The two slices are adjacent. Merge them.
c.Contents = c.iobuf.Contents[c.base : s.base+uint(len(s.Contents))]
s.Release()
} else {
result = append(result, c)
c = s
}
}
return append(result, c)
}
// NewSlice creates a Slice from a byte array. The value is not copied into an
// iobuf, it continues to refer to the buffer that was passed in.
func NewSlice(buf []byte) *Slice {
return &Slice{Contents: buf}
}