typ

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Feb 3, 2022 License: MIT Imports: 17 Imported by: 3

README

go-typ

Codacy Badge REUSE status Go Reference

Generic types and functions that are missing from Go, including sets, trees, linked lists, etc.

All code is implemented with 0 dependencies and in pure Go code (no CGo).

Background

Go v1.18 is about to be released now in February 2022, and with it comes some features that has been talked about for a really long time. One of which being generics! (Go 1.18 beta release notes)

They have moved generics from the Go v2.0 milestone over to Go v1.18, which means they have to stay backwards compatible and cannot alter any existing types. On top of this, they do not seem to plan on releasing any generic data types in the Go standard library until Go v1.19. All in all, to use generic data types with Go v1.18, you'll have to either write your own, or use a third-party package, like this one :)

This repository includes those generic functions and types that I find are missing from the release of Go v1.18-beta1, as well as a number of other data structures and utility functions I think should've been included in the standard library a long time ago. But now with generics, we can finally have sensible implementations of sets, trees, stacks, etc without excessive casting.

Compatibility

Requires Go v1.18beta1 or later as the code makes use of generics.

Installation and usage

go get -u gopkg.in/typ.v1
func UsingSets() {
	set1 := make(typ.Set[string])
	set1.Add("A")
	set1.Add("B")
	set1.Add("C")
	fmt.Println("set1:", set1) // {A B C}

	set2 := make(typ.Set[string])
	set2.Add("B")
	set2.Add("C")
	set2.Add("D")
	fmt.Println("set2:", set2) // {B C D}

	fmt.Println("union:", set1.Union(set2))         // {A B C D}
	fmt.Println("intersect:", set1.Intersect(set2)) // {B C}
	fmt.Println("set diff:", set1.SetDiff(set2))    // {A}
	fmt.Println("sym diff:", set1.SymDiff(set2))    // {A D}
}

func UsingOrderedTree() {
	var tree typ.OrderedTree[string]

	// Unordered input
	tree.Add("E")
	tree.Add("B")
	tree.Add("D")
	tree.Add("C")
	tree.Add("A")

	// Sorted output
	fmt.Println(tree.Len(), tree) // 5 [A B C D E]
}

Features

Types
  • typ.Array2D[T]: 2-dimensional array.
  • typ.AtomicValue[T]: Atomic value store, wrapper around sync/atomic.Value.
  • typ.KeyedMutex[T]: Mutual exclusive lock on a per-key basis.
  • typ.KeyedRWMutex[T]: Mutual exclusive reader/writer lock on a per-key basis.
  • typ.List[T]: Linked list, forked from container/list.
  • typ.Null[T]: Nullable type without needing pointers, forked from github.com/volatiletech/null/v9
  • typ.OrderedSlice[T]: Always-sorted slice for ordered types.
  • typ.OrderedTree[T]: AVL-tree (auto-balancing binary search tree) implementation for ordered types.
  • typ.Pool[T]: Object pool, wrapper around sync.Pool.
  • typ.Publisher[T]: Publish-subscribe pattern (pubsub) using channels.
  • typ.Queue[T]: First-in-first-out collection.
  • typ.Ring[T]: Circular list, forked from container/ring.
  • typ.Set[T]: Set, based on set theory.
  • typ.SortedSlice[T]: Always-sorted slice. Requires custom less function.
  • typ.Stack[T]: First-in-last-out collection.
  • typ.SyncMap[K,V]: Concurrent map, forked from sync.Map.

Explanation:

  • Forked type: Copied their code and modified it so it uses generic types down to the backing struct layer. This benefits the most from generics support.

  • Wrapped type: Code depends on the underlying non-generic type, and adds abstraction to hide the type casting. Less performant than full generic support, but is done to reduce excessive complexity in this repository.

  • Neither forked nor wrapped: Original code written by yours truly.

Constraints
  • typ.Number: Type constraint for any number: integers, floats, & complex.
  • typ.Real: Type constraint for real numbers: integers & floats.
Utility functions
  • typ.Abs[T](T) T: Absolute value of a number.
  • typ.All[T]([]T, func(T) bool) bool: Does condition match all values?
  • typ.Any[T]([]T, func(T) bool) bool: Does condition match any value?
  • typ.ChunkIter[T]([]T, int) [][]T: Invoke callback for all chunks in a slice.
  • typ.Chunk[T]([]T, int) [][]T: Divide up a slice.
  • typ.Clamp01[T](T) T: Clamp a value between 0 and 1.
  • typ.Clamp[T](T, T, T) T: Clamp a value inside a range.
  • typ.Coal[T](...T) T: Coalesce operator, returns first non-zero value.
  • typ.ContainsFunc[T]([]T, T, func(T, T) bool) bool: Checks if value exists in slice with custom equals.
  • typ.ContainsValue[K, V](map[K]V, V) bool: Does map contain value?
  • typ.Contains[T]([]T, T) bool: Does slice contain value?
  • typ.CountBy[K, V]([]V, func(V) K) []Counting[K]: Count elements by key.
  • typ.Digits10Sign[T](T) int: Number of base 10 digits (including sign) in integer.
  • typ.Digits10[T](T) int: Number of base 10 digits (excluding sign) in integer.
  • typ.DistinctFunc[T]([]T, func(T, T) bool) []T: Returns new slice of unique elements with custom equals.
  • typ.Distinct[T]([]T, func(T, T) bool) []T: Returns new slice of unique elements.
  • typ.ExceptSet[T]([]T, Set[T]) []T: Exclude values from other set.
  • typ.Except[T]([]T, []T) []T: Exclude values from other slice.
  • typ.Fill[T]([]T, T): Fill a slice with a value.
  • typ.Filter[T](slice []T, func(T) bool) []T: Returns filtered slice.
  • typ.FoldReverse[TState, T]([]T, TState, func(TState, T) TState) TState: Accumulate values from slice in reverse order.
  • typ.Fold[TState, T]([]T, TState, func(TState, T) TState) TState: Accumulate values from slice.
  • typ.GroupBy[K, V]([]V, func(V) K) []Grouping[K, V]: Group elements by key.
  • typ.IndexFunc[T]([]T, func(T) bool) int: Returns index of a value, or -1 if not found.
  • typ.Index[T]([]T, T) int: Returns index of a value, or -1 if not found.
  • typ.InsertSlice[T](*[]T, int, []T): Inserts a slice of values at index.
  • typ.Insert[T](*[]T, int, T): Inserts a value at index.
  • typ.IsNil[T](T) bool: Returns true if the generic value is nil.
  • typ.Last[T]([]T) T: Returns the last item in a slice.
  • typ.MakeChanOfChan[T](chan T, ...int) chan T: Returns the result of make(chan T), useful for anonymous types.
  • typ.MakeChanOf[T](T, ...int) chan T: Returns the result of make(chan T), useful for anonymous types.
  • typ.MakeMapOfMap[K,V](map[K]V, ...int) map[K]V: Returns the result of make(map[K]V), useful for anonymous types.
  • typ.MakeMapOf[K,V](K, V, ...int) map[K]V: Returns the result of make(map[K]V), useful for anonymous types.
  • typ.MakeSliceOfKey[K,V](map[K]V, ...int) []K: Returns the result of make([]K), useful for anonymous types.
  • typ.MakeSliceOfSlice[T]([]T, ...int) []T: Returns the result of make([]T), useful for anonymous types.
  • typ.MakeSliceOfValue[K,V](map[K]V, ...int) []V: Returns the result of make([]V), useful for anonymous types.
  • typ.MakeSliceOf[T](T, ...int) []T: Returns the result of make([]T), useful for anonymous types.
  • typ.MapErr[TA, TB](slice []TA, func(TA) (TB, error)) ([]TB, error): Returns converted slice, or first error.
  • typ.Map[TA, TB](slice []TA, func(TA) TB) []TB: Returns converted slice.
  • typ.Max[T](...T) T: Return the largest value.
  • typ.Min[T](...T) T: Return the smallest value.
  • typ.NewOf[T](*T) *T: Returns the result of new(T), useful for anonymous types.
  • typ.PairsIter[T]([]T, func(T, T)): Invoke callback for all pairs in a slice.
  • typ.Pairs[T]([]T) [][2]T: Returns all pairs from a slice.
  • typ.Product[T](...T) T: Multiplies together numbers.
  • typ.Ptr[T](T) *T: Return a pointer of the value, such as a literal.
  • typ.RecvContext[T](context.Context, <-chan T) (T, bool): Receive from a channel, or cancel with context.
  • typ.RecvQueuedFull[T](<-chan T, []T): Receive all queued values from a channel's buffer.
  • typ.RecvQueued[T](<-chan T, int) []T: Receive all queued values from a channel's buffer.
  • typ.RecvTimeout[T](chan<- T, time.Duration): Receive from channel with timeout.
  • typ.RemoveSlice[T](*[]T, int, int): Removes a slice of values at index.
  • typ.Remove[T](*[]T, int): Removes a value at index.
  • typ.Reverse[T]([]T): Reverse the order of a slice.
  • typ.SafeGetOr[T]([]T, int, T) T: Index a slice, or return fallback value if index is out of bounds.
  • typ.SafeGet[T]([]T, int) T: Index a slice, or return zero if index is out of bounds.
  • typ.Search[T]([]T, T): Searches for element index or insertion index in slice.
  • typ.SendContext[T](context.Context, chan<- T, T) bool: Send to a channel, or cancel with context.
  • typ.SendTimeout[T](<-chan T, T, time.Duration): Send to channel with timeout.
  • typ.ShuffleRand[T]([]T, *rand.Rand): Randomizes the order of a slice.
  • typ.Shuffle[T]([]T): Randomizes the order of a slice.
  • typ.SortDesc[T]([]T): Sort ordered slices in descending order.
  • typ.Sort[T]([]T): Sort ordered slices in ascending order.
  • typ.Sum[T](...T) T: Sums up numbers (addition).
  • typ.TernCast[T](bool, any, T) T: Conditionally cast a value.
  • typ.Tern[T](bool, T, T) T: Ternary operator, return based on conditional.
  • typ.TrimFunc[T]([]T, func(T) bool) []T: Trim away unwanted matches from start and end.
  • typ.TrimLeftFunc[T]([]T, func(T) bool) []T: Trim away unwanted matches from start.
  • typ.TrimLeft[T]([]T, []T): Trim away unwanted elements from start.
  • typ.TrimRightFunc[T]([]T, func(T) bool) []T: Trim away unwanted matches from end.
  • typ.TrimRight[T]([]T, []T): Trim away unwanted elements from end.
  • typ.Trim[T]([]T, []T): Trim away unwanted elements from start and end.
  • typ.TryGet[T]([]T, int) (T, bool): Index a slice, or return false if index is out of bounds.
  • typ.WindowedIter[T]([]T, int, func([]T)): Invoke callback for all windows in a slice.
  • typ.Windowed[T]([]T, int) [][]T: Returns all windows from a slice.
  • typ.ZeroOf[T](T) T: Returns the zero value for an anonymous type.
  • typ.Zero[T]() T: Returns the zero value for a type.

