From c548dedb4f504d151f4c19a40494889c8db14d2a Mon Sep 17 00:00:00 2001 From: qydysky Date: Sun, 13 Aug 2023 01:39:43 +0800 Subject: [PATCH] add --- component/Component.go | 150 +++++++++++------------------------- component/Component_test.go | 49 ++++++------ sync/Map.go | 8 ++ 3 files changed, 75 insertions(+), 132 deletions(-) diff --git a/component/Component.go b/component/Component.go index a90ab63..a315c5f 100644 --- a/component/Component.go +++ b/component/Component.go @@ -3,131 +3,73 @@ package part import ( "context" "errors" - "sort" - "sync" -) + "maps" + "sync/atomic" -var ( - ErrWrongType = errors.New("ErrWrongType") + psync "github.com/qydysky/part/sync" ) -type CItem struct { - Key string - Deal func(ctx context.Context, ptr any) error -} - -func NewCI[T any](key string, f func(ctx context.Context, ptr *T) error) *CItem { - return &CItem{ - Key: key, - 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") + ErrNoLink = errors.New("ErrNoLink") + ErrLinked = errors.New("ErrLinked") + ErrNoExist = errors.New("ErrNoExist") + ErrConflict = errors.New("ErrConflict") + ErrWrongType = errors.New("ErrWrongType") ) type components struct { - MatchF func(mkey, key string) bool - - withLock bool - m []*CItem - mm map[string]int - sync.RWMutex + m psync.Map + link map[string][]string + loadLink atomic.Bool } -// strings.HasPrefix -// -// strings.HasSuffix -// -// DotMatch -func NewComp(withLock bool, matchf func(mkey, key string) bool) *components { - return &components{ - MatchF: matchf, - withLock: withLock, - mm: make(map[string]int), - } +func NewComp() *components { + return &components{link: make(map[string][]string)} } -func (t *components) Put(item *CItem) error { - if t.withLock { - t.Lock() - defer t.Unlock() - } - 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 - }) - for i := 0; i < len(t.m); i++ { - t.mm[t.m[i].Key] = i +func (t *components) Put(Key string, Deal func(ctx context.Context, ptr any) error) error { + _, loaded := t.m.LoadOrStore(Key, Deal) + if loaded { + return ErrConflict } return nil } -func (t *components) Del(key string) { - if t.withLock { - t.Lock() - defer t.Unlock() - } - for i := 0; i < len(t.m); i++ { - 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 - } +func (t *components) Del(Key string) { + t.m.Delete(Key) } func (t *components) Run(key string, ctx context.Context, ptr any) error { - if t.withLock { - t.RLock() - defer t.RUnlock() + if !t.loadLink.Load() { + return ErrNoLink } - - var ( - i = 0 - got = false - ) - - if mi, ok := t.mm[key]; ok { - i = mi + links := t.link[key] + if len(links) == 0 { + return ErrNoLink } - 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) + for i := 0; i < len(links); i++ { + if deal, ok := t.m.LoadV(links[i]).(func(ctx context.Context, ptr any) error); ok { + if e := deal(ctx, ptr); e != nil { + return e + } } } + return nil +} - if !got { - return errors.Join(ErrNotExist, errors.New(key)) +func (t *components) Link(link map[string][]string) error { + if t.loadLink.CompareAndSwap(false, true) { + t.link = maps.Clone(link) } - - return nil + return ErrLinked } -func Put[T any](key string, f func(ctx context.Context, ptr *T) error) error { - return Comp.Put(&CItem{ - Key: key, - Deal: func(ctx context.Context, ptr any) error { - if item, ok := ptr.(*T); ok { - return f(ctx, item) - } - return errors.Join(ErrWrongType, errors.New(key)) - }, +func Put[T any](key string, deal func(ctx context.Context, ptr *T) error) error { + return Comp.Put(key, func(ctx context.Context, ptr any) error { + if item, ok := ptr.(*T); ok { + return deal(ctx, item) + } + return errors.Join(ErrWrongType, errors.New(key)) }) } @@ -135,12 +77,8 @@ func Run[T any](key string, ctx context.Context, ptr *T) error { return Comp.Run(key, ctx, ptr) } -func Init(withLock bool, f func(mkey, key string) bool) { - Comp = NewComp(withLock, f) -} - -func DotMatch(mkey, key string) bool { - return mkey == key || (len(mkey) > len(key) && mkey[0:len(key)] == key && mkey[len(key)] == '.') +func Link(link map[string][]string) error { + return Comp.Link(link) } -var Comp *components = NewComp(false, DotMatch) +var Comp *components = NewComp() diff --git a/component/Component_test.go b/component/Component_test.go index 0976ae4..2592558 100644 --- a/component/Component_test.go +++ b/component/Component_test.go @@ -9,8 +9,6 @@ import ( ) func Test1(t *testing.T) { - Init(false, DotMatch) - Put(`1`, func(ctx context.Context, ptr *int) error { if *ptr > 1 { return nil @@ -27,24 +25,22 @@ func Test1(t *testing.T) { t.Fatal(e) } - 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(`1.2`, 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") - }, + Comp.Put(`1.2.1`, func(_ context.Context, ptr any) error { + if sp, ok := ptr.(*int); ok && *sp >= 3 { + return nil + } + return errors.New("1.2.1") + }) + + Comp.Link(map[string][]string{ + `1`: {`1`}, }) var s = 3 @@ -54,9 +50,6 @@ func Test1(t *testing.T) { Comp.Del(`1.2`) - 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() } @@ -67,7 +60,6 @@ func Test1(t *testing.T) { } func TestDot(t *testing.T) { - Init(false, DotMatch) Put[int](`1`, func(ctx context.Context, ptr *int) error { if *ptr == 1 { return nil @@ -81,6 +73,9 @@ func TestDot(t *testing.T) { Put[int](`1.2`, func(ctx context.Context, ptr *int) error { return errors.New("1.2") }) + Link(map[string][]string{ + `1`: {`1.2`}, + }) i := 1 if e := Run(`1`, context.Background(), &i); !strings.Contains(e.Error(), "1.2") { t.Fatal(e) @@ -88,7 +83,6 @@ func TestDot(t *testing.T) { } func Test3(t *testing.T) { - Init(false, DotMatch) sumup := func(ctx context.Context, ptr *int) error { return nil } @@ -97,6 +91,9 @@ func Test3(t *testing.T) { } else { println("bili_danmu.Reply.wsmsg.preparing.sumup") } + Link(map[string][]string{ + `bili_danmu.Reply.wsmsg.preparing`: {`bili_danmu.Reply.wsmsg.preparing.sumup`}, + }) i := 1 if e := Run(`bili_danmu.Reply.wsmsg.preparing`, context.Background(), &i); e != nil { t.Fatal(e) @@ -104,8 +101,6 @@ func Test3(t *testing.T) { } func Benchmark2(b *testing.B) { - Init(false, DotMatch) - b.ResetTimer() for i := 0; i < b.N; i++ { Put[int](strconv.Itoa(i), func(ctx context.Context, ptr *int) error { return nil @@ -114,12 +109,14 @@ func Benchmark2(b *testing.B) { } func Benchmark1(b *testing.B) { - Init(false, DotMatch) for i := 0; i < 1000; i++ { Put[int](`1`, func(ctx context.Context, ptr *int) error { return nil }) } + Link(map[string][]string{ + `1`: {`1`}, + }) ctx := context.Background() b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/sync/Map.go b/sync/Map.go index 1fe1bde..66a5baf 100644 --- a/sync/Map.go +++ b/sync/Map.go @@ -16,6 +16,14 @@ func (t *Map) Store(k, v any) { t.m.Store(k, v) } +func (t *Map) LoadOrStore(k, v any) (actual any, loaded bool) { + actual, loaded = t.m.LoadOrStore(k, v) + if !loaded { + t.size.Add(1) + } + return +} + func (t *Map) Load(k any) (any, bool) { return t.m.Load(k) } -- 2.39.2