dragonfly/pkg/syncmap/syncmap.go

231 lines
6.4 KiB
Go

/*
* Copyright 2020 The Dragonfly Authors
*
* 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 syncmap
import (
"container/list"
"strconv"
"sync"
"time"
"github.com/pkg/errors"
"go.uber.org/atomic"
"d7y.io/dragonfly/v2/internal/dferrors"
"d7y.io/dragonfly/v2/pkg/util/stringutils"
)
// SyncMap is a thread-safe map providing generic support
type SyncMap struct {
*sync.Map
}
// NewSyncMap returns a new SyncMap.
func NewSyncMap() *SyncMap {
return &SyncMap{&sync.Map{}}
}
// Add adds a key-value pair into the *sync.Map.
// The ErrEmptyValue error will be returned if the key is empty.
func (mmap *SyncMap) Add(key string, value interface{}) error {
if stringutils.IsBlank(key) {
return errors.Wrap(dferrors.ErrEmptyValue, "key")
}
mmap.Store(key, value)
return nil
}
// Get returns result as interface{} according to the key.
// The ErrEmptyValue error will be returned if the key is empty.
// And the ErrDataNotFound error will be returned if the key cannot be found.
func (mmap *SyncMap) Get(key string) (interface{}, error) {
if stringutils.IsBlank(key) {
return nil, errors.Wrap(dferrors.ErrEmptyValue, "key")
}
if v, ok := mmap.Load(key); ok {
return v, nil
}
return nil, errors.Wrapf(dferrors.ErrDataNotFound, "get key %s from map", key)
}
// GetAsMap returns result as SyncMap.
// The ErrConvertFailed error will be returned if the assertion fails.
func (mmap *SyncMap) GetAsMap(key string) (*SyncMap, error) {
v, err := mmap.Get(key)
if err != nil {
return nil, errors.Wrapf(err, "get key %s from map", key)
}
if value, ok := v.(*SyncMap); ok {
return value, nil
}
return nil, errors.Wrapf(dferrors.ErrConvertFailed, "get key %s from map with value %s", key, v)
}
// GetAsList returns result as list
// The ErrConvertFailed error will be returned if the assertion fails.
func (mmap *SyncMap) GetAsList(key string) (*list.List, error) {
v, err := mmap.Get(key)
if err != nil {
return list.New(), errors.Wrapf(err, "get key %s from map", key)
}
if value, ok := v.(*list.List); ok {
return value, nil
}
return nil, errors.Wrapf(dferrors.ErrConvertFailed, "get key %s from map with value %s", key, v)
}
// GetAsInt returns result as int.
// The ErrConvertFailed error will be returned if the assertion fails.
func (mmap *SyncMap) GetAsInt(key string) (int, error) {
v, err := mmap.Get(key)
if err != nil {
return 0, errors.Wrapf(err, "get key %s from map", key)
}
if value, ok := v.(int); ok {
return value, nil
}
return 0, errors.Wrapf(dferrors.ErrConvertFailed, "get key %s from map with value %s", key, v)
}
// GetAsInt64 returns result as int64.
// The ErrConvertFailed error will be returned if the assertion fails.
func (mmap *SyncMap) GetAsInt64(key string) (int64, error) {
v, err := mmap.Get(key)
if err != nil {
return 0, errors.Wrapf(err, "get key %s from map", key)
}
if value, ok := v.(int64); ok {
return value, nil
}
return 0, errors.Wrapf(dferrors.ErrConvertFailed, "get key %s from map with value %s", key, v)
}
// GetAsString returns result as string.
// The ErrConvertFailed error will be returned if the assertion fails.
func (mmap *SyncMap) GetAsString(key string) (string, error) {
v, err := mmap.Get(key)
if err != nil {
return "", errors.Wrapf(err, "get key %s from map", key)
}
if value, ok := v.(string); ok {
return value, nil
}
return "", errors.Wrapf(dferrors.ErrConvertFailed, "get key %s from map with value %s", key, v)
}
// GetAsBool returns result as bool.
// The ErrConvertFailed error will be returned if the assertion fails.
func (mmap *SyncMap) GetAsBool(key string) (bool, error) {
v, err := mmap.Get(key)
if err != nil {
return false, errors.Wrapf(err, "get key %s from map", key)
}
if value, ok := v.(bool); ok {
return value, nil
}
return false, errors.Wrapf(dferrors.ErrConvertFailed, "get key %s from map with value %s", key, v)
}
// GetAsAtomicInt returns result as *AtomicInt.
// The ErrConvertFailed error will be returned if the assertion fails.
func (mmap *SyncMap) GetAsAtomicInt(key string) (*atomic.Int32, error) {
v, err := mmap.Get(key)
if err != nil {
return nil, errors.Wrapf(err, "get key %s from map", key)
}
if value, ok := v.(*atomic.Int32); ok {
return value, nil
}
return nil, errors.Wrapf(dferrors.ErrConvertFailed, "get key %s from map with value %s", key, v)
}
// GetAsTime returns result as Time.
// The ErrConvertFailed error will be returned if the assertion fails.
func (mmap *SyncMap) GetAsTime(key string) (time.Time, error) {
v, err := mmap.Get(key)
if err != nil {
return time.Now(), errors.Wrapf(err, "get key %s from map", key)
}
if value, ok := v.(time.Time); ok {
return value, nil
}
return time.Now(), errors.Wrapf(dferrors.ErrConvertFailed, "get key %s from map with value %s", key, v)
}
// Remove deletes the key-value pair from the mmap.
// The ErrEmptyValue error will be returned if the key is empty.
// And the ErrDataNotFound error will be returned if the key cannot be found.
func (mmap *SyncMap) Remove(key string) error {
if stringutils.IsBlank(key) {
return errors.Wrap(dferrors.ErrEmptyValue, "key")
}
if _, ok := mmap.Load(key); !ok {
return errors.Wrapf(dferrors.ErrDataNotFound, "get key %s from map", key)
}
mmap.Delete(key)
return nil
}
// ListKeyAsStringSlice returns the list of keys as a string slice.
func (mmap *SyncMap) ListKeyAsStringSlice() (result []string) {
if mmap == nil {
return []string{}
}
rangeFunc := func(key, value interface{}) bool {
if v, ok := key.(string); ok {
result = append(result, v)
return true
}
return true
}
mmap.Range(rangeFunc)
return
}
// ListKeyAsIntSlice returns the list of keys as an int slice.
func (mmap *SyncMap) ListKeyAsIntSlice() (result []int) {
if mmap == nil {
return []int{}
}
rangeFunc := func(key, value interface{}) bool {
if v, ok := key.(string); ok {
if value, err := strconv.Atoi(v); err == nil {
result = append(result, value)
return true
}
}
return true
}
mmap.Range(rangeFunc)
return
}