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  }