container

package
v0.32.5 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2025 License: Unlicense Imports: 5 Imported by: 5

Documentation

Overview

Package container provides common container types.

TODO(a.garipov): Consider adding a set interface.

TODO(a.garipov): Consider adding a intersect and union operations on sets.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func MapSetToString

func MapSetToString[T constraints.Ordered](set *MapSet[T]) (s string)

MapSetToString converts a *MapSet of values of an ordered type into a reproducible string.

func MapSetToStringFunc

func MapSetToStringFunc[T comparable](set *MapSet[T], compare func(a, b T) (res int)) (s string)

MapSetToStringFunc is like MapSetToString but uses an explicit comparison function.

Types

type KeyValue added in v0.25.3

type KeyValue[K comparable, V any] struct {
	Key   K
	Value V
}

KeyValue is a simple structure for pairs of values where one identifies the other. It is useful when multiple values need to be processed in a defined order and each value is associated with its own name or ID.

type KeyValues added in v0.25.3

type KeyValues[K comparable, V any] []KeyValue[K, V]

KeyValues is a slice of [KeyValue]s.

Example
package main

import (
	"fmt"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	type service struct{}

	var (
		serviceA = service{}
		serviceB = service{}
		serviceC = service{}
	)

	type svcName string

	validate := func(_ service) (err error) {
		return nil
	}

	// These should be validated in this order.
	services := container.KeyValues[svcName, service]{{
		Key:   "svc_a",
		Value: serviceA,
	}, {
		Key:   "svc_b",
		Value: serviceB,
	}, {
		Key:   "svc_c",
		Value: serviceC,
	}}

	for _, kv := range services {
		fmt.Printf("validating service %q: %v\n", kv.Key, validate(kv.Value))
	}

}
Output:

validating service "svc_a": <nil>
validating service "svc_b": <nil>
validating service "svc_c": <nil>

type MapSet

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

MapSet is a set that uses a map as its storage.

TODO(a.garipov): Figure out a way to add a reproducible String method.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	const x = 1
	set := container.NewMapSet[int]()

	ok := set.Has(x)
	fmt.Printf("%s contains %v is %t\n", container.MapSetToString(set), x, ok)

	set.Add(x)
	ok = set.Has(x)
	fmt.Printf("%s contains %v is %t\n", container.MapSetToString(set), x, ok)

	other := container.NewMapSet(x)
	ok = set.Equal(other)
	fmt.Printf(
		"%s is equal to %s is %t\n",
		container.MapSetToString(set),
		container.MapSetToString(other),
		ok,
	)

	set.Add(2)
	values := set.Values()
	slices.Sort(values)
	fmt.Printf("values of %s are %v\n", container.MapSetToString(set), values)

	set.Delete(x)
	ok = set.Has(x)
	fmt.Printf("%s contains %v is %t\n", container.MapSetToString(set), x, ok)

	set.Range(func(n int) (cont bool) {
		fmt.Printf("got value %d\n", n)

		return false
	})

	set = container.NewMapSet(x)
	fmt.Printf("%s has length %d\n", container.MapSetToString(set), set.Len())

	set.Clear()
	fmt.Printf("%s has length %d\n", container.MapSetToString(set), set.Len())

}
Output:


[] contains 1 is false
[1] contains 1 is true
[1] is equal to [1] is true
values of [1 2] are [1 2]
[2] contains 1 is false
got value 2
[1] has length 1
[] has length 0
Example (Nil)
package main

import (
	"fmt"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	const x = 1

	var set *container.MapSet[int]

	panicked := false
	setPanicked := func() {
		panicked = recover() != nil
	}

	func() {
		defer setPanicked()

		set.Clear()
	}()
	fmt.Printf("panic after clear: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Delete(x)
	}()
	fmt.Printf("panic after delete: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Has(x)
	}()
	fmt.Printf("panic after has: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Len()
	}()
	fmt.Printf("panic after len: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Range(func(n int) (cont bool) {
			fmt.Printf("got value %d\n", n)

			return true
		})
	}()
	fmt.Printf("panic after range: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Values()
	}()
	fmt.Printf("panic after values: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Add(x)
	}()
	fmt.Printf("panic after add: %t\n", panicked)

}
Output:


