From b0a97978d80d7f3e3a1363bedff05a70d76249cd Mon Sep 17 00:00:00 2001 From: Charlie <3140647@qq.com> Date: Fri, 25 Aug 2023 15:31:00 +0800 Subject: [PATCH] update --- cache/{ => bigcache}/big_cache.go | 31 +++-- cache/bigcache/big_cache_test.go | 27 +++++ cache/cache.go | 170 +++++++++++++++------------- cache/cache_builder.go | 128 +++++++++------------ cache/cache_builder_test.go | 47 +++++--- cache/cache_preload.go | 12 ++ cache/cache_test.go | 85 +++++++------- cache/distributd_cache.go | 10 -- cache/distributed_cache.go | 14 +++ cache/empty_cache_adaper.go | 10 ++ cache/{ => freecache}/free_cache.go | 16 ++- cache/freecache/free_cache_test.go | 1 + cache/local_cache.go | 7 -- cache/lru.go | 2 + cache/mem.go | 5 +- cache/msg_pack.go | 43 +++++++ cache/qps.go | 6 +- cache/readme.md | 8 ++ cache/redis.go | 14 +-- cache/stats.go | 4 +- cache/tiny_lfu.go | 22 +++- calendar/duration.go | 13 +++ calendar/scheduled_executor.go | 14 +++ calendar/scheduled_executor_test.go | 14 +++ collections/list/array_list.go | 38 +++---- collections/list/linked_list.go | 32 ++---- collections/list/list.go | 6 +- collections/queue.go | 4 +- collections/rbtree/rbtree.go | 9 ++ crypto/{ => sm2}/sm2.go | 72 ++++++------ crypto/{ => sm2}/sm2_test.go | 34 ++++-- encode/encode.go | 19 ++++ errors/error.go | 19 +++- errors/error_test.go | 18 +-- file_store/file_store.go | 21 ++++ file_store/oss/oss.go | 6 + file_store/readme.md | 38 +++++++ go.mod | 51 +++++---- go.sum | 114 +++++++++++++++---- idGenerator/id_generator.go | 118 +++++++++++++++++++ idGenerator/id_generator_test.go | 32 ++++++ ketama/ketama.go | 38 +++++++ ketama/ketama_test.go | 32 ++++++ locker/empty_locker.go | 3 + locker/synchronizeable.go | 96 ++++++++++++++++ logx/logrus_options.go | 8 +- maps/sort_map.go | 11 +- mathx/int.go | 35 ------ mathx/int_test.go | 27 ----- mathx/math.go | 46 ++++++++ mathx/math_test.go | 54 +++++++++ sets/set.go | 1 + sets/sorted_set.go | 12 +- stringx/append.go | 8 ++ stringx/append_test.go | 8 ++ stringx/mask.go | 40 +++++++ stringx/mask_test.go | 28 +++++ tree/avl_tree.go | 25 ++++ 58 files changed, 1330 insertions(+), 476 deletions(-) rename cache/{ => bigcache}/big_cache.go (74%) create mode 100644 cache/bigcache/big_cache_test.go create mode 100644 cache/cache_preload.go delete mode 100644 cache/distributd_cache.go create mode 100644 cache/distributed_cache.go create mode 100644 cache/empty_cache_adaper.go rename cache/{ => freecache}/free_cache.go (82%) create mode 100644 cache/freecache/free_cache_test.go delete mode 100644 cache/local_cache.go create mode 100644 cache/lru.go create mode 100644 cache/msg_pack.go create mode 100644 calendar/scheduled_executor.go create mode 100644 calendar/scheduled_executor_test.go rename crypto/{ => sm2}/sm2.go (88%) rename crypto/{ => sm2}/sm2_test.go (76%) create mode 100644 encode/encode.go create mode 100644 file_store/file_store.go create mode 100644 file_store/oss/oss.go create mode 100644 file_store/readme.md create mode 100644 idGenerator/id_generator.go create mode 100644 idGenerator/id_generator_test.go create mode 100644 ketama/ketama.go create mode 100644 ketama/ketama_test.go create mode 100644 locker/synchronizeable.go delete mode 100644 mathx/int.go delete mode 100644 mathx/int_test.go create mode 100644 mathx/math.go create mode 100644 mathx/math_test.go create mode 100644 stringx/append.go create mode 100644 stringx/append_test.go create mode 100644 stringx/mask.go create mode 100644 stringx/mask_test.go create mode 100644 tree/avl_tree.go diff --git a/cache/big_cache.go b/cache/bigcache/big_cache.go similarity index 74% rename from cache/big_cache.go rename to cache/bigcache/big_cache.go index 385ef2e..db988af 100644 --- a/cache/big_cache.go +++ b/cache/bigcache/big_cache.go @@ -1,4 +1,4 @@ -package cache +package bigcache import ( "errors" @@ -8,8 +8,6 @@ import ( "github.com/charlienet/go-mixed/logx" ) -var _ MemCache = &bigCacheClient{} - type BigCacheConfig struct { Shards int LifeWindow time.Duration @@ -49,8 +47,13 @@ func NewBigCache(c BigCacheConfig) (*bigCacheClient, error) { }, nil } -func (c *bigCacheClient) Get(key string) ([]byte, error) { - return c.cache.Get(key) +func (c *bigCacheClient) Get(key string) ([]byte, bool) { + b, err := c.cache.Get(key) + if err == nil { + return b, false + } + + return b, true } func (c *bigCacheClient) Set(key string, entry []byte, expire time.Duration) error { @@ -68,9 +71,23 @@ func (c *bigCacheClient) Delete(keys ...string) error { return nil } -func (c *bigCacheClient) Exist(key string) { +func (c *bigCacheClient) Exist(key string) bool { + _, err := c.cache.Get(key) + if err == nil { + return true + } + + return !errors.Is(err, bigcache.ErrEntryNotFound) +} + +func (c *bigCacheClient) Clear() { + } func (c *bigCacheClient) IsNotFound(err error) bool { - return errors.Is(err, bigcache.ErrEntryNotFound) + if err == nil { + return true + } + + return !errors.Is(err, bigcache.ErrEntryNotFound) } diff --git a/cache/bigcache/big_cache_test.go b/cache/bigcache/big_cache_test.go new file mode 100644 index 0000000..0b21abd --- /dev/null +++ b/cache/bigcache/big_cache_test.go @@ -0,0 +1,27 @@ +package bigcache + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestBigCache(t *testing.T) { + r := require.New(t) + + c, err := NewBigCache(BigCacheConfig{}) + r.Nil(err) + + cacheKey := "a" + cacheValue := "bbb" + + c.Set(cacheKey, []byte(cacheValue), time.Second*5) + + r.True(c.Exist(cacheKey)) + r.False(c.Exist("abb")) + + b, ok := c.Get(cacheKey) + r.True(ok) + r.Equal(cacheValue, string(b)) +} diff --git a/cache/cache.go b/cache/cache.go index c0a491d..3785b25 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -6,62 +6,73 @@ import ( "fmt" "time" - "github.com/charlienet/go-mixed/bytesconv" - "github.com/charlienet/go-mixed/json" "github.com/charlienet/go-mixed/locker" "github.com/charlienet/go-mixed/logx" + "golang.org/x/sync/singleflight" ) var ErrNotFound = errors.New("key not found") +// 数据加载函数定义 type LoadFunc func(context.Context) (any, error) -type Cache struct { - prefix string // 键前缀 - retry int // 资源获取时的重试次数 - mem MemCache // 内存缓存 - distributdCache DistributdCache // 分布式缓存 - publishSubscribe PublishSubscribe // 发布订阅 - lock locker.ChanLocker // 资源锁 - stats *Stats // 缓存命中计数 - qps *qps // 访问计数 - logger logx.Logger // 日志记录 +type ICache interface { } -func NewCache(opts ...option) *Cache { +type Cache struct { + prefix string // 键前缀 + retry int // 资源获取时的重试次数 + mem MemCache // 内存缓存 + rds DistributedCache // 远程缓存 + publishSubscribe PublishSubscribe // 发布订阅 + group singleflight.Group // singleflight.Group + lock locker.ChanLocker // 资源锁 + stats *Stats // 缓存命中计数 + qps *qps // 访问计数 + logger logx.Logger // 日志记录 +} + +func New(opts ...option) (*Cache, error) { c := acquireDefaultCache() for _, f := range opts { if err := f(c); err != nil { - return c + return c, nil } } - go c.subscribe() + // 未设置内存缓存时,添加默认缓存 + if c.mem == nil { + c.mem = NewTinyLFU(1<<12, time.Second*30) + } - return c + return c, nil } -func (c *Cache) Set(key string, value any, expiration time.Duration) error { - if c.mem != nil { - bytes, err := bytesconv.Encode(value) - if err != nil { - return err - } +func (c *Cache) Set(ctx context.Context, key string, value any, expiration time.Duration) error { + buf, err := Marshal(value) + if err != nil { + return err + } - c.mem.Set(key, bytes, expiration) + if c.mem != nil { + c.mem.Set(key, buf, expiration) + } + + if c.rds != nil { + c.rds.Set(ctx, key, buf, expiration) } return nil } -func (c *Cache) Get(key string, out any) error { +func (c *Cache) Get(ctx context.Context, key string, out any) error { if c.mem != nil { - c.getFromMem(key, out) + c.getFromMem(key) } - if c.distributdCache != nil { - if err := c.distributdCache.Get(key, out); err != nil { + if c.rds != nil { + if err := c.rds.Get(ctx, key, out); err != nil { } } @@ -70,7 +81,7 @@ func (c *Cache) Get(key string, out any) error { } func (c *Cache) GetFn(ctx context.Context, key string, out any, fn LoadFunc, expiration time.Duration) (bool, error) { - c.Get(key, out) + c.Get(ctx, key, out) // 多级缓存中未找到时,放置缓存对象 ret, err := fn(ctx) @@ -78,7 +89,7 @@ func (c *Cache) GetFn(ctx context.Context, key string, out any, fn LoadFunc, exp return false, err } - c.Set(key, ret, expiration) + c.Set(ctx, key, ret, expiration) return false, nil } @@ -87,32 +98,69 @@ func (c *Cache) Exist(key string) (bool, error) { return false, nil } -func (c *Cache) Delete(key ...string) error { +func (c *Cache) Delete(ctx context.Context, key ...string) error { if c.mem != nil { c.mem.Delete(key...) } - if c.distributdCache != nil { - c.distributdCache.Delete(key...) + if c.rds != nil { + c.rds.Delete(ctx, key...) + } + + for _, k := range key { + c.group.Forget(k) } return nil } -func (c *Cache) subscribe() { +// 清除本地缓存 +func (c *Cache) ClearMem() { + if c.mem != nil { + c.mem.Clear() + } } -func (c *Cache) getFromMem(key string, out any) error { - bytes, err := c.mem.Get(key) - if err != nil { - return err - } +func (c *Cache) Clear() { - if err := bytesconv.Decode(bytes, out); err != nil { - return err - } +} - return nil +func (c *Cache) Disable() { + +} + +func (c *Cache) Enable() { + +} + +func (c *Cache) getOnce(ctx context.Context, key string) (b []byte, cached bool, err error) { + if c.mem != nil { + b, ok := c.mem.Get(key) + if ok { + return b, true, nil + } + } + c.group.Do(key, func() (any, error) { + if c.mem != nil { + b, ok := c.mem.Get(key) + if ok { + return b, nil + } + } + + if c.rds != nil { + c.rds.Get(ctx, key, nil) + } + + return nil, nil + }) + + return +} + +func (c *Cache) getFromMem(key string) ([]byte, bool) { + bytes, cached := c.mem.Get(key) + return bytes, cached } // 从缓存加载数据 @@ -125,8 +173,6 @@ func (c *Cache) getFromCache() { // 从数据源加载数据 func (c *Cache) getFromSource(ctx context.Context, key string, fn LoadFunc) error { - // 1. 尝试获取资源锁,如成功获取到锁加载数据 - // 2. 未获取到锁,等待从缓存中获取 ch, ok := c.lock.Get(key) if ok { defer c.lock.Release(key) @@ -150,39 +196,3 @@ func (c *Cache) getFromSource(ctx context.Context, key string, fn LoadFunc) erro return c.getFromSource(ctx, key, fn) } } - -func (c *Cache) marshal(value any) ([]byte, error) { - switch value := value.(type) { - case nil: - return nil, nil - case []byte: - return value, nil - case string: - return []byte(value), nil - } - - b, err := json.Marshal(value) - return b, err -} - -func (c *Cache) unmarshal(b []byte, value any) error { - if len(b) == 0 { - return nil - } - - switch value := value.(type) { - case nil: - return nil - case *[]byte: - clone := make([]byte, len(b)) - copy(clone, b) - *value = clone - return nil - case *string: - *value = string(b) - return nil - } - - err := json.Unmarshal(b, value) - return err -} diff --git a/cache/cache_builder.go b/cache/cache_builder.go index 4f18222..e7344ea 100644 --- a/cache/cache_builder.go +++ b/cache/cache_builder.go @@ -1,99 +1,81 @@ package cache -import "github.com/charlienet/go-mixed/logx" +import ( + "context" + "time" + + "github.com/charlienet/go-mixed/cache/bigcache" + "github.com/charlienet/go-mixed/cache/freecache" + "github.com/charlienet/go-mixed/logx" +) const defaultPrefix = "cache" + type option func(*Cache) error type options struct { Prefix string } -func acquireDefaultCache() *Cache { - return &Cache{ - prefix: defaultPrefix, - qps: NewQps(), +func WithRedis(opts RedisConfig) option { + return func(c *Cache) error { + if len(opts.Prefix) == 0 { + opts.Prefix = defaultPrefix + } + + rds := NewRedis(opts) + + c.rds = rds + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) + defer cancel() + return rds.Ping(ctx) } } -type cacheBuilder struct { - prefix string - redisOptions RedisConfig - bigCacheConfig BigCacheConfig - freeSize int - publishSubscribe PublishSubscribe - log logx.Logger +func WithBigCache(opts bigcache.BigCacheConfig) option { + return func(c *Cache) error { + mem, err := bigcache.NewBigCache(opts) + + c.mem = mem + return err + } } -func NewCacheBuilder() *cacheBuilder { - return &cacheBuilder{} -} +func WithFreeCache(size int) option { + return func(c *Cache) error { + mem := freecache.NewFreeCache(size) + c.mem = mem -func (b *cacheBuilder) WithLogger(log logx.Logger) *cacheBuilder { - b.log = log - return b -} - -func (b *cacheBuilder) WithPrefix(prefix string) *cacheBuilder { - b.prefix = prefix - return b -} - -func (b *cacheBuilder) WithRedis(opts RedisConfig) *cacheBuilder { - b.redisOptions = opts - return b -} - -func (b *cacheBuilder) WithBigCache(opts BigCacheConfig) *cacheBuilder { - b.bigCacheConfig = opts - return b -} - -func (b *cacheBuilder) WithFreeCache(size int) *cacheBuilder { - b.freeSize = size - return b + return nil + } } // 使用自定义分布式缓存 -func WithDistributedCache(c DistributdCache) { - +func WithDistributedCache(rds DistributedCache) option { + return func(c *Cache) error { + c.rds = rds + return nil + } } -func (b *cacheBuilder) WithPublishSubscribe(p PublishSubscribe) *cacheBuilder { - b.publishSubscribe = p - return b +func WithPublishSubscribe(p PublishSubscribe) option { + return func(c *Cache) error { + return nil + } } -func (b cacheBuilder) Build() (*Cache, error) { - var err error - cache := acquireDefaultCache() - if len(b.prefix) > 0 { - cache.prefix = b.prefix +func WithLogger(log logx.Logger) option { + return func(c *Cache) error { + c.logger = log + + return nil + } +} + +func acquireDefaultCache() *Cache { + return &Cache{ + qps: NewQps(), } - - b.redisOptions.Prefix = cache.prefix - - redis := NewRedis(b.redisOptions) - if err := redis.Ping(); err != nil { - return cache, err - } - - var mem MemCache - if b.freeSize > 0 { - mem = NewFreeCache(b.freeSize) - } else { - if b.log != nil { - b.bigCacheConfig.log = b.log - } - - mem, err = NewBigCache(b.bigCacheConfig) - } - - cache.distributdCache = redis - cache.mem = mem - cache.publishSubscribe = b.publishSubscribe - cache.logger = b.log - - return cache, err } diff --git a/cache/cache_builder_test.go b/cache/cache_builder_test.go index e3dca8d..d70db6e 100644 --- a/cache/cache_builder_test.go +++ b/cache/cache_builder_test.go @@ -3,27 +3,38 @@ package cache import ( "testing" "time" - - "github.com/charlienet/go-mixed/logx" ) func TestBuilder(t *testing.T) { - cache, err := NewCacheBuilder(). - WithLogger(logx.NewLogrus(logx.WithFormatter(logx.NewNestedFormatter(logx.NestedFormatterOption{ - Color: true, - })))). - WithRedis(RedisConfig{ - Addrs: []string{"192.168.2.222:6379"}, - Password: "123456", - }). - WithBigCache(BigCacheConfig{}). - // WithFreeCache(10 * 1024 * 1024). - Build() + now := time.Now() + t.Log(now) + t1, _ := time.ParseDuration("9h27m") + t1 += time.Hour * 24 + t2, _ := time.ParseDuration("16h28m") + t.Log(t1) + t.Log(t2) - if err != nil { - t.Fatal(err) - } + f := time.Date(2022, time.December, 12, 8, 0, 0, 0, time.Local) + t.Log(f.Sub(time.Now())) - u := SimpleUser{FirstName: "Radomir", LastName: "Sohlich"} - t.Log(cache.Set(defaultKey, u, time.Minute*10)) + // cache, err := New( + // WithLogger(logx.NewLogrus(logx.WithNestedFormatter(logx.NestedFormatterOption{ + // Color: true, + // }))). + // UseRedis(RedisConfig{ + // Addrs: []string{"192.168.2.222:6379"}, + // Password: "123456", + // }). + // UseBigCache(bigcache.BigCacheConfig{}). + // Build() + + // if err != nil { + // t.Fatal(err) + // } + + // ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) + // defer cancel() + + // u := SimpleUser{FirstName: "Radomir", LastName: "Sohlich"} + // t.Log(cache.Set(ctx, defaultKey, u, time.Minute*10)) } diff --git a/cache/cache_preload.go b/cache/cache_preload.go new file mode 100644 index 0000000..0fd0790 --- /dev/null +++ b/cache/cache_preload.go @@ -0,0 +1,12 @@ +package cache + +import "context" + +// PreLoadItem 预加载数据项 +type PreLoadItem struct { + Key string + Value any +} + +// PreloadFunc 数据预加载函数定义 +type PreloadFunc func(context.Context) ([]PreLoadItem, error) diff --git a/cache/cache_test.go b/cache/cache_test.go index 2c2e16c..8745eac 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -6,9 +6,6 @@ import ( "sync/atomic" "testing" "time" - - "github.com/charlienet/go-mixed/bytesconv" - "github.com/charlienet/go-mixed/logx" ) var ( @@ -16,25 +13,26 @@ var ( ) func TestNewCache(t *testing.T) { - c, err := NewCacheBuilder(). - WithRedis(RedisConfig{ - Addrs: []string{"192.168.2.222:6379"}, - Password: "123456", - }). - WithPrefix("cache_test"). - WithLogger(logx.NewLogrus()). - Build() + // c, err := NewCacheBuilder(). + // UseRedis(RedisConfig{ + // Addrs: []string{"192.168.2.222:6379"}, + // Password: "123456", + // }). + // WithPrefix("cache_test"). + // WithLogger(logx.NewLogrus()). + // Build() - if err != nil { - t.Fatal(err) - } + // if err != nil { + // t.Fatal(err) + // } - c.Set("abc", "value", time.Minute*10) + // ctx := context.Background() + // c.Set(ctx, "abc", "value", time.Minute*10) - var s string - c.Get("abc", &s) + // var s string + // c.Get(ctx, "abc", &s) - t.Log(s) + // t.Log(s) } type SimpleUser struct { @@ -43,45 +41,43 @@ type SimpleUser struct { } func TestMemCache(t *testing.T) { - b, _ := NewBigCache(BigCacheConfig{}) - var mems = []MemCache{ - NewFreeCache(10 * 1024 * 1024), - b, - } + // b, _ := bigcache.NewBigCache(bigcache.BigCacheConfig{}) + // var mems = []MemCache{ + // NewFreeCache(10 * 1024 * 1024), + // b, + // } - u := SimpleUser{FirstName: "Radomir", LastName: "Sohlich"} - encoded, _ := bytesconv.Encode(u) - for _, m := range mems { - m.Set(defaultKey, encoded, time.Second) - ret, err := m.Get(defaultKey) - if err != nil { - t.Fatal(err) - } + // u := SimpleUser{FirstName: "Radomir", LastName: "Sohlich"} + // encoded, _ := bytesconv.Encode(u) + // for _, m := range mems { + // m.Set(defaultKey, encoded, time.Second) + // ret, _ := m.Get(defaultKey) - var u2 SimpleUser - bytesconv.Decode(ret, &u2) - t.Log(u2) - } + // var u2 SimpleUser + // bytesconv.Decode(ret, &u2) + // t.Log(u2) + // } } func TestDistributedCache(t *testing.T) { c := NewRedis(RedisConfig{Addrs: []string{"192.168.2.222:6379"}, DB: 6, Password: "123456", Prefix: "abcdef"}) - if err := c.Ping(); err != nil { + ctx := context.Background() + if err := c.Ping(ctx); err != nil { t.Fatal(err) } - t.Log(c.Exist(defaultKey)) + t.Log(c.Exist(ctx, defaultKey)) u := SimpleUser{FirstName: "redis client"} var u2 SimpleUser - c.Get(defaultKey, &u2) + c.Get(ctx, defaultKey, &u2) - c.Set(defaultKey, u, time.Minute*10) - t.Log(c.Exist(defaultKey)) + c.Set(ctx, defaultKey, u, time.Minute*10) + t.Log(c.Exist(ctx, defaultKey)) - if err := c.Get(defaultKey, &u2); err != nil { + if err := c.Get(ctx, defaultKey, &u2); err != nil { t.Fatal("err:", err) } t.Logf("%+v", u2) @@ -136,10 +132,9 @@ func load() (any, error) { } func buildCache() *Cache { - c, err := NewCacheBuilder(). - WithFreeCache(10 * 1024 * 1024). - WithRedis(RedisConfig{Addrs: []string{"192.168.2.222:6379"}, DB: 6, Password: "123456"}). - Build() + c, err := New( + WithFreeCache(10*1024*1024), + WithRedis(RedisConfig{Addrs: []string{"192.168.2.222:6379"}, DB: 6, Password: "123456"})) if err != nil { panic(err) diff --git a/cache/distributd_cache.go b/cache/distributd_cache.go deleted file mode 100644 index 2b05b8e..0000000 --- a/cache/distributd_cache.go +++ /dev/null @@ -1,10 +0,0 @@ -package cache - -import "time" - -type DistributdCache interface { - Get(key string, out any) error - Set(key string, value any, expiration time.Duration) error - Delete(key ...string) error - Ping() error -} diff --git a/cache/distributed_cache.go b/cache/distributed_cache.go new file mode 100644 index 0000000..7b793f7 --- /dev/null +++ b/cache/distributed_cache.go @@ -0,0 +1,14 @@ +package cache + +import ( + "context" + "time" +) + +// 分布式缓存接口 +type DistributedCache interface { + Get(ctx context.Context, key string, out any) error + Set(ctx context.Context, key string, value any, expiration time.Duration) error + Delete(ctx context.Context, key ...string) error + Ping(ctx context.Context) error +} diff --git a/cache/empty_cache_adaper.go b/cache/empty_cache_adaper.go new file mode 100644 index 0000000..5ca7dbf --- /dev/null +++ b/cache/empty_cache_adaper.go @@ -0,0 +1,10 @@ +package cache + +import "context" + +// var emptyCache DistributedCache = &emptyCacheAdapter{} + +type emptyCacheAdapter struct { +} + +func (*emptyCacheAdapter) Delete(ctx context.Context, keys ...string) {} diff --git a/cache/free_cache.go b/cache/freecache/free_cache.go similarity index 82% rename from cache/free_cache.go rename to cache/freecache/free_cache.go index 5a0d64c..74e56cf 100644 --- a/cache/free_cache.go +++ b/cache/freecache/free_cache.go @@ -1,4 +1,4 @@ -package cache +package freecache import ( "errors" @@ -10,8 +10,6 @@ import ( const defaultSize = 10 * 1024 * 1024 // 10M -var _ MemCache = &freeCache{} - type freeCache struct { cache *freecache.Cache } @@ -29,8 +27,12 @@ func NewFreeCache(size int) *freeCache { } } -func (c *freeCache) Get(key string) ([]byte, error) { - return c.cache.Get([]byte(key)) +func (c *freeCache) Get(key string) ([]byte, bool) { + b, err := c.cache.Get([]byte(key)) + if err != nil { + return b, false + } + return b, true } func (c *freeCache) Set(key string, value []byte, d time.Duration) error { @@ -54,6 +56,10 @@ func (c *freeCache) Exist(key string) error { return nil } +func (c *freeCache) Clear() { + +} + func (c *freeCache) IsNotFound(err error) bool { return errors.Is(err, freecache.ErrNotFound) } diff --git a/cache/freecache/free_cache_test.go b/cache/freecache/free_cache_test.go new file mode 100644 index 0000000..0841105 --- /dev/null +++ b/cache/freecache/free_cache_test.go @@ -0,0 +1 @@ +package freecache diff --git a/cache/local_cache.go b/cache/local_cache.go deleted file mode 100644 index 6b4ff29..0000000 --- a/cache/local_cache.go +++ /dev/null @@ -1,7 +0,0 @@ -package cache - -type LocalCache interface { - Set(key string, data []byte) - Get(key string) ([]byte, bool) - Del(key string) -} diff --git a/cache/lru.go b/cache/lru.go new file mode 100644 index 0000000..9cacc5f --- /dev/null +++ b/cache/lru.go @@ -0,0 +1,2 @@ +package cache + diff --git a/cache/mem.go b/cache/mem.go index d06f58d..1d1f3d0 100644 --- a/cache/mem.go +++ b/cache/mem.go @@ -3,7 +3,8 @@ package cache import "time" type MemCache interface { - Get(key string) ([]byte, error) - Set(key string, entry []byte, expire time.Duration) error + Get(key string) ([]byte, bool) + Set(key string, b []byte, expire time.Duration) error Delete(key ...string) error + Clear() } diff --git a/cache/msg_pack.go b/cache/msg_pack.go new file mode 100644 index 0000000..00ac538 --- /dev/null +++ b/cache/msg_pack.go @@ -0,0 +1,43 @@ +package cache + +import ( + "github.com/vmihailenco/msgpack/v5" +) + +func Marshal(v any) ([]byte, error) { + switch v := v.(type) { + case nil: + return nil, nil + case []byte: + return v, nil + case string: + return []byte(v), nil + } + + b, err := msgpack.Marshal(v) + if err != nil { + return nil, err + } + + return b, err +} + +func Unmarshal(b []byte, v any) error { + if len(b) == 0 { + return nil + } + + switch v := v.(type) { + case nil: + return nil + case *[]byte: + clone := make([]byte, len(b)) + copy(clone, b) + *v = clone + case *string: + *v = string(b) + return nil + } + + return msgpack.Unmarshal(b, v) +} diff --git a/cache/qps.go b/cache/qps.go index 4f6dfb1..54c09bf 100644 --- a/cache/qps.go +++ b/cache/qps.go @@ -31,7 +31,9 @@ func (q *qps) statisticsTotal() { } }() - ticker := time.NewTicker(time.Second) + ticker := time.NewTicker(time.Minute) + defer ticker.Stop() + for range ticker.C { q.all.viewTotal = atomic.SwapInt64(&q.all.total, 0) q.memoryTotal.viewTotal = atomic.SwapInt64(&q.memoryTotal.total, 0) @@ -39,5 +41,7 @@ func (q *qps) statisticsTotal() { q.redisTotal.viewTotal = atomic.SwapInt64(&q.redisTotal.total, 0) q.redisHit.viewTotal = atomic.SwapInt64(&q.redisHit.total, 0) q.sourceTotal.viewTotal = atomic.SwapInt64(&q.sourceTotal.total, 0) + + // percnt := 0 } } diff --git a/cache/readme.md b/cache/readme.md index 95288f2..c50e1e2 100644 --- a/cache/readme.md +++ b/cache/readme.md @@ -14,6 +14,14 @@ ## 使用方式 +创建 + +```go +cache.New().UseRedis().UseBigCache().Build() + +``` + ```go Cache.Get(key, dist, func() (bool,error){}, options func(){}) +Cache.GetFn(context, key, dist, func() (bool, error)) ``` diff --git a/cache/redis.go b/cache/redis.go index db9896b..2b068cf 100644 --- a/cache/redis.go +++ b/cache/redis.go @@ -54,7 +54,7 @@ func NewRedis(c RedisConfig) *redisClient { } } -func (c *redisClient) Get(key string, out any) error { +func (c *redisClient) Get(cxt context.Context, key string, out any) error { val, err := c.client.Get(context.Background(), c.getKey(key)).Result() if errors.Is(err, redis.Nil) { return ErrNotFound @@ -72,23 +72,23 @@ func (c *redisClient) Get(key string, out any) error { return json.Unmarshal(bytesconv.StringToBytes(val), out) } -func (c *redisClient) Set(key string, value any, expiration time.Duration) error { +func (c *redisClient) Set(ctx context.Context, key string, value any, expiration time.Duration) error { j, _ := json.Marshal(value) return c.client.Set(context.Background(), c.getKey(key), j, expiration).Err() } -func (c *redisClient) Exist(key string) (bool, error) { +func (c *redisClient) Exist(ctx context.Context, key string) (bool, error) { val, err := c.client.Exists(context.Background(), c.getKey(key)).Result() return val > 0, err } -func (c *redisClient) Delete(key ...string) error { +func (c *redisClient) Delete(ctx context.Context, key ...string) error { keys := make([]string, 0, len(key)) for _, k := range key { keys = append(keys, c.getKey(k)) } - _ , err := c.client.Del(context.Background(), keys...).Result() + _, err := c.client.Del(context.Background(), keys...).Result() if err != nil { return err } @@ -96,8 +96,8 @@ func (c *redisClient) Delete(key ...string) error { return nil } -func (c *redisClient) Ping() error { - _, err := c.client.Ping(context.Background()).Result() +func (c *redisClient) Ping(ctx context.Context) error { + _, err := c.client.Ping(ctx).Result() return err } diff --git a/cache/stats.go b/cache/stats.go index fcb6fa6..871258e 100644 --- a/cache/stats.go +++ b/cache/stats.go @@ -7,11 +7,11 @@ type Stats struct { Misses uint64 } -func (s *Stats) AddHits() { +func (s *Stats) IncrementHits() { atomic.AddUint64(&s.Hits, 1) } -func (s *Stats) AddMisses() { +func (s *Stats) IncrementMisses() { atomic.AddUint64(&s.Misses, 1) } diff --git a/cache/tiny_lfu.go b/cache/tiny_lfu.go index 4479c12..34c32f6 100644 --- a/cache/tiny_lfu.go +++ b/cache/tiny_lfu.go @@ -7,6 +7,8 @@ import ( "github.com/vmihailenco/go-tinylfu" ) +var _ MemCache = &TinyLFU{} + type TinyLFU struct { mu locker.Locker lfu *tinylfu.T @@ -21,15 +23,17 @@ func NewTinyLFU(size int, ttl time.Duration) *TinyLFU { } } -func (c *TinyLFU) Set(key string, b []byte, expire time.Duration) { +func (c *TinyLFU) Set(key string, b []byte, expire time.Duration) error { c.mu.Lock() defer c.mu.Unlock() c.lfu.Set(&tinylfu.Item{ - Key: key, - Value: b, + Key: key, + Value: b, ExpireAt: time.Now().Add(c.ttl), }) + + return nil } func (c *TinyLFU) Get(key string) ([]byte, bool) { @@ -44,9 +48,17 @@ func (c *TinyLFU) Get(key string) ([]byte, bool) { return val.([]byte), true } -func (c *TinyLFU) Del(key string) { +func (c *TinyLFU) Delete(keys ...string) error { c.mu.Lock() defer c.mu.Unlock() - c.lfu.Del(key) + for _, k := range keys { + c.lfu.Del(k) + } + + return nil +} + +func (c *TinyLFU) Clear() { + } diff --git a/calendar/duration.go b/calendar/duration.go index 9bbe295..6f31ecb 100644 --- a/calendar/duration.go +++ b/calendar/duration.go @@ -9,3 +9,16 @@ func ParseDuration(s string) (time.Duration, error) { return time.ParseDuration(s) } + +func ParseDurationDefault(s string, d time.Duration) time.Duration { + if len(s) == 0 { + return d + } + + ret, err := time.ParseDuration(s) + if err != nil { + return d + } + + return ret +} diff --git a/calendar/scheduled_executor.go b/calendar/scheduled_executor.go new file mode 100644 index 0000000..0d7dc8e --- /dev/null +++ b/calendar/scheduled_executor.go @@ -0,0 +1,14 @@ +package calendar + +import "time" + +type ScheduledExecutor struct { +} + +func NewScheduledExecutor() *ScheduledExecutor { + return &ScheduledExecutor{} +} + +func (e *ScheduledExecutor) Schedule(i any, duration time.Duration) { + +} diff --git a/calendar/scheduled_executor_test.go b/calendar/scheduled_executor_test.go new file mode 100644 index 0000000..3b419cb --- /dev/null +++ b/calendar/scheduled_executor_test.go @@ -0,0 +1,14 @@ +package calendar_test + +import ( + "testing" + "time" + + "github.com/charlienet/go-mixed/calendar" +) + +func TestExecutor(t *testing.T) { + executor := calendar.NewScheduledExecutor() + + executor.Schedule(nil, time.Minute) +} diff --git a/collections/list/array_list.go b/collections/list/array_list.go index 086b582..80b3dd9 100644 --- a/collections/list/array_list.go +++ b/collections/list/array_list.go @@ -1,9 +1,5 @@ package list -import ( - "github.com/charlienet/go-mixed/locker" -) - const minCapacity = 16 type ArrayList[T any] struct { @@ -31,7 +27,7 @@ func NewArrayList[T any](elems ...T) *ArrayList[T] { } l := &ArrayList[T]{ - list: list[T]{size: size, locker: locker.EmptyLocker}, + list: list[T]{size: size}, buf: buf, tail: tail, minCap: minCap, @@ -45,8 +41,8 @@ func NewArrayList[T any](elems ...T) *ArrayList[T] { } func (l *ArrayList[T]) PushFront(v T) { - l.locker.Lock() - defer l.locker.Unlock() + l.mu.Lock() + defer l.mu.Unlock() l.grow() @@ -56,8 +52,8 @@ func (l *ArrayList[T]) PushFront(v T) { } func (l *ArrayList[T]) PushBack(v T) { - l.locker.Lock() - defer l.locker.Unlock() + l.mu.Lock() + defer l.mu.Unlock() l.grow() @@ -68,8 +64,8 @@ func (l *ArrayList[T]) PushBack(v T) { } func (l *ArrayList[T]) PopFront() T { - l.locker.Lock() - defer l.locker.Unlock() + l.mu.Lock() + defer l.mu.Unlock() if l.size <= 0 { panic("list: PopFront() called on empty list") @@ -86,8 +82,8 @@ func (l *ArrayList[T]) PopFront() T { } func (l *ArrayList[T]) PopBack() T { - l.locker.Lock() - defer l.locker.Unlock() + l.mu.Lock() + defer l.mu.Unlock() l.tail = l.prev(l.tail) @@ -105,8 +101,8 @@ func (l *ArrayList[T]) RemoveAt(at int) T { panic(ErrorOutOffRange) } - l.locker.Lock() - defer l.locker.Unlock() + l.mu.Lock() + defer l.mu.Unlock() rm := (l.head + at) & (len(l.buf) - 1) if at*2 < l.size { @@ -127,22 +123,22 @@ func (l *ArrayList[T]) RemoveAt(at int) T { } func (l *ArrayList[T]) Front() T { - l.locker.RLock() - defer l.locker.RUnlock() + l.mu.RLock() + defer l.mu.RUnlock() return l.buf[l.head] } func (l *ArrayList[T]) Back() T { - l.locker.RLock() - defer l.locker.RUnlock() + l.mu.RLock() + defer l.mu.RUnlock() return l.buf[l.tail] } func (l *ArrayList[T]) ForEach(fn func(T)) { - l.locker.RLock() - defer l.locker.RUnlock() + l.mu.RLock() + defer l.mu.RUnlock() n := l.head for i := 0; i < l.size; i++ { diff --git a/collections/list/linked_list.go b/collections/list/linked_list.go index 4240f77..0652164 100644 --- a/collections/list/linked_list.go +++ b/collections/list/linked_list.go @@ -1,9 +1,5 @@ package list -import ( - "github.com/charlienet/go-mixed/locker" -) - type LinkedList[T any] struct { list[T] front, tail *LinkedNode[T] @@ -16,9 +12,7 @@ type LinkedNode[T any] struct { // NewLinkedList 初始化链表 func NewLinkedList[T any](elems ...T) *LinkedList[T] { - l := &LinkedList[T]{ - list: list[T]{locker: locker.EmptyLocker}, - } + l := &LinkedList[T]{} for _, e := range elems { l.pushBackNode(&LinkedNode[T]{Value: e}) @@ -28,8 +22,8 @@ func NewLinkedList[T any](elems ...T) *LinkedList[T] { } func (l *LinkedList[T]) PushBack(v T) *LinkedList[T] { - l.locker.Lock() - defer l.locker.Unlock() + l.mu.Lock() + defer l.mu.Unlock() l.pushBackNode(&LinkedNode[T]{Value: v}) @@ -37,8 +31,8 @@ func (l *LinkedList[T]) PushBack(v T) *LinkedList[T] { } func (l *LinkedList[T]) PushFront(v T) *LinkedList[T] { - l.locker.Lock() - defer l.locker.Unlock() + l.mu.Lock() + defer l.mu.Unlock() l.pushFrontNode(&LinkedNode[T]{Value: v}) @@ -65,8 +59,8 @@ func (l *LinkedList[T]) Back() T { } func (l *LinkedList[T]) ForEach(fn func(T) bool) { - l.locker.RLock() - defer l.locker.RUnlock() + l.mu.RLock() + defer l.mu.RUnlock() for current := l.front; current != nil; current = current.Next { if fn(current.Value) { @@ -77,12 +71,10 @@ func (l *LinkedList[T]) ForEach(fn func(T) bool) { func (l *LinkedList[T]) GetAt(i int) T { if i <= l.Size() { - var n int - for current := l.front; current != nil; current = current.Next { + for n, current := 0, l.front; current != nil; current, n = current.Next, n+1 { if n == i { return current.Value } - n++ } } @@ -90,8 +82,8 @@ func (l *LinkedList[T]) GetAt(i int) T { } func (l *LinkedList[T]) Remove(n *LinkedNode[T]) { - l.locker.Lock() - defer l.locker.Unlock() + l.mu.Lock() + defer l.mu.Unlock() if n.Next != nil { n.Next.Prev = n.Prev @@ -112,8 +104,8 @@ func (l *LinkedList[T]) Remove(n *LinkedNode[T]) { } func (l *LinkedList[T]) RemoveAt(index int) { - l.locker.Lock() - defer l.locker.Unlock() + l.mu.Lock() + defer l.mu.Unlock() var i int for current := l.front; current != nil; current = current.Next { diff --git a/collections/list/list.go b/collections/list/list.go index 150bd58..30ce0c8 100644 --- a/collections/list/list.go +++ b/collections/list/list.go @@ -12,12 +12,12 @@ type List[T any] interface { } type list[T any] struct { - size int - locker locker.RWLocker + size int + mu locker.WithRWLocker } func (l *list[T]) Synchronize() { - l.locker = locker.NewRWLocker() + l.mu.Synchronize() } func (l *list[T]) ForEach(fn func(T) bool) { panic("Not Implemented") } diff --git a/collections/queue.go b/collections/queue.go index 20a1a26..736d3c2 100644 --- a/collections/queue.go +++ b/collections/queue.go @@ -1,6 +1,8 @@ package collections -import "sync" +import ( + "sync" +) var _ Queue[string] = &ArrayQueue[string]{} diff --git a/collections/rbtree/rbtree.go b/collections/rbtree/rbtree.go index b06fe3a..c4aa1ad 100644 --- a/collections/rbtree/rbtree.go +++ b/collections/rbtree/rbtree.go @@ -1 +1,10 @@ package rbtree + +type color bool + +const ( + black, red color = true, false +) + +type TreeNode[K any, V any] struct { +} diff --git a/crypto/sm2.go b/crypto/sm2/sm2.go similarity index 88% rename from crypto/sm2.go rename to crypto/sm2/sm2.go index 3027fa2..1afd36d 100644 --- a/crypto/sm2.go +++ b/crypto/sm2/sm2.go @@ -1,4 +1,4 @@ -package crypto +package sm2 import ( "crypto/rand" @@ -14,7 +14,7 @@ var ( C1C2C3 = 1 ) -var _ IAsymmetric = &sm2Instance{} +type option func(*sm2Instance) error type sm2Instance struct { mode int @@ -22,9 +22,42 @@ type sm2Instance struct { puk *s.PublicKey } -type option func(*sm2Instance) error +func WithSm2PrivateKey(p []byte, pwd []byte) option { + return func(so *sm2Instance) error { + priv, err := x.ReadPrivateKeyFromPem(p, pwd) + if err != nil { + return err + } -func NewSm2(opts ...option) (*sm2Instance, error) { + so.prk = priv + return nil + } +} + +func WithSm2PublicKey(p []byte) option { + return func(so *sm2Instance) error { + if len(p) == 0 { + return nil + } + + pub, err := x.ReadPublicKeyFromPem(p) + if err != nil { + return err + } + + so.puk = pub + return nil + } +} + +func WithMode(mode int) option { + return func(so *sm2Instance) error { + so.mode = mode + return nil + } +} + +func New(opts ...option) (*sm2Instance, error) { o := &sm2Instance{ mode: defaultMode, } @@ -51,37 +84,6 @@ func NewSm2(opts ...option) (*sm2Instance, error) { return o, nil } -func ParseSm2PrivateKey(p []byte, pwd []byte) option { - return func(so *sm2Instance) error { - priv, err := x.ReadPrivateKeyFromPem(p, pwd) - if err != nil { - return err - } - - so.prk = priv - return nil - } -} - -func ParseSm2PublicKey(p []byte) option { - return func(so *sm2Instance) error { - pub, err := x.ReadPublicKeyFromPem(p) - if err != nil { - return err - } - - so.puk = pub - return nil - } -} - -func WithMode(mode int) option { - return func(so *sm2Instance) error { - so.mode = mode - return nil - } -} - func (o *sm2Instance) Encrypt(msg []byte) ([]byte, error) { return s.Encrypt(o.puk, msg, rand.Reader, o.mode) } diff --git a/crypto/sm2_test.go b/crypto/sm2/sm2_test.go similarity index 76% rename from crypto/sm2_test.go rename to crypto/sm2/sm2_test.go index 4dbd0ac..5f0656d 100644 --- a/crypto/sm2_test.go +++ b/crypto/sm2/sm2_test.go @@ -1,20 +1,34 @@ -package crypto_test +package sm2 import ( + "crypto/rand" "crypto/x509" "encoding/hex" "encoding/pem" "fmt" "testing" - "github.com/charlienet/go-mixed/crypto" + "github.com/tjfoc/gmsm/sm2" + x "github.com/tjfoc/gmsm/x509" ) +func TestPem(t *testing.T) { + + key, _ := sm2.GenerateKey(rand.Reader) + + prv, _ := x.WritePrivateKeyToPem(key, []byte{}) + pub, _ := x.WritePublicKeyToPem(key.Public().(*sm2.PublicKey)) + + t.Log(x.WritePublicKeyToHex(&key.PublicKey)) + t.Log(string(prv)) + t.Log(string(pub)) +} + func TestNewSm2(t *testing.T) { - o, err := crypto.NewSm2() + o, err := New() t.Logf("%+v, %v", o, err) - t.Log(crypto.NewSm2(crypto.ParseSm2PrivateKey([]byte{}, []byte{}))) + t.Log(New(WithSm2PrivateKey([]byte{}, []byte{}))) msg := []byte("123456") sign, err := o.Sign(msg) @@ -49,9 +63,9 @@ hslcifiQY8173nHtaB3R6T0PwRQTwKbpdec0dwVCpvVcdzHtivndlG0mqQ== ) func TestPrivatePem(t *testing.T) { - signer, err := crypto.NewSm2( - crypto.ParseSm2PrivateKey([]byte(privPem), []byte{}), - crypto.ParseSm2PublicKey([]byte(pubPem))) + signer, err := New( + WithSm2PrivateKey([]byte(privPem), []byte{}), + WithSm2PublicKey([]byte(pubPem))) t.Log(signer, err) if err != nil { @@ -67,9 +81,9 @@ func TestPrivatePem(t *testing.T) { } func TestBadPublicPem(t *testing.T) { - signer, err := crypto.NewSm2( - crypto.ParseSm2PrivateKey([]byte(privPem), []byte{}), - crypto.ParseSm2PublicKey([]byte(badPubPem))) + signer, err := New( + WithSm2PrivateKey([]byte(privPem), []byte{}), + WithSm2PublicKey([]byte(badPubPem))) t.Log(signer, err) diff --git a/encode/encode.go b/encode/encode.go new file mode 100644 index 0000000..2a8d09a --- /dev/null +++ b/encode/encode.go @@ -0,0 +1,19 @@ +package encode + +import "encoding/hex" + +type BytesResult []byte + +func FromString(s string) BytesResult { + return BytesResult([]byte(s)) +} + +func FromHexString(s string) BytesResult { + b, _ := hex.DecodeString(s) + return BytesResult(b) +} + +func FromBytes(b []byte) BytesResult { + return BytesResult(b) +} + diff --git a/errors/error.go b/errors/error.go index e365d31..4dad400 100644 --- a/errors/error.go +++ b/errors/error.go @@ -12,6 +12,17 @@ const ( defaultErrorCode = "999999" ) +type Error interface { + Wraped() []error + Code() string + + error + + private() +} + +var _ Error = &CodeError{} + type CodeError struct { cause error // 原始错误信息 code string // 错误码 @@ -70,6 +81,10 @@ func (e *CodeError) WithCause(err error) *CodeError { return new(err, e.code, e.message) } +func (e *CodeError) Wraped() []error { + return []error{} +} + func (e *CodeError) Format(s fmt.State, verb rune) { switch verb { case 'v': @@ -86,6 +101,8 @@ func (e *CodeError) Format(s fmt.State, verb rune) { } } +func (*CodeError) private() {} + func new(err error, code string, args ...any) *CodeError { return &CodeError{ code: code, @@ -102,7 +119,7 @@ func newf(err error, code string, format string, args ...any) *CodeError { } } -func Error(code string, args ...any) *CodeError { +func ErrorWithCode(code string, args ...any) *CodeError { return new(nil, code, args...) } diff --git a/errors/error_test.go b/errors/error_test.go index 410bd3c..adacaca 100644 --- a/errors/error_test.go +++ b/errors/error_test.go @@ -16,8 +16,8 @@ const ( ) var ( - globalError = errors.Error(defaultErrorCode, "全局错误对象") - errorbyCode = errors.Error(testCode, "全局错误对象") + globalError = errors.ErrorWithCode(defaultErrorCode, "全局错误对象") + errorbyCode = errors.ErrorWithCode(testCode, "全局错误对象") ) func TestPersetError(t *testing.T) { @@ -40,7 +40,7 @@ func TestWithMessage(t *testing.T) { } func TestNewError(t *testing.T) { - var e error = errors.Error("123456", "测试") + var e error = errors.ErrorWithCode("123456", "测试") err := e.(*errors.CodeError) t.Log(e, err.Code()) @@ -58,17 +58,17 @@ func TestWithStack(t *testing.T) { } func TestLogMessage(t *testing.T) { - t.Logf("%+v", errors.Error("88888", "错误消息")) - t.Log(errors.Error("77777")) - t.Log(errors.Error("77777", "测试")) + t.Logf("%+v", errors.ErrorWithCode("88888", "错误消息")) + t.Log(errors.ErrorWithCode("77777")) + t.Log(errors.ErrorWithCode("77777", "测试")) } func TestIs(t *testing.T) { code1 := "000090" code2 := "000091" - e1 := errors.Error(code1) - e2 := errors.Error(code1) - e3 := errors.Error(code2) + e1 := errors.ErrorWithCode(code1) + e2 := errors.ErrorWithCode(code1) + e3 := errors.ErrorWithCode(code2) t.Log(errors.Is(e1, e2)) t.Log(errors.Is(e1, e3)) diff --git a/file_store/file_store.go b/file_store/file_store.go new file mode 100644 index 0000000..b15ce41 --- /dev/null +++ b/file_store/file_store.go @@ -0,0 +1,21 @@ +package filestore + +import ( + "errors" + "io" + "os" +) + +func New() { + f, err := os.Open("") + + _ = err + _ = f + +} + +func Store(name string, reader io.Reader) error { + + return errors.New("abc") + +} diff --git a/file_store/oss/oss.go b/file_store/oss/oss.go new file mode 100644 index 0000000..0a05db1 --- /dev/null +++ b/file_store/oss/oss.go @@ -0,0 +1,6 @@ +package oss + +// add two int +func Add(a, b int) { + +} diff --git a/file_store/readme.md b/file_store/readme.md new file mode 100644 index 0000000..cb0c8f4 --- /dev/null +++ b/file_store/readme.md @@ -0,0 +1,38 @@ +# 文件存储组件 + +1. 支持磁盘,OSS,FTP等 +2. 支持自定义存储 +3. 支持同时存储到不同的存储目标 + +创建文件存储 + +```GO + +New().WithStore(LocalDisk("D:\abc")) + + +``` + +删除文件 + +```GO + +filestore.Delete("filename") + +``` + +文件移动 + +```GO + +filestore.Move("old", "new") + +``` + +文件重命名 + +```GO + +filestore.Rename("old", "new") + +``` diff --git a/go.mod b/go.mod index 9339e30..a15f8f5 100644 --- a/go.mod +++ b/go.mod @@ -1,52 +1,61 @@ module github.com/charlienet/go-mixed -go 1.18 +go 1.21 require ( - github.com/bits-and-blooms/bitset v1.3.3 - github.com/cespare/xxhash/v2 v2.1.2 - github.com/go-playground/universal-translator v0.18.0 + github.com/bits-and-blooms/bitset v1.8.0 + github.com/cespare/xxhash/v2 v2.2.0 + github.com/go-playground/universal-translator v0.18.1 github.com/json-iterator/go v1.1.12 github.com/shopspring/decimal v1.3.1 github.com/spaolacci/murmur3 v1.1.0 github.com/tjfoc/gmsm v1.4.1 ) +require github.com/alphadose/haxmap v1.3.0 + require ( - github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect + github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect - github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect - github.com/jonboulle/clockwork v0.3.0 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.5.1 // indirect github.com/tebeka/strftime v0.1.5 // indirect - github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect - golang.org/x/text v0.3.7 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/yuin/gopher-lua v1.1.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/text v0.12.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( - github.com/alicebob/miniredis/v2 v2.23.0 - github.com/allegro/bigcache/v3 v3.0.2 - github.com/alphadose/haxmap v1.0.2 + github.com/allegro/bigcache/v3 v3.1.0 + github.com/coocood/freecache v1.2.3 + github.com/vmihailenco/go-tinylfu v0.2.2 +) + +require ( + github.com/alicebob/miniredis/v2 v2.30.5 github.com/antonfisher/nested-logrus-formatter v1.3.1 - github.com/coocood/freecache v1.2.2 - github.com/dlclark/regexp2 v1.7.0 + github.com/dlclark/regexp2 v1.10.0 github.com/go-redis/redis/v8 v8.11.5 github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f github.com/pkg/errors v0.9.1 - github.com/sirupsen/logrus v1.9.0 - github.com/stretchr/testify v1.8.0 - github.com/vmihailenco/go-tinylfu v0.2.2 - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e - golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 + github.com/sirupsen/logrus v1.9.3 + github.com/stretchr/testify v1.8.4 + github.com/vmihailenco/msgpack/v5 v5.3.5 + golang.org/x/crypto v0.12.0 + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 + golang.org/x/sync v0.3.0 + golang.org/x/sys v0.11.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) diff --git a/go.sum b/go.sum index 1cab121..7bc1634 100644 --- a/go.sum +++ b/go.sum @@ -3,27 +3,40 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.23.0 h1:+lwAJYjvvdIVg6doFHuotFjueJ/7KY10xo/vm3X3Scw= -github.com/alicebob/miniredis/v2 v2.23.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= -github.com/allegro/bigcache/v3 v3.0.2 h1:AKZCw+5eAaVyNTBmI2fgyPVJhHkdWder3O9IrprcQfI= -github.com/allegro/bigcache/v3 v3.0.2/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I= -github.com/alphadose/haxmap v1.0.2 h1:ZZwFf15DcsAz4O+SyqrpH/xeO5Plh7mNRXDM9QIcWQQ= -github.com/alphadose/haxmap v1.0.2/go.mod h1:Pq2IXbl9/ytYHfrIAd7rIVtZQ2ezdIhZfvdqOizDeWY= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.23.1 h1:jR6wZggBxwWygeXcdNyguCOCIjPsZyNUNlAkTx2fu0U= +github.com/alicebob/miniredis/v2 v2.23.1/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= +github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M= +github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= +github.com/alicebob/miniredis/v2 v2.30.5 h1:3r6kTHdKnuP4fkS8k2IrvSfxpxUTcW1SOL0wN7b7Dt0= +github.com/alicebob/miniredis/v2 v2.30.5/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= +github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk= +github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I= +github.com/alphadose/haxmap v1.2.0 h1:noGrAmCE+gNheZ4KpW+sYj9W5uMcO1UAjbAq9XBOAfM= +github.com/alphadose/haxmap v1.2.0/go.mod h1:rjHw1IAqbxm0S3U5tD16GoKsiAd8FWx5BJ2IYqXwgmM= +github.com/alphadose/haxmap v1.3.0 h1:C/2LboOnPCZP27GmmSXOcwx360st0P8N0fTJ3voefKc= +github.com/alphadose/haxmap v1.3.0/go.mod h1:rjHw1IAqbxm0S3U5tD16GoKsiAd8FWx5BJ2IYqXwgmM= github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= -github.com/bits-and-blooms/bitset v1.3.3 h1:R1XWiopGiXf66xygsiLpzLo67xEYvMkHw3w+rCOSAwg= -github.com/bits-and-blooms/bitset v1.3.3/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.4.0 h1:+YZ8ePm+He2pU3dZlIZiOeAKfrBkXi1lSrXJ/Xzgbu8= +github.com/bits-and-blooms/bitset v1.4.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8= +github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c= +github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/coocood/freecache v1.2.2 h1:UPkJCxhRujykq1jXuwxAPgDHnm6lKGrLZPnuHzgWRtE= -github.com/coocood/freecache v1.2.2/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj7rthiQ3vk= +github.com/coocood/freecache v1.2.3 h1:lcBwpZrwBZRZyLk/8EMyQVXRiFl663cCuMOrjCALeto= +github.com/coocood/freecache v1.2.3/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj7rthiQ3vk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -31,6 +44,10 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0= +github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= +github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -39,8 +56,12 @@ github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -63,6 +84,8 @@ github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uc github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 h1:0iQektZGS248WXmGIYOwRXSQhD4qn3icjMpuxwO7qlo= @@ -88,31 +111,57 @@ github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5g github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= +github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tebeka/strftime v0.1.5 h1:1NQKN1NiQgkqd/2moD6ySP/5CoZQsKa1d3ZhJ44Jpmg= github.com/tebeka/strftime v0.1.5/go.mod h1:29/OidkoWHdEKZqzyDLUyC+LmgDgdHo4WAFCDT7D/Ig= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/vmihailenco/go-tinylfu v0.2.2 h1:H1eiG6HM36iniK6+21n9LLpzx1G9R3DJa2UjUjbynsI= github.com/vmihailenco/go-tinylfu v0.2.2/go.mod h1:CutYi2Q9puTxfcolkliPq4npPuofg9N9t8JVrjzwa3Q= -github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 h1:k/gmLsJDWwWqbLCur2yWnJzwQEKRcAHXo6seXGuSwWw= -github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ= +github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE= +github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= +golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -122,24 +171,41 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -164,6 +230,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/idGenerator/id_generator.go b/idGenerator/id_generator.go new file mode 100644 index 0000000..ce7f741 --- /dev/null +++ b/idGenerator/id_generator.go @@ -0,0 +1,118 @@ +package idgenerator + +import ( + "fmt" + "math" + "time" + + _ "unsafe" +) + +// 时间段开始时间 2022-01-01 +const startTimeStamp = 1640966400 + +const ( + MachineIdBits = uint(8) //机器id所占的位数 + SequenceBits = uint(12) //序列所占的位数 + MachineIdMax = int64(-1 ^ (-1 << MachineIdBits)) //支持的最大机器id数量 + SequenceMask = uint64(-1 ^ (-1 << SequenceBits)) // + MachineIdShift = uint64(SequenceBits) //机器id左移位数 + TimestampShift = uint64(SequenceBits + MachineIdBits) //时间戳左移位数 +) + +type TimePrecision int + +const ( + Second TimePrecision = iota // 秒 + Minute // 分 + Day // 日 +) + +type Config struct { + Machine int + TimeScope TimePrecision +} + +type Generator struct { + machine uint64 + timeScope TimePrecision // 时间段精度 + timestamp uint64 // 上次生成时间 + sequence uint64 // 上次使用序列 +} + +type Id struct { + machine uint64 // 机器标识 + Scope int // 时间精度 + Timestamp uint64 // 生成时间 + Sequence uint64 // 标识序列 +} + +func New(cfg Config) *Generator { + return &Generator{ + machine: uint64(cfg.Machine), + timeScope: cfg.TimeScope, + } +} + +func (g *Generator) Next() Id { + + now := currentTimestamp() + + if g.timestamp == now && g.sequence == 0 { + fmt.Println(time.Now().Format("2006-01-02 15:04:05.000"), "下一个时间点") + for now <= g.timestamp { + // runtime.Gosched() + now = currentTimestamp() + } + } + + g.timestamp = now // 标识生成时间 + g.sequence = (g.sequence + 1) & SequenceMask // 生成下一序列,超过最大值时返回零 + + return Id{ + machine: g.machine, + Timestamp: g.timestamp, + Sequence: g.sequence, + } +} + +func (i Id) Id() uint64 { + return i.Timestamp< b + slices.SortFunc(keys, func(a, b K) int { + if a == b { + return 0 + } + + return expr.Ternary(a > b, -1, 1) }) return &sorted_map[K, V]{ diff --git a/mathx/int.go b/mathx/int.go deleted file mode 100644 index 2a81ad4..0000000 --- a/mathx/int.go +++ /dev/null @@ -1,35 +0,0 @@ -package mathx - -import ( - "github.com/charlienet/go-mixed/expr" - "golang.org/x/exp/constraints" - "unsafe" -) - -// Max returns the larger one of v1 and v2. -func Max[T constraints.Ordered](v1, v2 T) T { - return expr.Ternary(v1 > v2, v1, v2) -} - -// Min returns the smaller one of v1 and v2. -func Min[T constraints.Ordered](v1, v2 T) T { - return expr.Ternary(v1 < v2, v1, v2) -} - -func Abs1[T constraints.Signed](n T) T { - shift := 63 - switch unsafe.Sizeof(n) { - case 1: - shift = 7 - case 4: - shift = 31 - } - - y := n >> shift - return T((n ^ y) - y) -} - -func Abs(n int64) int64 { - y := n >> 63 - return (n ^ y) - y -} diff --git a/mathx/int_test.go b/mathx/int_test.go deleted file mode 100644 index c667840..0000000 --- a/mathx/int_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package mathx_test - -import ( - "github.com/charlienet/go-mixed/mathx" - "github.com/stretchr/testify/assert" - "testing" -) - -func TestMin(t *testing.T) { - assert.Equal(t, 1, mathx.Min(1, 3)) - assert.Equal(t, 2, mathx.Min(66, 2)) -} - -func TestMax(t *testing.T) { - assert.Equal(t, 3, mathx.Max(1, 3)) - assert.Equal(t, 66, mathx.Max(66, 2)) -} - -func TestAbs(t *testing.T) { - assert.Equal(t, 23, mathx.Abs1(23)) - assert.Equal(t, 23, mathx.Abs1(-23)) - assert.Equal(t, 0, mathx.Abs1(0)) - - var u int8 = -127 - var exp int8 = 127 - assert.Equal(t, exp, mathx.Abs1(u)) -} diff --git a/mathx/math.go b/mathx/math.go new file mode 100644 index 0000000..abaaf4e --- /dev/null +++ b/mathx/math.go @@ -0,0 +1,46 @@ +package mathx + +import ( + "github.com/charlienet/go-mixed/expr" + "golang.org/x/exp/constraints" +) + +type Real interface { + constraints.Integer | constraints.Float +} + +// Max returns the larger one of v1 and v2. +func Max[T Real](v1, v2 T) T { + return expr.Ternary(v1 > v2, v1, v2) +} + +// Min returns the smaller one of v1 and v2. +func Min[T Real](v1, v2 T) T { + return expr.Ternary(v1 < v2, v1, v2) +} + +func Abs[T Real](val T) T { + return expr.Ternary(val < 0, -val, val) +} + +// Neg returns the negative of value. It does not negate value. For +// negating, simply use -value instead. +func Neg[T Real](value T) T { + return expr.Ternary(value < 0, value, -value) +} + +func Clamp[T Real](value, min, max T) T { + if min > max { + return min + } + + if value < min { + return min + } + + if value > max { + return max + } + + return value +} diff --git a/mathx/math_test.go b/mathx/math_test.go new file mode 100644 index 0000000..dbe51f3 --- /dev/null +++ b/mathx/math_test.go @@ -0,0 +1,54 @@ +package mathx_test + +import ( + "testing" + + "github.com/charlienet/go-mixed/mathx" + "github.com/stretchr/testify/assert" +) + +func TestMin(t *testing.T) { + assert.Equal(t, 1, mathx.Min(1, 3)) + assert.Equal(t, 2, mathx.Min(66, 2)) +} + +func TestMax(t *testing.T) { + assert.Equal(t, 3, mathx.Max(1, 3)) + assert.Equal(t, 66, mathx.Max(66, 2)) +} + +func TestAbs(t *testing.T) { + assert.Equal(t, 23, mathx.Abs(23)) + assert.Equal(t, 23, mathx.Abs(-23)) + assert.Equal(t, 0, mathx.Abs(0)) + + var u int8 = -127 + var exp int8 = 127 + assert.Equal(t, exp, mathx.Abs(u)) + + assert.Equal(t, 1.23, mathx.Abs(-1.23)) +} + +func TestClamp(t *testing.T) { + tests := []struct{ value, min, max, want int }{ + // Min. + {-1, 0, 2, 0}, + {0, 0, 2, 0}, + // Mid. + {1, 0, 2, 1}, + {2, 0, 2, 2}, + // Max. + {2, 0, 2, 2}, + {3, 0, 2, 2}, + // Empty range. + {-1, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 0, 0, 0}, + } + for _, test := range tests { + got := mathx.Clamp(test.value, test.min, test.max) + if got != test.want { + t.Errorf("Clamp(%v, %v, %v) = %v, want %v", test.value, test.min, test.max, got, test.want) + } + } +} diff --git a/sets/set.go b/sets/set.go index f82caad..b83347c 100644 --- a/sets/set.go +++ b/sets/set.go @@ -28,6 +28,7 @@ type option struct { type setFunc func(option) func WithSync() setFunc { + return func(o option) { o.locker = &sync.RWMutex{} } diff --git a/sets/sorted_set.go b/sets/sorted_set.go index 15f5514..27c91f9 100644 --- a/sets/sorted_set.go +++ b/sets/sorted_set.go @@ -1,8 +1,10 @@ package sets import ( + "slices" + + "github.com/charlienet/go-mixed/expr" "golang.org/x/exp/constraints" - "golang.org/x/exp/slices" ) type sorted_set[T constraints.Ordered] struct { @@ -50,8 +52,12 @@ func (s *sorted_set[T]) Asc() Set[T] { func (s *sorted_set[T]) Desc() Set[T] { keys := s.sorted - slices.SortFunc(keys, func(a, b T) bool { - return a > b + slices.SortFunc(keys, func(a, b T) int { + if a == b { + return 0 + } + + return expr.Ternary(a > b, -1, 1) }) return &sorted_set[T]{ diff --git a/stringx/append.go b/stringx/append.go new file mode 100644 index 0000000..fdcb9a7 --- /dev/null +++ b/stringx/append.go @@ -0,0 +1,8 @@ +package stringx + +import "fmt" + +func Append[E any](dst []byte, e E) []byte { + toAppend := fmt.Sprintf("%v", e) + return append(dst, []byte(toAppend)...) +} diff --git a/stringx/append_test.go b/stringx/append_test.go new file mode 100644 index 0000000..7b7eba3 --- /dev/null +++ b/stringx/append_test.go @@ -0,0 +1,8 @@ +package stringx_test + +import ( + "testing" +) + +func TestAppend(t *testing.T) { +} diff --git a/stringx/mask.go b/stringx/mask.go new file mode 100644 index 0000000..f6fedc6 --- /dev/null +++ b/stringx/mask.go @@ -0,0 +1,40 @@ +package stringx + +import ( + "strings" +) + +type Place int + +const ( + Begin Place = iota + Middle + End +) + +func Mask(s string, place Place, length int, mask ...rune) string { + m := '*' + if len(mask) > 0 { + m = mask[0] + } + + n := len(s) + if length >= n { + return strings.Repeat(string(m), n) + } + + i := 0 + if place == Middle { + i = (n - length) / 2 + } else if place == End { + i = n - length + } + + end := i + length + r := []rune(s) + for ; i < end; i++ { + r[i] = m + } + + return string(r) +} diff --git a/stringx/mask_test.go b/stringx/mask_test.go new file mode 100644 index 0000000..97fff1a --- /dev/null +++ b/stringx/mask_test.go @@ -0,0 +1,28 @@ +package stringx_test + +import ( + "testing" + + "github.com/charlienet/go-mixed/stringx" + "github.com/stretchr/testify/assert" +) + +func TestMask(t *testing.T) { + cases := []struct { + origin string + place stringx.Place + length int + excepted string + }{ + {"aa", stringx.Begin, 6, "**"}, + {"18980832408", stringx.Begin, 4, "****0832408"}, + {"18980832408", stringx.End, 4, "1898083****"}, + {"18980832408", stringx.Middle, 4, "189****2408"}, + } + + a := assert.New(t) + for _, c := range cases { + t.Log(stringx.Mask(c.origin, c.place, c.length)) + a.Equal(c.excepted, stringx.Mask(c.origin, c.place, c.length)) + } +} diff --git a/tree/avl_tree.go b/tree/avl_tree.go new file mode 100644 index 0000000..e36996a --- /dev/null +++ b/tree/avl_tree.go @@ -0,0 +1,25 @@ +package tree + +type avlTree struct { +} + +func NewAVLTree() { + +} + +// 左单旋,新插入的节点在右子树的右侧 +func (t *avlTree) rotateL() { + +} + +// 右单旋,新插入的节点在左子树的左侧 +func (t *avlTree) rotateR() { + +} + +// 右左双旋,新插入的节点在右子树的左侧 +// 1. 先对subR进行一个右单旋 +// 2. 再对parent进行一个左单旋然后修改平衡因子 +func (t *avlTree) rotateRL() { + +}