Development

Please read the CONTRIBUTING.md for information about development environment and guidelines.

Similar projects

All the below include multiple data structure implementations each, all with Go 1.18 generics support.

License

This project is primarily licensed under the MIT license:

  • My Go code in this project is licensed under the MIT license: LICENSES/MIT.txt

  • Some Go code in this project is forked from Go's source code, which is licensed under the 3-Clause BSD license: LICENSES/BSD-3-Clause.txt

  • Some Go code in this project is forked from Volatile Tech's source code (https://github.com/volatiletech/null), which is licensed under the 2-Clause BSD license: LICENSES/BSD-2-Clause.txt

  • Documentation is licensed under the Creative Commons Attribution 4.0 International (CC-BY-4.0) license: LICENSES

  • Miscellanious files are licensed under the Creative Commons Zero Universal license (CC0-1.0): LICENSES

  • GitHub Action for REUSE linting (and not any of go-typ's code) is licensed under GNU General Public License 3.0 or later (GPL-3.0-or-later): LICENSES/GPL-3.0-or-later.txt

Copyright © Kalle Fagerberg

Documentation

Overview

Package typ includes generic types that are missing from the Go standard library. This includes types for sets, sorted slices, trees, etc.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrAlreadyUnsubscribed       = errors.New("already unsubscribed")
	ErrSubscriptionNotInitalized = errors.New("subscription is not initialized")
)

Errors specific for the listener and subscriptions.

Functions

func Abs

func Abs[T Real](v T) T

Abs returns the absolute value of a number, in other words removing the sign, in other words (again) changing negative numbers to positive and leaving positive numbers as-is.

Abs(0)   // => 0
Abs(15)  // => 15
Abs(-15) // => 15

func All

func All[T any](slice []T, cond func(value T) bool) bool

All checks if all values matches the condition. Returns true if the slice is empty.

func Any

func Any[T any](slice []T, cond func(value T) bool) bool

Any checks if any value matches the condition. Returns false if the slice is empty.

func Chunk

func Chunk[T any](slice []T, size int) [][]T

Chunk divides the slice up into chunks with a size limit. The last chunk may be smaller than size if the slice is not evenly divisible.

func ChunkIter

func ChunkIter[T any](slice []T, size int, callback func(chunk []T))

ChunkIter divides the slice up into chunks and invokes the callback on each chunk. The last chunk may be smaller than size if the slice is not evenly divisible.

func Clamp

func Clamp[T constraints.Ordered](v, min, max T) T

Clamp returns the value clamped between the minimum and maximum values.

func Clamp01

func Clamp01[T Real](v T) T

Clamp01 returns the value clamped between 0 (zero) and 1 (one).

func Coal

func Coal[T comparable](values ...T) T

Coal will return the first non-zero value. Equivalent to the "null coalescing" operator from other languages, or the SQL "COALESCE(...)" expression.

var result = null ?? myDefaultValue;       // C#, JavaScript, PHP, etc
var result = typ.Coal(nil, myDefaultValue) // Go
Example
bindAddressFromUser := ""
bindAddressDefault := "localhost:8080"

fmt.Println("Adress 1:", typ.Coal(bindAddressFromUser, bindAddressDefault))

bindAddressFromUser = "192.168.1.10:80"
fmt.Println("Adress 2:", typ.Coal(bindAddressFromUser, bindAddressDefault))
Output:

Adress 1: localhost:8080
Adress 2: 192.168.1.10:80

func Compare

func Compare[T constraints.Ordered](a, b T) int

Compare checks if either value is greater or equal to the other. The result will be 0 if a == b, -1 if a < b, and +1 if a > b.

func Concat

func Concat[T any](a, b []T) []T

Concat returns a new slice with the values from the two slices concatenated.

func Contains

func Contains[T comparable](slice []T, value T) bool

Contains checks if a value exists inside a slice of values.

func ContainsFunc

func ContainsFunc[T any](slice []T, value T, equals func(a, b T) bool) bool

ContainsFunc checks if a value exists inside a slice of values with a custom equals operation.

func ContainsValue

func ContainsValue[K comparable, V comparable](m map[K]V, value V) bool

ContainsValue checks if a value exists inside a map.

func Digits10

func Digits10[T constraints.Integer](v T) int

Digits10 returns the number of digits in the number as if it would be converted to a string in base 10. This is computed by comparing its value to all orders of 10, making it increadibly faster than calculating logaritms or by performing divisions.

func DigitsSign10

func DigitsSign10[T constraints.Integer](v T) int

DigitsSign10 returns the number of digits in the number as if it would be converted to a string in base 10, plus 1 if the number is negative to account for the negative sign. This is computed by comparing its value to all orders of 10, making it increadibly faster than calculating logaritms or by performing divisions.

func Distinct

func Distinct[T comparable](slice []T) []T

Distinct returns a new slice of only unique values.

Example
values := []string{"a", "b", "b", "a"}

fmt.Printf("All: %v\n", values)
fmt.Printf("Distinct: %v\n", typ.Distinct(values))
Output:

All: [a b b a]
Distinct: [a b]

func DistinctFunc

func DistinctFunc[T any](slice []T, equals func(a, b T) bool) []T

DistinctFunc returns a new slice of only unique values.

func Except

func Except[T comparable](slice []T, exclude []T) []T

Except returns a new slice for all items that are not found in the slice of items to exclude.

func ExceptSet

func ExceptSet[T comparable](slice []T, exclude Set[T]) []T

ExceptSet returns a new slice for all items that are not found in the set of items to exclude.

func Fill

func Fill[T any](slice []T, value T)

Fill populates a whole slice with the same value using exponential copy.

func Filter

func Filter[T any](slice []T, match func(value T) bool) []T

Filter will return a new slice of all matching elements.

func Fold

func Fold[TState, T any](slice []T, seed TState, acc func(state TState, value T) TState) TState

Fold will accumulate an answer based on all values in a slice. Returns the seed value as-is if the slice is empty.

func FoldReverse

func FoldReverse[TState, T any](slice []T, seed TState, acc func(state TState, value T) TState) TState

FoldReverse will accumulate an answer based on all values in a slice, starting with the last element and accumulating backwards. Returns the seed value as-is if the slice is empty.

func Index

func Index[T comparable](slice []T, value T) int

Index returns the index of a value, or -1 if none found.

This differs from Search as Index doesn't require the slice to be sorted.

func IndexFunc

func IndexFunc[T any](slice []T, f func(value T) bool) int

IndexFunc returns the index of the first occurence where the function returns true, or -1 if none found.

This differs from Search as Index doesn't require the slice to be sorted.

func Insert

func Insert[T any](slice *[]T, index int, value T)

Insert inserts a value at a given index in the slice and shifts all following values to the right.

func InsertSlice

func InsertSlice[T any](slice *[]T, index int, values []T)

InsertSlice inserts a slice of values at a given index in the slice and shifts all following values to the right.

func IsNil

func IsNil[T any](value T) bool

IsNil checks if the generic value is nil.

