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 {
|
||||
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)复杂度
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue