github.com/fern4lvarez/piladb@v0.2.0-alpha.20180407/pkg/stack/stack.go (about) 1 // Package stack provides a basic implementation 2 // of a stack using a linked list. 3 package stack 4 5 import "sync" 6 7 // Stack implements the Stacker interface, and represents the stack 8 // data structure as a linked list, containing a pointer 9 // to the first Frame as a head, the last one as a base, 10 // and the size of the stack. 11 // It also contain a mutex to lock and unlock 12 // the access to the stack at I/O operations. 13 type Stack struct { 14 head *frame 15 tail *frame 16 size int 17 mux sync.RWMutex 18 } 19 20 // frame represents an element of the stack. It contains 21 // data, and links to the up and down frames as pointers. 22 type frame struct { 23 data interface{} 24 down *frame 25 up *frame 26 } 27 28 // NewStack returns a blank stack, where head is nil and size 29 // is 0. 30 func NewStack() *Stack { 31 return &Stack{} 32 } 33 34 // Push adds a new element on top of the stack, creating 35 // a new head holding this data and updating its head on 36 // top of the stack's head. It will update the tail 37 // only if the stack was empty. 38 func (s *Stack) Push(element interface{}) { 39 s.mux.Lock() 40 defer s.mux.Unlock() 41 42 head := &frame{ 43 data: element, 44 down: s.head, 45 up: nil, 46 } 47 48 // connect former head with new head 49 // if Stack had already an element 50 if s.size > 0 { 51 s.head.up = head 52 } 53 54 s.head = head 55 s.size++ 56 57 // tail and head are the same element 58 // when pushing a first one 59 if s.size == 1 { 60 s.tail = head 61 return 62 } 63 64 // update the tail when the pushed 65 // element is the only on top of the 66 // tail 67 if s.size == 2 { 68 s.tail.up = s.head 69 } 70 } 71 72 // Pop removes and returns the element on top of the stack, 73 // updating its head to the Frame underneath. If the stack was empty, 74 // it returns false. 75 func (s *Stack) Pop() (interface{}, bool) { 76 s.mux.Lock() 77 defer s.mux.Unlock() 78 79 if s.size == 0 { 80 return nil, false 81 } 82 83 element := s.head.data 84 s.head = s.head.down 85 s.size-- 86 87 // update the tail when it's the 88 // only element after the Pop operation 89 if s.size == 1 { 90 s.tail.up = nil 91 } 92 93 return element, true 94 } 95 96 // Base bases the stack on top of a new element, so 97 // this element becomes the bottommost element of the 98 // stack. 99 func (s *Stack) Base(element interface{}) { 100 s.mux.Lock() 101 defer s.mux.Unlock() 102 103 tail := &frame{ 104 data: element, 105 down: nil, 106 up: s.tail, 107 } 108 109 s.tail = tail 110 s.size++ 111 112 // tail and head are the same element 113 // when basing a first one 114 if s.size == 1 { 115 s.head = tail 116 return 117 } 118 119 // link the element above with new 120 // tail 121 if s.size > 1 { 122 s.tail.up.down = tail 123 } 124 } 125 126 // Sweep removes and returns the element at the bottom of the stack, 127 // turning the Frame above into the new tail. If the stack was empty, 128 // it returns false. 129 func (s *Stack) Sweep() (interface{}, bool) { 130 s.mux.Lock() 131 defer s.mux.Unlock() 132 133 if s.size == 0 { 134 return nil, false 135 } 136 137 element := s.tail.data 138 s.size-- 139 140 // head and tail are nil 141 // if Stack has no elements 142 if s.size == 0 { 143 s.head = nil 144 s.tail = nil 145 return element, true 146 } 147 148 // head becomes the tail when 149 // is the remaining element in Stack 150 if s.size == 1 { 151 s.head.down = nil 152 s.head.up = nil 153 s.tail = s.head 154 return element, true 155 } 156 157 s.tail = s.tail.up 158 s.tail.down = nil 159 return element, true 160 } 161 162 // SweepPush makes a Sweep and Push operations as an atomic 163 // one, returning the swept element and the validity of 164 // the operation. If Stack was empty, it will return false. 165 func (s *Stack) SweepPush(element interface{}) (interface{}, bool) { 166 s.mux.Lock() 167 defer s.mux.Unlock() 168 169 if s.size == 0 { 170 return nil, false 171 } 172 173 head := &frame{ 174 data: element, 175 down: s.head, 176 up: nil, 177 } 178 179 swept := s.tail.data 180 181 // head becomes tail when there is 182 // a single element in the Stack 183 if s.size == 1 { 184 head.down = nil 185 s.tail = head 186 s.head = head 187 return swept, true 188 } 189 190 // set head 191 s.head.up = head 192 s.head = head 193 194 // sweep tail 195 s.tail = s.tail.up 196 s.tail.down = nil 197 198 return swept, true 199 } 200 201 // Rotate puts the bottommost element of the Stack into the top, 202 // as an action of rotating the contents. Return false if the Stack 203 // is empty. 204 func (s *Stack) Rotate() bool { 205 s.mux.Lock() 206 defer s.mux.Unlock() 207 208 if s.size == 0 { 209 return false 210 } 211 212 if s.size == 1 { 213 return true 214 } 215 216 // build new head 217 head := s.tail 218 head.down = s.head 219 220 // set new tail 221 s.tail = s.tail.up 222 s.tail.down = nil 223 224 // set new head 225 s.head = head 226 s.head.down.up = head 227 s.head.up = nil 228 229 return true 230 } 231 232 // Size returns the number of elements that a stack contains. 233 func (s *Stack) Size() int { 234 s.mux.RLock() 235 defer s.mux.RUnlock() 236 237 return s.size 238 } 239 240 // Peek returns the element on top of the stack. 241 func (s *Stack) Peek() interface{} { 242 s.mux.RLock() 243 defer s.mux.RUnlock() 244 245 if s.head == nil { 246 return nil 247 } 248 return s.head.data 249 } 250 251 // Flush flushes the content of the stack. 252 func (s *Stack) Flush() { 253 s.mux.Lock() 254 defer s.mux.Unlock() 255 256 s.size = 0 257 s.head = nil 258 s.tail = nil 259 }