Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"golang.go"
]
}
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"cSpell.words": [
"Doakes",
"Donato",
"Ramstorag",
"Ricupero"
]
}
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# r9e
ramstorage (r9e) is a Golang Memory storage library

RamStorage (r9e) is a Golang Memory storage library
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/slashdevops/r9e

go 1.18
7 changes: 7 additions & 0 deletions godoc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Package r9e provides a collection of memory store containers.
//
// this package include:
//
// MapKeyValue: a simple, fast, and efficient key-value store library.
//
package r9e
321 changes: 321 additions & 0 deletions mapkeyvalue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,321 @@
package r9e

import (
"sort"
"sync"
)

type mapKeyValueOptions struct {
size int
}

// MapKeyValueOptions are the options for MapKeyValue.
type MapKeyValueOptions func(*mapKeyValueOptions)

// WithSize sets the size of the MapKeyValue.
func WithSize(size int) MapKeyValueOptions {
return func(kv *mapKeyValueOptions) {
kv.size = size
}
}

// MapKeyValue is a generic key-value store container that is thread-safe.
// This use a golang native map data structure as underlying data structure and a mutex to
// protect the data.
type MapKeyValue[K comparable, T any] struct {
mu sync.RWMutex
data map[K]T
}

// NewMapKeyValue returns a new MapKeyValue container.
func NewMapKeyValue[K comparable, T any](options ...MapKeyValueOptions) *MapKeyValue[K, T] {
// parse options
kvo := mapKeyValueOptions{}
for _, opt := range options {
opt(&kvo)
}

return &MapKeyValue[K, T]{
data: make(map[K]T, kvo.size),
}
}

// Get returns the value associated with the key.
func (r *MapKeyValue[K, T]) GetCheck(key K) (T, bool) {
r.mu.RLock()
defer r.mu.RUnlock()

value, ok := r.data[key]
return value, ok
}

// Get returns the value associated with the key.
func (r *MapKeyValue[K, T]) Get(key K) T {
r.mu.RLock()
defer r.mu.RUnlock()

return r.data[key]
}

// Set sets the value associated with the key.
func (r *MapKeyValue[K, T]) Set(key K, value T) {
r.mu.Lock()
defer r.mu.Unlock()

r.data[key] = value
}

// Delete deletes the value associated with the key.
func (r *MapKeyValue[K, T]) Delete(key K) {
r.mu.Lock()
defer r.mu.Unlock()

delete(r.data, key)
}

// Clear deletes all key-value pairs.
func (r *MapKeyValue[K, T]) Clear() {
r.mu.Lock()
defer r.mu.Unlock()

r.data = make(map[K]T)
}

// Len returns the number of key-value pairs stored in the container.
func (r *MapKeyValue[K, T]) Len() int {
r.mu.RLock()
defer r.mu.RUnlock()

return len(r.data)
}

// Keys returns all keys stored in the container.
func (r *MapKeyValue[K, T]) Keys() []K {
r.mu.RLock()
defer r.mu.RUnlock()

keys := make([]K, 0, len(r.data))
for key := range r.data {
keys = append(keys, key)
}
return keys
}

// Values returns all values stored in the container.
func (r *MapKeyValue[K, T]) Values() []T {
r.mu.RLock()
defer r.mu.RUnlock()

values := make([]T, 0, len(r.data))
for _, value := range r.data {
values = append(values, value)
}
return values
}

// Each calls the given function for each key-value pair in the container.
func (r *MapKeyValue[K, T]) Each(fn func(key K, value T)) {
r.mu.RLock()
defer r.mu.RUnlock()

for key, value := range r.data {
fn(key, value)
}
}

// EachKey calls the given function for each key in the container.
func (r *MapKeyValue[K, T]) EachKey(fn func(key K)) {
r.mu.RLock()
defer r.mu.RUnlock()

for key := range r.data {
fn(key)
}
}

// EachValue calls the given function for each value in the container.
func (r *MapKeyValue[K, T]) EachValue(fn func(value T)) {
r.mu.RLock()
defer r.mu.RUnlock()

for _, value := range r.data {
fn(value)
}
}

// Clone returns a new MapKeyValue with a copy of the underlying data.
func (r *MapKeyValue[K, T]) Clone() *MapKeyValue[K, T] {
r.mu.RLock()
defer r.mu.RUnlock()

clone := NewMapKeyValue[K, T](WithSize(r.Len()))
for key, value := range r.data {
clone.Set(key, value)
}
return clone
}

// CloneAndClear returns a new MapKeyValue with a copy of the underlying data and clears the container.
func (r *MapKeyValue[K, T]) CloneAndClear() *MapKeyValue[K, T] {
r.mu.RLock()
defer r.mu.RUnlock()

clone := NewMapKeyValue[K, T](WithSize(r.Len()))
for key, value := range r.data {
clone.Set(key, value)
}
r.Clear()
return clone
}

