-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
311 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
* Cadence - The resource-oriented smart contract programming language | ||
* | ||
* Copyright Dapper Labs, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* Based on https://github.com/vishalkuo/bimap, Copyright Vishal Kuo | ||
* | ||
*/ | ||
|
||
package bimap | ||
|
||
type BiMap[K comparable, V comparable] struct { | ||
forward map[K]V | ||
backward map[V]K | ||
} | ||
|
||
// NewBiMap returns a an empty, mutable, biMap | ||
func NewBiMap[K comparable, V comparable]() *BiMap[K, V] { | ||
return &BiMap[K, V]{forward: make(map[K]V), backward: make(map[V]K)} | ||
} | ||
|
||
// NewBiMapFrom returns a new BiMap from a map[K, V] | ||
func NewBiMapFromMap[K comparable, V comparable](forwardMap map[K]V) *BiMap[K, V] { | ||
biMap := NewBiMap[K, V]() | ||
for k, v := range forwardMap { | ||
biMap.Insert(k, v) | ||
} | ||
return biMap | ||
} | ||
|
||
// Insert puts a key and value into the BiMap, and creates the reverse mapping from value to key. | ||
func (b *BiMap[K, V]) Insert(k K, v V) { | ||
if _, ok := b.forward[k]; ok { | ||
delete(b.backward, b.forward[k]) | ||
} | ||
b.forward[k] = v | ||
b.backward[v] = k | ||
} | ||
|
||
// Exists checks whether or not a key exists in the BiMap | ||
func (b *BiMap[K, V]) Exists(k K) bool { | ||
_, ok := b.forward[k] | ||
return ok | ||
} | ||
|
||
// ExistsInverse checks whether or not a value exists in the BiMap | ||
func (b *BiMap[K, V]) ExistsInverse(k V) bool { | ||
_, ok := b.backward[k] | ||
return ok | ||
} | ||
|
||
// Get returns the value for a given key in the BiMap and whether or not the element was present. | ||
func (b *BiMap[K, V]) Get(k K) (V, bool) { | ||
if !b.Exists(k) { | ||
return *new(V), false | ||
} | ||
return b.forward[k], true | ||
} | ||
|
||
// GetInverse returns the key for a given value in the BiMap and whether or not the element was present. | ||
func (b *BiMap[K, V]) GetInverse(v V) (K, bool) { | ||
if !b.ExistsInverse(v) { | ||
return *new(K), false | ||
} | ||
return b.backward[v], true | ||
} | ||
|
||
// Delete removes a key-value pair from the BiMap for a given key. Returns if the key doesn't exist | ||
func (b *BiMap[K, V]) Delete(k K) { | ||
if !b.Exists(k) { | ||
return | ||
} | ||
val, _ := b.Get(k) | ||
delete(b.forward, k) | ||
delete(b.backward, val) | ||
} | ||
|
||
// DeleteInverse emoves a key-value pair from the BiMap for a given value. Returns if the value doesn't exist | ||
func (b *BiMap[K, V]) DeleteInverse(v V) { | ||
if !b.ExistsInverse(v) { | ||
return | ||
} | ||
|
||
key, _ := b.GetInverse(v) | ||
delete(b.backward, v) | ||
delete(b.forward, key) | ||
|
||
} | ||
|
||
// Size returns the number of elements in the bimap | ||
func (b *BiMap[K, V]) Size() int { | ||
return len(b.forward) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
/* | ||
* Cadence - The resource-oriented smart contract programming language | ||
* | ||
* Copyright Dapper Labs, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package bimap | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
const key = "key" | ||
const value = "value" | ||
|
||
func TestNewBiMap(t *testing.T) { | ||
actual := NewBiMap[string, string]() | ||
expected := &BiMap[string, string]{forward: make(map[string]string), backward: make(map[string]string)} | ||
assert.Equal(t, expected, actual, "They should be equal") | ||
} | ||
|
||
func TestNewBiMapFrom(t *testing.T) { | ||
actual := NewBiMapFromMap(map[string]string{ | ||
key: value, | ||
}) | ||
actual.Insert(key, value) | ||
|
||
fwdExpected := make(map[string]string) | ||
invExpected := make(map[string]string) | ||
fwdExpected[key] = value | ||
invExpected[value] = key | ||
expected := &BiMap[string, string]{forward: fwdExpected, backward: invExpected} | ||
|
||
assert.Equal(t, expected, actual, "They should be equal") | ||
} | ||
|
||
func TestBiMap_Insert(t *testing.T) { | ||
actual := NewBiMap[string, string]() | ||
actual.Insert(key, value) | ||
|
||
fwdExpected := make(map[string]string) | ||
invExpected := make(map[string]string) | ||
fwdExpected[key] = value | ||
invExpected[value] = key | ||
expected := &BiMap[string, string]{forward: fwdExpected, backward: invExpected} | ||
|
||
assert.Equal(t, expected, actual, "They should be equal") | ||
} | ||
|
||
func TestBiMap_InsertTwice(t *testing.T) { | ||
additionalValue := value + value | ||
|
||
actual := NewBiMap[string, string]() | ||
actual.Insert(key, value) | ||
actual.Insert(key, additionalValue) | ||
|
||
fwdExpected := make(map[string]string) | ||
invExpected := make(map[string]string) | ||
fwdExpected[key] = additionalValue | ||
|
||
invExpected[additionalValue] = key | ||
expected := &BiMap[string, string]{forward: fwdExpected, backward: invExpected} | ||
|
||
assert.Equal(t, expected, actual, "They should be equal") | ||
} | ||
|
||
func TestBiMap_Exists(t *testing.T) { | ||
actual := NewBiMap[string, string]() | ||
|
||
actual.Insert(key, value) | ||
assert.False(t, actual.Exists("ARBITARY_KEY"), "Key should not exist") | ||
assert.True(t, actual.Exists(key), "Inserted key should exist") | ||
} | ||
|
||
func TestBiMap_InverseExists(t *testing.T) { | ||
actual := NewBiMap[string, string]() | ||
|
||
actual.Insert(key, value) | ||
assert.False(t, actual.ExistsInverse("ARBITARY_VALUE"), "Value should not exist") | ||
assert.True(t, actual.ExistsInverse(value), "Inserted value should exist") | ||
} | ||
|
||
func TestBiMap_Get(t *testing.T) { | ||
actual := NewBiMap[string, string]() | ||
|
||
actual.Insert(key, value) | ||
|
||
actualVal, ok := actual.Get(key) | ||
|
||
assert.True(t, ok, "It should return true") | ||
assert.Equal(t, value, actualVal, "Value and returned val should be equal") | ||
|
||
actualVal, ok = actual.Get(value) | ||
|
||
assert.False(t, ok, "It should return false") | ||
assert.Empty(t, actualVal, "Actual val should be empty") | ||
} | ||
|
||
func TestBiMap_GetInverse(t *testing.T) { | ||
actual := NewBiMap[string, string]() | ||
|
||
actual.Insert(key, value) | ||
|
||
actualKey, ok := actual.GetInverse(value) | ||
|
||
assert.True(t, ok, "It should return true") | ||
assert.Equal(t, key, actualKey, "Key and returned key should be equal") | ||
|
||
actualKey, ok = actual.Get(value) | ||
|
||
assert.False(t, ok, "It should return false") | ||
assert.Empty(t, actualKey, "Actual key should be empty") | ||
} | ||
|
||
func TestBiMap_Size(t *testing.T) { | ||
actual := NewBiMap[string, string]() | ||
|
||
assert.Equal(t, 0, actual.Size(), "Length of empty bimap should be zero") | ||
|
||
actual.Insert(key, value) | ||
|
||
assert.Equal(t, 1, actual.Size(), "Length of bimap should be one") | ||
} | ||
|
||
func TestBiMap_Delete(t *testing.T) { | ||
actual := NewBiMap[string, string]() | ||
dummyKey := "DummyKey" | ||
dummyVal := "DummyVal" | ||
actual.Insert(key, value) | ||
actual.Insert(dummyKey, dummyVal) | ||
|
||
assert.Equal(t, 2, actual.Size(), "Size of bimap should be two") | ||
|
||
actual.Delete(dummyKey) | ||
|
||
fwdExpected := make(map[string]string) | ||
invExpected := make(map[string]string) | ||
fwdExpected[key] = value | ||
invExpected[value] = key | ||
|
||
expected := &BiMap[string, string]{forward: fwdExpected, backward: invExpected} | ||
|
||
assert.Equal(t, 1, actual.Size(), "Size of bimap should be two") | ||
assert.Equal(t, expected, actual, "They should be the same") | ||
|
||
actual.Delete(dummyKey) | ||
|
||
assert.Equal(t, 1, actual.Size(), "Size of bimap should be two") | ||
assert.Equal(t, expected, actual, "They should be the same") | ||
} | ||
|
||
func TestBiMap_InverseDelete(t *testing.T) { | ||
actual := NewBiMap[string, string]() | ||
dummyKey := "DummyKey" | ||
dummyVal := "DummyVal" | ||
actual.Insert(key, value) | ||
actual.Insert(dummyKey, dummyVal) | ||
|
||
assert.Equal(t, 2, actual.Size(), "Size of bimap should be two") | ||
|
||
actual.DeleteInverse(dummyVal) | ||
|
||
fwdExpected := make(map[string]string) | ||
invExpected := make(map[string]string) | ||
fwdExpected[key] = value | ||
invExpected[value] = key | ||
|
||
expected := &BiMap[string, string]{forward: fwdExpected, backward: invExpected} | ||
|
||
assert.Equal(t, 1, actual.Size(), "Size of bimap should be two") | ||
assert.Equal(t, expected, actual, "They should be the same") | ||
|
||
actual.DeleteInverse(dummyVal) | ||
|
||
assert.Equal(t, 1, actual.Size(), "Size of bimap should be two") | ||
assert.Equal(t, expected, actual, "They should be the same") | ||
} | ||
|
||
func TestBiMap_WithVaryingType(t *testing.T) { | ||
actual := NewBiMap[string, int]() | ||
dummyKey := "Dummy key" | ||
dummyVal := 3 | ||
|
||
actual.Insert(dummyKey, dummyVal) | ||
|
||
res, _ := actual.Get(dummyKey) | ||
resVal, _ := actual.GetInverse(dummyVal) | ||
assert.Equal(t, dummyVal, res, "Get by string key should return integer val") | ||
assert.Equal(t, dummyKey, resVal, "Get by integer val should return string key") | ||
|
||
} |