func Last

func Last[T any](slice []T) T

Last returns the last item in a slice. Will panic with an out of bound error if the slice is empty.

func MakeChanOf

func MakeChanOf[T any](_ T, size ...int) chan T

MakeChanOf returns the result of make(chan T) for the same type as the first argument.

Useful when wanting to call make() on a channel of anonymous types by making use of type inference to skip having to declare the full anonymous type multiple times, which is quite common when writing tests.

func MakeChanOfChan

func MakeChanOfChan[T any](_ chan T, size ...int) chan T

MakeChanOfChan returns the result of make(chan T) for the same type as the channel type in the first argument.

Useful when wanting to call make() on a channel of anonymous types by making use of type inference to skip having to declare the full anonymous type multiple times, which is quite common when writing tests.

func MakeMapOf

func MakeMapOf[K comparable, V any](_ K, _ V, size ...int) map[K]V

MakeMapOf returns the result of make(map[K]V) for the same type as the first arguments.

Useful when wanting to call make() on a map of anonymous types by making use of type inference to skip having to declare the full anonymous type multiple times, which is quite common when writing tests.

func MakeMapOfMap

func MakeMapOfMap[K comparable, V any](_ map[K]V, size ...int) map[K]V

MakeMapOfMap returns the result of make(map[K]V) for the same type as the key and value types of the first argument.

Useful when wanting to call make() on a map of anonymous types by making use of type inference to skip having to declare the full anonymous type multiple times, which is quite common when writing tests.

Example
files := map[string]struct {
	SizeMB    int
	CreatedAt time.Time
	UpdatedAt time.Time
}{
	"/root/gopher.png": {
		SizeMB:    10,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	},
	"/root/meaningoflife.txt": {
		SizeMB:    0,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	},
}
filteredFiles := typ.MakeMapOfMap(files)
for path, f := range files {
	if ok, _ := filepath.Match("/root/*.txt", path); ok {
		filteredFiles[path] = f
	}
}
fmt.Println("Filtered:")
for path, f := range filteredFiles {
	fmt.Println(path, ":", f.SizeMB, "MB")
}
Output:

Filtered:
/root/meaningoflife.txt : 0 MB

func MakeSliceOf

func MakeSliceOf[T any](_ T, size ...int) []T

MakeSliceOf returns the result of make([]T) for the same type as the first argument.

Useful when wanting to call make() on a slice of anonymous types by making use of type inference to skip having to declare the full anonymous type multiple times, which is quite common when writing tests.

func MakeSliceOfKey

func MakeSliceOfKey[K comparable, V any](_ map[K]V, size ...int) []K

MakeSliceOfKey returns the result of make([]T) for the same type as the map key type of the first argument.

Useful when wanting to call make() on a slice of anonymous types by making use of type inference to skip having to declare the full anonymous type multiple times, which is quite common when writing tests.

func MakeSliceOfSlice

func MakeSliceOfSlice[T any](_ []T, size ...int) []T

MakeSliceOfSlice returns the result of make([]T) for the same type as the slice element type of the first argument.

Useful when wanting to call make() on a slice of anonymous types by making use of type inference to skip having to declare the full anonymous type multiple times, which is quite common when writing tests.

Example
var users = []struct {
	ID       int
	Username string
	Admin    bool
}{
	{1, "foo", true},
	{2, "bar", false},
}

var admins = typ.MakeSliceOfSlice(users)
for _, u := range users {
	if u.Admin {
		admins = append(admins, u)
	}
}

fmt.Println("users:", len(users))
fmt.Println("admins:", len(admins))
Output:

users: 2
admins: 1

func MakeSliceOfValue

func MakeSliceOfValue[K comparable, V any](_ map[K]V, size ...int) []V

MakeSliceOfValue returns the result of make([]T) for the same type as the map value type of the first argument.

Useful when wanting to call make() on a slice of anonymous types by making use of type inference to skip having to declare the full anonymous type multiple times, which is quite common when writing tests.

func Map

func Map[TA any, TB any](slice []TA, conv func(value TA) TB) []TB

Map will apply a conversion function to all elements in a slice and return the new slice with converted values.

func MapErr

func MapErr[TA any, TB any](slice []TA, conv func(value TA) (TB, error)) ([]TB, error)

MapErr will apply a conversion function to all elements in a slice and return the new slice with converted values. Will cancel the conversion on the first error occurrence.

func Max

func Max[T constraints.Ordered](v ...T) T

Max returns the largest value.

func Min

func Min[T constraints.Ordered](v ...T) T

Min returns the smallest value.

func NewOf

func NewOf[T any](*T) *T

NewOf returns the result of new() for the same type as the first argument. Useful when wanting to call new() on an anonymous type.

Example
myVector := new(struct {
	X int
	Y int
	Z int
})

otherVector := typ.NewOf(myVector)

fmt.Println("myVector:", myVector)
fmt.Println("otherVector:", otherVector)
fmt.Println("same?:", myVector == otherVector) // different pointers
Output:

myVector: &{0 0 0}
otherVector: &{0 0 0}
same?: false

func Pairs

func Pairs[T any](slice []T) [][2]T

Pairs returns a slice of pairs for the given slice. If the slice has less than two items, then an empty slice is returned.

func PairsIter

func PairsIter[T any](slice []T, callback func(a, b T))

PairsIter invokes the provided callback for all pairs for the given slice. If the slice has less than two items, then no invokation is performed.

func Product

func Product[T Number](v ...T) T

Product multiplies together all numbers from the arguments. Returns 1 if no arguments.

func Ptr

func Ptr[T any](value T) *T

Ptr returns a pointer to the value. Useful when working with literals.

func RecvContext

func RecvContext[T any](ctx context.Context, ch <-chan T) (T, bool)

RecvContext receives a value from a channel, or cancels when the given context is cancelled.

func RecvQueued

func RecvQueued[T any](ch <-chan T, maxValues int) []T

RecvQueued will receive all values from a channel until either there's no more values in the channel's queue buffer, or it has received maxValues values, or until the channel is closed, whichever comes first.

func RecvQueuedFull

func RecvQueuedFull[T any](ch <-chan T, buf []T) int

RecvQueuedFull will receive all values from a channel until either there's no more values in the channel's queue buffer, or it has filled buf with values, or until the channel is closed, whichever comes first, and then returns the number of values that was received.

func RecvTimeout

func RecvTimeout[T any](ch <-chan T, timeout time.Duration) (T, bool)

RecvTimeout receives a value from a channel, or cancels after a given timeout. If the timeout duration is zero or negative, then no limit is used.

func Remove

func Remove[T any](slice *[]T, index int)

Remove takes out a value at a given index and shifts all following values to the left.

func RemoveSlice

func RemoveSlice[T any](slice *[]T, index int, length int)

RemoveSlice takes out a slice of values at a given index and length and shifts all following values to the left.

func Repeat

func Repeat[T any](value T, count int) []T

Repeat creates a new slice with the given value repeated across it.

func Reverse

func Reverse[T any](slice []T)

Reverse will reverse all elements inside a slice, in place.

func SafeGet

func SafeGet[T any](slice []T, index int) T

SafeGet will get a value from a slice, or the zero value for the type if the index is outside the bounds of the slice. Passing a nil slice is equivalent to passing an empty slice.

func SafeGetOr

func SafeGetOr[T any](slice []T, index int, fallback T) T

SafeGetOr will get a value from a slice, or the fallback value for the type if the index is outside the bounds of the slice. Passing a nil slice is equivalent to passing an empty slice.

func Search[T constraints.Ordered](slice []T, value T) int

Search performs a binary search to find the index of a value in a sorted slice of ordered values. The index of the first match is returned, or the index where it insert the value if the value is not present. The slice must be sorted in ascending order.

func SendContext

func SendContext[T any](ctx context.Context, ch chan<- T, value T) bool

SendContext receives a value from a channel, or cancels when the given context is cancelled.

func SendTimeout

func SendTimeout[T any](ch chan<- T, value T, timeout time.Duration) bool

SendTimeout sends a value to a channel, or cancels after a given duration.

func Shuffle

func Shuffle[T any](slice []T)

Shuffle will randomize the order of all elements inside a slice. It uses the rand package for random number generation, so you are expected to have called rand.Seed beforehand.

func ShuffleRand

func ShuffleRand[T any](slice []T, rand *rand.Rand)

ShuffleRand will randomize the order of all elements inside a slice using the Fisher-Yates shuffle algoritm. It uses the rand argument for random number generation.

func Sort

func Sort[T constraints.Ordered](slice []T)

Sort will sort a slice using the default less-than operator.

func SortDesc

func SortDesc[T constraints.Ordered](slice []T)

SortDesc will sort a slice using the default less-than operator in descending order.

func Sum

func Sum[T Number](v ...T) T

Sum adds upp all numbers from the arguments. Returns 0 if no arguments.

func Tern

func Tern[T any](cond bool, ifTrue, ifFalse T) T

Tern returns different values depending on the given conditional boolean. Equivalent to the "ternary" operator from other languages.

