diff --git a/message.go b/message.go index c38abada..1057c3dd 100644 --- a/message.go +++ b/message.go @@ -384,30 +384,31 @@ type Arena interface { Allocate(minsz Size, segs map[SegmentID]*Segment) (SegmentID, []byte, error) } -type singleSegmentArena []byte +// SingleSegmentArena is an Arena implementation that stores message data +// in a continguous slice. Allocation is performed by first allocating a +// new slice and copying existing data. SingleSegment arena does not fail +// unless the caller attempts to access another segment. +type SingleSegmentArena []byte -// SingleSegment returns a new arena with an expanding single-segment -// buffer. b can be used to populate the segment for reading or to -// reserve memory of a specific size. A SingleSegment arena does not -// return errors unless you attempt to access another segment. -func SingleSegment(b []byte) Arena { - ssa := new(singleSegmentArena) - *ssa = b - return ssa +// SingleSegment constructs a SingleSegmentArena from b. b MAY be nil. +// Callers MAY use b to populate the segment for reading, or to reserve +// memory of a specific size. +func SingleSegment(b []byte) *SingleSegmentArena { + return (*SingleSegmentArena)(&b) } -func (ssa *singleSegmentArena) NumSegments() int64 { +func (ssa SingleSegmentArena) NumSegments() int64 { return 1 } -func (ssa *singleSegmentArena) Data(id SegmentID) ([]byte, error) { +func (ssa SingleSegmentArena) Data(id SegmentID) ([]byte, error) { if id != 0 { return nil, errorf("segment %d requested in single segment arena", id) } - return *ssa, nil + return ssa, nil } -func (ssa *singleSegmentArena) Allocate(sz Size, segs map[SegmentID]*Segment) (SegmentID, []byte, error) { +func (ssa *SingleSegmentArena) Allocate(sz Size, segs map[SegmentID]*Segment) (SegmentID, []byte, error) { data := []byte(*ssa) if segs[0] != nil { data = segs[0].data @@ -428,8 +429,8 @@ func (ssa *singleSegmentArena) Allocate(sz Size, segs map[SegmentID]*Segment) (S return 0, *ssa, nil } -func (ssa *singleSegmentArena) String() string { - return fmt.Sprintf("single-segment arena [len=%d cap=%d]", len(*ssa), cap(*ssa)) +func (ssa SingleSegmentArena) String() string { + return fmt.Sprintf("single-segment arena [len=%d cap=%d]", len(ssa), cap(ssa)) } type roSingleSegment []byte @@ -453,15 +454,16 @@ func (ss roSingleSegment) String() string { return fmt.Sprintf("read-only single-segment arena [len=%d]", len(ss)) } -type multiSegmentArena [][]byte +// MultiSegment is an arena that stores object data across multiple []byte +// buffers, allocating new buffers of exponentially-increasing size when +// full. This avoids the potentially-expensive slice copying of SingleSegment. +type MultiSegmentArena [][]byte // MultiSegment returns a new arena that allocates new segments when -// they are full. b can be used to populate the buffer for reading or -// to reserve memory of a specific size. -func MultiSegment(b [][]byte) Arena { - msa := new(multiSegmentArena) - *msa = b - return msa +// they are full. b MAY be nil. Callers MAY use b to populate the +// buffer for reading or to reserve memory of a specific size. +func MultiSegment(b [][]byte) *MultiSegmentArena { + return (*MultiSegmentArena)(&b) } // demuxArena slices b into a multi-segment arena. It assumes that @@ -482,18 +484,18 @@ func demuxArena(hdr streamHeader, data []byte) (Arena, error) { return MultiSegment(segs), nil } -func (msa *multiSegmentArena) NumSegments() int64 { +func (msa *MultiSegmentArena) NumSegments() int64 { return int64(len(*msa)) } -func (msa *multiSegmentArena) Data(id SegmentID) ([]byte, error) { +func (msa *MultiSegmentArena) Data(id SegmentID) ([]byte, error) { if int64(id) >= int64(len(*msa)) { return nil, errorf("segment %d requested (arena only has %d segments)", id, len(*msa)) } return (*msa)[id], nil } -func (msa *multiSegmentArena) Allocate(sz Size, segs map[SegmentID]*Segment) (SegmentID, []byte, error) { +func (msa *MultiSegmentArena) Allocate(sz Size, segs map[SegmentID]*Segment) (SegmentID, []byte, error) { var total int64 for i, data := range *msa { id := SegmentID(i) @@ -519,7 +521,7 @@ func (msa *multiSegmentArena) Allocate(sz Size, segs map[SegmentID]*Segment) (Se return id, buf, nil } -func (msa *multiSegmentArena) String() string { +func (msa *MultiSegmentArena) String() string { return fmt.Sprintf("multi-segment arena [%d segments]", len(*msa)) }