github.com/hdt3213/godis@v1.2.9/datastruct/list/quicklist.go (about)

     1  package list
     2  
     3  import "container/list"
     4  
     5  // pageSize must be even
     6  const pageSize = 1024
     7  
     8  // QuickList is a linked list of page (which type is []interface{})
     9  // QuickList has better performance than LinkedList of Add, Range and memory usage
    10  type QuickList struct {
    11  	data *list.List // list of []interface{}
    12  	size int
    13  }
    14  
    15  // iterator of QuickList, move between [-1, ql.Len()]
    16  type iterator struct {
    17  	node   *list.Element
    18  	offset int
    19  	ql     *QuickList
    20  }
    21  
    22  func NewQuickList() *QuickList {
    23  	l := &QuickList{
    24  		data: list.New(),
    25  	}
    26  	return l
    27  }
    28  
    29  // Add adds value to the tail
    30  func (ql *QuickList) Add(val interface{}) {
    31  	ql.size++
    32  	if ql.data.Len() == 0 { // empty list
    33  		page := make([]interface{}, 0, pageSize)
    34  		page = append(page, val)
    35  		ql.data.PushBack(page)
    36  		return
    37  	}
    38  	// assert list.data.Back() != nil
    39  	backNode := ql.data.Back()
    40  	backPage := backNode.Value.([]interface{})
    41  	if len(backPage) == cap(backPage) { // full page, create new page
    42  		page := make([]interface{}, 0, pageSize)
    43  		page = append(page, val)
    44  		ql.data.PushBack(page)
    45  		return
    46  	}
    47  	// append into page
    48  	backPage = append(backPage, val)
    49  	backNode.Value = backPage
    50  }
    51  
    52  // find returns page and in-page-offset of given index
    53  func (ql *QuickList) find(index int) *iterator {
    54  	if ql == nil {
    55  		panic("list is nil")
    56  	}
    57  	if index < 0 || index >= ql.size {
    58  		panic("index out of bound")
    59  	}
    60  	var n *list.Element
    61  	var page []interface{}
    62  	var pageBeg int
    63  	if index < ql.size/2 {
    64  		// search from front
    65  		n = ql.data.Front()
    66  		pageBeg = 0
    67  		for {
    68  			// assert: n != nil
    69  			page = n.Value.([]interface{})
    70  			if pageBeg+len(page) > index {
    71  				break
    72  			}
    73  			pageBeg += len(page)
    74  			n = n.Next()
    75  		}
    76  	} else {
    77  		// search from back
    78  		n = ql.data.Back()
    79  		pageBeg = ql.size
    80  		for {
    81  			page = n.Value.([]interface{})
    82  			pageBeg -= len(page)
    83  			if pageBeg <= index {
    84  				break
    85  			}
    86  			n = n.Prev()
    87  		}
    88  	}
    89  	pageOffset := index - pageBeg
    90  	return &iterator{
    91  		node:   n,
    92  		offset: pageOffset,
    93  		ql:     ql,
    94  	}
    95  }
    96  
    97  func (iter *iterator) get() interface{} {
    98  	return iter.page()[iter.offset]
    99  }
   100  
   101  func (iter *iterator) page() []interface{} {
   102  	return iter.node.Value.([]interface{})
   103  }
   104  
   105  // next returns whether iter is in bound
   106  func (iter *iterator) next() bool {
   107  	page := iter.page()
   108  	if iter.offset < len(page)-1 {
   109  		iter.offset++
   110  		return true
   111  	}
   112  	// move to next page
   113  	if iter.node == iter.ql.data.Back() {
   114  		// already at last node
   115  		iter.offset = len(page)
   116  		return false
   117  	}
   118  	iter.offset = 0
   119  	iter.node = iter.node.Next()
   120  	return true
   121  }
   122  
   123  // prev returns whether iter is in bound
   124  func (iter *iterator) prev() bool {
   125  	if iter.offset > 0 {
   126  		iter.offset--
   127  		return true
   128  	}
   129  	// move to prev page
   130  	if iter.node == iter.ql.data.Front() {
   131  		// already at first page
   132  		iter.offset = -1
   133  		return false
   134  	}
   135  	iter.node = iter.node.Prev()
   136  	prevPage := iter.node.Value.([]interface{})
   137  	iter.offset = len(prevPage) - 1
   138  	return true
   139  }
   140  
   141  func (iter *iterator) atEnd() bool {
   142  	if iter.ql.data.Len() == 0 {
   143  		return true
   144  	}
   145  	if iter.node != iter.ql.data.Back() {
   146  		return false
   147  	}
   148  	page := iter.page()
   149  	return iter.offset == len(page)
   150  }
   151  
   152  func (iter *iterator) atBegin() bool {
   153  	if iter.ql.data.Len() == 0 {
   154  		return true
   155  	}
   156  	if iter.node != iter.ql.data.Front() {
   157  		return false
   158  	}
   159  	return iter.offset == -1
   160  }
   161  
   162  // Get returns value at the given index
   163  func (ql *QuickList) Get(index int) (val interface{}) {
   164  	iter := ql.find(index)
   165  	return iter.get()
   166  }
   167  
   168  func (iter *iterator) set(val interface{}) {
   169  	page := iter.page()
   170  	page[iter.offset] = val
   171  }
   172  
   173  // Set updates value at the given index, the index should between [0, list.size]
   174  func (ql *QuickList) Set(index int, val interface{}) {
   175  	iter := ql.find(index)
   176  	iter.set(val)
   177  }
   178  
   179  func (ql *QuickList) Insert(index int, val interface{}) {
   180  	if index == ql.size { // insert at
   181  		ql.Add(val)
   182  		return
   183  	}
   184  	iter := ql.find(index)
   185  	page := iter.node.Value.([]interface{})
   186  	if len(page) < pageSize {
   187  		// insert into not full page
   188  		page = append(page[:iter.offset+1], page[iter.offset:]...)
   189  		page[iter.offset] = val
   190  		iter.node.Value = page
   191  		ql.size++
   192  		return
   193  	}
   194  	// insert into a full page may cause memory copy, so we split a full page into two half pages
   195  	var nextPage []interface{}
   196  	nextPage = append(nextPage, page[pageSize/2:]...) // pageSize must be even
   197  	page = page[:pageSize/2]
   198  	if iter.offset < len(page) {
   199  		page = append(page[:iter.offset+1], page[iter.offset:]...)
   200  		page[iter.offset] = val
   201  	} else {
   202  		i := iter.offset - pageSize/2
   203  		nextPage = append(nextPage[:i+1], nextPage[i:]...)
   204  		nextPage[i] = val
   205  	}
   206  	// store current page and next page
   207  	iter.node.Value = page
   208  	ql.data.InsertAfter(nextPage, iter.node)
   209  	ql.size++
   210  }
   211  
   212  func (iter *iterator) remove() interface{} {
   213  	page := iter.page()
   214  	val := page[iter.offset]
   215  	page = append(page[:iter.offset], page[iter.offset+1:]...)
   216  	if len(page) > 0 {
   217  		// page is not empty, update iter.offset only
   218  		iter.node.Value = page
   219  		if iter.offset == len(page) {
   220  			// removed page[-1], node should move to next page
   221  			if iter.node != iter.ql.data.Back() {
   222  				iter.node = iter.node.Next()
   223  				iter.offset = 0
   224  			}
   225  			// else: assert iter.atEnd() == true
   226  		}
   227  	} else {
   228  		// page is empty, update iter.node and iter.offset
   229  		if iter.node == iter.ql.data.Back() {
   230  			// removed last element, ql is empty now
   231  			iter.ql.data.Remove(iter.node)
   232  			iter.node = nil
   233  			iter.offset = 0
   234  		} else {
   235  			nextNode := iter.node.Next()
   236  			iter.ql.data.Remove(iter.node)
   237  			iter.node = nextNode
   238  			iter.offset = 0
   239  		}
   240  	}
   241  	iter.ql.size--
   242  	return val
   243  }
   244  
   245  // Remove removes value at the given index
   246  func (ql *QuickList) Remove(index int) interface{} {
   247  	iter := ql.find(index)
   248  	return iter.remove()
   249  }
   250  
   251  // Len returns the number of elements in list
   252  func (ql *QuickList) Len() int {
   253  	return ql.size
   254  }
   255  
   256  // RemoveLast removes the last element and returns its value
   257  func (ql *QuickList) RemoveLast() interface{} {
   258  	if ql.Len() == 0 {
   259  		return nil
   260  	}
   261  	ql.size--
   262  	lastNode := ql.data.Back()
   263  	lastPage := lastNode.Value.([]interface{})
   264  	if len(lastPage) == 1 {
   265  		ql.data.Remove(lastNode)
   266  		return lastPage[0]
   267  	}
   268  	val := lastPage[len(lastPage)-1]
   269  	lastPage = lastPage[:len(lastPage)-1]
   270  	lastNode.Value = lastPage
   271  	return val
   272  }
   273  
   274  // RemoveAllByVal removes all elements with the given val
   275  func (ql *QuickList) RemoveAllByVal(expected Expected) int {
   276  	iter := ql.find(0)
   277  	removed := 0
   278  	for !iter.atEnd() {
   279  		if expected(iter.get()) {
   280  			iter.remove()
   281  			removed++
   282  		} else {
   283  			iter.next()
   284  		}
   285  	}
   286  	return removed
   287  }
   288  
   289  // RemoveByVal removes at most `count` values of the specified value in this list
   290  // scan from left to right
   291  func (ql *QuickList) RemoveByVal(expected Expected, count int) int {
   292  	if ql.size == 0 {
   293  		return 0
   294  	}
   295  	iter := ql.find(0)
   296  	removed := 0
   297  	for !iter.atEnd() {
   298  		if expected(iter.get()) {
   299  			iter.remove()
   300  			removed++
   301  			if removed == count {
   302  				break
   303  			}
   304  		} else {
   305  			iter.next()
   306  		}
   307  	}
   308  	return removed
   309  }
   310  
   311  func (ql *QuickList) ReverseRemoveByVal(expected Expected, count int) int {
   312  	if ql.size == 0 {
   313  		return 0
   314  	}
   315  	iter := ql.find(ql.size - 1)
   316  	removed := 0
   317  	for !iter.atBegin() {
   318  		if expected(iter.get()) {
   319  			iter.remove()
   320  			removed++
   321  			if removed == count {
   322  				break
   323  			}
   324  		}
   325  		iter.prev()
   326  	}
   327  	return removed
   328  }
   329  
   330  // ForEach visits each element in the list
   331  // if the consumer returns false, the loop will be break
   332  func (ql *QuickList) ForEach(consumer Consumer) {
   333  	if ql == nil {
   334  		panic("list is nil")
   335  	}
   336  	if ql.Len() == 0 {
   337  		return
   338  	}
   339  	iter := ql.find(0)
   340  	i := 0
   341  	for {
   342  		goNext := consumer(i, iter.get())
   343  		if !goNext {
   344  			break
   345  		}
   346  		i++
   347  		if !iter.next() {
   348  			break
   349  		}
   350  	}
   351  }
   352  
   353  func (ql *QuickList) Contains(expected Expected) bool {
   354  	contains := false
   355  	ql.ForEach(func(i int, actual interface{}) bool {
   356  		if expected(actual) {
   357  			contains = true
   358  			return false
   359  		}
   360  		return true
   361  	})
   362  	return contains
   363  }
   364  
   365  // Range returns elements which index within [start, stop)
   366  func (ql *QuickList) Range(start int, stop int) []interface{} {
   367  	if start < 0 || start >= ql.Len() {
   368  		panic("`start` out of range")
   369  	}
   370  	if stop < start || stop > ql.Len() {
   371  		panic("`stop` out of range")
   372  	}
   373  	sliceSize := stop - start
   374  	slice := make([]interface{}, 0, sliceSize)
   375  	iter := ql.find(start)
   376  	i := 0
   377  	for i < sliceSize {
   378  		slice = append(slice, iter.get())
   379  		iter.next()
   380  		i++
   381  	}
   382  	return slice
   383  }