lck

package module
v0.0.0-...-ab2b5b3 Latest Latest
Warning

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

Go to latest
Published: Apr 16, 2026 License: MIT Imports: 3 Imported by: 4

README

go-lck

Package lck implements thread-safe locking-types, for the Go programming language.

Documention

Online documentation, which includes examples, can be found at: http://godoc.org/github.com/reiver/go-lck

GoDoc

Examples

Here is an example locking-type that can hold a bool:

import "github.com/reiver/go-lck"

//

var lockable lck.Lockable[bool]

// ...

lockable.Set(true)

// ...

value := lockable.Get()

Here is another example locking-type, where here it holds a map:

import "github.com/reiver/go-lck"

//

var lockable lck.Map[string, any]

// ...

lockable.Set("something", 5)

// ...

value, found := lockable.Get("something")

Import

To import package lck use import code like the following:

import "github.com/reiver/go-lck"

Installation

To install package lck do the following:

GOPROXY=direct go get github.com/reiver/go-lck

Author

Package lck was written by Charles Iliya Krempeaux

Documentation

Overview

Package lck implements thread-safe locking-types, for the Go programming language.

Package lck provides two generic wrappers that serialize concurrent access to a shared value: Lockable for a single value, and Map for a keyed collection of values. Both types are ready to use at their zero value; no constructor is required.

A Lockable holds one value of type T, guarded by a read/write mutex. It supports atomic read, write, exchange, and read-modify-write operations.

A Map holds a keyed collection of values, guarded by a mutex. It supports all the operations of Lockable on a per-key basis, plus bulk operations such as iteration, key enumeration, and clearing.

Both types must not be copied after first use; instead pass them by pointer.

Example usage:

var counter lck.Lockable[int]
counter.Set(0)

var inventory lck.Map[string, int]
inventory.Set("apple", 5)

See also:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Lockable

type Lockable[T comparable] struct {
	// contains filtered or unexported fields
}

Lockable wraps a single value of type T with a read/write mutex, providing thread-safe read, write, exchange, and read-modify-write operations.

The zero value is ready to use. A Lockable must not be copied after first use; instead pass it by pointer.

Example usage:

var status lck.Lockable[string]
status.Set("ready")
current := status.Get()

See also:

func (*Lockable[T]) Get

func (receiver *Lockable[T]) Get() T

Get returns the current value.

Get acquires a read lock; multiple concurrent Get calls may proceed in parallel. If the receiver is nil, Get returns the zero value of T.

Example usage:

var flag lck.Lockable[bool]
flag.Set(true)
value := flag.Get()

func (*Lockable[T]) Let

func (receiver *Lockable[T]) Let(fn func(T) T) T

Let atomically replaces the current value with fn(current) and returns the previous value.

The callback funtion fn runs while the write lock is held; fn MUST NOT call any method on the same Lockable — doing so will deadlock. Panics inside fn correctly release the lock.

If the receiver is nil, Let returns the zero value of T and does not call the function fn.

Example usage:

var counter lck.Lockable[int]
prev := counter.Let(func(v int) int {
	return v + 1
})

func (*Lockable[T]) Set

func (receiver *Lockable[T]) Set(value T)

Set stores value, replacing any previous value.

If the receiver is nil, Set does nothing.

Example usage:

var name lck.Lockable[string]
name.Set("alice")

func (*Lockable[T]) Swap

func (receiver *Lockable[T]) Swap(value T) T

Swap stores value and returns the previous value.

If the receiver is nil, Swap returns the zero value of T and does not store anything.

Example usage:

var cache lck.Lockable[string]
old := cache.Swap("new-value")

type Map

type Map[K cmp.Ordered, V any] struct {
	// contains filtered or unexported fields
}

Map is a thread-safe generic map keyed by K and holding values of type V. All operations are guarded by an internal mutex.

The zero value is ready to use. A Map must not be copied after first use; instead pass it by pointer.

Example usage:

var inventory lck.Map[string, int]
inventory.Set("apple", 5)
count, found := inventory.Get("apple")

See also:

Example (String_int)
package main

import (
	"fmt"

	"github.com/reiver/go-lck"
)

func main() {

	var store lck.Map[string, int]

	fmt.Printf("INITIAL-STORE-LEN: %d\n", store.Len())

	store.Set("once", 1)
	store.Set("twice", 2)
	store.Set("thrice", 3)
	store.Set("fource", 4)

	fmt.Printf("STORE-LEN-AFTER-SETTING: %d\n", store.Len())

	value, found := store.Get("twice")
	fmt.Printf("STORE[twice]: %d, %t\n", value, found)

	fmt.Println()
	fmt.Println("KEY-VALUES:")
	store.For(func(key string, value int) {
		fmt.Println()
		fmt.Printf("- KEY: %q\n", key)
		fmt.Printf("- VALUE: %d\n", value)
	})

	store.Unset("twice")

	fmt.Println()
	fmt.Println("KEY-VALUES:")
	store.For(func(key string, value int) {
		fmt.Println()
		fmt.Printf("- KEY: %q\n", key)
		fmt.Printf("- VALUE: %d\n", value)
	})

}
Output:
INITIAL-STORE-LEN: 0
STORE-LEN-AFTER-SETTING: 4
STORE[twice]: 2, true

