collection

package
v1.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 1, 2026 License: Apache-2.0 Imports: 1 Imported by: 0

README

Collection

Thread-safe generic data structures for Go.

Features

Queue
  • FIFO (First In First Out) data structure
  • Thread-safe operations with mutex synchronization
  • Generic type support
  • Operations: Push, Pop, Front, Back, Size, Empty, Clear
Deque
  • Double-ended queue (deque) data structure
  • Thread-safe operations with mutex synchronization
  • Generic type support
  • Insert/remove from both ends
  • Operations: PushFront, PopFront, PushBack, PopBack, Front, Back, Size, Empty, Clear

Installation

go get -u github.com/common-library/go/collection

Usage

Queue
import "github.com/common-library/go/collection"

// Create a queue for integers
var queue collection.Queue[int]

// Push elements
queue.Push(1)
queue.Push(2)
queue.Push(3)

// Check size
size := queue.Size()  // 3

// Access elements
front := queue.Front()  // 1
back := queue.Back()    // 3

// Remove element
queue.Pop()  // Removes 1

// Check if empty
if queue.Empty() {
    fmt.Println("Queue is empty")
}

// Clear all elements
queue.Clear()

Key Functions:

  • Push(data T) - Add element to the back
  • Pop() - Remove element from the front
  • Front() T - Get front element without removing
  • Back() T - Get back element without removing
  • Size() int - Get number of elements
  • Empty() bool - Check if queue is empty
  • Clear() - Remove all elements
Deque
import "github.com/common-library/go/collection"

// Create a deque for strings
var deque collection.Deque[string]

// Push to both ends
deque.PushFront("front1")
deque.PushBack("back1")
deque.PushFront("front2")
deque.PushBack("back2")

// Deque now: [front2, front1, back1, back2]

// Access elements
front := deque.Front()  // "front2"
back := deque.Back()    // "back2"

// Remove from both ends
deque.PopFront()  // Removes "front2"
deque.PopBack()   // Removes "back2"

// Check size
size := deque.Size()  // 2

// Clear all elements
deque.Clear()

Key Functions:

  • PushFront(data T) - Add element to the front
  • PopFront() - Remove element from the front
  • PushBack(data T) - Add element to the back
  • PopBack() - Remove element from the back
  • Front() T - Get front element without removing
  • Back() T - Get back element without removing
  • Size() int - Get number of elements
  • Empty() bool - Check if deque is empty
  • Clear() - Remove all elements

Key Differences

Feature Queue Deque
Insert Back only Both ends
Remove Front only Both ends
Access Front, Back Front, Back
Order FIFO Flexible (FIFO/LIFO)
Use Cases Task processing, BFS Undo/redo, sliding window

Implementation Details

Thread Safety

Both Queue and Deque are thread-safe:

  • All operations are protected by mutex locks
  • Safe for concurrent access from multiple goroutines
  • Uses github.com/common-library/go/lock package for synchronization
Generic Support

Both data structures use Go generics (Go 1.18+):

// Works with any type
var intQueue collection.Queue[int]
var strQueue collection.Queue[string]
var customQueue collection.Queue[MyStruct]

var intDeque collection.Deque[int]
var ptrDeque collection.Deque[*MyStruct]
Performance Characteristics

Queue:

  • Push: O(1) amortized
  • Pop: O(n) - requires slice reslicing
  • Front/Back: O(1)
  • Size/Empty: O(1)

Deque:

  • PushFront: O(n) - requires prepending
  • PopFront: O(n) - requires slice reslicing
  • PushBack: O(1) amortized
  • PopBack: O(1)
  • Front/Back: O(1)
  • Size/Empty: O(1)

Error Handling

Panic Prevention

Front() and Back() methods will panic if called on an empty collection:

var queue collection.Queue[int]

// Check before accessing
if !queue.Empty() {
    front := queue.Front()  // Safe
} else {
    fmt.Println("Queue is empty")
}
Safe Pop Operations

Pop operations are safe on empty collections:

var deque collection.Deque[string]

deque.Pop()  // No panic, does nothing

Examples

BFS (Breadth-First Search) with Queue
type Node struct {
    Value    int
    Children []*Node
}

