Help us shape the future of Go! Take the 2026 Go Developer Survey

container

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 6 Imported by: 0

README

Gravitton container

Latest Stable Version Build Status Coverage Status Go Dev Reference Software License

Generic containers for Go


Features

  • Arrays: a value per geom.Point of a size, in one slice, with sides of any integer type.
  • Sets: immutable sorted sets of any Compare element, with union, intersection and difference.

The rules behind them are in the package documentation.

Installation

go get github.com/gravitton/container
import "github.com/gravitton/container"

Usage

Arrays

An Array[T, S] holds one value for every index of a size in columns and rows. S is the integer type of its sides and indices, taken from the size it is made with. An array is a handle, as a slice is: a copy shares its values, and Clone gives storage of its own.

a := container.Arr[int](geom.Sz(4, 3))                  // an Array[int, int], every value zero
small := container.Arr[uint8](geom.Sz[int16](320, 200)) // an Array[uint8, int16], indexed by geom.Point[int16]

a.Set(geom.Pt(2, 1), 7)
*a.Get(geom.Pt(2, 1)) += 1 // a pointer into the array
a.Contains(geom.Pt(4, 0))  // false, the check before Get and Set, which panic outside
a.Size()                   // 4x3; also Width, Height and Len
snapshot := a.Clone()      // storage of its own

Iteration

The values are stored row by row, and every traversal follows that order: Keys walks the indices, Data is the storage itself.

An array of four columns and three rows, each cell labelled with its index and its offset, beside the same twelve values as one slice, row after row

for index, value := range a.All() { // also Keys and Values
	*value += index.X
}

values := a.Data() // the values row by row as a slice into the array, the fastest loop
for i := range values {
	values[i] = min(values[i], 9)
}

data, err := json.Marshal(a)   // {"w":4,"h":3,"d":[…]}, the values row by row
err = json.Unmarshal(data, &a) // and back; an error where the values do not fill the size

Sets

A Set[E] holds any element with a Compare method, once each and in that order. It never changes: every operation returns a set, so one is safe to copy and share.

a := container.SetOf(geom.Pt(1, 1), geom.Pt(2, 1), geom.Pt(1, 2), geom.Pt(2, 2))
from := container.SetFrom(points) // the same from a slice it takes as its own, without a copy

a.Contains(geom.Pt(2, 1)) // true, a binary search
a.Len()                   // 4; also IsEmpty
a.First()                 // (1,1), true; also Last
a.Index(geom.Pt(2, 1))    // 2, true, the index At reads it back from

Set operations

Each operation walks both sets once and allocates its result once, or not at all where it equals one of them.

Two overlapping squares of points, a and b, and the cells of their union, intersection, difference and symmetric difference

b := container.SetOf(geom.Pt(2, 2), geom.Pt(3, 2), geom.Pt(2, 3), geom.Pt(3, 3))

a.Union(b)               // (1,1) (1,2) (2,1) (2,2) (2,3) (3,2) (3,3)
a.Intersection(b)        // (2,2)
a.Difference(b)          // (1,1) (1,2) (2,1)
a.SymmetricDifference(b) // (1,1) (1,2) (2,1) (2,3) (3,2) (3,3)

a.Intersects(b) // true, without building the intersection
a.Encloses(b)   // false, whether a holds every element of b
a.Equal(b)      // false

A set is walked and stored in its order:

for p := range a.All() { // also Backward
	draw(p)
}

a.Elements()    // a fresh slice; also AppendElements
json.Marshal(a) // [{"x":1,"y":1},…], null for the empty set

Full reference: pkg.go.dev.

Not planned, by design

A container knows no layout: an array has no neighbors and a set no shape. Those belong to the package that gives the indices a meaning. A new container joins when a second package needs it, so there is no map, list, heap or queue until a game asks for one.

Credits

License

The MIT License (MIT). Please see License File for more information.

Documentation

Overview

Package container provides generic containers, each used as a value, that know no layout. It builds on github.com/gravitton/geometry for the points and sizes an array speaks.

Types

  • Array is a table of values, one for every index of a size in columns and rows, stored row by row. It is a handle: a copy shares its values.
  • Set is an immutable set held in the order of its elements' Compare method, which alone decides that two elements are the same. SetOf copies the elements it is given; SetFrom takes the slice as its own.

Rules

A Set never changes: every operation returns a set, and one that would equal a side is that side. The one way to change a set is a write to the slice given to SetFrom.

Compare must be a total order, and the same each time it is asked; on any other the answers of a set are undefined. Elements that compare the same are one element: where both sets hold it, a result may hold the one of either set.

The zero value of every container is the empty one, ready to use.

Allocations

A slice or set result is allocated once, at its final size, and each slice result has an Append form that allocates nothing once the caller's slice has room. SetOf allocates once, for its copy of the elements, and SetFrom nothing. A read, a write and a test allocate nothing; Array.Data is a read, the array's own storage rather than a result.

Panics

