From 09487cfb7a55afcd2b7a8e294ef35faa9e715d96 Mon Sep 17 00:00:00 2001 From: qydysky Date: Tue, 25 Jul 2023 10:32:32 +0800 Subject: [PATCH] add --- component/Component.go | 93 +++++++++++++++++++++---------------- component/Component_test.go | 75 ++++++++++++++++++++++++------ 2 files changed, 114 insertions(+), 54 deletions(-) diff --git a/component/Component.go b/component/Component.go index 872cb05..4b0a43c 100644 --- a/component/Component.go +++ b/component/Component.go @@ -4,7 +4,6 @@ import ( "context" "errors" "sort" - "strings" "sync" ) @@ -14,21 +13,12 @@ var ( 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 { +func NewCI[T any](key string, f func(ctx context.Context, ptr *T) error) *CItem { return &CItem{ - Key: key, - Lock: lock, + Key: key, Deal: func(ctx context.Context, ptr any) error { if item, ok := ptr.(*T); ok { return f(ctx, item) @@ -44,73 +34,90 @@ var ( ErrConflict = errors.New("ErrConflict") ) -type Components struct { +type components struct { + MatchF func(mkey, key string) bool + m []*CItem mm map[string]int sync.RWMutex } -func (t *Components) Put(item *CItem) error { +// strings.HasPrefix +// +// strings.HasSuffix +// +// DotMatch +func NewComp(matchf func(mkey, key string) bool) *components { + return &components{ + MatchF: matchf, + mm: make(map[string]int), + } +} + +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 - } + if _, ok := t.mm[item.Key]; ok { + return errors.Join(ErrConflict, errors.New(item.Key)) } 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 - } + t.mm[t.m[i].Key] = i } return nil } -func (t *Components) Del(key string) { +func (t *components) Del(key string) { t.Lock() for i := 0; i < len(t.m); i++ { - if strings.HasPrefix(t.m[i].Key, key) { + if t.MatchF(t.m[i].Key, key) { delete(t.mm, t.m[i].Key) t.m = append(t.m[:i], t.m[i+1:]...) i -= 1 } } + for i := 0; i < len(t.m); i++ { + t.mm[t.m[i].Key] = i + } t.Unlock() } -func (t *Components) Run(key string, ctx context.Context, ptr any) error { +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) - } + var ( + i = 0 + got = false + ) + + if mi, ok := t.mm[key]; ok { + i = mi + } + for ; i < len(t.m) && t.MatchF(t.m[i].Key, key); i++ { + got = true + if e := t.m[i].Deal(ctx, ptr); e != nil { + return errors.Join(ErrCItemErr, e) } - } else { - return ErrNotExist + } + if !got { + return errors.Join(ErrNotExist, errors.New(key)) } return nil } -func Put[T any](key string, lock bool, f func(ctx context.Context, ptr *T) error) error { +func Put[T any](key string, f func(ctx context.Context, ptr *T) error) error { return Comp.Put(&CItem{ - Key: key, - Lock: lock, + Key: key, Deal: func(ctx context.Context, ptr any) error { if item, ok := ptr.(*T); ok { return f(ctx, item) } - return ErrWrongType + return errors.Join(ErrWrongType, errors.New(key)) }, }) } @@ -119,4 +126,12 @@ func Run[T any](key string, ctx context.Context, ptr *T) error { return Comp.Run(key, ctx, ptr) } -var Comp Components +func Init(f func(mkey, key string) bool) { + Comp = NewComp(f) +} + +func DotMatch(mkey, key string) bool { + return mkey == key || (len(mkey) > len(key) && mkey[0:len(key)] == key && mkey[len(key)] == '.') +} + +var Comp *components = NewComp(DotMatch) diff --git a/component/Component_test.go b/component/Component_test.go index 0f34c20..bd61924 100644 --- a/component/Component_test.go +++ b/component/Component_test.go @@ -3,24 +3,28 @@ package part import ( "context" "errors" + "strconv" + "strings" "testing" ) func Test1(t *testing.T) { - Put(`1`, false, func(ctx context.Context, ptr *int) error { + Init(DotMatch) + + Put(`1`, 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 e := Put(`1`, func(ctx context.Context, ptr *int) error { if *ptr > 1 { return nil } return errors.New("1") - }); e != ErrConflict { - t.Fatal() + }); !errors.Is(e, ErrConflict) { + t.Fatal(e) } Comp.Put(&CItem{ @@ -50,8 +54,11 @@ func Test1(t *testing.T) { Comp.Del(`1.2`) - if e := Comp.Run(`1.2.1`, context.Background(), &s); e != ErrNotExist { - t.Fatal(e) + for i := 0; i < len(Comp.m); i++ { + t.Log(Comp.m[i]) + } + if e := Comp.Run(`1.2.1`, context.Background(), &s); e == nil { + t.Fatal() } if e := Comp.Run(`1`, context.Background(), &s); e != nil { @@ -59,26 +66,64 @@ func Test1(t *testing.T) { } } +func TestDot(t *testing.T) { + Init(DotMatch) + Put[int](`1`, func(ctx context.Context, ptr *int) error { + if *ptr == 1 { + return nil + } else { + return errors.New("1") + } + }) + Put[int](`12`, func(ctx context.Context, ptr *int) error { + return errors.New("12") + }) + Put[int](`1.2`, func(ctx context.Context, ptr *int) error { + return errors.New("1.2") + }) + i := 1 + if e := Run(`1`, context.Background(), &i); !strings.Contains(e.Error(), "1.2") { + t.Fatal(e) + } +} + +func Test3(t *testing.T) { + sumup := func(ctx context.Context, ptr *int) error { + return nil + } + if e := Put[int](`bili_danmu.Reply.wsmsg.preparing.sumup`, sumup); e != nil { + panic(e) + } else { + println("bili_danmu.Reply.wsmsg.preparing.sumup") + } + i := 1 + if e := Run(`bili_danmu.Reply.wsmsg.preparing`, context.Background(), &i); e != nil { + t.Fatal(e) + } +} + func Benchmark2(b *testing.B) { + Init(DotMatch) b.ResetTimer() for i := 0; i < b.N; i++ { - Put[int](`1`, false, func(ctx context.Context, ptr *int) error { + Put[int](strconv.Itoa(i), 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 - }) + Init(DotMatch) + for i := 0; i < 1000; i++ { + Put[int](strconv.Itoa(i), func(ctx context.Context, ptr *int) error { + return nil + }) + } + ctx := context.Background() b.ResetTimer() for i := 0; i < b.N; i++ { - if e := Run(`1.2`, context.Background(), &i); e != nil { - b.Fatal() + if e := Run(`1`, ctx, &i); e != nil { + b.Fatal(e) } } } -- 2.39.2