From 38467cb4e7453b59ac25cbcb3d7a1e43c9319a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Schw=C3=B6rer?= Date: Thu, 4 Sep 2025 14:25:06 +0200 Subject: [PATCH] v0.0.597 add update methods to SyncMap --- dataext/syncMap.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 3 ++- go.sum | 4 ++++ goextVersion.go | 4 ++-- 4 files changed, 60 insertions(+), 3 deletions(-) diff --git a/dataext/syncMap.go b/dataext/syncMap.go index 995a91a..e678706 100644 --- a/dataext/syncMap.go +++ b/dataext/syncMap.go @@ -2,6 +2,8 @@ package dataext import "sync" +// SyncMap is a thread-safe map implementation for generic key-value pairs. +// All functions aresafe to be called in parallel. type SyncMap[TKey comparable, TData any] struct { data map[TKey]TData lock sync.Mutex @@ -11,6 +13,7 @@ func NewSyncMap[TKey comparable, TData any]() *SyncMap[TKey, TData] { return &SyncMap[TKey, TData]{data: make(map[TKey]TData), lock: sync.Mutex{}} } +// Set sets the value for the provided key func (s *SyncMap[TKey, TData]) Set(key TKey, data TData) { s.lock.Lock() defer s.lock.Unlock() @@ -22,6 +25,7 @@ func (s *SyncMap[TKey, TData]) Set(key TKey, data TData) { s.data[key] = data } +// SetIfNotContains sets the value for the provided key if it does not already exist func (s *SyncMap[TKey, TData]) SetIfNotContains(key TKey, data TData) bool { s.lock.Lock() defer s.lock.Unlock() @@ -39,6 +43,7 @@ func (s *SyncMap[TKey, TData]) SetIfNotContains(key TKey, data TData) bool { return true } +// SetIfNotContainsFunc sets the value for the provided key using the provided function func (s *SyncMap[TKey, TData]) SetIfNotContainsFunc(key TKey, data func() TData) bool { s.lock.Lock() defer s.lock.Unlock() @@ -56,6 +61,7 @@ func (s *SyncMap[TKey, TData]) SetIfNotContainsFunc(key TKey, data func() TData) return true } +// Get retrieves the value for the provided key func (s *SyncMap[TKey, TData]) Get(key TKey) (TData, bool) { s.lock.Lock() defer s.lock.Unlock() @@ -71,6 +77,8 @@ func (s *SyncMap[TKey, TData]) Get(key TKey) (TData, bool) { } } +// GetAndSetIfNotContains returns the existing value if the key exists. +// Otherwise, it sets the provided value and returns it. func (s *SyncMap[TKey, TData]) GetAndSetIfNotContains(key TKey, data TData) TData { s.lock.Lock() defer s.lock.Unlock() @@ -87,6 +95,8 @@ func (s *SyncMap[TKey, TData]) GetAndSetIfNotContains(key TKey, data TData) TDat } } +// GetAndSetIfNotContainsFunc returns the existing value if the key exists. +// Otherwise, it calls the provided function to generate the value, sets it, and returns it. func (s *SyncMap[TKey, TData]) GetAndSetIfNotContainsFunc(key TKey, data func() TData) TData { s.lock.Lock() defer s.lock.Unlock() @@ -104,6 +114,7 @@ func (s *SyncMap[TKey, TData]) GetAndSetIfNotContainsFunc(key TKey, data func() } } +// Delete removes the entry with the provided key and returns true if the key existed before. func (s *SyncMap[TKey, TData]) Delete(key TKey) bool { s.lock.Lock() defer s.lock.Unlock() @@ -119,6 +130,7 @@ func (s *SyncMap[TKey, TData]) Delete(key TKey) bool { return ok } +// DeleteIf deletes all entries that match the provided function and returns the number of removed entries. func (s *SyncMap[TKey, TData]) DeleteIf(fn func(key TKey, data TData) bool) int { s.lock.Lock() defer s.lock.Unlock() @@ -138,6 +150,42 @@ func (s *SyncMap[TKey, TData]) DeleteIf(fn func(key TKey, data TData) bool) int return rm } +// UpdateIfExists updates the value if the key exists, otherwise it does nothing. +func (s *SyncMap[TKey, TData]) UpdateIfExists(key TKey, fn func(data TData) TData) bool { + s.lock.Lock() + defer s.lock.Unlock() + + if s.data == nil { + s.data = make(map[TKey]TData) + } + + if v, ok := s.data[key]; ok { + s.data[key] = fn(v) + return true + } else { + return false + } +} + +// UpdateOrInsert updates the value if the key exists, otherwise it inserts the provided `insertValue`. +func (s *SyncMap[TKey, TData]) UpdateOrInsert(key TKey, fn func(data TData) TData, insertValue TData) bool { + s.lock.Lock() + defer s.lock.Unlock() + + if s.data == nil { + s.data = make(map[TKey]TData) + } + + if v, ok := s.data[key]; ok { + s.data[key] = fn(v) + return true + } else { + s.data[key] = insertValue + return false + } +} + +// Clear removes all entries from the map. func (s *SyncMap[TKey, TData]) Clear() { s.lock.Lock() defer s.lock.Unlock() @@ -145,6 +193,7 @@ func (s *SyncMap[TKey, TData]) Clear() { s.data = make(map[TKey]TData) } +// Contains checks if the map contains the provided key. func (s *SyncMap[TKey, TData]) Contains(key TKey) bool { s.lock.Lock() defer s.lock.Unlock() @@ -158,6 +207,7 @@ func (s *SyncMap[TKey, TData]) Contains(key TKey) bool { return ok } +// GetAllKeys returns a copy (!) of all keys in the map. func (s *SyncMap[TKey, TData]) GetAllKeys() []TKey { s.lock.Lock() defer s.lock.Unlock() @@ -175,6 +225,7 @@ func (s *SyncMap[TKey, TData]) GetAllKeys() []TKey { return r } +// GetAllValues returns a copy (!) of all values in the map. func (s *SyncMap[TKey, TData]) GetAllValues() []TData { s.lock.Lock() defer s.lock.Unlock() @@ -192,6 +243,7 @@ func (s *SyncMap[TKey, TData]) GetAllValues() []TData { return r } +// Count returns the number of entries in the map. func (s *SyncMap[TKey, TData]) Count() int { s.lock.Lock() defer s.lock.Unlock() diff --git a/go.mod b/go.mod index c8f45c2..e99feb1 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,8 @@ require ( ) require ( - github.com/bytedance/sonic v1.14.0 // indirect + github.com/bytedance/gopkg v0.1.3 // indirect + github.com/bytedance/sonic v1.14.1 // indirect github.com/bytedance/sonic/loader v0.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cloudwego/iasm v0.2.0 // indirect diff --git a/go.sum b/go.sum index 95783c5..139775c 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= +github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU= github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic v1.12.4 h1:9Csb3c9ZJhfUWeMtpCDCq6BUoH5ogfDFLUgQ/jG+R0k= @@ -25,6 +27,8 @@ github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= +github.com/bytedance/sonic v1.14.1 h1:FBMC0zVz5XUmE4z9wF4Jey0An5FueFvOsTKKKtwIl7w= +github.com/bytedance/sonic v1.14.1/go.mod h1:gi6uhQLMbTdeP0muCnrjHLeCUPyb70ujhnNlhOylAFc= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= diff --git a/goextVersion.go b/goextVersion.go index 04a4c2b..ebde1a2 100644 --- a/goextVersion.go +++ b/goextVersion.go @@ -1,5 +1,5 @@ package goext -const GoextVersion = "0.0.596" +const GoextVersion = "0.0.597" -const GoextVersionTimestamp = "2025-08-26T15:55:57+0200" +const GoextVersionTimestamp = "2025-09-04T14:25:05+0200"