var result = 1 > 2 ? "yes" : "no";        // C#, JavaScript, PHP, etc
var result = typ.Tern(1 > 2, "yes", "no") // Go
Example
age := 16
fmt.Println("To drink I want a glass of", typ.Tern(age >= 18, "wine", "milk"))
Output:

To drink I want a glass of milk

func TernCast

func TernCast[T any](cond bool, value any, ifFalse T) T

TernCast will cast the value if condition is true. Otherwise the last argument is returned.

func Trim

func Trim[T comparable](slice []T, unwanted []T) []T

Trim returns a slice of the slice that has had all unwanted values trimmed away from both the start and the end.

Example
x := []int{0, 1, 2, 3, 1, 2, 1}
fmt.Printf("All: %v\n", x)
fmt.Printf("Trimmed: %v\n", typ.Trim(x, []int{0, 1}))
Output:

All: [0 1 2 3 1 2 1]
Trimmed: [2 3 1 2]

func TrimFunc

func TrimFunc[T any](slice []T, unwanted func(value T) bool) []T

TrimFunc returns a slice of the slice that has had all unwanted values trimmed away from both the start and the end. Values are considered unwanted if the callback returns false.

func TrimLeft

func TrimLeft[T comparable](slice []T, unwanted []T) []T

TrimLeft returns a slice of the slice that has had all unwanted values trimmed away from the start of the slice.

func TrimLeftFunc

func TrimLeftFunc[T any](slice []T, unwanted func(value T) bool) []T

TrimLeftFunc returns a slice of the slice that has had all unwanted values trimmed away from the start of the slice. Values are considered unwanted if the callback returns false.

func TrimRight

func TrimRight[T comparable](slice []T, unwanted []T) []T

TrimRight returns a slice of the slice that has had all unwanted values trimmed away from the end of the slice.

func TrimRightFunc

func TrimRightFunc[T any](slice []T, unwanted func(value T) bool) []T

TrimRightFunc returns a slice of the slice that has had all unwanted values trimmed away from the end of the slice. Values are considered unwanted if the callback returns false.

func TryGet

func TryGet[T any](slice []T, index int) (T, bool)

TryGet will get a value from a slice, or return false on the second return value if the index is outside the bounds of the slice. Passing a nil slice is equivalent to passing an empty slice.

func Windowed

func Windowed[T any](slice []T, size int) [][]T

Windowed returns a slice of windows, where each window is a slice of the specified size from the specified slice.

func WindowedIter

func WindowedIter[T any](slice []T, size int, callback func(window []T))

WindowedIter invokes the provided callback for all windows, where each window is a slice of the specified size from the specified slice.

func Zero

func Zero[T any]() T

Zero returns the zero value for a given type.

func ZeroOf

func ZeroOf[T any](T) T

ZeroOf returns the zero value for a given type. The first argument is unused, but using Go's type inference can be useful to create the zero value for an anonymous type without needing to declare the full type.

Types

type Array2D

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

Array2D is a 2-dimensional array.

Example
// SPDX-FileCopyrightText: 2022 Kalle Fagerberg
//
// SPDX-License-Identifier: MIT

package main

import (
	"fmt"
	"strings"

	"gopkg.in/typ.v1"
)

type Sudoku struct {
	arr typ.Array2D[byte]
}

func (s Sudoku) PrintBoard() {
	var sb strings.Builder
	for y := 0; y < s.arr.Height(); y++ {
		if y%3 == 0 {
			sb.WriteString("+-------+-------+-------+\n")
		}
		for x := 0; x < s.arr.Width(); x++ {
			if x%3 == 0 {
				sb.WriteString("| ")
			}
			val := s.arr.Get(x, y)
			if val == 0 {
				sb.WriteByte(' ')
			} else {
				fmt.Fprint(&sb, val)
			}
			sb.WriteByte(' ')
		}
		sb.WriteString("|\n")
	}
	sb.WriteString("+-------+-------+-------+\n")
	fmt.Print(sb.String())
}

func main() {
	s := Sudoku{
		arr: typ.NewArray2DFromSlice(9, 9, [][]byte{
			{5, 3, 0, 0, 7, 0, 0, 0, 0},
			{6, 0, 0, 1, 9, 5, 0, 0, 0},
			{0, 9, 8, 0, 0, 0, 0, 6, 0},
			{8, 0, 0, 0, 6, 0, 0, 0, 3},
			{4, 0, 0, 8, 0, 3, 0, 0, 1},
			{7, 0, 0, 0, 2, 0, 0, 0, 6},
			{0, 6, 0, 0, 0, 0, 2, 8, 0},
			{0, 0, 0, 4, 1, 9, 0, 0, 5},
			{0, 0, 0, 0, 8, 0, 0, 7, 9},
		}),
	}

	s.arr.Set(2, 5, 3)

	s.PrintBoard()

}
Output:

+-------+-------+-------+
| 5 3   |   7   |       |
| 6     | 1 9 5 |       |
|   9 8 |       |   6   |
+-------+-------+-------+
| 8     |   6   |     3 |
| 4     | 8   3 |     1 |
| 7   3 |   2   |     6 |
+-------+-------+-------+
|   6   |       | 2 8   |
|       | 4 1 9 |     5 |
|       |   8   |   7 9 |
+-------+-------+-------+

func NewArray2D

func NewArray2D[T any](width, height int) Array2D[T]

NewArray2D initializes a 2-dimensional array with all zero values.

func NewArray2DFromSlice

func NewArray2DFromSlice[T any](width, height int, jagged [][]T) Array2D[T]

NewArray2DFromSlice initializes a 2-dimensional array based on a jagged slice of rows of values. Values from the jagged slice that are out of bounds are ignored.

func NewArray2DFromValue

func NewArray2DFromValue[T any](width, height int, value T) Array2D[T]

NewArray2DFromValue initializes a 2-dimensional array with a value.

func (Array2D[T]) Clone

func (a Array2D[T]) Clone() Array2D[T]

Clone returns a copy of this array.

func (Array2D[T]) Fill

func (a Array2D[T]) Fill(x1, y1, x2, y2 int, value T)

Fill will assign all values inside the region to the specified value. The coordinates are inclusive, meaning all values from [x1,y1] including [x1,y1] to [x2,y2] including [x2,y2] are set.

The method sorts the arguments, so x2 may be lower than x1 and y2 may be lower than y1.

func (Array2D[T]) Get

func (a Array2D[T]) Get(x, y int) T

Get returns a value from the array.

func (Array2D[T]) Height

func (a Array2D[T]) Height() int

Height returns the height of this array. The maximum y value is Height()-1.

func (Array2D[T]) Row

func (a Array2D[T]) Row(y int) []T

Row returns a mutable slice for an entire row. Changing values in this slice will affect the array.

func (Array2D[T]) RowSpan

func (a Array2D[T]) RowSpan(x1, x2, y int) []T

RowSpan returns a mutable slice for part of a row. Changing values in this slice will affect the array.

func (Array2D[T]) Set

func (a Array2D[T]) Set(x, y int, value T)

Set sets a value in the array.

func (Array2D[T]) String

func (a Array2D[T]) String() string

String returns a string representation of this array.

func (Array2D[T]) Width

func (a Array2D[T]) Width() int

Width returns the width of this array. The maximum x value is Width()-1.

type AtomicValue

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

AtomicValue is a wrapper around sync/atomic.Value from the Go stdlib.

An AtomicValue must not be copied after first use.

func (*AtomicValue[T]) CompareAndSwap

func (v *AtomicValue[T]) CompareAndSwap(old, new T) (swapped bool)

CompareAndSwap executes the compare-and-swap operation for the AtomicValue.

Using nil as the new value will result in panic.

func (*AtomicValue[T]) Load

func (v *AtomicValue[T]) Load() (val T)

Load returns the value set by the most recent call to Store, or the zero value for this type if there has been no call to Store.

func (*AtomicValue[T]) Store

func (v *AtomicValue[T]) Store(val T)

Store sets the value of the AtomicValue.

Using nil as the new value will result in panic.

func (*AtomicValue[T]) Swap

func (v *AtomicValue[T]) Swap(new T) (old T)

Swap stores the new value into the AtomicValue and returns the previous value. It returns a zero value if the AtomicValue is empty.

Using nil as the new value will result in panic.

type Counting

type Counting[K any] struct {
	Key   K
	Count int
}

Counting is a key-count store returned by the CountBy function.

func CountBy

func CountBy[K comparable, V any](slice []V, keyer func(value V) K) []Counting[K]

CountBy will count the number of occurrences for each key, using the key from the function provided.

type Element

type Element[T any] struct {

	// The value stored with this element.
	Value T
	// contains filtered or unexported fields
}

Element is an element of a linked list.

func (*Element[T]) Next

func (l *Element[T]) Next() *Element[T]

Next returns the next list element or nil.

func (*Element[T]) Prev

func (l *Element[T]) Prev() *Element[T]

Prev returns the previous list element or nil.

type Grouping

type Grouping[K, V any] struct {
	Key    K
	Values []V
}

