Skip to content

Instantly share code, notes, and snippets.

@ravlio
Last active August 15, 2019 14:37
Show Gist options
  • Save ravlio/296032849c6881ec757c9d3670128a68 to your computer and use it in GitHub Desktop.
Save ravlio/296032849c6881ec757c9d3670128a68 to your computer and use it in GitHub Desktop.
package rr_item_test
/*
Example of round robin with elements of arbitrary types based of interface method `Value() interface{}` and also with Stringer.
*/
import (
"github.com/stretchr/testify/require"
"strconv"
"sync"
"testing"
)
type Item interface {
Value() interface{}
String() string
}
type Int int
func (i Int) Value() interface{} {
return i
}
func (i Int) String() string {
return strconv.Itoa(int(i))
}
type String string
func (i String) Value() interface{} {
return i
}
func (i String) String() string {
return string(i)
}
type Roundrobin struct {
cur int // current elem position
obj []Item // elements slice
mx sync.RWMutex // sync mutex
}
// constructor
func New(i ...Item) *Roundrobin {
ret := &Roundrobin{}
ret.Add(i...)
return ret
}
func (r *Roundrobin) Add(i ...Item) {
r.mx.Lock()
// defer could affect performance, so we could move unlock at the end of function in production
defer r.mx.Unlock()
r.obj = append(r.obj, i...)
}
func (r *Roundrobin) Next() Item {
r.mx.RLock()
defer r.mx.RUnlock()
ret := r.obj[r.cur]
r.cur = (r.cur + 1) % len(r.obj) // Calculates next element id
return ret
}
func TestRR(t *testing.T) {
rr := New(Int(1), Int(2), String("3"))
require.Equal(t, Int(1), rr.Next())
require.Equal(t, Int(2), rr.Next())
require.Equal(t, String("3"), rr.Next())
require.Equal(t, Int(1), rr.Next())
rr.Add(Int(4), Int(5), String("6"))
require.Equal(t, "2", rr.Next().String())
require.Equal(t, "3", rr.Next().String())
require.Equal(t, "4", rr.Next().String())
require.Equal(t, "5", rr.Next().String())
require.Equal(t, "6", rr.Next().String())
require.Equal(t, "1", rr.Next().String())
}
package rr_test
/*
Пример раунд робина с элементами конкретного типа int
*/
import (
"github.com/stretchr/testify/require"
"math/rand"
"sync"
"testing"
)
type Roundrobin struct {
cur int // current elem position
obj []int // elements slice
mx sync.RWMutex // sync mutex
}
// constructor
func New(i ...int) *Roundrobin {
ret := &Roundrobin{}
ret.Add(i...)
return ret
}
func (r *Roundrobin) Add(i ...int) {
r.mx.Lock()
// defer could affect performance, so we could move unlock at the end of function in production
defer r.mx.Unlock()
r.obj = append(r.obj, i...)
}
func (r *Roundrobin) Next() int {
r.mx.RLock()
defer r.mx.RUnlock()
ret := r.obj[r.cur]
r.cur = (r.cur + 1) % len(r.obj) // Calculates next element id
return ret
}
func TestRR(t *testing.T) {
rr := New(1, 2, 3)
require.Equal(t, 1, rr.Next())
require.Equal(t, 2, rr.Next())
require.Equal(t, 3, rr.Next())
require.Equal(t, 1, rr.Next())
rr.Add(4, 5, 6)
require.Equal(t, 2, rr.Next())
require.Equal(t, 3, rr.Next())
require.Equal(t, 4, rr.Next())
require.Equal(t, 5, rr.Next())
require.Equal(t, 6, rr.Next())
require.Equal(t, 1, rr.Next())
}
func BenchmarkRR(b *testing.B) {
rr := New(1, 2, 3)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// Randomly adding elements
if rand.Intn(10) == 1 {
rr.Add(rand.Intn(1000))
}
rr.Next()
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment