diff --git a/README.md b/README.md index 6a58c8e..f229634 100644 --- a/README.md +++ b/README.md @@ -19,5 +19,5 @@ biMap.Size() // == 0 biMap2 := bimap.NewBiMap() biMap2.Insert("key", 1) // Notice different types val, ok := biMap2.Get("key") // Returns 1 -val, ok = biMap2.InverseGet(1) //Return "key" +val, ok = biMap2.InverseGet(1) // Returns "key" ``` diff --git a/bimap.go b/bimap.go index 42e247e..6987c58 100644 --- a/bimap.go +++ b/bimap.go @@ -4,16 +4,23 @@ import "sync" type biMap struct { s sync.RWMutex + immutable bool forward map[interface{}]interface{} inverse map[interface{}]interface{} } func NewBiMap() *biMap { - return &biMap{forward: make(map[interface{}]interface{}), inverse: make(map[interface{}]interface{})} + return &biMap{forward: make(map[interface{}]interface{}), inverse: make(map[interface{}]interface{}), immutable:false} } func (b *biMap) Insert(k interface{}, v interface{}) { + b.s.RLock() + if b.immutable { + panic("Cannot modify immutable map") + } + b.s.RUnlock() + b.s.Lock() defer b.s.Unlock() b.forward[k] = v @@ -56,6 +63,12 @@ func (b *biMap) InverseGet(v interface{}) (interface{}, bool) { } func (b *biMap) Delete(k interface{}) { + b.s.RLock() + if b.immutable { + panic("Cannot modify immutable map") + } + b.s.RUnlock() + if !b.Exists(k) { return } @@ -67,6 +80,12 @@ func (b *biMap) Delete(k interface{}) { } func (b *biMap) InverseDelete(v interface{}) { + b.s.RLock() + if b.immutable { + panic("Cannot modify immutable map") + } + b.s.RUnlock() + if !b.InverseExists(v) { return } @@ -83,4 +102,10 @@ func (b*biMap) Size() int{ b.s.RLock() defer b.s.RUnlock() return len(b.forward) +} + +func (b *biMap) SetImmutable() { + b.s.Lock() + defer b.s.Unlock() + b.immutable = true } \ No newline at end of file diff --git a/bimap_test.go b/bimap_test.go index c4dd8a3..c90a27d 100644 --- a/bimap_test.go +++ b/bimap_test.go @@ -154,6 +154,44 @@ func TestBiMap_WithVaryingType(t *testing.T) { } +func TestBiMap_SetImmutable(t *testing.T) { + actual := NewBiMap() + dummyKey := "Dummy key" + dummyVal := 3 + + actual.Insert(dummyKey, dummyVal) + + actual.SetImmutable() + + assert.Panics(t, func() { + actual.Delete(dummyKey) + }, "It should panic on a mutation operation") + + val, _ := actual.Get(dummyKey) + + assert.Equal(t, dummyVal, val, "It should still have the value") + + assert.Panics(t, func() { + actual.InverseDelete(dummyVal) + }, "It should panic on a mutation operation") + + key, _ := actual.InverseGet(dummyVal) + + assert.Equal(t, dummyKey, key, "It should still have the key") + + size := actual.Size() + + assert.Equal(t, 1, size, "Size should be one") + + assert.Panics(t, func() { + actual.Insert("New", 1) + }, "It should panic on a mutation operation") + + size = actual.Size() + + assert.Equal(t, 1, size, "Size should be one") + +}