diff options
Diffstat (limited to 'teleirc/matterbridge/vendor/github.com/zfjagann/golang-ring/ring.go')
| -rw-r--r-- | teleirc/matterbridge/vendor/github.com/zfjagann/golang-ring/ring.go | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/teleirc/matterbridge/vendor/github.com/zfjagann/golang-ring/ring.go b/teleirc/matterbridge/vendor/github.com/zfjagann/golang-ring/ring.go new file mode 100644 index 0000000..d90db39 --- /dev/null +++ b/teleirc/matterbridge/vendor/github.com/zfjagann/golang-ring/ring.go @@ -0,0 +1,235 @@ +/* +Package ring provides a simple implementation of a ring buffer. +*/ +package ring + +import "sync" + +/* +The DefaultCapacity of an uninitialized Ring buffer. + +Changing this value only affects ring buffers created after it is changed. +*/ +var DefaultCapacity int = 10 + +/* +Type Ring implements a Circular Buffer. +The default value of the Ring struct is a valid (empty) Ring buffer with capacity DefaultCapacify. +*/ +type Ring struct { + sync.Mutex + head int // the most recent value written + tail int // the least recent value written + buff []interface{} +} + +/* +Set the maximum size of the ring buffer. +*/ +func (r *Ring) SetCapacity(size int) { + r.Lock() + defer r.Unlock() + + r.checkInit() + r.extend(size) +} + +/* +Capacity returns the current capacity of the ring buffer. +*/ +func (r *Ring) Capacity() int { + r.Lock() + defer r.Unlock() + + return r.capacity() +} + +/* +ContentSize returns the current number of elements inside the ring buffer. +*/ +func (r *Ring) ContentSize() int { + r.Lock() + defer r.Unlock() + + if r.head == -1 { + return 0 + } else { + difference := (r.head - r.tail) + if difference < 0 { + difference += r.capacity() + } + return difference + 1 + } +} + +/* +Enqueue a value into the Ring buffer. +*/ +func (r *Ring) Enqueue(i interface{}) { + r.Lock() + defer r.Unlock() + + r.checkInit() + r.set(r.head+1, i) + old := r.head + r.head = r.mod(r.head + 1) + if old != -1 && r.head == r.tail { + r.tail = r.mod(r.tail + 1) + } +} + +/* +Dequeue a value from the Ring buffer. + +Returns nil if the ring buffer is empty. +*/ +func (r *Ring) Dequeue() interface{} { + r.Lock() + defer r.Unlock() + + r.checkInit() + if r.head == -1 { + return nil + } + v := r.get(r.tail) + r.set(r.tail, nil) + if r.tail == r.head { + r.head = -1 + r.tail = 0 + } else { + r.tail = r.mod(r.tail + 1) + } + return v +} + +/* +Read the value that Dequeue would have dequeued without actually dequeuing it. + +Returns nil if the ring buffer is empty. +*/ +func (r *Ring) Peek() interface{} { + r.Lock() + defer r.Unlock() + + r.checkInit() + if r.head == -1 { + return nil + } + return r.get(r.tail) +} + +/* +Values returns a slice of all the values in the circular buffer without modifying them at all. +The returned slice can be modified independently of the circular buffer. However, the values inside the slice +are shared between the slice and circular buffer. +*/ +func (r *Ring) Values() []interface{} { + r.Lock() + defer r.Unlock() + + if r.head == -1 { + return []interface{}{} + } + arr := make([]interface{}, 0, r.capacity()) + for i := 0; i < r.capacity(); i++ { + idx := r.mod(i + r.tail) + arr = append(arr, r.get(idx)) + if idx == r.head { + break + } + } + return arr +} + +/** +*** Unexported methods beyond this point. +**/ + +func (r *Ring) capacity() int { + return len(r.buff) +} + +// sets a value at the given unmodified index and returns the modified index of the value +func (r *Ring) set(p int, v interface{}) { + r.buff[r.mod(p)] = v +} + +// gets a value based at a given unmodified index +func (r *Ring) get(p int) interface{} { + return r.buff[r.mod(p)] +} + +// returns the modified index of an unmodified index +func (r *Ring) mod(p int) int { + v := p % len(r.buff) + for v < 0 { // this bit fixes negative indices + v += len(r.buff) + } + return v +} + +func (r *Ring) checkInit() { + if r.buff != nil { + return + } + + r.buff = make([]interface{}, DefaultCapacity) + for i := range r.buff { + r.buff[i] = nil + } + r.head, r.tail = -1, 0 +} + +func (r *Ring) extend(size int) { + if size == len(r.buff) { + return + } + + if size < len(r.buff) { + // shrink the buffer + if r.head == -1 { + // nothing in the buffer, so just shrink it directly + r.buff = r.buff[0:size] + } else { + newb := make([]interface{}, 0, size) + // buffer has stuff in it, so save the most recent stuff... + // start at HEAD-SIZE-1 and walk forwards + for i := size - 1; i >= 0; i-- { + idx := r.mod(r.head - i) + newb = append(newb, r.buff[idx]) + } + // reset head and tail to proper values + r.head = len(newb) - 1 + r.tail = 0 + r.buff = newb + } + return + } + + // grow the buffer + newb := make([]interface{}, size-len(r.buff)) + for i := range newb { + newb[i] = nil + } + if r.head == -1 { + // nothing in the buffer + r.buff = append(r.buff, newb...) + } else if r.head >= r.tail { + // growing at the end is safe + r.buff = append(r.buff, newb...) + } else { + // buffer has stuff that wraps around the end + // have to rearrange the buffer so the contents are still in order + part1 := make([]interface{}, len(r.buff[:r.head+1])) + copy(part1, r.buff[:r.head+1]) + part2 := make([]interface{}, len(r.buff[r.tail:])) + copy(part2, r.buff[r.tail:]) + r.buff = append(r.buff, newb...) + newTail := r.mod(r.tail + len(newb)) + r.tail = newTail + copy(r.buff[:r.head+1], part1) + copy(r.buff[r.head+1:r.tail], newb) + copy(r.buff[r.tail:], part2) + + } +} |
