]> 127.0.0.1 Git - part/.git/commitdiff
1
authorqydysky <qydysky@foxmail.com>
Mon, 24 Jul 2023 03:43:17 +0000 (11:43 +0800)
committerqydysky <qydysky@foxmail.com>
Mon, 24 Jul 2023 03:43:17 +0000 (11:43 +0800)
component/Component.go [new file with mode: 0644]
component/Component_test.go [new file with mode: 0644]

diff --git a/component/Component.go b/component/Component.go
new file mode 100644 (file)
index 0000000..872cb05
--- /dev/null
@@ -0,0 +1,122 @@
+package part
+
+import (
+       "context"
+       "errors"
+       "sort"
+       "strings"
+       "sync"
+)
+
+var (
+       ErrWrongType = errors.New("ErrWrongType")
+)
+
+type CItem struct {
+       Key  string
+       Lock bool
+       Deal func(ctx context.Context, ptr any) error
+       l    sync.Mutex
+}
+
+func (t *CItem) deal(ctx context.Context, ptr any) error {
+       t.l.Lock()
+       defer t.l.Unlock()
+       return t.Deal(ctx, ptr)
+}
+
+func NewCI[T any](key string, lock bool, f func(ctx context.Context, ptr *T) error) *CItem {
+       return &CItem{
+               Key:  key,
+               Lock: lock,
+               Deal: func(ctx context.Context, ptr any) error {
+                       if item, ok := ptr.(*T); ok {
+                               return f(ctx, item)
+                       }
+                       return ErrWrongType
+               },
+       }
+}
+
+var (
+       ErrNotExist = errors.New("ErrNotExist")
+       ErrCItemErr = errors.New("ErrCItemErr")
+       ErrConflict = errors.New("ErrConflict")
+)
+
+type Components struct {
+       m  []*CItem
+       mm map[string]int
+       sync.RWMutex
+}
+
+func (t *Components) Put(item *CItem) error {
+       t.Lock()
+       defer t.Unlock()
+       for i := 0; i < len(t.m); i++ {
+               if t.m[i].Key == item.Key {
+                       return ErrConflict
+               }
+       }
+       t.m = append(t.m, item)
+       sort.Slice(t.m, func(i, j int) bool {
+               return t.m[i].Key < t.m[j].Key
+       })
+       if t.mm == nil {
+               t.mm = make(map[string]int)
+       }
+       for i := 0; i < len(t.m); i++ {
+               if strings.HasPrefix(item.Key, t.m[i].Key) {
+                       t.mm[t.m[i].Key] = i
+               }
+       }
+       return nil
+}
+
+func (t *Components) Del(key string) {
+       t.Lock()
+       for i := 0; i < len(t.m); i++ {
+               if strings.HasPrefix(t.m[i].Key, key) {
+                       delete(t.mm, t.m[i].Key)
+                       t.m = append(t.m[:i], t.m[i+1:]...)
+                       i -= 1
+               }
+       }
+       t.Unlock()
+}
+
+func (t *Components) Run(key string, ctx context.Context, ptr any) error {
+       t.RLock()
+       defer t.RUnlock()
+
+       if i, ok := t.mm[key]; ok {
+               for ; i < len(t.m) && strings.HasPrefix(t.m[i].Key, key); i++ {
+                       if e := t.m[i].deal(ctx, ptr); e != nil {
+                               return errors.Join(ErrCItemErr, e)
+                       }
+               }
+       } else {
+               return ErrNotExist
+       }
+
+       return nil
+}
+
+func Put[T any](key string, lock bool, f func(ctx context.Context, ptr *T) error) error {
+       return Comp.Put(&CItem{
+               Key:  key,
+               Lock: lock,
+               Deal: func(ctx context.Context, ptr any) error {
+                       if item, ok := ptr.(*T); ok {
+                               return f(ctx, item)
+                       }
+                       return ErrWrongType
+               },
+       })
+}
+
+func Run[T any](key string, ctx context.Context, ptr *T) error {
+       return Comp.Run(key, ctx, ptr)
+}
+
+var Comp Components
diff --git a/component/Component_test.go b/component/Component_test.go
new file mode 100644 (file)
index 0000000..0f34c20
--- /dev/null
@@ -0,0 +1,84 @@
+package part
+
+import (
+       "context"
+       "errors"
+       "testing"
+)
+
+func Test1(t *testing.T) {
+       Put(`1`, false, func(ctx context.Context, ptr *int) error {
+               if *ptr > 1 {
+                       return nil
+               }
+               return errors.New("1")
+       })
+
+       if e := Put(`1`, false, func(ctx context.Context, ptr *int) error {
+               if *ptr > 1 {
+                       return nil
+               }
+               return errors.New("1")
+       }); e != ErrConflict {
+               t.Fatal()
+       }
+
+       Comp.Put(&CItem{
+               Key: `1.2`,
+               Deal: func(_ context.Context, ptr any) error {
+                       if sp, ok := ptr.(*int); ok && *sp >= 2 {
+                               return nil
+                       }
+                       return errors.New("1.2")
+               },
+       })
+
+       Comp.Put(&CItem{
+               Key: `1.2.1`,
+               Deal: func(_ context.Context, ptr any) error {
+                       if sp, ok := ptr.(*int); ok && *sp >= 3 {
+                               return nil
+                       }
+                       return errors.New("1.2.1")
+               },
+       })
+
+       var s = 3
+       if e := Comp.Run(`1`, context.Background(), &s); e != nil {
+               t.Fatal(e)
+       }
+
+       Comp.Del(`1.2`)
+
+       if e := Comp.Run(`1.2.1`, context.Background(), &s); e != ErrNotExist {
+               t.Fatal(e)
+       }
+
+       if e := Comp.Run(`1`, context.Background(), &s); e != nil {
+               t.Fatal(e)
+       }
+}
+
+func Benchmark2(b *testing.B) {
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               Put[int](`1`, false, func(ctx context.Context, ptr *int) error {
+                       return nil
+               })
+       }
+}
+
+func Benchmark1(b *testing.B) {
+       Put[int](`1`, false, func(ctx context.Context, ptr *int) error {
+               return nil
+       })
+       Put[int](`1.2`, false, func(ctx context.Context, ptr *int) error {
+               return nil
+       })
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               if e := Run(`1.2`, context.Background(), &i); e != nil {
+                       b.Fatal()
+               }
+       }
+}