func BFS(root *Node) []int {
    var queue collection.Queue[*Node]
    var result []int
    
    queue.Push(root)
    
    for !queue.Empty() {
        node := queue.Front()
        queue.Pop()
        
        result = append(result, node.Value)
        
        for _, child := range node.Children {
            queue.Push(child)
        }
    }
    
    return result
}
Sliding Window with Deque
func maxSlidingWindow(nums []int, k int) []int {
    var deque collection.Deque[int]  // Stores indices
    var result []int
    
    for i := 0; i < len(nums); i++ {
        // Remove indices outside window
        for !deque.Empty() && deque.Front() <= i-k {
            deque.PopFront()
        }
        
        // Remove smaller elements
        for !deque.Empty() && nums[deque.Back()] < nums[i] {
            deque.PopBack()
        }
        
        deque.PushBack(i)
        
        if i >= k-1 {
            result = append(result, nums[deque.Front()])
        }
    }
    
    return result
}
Task Queue
type Task struct {
    ID   int
    Name string
}

func ProcessTasks() {
    var taskQueue collection.Queue[Task]
    
    // Producer
    go func() {
        for i := 0; i < 100; i++ {
            taskQueue.Push(Task{ID: i, Name: fmt.Sprintf("Task-%d", i)})
            time.Sleep(10 * time.Millisecond)
        }
    }()
    
    // Consumer
    for {
        if !taskQueue.Empty() {
            task := taskQueue.Front()
            taskQueue.Pop()
            
            // Process task
            fmt.Printf("Processing: %s\n", task.Name)
        }
        
        time.Sleep(50 * time.Millisecond)
    }
}
Undo/Redo Stack with Deque
type Command struct {
    Action string
    Data   interface{}
}

type Editor struct {
    history collection.Deque[Command]
    current int
}

func (e *Editor) Execute(cmd Command) {
    e.history.PushBack(cmd)
    e.current = e.history.Size() - 1
}

func (e *Editor) Undo() {
    if e.current >= 0 {
        e.current--
    }
}

func (e *Editor) Redo() {
    if e.current < e.history.Size()-1 {
        e.current++
    }
}

Best Practices

  1. Check Before Access

    if !queue.Empty() {
        front := queue.Front()
    }
    
  2. Clear When Done

    defer queue.Clear()  // Clean up resources
    
  3. Use Appropriate Data Structure

    // FIFO only → Queue
    var taskQueue collection.Queue[Task]
    
    // Need both ends → Deque
    var buffer collection.Deque[byte]
    
  4. Thread Safety is Built-in

    // Safe without external locking
    go queue.Push(1)
    go queue.Push(2)
    go queue.Pop()
    
  5. Generic Type Safety

    // Type-safe at compile time
    var intQueue collection.Queue[int]
    intQueue.Push(42)      // OK
    // intQueue.Push("str") // Compile error
    

Performance Considerations

When to Use Queue
  • Sequential task processing
  • BFS algorithms
  • Producer-consumer patterns
  • Event handling
When to Use Deque
  • Sliding window algorithms
  • Undo/redo functionality
  • Need efficient insertion/deletion at both ends
  • Palindrome checking
Optimization Tips

For high-performance scenarios:

// Pre-allocate if size is known
// Note: Current implementation doesn't support capacity
// Consider implementing a custom version with pre-allocation

// Batch operations
for _, item := range items {
    queue.Push(item)
}

Dependencies

  • github.com/common-library/go/lock - Mutex synchronization

Limitations

  1. No Capacity Limit: Grows unbounded, may cause memory issues
  2. No Iterator: No built-in way to iterate over elements
  3. Pop Performance: O(n) due to slice operations (consider using circular buffer for production)
  4. No Index Access: Cannot access elements by index

Alternatives

For production use cases requiring high performance:

  • container/list - Standard library doubly linked list
  • github.com/gammazero/deque - High-performance deque
  • Custom circular buffer implementation

Further Reading

Documentation

Overview

Package collection provides thread-safe data structure implementations.

This package offers generic data structures with built-in synchronization using the common-library lock package.

Features:

  • Thread-safe Queue (FIFO) with generics
  • Thread-safe Deque (double-ended queue) with generics
  • Automatic mutex-based synchronization
  • Type-safe operations using Go generics

Example usage:

var d collection.Deque[string]
d.PushBack("hello")
back := d.Back()
d.PopBack()

Package collection provides thread-safe data structure implementations.

This package offers generic data structures with built-in synchronization using the common-library lock package.

Features:

  • Thread-safe Queue (FIFO) with generics
  • Thread-safe Deque (double-ended queue) with generics
  • Automatic mutex-based synchronization
  • Type-safe operations using Go generics

Example usage:

var q collection.Queue[int]
q.Push(1)
front := q.Front()
q.Pop()

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Deque

type Deque[T any] struct {
	// contains filtered or unexported fields
}

Deque is struct that provides deque related methods.

func (*Deque[T]) Back

