From: qydysky Date: Fri, 16 May 2025 17:29:31 +0000 (+0800) Subject: 1 (#55) X-Git-Tag: v0.28.20250516172937 X-Git-Url: http://127.0.0.1:8081/?a=commitdiff_plain;h=8a31d604d256679cec7db71e90cd9bead09ced53;p=part%2F.git 1 (#55) --- diff --git a/slice/SliceIndex.go b/slice/SliceIndex.go new file mode 100644 index 0000000..13c8d2f --- /dev/null +++ b/slice/SliceIndex.go @@ -0,0 +1,251 @@ +package part + +import ( + "io" + "iter" + "sync" + + perrors "github.com/qydysky/part/errors" +) + +var ErrNoSameSliceIndex = perrors.New("SliceIndex.HadModified", "ErrNoSameSliceIndex") + +type SliceIndexModified struct { + p uintptr + t uint64 +} +type SliceIndex[T comparable] struct { + l sync.RWMutex + in *SliceIndexNoLock[T] +} + +func NewSliceIndex[T comparable](source []T) *SliceIndex[T] { + return &SliceIndex[T]{ + in: NewSliceIndexNoLock(source), + } +} +func (t *SliceIndex[T]) GetModified() SliceIndexModified { + return t.in.GetModified() +} +func (t *SliceIndex[T]) HadModified(mt SliceIndexModified) (modified bool, err error) { + return t.in.HadModified(mt) +} +func (t *SliceIndex[T]) Merge(s, e int) { + t.l.Lock() + defer t.l.Unlock() + t.in.Merge(s, e) +} +func (t *SliceIndex[T]) Append(s, e int) { + t.l.Lock() + defer t.l.Unlock() + t.in.Append(s, e) +} +func (t *SliceIndex[T]) Size() (c int) { + t.l.RLock() + defer t.l.RUnlock() + return t.in.Size() +} +func (t *SliceIndex[T]) Clear() { + t.l.Lock() + defer t.l.Unlock() + t.in.Clear() +} +func (t *SliceIndex[T]) Reset() { + t.l.Lock() + defer t.l.Unlock() + t.in.Clear() +} +func (t *SliceIndex[T]) Iter() iter.Seq2[int, T] { + return func(yield func(int, T) bool) { + t.l.RLock() + defer t.l.RUnlock() + index := 0 + for i := 0; i < len(t.in.buf); i += 2 { + for z := t.in.buf[i]; z < t.in.buf[i+1]; z++ { + if !yield(index, t.in.source[z]) { + return + } + index += 1 + } + } + } +} +func (t *SliceIndex[T]) Equal(b []T) bool { + matched := 0 + for _, v := range t.Iter() { + if matched == len(b) { + return false + } + if b[matched] != v { + return false + } + matched += 1 + } + return matched != len(b)-1 +} +func (t *SliceIndex[T]) Read(p []T) (n int, err error) { + t.l.Lock() + defer t.l.Unlock() + return t.in.Read(p) +} +func (t *SliceIndex[T]) IsEmpty() bool { + t.l.RLock() + defer t.l.RUnlock() + return t.in.IsEmpty() +} +func (t *SliceIndex[T]) RemoveBack(n int) { + t.l.Lock() + defer t.l.Unlock() + t.in.RemoveBack(n) +} +func (t *SliceIndex[T]) RemoveFront(n int) { + t.l.Lock() + defer t.l.Unlock() + t.in.RemoveFront(n) +} + +type SliceIndexNoLock[T comparable] struct { + buf []int + source []T + modified SliceIndexModified +} + +func NewSliceIndexNoLock[T comparable](source []T) *SliceIndexNoLock[T] { + return &SliceIndexNoLock[T]{ + buf: []int{}, + source: source, + } +} +func (t *SliceIndexNoLock[T]) GetModified() SliceIndexModified { + return t.modified +} +func (t *SliceIndexNoLock[T]) HadModified(mt SliceIndexModified) (modified bool, err error) { + if t.modified.p != mt.p { + err = ErrNoSameSliceIndex + } + modified = t.modified.t != mt.t + return +} +func (t *SliceIndexNoLock[T]) Merge(s, e int) { + if len(t.buf) == 0 { + t.buf = append(t.buf, s, e) + t.modified.t += 1 + return + } else { + for i := 0; i < len(t.buf); i += 2 { + if e < t.buf[i] { + t.buf = append([]int{s, e}, t.buf...) + t.modified.t += 1 + return + } else if t.buf[i] <= e && e <= t.buf[i+1] { + if s < t.buf[i] { + t.buf[i] = s + t.modified.t += 1 + } + return + } else if t.buf[i] <= s && s <= t.buf[i+1] { + if t.buf[i+1] < e { + t.buf[i+1] = e + t.modified.t += 1 + } + return + } + } + t.buf = append(t.buf, s, e) + t.modified.t += 1 + return + } +} +func (t *SliceIndexNoLock[T]) Append(s, e int) { + if i := len(t.buf) - 1; i >= 0 && s == t.buf[i] { + if t.buf[i] < e { + t.buf[i] = e + t.modified.t += 1 + } + } else { + t.buf = append(t.buf, s, e) + t.modified.t += 1 + } +} +func (t *SliceIndexNoLock[T]) Size() (c int) { + for i := 0; i < len(t.buf); i += 2 { + c += t.buf[i+1] - t.buf[i] + } + return +} +func (t *SliceIndexNoLock[T]) Clear() { + t.buf = nil + t.modified.t += 1 +} +func (t *SliceIndexNoLock[T]) Reset() { + t.buf = t.buf[:0] + t.modified.t += 1 +} +func (t *SliceIndexNoLock[T]) Iter() iter.Seq2[int, T] { + return func(yield func(int, T) bool) { + index := 0 + for i := 0; i < len(t.buf); i += 2 { + for z := t.buf[i]; z < t.buf[i+1]; z++ { + if !yield(index, t.source[z]) { + return + } + index += 1 + } + } + } +} +func (t *SliceIndexNoLock[T]) Equal(b []T) bool { + matched := 0 + for _, v := range t.Iter() { + if matched == len(b) { + return false + } + if b[matched] != v { + return false + } + matched += 1 + } + return matched != len(b)-1 +} +func (t *SliceIndexNoLock[T]) Read(p []T) (n int, err error) { + if len(t.buf) == 0 { + return 0, io.EOF + } + n = copy(p, t.source[t.buf[0]:t.buf[1]]) + if t.buf[1]-t.buf[0] == n { + t.buf = t.buf[2:] + } else { + t.buf[0] += n + } + t.modified.t += 1 + return +} +func (t *SliceIndexNoLock[T]) IsEmpty() bool { + return len(t.buf) == 0 +} +func (t *SliceIndexNoLock[T]) RemoveBack(n int) { + for i := len(t.buf) - 1; n > 0 && i >= 0; i-- { + l := t.buf[i+1] - t.buf[i] + if n < l { + t.buf[i+1] = t.buf[i+1] - n + t.modified.t += 1 + } else if n >= l { + t.buf = t.buf[:len(t.buf)-2] + n -= l + t.modified.t += 1 + } + } +} +func (t *SliceIndexNoLock[T]) RemoveFront(n int) { + for i := 0; n > 0 && i < len(t.buf); i++ { + l := t.buf[i+1] - t.buf[i] + if n < l { + t.buf[i] = t.buf[i] + n + t.modified.t += 1 + } else if n >= l { + t.buf = t.buf[2:] + n -= l + t.modified.t += 1 + } + } +} diff --git a/slice/SliceIndex_test.go b/slice/SliceIndex_test.go new file mode 100644 index 0000000..87ea4ce --- /dev/null +++ b/slice/SliceIndex_test.go @@ -0,0 +1,73 @@ +package part + +import ( + "bytes" + "io" + "testing" +) + +func Test_SliceIndex(t *testing.T) { + var ( + buf = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + b = NewSliceIndex(buf) + ) + b.Append(0, 3) + if !b.Equal(buf[0:3]) { + t.Fatal() + } + if b.Equal(buf[0:2]) { + t.Fatal() + } + if b.Equal(buf[0:4]) { + t.Fatal() + } + b.Merge(0, 3) + if !b.Equal(buf[0:3]) { + t.Fatal() + } + b.Append(3, 4) + if !b.Equal(buf[0:4]) { + t.Fatal() + } + buf1 := bytes.NewBuffer(make([]byte, 10)) + io.Copy(buf1, b) + if buf1.String() == "0123" { + t.Fatal() + } +} + +func Benchmark_SI1(b *testing.B) { + var ( + buf = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + bu = NewSliceIndex(buf) + ) + bu.Append(0, 3) + b.ResetTimer() + for i := 0; i < b.N; i++ { + if !bu.Equal(buf[0:3]) { + b.Fatal() + } + } +} + +func Benchmark_SI3(b *testing.B) { + var ( + buf = []byte("abc") + bu = NewSliceIndexNoLock(buf) + ) + b.ResetTimer() + for i := 0; i < b.N; i++ { + bu.Append(0, 3) + } +} + +func Benchmark_SI2(b *testing.B) { + var ( + buf = []byte{} + ) + b.ResetTimer() + for i := 0; i < b.N; i++ { + buf = append(buf, []byte("abccc")...) + } + _ = buf +}