A degenerate value gets an answer; an argument with no meaning gets a panic, whose value is an error:

  • Arr for a negative width or height, or a size of more values than an int counts.
  • Array.Get and Array.Set for an index outside the array, and Set.At for an index outside the set.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Array

type Array[T any, S geom.Integer] struct {
	// contains filtered or unexported fields
}

Array is a table of values of type T, one for every index of a size in columns and rows, stored row by row. Its sides and indices are of the integer type S, which bounds each side by what S holds; only the number of values is an int. It is a handle: a copy shares its values, and Array.Clone gives storage of its own. The zero value is the empty array.

func Arr

func Arr[T any, S geom.Integer](size geom.Size[S]) Array[T, S]

Arr returns an array of the given size, every value zero. It panics for a negative width or height, and for a size of more values than an int counts.

Example
a := Arr[int](geom.Sz(4, 3))
small := Arr[uint8](geom.Sz[int16](320, 200))

a.Set(geom.Pt(2, 1), 7)
*a.Get(geom.Pt(2, 1)) += 1
snapshot := a.Clone()

for index, value := range a.All() {
	*value += index.X
}

values := a.Data()
for i := range values {
	values[i] = min(values[i], 9)
}

data, _ := json.Marshal(a)
var decoded Array[int, int]
err := json.Unmarshal(data, &decoded)

fmt.Println(a.Contains(geom.Pt(4, 0)), a.Size(), a.Len(), small.Size())
fmt.Println(snapshot.Data())
fmt.Println(a.Data())
fmt.Println(string(data))
fmt.Println(decoded.Data(), err)
Output:
false 4x3 12 320x200
[0 0 0 0 0 0 8 0 0 0 0 0]
[0 1 2 3 0 1 9 3 0 1 2 3]
{"w":4,"h":3,"d":[0,1,2,3,0,1,9,3,0,1,2,3]}
[0 1 2 3 0 1 9 3 0 1 2 3] <nil>

func (Array[T, S]) All

func (a Array[T, S]) All() iter.Seq2[geom.Point[S], *T]

All returns an iterator over every index with a pointer into the array to its value, in the order of Keys.

func (Array[T, S]) Clear

func (a Array[T, S]) Clear()

Clear resets every value of the array to the zero value.

func (Array[T, S]) Clone

func (a Array[T, S]) Clone() Array[T, S]

Clone returns a copy of the array with storage of its own, its values copied as an assignment copies them.

func (Array[T, S]) Contains

func (a Array[T, S]) Contains(index geom.Point[S]) bool

Contains reports whether the index is that of a value of the array.

func (Array[T, S]) Data

func (a Array[T, S]) Data() []T

Data returns the values of the array row by row as a slice into the array: a write through it changes the array, and an append to it never does. It is nil for the zero array.

func (Array[T, S]) Fill

func (a Array[T, S]) Fill(value T)

Fill sets every value of the array to value.

func (Array[T, S]) Get

func (a Array[T, S]) Get(index geom.Point[S]) *T

Get returns a pointer into the array to the value at the index: a write through it changes the array. It panics for an index outside the array.

func (Array[T, S]) Height

func (a Array[T, S]) Height() S

Height returns the number of rows of the array.

func (Array[T, S]) Keys

func (a Array[T, S]) Keys() iter.Seq[geom.Point[S]]

Keys returns an iterator over every index of the array, row by row.

func (Array[T, S]) Len

func (a Array[T, S]) Len() int

Len returns the number of values of the array (width·height), an int whatever S is.

func (Array[T, S]) MarshalJSON

func (a Array[T, S]) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler with the size of the array, flat as geom.Size writes it, and its values row by row, null for the zero array.

func (Array[T, S]) Set

func (a Array[T, S]) Set(index geom.Point[S], value T)

Set stores value at the index. It panics for an index outside the array.

func (Array[T, S]) Size

func (a Array[T, S]) Size() geom.Size[S]

Size returns the number of columns and rows of the array.

func (*Array[T, S]) UnmarshalJSON

func (a *Array[T, S]) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler, reading null as the zero array and null values as none. It returns an error for a size Arr panics for or S cannot hold, and for a number of values other than the width times the height, and leaves the array as it was on an error.

func (Array[T, S]) Values

func (a Array[T, S]) Values() iter.Seq[*T]

Values returns an iterator over pointers into the array to its values, in the order of Keys.

func (Array[T, S]) Width

func (a Array[T, S]) Width() S

Width returns the number of columns of the array.

type Set

type Set[E interface{ Compare(E) int }] struct {
	// contains filtered or unexported fields
}

Set is an immutable set of elements, held once each in the order of their Compare method, which alone decides that two elements are the same and must be a total order. A set is safe to copy and share. The zero value is the empty set.

func SetFrom

func SetFrom[E interface{ Compare(E) int }](elements []E) Set[E]

SetFrom returns the set of the given elements, in any order and with any repeats, taking the slice as its own: it rearranges what the slice holds, and a later write to it changes the set.

