1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
// Copyright 2024 Bjørn Erik Pedersen
// SPDX-License-Identifier: MIT
package slicehelpers
import "sync"
// Chunk splits the slice s into n number of chunks.
func Chunk[T any](s []T, n int) [][]T {
if len(s) == 0 {
return nil
}
var partitions [][]T
sizeDefault := len(s) / n
sizeBig := len(s) - sizeDefault*n
size := sizeDefault + 1
for i, idx := 0, 0; i < n; i++ {
if i == sizeBig {
size--
if size == 0 {
break
}
}
partitions = append(partitions, s[idx:idx+size])
idx += size
}
return partitions
}
// Partition partitions s into slices of size size.
func Partition[T any](s []T, size int) [][]T {
if len(s) == 0 {
return nil
}
if size <= 0 {
return nil
}
var partitions [][]T
for i := 0; i < len(s); i += size {
end := i + size
if end > len(s) {
end = len(s)
}
partitions = append(partitions, s[i:end])
}
return partitions
}
// stack represents a stack data structure.
type stack[T any] struct {
zero T
items []T
}
type StackConfig struct {
// ThreadSafe indicates if the stack should be thread safe.
ThreadSafe bool
}
// NewStack returns a new Stack.
func NewStack[T any](conf StackConfig) Stack[T] {
s := &stack[T]{}
if !conf.ThreadSafe {
return s
}
return &threadSafeStack[T]{stack: s}
}
// Push adds an element to the stack.
func (s *stack[T]) Push(v T) {
s.items = append(s.items, v)
}
// Peek returns the top element of the stack.
func (s *stack[T]) Peek() T {
if len(s.items) == 0 {
return s.zero
}
return s.items[len(s.items)-1]
}
// Pop removes and returns the top element of the stack.
func (s *stack[T]) Pop() T {
if len(s.items) == 0 {
return s.zero
}
v := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return v
}
// Drain removes all elements from the stack and returns them.
func (s *stack[T]) Drain() []T {
items := s.items
s.items = nil
return items
}
// Len returns the number of elements in the stack.
func (s *stack[T]) Len() int {
return len(s.items)
}
type Stack[T any] interface {
// Push adds an element to the stack.
Push(v T)
// Pop removes and returns the top element of the stack.
Pop() T
// Peek returns the top element of the stack.
Peek() T
// Drain removes all elements from the stack and returns them.
Drain() []T
// Len returns the number of elements in the stack.
Len() int
}
type threadSafeStack[T any] struct {
*stack[T]
mu sync.RWMutex
}
func (s *threadSafeStack[T]) Push(v T) {
s.mu.Lock()
s.stack.Push(v)
s.mu.Unlock()
}
func (s *threadSafeStack[T]) Pop() T {
s.mu.Lock()
v := s.stack.Pop()
s.mu.Unlock()
return v
}
func (s *threadSafeStack[T]) Peek() T {
s.mu.RLock()
v := s.stack.Peek()
s.mu.RUnlock()
return v
}
func (s *threadSafeStack[T]) Drain() []T {
s.mu.Lock()
items := s.stack.Drain()
s.mu.Unlock()
return items
}
func (s *threadSafeStack[T]) Len() int {
s.mu.RLock()
l := s.stack.Len()
s.mu.RUnlock()
return l
}
|