Skip to content

discretewater/golot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

golot/stack

Go Reference

A generic, thread-safe, and performance-oriented LIFO (Last-In-First-Out) stack implementation for Go.

Overview

golot/stack provides a robust and easy-to-use stack data structure that leverages Go's generics for full type safety. It is designed for high-concurrency environments and includes advanced features for memory and performance tuning, such as pre-allocation and automatic memory shrinking.

Features

  • Type-Safe: Built with Go generics ([T any]) to ensure compile-time type safety.
  • Thread-Safe: All operations are safe for concurrent access, protected by sync.RWMutex.
  • Zero-Value Ready: A declared var s Stack[T] is an empty, usable stack with default settings.
  • Performance-Tuned: Includes NewWithCapacity to pre-allocate memory and avoid reallocations in performance-critical paths.
  • Memory-Efficient: Features a configurable, automatic memory shrinking strategy to release unused memory after usage peaks.
  • Clean API: Offers a simple and intuitive interface (Push, Pop, Peek, Size, IsEmpty).

Installation

go get codeberg.org/WIZARDELF/golot/stack

API and Usage

Interface

The stack implements the following interface:

type IStack[T any] interface {
    Size() int
    IsEmpty() bool
    Peek() (T, error)
    Push(element T)
    Pop() (T, error)
}

Basic Usage

Creating and using a stack is straightforward.

import "codeberg.org/WIZARDELF/golot/stack"

// Create a new stack for integers
s := stack.New[int]()

// Push elements onto the stack
s.Push(10)
s.Push(20)

// Peek at the top element
top, err := s.Peek()
// top: 20, err: nil

// Pop the top element
val, err := s.Pop()
// val: 20, err: nil

fmt.Printf("Stack size: %d\n", s.Size()) // "Stack size: 1"

Zero Value

The zero value of a Stack is a valid, empty stack ready for use.

var s stack.Stack[string] // No initialization needed

s.Push("hello")
val, _ := s.Pop() // val: "hello"

fmt.Println(s.IsEmpty()) // true

Performance: Pre-allocating Capacity

If you know the approximate number of elements you'll store, you can pre-allocate memory with NewWithCapacity to improve performance by preventing reallocations.

// Create a stack with an initial capacity for 100 elements
s := stack.NewWithCapacity[MyStruct](100)

for i := 0; i < 100; i++ {
    s.Push(MyStruct{...}) // These pushes will not trigger a memory reallocation
}

Advanced Configuration: Memory Shrinking

The stack automatically shrinks its underlying storage to conserve memory. This behavior can be tuned or disabled using the WithShrinkHeuristics functional option.

// Example 1: Create a stack with a more aggressive shrink policy
// Shrink when length is below 25% of capacity, and capacity is > 32.
s1 := stack.New[int](
    stack.WithShrinkHeuristics[int](0.25, 32),
)

// Example 2: Disable automatic shrinking entirely
// This can be useful in scenarios where performance is critical and memory
// usage patterns are predictable.
s2 := stack.New[int](
    stack.WithShrinkHeuristics[int](0, 0),
)

Concurrency

All methods are thread-safe. You can safely use a single stack instance across multiple goroutines.

s := stack.New[int]()
var wg sync.WaitGroup

// Producer goroutine
wg.Add(1)
go func() {
    defer wg.Done()
    for i := 0; i < 1000; i++ {
        s.Push(i)
    }
}()

// Consumer goroutine
wg.Add(1)
go func() {
    defer wg.Done()
    for i := 0; i < 1000; i++ {
        // Note: In a real-world scenario, you'd handle the error
        // and the possibility that the stack is empty.
        s.Pop()
    }
}()

wg.Wait()
fmt.Println("Done. Stack is empty:", s.IsEmpty())

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages