Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added NewGeneric creation function and related test units #157

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion concurrent_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ func New[V any]() ConcurrentMap[string, V] {
return create[string, V](fnv32)
}

// Creates a new concurrent map with generic key type.
func NewGeneric[K comparable, V any]() ConcurrentMap[K, V] {
return create[K, V](genericfnv32[K])
}

// Creates a new concurrent map.
func NewStringer[K Stringer, V any]() ConcurrentMap[K, V] {
return create[K, V](strfnv32[K])
Expand Down Expand Up @@ -224,7 +229,7 @@ func (m ConcurrentMap[K, V]) Clear() {
// It returns once the size of each buffered channel is determined,
// before all the channels are populated using goroutines.
func snapshot[K comparable, V any](m ConcurrentMap[K, V]) (chans []chan Tuple[K, V]) {
//When you access map items before initializing.
// When you access map items before initializing.
if len(m.shards) == 0 {
panic(`cmap.ConcurrentMap is not initialized. Should run New() before usage.`)
}
Expand Down Expand Up @@ -338,6 +343,11 @@ func (m ConcurrentMap[K, V]) MarshalJSON() ([]byte, error) {
}
return json.Marshal(tmp)
}

func genericfnv32[K comparable](key K) uint32 {
return fnv32(fmt.Sprintf("%v", key))
}

func strfnv32[K fmt.Stringer](key K) uint32 {
return fnv32(key.String())
}
Expand Down
35 changes: 34 additions & 1 deletion concurrent_map_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,30 @@ func BenchmarkItems(b *testing.B) {
}
}

func BenchmarkGenericStruct(b *testing.B) {
m := NewGeneric[Animal, int]()

// Insert 10000 elements.
for i := 0; i < 10000; i++ {
m.Set(Animal{strconv.Itoa(i)}, i)
}
for i := 0; i < b.N; i++ {
m.Items()
}
}

func BenchmarkGenericInt(b *testing.B) {
m := NewGeneric[int, Animal]()

// Insert 10000 elements.
for i := 0; i < 10000; i++ {
m.Set(i, Animal{strconv.Itoa(i)})
}
for i := 0; i < b.N; i++ {
m.Items()
}
}

func BenchmarkItemsInteger(b *testing.B) {
m := NewStringer[Integer, Animal]()

Expand All @@ -35,6 +59,7 @@ func BenchmarkItemsInteger(b *testing.B) {
m.Items()
}
}

func directSharding(key uint32) uint32 {
return key
}
Expand Down Expand Up @@ -136,12 +161,15 @@ func BenchmarkMultiInsertDifferentSyncMap(b *testing.B) {
func BenchmarkMultiInsertDifferent_1_Shard(b *testing.B) {
runWithShards(benchmarkMultiInsertDifferent, b, 1)
}

func BenchmarkMultiInsertDifferent_16_Shard(b *testing.B) {
runWithShards(benchmarkMultiInsertDifferent, b, 16)
}

func BenchmarkMultiInsertDifferent_32_Shard(b *testing.B) {
runWithShards(benchmarkMultiInsertDifferent, b, 32)
}

func BenchmarkMultiInsertDifferent_256_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 256)
}
Expand Down Expand Up @@ -235,12 +263,15 @@ func BenchmarkMultiGetSetDifferentSyncMap(b *testing.B) {
func BenchmarkMultiGetSetDifferent_1_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 1)
}

func BenchmarkMultiGetSetDifferent_16_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 16)
}

func BenchmarkMultiGetSetDifferent_32_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 32)
}

func BenchmarkMultiGetSetDifferent_256_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 256)
}
Expand Down Expand Up @@ -282,17 +313,19 @@ func BenchmarkMultiGetSetBlockSyncMap(b *testing.B) {
func BenchmarkMultiGetSetBlock_1_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetBlock, b, 1)
}

func BenchmarkMultiGetSetBlock_16_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetBlock, b, 16)
}

func BenchmarkMultiGetSetBlock_32_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetBlock, b, 32)
}

func BenchmarkMultiGetSetBlock_256_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetBlock, b, 256)
}


func GetSet[K comparable, V any](m ConcurrentMap[K, V], finished chan struct{}) (set func(key K, value V), get func(key K, value V)) {
return func(key K, value V) {
for i := 0; i < 10; i++ {
Expand Down
66 changes: 65 additions & 1 deletion concurrent_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,6 @@ func TestFnv32(t *testing.T) {
if fnv32(string(key)) != hasher.Sum32() {
t.Errorf("Bundled fnv32 produced %d, expected result from hash/fnv32 is %d", fnv32(string(key)), hasher.Sum32())
}

}

func TestUpsert(t *testing.T) {
Expand Down Expand Up @@ -641,3 +640,68 @@ func TestUnDrainedIterBuffered(t *testing.T) {
t.Error("We should have counted 200 elements.")
}
}

func TestMapGenericInt(t *testing.T) {
m := NewGeneric[int, string]()
if m.shards == nil {
t.Error("map is null.")
}
if m.Count() != 0 {
t.Error("new map should be empty.")
}

m.Set(1, "elephant")
m.Set(2, "monkey")
value, ok := m.Get(1)
if !ok || value != "elephant" {
t.Error("Cannot get value of key 1, which should be elephant")
}
value, ok = m.Get(2)
if !ok || value != "monkey" {
t.Error("Cannot get value of key 2, which should be monkey")
}

if m.Count() != 2 {
t.Error("map should contain exactly two elements.")
}

m.Remove(1)
m.Remove(2)
if m.Count() != 0 {
t.Error("Expecting count to be zero once item was removed.")
}
}

func TestMapGenericStruct(t *testing.T) {
type TmpStruct struct {
Name string
}
m := NewGeneric[TmpStruct, string]()
if m.shards == nil {
t.Error("map is null.")
}
if m.Count() != 0 {
t.Error("new map should be empty.")
}

m.Set(TmpStruct{"elephant"}, "elephant")
m.Set(TmpStruct{"monkey"}, "monkey")
value, ok := m.Get(TmpStruct{"elephant"})
if !ok || value != "elephant" {
t.Error("Cannot get value of key elephant, which should be elephant")
}
value, ok = m.Get(TmpStruct{"monkey"})
if !ok || value != "monkey" {
t.Error("Cannot get value of key monkey, which should be monkey")
}

if m.Count() != 2 {
t.Error("map should contain exactly two elements.")
}

m.Remove(TmpStruct{"elephant"})
m.Remove(TmpStruct{"monkey"})
if m.Count() != 0 {
t.Error("Expecting count to be zero once item was removed.")
}
}