forked from p93542168/wheat-cache
feat(listx): add listx structure
This commit is contained in:
parent
41ef546d95
commit
15e1bb06af
|
@ -27,12 +27,12 @@ type StringXInterface interface {
|
||||||
|
|
||||||
type ListXInterface interface {
|
type ListXInterface interface {
|
||||||
KeyBaseInterface
|
KeyBaseInterface
|
||||||
LPush([]string) UpdateLength
|
LPush(...string) UpdateLength
|
||||||
RPush([]string) UpdateLength
|
RPush(...string) UpdateLength
|
||||||
LPop(int) ([]string, UpdateLength, error)
|
LPop(int) ([]string, UpdateLength)
|
||||||
RPop(int) ([]string, UpdateLength, error)
|
RPop(int) ([]string, UpdateLength)
|
||||||
Index(int) (string, error)
|
Index(int) (string, error)
|
||||||
Insert(int, bool, []string) (UpdateLength, error)
|
Insert(int, bool, ...string) (UpdateLength, error)
|
||||||
Length() int
|
Length() int
|
||||||
Slice(start, end int) (UpdateLength, error) // 切片, O(n)复杂度
|
Slice(start, end int) (UpdateLength, error) // 切片, O(n)复杂度
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package listx
|
package listx
|
||||||
|
|
||||||
import "gitee.com/timedb/wheatCache/pkg/structure"
|
import (
|
||||||
|
"gitee.com/timedb/wheatCache/pkg/errorx"
|
||||||
|
"gitee.com/timedb/wheatCache/pkg/structure"
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1. 双向链表
|
1. 双向链表
|
||||||
|
@ -9,11 +12,103 @@ import "gitee.com/timedb/wheatCache/pkg/structure"
|
||||||
4. 支持切片
|
4. 支持切片
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
type ListxNode struct {
|
||||||
|
next *ListxNode
|
||||||
|
pre *ListxNode
|
||||||
|
val *structure.Value
|
||||||
|
}
|
||||||
|
|
||||||
type Listx struct {
|
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 {
|
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 实现
|
// RollBack TODO 事务相关, V2 实现
|
||||||
|
@ -35,34 +130,206 @@ func (l *Listx) Encode() ([]byte, error) {
|
||||||
panic("not implemented") // TODO: Implement
|
panic("not implemented") // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listx) LPush(_ []string) structure.UpdateLength {
|
func (l *Listx) LPush(valueStr ...string) structure.UpdateLength {
|
||||||
panic("not implemented") // TODO: Implement
|
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 {
|
func (l *Listx) RPush(valueStr ...string) structure.UpdateLength {
|
||||||
panic("not implemented") // TODO: Implement
|
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) {
|
func (l *Listx) LPop(count int) ([]string, structure.UpdateLength) {
|
||||||
panic("not implemented") // TODO: Implement
|
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) {
|
func (l *Listx) RPop(count int) ([]string, structure.UpdateLength) {
|
||||||
panic("not implemented") // TODO: Implement
|
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) {
|
func (l *Listx) Index(index int) (string, error) {
|
||||||
panic("not implemented") // TODO: Implement
|
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) {
|
// Insert, right 为 true 右添加,否则左添加
|
||||||
panic("not implemented") // TODO: Implement
|
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 {
|
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) {
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,20 +17,26 @@ type Value struct {
|
||||||
onType DynamicType
|
onType DynamicType
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewValue() *Value {
|
func NewValue(val ...string) *Value {
|
||||||
return &Value{
|
|
||||||
|
stcValue := &Value{
|
||||||
val: make([]byte, defaultLen),
|
val: make([]byte, defaultLen),
|
||||||
length: 0,
|
length: 0,
|
||||||
onType: DynamicNull,
|
onType: DynamicNull,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(val) > 0 {
|
||||||
|
stcValue.InferValue(val[0])
|
||||||
|
}
|
||||||
|
return stcValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Value) GetLength() int {
|
func (v *Value) GetLength() int {
|
||||||
return len(v.val)
|
return v.length
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Value) GetSize() int {
|
func (v *Value) GetSize() int {
|
||||||
return v.length
|
return len(v.val) + 16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Value) GetDynamicType() DynamicType {
|
func (v *Value) GetDynamicType() DynamicType {
|
||||||
|
|
Loading…
Reference in New Issue