panic after clear: false
panic after delete: false
panic after has: false
panic after len: false
panic after range: false
panic after values: false
panic after add: true

func NewMapSet

func NewMapSet[T comparable](values ...T) (set *MapSet[T])

NewMapSet returns a new map set containing values.

func (*MapSet[T]) Add

func (set *MapSet[T]) Add(v T)

Add adds v to set.

func (*MapSet[T]) Clear

func (set *MapSet[T]) Clear()

Clear clears set in a way that retains the internal storage for later reuse to reduce allocations. Calling Clear on a nil set has no effect, just like a clear on a nil map doesn't.

func (*MapSet[T]) Clone

func (set *MapSet[T]) Clone() (clone *MapSet[T])

Clone returns a deep clone of set. If set is nil, clone is nil.

Example
package main

import (
	"fmt"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	var set *container.MapSet[int]
	fmt.Printf("nil:   %#v\n", set.Clone())

	const x, y = 1, 2
	set = container.NewMapSet(x)
	clone := set.Clone()
	clone.Add(y)

	fmt.Printf("orig:  %t %t\n", set.Has(x), set.Has(y))
	fmt.Printf("clone: %t %t\n", clone.Has(x), clone.Has(y))

}
Output:

nil:   (*container.MapSet[int])(nil)
orig:  true false
clone: true true

func (*MapSet[T]) Delete

func (set *MapSet[T]) Delete(v T)

Delete deletes v from set. Calling Delete on a nil set has no effect, just like delete on a nil map doesn't.

func (*MapSet[T]) Equal

func (set *MapSet[T]) Equal(other *MapSet[T]) (ok bool)

Equal returns true if set is equal to other. set and other may be nil; Equal returns true if both are nil, but a nil *MapSet is not equal to a non-nil empty one.

Example
package main

import (
	"fmt"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	const x, y = 1, 2
	set := container.NewMapSet(x)

	fmt.Printf("same:       %t\n", set.Equal(container.NewMapSet(x)))
	fmt.Printf("other elem: %t\n", set.Equal(container.NewMapSet(y)))
	fmt.Printf("other len:  %t\n", set.Equal(container.NewMapSet(x, y)))
	fmt.Printf("nil:        %t\n", set.Equal(nil))
	fmt.Printf("nil eq nil: %t\n", (*container.MapSet[int])(nil).Equal(nil))

}
Output:

same:       true
other elem: false
other len:  false
nil:        false
nil eq nil: true

func (*MapSet[T]) Has

func (set *MapSet[T]) Has(v T) (ok bool)

Has returns true if v is in set. Calling Has on a nil set returns false, just like indexing on an empty map does.

func (*MapSet[T]) Len

func (set *MapSet[T]) Len() (n int)

Len returns the length of set. A nil set has a length of zero, just like an empty map.

func (*MapSet[T]) Range

func (set *MapSet[T]) Range(f func(v T) (cont bool))

Range calls f with each value of set in an undefined order. If cont is false, Range stops the iteration. Calling Range on a nil *MapSet has no effect.

func (*MapSet[T]) Values

func (set *MapSet[T]) Values() (values []T)

Values returns all values in set. The order of the values is undefined. Values returns nil if set is nil.

type RingBuffer added in v0.25.2

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

RingBuffer is the generic implementation of ring buffer data structure.

func NewRingBuffer added in v0.25.2

func NewRingBuffer[T any](size uint) (rb *RingBuffer[T])

NewRingBuffer initializes a new ring buffer with the given size.

func (*RingBuffer[T]) Clear added in v0.25.2

func (rb *RingBuffer[T]) Clear()

Clear clears the buffer.

func (*RingBuffer[T]) Current added in v0.25.2

func (rb *RingBuffer[T]) Current() (e T)

Current returns the element at the current position. It returns zero value of T if rb is nil or empty.

Example
package main

