github.com/clubpay/ronykit/kit@v0.14.4-0.20240515065620-d0dace45cbc7/utils/linked_list.go (about)

     1  package utils
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"sync"
     7  )
     8  
     9  /*
    10     Creation Time: 2019 - Jun - 20
    11     Created by:  (ehsan)
    12     Maintainers:
    13        1.  Ehsan N. Moosa (E2)
    14     Auditor: Ehsan N. Moosa (E2)
    15  */
    16  
    17  var nodePool sync.Pool
    18  
    19  func acquireNode() *Node {
    20  	n, ok := nodePool.Get().(*Node)
    21  	if !ok {
    22  		return &Node{}
    23  	}
    24  
    25  	return n
    26  }
    27  
    28  func releaseNode(n *Node) {
    29  	*n = Node{}
    30  	nodePool.Put(n)
    31  }
    32  
    33  type Node struct {
    34  	next *Node
    35  	prev *Node
    36  	data any
    37  }
    38  
    39  func (n Node) GetData() any {
    40  	return n.data
    41  }
    42  
    43  type LinkedList struct {
    44  	lock sync.RWMutex
    45  	head *Node
    46  	tail *Node
    47  	size int32
    48  }
    49  
    50  func NewLinkedList() *LinkedList {
    51  	return &LinkedList{}
    52  }
    53  
    54  func (ll *LinkedList) Append(data any) {
    55  	ll.lock.Lock()
    56  	ll.size += 1
    57  	n := acquireNode()
    58  	n.data = data
    59  	if ll.tail == nil {
    60  		ll.tail, ll.head = n, n
    61  	} else {
    62  		o := ll.tail
    63  		ll.tail = n
    64  		ll.tail.prev = o
    65  		o.next = ll.tail
    66  	}
    67  	ll.lock.Unlock()
    68  }
    69  
    70  func (ll *LinkedList) Prepend(data any) {
    71  	ll.lock.Lock()
    72  	ll.size += 1
    73  	n := acquireNode()
    74  	n.data = data
    75  	if ll.head == nil {
    76  		ll.tail, ll.head = n, n
    77  	} else {
    78  		o := ll.head
    79  		ll.head = n
    80  		ll.head.next = o
    81  		o.prev = ll.head
    82  	}
    83  	ll.lock.Unlock()
    84  }
    85  
    86  func (ll *LinkedList) Size() int32 {
    87  	ll.lock.RLock()
    88  	n := ll.size
    89  	ll.lock.RUnlock()
    90  
    91  	return n
    92  }
    93  
    94  func (ll *LinkedList) Head() *Node {
    95  	return ll.head
    96  }
    97  
    98  func (ll *LinkedList) PickHeadData() any {
    99  	ll.lock.Lock()
   100  	if ll.head == nil {
   101  		ll.lock.Unlock()
   102  
   103  		return nil
   104  	}
   105  
   106  	n := ll.head
   107  	if ll.head.next != nil {
   108  		ll.head = ll.head.next
   109  		ll.head.prev = nil
   110  	} else {
   111  		ll.head, ll.tail = nil, nil
   112  	}
   113  	ll.size--
   114  	ll.lock.Unlock()
   115  	data := n.data
   116  	releaseNode(n)
   117  
   118  	return data
   119  }
   120  
   121  func (ll *LinkedList) Tail() *Node {
   122  	return ll.tail
   123  }
   124  
   125  func (ll *LinkedList) PickTailData() any {
   126  	ll.lock.Lock()
   127  	if ll.tail == nil {
   128  		ll.lock.Unlock()
   129  
   130  		return nil
   131  	}
   132  	n := ll.tail
   133  	if ll.tail.prev != nil {
   134  		ll.tail = ll.tail.prev
   135  		ll.tail.next = nil
   136  	} else {
   137  		ll.head, ll.tail = nil, nil
   138  	}
   139  	ll.size -= 1
   140  	ll.lock.Unlock()
   141  	data := n.data
   142  	releaseNode(n)
   143  
   144  	return data
   145  }
   146  
   147  func (ll *LinkedList) Get(index int32) (n *Node) {
   148  	ll.lock.RLock()
   149  	if index < ll.size<<1 {
   150  		n = ll.head
   151  		for index > 0 {
   152  			n = n.next
   153  			index--
   154  		}
   155  	} else {
   156  		n = ll.tail
   157  		for index > 0 {
   158  			n = n.prev
   159  			index--
   160  		}
   161  	}
   162  	ll.lock.RUnlock()
   163  
   164  	return n
   165  }
   166  
   167  func (ll *LinkedList) RemoveAt(index int32) {
   168  	n := ll.Get(index)
   169  	ll.lock.Lock()
   170  	if n.next != nil {
   171  		n.next.prev = n.prev
   172  	}
   173  	if n.prev != nil {
   174  		n.prev.next = n.next
   175  	}
   176  	ll.size--
   177  	ll.lock.Unlock()
   178  }
   179  
   180  func (ll *LinkedList) Reset() {
   181  	for ll.PickHeadData() != nil {
   182  	}
   183  }
   184  
   185  func (ll *LinkedList) String() string {
   186  	sb := strings.Builder{}
   187  	n := ll.head
   188  	idx := 0
   189  
   190  	for n != nil {
   191  		sb.WriteString(fmt.Sprintf("%d. %v\n", idx, n.data))
   192  		n = n.next
   193  		idx++
   194  	}
   195  
   196  	return sb.String()
   197  }