]> 127.0.0.1 Git - part/.git/commitdiff
add
authorqydysky <qydysky@foxmail.com>
Sat, 12 Aug 2023 17:39:43 +0000 (01:39 +0800)
committerqydysky <qydysky@foxmail.com>
Sat, 12 Aug 2023 17:39:43 +0000 (01:39 +0800)
component/Component.go
component/Component_test.go
sync/Map.go

index a90ab63deb4cb5600de0f94c199859a6bdf1b844..a315c5f5a823f46161c5d1fdfd1c7a9c417d4f6e 100644 (file)
@@ -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()
index 0976ae4eb3468a2dfb5dc899d7d01690048d59b2..25925581a490446347189fa5c2280d12bf228495 100644 (file)
@@ -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++ {
index 1fe1bde60c291b61fc9a52b411f84b7ed25125c3..66a5baff1a55b34ea20dbdfe76f85f88a9d17610 100644 (file)
@@ -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)
 }