From 15e1bb06afee4a3597c8978212cd4cc3a891c52c Mon Sep 17 00:00:00 2001 From: bandl <1658002533@qq.com> Date: Fri, 22 Oct 2021 15:36:25 +0800 Subject: [PATCH] feat(listx): add listx structure --- pkg/structure/interface.gen.go | 10 +- pkg/structure/listx/listx.go | 299 +++++++++++++++++++++++++++++++-- pkg/structure/value.go | 14 +- 3 files changed, 298 insertions(+), 25 deletions(-) diff --git a/pkg/structure/interface.gen.go b/pkg/structure/interface.gen.go index 112137a..f4a8d72 100644 --- a/pkg/structure/interface.gen.go +++ b/pkg/structure/interface.gen.go @@ -27,12 +27,12 @@ type StringXInterface interface { type ListXInterface interface { KeyBaseInterface - LPush([]string) UpdateLength - RPush([]string) UpdateLength - LPop(int) ([]string, UpdateLength, error) - RPop(int) ([]string, UpdateLength, error) + LPush(...string) UpdateLength + RPush(...string) UpdateLength + LPop(int) ([]string, UpdateLength) + RPop(int) ([]string, UpdateLength) Index(int) (string, error) - Insert(int, bool, []string) (UpdateLength, error) + Insert(int, bool, ...string) (UpdateLength, error) Length() int Slice(start, end int) (UpdateLength, error) // 切片, O(n)复杂度 } diff --git a/pkg/structure/listx/listx.go b/pkg/structure/listx/listx.go index 56b8577..9c45d18 100644 --- a/pkg/structure/listx/listx.go +++ b/pkg/structure/listx/listx.go @@ -1,6 +1,9 @@ package listx -import "gitee.com/timedb/wheatCache/pkg/structure" +import ( + "gitee.com/timedb/wheatCache/pkg/errorx" + "gitee.com/timedb/wheatCache/pkg/structure" +) /* 1. 双向链表 @@ -9,11 +12,103 @@ import "gitee.com/timedb/wheatCache/pkg/structure" 4. 支持切片 */ +type ListxNode struct { + next *ListxNode + pre *ListxNode + val *structure.Value +} + type Listx struct { + head *ListxNode + tail *ListxNode + length int +} + +func NewListXSingle() structure.ListXInterface { + return &Listx{ + head: nil, + tail: nil, + length: 0, + } +} + +func (l *Listx) initByValue(val string) int { + if l.head == nil && l.length == 0 { + node := &ListxNode{ + val: structure.NewValue(val), + } + l.head = node + l.tail = node + l.length = 1 + + return node.val.GetSize() + } + + return 0 +} + +// 定位到 list 的元素, 支持反向索引 +func (l *Listx) location(index int) (*ListxNode, error) { + // 正定位 + if index >= 0 { + node := l.head + for ; index != 0 && node != nil; index -= 1 { + node = node.next + } + + if node == nil { + return nil, errorx.New("index crosses the line") + } + return node, nil + } + + node := l.tail + for index = (-index) - 1; index != 0 && node != nil; { + node = node.pre + index -= 1 + } + + if node == nil { + return nil, errorx.New("index crosses the line") + } + return node, nil + +} + +// 转换为左索引,负数索引 +func (l *Listx) leftIndex(index int) (int, error) { + if index < 0 && l.length+index > 0 { + return index, nil + } + + if index >= 0 && index < l.length { + return index - l.length, nil + } + + return 0, errorx.New("the index is not valid, index:%d", index) +} + +// 转换为右索引,正数索引 +func (l *Listx) rightIndex(index int) (int, error) { + if index >= 0 && index < l.length { + return index, nil + } + + if index < 0 && l.length+index >= 0 { + return l.length + index, nil + } + + return 0, errorx.New("the index is not valid, index:%d", index) } func (l *Listx) SizeByte() int64 { - panic("not implemented") // TODO: Implement + bytes := 0 + r := l.head + for r != nil { + bytes += 16 + r.val.GetSize() + r = r.next + } + return int64(bytes) } // RollBack TODO 事务相关, V2 实现 @@ -35,34 +130,206 @@ func (l *Listx) Encode() ([]byte, error) { panic("not implemented") // TODO: Implement } -func (l *Listx) LPush(_ []string) structure.UpdateLength { - panic("not implemented") // TODO: Implement +func (l *Listx) LPush(valueStr ...string) structure.UpdateLength { + if len(valueStr) == 0 { + return 0 + } + + // 使用第一个元素尝试初始化列表 + updateLength := l.initByValue(valueStr[0]) + for i := 1; i < len(valueStr); i++ { + head := l.head + val := structure.NewValue(valueStr[i]) + node := &ListxNode{val: val} + node.next = head + head.pre = node + l.head = node + l.length += 1 + updateLength += val.GetSize() + } + return structure.UpdateLength(updateLength) } -func (l *Listx) RPush(_ []string) structure.UpdateLength { - panic("not implemented") // TODO: Implement +func (l *Listx) RPush(valueStr ...string) structure.UpdateLength { + if len(valueStr) == 0 { + return 0 + } + + updateLength := l.initByValue(valueStr[0]) + for i := 1; i < len(valueStr); i++ { + tail := l.tail + val := structure.NewValue(valueStr[i]) + node := &ListxNode{val: val} + tail.next = node + node.pre = tail + l.tail = node + l.length += 1 + updateLength += val.GetSize() + } + + return structure.UpdateLength(updateLength) } -func (l *Listx) LPop(_ int) ([]string, structure.UpdateLength, error) { - panic("not implemented") // TODO: Implement +func (l *Listx) LPop(count int) ([]string, structure.UpdateLength) { + values := make([]string, 0, count) + + head := l.head + + // 动态变化长度 + updateLength := 0 + + for nodePoint := 0; head != nil && nodePoint < count; nodePoint++ { + values = append(values, head.val.ToString()) + updateLength += head.val.GetSize() + head = head.next + l.length -= 1 + } + + if head != nil { + head.pre = nil + } else { + l.tail = nil + } + + l.head = head + + return values, structure.UpdateLength(updateLength) } -func (l *Listx) RPop(_ int) ([]string, structure.UpdateLength, error) { - panic("not implemented") // TODO: Implement +func (l *Listx) RPop(count int) ([]string, structure.UpdateLength) { + values := make([]string, 0, count) + tail := l.tail + + updateLength := 0 + + for nodePoint := 0; tail != nil && nodePoint < count; nodePoint++ { + values = append(values, tail.val.ToString()) + updateLength += tail.val.GetSize() + tail = tail.pre + l.length -= 1 + } + + if tail != nil { + tail.next = nil + } else { + l.head = nil + } + + l.tail = tail + + return values, structure.UpdateLength(updateLength) } -func (l *Listx) Index(_ int) (string, error) { - panic("not implemented") // TODO: Implement +func (l *Listx) Index(index int) (string, error) { + node, err := l.location(index) + if err != nil { + return "", nil + } + + return node.val.ToString(), nil } -func (l *Listx) Insert(_ int, _ bool, _ []string) (structure.UpdateLength, error) { - panic("not implemented") // TODO: Implement +// Insert, right 为 true 右添加,否则左添加 +func (l *Listx) Insert(index int, right bool, valueStr ...string) (structure.UpdateLength, error) { + targetNode, err := l.location(index) + if err != nil { + return 0, err + } + + updateLength := 0 + for _, valStr := range valueStr { + val := structure.NewValue(valStr) + node := &ListxNode{val: val} + + // 右插 + if right { + node.pre = targetNode + node.next = targetNode.next + + targetNode.next = node + targetNode.next.pre = node + + // 更新尾部 + if targetNode == l.tail { + l.tail = node + } + + targetNode = node + } else { + // 左插 + node.pre = targetNode.pre + targetNode.pre.next = node + + node.next = targetNode + targetNode.pre = node + + // 更新头部 + if targetNode == l.head { + l.head = node + } + targetNode = node + } + + updateLength += val.GetSize() + l.length += 1 + } + + return structure.UpdateLength(updateLength), nil } func (l *Listx) Length() int { - panic("not implemented") // TODO: Implement + return l.length } +// Slice 切片 func (l *Listx) Slice(start int, end int) (structure.UpdateLength, error) { - panic("not implemented") // TODO: Implement + + startOffset, err := l.rightIndex(start) + if err != nil { + return 0, err + } + + endRightOffset, err := l.rightIndex(end) + if err != nil && end != l.length { + return 0, errorx.New("index overstep the boundary, index: %d", end) + } + + if startOffset >= endRightOffset && endRightOffset != 0 { + return 0, errorx.New("the start index must be larger than the end index") + } + + // 计算左偏移 + var endOffset int + if end == l.length { + endOffset = 0 + } else { + endOffset, err = l.leftIndex(end) + if err != nil { + return 0, err + } + } + + updateLength := 0 + + // 右切片 + head := l.head + for nodePoint := 0; head != nil && nodePoint < startOffset; nodePoint++ { + updateLength += head.val.GetSize() + head = head.next + l.length -= 1 + } + l.head = head + head.pre = nil + + tail := l.tail + for nodePoint := 0; tail != nil && nodePoint < -endOffset; nodePoint++ { + updateLength += tail.val.GetSize() + tail = tail.pre + l.length -= 1 + } + + l.tail = tail + tail.next = nil + + return structure.UpdateLength(updateLength), nil } diff --git a/pkg/structure/value.go b/pkg/structure/value.go index be578ae..2b101b4 100644 --- a/pkg/structure/value.go +++ b/pkg/structure/value.go @@ -17,20 +17,26 @@ type Value struct { onType DynamicType } -func NewValue() *Value { - return &Value{ +func NewValue(val ...string) *Value { + + stcValue := &Value{ val: make([]byte, defaultLen), length: 0, onType: DynamicNull, } + + if len(val) > 0 { + stcValue.InferValue(val[0]) + } + return stcValue } func (v *Value) GetLength() int { - return len(v.val) + return v.length } func (v *Value) GetSize() int { - return v.length + return len(v.val) + 16 } func (v *Value) GetDynamicType() DynamicType {