Skip to content

Commit

Permalink
Separated Collection and List
Browse files Browse the repository at this point in the history
  • Loading branch information
protoman92 committed Mar 6, 2018
1 parent c18cf4b commit abcd168
Show file tree
Hide file tree
Showing 20 changed files with 363 additions and 291 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ before_install:
- go get github.com/mattn/goveralls

script:
- $GOPATH/bin/goveralls -race -v -service=travis-ci
- $GOPATH/bin/goveralls -service=travis-ci
51 changes: 51 additions & 0 deletions gocollection/basicList_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package gocollection

import (
"fmt"
"testing"
)

func testListBasicOps(t *testing.T, list List) {
/// Setup & When & Then
getValue1, getFound1 := list.Get(0)

if getValue1 != nil || getFound1 {
t.Errorf("Should not have any element")
}

newElements := []Element{1, 2, 3, 4}
list.AddAll(newElements...)

for ix := range newElements {
e := newElements[ix]
value, found := list.Get(ix)

if value != e || !found {
t.Errorf("Should have found element")
}
}

fmt.Printf("Final list: %v\n", list)
}

func testListAllOps(t *testing.T, listFn func() List) {
testCollectionBasicOps(t, listFn())
testListBasicOps(t, listFn())
}

func TestSliceListAllOps(t *testing.T) {
t.Parallel()

testListAllOps(t, func() List {
return NewSliceList()
})
}

func TestLockConcurrentListAllOps(t *testing.T) {
t.Parallel()

testListAllOps(t, func() List {
sl := NewSliceList()
return NewLockConcurrentList(sl)
})
}
56 changes: 56 additions & 0 deletions gocollection/basic_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package gocollection

import (
"strconv"
"testing"
)

func testCollectionBasicOps(t *testing.T, c Collection) {
/// Setup & When & Then
add1 := c.Add(1)
add2 := c.Add(2)
add3 := c.Add(3)
add4 := c.Add(4)

if add1 != 1 || add2 != 1 || add3 != 1 || add4 != 1 {
t.Errorf("Added wrong element count")
}

if c.Length() != 4 {
t.Errorf("Should have 4 elements")
}

deletedFound1 := c.Remove(2)

if c.Length() != 3 || !deletedFound1 {
t.Errorf("Should have 3 elements")
}

slice := make([]Element, 1000)

for ix := range slice {
slice[ix] = strconv.Itoa(ix)
}

addAll1 := c.AddAll(slice...)

if addAll1 != 1000 {
t.Errorf("Added wrong element count")
}

if c.Length() != 1003 {
t.Errorf("Should have 1003 elements")
}

deletedFound2 := c.Remove("Not existent")

if deletedFound2 {
t.Errorf("Should not have found element")
}

c.Clear()

if c.Length() != 0 {
t.Errorf("Should not have any element")
}
}
15 changes: 15 additions & 0 deletions gocollection/collection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package gocollection

// Element represents a Collection element.
type Element interface{}

// Collection represents a collection of elements which may be ordered (list) or
// unordered (set).
type Collection interface {
Add(element Element) int
AddAll(elements ...Element) int
Contains(element Element) bool
Clear()
Length() int
Remove(element Element) bool
}
58 changes: 58 additions & 0 deletions gocollection/concurrentCollection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package gocollection

// ConcurrentCollection represents a thread-safe Collection.
type ConcurrentCollection interface {
Collection
AddAsync(element Element, callback func(int))
AddAllAsync(callback func(int), elements ...Element)
ClearAsync(callback func())
ContainsAsync(element Element, callback func(bool))
LengthAsync(callback func(int))
RemoveAsync(element Element, callback func(bool))
}

type concurrentCollection struct {
Collection
}

func (cc *concurrentCollection) AddAsync(element Element, callback func(int)) {
go func() {
added := cc.Add(element)
callback(added)
}()
}

func (cc *concurrentCollection) AddAllAsync(callback func(int), elements ...Element) {
go func() {
added := cc.AddAll(elements...)
callback(added)
}()
}

func (cc *concurrentCollection) ClearAsync(callback func()) {
go func() {
cc.Clear()
callback()
}()
}

func (cc *concurrentCollection) ContainsAsync(element Element, callback func(bool)) {
go func() {
contains := cc.Contains(element)
callback(contains)
}()
}

func (cc *concurrentCollection) LengthAsync(callback func(int)) {
go func() {
length := cc.Length()
callback(length)
}()
}