import (
	"fmt"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	const size, x, y, z = 2, 1, 2, 3

	var rb *container.RingBuffer[int]
	fmt.Printf("nil: %#v\n", rb.Current())

	rb = container.NewRingBuffer[int](size)
	fmt.Printf("empty: %#v\n", rb.Current())

	rb.Push(x)
	fmt.Printf("push %d: %#v\n", x, rb.Current())

	rb.Push(y)
	fmt.Printf("push %d: %#v\n", y, rb.Current())

	rb.Push(z)
	fmt.Printf("push %d: %#v\n", z, rb.Current())
	fmt.Printf("current: %#v\n", rb.Current())

}
Output:

nil: 0
empty: 0
push 1: 0
push 2: 1
push 3: 2
current: 2

func (*RingBuffer[T]) Len added in v0.25.2

func (rb *RingBuffer[T]) Len() (l uint)

Len returns a length of the buffer.

func (*RingBuffer[T]) Push added in v0.25.2

func (rb *RingBuffer[T]) Push(e T)

Push adds an element to the buffer and sets the current position to the next element.

func (*RingBuffer[T]) Range added in v0.25.2

func (rb *RingBuffer[T]) Range(f func(T) (cont bool))

Range calls f for each element of the buffer starting from the current position until f returns false.

func (*RingBuffer[T]) ReverseRange added in v0.25.2

func (rb *RingBuffer[T]) ReverseRange(f func(T) (cont bool))

ReverseRange calls f for each element of the buffer in reverse order ending with the current position until f returns false.

type SortedSliceSet added in v0.30.1

type SortedSliceSet[T cmp.Ordered] struct {
	// contains filtered or unexported fields
}

SortedSliceSet is a simple set implementation that has a sorted set of values as its underlying storage.

TODO(a.garipov): Consider relaxing the type requirement or adding a version with a comparison function.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	const x = 1
	set := container.NewSortedSliceSet[int]()

	ok := set.Has(x)
	fmt.Printf("%s contains %v is %t\n", set, x, ok)

	set.Add(x)
	ok = set.Has(x)
	fmt.Printf("%s contains %v is %t\n", set, x, ok)

	other := container.NewSortedSliceSet(x)
	ok = set.Equal(other)
	fmt.Printf("%s is equal to %s is %t\n", set, other, ok)

	set.Add(2)
	values := set.Values()
	slices.Sort(values)
	fmt.Printf("values of %s are %v\n", set, values)

	set.Delete(x)
	ok = set.Has(x)
	fmt.Printf("%s contains %v is %t\n", set, x, ok)

	set.Range(func(n int) (cont bool) {
		fmt.Printf("got value %d\n", n)

		return false
	})

	set = container.NewSortedSliceSet(x)
	fmt.Printf("%s has length %d\n", set, set.Len())

	set.Clear()
	fmt.Printf("%s has length %d\n", set, set.Len())

}
Output:


[] contains 1 is false
[1] contains 1 is true
[1] is equal to [1] is true
values of [1 2] are [1 2]
[2] contains 1 is false
got value 2
[1] has length 1
[] has length 0
Example (Nil)
package main

import (
	"fmt"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	const x = 1

	var set *container.SortedSliceSet[int]

	panicked := false
	setPanicked := func() {
		panicked = recover() != nil
	}

	func() {
		defer setPanicked()

		set.Clear()
	}()
	fmt.Printf("panic after clear: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Delete(x)
	}()
	fmt.Printf("panic after delete: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Has(x)
	}()
	fmt.Printf("panic after has: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Len()
	}()
	fmt.Printf("panic after len: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Range(func(n int) (cont bool) {
			fmt.Printf("got value %d\n", n)

			return true
		})
	}()
	fmt.Printf("panic after range: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Values()
	}()
	fmt.Printf("panic after values: %t\n", panicked)

	func() {
		defer setPanicked()

		set.Add(x)
	}()
	fmt.Printf("panic after add: %t\n", panicked)

}
Output:


panic after clear: false
panic after delete: true
panic after has: false
panic after len: false
panic after range: false
panic after values: false
panic after add: true