KEY-VALUES:

- KEY: "fource"
- VALUE: 4

- KEY: "once"
- VALUE: 1

- KEY: "thrice"
- VALUE: 3

- KEY: "twice"
- VALUE: 2

KEY-VALUES:

- KEY: "fource"
- VALUE: 4

- KEY: "once"
- VALUE: 1

- KEY: "thrice"
- VALUE: 3

func (*Map[K, V]) Clear

func (receiver *Map[K, V]) Clear()

Clear removes every entry from the map.

The underlying hash table remains allocated, so subsequent inserts do not pay reallocation cost. If the receiver is nil, or the map has never held entries, Clear does nothing.

Example usage:

var cache lck.Map[string, int]
cache.Set("a", 1)
cache.Clear()

func (*Map[K, V]) For

func (receiver *Map[K, V]) For(fn func(K, V))

For iterates over the map, invoking the function fn once per entry in sorted key order.

For takes a snapshot of the entries while the lock is held, then releases the lock and invokes fn on each snapshot entry. Mutations made by the function fn (or by other goroutines) after the snapshot is taken are not reflected in the current iteration.

If the receiver is nil, For does nothing.

Example usage:

inventory.For(func(key string, value int) {
	fmt.Println(key, value)
})

func (*Map[K, V]) Get

func (receiver *Map[K, V]) Get(key K) (V, bool)

Get returns the value stored at key, and a flag indicating whether the key was present.

If the key is absent, or the receiver is nil, Get returns the zero value of V and false.

Example usage:

value, found := inventory.Get("apple")
if !found {
	// key is absent
}

func (*Map[K, V]) Has

func (receiver *Map[K, V]) Has(key K) bool

Has reports whether key is present in the map.

Has is equivalent to discarding the value returned by Map.Get, but it avoids copying the value, which matters when V is large.

If the receiver is nil, Has returns false.

Example usage:

if inventory.Has("apple") {
	// key is present
}

func (*Map[K, V]) Keys

func (receiver *Map[K, V]) Keys() []K

Keys returns a snapshot of every key currently in the map.

The returned slice is independent of the map — subsequent mutations do not affect it.

If the receiver is nil, Keys returns nil.

Example usage:

for _, key := range inventory.Keys() {
	// ...
}

func (*Map[K, V]) Len

func (receiver *Map[K, V]) Len() int

Len returns the number of entries currently in the map.

If the receiver is nil, Len returns 0.

Example usage:

size := inventory.Len()

func (*Map[K, V]) Let

func (receiver *Map[K, V]) Let(key K, fn func(V, bool) V) (V, bool)

Let atomically replaces the value at key with fn(current, found) and returns the previous value and presence flag.

If key was absent, fn is called with the zero value of V and found=false. Let always writes fn's return value, so after Let returns the key is present with the value fn returned.

The callback fn runs while the write lock is held; fn MUST NOT call any method on the same Map — doing so will deadlock.

If the receiver is nil, Let returns the zero value of V and false, and does not call fn.

Example usage:

prev, had := counters.Let("hits", func(v int, found bool) int {
	return v + 1
})

func (*Map[K, V]) Set

func (receiver *Map[K, V]) Set(key K, value V)

Set stores value at key, replacing any previous entry.

If the receiver is nil, Set does nothing.

Example usage:

inventory.Set("apple", 5)

func (*Map[K, V]) Swap

func (receiver *Map[K, V]) Swap(key K, value V) (V, bool)

Swap stores value at key and returns the previous value and presence flag.

If the key was absent, Swap returns the zero value of V and false, then inserts the new entry. After Swap returns the key is always present with the supplied value.

If the receiver is nil, Swap returns the zero value of V and false, and does not store anything.

Example usage:

old, found := inventory.Swap("apple", 10)

func (*Map[K, V]) Unset

func (receiver *Map[K, V]) Unset(key K) (V, bool)

Unset removes the entry at key and returns its previous value and presence flag.

If the key was absent, Unset returns the zero value of V and false. If the receiver is nil, Unset returns the zero value of V and false, and does not remove anything.

Example usage:

inventory.Unset("apple")

Another example usage:

old, found := inventory.Unset("apple")

Jump to

Keyboard shortcuts

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