func (cc *concurrentCollection) RemoveAsync(element Element, callback func(bool)) {
go func() {
found := cc.Remove(element)
callback(found)
}()
}
33 changes: 33 additions & 0 deletions gocollection/concurrentList.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package gocollection

import (
"fmt"
)

// ConcurrentList represents a thread-safe List.
type ConcurrentList interface {
ConcurrentCollection
listExtra
GetAsync(index int, callback func(Element, bool))
}

type concurrentList struct {
ConcurrentCollection
listExtra
}

func (cl *concurrentList) String() string {
return fmt.Sprint(cl.listExtra)
}

func (cl *concurrentList) GetAsync(index int, callback func(Element, bool)) {
go func() {
e, found := cl.listExtra.Get(index)
callback(e, found)
}()
}

func newConcurrentList(list List) ConcurrentList {
collection := &concurrentCollection{Collection: list}
return &concurrentList{ConcurrentCollection: collection, listExtra: list}
}
35 changes: 35 additions & 0 deletions gocollection/concurrentList_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package gocollection

import (
"testing"
)

func testListConcurrentOps(tb testing.TB, cl ConcurrentCollection) {
params := &ConcurrentCollectionOpsParams{
concurrentCollection: cl,
log: false,
keyCount: 500,
}

setupConcurrentCollectionOps(params)
}

func benchmarkListConcurrentOps(b *testing.B, clFn func() ConcurrentCollection) {
for i := 0; i < b.N; i++ {
testListConcurrentOps(b, clFn())
}
}

func BenchmarkLockListConcurrentOps(b *testing.B) {
benchmarkListConcurrentOps(b, func() ConcurrentCollection {
sl := NewSliceList()
return NewLockConcurrentList(sl)
})
}

func TestLockListConcurrentOps(t *testing.T) {
t.Parallel()
sl := NewSliceList()
cl := NewLockConcurrentList(sl)
testListConcurrentOps(t, cl)
}
59 changes: 7 additions & 52 deletions golist/concurrent_test.go → gocollection/concurrent_test.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
package golist
package gocollection

import (
"fmt"
"strconv"
"sync"
"testing"
)

type ConcurrentListOpsParams struct {
concurrentList ConcurrentList
log bool
keyCount int
type ConcurrentCollectionOpsParams struct {
concurrentCollection ConcurrentCollection
log bool
keyCount int
}

func setupConcurrentListOps(params *ConcurrentListOpsParams) {
func setupConcurrentCollectionOps(params *ConcurrentCollectionOpsParams) {
/// Setup
cl := params.concurrentList
cl := params.concurrentCollection
keys := make([]string, params.keyCount)

for ix := range keys {
Expand Down Expand Up @@ -76,20 +75,6 @@ func setupConcurrentListOps(params *ConcurrentListOpsParams) {
}

// Get
for ix := range keys {
accessWaitGroup().Add(1)

go func(ix int) {
cl.GetAsync(ix, func(e Element, found bool) {
if params.log {
fmt.Printf("Got %v for index %d, found: %t\n", e, ix, found)
}

accessWaitGroup().Done()
})
}(ix)
}

for _, key := range keys {
accessWaitGroup().Add(1)

Expand Down Expand Up @@ -120,33 +105,3 @@ func setupConcurrentListOps(params *ConcurrentListOpsParams) {

accessWaitGroup().Wait()
}

func testConcurrentListConcurrentOps(tb testing.TB, cl ConcurrentList) {
params := &ConcurrentListOpsParams{
concurrentList: cl,
log: false,
keyCount: 500,
}

setupConcurrentListOps(params)
}

func benchmarkConcurrentListConcurrentOps(b *testing.B, clFn func() ConcurrentList) {
for i := 0; i < b.N; i++ {
testConcurrentListConcurrentOps(b, clFn())
}
}

func BenchmarkLockConcurrentListConcurrentOps(b *testing.B) {
benchmarkConcurrentListConcurrentOps(b, func() ConcurrentList {
sl := NewSliceList()
return NewLockConcurrentList(sl)
})
}

func TestLockConcurrentListConcurrentOps(t *testing.T) {
t.Parallel()
sl := NewSliceList()
cl := NewLockConcurrentList(sl)
testConcurrentListConcurrentOps(t, cl)
}
12 changes: 12 additions & 0 deletions gocollection/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package gocollection

// This represents the minimal interface with additional List methods.
type listExtra interface {
Get(index int) (Element, bool)
}

// List represents an indexed Collection of elements.
type List interface {
Collection
listExtra
}
Loading

0 comments on commit abcd168

Please sign in to comment.