Grouping is a key-values store returned by the GroupBy functions.

func GroupBy

func GroupBy[K comparable, V any](slice []V, keyer func(value V) K) []Grouping[K, V]

GroupBy will group all elements in the slice and return a slice of groups, using the key from the function provided.

type KeyedLocker

type KeyedLocker[T comparable] interface {
	LockKey(key T)
	UnlockKey(key T)
}

KeyedLocker represents an object that can be locked and unlocked on a per-key basis.

type KeyedMutex

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

KeyedMutex is a keyed mutual exclusion lock. The zero value for a KeyedMutex is an unlocked mutex for any key.

The KeyedMutex does not clear its own cache, so it will continue to grow for every new key that is used, unless you call the ClearKey method.

A KeyedMutex must not be copied after first use.

func (*KeyedMutex[T]) ClearKey

func (km *KeyedMutex[T]) ClearKey(key T)

func (*KeyedMutex[T]) LockKey

func (km *KeyedMutex[T]) LockKey(key T)

func (*KeyedMutex[T]) TryLockKey

func (km *KeyedMutex[T]) TryLockKey(key T) bool

func (*KeyedMutex[T]) UnlockKey

func (km *KeyedMutex[T]) UnlockKey(key T)

type KeyedRWMutex

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

KeyedRWMutex is a keyed reader/writer mutual exclusion lock. The lock can be held on a per-unique-key basis by an arbitrary number of readers or a single writer. The zero value for a KeyedRWMutex is an unlocked mutex for any key.

The KeyedRWMutex does not clear its own cache, so it will continue to grow for every new key that is used, unless you call the ClearKey method.

A KeyedRWMutex must not be copied after first use.

func (*KeyedRWMutex[T]) ClearKey

func (km *KeyedRWMutex[T]) ClearKey(key T)

func (*KeyedRWMutex[T]) LockKey

func (km *KeyedRWMutex[T]) LockKey(key T)

func (*KeyedRWMutex[T]) RLockKey

func (km *KeyedRWMutex[T]) RLockKey(key T)

func (*KeyedRWMutex[T]) RUnlockKey

func (km *KeyedRWMutex[T]) RUnlockKey(key T)

func (*KeyedRWMutex[T]) TryLockKey

func (km *KeyedRWMutex[T]) TryLockKey(key T) bool

func (*KeyedRWMutex[T]) TryRLockKey

func (km *KeyedRWMutex[T]) TryRLockKey(key T) bool

func (*KeyedRWMutex[T]) UnlockKey

func (km *KeyedRWMutex[T]) UnlockKey(key T)

type List

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

List represents a doubly linked list. The zero value for List is an empty list ready to use.

This list is a fork of the official Go implementation, with the change of making it generic.

Example
// Create a new list and put some numbers in it.
l := typ.NewList[int]()
e4 := l.PushBack(4)
e1 := l.PushFront(1)
l.InsertBefore(3, e4)
l.InsertAfter(2, e1)

// Iterate through list and print its contents.
for e := l.Front(); e != nil; e = e.Next() {
	fmt.Println(e.Value)
}
Output:

1
2
3
4

func NewList

func NewList[T any]() *List[T]

NewList returns an initialized list.

func (*List[T]) Back

func (l *List[T]) Back() *Element[T]

Back returns the last element of list l or nil if the list is empty.

func (*List[T]) Front

func (l *List[T]) Front() *Element[T]

Front returns the first element of list l or nil if the list is empty.

func (*List[T]) Init

func (l *List[T]) Init() *List[T]

Init initializes or clears list l.

func (*List[T]) InsertAfter

func (l *List[T]) InsertAfter(v T, mark *Element[T]) *Element[T]

InsertAfter inserts a new element e with value v immediately after mark and returns e. If mark is not an element of l, the list is not modified. The mark must not be nil.

func (*List[T]) InsertBefore

func (l *List[T]) InsertBefore(v T, mark *Element[T]) *Element[T]

InsertBefore inserts a new element e with value v immediately before mark and returns e. If mark is not an element of l, the list is not modified. The mark must not be nil.

func (*List[T]) Len

func (l *List[T]) Len() int

Len returns the number of elements of list l. The complexity is O(1).

func (*List[T]) MoveAfter

func (l *List[T]) MoveAfter(e, mark *Element[T])

MoveAfter moves element e to its new position after mark. If e or mark is not an element of l, or e == mark, the list is not modified. The element and mark must not be nil.

func (*List[T]) MoveBefore

func (l *List[T]) MoveBefore(e, mark *Element[T])

MoveBefore moves element e to its new position before mark. If e or mark is not an element of l, or e == mark, the list is not modified. The element and mark must not be nil.

func (*List[T]) MoveToBack

func (l *List[T]) MoveToBack(e *Element[T])

MoveToBack moves element e to the back of list l. If e is not an element of l, the list is not modified. The element must not be nil.

func (*List[T]) MoveToFront

func (l *List[T]) MoveToFront(e *Element[T])

MoveToFront moves element e to the front of list l. If e is not an element of l, the list is not modified. The element must not be nil.

func (*List[T]) PushBack

func (l *List[T]) PushBack(v T) *Element[T]

PushBack inserts a new element e with value v at the back of list l and returns e.

func (*List[T]) PushBackList

func (l *List[T]) PushBackList(other *List[T])

PushBackList inserts a copy of another list at the back of list l. The lists l and other may be the same. They must not be nil.

func (*List[T]) PushFront

func (l *List[T]) PushFront(v T) *Element[T]

PushFront inserts a new element e with value v at the front of list l and returns e.

func (*List[T]) PushFrontList

func (l *List[T]) PushFrontList(other *List[T])

PushFrontList inserts a copy of another list at the front of list l. The lists l and other may be the same. They must not be nil.

func (*List[T]) Remove

func (l *List[T]) Remove(e *Element[T]) T

Remove removes e from l if e is an element of list l. It returns the element value e.Value. The element must not be nil.

type Null

type Null[T any] struct {
	Val   T
	Valid bool
	Set   bool
}

Null is a nullable value that stores its nullable state inside its struct, meaning you never have to deal with pointers and possible nil dereferences.

It also means the types can live on the stack and never require to be allocated on the heap and managed by the garbage collector, which is unnecessary optimization for most, but requirement for others.

The type implements the following interfaces, making it possible to use in serialization:

encoding.TextMarshaler
encoding.TextUnmarshaler
encoding/json.Marshaler
encoding/json.Unmarshaler

Note that while the type is generic, the JSON serialization logic still uses reflection and interface{} casting, as it relies on the built in encoding/json package.

The type also implements the following types, making it possible to be used in place of sql.NullXXX:

database/sql.Scanner
database/sql/driver.Valuer

This Null implementation is forked from github.com/volatiletech/null/v9 to make it generic.

Example
type User struct {
	FirstName   string          `json:"firstName"`
	MiddleName  Null[string]    `json:"middleName"`
	LastName    string          `json:"lastName"`
	DateOfBirth Null[time.Time] `json:"dob"`
	DateOfDeath Null[time.Time] `json:"dod"`
}
user := User{
	FirstName:   "John",
	MiddleName:  Null[string]{},
	LastName:    "Doe",
	DateOfBirth: NullFrom(time.Date(1980, 5, 13, 0, 0, 0, 0, time.UTC)),
	DateOfDeath: Null[time.Time]{},
}

bytes, _ := json.MarshalIndent(&user, "", "  ")
fmt.Println(string(bytes))
Output:

{
  "firstName": "John",
  "middleName": null,
  "lastName": "Doe",
  "dob": "1980-05-13T00:00:00Z",
  "dod": null
}

func NewNull

func NewNull[T any](value T, valid bool) Null[T]

NewNull creates a new nullable value.

func NullFrom

func NullFrom[T any](value T) Null[T]

NullFrom creates a new nullable value that will be marked invalid if nil, and will always be valid if type is not nullable.

func NullFromPtr

func NullFromPtr[T any](ptr *T) Null[T]

NullFromPtr creates a new nullable value that will be marked invalid if nil.

func (Null[T]) IsSet

func (n Null[T]) IsSet() bool

IsSet returns true if this carries an explicit value (null inclusive).

func (Null[T]) IsValid

func (n Null[T]) IsValid() bool

IsValid returns true if this carries an explicit value and is not null.

func (Null[T]) IsZero

func (n Null[T]) IsZero() bool

IsZero returns true for null or zero values.

func (Null[T]) MarshalJSON

func (n Null[T]) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

func (Null[T]) MarshalText

func (n Null[T]) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler.

func (Null[T]) Ptr

func (n Null[T]) Ptr() *T

Ptr returns a pointer to the inner value, or a nil pointer if this value is null.

func (*Null[T]) Scan

func (n *Null[T]) Scan(value any) error

Scan implements sql.Scanner.

func (*Null[T]) SetValid

func (n *Null[T]) SetValid(value T)

SetValid changes the inner value and also sets it to be non-null.

func (*Null[T]) UnmarshalJSON

