Pure package detail
deque
gno.land/p/moul/deque/v2
Indexed deployment identity with independently loaded latest RPC source. Functions and Render are realm-only RPC capabilities.
Indexed deployment
Identity
- Package path
- gno.land/p/moul/deque/v2
- Block
- 23336
- Deployed (UTC)
- Transaction
- +j+Z4JmJCzGf5E60GJGkrNJoSUNPAhCab1OUm/crl/A=
Latest RPC state
Source
// Package deque provides a doubly-linked deque with optional size limits,
// optimized for minimal storage updates and O(1) operations in Gno environments.
//
// This implementation uses a doubly-linked list structure that provides:
// - O(1) push back operations
// - O(1) pop front operations
// - O(1) access to first/last elements
// - No array resizing or slice shifting
// - Minimal allocations (one node per element)
// - Minimal storage updates (typically 1-2 pointer updates per operation)
// - Optional max-size eviction policy
//
// Optimized for Gno blockchain storage: each operation updates only specific nodes
// rather than entire data structures, making it ideal for storage-efficient lists
// that need simple read operations like first/last access, size checks, list
// enumeration, and iteration with minimal storage update overhead.
//
// Example usage:
//
// // Unbounded deque
// d := deque.New()
// d.PushBack("a", "b", "c")
//
// // Bounded deque with automatic eviction
// d = deque.NewBounded(3)
// d.PushBack("a", "b", "c", "d") // "a" gets evicted
//
// first := d.PopFront() // Returns "b"
// last := d.Last() // Returns "d"
//
// // Iterate forward
// iter := d.All()
// iter(func(val any) bool {
// println(val)
// return true // continue
// })
//
// // Iterate backward
// iter = d.Backward()
// iter(func(val any) bool {
// println(val)
// return true // continue
// })
package deque
// Node represents a single element in the doubly-linked list
type Node struct {
value any
prev *Node
next *Node
}
// Deque represents a doubly-linked deque with optional size limits
type Deque struct {
head *Node
tail *Node
size int
max int // 0 = unlimited
}
// New creates a new unbounded deque.
func New() *Deque {
return &Deque{
max: 0, // unlimited
}
}
// NewBounded creates a new bounded deque with the specified maximum size.
// When the deque exceeds maxSize, elements are removed from the front.
func NewBounded(maxSize int) *Deque {
if maxSize <= 0 {
maxSize = 1
}
return &Deque{
max: maxSize,
}
}
// PushBack adds one or more elements to the back of the deque.
// If the deque exceeds maxSize, elements are removed from the front.
func (d *Deque) PushBack(items ...any) {
for _, item := range items {
d.pushBackSingle(item)
}
}
// pushBackSingle adds a single element to the back
func (d *Deque) pushBackSingle(item any) {
node := &Node{value: item}
if d.tail == nil {
// First element
d.head = node
d.tail = node
} else {
// Link to existing tail
d.tail.next = node
node.prev = d.tail
d.tail = node
}
d.size++
// Handle size limit by removing from front
if d.max > 0 && d.size > d.max {
d.popFrontNode()
}
}
// PopFront removes and returns the front element.
// Returns nil if the deque is empty.
func (d *Deque) PopFront() any {
if d.head == nil {
return nil
}
value := d.head.value
d.popFrontNode()
return value
}
// popFrontNode removes the front node
func (d *Deque) popFrontNode() {
if d.head == nil {
return
}
if d.head == d.tail {
// Only one element
d.head = nil
d.tail = nil
} else {
// Move head forward
d.head = d.head.next
d.head.prev = nil
}
d.size--
}
// PopBack removes and returns the back element.
// Returns nil if the deque is empty.
func (d *Deque) PopBack() any {
if d.tail == nil {
return nil
}
value := d.tail.value
d.popBackNode()
return value
}
// popBackNode removes the back node
func (d *Deque) popBackNode() {
if d.tail == nil {
return
}
if d.head == d.tail {
// Only one element
d.head = nil
d.tail = nil
} else {
// Move tail backward
d.tail = d.tail.prev
d.tail.next = nil
}
d.size--
}
// PushFront adds one or more elements to the front of the deque.
// If bounded and size limit is exceeded, elements are removed from the back.
func (d *Deque) PushFront(items ...any) {
for _, item := range items {
d.pushFrontSingle(item)
}
}
// pushFrontSingle adds a single element to the front
func (d *Deque) pushFrontSingle(item any) {
node := &Node{value: item}
if d.head == nil {
// First element
d.head = node
d.tail = node
} else {
// Link to existing head
d.head.prev = node
node.next = d.head
d.head = node
}
d.size++
// Handle size limit by removing from back
if d.max > 0 && d.size > d.max {
d.popBackNode()
}
}
// Size returns the current number of elements
func (d *Deque) Size() int {
return d.size
}
// MaxSize returns the maximum size limit (0 = unlimited)
func (d *Deque) MaxSize() int {
return d.max
}
// IsEmpty returns true if the deque is empty
func (d *Deque) IsEmpty() bool {
return d.size == 0
}
// IsBounded returns true if the deque has a size limit
func (d *Deque) IsBounded() bool {
return d.max > 0
}
// First returns the front element without removing it.
// Returns nil if the deque is empty.
func (d *Deque) First() any {
if d.head == nil {
return nil
}
return d.head.value
}
// Last returns the back element without removing it.
// Returns nil if the deque is empty.
func (d *Deque) Last() any {
if d.tail == nil {
return nil
}
return d.tail.value
}
// Get returns the element at the specified index (0 = front).
// Returns nil if index is out of bounds.
func (d *Deque) Get(index int) any {
if index < 0 || index >= d.size {
return nil
}
node := d.head
for i := 0; i < index; i++ {
node = node.next
}
return node.value
}
// List returns all elements as a slice, ordered from front to back
func (d *Deque) List() []any {
if d.size == 0 {
return nil
}
result := make([]any, d.size)
node := d.head
for i := 0; i < d.size; i++ {
result[i] = node.value
node = node.next
}
return result
}
// Enumerate calls fn for each element with its index (0-based from front)
func (d *Deque) Enumerate(fn func(index int, value any) bool) {
node := d.head
for i := 0; i < d.size; i++ {
if fn(i, node.value) {
break
}
node = node.next
}
}
// Clear removes all elements from the deque
func (d *Deque) Clear() {
d.head = nil
d.tail = nil
d.size = 0
}
// SetMaxSize changes the maximum size limit.
// If the new limit is smaller than current size, elements are removed from front.
func (d *Deque) SetMaxSize(maxSize int) {
d.max = maxSize
if maxSize > 0 {
for d.size > maxSize {
d.popFrontNode()
}
}
}
// All returns an iterator function for forward traversal (Go 1.23+ compatible)
// Note: range-over-func syntax is not yet supported in Gno, use iter() directly
func (d *Deque) All() func(yield func(any) bool) {
return func(yield func(any) bool) {
current := d.head
for current != nil {
if !yield(current.value) {
return
}
current = current.next
}
}
}
// Backward returns an iterator function for backward traversal (Go 1.23+ compatible)
// Note: range-over-func syntax is not yet supported in Gno, use iter() directly
func (d *Deque) Backward() func(yield func(any) bool) {
return func(yield func(any) bool) {
current := d.tail
for current != nil {
if !yield(current.value) {
return
}
current = current.prev
}
}
}
The verified vm/qfuncs operation accepts realm paths only.
Pure packages expose source files but do not have Realm Render.