func (d *Deque[T]) Back() T

Back returns the back element of the deque without removing it.

This is a thread-safe operation. The caller should ensure the deque is not empty before calling this method to avoid index out of range panics.

Returns the element at the back of the deque.

Example:

back := deque.Back()

func (*Deque[T]) Clear

func (d *Deque[T]) Clear()

Clear removes all elements from the deque.

This is a thread-safe operation. After calling Clear, the deque will be empty and Size will return 0.

Example:

deque.Clear()

func (*Deque[T]) Empty

func (d *Deque[T]) Empty() bool

Empty returns true if the deque contains no elements.

This is a thread-safe operation.

Returns true if the deque is empty, false otherwise.

Example:

if deque.Empty() {
    fmt.Println("Deque is empty")
}

func (*Deque[T]) Front

func (d *Deque[T]) Front() T

Front returns the front element of the deque without removing it.

This is a thread-safe operation. The caller should ensure the deque is not empty before calling this method to avoid index out of range panics.

Returns the element at the front of the deque.

Example:

front := deque.Front()

func (*Deque[T]) PopBack

func (d *Deque[T]) PopBack()

PopBack removes the element at the back of the deque.

This is a thread-safe operation. If the deque is empty, this method does nothing. Elements can be removed from either end of the deque.

Example:

deque.PopBack()

func (*Deque[T]) PopFront

func (d *Deque[T]) PopFront()

PopFront removes the element at the front of the deque.

This is a thread-safe operation. If the deque is empty, this method does nothing. Elements can be removed from either end of the deque.

Example:

deque.PopFront()

func (*Deque[T]) PushBack

func (d *Deque[T]) PushBack(data T)

PushBack inserts an element at the back of the deque.

This is a thread-safe operation. Elements can be added to either end of the deque.

Parameters:

  • data: the element to add to the back of the deque

Example:

deque.PushBack(42)
deque.PushBack("hello")

func (*Deque[T]) PushFront

func (d *Deque[T]) PushFront(data T)

PushFront inserts an element at the front of the deque.

This is a thread-safe operation. Elements can be added to either end of the deque.

Parameters:

  • data: the element to add to the front of the deque

Example:

deque.PushFront(42)
deque.PushFront("hello")

func (*Deque[T]) Size

func (d *Deque[T]) Size() int

Size returns the number of elements in the deque.

This is a thread-safe operation.

Returns the current size of the deque.

Example:

size := deque.Size()
fmt.Printf("Deque has %d elements\n", size)

type Queue

type Queue[T any] struct {
	// contains filtered or unexported fields
}

Queue is struct that provides queue related methods.

func (*Queue[T]) Back

func (q *Queue[T]) Back() T

Back returns the back element of the queue without removing it.

This is a thread-safe operation. The caller should ensure the queue is not empty before calling this method to avoid index out of range panics.

Returns the element at the back of the queue.

Example:

back := queue.Back()

func (*Queue[T]) Clear

func (q *Queue[T]) Clear()

Clear removes all elements from the queue.

This is a thread-safe operation. After calling Clear, the queue will be empty and Size will return 0.

Example:

queue.Clear()

func (*Queue[T]) Empty

func (q *Queue[T]) Empty() bool

Empty returns true if the queue contains no elements.

This is a thread-safe operation.

Returns true if the queue is empty, false otherwise.

Example:

if queue.Empty() {
    fmt.Println("Queue is empty")
}

func (*Queue[T]) Front

func (q *Queue[T]) Front() T

Front returns the front element of the queue without removing it.

This is a thread-safe operation. The caller should ensure the queue is not empty before calling this method to avoid index out of range panics.

Returns the element at the front of the queue.

Example:

front := queue.Front()

func (*Queue[T]) Pop

func (q *Queue[T]) Pop()

Pop removes the element at the front of the queue.

This is a thread-safe operation. If the queue is empty, this method does nothing. Elements are removed from the front, implementing FIFO (First In First Out) behavior.

Example:

queue.Pop()

func (*Queue[T]) Push

func (q *Queue[T]) Push(data T)

Push inserts an element at the back of the queue.

This is a thread-safe operation. Elements are added to the back and removed from the front, implementing FIFO (First In First Out) behavior.

Parameters:

  • data: the element to add to the queue

Example:

queue.Push(42)
queue.Push("hello")

func (*Queue[T]) Size

func (q *Queue[T]) Size() int

Size returns the number of elements in the queue.

This is a thread-safe operation.

Returns the current size of the queue.

Example:

size := queue.Size()
fmt.Printf("Queue has %d elements\n", size)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL