gitee.com/h79/goutils@v1.22.10/common/queue/capacity.go (about)

     1  package queue
     2  
     3  import "time"
     4  
     5  var _ Queue = (*Capacity)(nil)
     6  
     7  // Capacity 固定长度的队列
     8  type Capacity struct {
     9  	l        []IPriority
    10  	location *time.Location
    11  	count    int
    12  }
    13  
    14  func NewCapacity(capacity int) *Capacity {
    15  	if capacity <= 0 {
    16  		capacity = minCapacity
    17  	}
    18  	if capacity > maxCapacity {
    19  		capacity = maxCapacity
    20  	}
    21  	return &Capacity{
    22  		location: time.Local,
    23  		l:        make([]IPriority, capacity),
    24  	}
    25  }
    26  
    27  func (sq *Capacity) SetLocation(l *time.Location) {
    28  	sq.location = l
    29  }
    30  
    31  func (sq *Capacity) Len() int {
    32  	return sq.count
    33  }
    34  
    35  func (sq *Capacity) Push(elem any) error {
    36  	if sq.count == len(sq.l) {
    37  		sq.resize()
    38  	}
    39  	p := NewPriorityItem(elem, WithUnixNano(sq.location))
    40  	index := sq.getInsertIndex(p.PValue(), 0, sq.count-1)
    41  	copy(sq.l[index+1:], sq.l[index:])
    42  	sq.l[index] = p
    43  	sq.count++
    44  	return nil
    45  }
    46  
    47  func (sq *Capacity) Add(elem any) error {
    48  	return sq.Push(elem)
    49  }
    50  
    51  func (sq *Capacity) Peek() any {
    52  	if sq.Empty() {
    53  		return nil
    54  	}
    55  	return sq.l[0].GValue()
    56  }
    57  
    58  // Get index -1 refers to the last.
    59  func (sq *Capacity) Get(index int) any {
    60  	if index < 0 || index >= sq.count {
    61  		return nil
    62  	}
    63  	return sq.l[index].GValue()
    64  }
    65  
    66  // Find return index -1 not found.
    67  func (sq *Capacity) Find(fn IndexFunc) (any, int) {
    68  	for i := 0; i < sq.count; i++ {
    69  		if fn(sq.l[i], i) {
    70  			return sq.l[i], i
    71  		}
    72  	}
    73  	return nil, -1
    74  }
    75  
    76  func (sq *Capacity) Foreach(fn IndexFunc) {
    77  	for i := 0; i < sq.count; i++ {
    78  		if fn(sq.l[i], i) {
    79  			return
    80  		}
    81  	}
    82  }
    83  
    84  func (sq *Capacity) Pop() any {
    85  	if sq.Empty() {
    86  		return nil
    87  	}
    88  	ret := sq.l[0]
    89  	copy(sq.l[0:], sq.l[1:])
    90  	sq.count--
    91  	if sq.count < 0 {
    92  		sq.count = 0
    93  	} else {
    94  		sq.l[sq.count] = nil
    95  	}
    96  	return ret.GValue()
    97  }
    98  
    99  func (sq *Capacity) Empty() bool {
   100  	return sq.count <= 0
   101  }
   102  
   103  func (sq *Capacity) ToList() []any {
   104  	var (
   105  		buf = make([]any, sq.count)
   106  	)
   107  	for i := 0; i < sq.count; i++ {
   108  		buf[i] = sq.Get(i)
   109  	}
   110  	return buf
   111  }
   112  
   113  func (sq *Capacity) resize() {
   114  	if sq.count >= maxCapacity {
   115  		return
   116  	}
   117  	size := sq.count << 1
   118  	if size > maxCapacity {
   119  		size = maxCapacity
   120  	}
   121  	newBuf := make([]IPriority, size)
   122  
   123  	copy(newBuf, sq.l[:sq.count])
   124  
   125  	sq.l = newBuf
   126  }
   127  
   128  func (sq *Capacity) getInsertIndex(priority int64, leftIndex, rightIndex int) (index int) {
   129  	if sq.count <= 0 {
   130  		// 如果当前优先级切片没有元素,则插入的index就是0
   131  		return 0
   132  	}
   133  
   134  	length := rightIndex - leftIndex
   135  	if sq.l[leftIndex].PValue() >= priority {
   136  		// 如果当前切片中最小的元素都超过了插入的优先级,则插入位置应该是最左边
   137  		return leftIndex
   138  	}
   139  
   140  	if sq.l[rightIndex].PValue() <= priority {
   141  		// 如果当前切片中最大的元素都没超过插入的优先级,则插入位置应该是最右边
   142  		return rightIndex + 1
   143  	}
   144  
   145  	if length == 1 && sq.l[leftIndex].PValue() < priority && sq.l[rightIndex].PValue() >= priority {
   146  		// 如果插入的优先级刚好在仅有的两个优先级之间,则中间的位置就是插入位置
   147  		return leftIndex + 1
   148  	}
   149  
   150  	middleVal := sq.l[leftIndex+length/2].PValue()
   151  
   152  	// 这里用二分法递归的方式,一直寻找正确的插入位置
   153  	if priority <= middleVal {
   154  		return sq.getInsertIndex(priority, leftIndex, leftIndex+length/2)
   155  	}
   156  	return sq.getInsertIndex(priority, leftIndex+length/2, rightIndex)
   157  }