New func to specify minimum capacity

A larger minimum capacity can be specified to avoid buffer resizing in cases
where the size frequently grows and shrinks across a wide range.

Add module support
This commit is contained in:
Andrew Gillis 2019-05-15 00:17:53 -04:00
parent c892bbebe0
commit 2ff0cd8822
4 changed files with 66 additions and 7 deletions

View file

@ -1,10 +1,10 @@
language: go
go:
- "1.8"
- "1.9"
- "1.10"
- "1.11"
- "1.12"
- "tip"
before_script:

View file

@ -6,10 +6,22 @@ const minCapacity = 16
// Deque represents a single instance of the deque data structure.
type Deque struct {
buf []interface{}
head int
tail int
count int
buf []interface{}
head int
tail int
count int
minCap int
}
// New creates a new Deque that has a minimum capacity of 2^minCapacityExp. If
// the value of the minimum capacity is less than or equal to the minimum
// allowed, then New returns the same as new(Deque).
func New(minCapacityExp uint) *Deque {
q := new(Deque)
if 1<<minCapacityExp > minCapacity {
q.minCap = 1 << minCapacityExp
}
return q
}
// Len returns the number of elements currently stored in the queue.
@ -191,7 +203,10 @@ func (q *Deque) next(i int) int {
// growIfFull resizes up if the buffer is full.
func (q *Deque) growIfFull() {
if len(q.buf) == 0 {
q.buf = make([]interface{}, minCapacity)
if q.minCap == 0 {
q.minCap = minCapacity
}
q.buf = make([]interface{}, q.minCap)
return
}
if q.count == len(q.buf) {
@ -201,7 +216,7 @@ func (q *Deque) growIfFull() {
// shrinkIfExcess resize down if the buffer 1/4 full.
func (q *Deque) shrinkIfExcess() {
if len(q.buf) > minCapacity && (q.count<<2) == len(q.buf) {
if len(q.buf) > q.minCap && (q.count<<2) == len(q.buf) {
q.resize()
}
}

View file

@ -480,6 +480,25 @@ func TestRemoveOutOfRangePanics(t *testing.T) {
})
}
func TestNew(t *testing.T) {
exp := uint(8)
q := New(8)
q.PushBack("A")
if q.minCap != 1<<exp {
t.Fatal("wrong minimum capacity")
}
if len(q.buf) != 1<<exp {
t.Fatal("wrong buffer size")
}
q.PopBack()
if q.minCap != 1<<exp {
t.Fatal("wrong minimum capacity")
}
if len(q.buf) != 1<<exp {
t.Fatal("wrong buffer size")
}
}
func assertPanics(t *testing.T, name string, f func()) {
defer func() {
if r := recover(); r == nil {
@ -558,6 +577,30 @@ func BenchmarkRemove(b *testing.B) {
}
}
func BenchmarkYoyo(b *testing.B) {
var q Deque
for i := 0; i < b.N; i++ {
for j := 0; j < 65536; j++ {
q.PushBack(j)
}
for j := 0; j < 65536; j++ {
q.PopFront()
}
}
}
func BenchmarkYoyoFixed(b *testing.B) {
q := New(16)
for i := 0; i < b.N; i++ {
for j := 0; j < 65536; j++ {
q.PushBack(j)
}
for j := 0; j < 65536; j++ {
q.PopFront()
}
}
}
// insert is used to insert an element into the middle of the queue, before the
// element at the specified index. insert(0,e) is the same as PushFront(e) and
// insert(Len(),e) is the same as PushBack(e). Complexity is constant plus

1
go.mod Normal file
View file

@ -0,0 +1 @@
module github.com/gammazero/deque