From 2c5dc78b949e1f3c0a6a3920a3880c59d4924309 Mon Sep 17 00:00:00 2001 From: qydysky Date: Mon, 24 Jul 2023 11:43:17 +0800 Subject: [PATCH] 1 --- component/Component.go | 122 ++++++++++++++++++++++++++++++++++++ component/Component_test.go | 84 +++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 component/Component.go create mode 100644 component/Component_test.go diff --git a/component/Component.go b/component/Component.go new file mode 100644 index 0000000..872cb05 --- /dev/null +++ b/component/Component.go @@ -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 index 0000000..0f34c20 --- /dev/null +++ b/component/Component_test.go @@ -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() + } + } +} -- 2.39.2