// Map returns a new MapKeyValue after applying the given function fn to each key-value pair.
func (r *MapKeyValue[K, T]) Map(fn func(key K, value T) (newKey K, newValue T)) *MapKeyValue[K, T] {
r.mu.Lock()
defer r.mu.Unlock()

m := NewMapKeyValue[K, T](WithSize(r.Len()))
for key, value := range r.data {
newKey, newValue := fn(key, value)
m.Set(newKey, newValue)
}
return m
}

// MapKey returns a new MapKeyValue after applying the given function fn to each key.
func (r *MapKeyValue[K, T]) MapKey(fn func(key K) K) *MapKeyValue[K, T] {
r.mu.Lock()
defer r.mu.Unlock()

m := NewMapKeyValue[K, T](WithSize(r.Len()))
for key := range r.data {
newKey := fn(key)
m.Set(newKey, r.data[key])
}
return m
}

// MapValue returns a new MapKeyValue after applying the given function fn to each value.
func (r *MapKeyValue[K, T]) MapValue(fn func(value T) T) *MapKeyValue[K, T] {
r.mu.Lock()
defer r.mu.Unlock()

m := NewMapKeyValue[K, T](WithSize(r.Len()))
for key, value := range r.data {
newValue := fn(value)
m.Set(key, newValue)
}
return m
}

// Filter returns a new MapKeyValue after applying the given function fn to each key-value pair.
func (r *MapKeyValue[K, T]) Filter(fn func(key K, value T) bool) *MapKeyValue[K, T] {
r.mu.Lock()
defer r.mu.Unlock()

m := NewMapKeyValue[K, T](WithSize(r.Len()))
for key, value := range r.data {
if fn(key, value) {
m.Set(key, value)
}
}
return m
}

// FilterKey returns a new MapKeyValue after applying the given function fn to each key.
func (r *MapKeyValue[K, T]) FilterKey(fn func(key K) bool) *MapKeyValue[K, T] {
r.mu.Lock()
defer r.mu.Unlock()

m := NewMapKeyValue[K, T](WithSize(r.Len()))
for key := range r.data {
if fn(key) {
m.Set(key, r.data[key])
}
}
return m
}

// FilterValue returns a new MapKeyValue after applying the given function fn to each value.
func (r *MapKeyValue[K, T]) FilterValue(fn func(value T) bool) *MapKeyValue[K, T] {
r.mu.Lock()
defer r.mu.Unlock()

m := NewMapKeyValue[K, T](WithSize(r.Len()))
for key, value := range r.data {
if fn(value) {
m.Set(key, value)
}
}
return m
}

// Partition returns two new MapKeyValue. One with all the elements that satisfy the predicate and
// another with the rest. The predicate is applied to each element.
func (r *MapKeyValue[K, T]) Partition(fn func(key K, value T) bool) (match, others *MapKeyValue[K, T]) {
r.mu.Lock()
defer r.mu.Unlock()

match = NewMapKeyValue[K, T](WithSize(r.Len()))
others = NewMapKeyValue[K, T](WithSize(r.Len()))
for key, value := range r.data {
if fn(key, value) {
match.Set(key, value)
} else {
others.Set(key, value)
}
}
return
}

// PartitionKey returns two new MapKeyValue. One with all the elements that satisfy the predicate and
// another with the rest. The predicate is applied to each key.
func (r *MapKeyValue[K, T]) PartitionKey(fn func(key K) bool) (match, others *MapKeyValue[K, T]) {
r.mu.Lock()
defer r.mu.Unlock()

match = NewMapKeyValue[K, T](WithSize(r.Len()))
others = NewMapKeyValue[K, T](WithSize(r.Len()))
for key := range r.data {
if fn(key) {
match.Set(key, r.data[key])
} else {
others.Set(key, r.data[key])
}
}
return
}

// PartitionValue returns two new MapKeyValue. One with all the elements that satisfy the predicate and
// another with the rest. The predicate is applied to each value.
func (r *MapKeyValue[K, T]) PartitionValue(fn func(value T) bool) (match, others *MapKeyValue[K, T]) {
r.mu.Lock()
defer r.mu.Unlock()

match = NewMapKeyValue[K, T](WithSize(r.Len()))
others = NewMapKeyValue[K, T](WithSize(r.Len()))
for key, value := range r.data {
if fn(value) {
match.Set(key, value)
} else {
others.Set(key, value)
}
}
return
}

func (r *MapKeyValue[K, T]) SortKeys(less func(key1, key2 K) bool) *MapKeyValue[K, T] {
r.mu.Lock()
defer r.mu.Unlock()

keys := r.Keys()

sort.Slice(keys, func(i, j int) bool {
return less(keys[i], keys[j])
})

m := NewMapKeyValue[K, T](WithSize(r.Len()))
for _, key := range keys {
m.Set(key, r.data[key])
}
return m
}
Loading