package listx import ( "gitee.com/timedb/wheatCache/pkg/errorx" "gitee.com/timedb/wheatCache/pkg/structure" ) /* 1. 双向链表 2. 支持头尾操作 3. 支持索引 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 { bytes := 0 r := l.head for r != nil { bytes += 16 + r.val.GetSize() r = r.next } return int64(bytes) } // RollBack TODO 事务相关, V2 实现 func (l *Listx) RollBack() error { panic("not implemented") // TODO: Implement } // Begin 事务相关, V2 实现 func (l *Listx) Begin() error { panic("not implemented") // TODO: Implement } // Comment 事务相关, V2 实现 func (l *Listx) Comment() error { panic("not implemented") // TODO: Implement } func (l *Listx) Encode() ([]byte, error) { 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(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(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(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(index int) (string, error) { node, err := l.location(index) if err != nil { return "", nil } return node.val.ToString(), nil } // 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 { return l.length } // Slice 切片 func (l *Listx) Slice(start int, end int) (structure.UpdateLength, error) { 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 } func (l *Listx) Range(start, end int) ([]string, error) { startOffset, err := l.rightIndex(start) if err != nil { return nil, err } endRightOffset, err := l.rightIndex(end) if err != nil && end != l.length { return nil, errorx.New("index overstep the boundary, index: %d", end) } if startOffset >= endRightOffset && endRightOffset != 0 { return nil, errorx.New("the start index must be larger than the end index") } head := l.head for nodePoint := 0; head != nil && nodePoint < startOffset; nodePoint++ { head = head.next } values := make([]string, 0) for i := 0; i < endRightOffset-startOffset && head != nil; i++ { values = append(values, head.val.ToString()) head = head.next } return values, nil }