func NewSortedSliceSet added in v0.30.1

func NewSortedSliceSet[T cmp.Ordered](elems ...T) (set *SortedSliceSet[T])

NewSortedSliceSet returns a new *SortedSliceSet. elems must not be modified after calling NewSortedSliceSet.

func (*SortedSliceSet[T]) Add added in v0.30.1

func (set *SortedSliceSet[T]) Add(v T)

Add adds v to set.

func (*SortedSliceSet[T]) Clear added in v0.30.1

func (set *SortedSliceSet[T]) Clear()

Clear clears set in a way that retains the internal storage for later reuse to reduce allocations. Calling Clear on a nil set has no effect, just like a clear on a nil slice doesn't.

func (*SortedSliceSet[T]) Clone added in v0.30.1

func (set *SortedSliceSet[T]) Clone() (clone *SortedSliceSet[T])

Clone returns a clone of set. If set is nil, clone is nil.

NOTE: It calls slices.Clone on the underlying storage, so these elements are cloned shallowly.

Example
package main

import (
	"fmt"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	var set *container.SortedSliceSet[int]
	fmt.Printf("nil:   %#v\n", set.Clone())

	const x, y = 1, 2
	set = container.NewSortedSliceSet(x)
	clone := set.Clone()
	clone.Add(y)

	fmt.Printf("orig:  %t %t\n", set.Has(x), set.Has(y))
	fmt.Printf("clone: %t %t\n", clone.Has(x), clone.Has(y))

}
Output:

nil:   (*container.SortedSliceSet[int])(nil)
orig:  true false
clone: true true

func (*SortedSliceSet[T]) Delete added in v0.30.1

func (set *SortedSliceSet[T]) Delete(v T)

Delete deletes v from set.

func (*SortedSliceSet[T]) Equal added in v0.30.1

func (set *SortedSliceSet[T]) Equal(other *SortedSliceSet[T]) (ok bool)

Equal returns true if set is equal to other. set and other may be nil; Equal returns true if both are nil, but a nil *SortedSliceSet is not equal to a non-nil empty one.

Example
package main

import (
	"fmt"

	"github.com/AdguardTeam/golibs/container"
)

func main() {
	const x, y = 1, 2
	set := container.NewSortedSliceSet(x)

	fmt.Printf("same:       %t\n", set.Equal(container.NewSortedSliceSet(x)))
	fmt.Printf("other elem: %t\n", set.Equal(container.NewSortedSliceSet(y)))
	fmt.Printf("other len:  %t\n", set.Equal(container.NewSortedSliceSet(x, y)))
	fmt.Printf("nil:        %t\n", set.Equal(nil))
	fmt.Printf("nil eq nil: %t\n", (*container.SortedSliceSet[int])(nil).Equal(nil))

}
Output:

same:       true
other elem: false
other len:  false
nil:        false
nil eq nil: true

func (*SortedSliceSet[T]) Has added in v0.30.1

func (set *SortedSliceSet[T]) Has(v T) (ok bool)

Has returns true if v is in set. Calling Has on a nil set returns false, just like iterating over a nil or empty slice does.

func (*SortedSliceSet[T]) Len added in v0.30.1

func (set *SortedSliceSet[T]) Len() (n int)

Len returns the length of set. A nil set has a length of zero, just like an nil or empty slice.

func (*SortedSliceSet[T]) Range added in v0.30.1

func (set *SortedSliceSet[T]) Range(f func(v T) (cont bool))

Range calls f with each value of set in their sorted order. If cont is false, Range stops the iteration. Calling Range on a nil *SortedSliceSet has no effect.

func (*SortedSliceSet[T]) String added in v0.30.1

func (set *SortedSliceSet[T]) String() (s string)

String implements the fmt.Stringer interface for *SortedSliceSet. Calling String on a nil *SortedSliceSet does not panic.

func (*SortedSliceSet[T]) Values added in v0.30.1

func (set *SortedSliceSet[T]) Values() (values []T)

Values returns the underlying slice of set. values must not be modified. Values returns nil if set is nil.

Jump to

Keyboard shortcuts

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