| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- package blob
- import (
- "errors"
- "fmt"
- "sync"
- "sync/atomic"
- )
- var (
- // ensure Bytes conforms to these interfaces:
- _ interface {
- Blob
- ViewBlob
- SliceBlob
- SetBlob
- GrowBlob
- TruncateBlob
- } = (*Bytes)(nil)
- )
- // Bytes is a Blob that wraps a byte slice.
- type Bytes struct {
- mu *sync.Mutex // mutex can be shared when the byte slice is shared
- bytes []byte
- length int64
- }
- // NewBytes returns a Blob that wraps the given byte slice.
- // Mutations to this Blob are reflected in the original slice.
- func NewBytes(buf []byte) *Bytes {
- return &Bytes{
- bytes: buf,
- length: int64(len(buf)),
- mu: new(sync.Mutex),
- }
- }
- // NewBytesLength returns a new Bytes with the given length of zero-byte data.
- func NewBytesLength(length int) *Bytes {
- return NewBytes(make([]byte, length))
- }
- // Bytes implements Blob.
- func (b *Bytes) Bytes() []byte {
- // always return a copy of the bytes, to avoid concurrent modification
- newB, err := b.Slice(0, int64(b.Len()))
- if err != nil {
- panic(err)
- }
- return newB.(*Bytes).bytes
- }
- // Len implements Blob.
- func (b *Bytes) Len() int {
- return int(atomic.LoadInt64(&b.length))
- }
- // View implements Blob.
- func (b *Bytes) View(start, end int64) (Blob, error) {
- if start < 0 || start > int64(b.Len()) {
- return nil, fmt.Errorf("Start index out of bounds: %d", start)
- }
- if end < 0 || end > int64(b.Len()) {
- return nil, fmt.Errorf("End index out of bounds: %d", end)
- }
- b.mu.Lock()
- defer b.mu.Unlock()
- newB := NewBytes(b.bytes[start:end])
- newB.mu = b.mu
- return newB, nil
- }
- // Slice implements Blob.
- func (b *Bytes) Slice(start, end int64) (Blob, error) {
- if start < 0 || start > int64(b.Len()) {
- return nil, fmt.Errorf("Start index out of bounds: %d", start)
- }
- if end < 0 || end > int64(b.Len()) {
- return nil, fmt.Errorf("End index out of bounds: %d", end)
- }
- buf := make([]byte, end-start)
- b.mu.Lock()
- copy(buf, b.bytes)
- b.mu.Unlock()
- return NewBytes(buf), nil
- }
- // Set implements Blob.
- func (b *Bytes) Set(src Blob, destStart int64) (n int, err error) {
- if destStart < 0 {
- return 0, errors.New("negative offset")
- }
- if destStart >= int64(b.Len()) && destStart == 0 && src.Len() > 0 {
- return 0, fmt.Errorf("Offset out of bounds: %d", destStart)
- }
- b.mu.Lock()
- n = copy(b.bytes[destStart:], src.Bytes())
- b.mu.Unlock()
- return n, nil
- }
- // Grow implements Blob.
- func (b *Bytes) Grow(offset int64) error {
- b.mu.Lock()
- b.bytes = append(b.bytes, make([]byte, offset)...)
- atomic.StoreInt64(&b.length, int64(len(b.bytes)))
- b.mu.Unlock()
- return nil
- }
- // Truncate implements Blob.
- func (b *Bytes) Truncate(size int64) error {
- if int64(b.Len()) < size {
- return nil
- }
- b.mu.Lock()
- if int64(b.Len()) >= size {
- b.bytes = b.bytes[:size]
- atomic.StoreInt64(&b.length, int64(len(b.bytes)))
- }
- b.mu.Unlock()
- return nil
- }
|