func SetOf

func SetOf[E interface{ Compare(E) int }](elements ...E) Set[E]

SetOf returns the set of the given elements, in any order and with any repeats.

Example
a := SetOf(geom.Pt(1, 1), geom.Pt(2, 1), geom.Pt(1, 2), geom.Pt(2, 2))
points := []geom.Point[int]{geom.Pt(2, 2), geom.Pt(1, 1), geom.Pt(2, 1), geom.Pt(1, 2), geom.Pt(1, 1)}
from := SetFrom(points)

first, ok := a.First()
index, found := a.Index(geom.Pt(2, 1))

fmt.Println(from.Equal(a), a.Contains(geom.Pt(2, 1)), a.Len())
fmt.Println(first, ok, index, found)
fmt.Println(slices.Collect(a.All()), slices.Collect(a.Backward()))
fmt.Println(a.Elements())

data, _ := json.Marshal(a)
fmt.Println(string(data))
Output:
true true 4
(1,1) true 2 true
[(1,1) (1,2) (2,1) (2,2)] [(2,2) (2,1) (1,2) (1,1)]
[(1,1) (1,2) (2,1) (2,2)]
[{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":1},{"x":2,"y":2}]

func (Set[E]) All

func (s Set[E]) All() iter.Seq[E]

All returns an iterator over the elements of the set, in order.

func (Set[E]) AppendElements

func (s Set[E]) AppendElements(dst []E) []E

AppendElements appends the elements of Elements to dst and returns the extended slice.

func (Set[E]) At

func (s Set[E]) At(i int) E

At returns the element at the index in the order of the set. It panics for an index outside the set.

func (Set[E]) Backward

func (s Set[E]) Backward() iter.Seq[E]

Backward returns an iterator over the elements of the set, in reverse order.

func (Set[E]) Contains

func (s Set[E]) Contains(element E) bool

Contains reports whether the element is in the set.

func (Set[E]) Difference

func (s Set[E]) Difference(other Set[E]) Set[E]

Difference returns the set of the elements in s that are not in other.

func (Set[E]) Elements

func (s Set[E]) Elements() []E

Elements returns the elements of the set in order, and nil for the empty set.

func (Set[E]) Encloses

func (s Set[E]) Encloses(other Set[E]) bool

Encloses reports whether s holds every element of other. Every set encloses the empty one.

func (Set[E]) Equal

func (s Set[E]) Equal(other Set[E]) bool

Equal reports whether s and other hold the same elements.

func (Set[E]) First

func (s Set[E]) First() (E, bool)

First returns the first element in the order of the set and true, or false for the empty set.

func (Set[E]) Index

func (s Set[E]) Index(element E) (int, bool)

Index returns the index of the element in the order of the set, the one At reads it back from, and true, or false where the set does not hold it.

func (Set[E]) Intersection

func (s Set[E]) Intersection(other Set[E]) Set[E]

Intersection returns the set of the elements in both s and other.

func (Set[E]) Intersects

func (s Set[E]) Intersects(other Set[E]) bool

Intersects reports whether s and other hold an element in common.

func (Set[E]) IsEmpty

func (s Set[E]) IsEmpty() bool

IsEmpty reports whether the set holds no element.

func (Set[E]) Last

func (s Set[E]) Last() (E, bool)

Last returns the last element in the order of the set and true, or false for the empty set.

func (Set[E]) Len

func (s Set[E]) Len() int

Len returns the number of elements in the set.

func (Set[E]) MarshalJSON

func (s Set[E]) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler with the elements as an array in order, null for the empty set.

func (Set[E]) SymmetricDifference

func (s Set[E]) SymmetricDifference(other Set[E]) Set[E]

SymmetricDifference returns the set of the elements in s or in other, and not in both.

func (Set[E]) Union

func (s Set[E]) Union(other Set[E]) Set[E]

Union returns the set of the elements in s, in other or in both.

Example
a := SetOf(geom.Pt(1, 1), geom.Pt(2, 1), geom.Pt(1, 2), geom.Pt(2, 2))
b := SetOf(geom.Pt(2, 2), geom.Pt(3, 2), geom.Pt(2, 3), geom.Pt(3, 3))

fmt.Println(a.Union(b).Elements())
fmt.Println(a.Intersection(b).Elements())
fmt.Println(a.Difference(b).Elements())
fmt.Println(a.SymmetricDifference(b).Elements())
fmt.Println(a.Intersects(b), a.Encloses(b), a.Equal(b))
Output:
[(1,1) (1,2) (2,1) (2,2) (2,3) (3,2) (3,3)]
[(2,2)]
[(1,1) (1,2) (2,1)]
[(1,1) (1,2) (2,1) (2,3) (3,2) (3,3)]
true false false

func (*Set[E]) UnmarshalJSON

func (s *Set[E]) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler, reading an array of elements in any order and with any repeats, and null or an empty array as the empty set. It leaves the set as it was on an error.

Jump to

Keyboard shortcuts

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