func (n *Null[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler.

func (*Null[T]) UnmarshalText

func (n *Null[T]) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler.

func (Null[T]) Value

func (n Null[T]) Value() (driver.Value, error)

Value implements driver.Value.

type Number

type Number interface {
	constraints.Integer | constraints.Float | constraints.Complex
}

Number is a type constraint for any Go numbers, including complex numbers.

type OrderedSlice

type OrderedSlice[T constraints.Ordered] struct {
	// contains filtered or unexported fields
}

OrderedSlice is a slice of ordered values. The slice is always sorted thanks to only inserting values in a sorted order.

Example
var slice typ.OrderedSlice[string]
slice.Add("f")
slice.Add("b")
slice.Add("e")
slice.Add("a")
slice.Add("d")
slice.Add("c")
slice.Add("g")

fmt.Println(slice)
fmt.Println("Contains a?", slice.Contains("a"))
slice.Remove("d")
fmt.Println(slice)
Output:

[a b c d e f g]
Contains a? true
[a b c e f g]

func NewOrderedSlice

func NewOrderedSlice[T constraints.Ordered](values []T) OrderedSlice[T]

NewOrderedSlice returns a new sorted slice based on a slice of values. Only ordered types are allowed. The values are sorted on insertion.

func (*OrderedSlice[T]) Add

func (s *OrderedSlice[T]) Add(value T) int

func (*OrderedSlice[T]) Contains

func (s *OrderedSlice[T]) Contains(value T) bool

func (*OrderedSlice[T]) Get

func (s *OrderedSlice[T]) Get(index int) T

func (*OrderedSlice[T]) Index

func (s *OrderedSlice[T]) Index(value T) int

func (*OrderedSlice[T]) Len

func (s *OrderedSlice[T]) Len() int

func (*OrderedSlice[T]) Remove

func (s *OrderedSlice[T]) Remove(value T) int

func (*OrderedSlice[T]) RemoveAt

func (s *OrderedSlice[T]) RemoveAt(index int)

func (OrderedSlice[T]) String

func (s OrderedSlice[T]) String() string

type OrderedTree

type OrderedTree[T constraints.Ordered] struct {
	// contains filtered or unexported fields
}

OrderedTree is a binary search tree (BST) for ordered Go types (numbers & strings), implemented as an AVL tree (Adelson-Velsky and Landis tree), a type of self-balancing BST. This guarantees O(log n) operations on insertion, searching, and deletion.

Example
var tree typ.OrderedTree[string]

// Unordered input
tree.Add("E")
tree.Add("B")
tree.Add("D")
tree.Add("C")
tree.Add("A")

// Sorted output
fmt.Println(tree.Len(), tree)
Output:

5 [A B C D E]

func (*OrderedTree[T]) Add

func (n *OrderedTree[T]) Add(value T)

Add will add another value to this tree. Duplicate values are allowed and are not dismissed.

func (*OrderedTree[T]) Clear

func (n *OrderedTree[T]) Clear()

Clear will reset this tree to an empty tree.

func (*OrderedTree[T]) Clone

func (n *OrderedTree[T]) Clone() OrderedTree[T]

Clone will return a copy of this tree, with a new set of nodes. The values are copied as-is, so no pointers inside your value type gets a deep clone.

func (*OrderedTree[T]) Contains

func (n *OrderedTree[T]) Contains(value T) bool

Contains checks if a value exists in this tree by iterating the binary search tree.

func (*OrderedTree[T]) Len

func (n *OrderedTree[T]) Len() int

Len returns the number of nodes in this tree.

func (*OrderedTree[T]) Remove

func (n *OrderedTree[T]) Remove(value T) bool

Remove will try to remove the first occurrence of a value from the tree.

func (*OrderedTree[T]) SliceInOrder

func (n *OrderedTree[T]) SliceInOrder() []T

SliceInOrder returns a slice of values by walking the tree in in-order. This returns all values in sorted order. See WalkInOrder for more details.

func (*OrderedTree[T]) SlicePostOrder

func (n *OrderedTree[T]) SlicePostOrder() []T

SlicePostOrder returns a slice of values by walking the tree in post-order. See WalkPostOrder for more details.

func (*OrderedTree[T]) SlicePreOrder

func (n *OrderedTree[T]) SlicePreOrder() []T

SlicePreOrder returns a slice of values by walking the tree in pre-order. See WalkPreOrder for more details.

func (OrderedTree[T]) String

func (n OrderedTree[T]) String() string

func (*OrderedTree[T]) WalkInOrder

func (n *OrderedTree[T]) WalkInOrder(walker func(value T))

WalkInOrder will iterate all values in this tree by first visiting each node's left branch, followed by the its own value, and then its right branch.

This is useful when reading a tree's values in order, as this guarantees iterating them in a sorted order.

func (*OrderedTree[T]) WalkPostOrder

func (n *OrderedTree[T]) WalkPostOrder(walker func(value T))

WalkPostOrder will iterate all values in this tree by first visiting each node's left branch, followed by the its right branch, and then its own value.

This is useful when deleting values from a tree, as this guarantees to always delete leaf nodes.

func (*OrderedTree[T]) WalkPreOrder

func (n *OrderedTree[T]) WalkPreOrder(walker func(value T))

WalkPreOrder will iterate all values in this tree by first visiting each node's value, followed by the its left branch, and then its right branch.

This is useful when copying binary search trees, as inserting back in this order will guarantee the clone will have the exact same layout.

type Pool

type Pool[T any] struct {
	New func() T
	// contains filtered or unexported fields
}

Pool is a wrapper around sync.Pool to allow generic and type safe access.

Example
// SPDX-FileCopyrightText: 2022 Kalle Fagerberg
//
// SPDX-License-Identifier: MIT

package main

import (
	"bytes"
	"io"
	"os"
	"time"

	"gopkg.in/typ.v1"
)

var bufPool = typ.Pool[*bytes.Buffer]{
	New: func() *bytes.Buffer {
		// The Pool's New function should generally only return pointer
		// types, since a pointer can be put into the return interface
		// value without an allocation:
		return new(bytes.Buffer)
	},
}

// timeNow is a fake version of time.Now for tests.
func timeNow() time.Time {
	return time.Unix(1136214245, 0)
}

func Log(w io.Writer, key, val string) {
	b := bufPool.Get()
	b.Reset()
	// Replace this with time.Now() in a real logger.
	b.WriteString(timeNow().UTC().Format(time.RFC3339))
	b.WriteByte(' ')
	b.WriteString(key)
	b.WriteByte('=')
	b.WriteString(val)
	w.Write(b.Bytes())
	bufPool.Put(b)
}

func main() {
	Log(os.Stdout, "path", "/search?q=flowers")
}
Output:

2006-01-02T15:04:05Z path=/search?q=flowers

func (*Pool[T]) Get

func (p *Pool[T]) Get() T

Get attempts to obtain an arbitrary item from the Pool, remove it from the Pool, and return it to the caller. At any stage it may fail and will instead use the Pool.New function to create a new item and return that instead.

func (*Pool[T]) Put

func (p *Pool[T]) Put(x T)

Put adds x to the pool.

type Publisher

type Publisher[T any] struct {
	OnPubTimeout    func(ev T)    // called if Pub or PubWait times out
	PubTimeoutAfter time.Duration // times out Pub & PubWait, if positive
	// contains filtered or unexported fields
}

Publisher is a type that allows publishing an event which will be sent out to all subscribed channels. A sort of "fan-out message queue".

Example
// SPDX-FileCopyrightText: 2022 Kalle Fagerberg
//
// SPDX-License-Identifier: MIT

package main

import (
	"fmt"
	"sync"

	"gopkg.in/typ.v1"
)

func printMessages(prefix string, ch <-chan string, wg *sync.WaitGroup) {
	for msg := range ch {
		fmt.Println(prefix, msg)
	}
	wg.Done()
}

func main() {
	var pub typ.Publisher[string]
	var wg sync.WaitGroup

	sub1 := pub.Sub()
	sub2 := pub.Sub()

	wg.Add(2)
	go printMessages("sub1:", sub1, &wg)
	go printMessages("sub2:", sub2, &wg)

	pub.PubWait("hello there")
	pub.UnsubAll()
	wg.Wait()

}
Output:

sub1: hello there
sub2: hello there

func (*Publisher[T]) Pub

func (o *Publisher[T]) Pub(ev T)

Pub sends the event to all subscriptions in their own goroutines and returns immediately without waiting for any of the channels to finish sending.

func (*Publisher[T]) PubSlice

func (o *Publisher[T]) PubSlice(evs []T)

PubSlice sends a slice of events to all subscriptions in their own goroutines and returns immediately without waiting for any of the channels to finish sending.

func (*Publisher[T]) PubSliceSync

func (o *Publisher[T]) PubSliceSync(evs []T)

PubSliceSync blocks while sending a slice of events syncronously to all subscriptions without starting a single goroutine. Useful in performance-critical use cases where there are a low expected number of subscribers (0-3).

func (*Publisher[T]) PubSliceWait

func (o *Publisher[T]) PubSliceWait(evs []T)

PubSliceWait blocks while sending a slice of events to all subscriptions in their own goroutines, and waits until all have received the message or timed out.

func (*Publisher[T]) PubSync

func (o *Publisher[T]) PubSync(ev T)

PubSync blocks while sending the event syncronously to all subscriptions without starting a single goroutine. Useful in performance-critical use cases where there are a low expected number of subscribers (0-3).

func (*Publisher[T]) PubWait

func (o *Publisher[T]) PubWait(ev T)

PubWait blocks while sending the event to all subscriptions in their own goroutines, and waits until all have received the message or timed out.

func (*Publisher[T]) Sub

func (o *Publisher[T]) Sub() <-chan T

Sub subscribes to events in a newly created channel with no buffer.

func (*Publisher[T]) SubBuf

func (o *Publisher[T]) SubBuf(size int) <-chan T

SubBuf subscribes to events in a newly created channel with a specified buffer size.

func (*Publisher[T]) Unsub

func (o *Publisher[T]) Unsub(sub <-chan T) error

Unsub unsubscribes a previously subscribed channel.

func (*Publisher[T]) UnsubAll

func (o *Publisher[T]) UnsubAll() error

UnsubAll unsubscribes all subscription channels, rendering them all useless.

type Queue

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

Queue is a first-in-first-out collection.

The implementation is done via a linked-list.

Example
var q Queue[string]
q.Enqueue("tripp")
q.Enqueue("trapp")
q.Enqueue("trull")

fmt.Println(q.Len())     // 3
fmt.Println(q.Dequeue()) // tripp, true
fmt.Println(q.Dequeue()) // trapp, true
fmt.Println(q.Dequeue()) // trull, true
fmt.Println(q.Dequeue()) // "", false
Output:

3
tripp true
trapp true
trull true
 false

func (*Queue[T]) Dequeue

func (q *Queue[T]) Dequeue() (T, bool)

Dequeue removes and returns a value from the end of the queue.

func (*Queue[T]) Enqueue

func (q *Queue[T]) Enqueue(value T)

Enqueue adds a value to the start of the queue.

func (*Queue[T]) Len

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

Len returns the number of elements in the queue.

func (*Queue[T]) Peek

func (q *Queue[T]) Peek() (T, bool)

Peek returns (but does not remove) a value from the end of the queue.

type Real

type Real interface {
	constraints.Integer | constraints.Float
}

Real is a type constraint for any real numbers. That being integers or floats.

type Ring

type Ring[T any] struct {
	Value T // for use by client; untouched by this library
	// contains filtered or unexported fields
}

A Ring is an element of a circular list, or ring. Rings do not have a beginning or end; a pointer to any ring element serves as reference to the entire ring. Empty rings are represented as nil Ring pointers. The zero value for a Ring is a one-element ring with a nil Value.

This list is a fork of the official Go implementation, with the change of making it generic.

func NewRing

func NewRing[T any](n int) *Ring[T]

NewRing creates a ring of n elements.

func (*Ring[T]) Do

func (r *Ring[T]) Do(f func(T))

Do calls function f on each element of the ring, in forward order. The behavior of Do is undefined if f changes *r.

Example
// Create a new ring of size 5
r := typ.NewRing[int](5)

// Get the length of the ring
n := r.Len()

// Initialize the ring with some integer values
for i := 0; i < n; i++ {
	r.Value = i
	r = r.Next()
}

// Iterate through the ring and print its contents
r.Do(func(p int) {
	fmt.Println(p)
})
Output:

0
1
2
3
4

func (*Ring[T]) Len

func (r *Ring[T]) Len() int

Len computes the number of elements in ring r. It executes in time proportional to the number of elements.

Example
// Create a new ring of size 4
r := typ.NewRing[int](4)

// Print out its length
fmt.Println(r.Len())
Output:

4
func (r *Ring[T]) Link(s *Ring[T]) *Ring[T]

Link connects ring r with ring s such that r.Next() becomes s and returns the original value for r.Next(). r must not be empty.

If r and s point to the same ring, linking them removes the elements between r and s from the ring. The removed elements form a subring and the result is a reference to that subring (if no elements were removed, the result is still the original value for r.Next(), and not nil).

If r and s point to different rings, linking them creates a single ring with the elements of s inserted after r. The result points to the element following the last element of s after insertion.

func (*Ring[T]) Move

func (r *Ring[T]) Move(n int) *Ring[T]

Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0) in the ring and returns that ring element. r must not be empty.

Example
// Create a new ring of size 5
r := typ.NewRing[int](5)

// Get the length of the ring
n := r.Len()

// Initialize the ring with some integer values
for i := 0; i < n; i++ {
	r.Value = i
	r = r.Next()
}

// Move the pointer forward by three steps
r = r.Move(3)

// Iterate through the ring and print its contents
r.Do(func(p int) {
	fmt.Println(p)
})
Output:

3
4
0
1
2

func (*Ring[T]) Next

func (r *Ring[T]) Next() *Ring[T]

Next returns the next ring element. r must not be empty.

Example
// Create a new ring of size 5
r := typ.NewRing[int](5)

// Get the length of the ring
n := r.Len()

// Initialize the ring with some integer values
for i := 0; i < n; i++ {
	r.Value = i
	r = r.Next()
}

// Iterate through the ring and print its contents
for j := 0; j < n; j++ {
	fmt.Println(r.Value)
	r = r.Next()
}
Output:

0
1
2
3
4

func (*Ring[T]) Prev

func (r *Ring[T]) Prev() *Ring[T]

Prev returns the previous ring element. r must not be empty.

Example
// Create a new ring of size 5
r := typ.NewRing[int](5)

// Get the length of the ring
n := r.Len()

// Initialize the ring with some integer values
for i := 0; i < n; i++ {
	r.Value = i
	r = r.Next()
}

// Iterate through the ring backwards and print its contents
for j := 0; j < n; j++ {
	r = r.Prev()
	fmt.Println(r.Value)
}
Output:

4
3
2
1
0
func (r *Ring[T]) Unlink(n int) *Ring[T]

Unlink removes n % r.Len() elements from the ring r, starting at r.Next(). If n % r.Len() == 0, r remains unchanged. The result is the removed subring. r must not be empty.

type Set

type Set[T comparable] map[T]struct{}

Set holds a collection of values with no duplicates. Its methods are based on the mathmatical branch of set theory, and its implementation is using a Go map[T]struct{}.

Example
set := make(typ.Set[string])
set.Add("A")
set.Add("B")
set.Add("C")

for value := range set {
	fmt.Println("Value:", value)
}
Output:

Value: A
Value: B
Value: C
Example (SetOperations)
set1 := make(typ.Set[string])
set1.Add("A")
set1.Add("B")
set1.Add("C")
fmt.Println("set1:", set1) // {A B C}

set2 := make(typ.Set[string])
set2.Add("B")
set2.Add("C")
set2.Add("D")
fmt.Println("set2:", set2) // {B C D}

fmt.Println("union:", set1.Union(set2))         // {A B C D}
fmt.Println("intersect:", set1.Intersect(set2)) // {B C}
fmt.Println("set diff:", set1.SetDiff(set2))    // {A}
fmt.Println("sym diff:", set1.SymDiff(set2))    // {A D}

// Please note: the Set.String() output is not sorted!
Output:

func CartesianProduct

func CartesianProduct[TA comparable, TB comparable](a Set[TA], b Set[TB]) Set[SetProduct[TA, TB]]

CartesianProduct performs a "Cartesian product" on two sets and returns a new set. A Cartesian product of two sets is a set of all possible combinations between two sets. In mathmatics it's denoted as:

A × B

Example:

{1 2 3} × {a b c} = {1a 1b 1c 2a 2b 2c 3a 3b 3c}

This operation is noncommutative, meaning you will get different results depending on the order of the operands. In other words:

A.CartesianProduct(B) != B.CartesianProduct(A)

This noncommutative attribute of the Cartesian product operation is due to the pairs being in reverse order if you reverse the order of the operands. Example:

{1 2 3} × {a b c} = {1a 1b 1c 2a 2b 2c 3a 3b 3c}
{a b c} × {1 2 3} = {a1 a2 a3 b1 b2 b3 c1 c2 c3}
{1a 1b 1c 2a 2b 2c 3a 3b 3c} != {a1 a2 a3 b1 b2 b3 c1 c2 c3}

func NewSetOfKeys

func NewSetOfKeys[K comparable, V any](m map[K]V) Set[K]

NewSetOfKeys returns a Set with all keys from a map added to it.

func NewSetOfSlice

func NewSetOfSlice[T comparable](slice []T) Set[T]

NewSetOfSlice returns a Set with all values from a slice added to it.

func NewSetOfValues

func NewSetOfValues[K comparable, V comparable](m map[K]V) Set[V]

NewSetOfValues returns a Set with all values from a map added to it.

func (Set[T]) Add

func (s Set[T]) Add(value T) bool

Add will add an element to the set, and return true if it was added or false if the value already existed in the set.

func (Set[T]) AddSet

func (s Set[T]) AddSet(set Set[T]) int

AddSet will add all element found in specified set to this set, and return the number of values that was added.

func (Set[T]) Clone

func (s Set[T]) Clone() Set[T]

Clone returns a copy of the set.

func (Set[T]) Has

func (s Set[T]) Has(value T) bool

Has returns true if the value exists in the set.

func (Set[T]) Intersect

func (s Set[T]) Intersect(other Set[T]) Set[T]

Intersect performs an "intersection" on the sets and returns a new set. An intersection is a set of all elements that appear in both sets. In mathmatics it's denoted as:

A ∩ B

Example:

{1 2 3} ∩ {3 4 5} = {3}

This operation is commutative, meaning you will get the same result no matter the order of the operands. In other words:

A.Intersect(B) == B.Intersect(A)

func (Set[T]) Remove

func (s Set[T]) Remove(value T) bool

Remove will remove an element from the set, and return true if it was removed or false if no such value existed in the set.

func (Set[T]) RemoveSet

func (s Set[T]) RemoveSet(set Set[T]) int

RemoveSet will remove all element found in specified set from this set, and return the number of values that was removed.

func (Set[T]) SetDiff

func (s Set[T]) SetDiff(other Set[T]) Set[T]

SetDiff performs a "set difference" on the sets and returns a new set. A set difference resembles a subtraction, where the result is a set of all elements that appears in the first set but not in the second. In mathmatics it's denoted as:

A \ B

Example:

{1 2 3} \ {3 4 5} = {1 2}

This operation is noncommutative, meaning you will get different results depending on the order of the operands. In other words:

A.SetDiff(B) != B.SetDiff(A)

func (Set[T]) Slice

func (s Set[T]) Slice() []T

Slice returns a new slice of all values in the set.

func (Set[T]) String

func (s Set[T]) String() string

String converts this set to its string representation.

func (Set[T]) SymDiff

func (s Set[T]) SymDiff(other Set[T]) Set[T]

SymDiff performs a "symmetric difference" on the sets and returns a new set. A symmetric difference is the set of all elements that appear in either of the sets, but not both. In mathmatics it's commonly denoted as either:

A △ B

or

A ⊖ B

Example:

{1 2 3} ⊖ {3 4 5} = {1 2 4 5}

This operation is commutative, meaning you will get the same result no matter the order of the operands. In other words:

A.SymDiff(B) == B.SymDiff(A)

func (Set[T]) Union

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

Union performs a "union" on the sets and returns a new set. A union is a set of all elements that appear in either set. In mathmatics it's denoted as:

A ∪ B

Example:

{1 2 3} ∪ {3 4 5} = {1 2 3 4 5}

This operation is commutative, meaning you will get the same result no matter the order of the operands. In other words:

A.Union(B) == B.Union(A)

type SetProduct

type SetProduct[TA comparable, TB comparable] struct {
	A TA
	B TB
}

SetProduct is the resulting type from a Cartesian product operation.

type SortOrdered

type SortOrdered[T constraints.Ordered] []T

SortOrdered implements sort.Interface via the default less-than operator.

func (SortOrdered[T]) Len

func (s SortOrdered[T]) Len() int

func (SortOrdered[T]) Less

func (s SortOrdered[T]) Less(i, j int) bool

func (SortOrdered[T]) Swap

func (s SortOrdered[T]) Swap(i, j int)

type SortedSlice

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

SortedSlice is a slice of ordered values. The slice is always sorted thanks to only inserting values in a sorted order.

Example
// SPDX-FileCopyrightText: 2022 Kalle Fagerberg
//
// SPDX-License-Identifier: MIT

package main

import (
	"fmt"

	"gopkg.in/typ.v1"
)

type User struct {
	Name    string
	IsAdmin bool
}

func (u User) String() string {
	if u.IsAdmin {
		return fmt.Sprintf("%s (admin)", u.Name)
	}
	return u.Name
}

func (u User) AsAdmin() User {
	u.IsAdmin = true
	return u
}

func main() {
	slice := typ.NewSortedSlice([]User{}, func(a, b User) bool {
		return a.Name < b.Name
	})
	johnDoe := User{Name: "John"}
	slice.Add(johnDoe)
	slice.Add(User{Name: "Jane"})
	slice.Add(User{Name: "Ann"})
	slice.Add(User{Name: "Wayne"})

	fmt.Println(slice)
	fmt.Println("Contains John non-admin?", slice.Contains(johnDoe))
	fmt.Println("Contains John admin?", slice.Contains(johnDoe.AsAdmin()))
	slice.Remove(johnDoe)
	fmt.Println(slice)

}
Output:

[Ann Jane John Wayne]
Contains John non-admin? true
Contains John admin? false
[Ann Jane Wayne]

func NewSortedSlice

func NewSortedSlice[T comparable](values []T, less func(a, b T) bool) SortedSlice[T]

NewSortedSlice returns a new sorted slice based on a slice of values and a custom less function that is used to keep values sorted. The values are sorted on insertion.

The less function is expected to return the same value for the same set of inputs for the lifetime of the sorted slice.

Note that if the less function is used when finding values to remove. If the less function cannot properly distinguish between two elements, then any of the equivalent elements may be the one being removed. The SortedSlice does not keep track of collision detection.

func (*SortedSlice[T]) Add

func (s *SortedSlice[T]) Add(value T) int

func (*SortedSlice[T]) Contains

func (s *SortedSlice[T]) Contains(value T) bool

func (*SortedSlice[T]) Get

func (s *SortedSlice[T]) Get(index int) T

func (*SortedSlice[T]) Index

func (s *SortedSlice[T]) Index(value T) int

func (*SortedSlice[T]) Len

func (s *SortedSlice[T]) Len() int

func (*SortedSlice[T]) Remove

func (s *SortedSlice[T]) Remove(value T) int

func (*SortedSlice[T]) RemoveAt

func (s *SortedSlice[T]) RemoveAt(index int)

func (SortedSlice[T]) String

func (s SortedSlice[T]) String() string

type Stack

type Stack[T any] []T

Stack is a first-in-last-out collection.

Example
var s Stack[string]
s.Push("tripp")
s.Push("trapp")
s.Push("trull")

fmt.Println(len(s))  // 3
fmt.Println(s.Pop()) // trull, true
fmt.Println(s.Pop()) // trapp, true
fmt.Println(s.Pop()) // tripp, true
fmt.Println(s.Pop()) // "", false
Output:

3
trull true
trapp true
tripp true
 false

func (*Stack[T]) Peek

func (s *Stack[T]) Peek() (T, bool)

Peek returns (but does not remove) the value on top of the stack, or false if the stack is empty.

func (*Stack[T]) Pop

func (s *Stack[T]) Pop() (T, bool)

Pop removes and returns the value on top of the stack, or false if the stack is empty.

func (*Stack[T]) Push

func (s *Stack[T]) Push(value T)

Push adds a value to the top of the stack.

type SyncMap

type SyncMap[K comparable, V any] struct {
	// contains filtered or unexported fields
}

SyncMap is like a Go map[K]V but is safe for concurrent use by multiple goroutines without additional locking or coordination. Loads, stores, and deletes run in amortized constant time.

The SyncMap type is specialized. Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.

The SyncMap type is optimized for two common use cases: (1) when the entry for a given key is only ever written once but read many times, as in caches that only grow, or (2) when multiple goroutines read, write, and overwrite entries for disjoint sets of keys. In these two cases, use of a SyncMap may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.

The zero SyncMap is empty and ready for use. A SyncMap must not be copied after first use.

This map is a fork of the official Go implementation, with the change of making it generic.

func (*SyncMap[K, V]) Delete

func (m *SyncMap[K, V]) Delete(key K)

Delete deletes the value for a key.

func (*SyncMap[K, V]) Load

func (m *SyncMap[K, V]) Load(key K) (value V, ok bool)

Load returns the value stored in the map for a key, or nil if no value is present. The ok result indicates whether value was found in the map.

func (*SyncMap[K, V]) LoadAndDelete

func (m *SyncMap[K, V]) LoadAndDelete(key K) (value V, loaded bool)

LoadAndDelete deletes the value for a key, returning the previous value if any. The loaded result reports whether the key was present.

func (*SyncMap[K, V]) LoadOrStore

func (m *SyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool)

LoadOrStore returns the existing value for the key if present. Otherwise, it stores and returns the given value. The loaded result is true if the value was loaded, false if stored.

func (*SyncMap[K, V]) Range

func (m *SyncMap[K, V]) Range(f func(key K, value V) bool)

Range calls f sequentially for each key and value present in the map. If f returns false, range stops the iteration.

Range does not necessarily correspond to any consistent snapshot of the SyncMap's contents: no key will be visited more than once, but if the value for any key is stored or deleted concurrently, Range may reflect any mapping for that key from any point during the Range call.

Range may be O(N) with the number of elements in the map even if f returns false after a constant number of calls.

func (*SyncMap[K, V]) Store

func (m *SyncMap[K, V]) Store(key K, value V)

Store sets the value for a key.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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