feat(listx): add listx structure

This commit is contained in:
bandl 2021-10-22 15:36:25 +08:00
parent 41ef546d95
commit 15e1bb06af
3 changed files with 298 additions and 25 deletions

View File

@ -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)复杂度
}

View File

@ -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
}

View File

@ -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 {