diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/bytes.go b/bytes.go index 255aaad..3829cf7 100644 --- a/bytes.go +++ b/bytes.go @@ -6,6 +6,7 @@ import ( "unsafe" ) +// Bytes wraps the behavior of Vec as Vec[byte] adding new methods on top. type Bytes Vec[byte] var ( @@ -13,14 +14,17 @@ var ( _ io.ReaderFrom = Bytes{} ) +// NewBytes returns a Bytes instance with size `size` and capacity `capacity`. func NewBytes(size, capacity int) Bytes { return BytesFrom(make([]byte, size, capacity)) } +// BytesFrom creates a Bytes instance from `bts` bytes. func BytesFrom(bts []byte) Bytes { return Bytes(bts) } +// Slice returns a sliced Bytes using indexes starting from `low` and ending in `max`. func (b Bytes) Slice(low, max int) Bytes { if max <= 0 { return b[low:] @@ -29,73 +33,104 @@ func (b Bytes) Slice(low, max int) Bytes { return b[low:max] } -func (b *Bytes) CopyFrom(b2 Bytes) { - b.Reserve(b2.Len()) - copy(*b, b2) +// CopyFrom copies the bytes from `other` to `b`. +func (b *Bytes) CopyFrom(other Bytes) { + b.Reserve(other.Len()) + copy(*b, other) } +// WriteTo writes the bytes to an io.Writer. +// +// Implements the io.WriterTo interface. func (b Bytes) WriteTo(w io.Writer) (int64, error) { n, err := w.Write(b) return int64(n), err } +// ReadFrom reads bytes from an io.Reader into `b`. +// +// This function does NOT append bytes, it uses the existing buffer. +// +// Implements the io.ReaderFrom interface. func (b Bytes) ReadFrom(r io.Reader) (int64, error) { n, err := r.Read(b) return int64(n), err } +// LimitReadFrom is like ReadFrom but it is limited to `n` bytes. func (b *Bytes) LimitReadFrom(r io.Reader, n int) (int64, error) { b.Reserve(n) return b.Slice(0, n).ReadFrom(r) } -// LimitWriteTo writes a limited amount from `b` to `w`. +// LimitWriteTo writes a limited amount of `n` bytes to an io.Writer. func (b Bytes) LimitWriteTo(w io.Writer, n int) (int64, error) { return b.Slice(0, Min(b.Len(), n)).WriteTo(w) } +// Len returns the length of `b`. +// +// This function is equivalent to `len(b))`. func (b Bytes) Len() int { return len(b) } +// Cap returns the capacity of `b`. +// +// This function is equivalent to `cap(b))`. func (b Bytes) Cap() int { return cap(b) } -// String returns the `Bytes`' string representation. +// String converts `b` to a string. +// +// This function produces an allocation. To avoid the allocation use UnsafeString. func (b Bytes) String() string { return string(b) } +// UnsafeString converts `b` to a string without producing allocations. func (b Bytes) UnsafeString() string { return *(*string)(unsafe.Pointer(&b)) } -func (b Bytes) Index(c byte) int { +// IndexByte returns the index of `c` in `b`. +// +// This function is equivalent to bytes.IndexByte(b, c). +func (b Bytes) IndexByte(c byte) int { return bytes.IndexByte(b, c) } -func (b Bytes) Contains(c byte) bool { - return bytes.IndexByte(b, c) != -1 +// Index returns the index of `other` in `b`. +// +// This function is equivalent to bytes.Index(b, other). +func (b Bytes) Index(other Bytes) int { + return bytes.Index(b, other) } +// Resize increases or decreases the size of Bytes. func (b *Bytes) Resize(n int) { vc := (*Vec[byte])(b) vc.Resize(n) } +// Reserve increases the size of Bytes if needed. +// +// The call doesn't produce any allocation if `n` < cap(b). func (b *Bytes) Reserve(n int) { vc := (*Vec[byte])(b) vc.Reserve(n) } -func (b *Bytes) Append(bts ...byte) { +// Append appends bytes at the end of Bytes. +func (b *Bytes) Append(others ...byte) { vc := (*Vec[byte])(b) - vc.Append(bts...) + vc.Append(others...) } +// Push pushes the `bts` to the beginning of Bytes. func (b *Bytes) Push(bts ...byte) { vc := (*Vec[byte])(b) vc.Push(bts...) diff --git a/iter.go b/iter.go index d0bd98c..f0ed3b6 100644 --- a/iter.go +++ b/iter.go @@ -1,28 +1,39 @@ package tl +// Iter defines an iterator interface. type Iter[T any] interface { + // Next is called to iterate to the next element. + // + // Returns true if a next element is available, false otherwise. Next() bool + // Get returns the current element. Get() T + // GetPtr returns a pointer to the current element. GetPtr() *T } +// IterDrop implements an iterator which current element can be dropped. type IterDrop[T any] interface { Iter[T] - + // Drop removes the current element from the iterator. Drop() } +// IterBidir defines a bidirectional iterator. type IterBidir[T any] interface { Iter[T] - + // Back is like next but for going backwards. It moves the iterator to the previous position. + // For some implementations that might mean going in reverse mode (not going backwards). Back() bool } +// IterDropBidir merges IterBidir and IterDrop in one interface. type IterDropBidir[T any] interface { IterDrop[T] IterBidir[T] } +// Advance advances iter a number of `count` positions. func Advance[T any](iter Iter[T], count int) { for i := 0; i < count && iter.Next(); i++ { } diff --git a/iter/filter.go b/iter/filter.go index f389b16..5bc2e82 100644 --- a/iter/filter.go +++ b/iter/filter.go @@ -25,6 +25,7 @@ func (iter *iterFilter[T]) GetPtr() *T { return iter.inner.GetPtr() } +// Filter filters the values of iterators. func Filter[T any](inner tl.Iter[T], fn tl.CompareFunc[T]) tl.Iter[T] { return &iterFilter[T]{ inner: inner, diff --git a/iter/flatten.go b/iter/flatten.go index a12536a..c176387 100644 --- a/iter/flatten.go +++ b/iter/flatten.go @@ -31,6 +31,7 @@ func (iter *iterFlatten[T]) GetPtr() *T { return &iter.current } +// Flatten flattens the elements of `inner`. func Flatten[T any](inner tl.Iter[[]T]) tl.Iter[T] { return &iterFlatten[T]{ inner: inner, diff --git a/iter/index.go b/iter/index.go index 19d57e9..335105f 100644 --- a/iter/index.go +++ b/iter/index.go @@ -2,6 +2,7 @@ package iter import "github.com/dgrr/tl" +// Index indexes an element inside an iterator. func Index[T any](iter tl.Iter[T], cmpFn tl.CompareFunc[T]) int { i := 0 for ; iter.Next(); i++ { @@ -13,6 +14,7 @@ func Index[T any](iter tl.Iter[T], cmpFn tl.CompareFunc[T]) int { return -1 } +// Search searches for an element inside an iterator. func Search[T any](iter tl.Iter[T], cmpFn tl.CompareFunc[T]) tl.Iter[T] { for iter.Next() { if cmpFn(iter.Get()) { diff --git a/iter/map.go b/iter/map.go index 7c9d899..b901590 100644 --- a/iter/map.go +++ b/iter/map.go @@ -26,6 +26,7 @@ func (iter *iterMap[T, V]) GetPtr() *V { return &iter.current } +// Map maps the values of an iterator using `conv`. func Map[T, V any](inner tl.Iter[T], conv func(T) V) tl.Iter[V] { return &iterMap[T, V]{ inner: inner, diff --git a/iter/nth.go b/iter/nth.go index 564d1e8..03f5eca 100644 --- a/iter/nth.go +++ b/iter/nth.go @@ -26,6 +26,7 @@ func (iter *iterNth[T]) GetPtr() *T { return iter.val } +// Nth takes the nth element of an iterator. func Nth[T any](inner tl.Iter[T], nth int) tl.Iter[T] { for nth != 0 { nth-- diff --git a/iter/numeric.go b/iter/numeric.go index 2beb7df..151e332 100644 --- a/iter/numeric.go +++ b/iter/numeric.go @@ -28,6 +28,7 @@ func (iter *iterSum[T]) GetPtr() *T { return &iter.result } +// Sum sums up all the elements inside an iterator. func Sum[T constraints.Integer | constraints.Float](inner tl.Iter[T]) tl.Iter[T] { return &iterSum[T]{ inner: inner, diff --git a/iter/range.go b/iter/range.go index 594ee8f..e67fe76 100644 --- a/iter/range.go +++ b/iter/range.go @@ -30,6 +30,7 @@ func (iter *iterRange[T]) GetPtr() *T { return &iter.value } +// Range creates an iterator over a range. func Range[T constraints.Integer](start, stop, step T) tl.Iter[T] { return &iterRange[T]{ start: start, stop: stop, step: step, diff --git a/iter/slice.go b/iter/slice.go index 08f76fe..01cc14b 100644 --- a/iter/slice.go +++ b/iter/slice.go @@ -41,6 +41,7 @@ func AppendTo[T any](vs []T, iter tl.Iter[T]) []T { return vs } +// ToSlice converts a iterator to a slice. func ToSlice[T any](iter tl.Iter[T]) []T { newSlice := make([]T, 0) diff --git a/iter/unique.go b/iter/unique.go index a6134f0..7b4b2de 100644 --- a/iter/unique.go +++ b/iter/unique.go @@ -30,6 +30,7 @@ func (iter *iterUnique[T]) GetPtr() *T { return iter.inner.GetPtr() } +// UniqueFn removes any duplicates from the iterator using `eq` as comparator. func UniqueFn[T any](inner tl.Iter[T], eq func(a, b T) bool) tl.Iter[T] { return &iterUnique[T]{ inner: inner, @@ -37,12 +38,14 @@ func UniqueFn[T any](inner tl.Iter[T], eq func(a, b T) bool) tl.Iter[T] { } } +// Unique removes any duplicates from the iterator. func Unique[T comparable](inner tl.Iter[T]) tl.Iter[T] { return UniqueFn(inner, func(a, b T) bool { return a == b }) } +// Get returns the last element of the iterator. func Get[T any](iter tl.Iter[T]) T { for iter.Next() { } diff --git a/iter/window.go b/iter/window.go index fd3d563..b7c02dc 100644 --- a/iter/window.go +++ b/iter/window.go @@ -32,6 +32,7 @@ func (iter *iterWindow[T]) GetPtr() *[]T { return &iter.win } +// Window returns an iterator containing the last `n` values. func Window[T any](inner tl.Iter[T], n int) tl.Iter[[]T] { return &iterWindow[T]{ inner: inner, diff --git a/iter/windowCopy.go b/iter/windowCopy.go index 9d0031b..a57d4ce 100644 --- a/iter/windowCopy.go +++ b/iter/windowCopy.go @@ -32,6 +32,7 @@ func (iter *iterWindowCopy[T]) GetPtr() *[]T { return &iter.win } +// WindowCopy operates like Window but copying the values. func WindowCopy[T any](inner tl.Iter[T], n int) tl.Iter[[]T] { return &iterWindowCopy[T]{ inner: inner, diff --git a/list.go b/list.go index 1b7c027..403d211 100644 --- a/list.go +++ b/list.go @@ -1,19 +1,23 @@ package tl +// ListElement is an element in a List. type ListElement[T any] struct { value T prev, next *ListElement[T] list *List[T] } +// Get returns the value of the element. func (e *ListElement[T]) Get() T { return e.value } +// GetPtr returns a pointer to the value of the element. func (e *ListElement[T]) GetPtr() *T { return &e.value } +// Drop drops the current element from the list. func (e *ListElement[T]) Drop() { if e.prev != nil { e.prev.next = e.next @@ -26,15 +30,18 @@ func (e *ListElement[T]) Drop() { e.list.size-- } +// List defines a doubly linked list. type List[T any] struct { root ListElement[T] size int } +// Size returns the size of the linked list (number of elements inside the list). func (list *List[T]) Size() int { return list.size } +// PushBack appends an element to the back of the queue. func (list *List[T]) PushBack(v T) *ListElement[T] { e := &ListElement[T]{ value: v, @@ -60,6 +67,7 @@ func (list *List[T]) PushBack(v T) *ListElement[T] { return e } +// PushFront pushes an element to the front of the queue. func (list *List[T]) PushFront(v T) *ListElement[T] { e := &ListElement[T]{ value: v, @@ -85,6 +93,7 @@ func (list *List[T]) PushFront(v T) *ListElement[T] { return e } +// Front returns an optional to the first element of the queue. func (list *List[T]) Front() (opt OptionalPtr[T]) { if list.root.next != nil { opt.Set(&list.root.next.value) @@ -93,6 +102,7 @@ func (list *List[T]) Front() (opt OptionalPtr[T]) { return } +// Back returns an optional to the last element of the queue. func (list *List[T]) Back() (opt OptionalPtr[T]) { if list.root.prev != nil { opt.Set(&list.root.prev.value) @@ -109,6 +119,7 @@ func (list *List[T]) Back() (opt OptionalPtr[T]) { // println("-------") // } +// PopFront pops the first element if any. func (list *List[T]) PopFront() (opt OptionalPtr[T]) { if list.root.next != nil { opt.Set(&list.root.next.value) @@ -119,6 +130,7 @@ func (list *List[T]) PopFront() (opt OptionalPtr[T]) { return } +// PopBack pops the last element if any. func (list *List[T]) PopBack() (opt OptionalPtr[T]) { if list.root.prev != nil { opt.Set(&list.root.prev.value) @@ -129,17 +141,13 @@ func (list *List[T]) PopBack() (opt OptionalPtr[T]) { return } +// Reset resets the list. func (list *List[T]) Reset() { list.root.next = nil list.root.prev = nil } -type iterList[T any] struct { - root *ListElement[T] - current *ListElement[T] - prev, next *ListElement[T] -} - +// Iter returns an iterator for the List. func (list *List[T]) Iter() IterDropBidir[T] { return &iterList[T]{ root: &list.root, @@ -148,6 +156,12 @@ func (list *List[T]) Iter() IterDropBidir[T] { } } +type iterList[T any] struct { + root *ListElement[T] + current *ListElement[T] + prev, next *ListElement[T] +} + func (iter *iterList[T]) Drop() { iter.current.Drop() } diff --git a/numeric.go b/numeric.go index f06c4e7..520e6fd 100644 --- a/numeric.go +++ b/numeric.go @@ -2,6 +2,7 @@ package tl import "golang.org/x/exp/constraints" +// Max returns the maximum instance of a set of numbers. func Max[T constraints.Ordered](numbers ...T) (r T) { if len(numbers) == 0 { return diff --git a/optional.go b/optional.go index 48096a0..4410df8 100644 --- a/optional.go +++ b/optional.go @@ -1,15 +1,18 @@ package tl +// Optional defines a value that can be optional. So, if might be defined or not. type Optional[T any] struct { value T hasValue bool } +// MakeOptional returns an Optional with a value `v`. func MakeOptional[T any](v T) (opt Optional[T]) { opt.Set(v) return opt } +// NewOptional returns an Optional with a value `v` if `v` is not nil. func NewOptional[T any](v *T) (opt Optional[T]) { if v != nil { opt.Set(*v) @@ -18,15 +21,18 @@ func NewOptional[T any](v *T) (opt Optional[T]) { return opt } +// None returns an empty Optional. func None[T any]() (opt Optional[T]) { return opt } +// From sets the value `v` to the Optional. func (opt Optional[T]) From(v T) Optional[T] { opt.Set(v) return opt } +// Ptr returns a pointer to the value or nil if there's no value. func (opt Optional[T]) Ptr() *T { if opt.hasValue { return &opt.value @@ -35,10 +41,12 @@ func (opt Optional[T]) Ptr() *T { return nil } +// Get returns the value. The function doesn't check whether the value is set or not. func (opt Optional[T]) Get() T { return opt.value } +// Or sets the value `v` to the Optional only if no value is already present. func (opt Optional[T]) Or(v T) Optional[T] { if !opt.hasValue { opt.Set(v) @@ -47,47 +55,50 @@ func (opt Optional[T]) Or(v T) Optional[T] { return opt } +// HasValue returns true if Optional contains a valid value. func (opt Optional[T]) HasValue() bool { return opt.hasValue } +// Set sets a value `v` to the Optional. func (opt *Optional[T]) Set(v T) { opt.value = v opt.hasValue = true } +// Reset sets the Optional as invalid. func (opt *Optional[T]) Reset() { opt.hasValue = false } +// OptionalPtr is like Optional but instead of holding a copy of the value, it holds a pointer. type OptionalPtr[T any] struct { value *T } +// MakeOptionalPtr returns an OptionalPtr using the value `v`. func MakeOptionalPtr[T any](v *T) (opt OptionalPtr[T]) { - if v != nil { - opt.Set(v) - } - + opt.Set(v) return opt } +// Ptr returns a pointer to the value. func (opt OptionalPtr[T]) Ptr() *T { - if opt.value != nil { - return opt.value - } - - return nil + return opt.value } +// Get returns a pointer to the value, because the value is a pointer already. func (opt OptionalPtr[T]) Get() *T { return opt.value } +// GetValue returns the value inside the Optional's pointer. This function might panic +// if the value is not defined (aka value == nil). func (opt *OptionalPtr[T]) GetValue() T { return *opt.value } +// Or sets the value `v` to the Optional only if not value is already present. func (opt OptionalPtr[T]) Or(v *T) OptionalPtr[T] { if !opt.HasValue() { opt.Set(v) @@ -96,14 +107,17 @@ func (opt OptionalPtr[T]) Or(v *T) OptionalPtr[T] { return opt } +// HasValue returns true if a value is present. func (opt OptionalPtr[T]) HasValue() bool { return opt.value != nil } +// Set sets the value `v` to the OptionalPtr. func (opt *OptionalPtr[T]) Set(v *T) { opt.value = v } +// Reset resets the OptionalPtr's value. func (opt *OptionalPtr[T]) Reset() { opt.value = nil } diff --git a/pair.go b/pair.go index 69f8099..a582dc1 100644 --- a/pair.go +++ b/pair.go @@ -1,10 +1,12 @@ package tl +// Pair defines a pair of values. type Pair[T, U any] struct { first T second U } +// MakePair returns a Pair instance using (t, u). func MakePair[T, U any](t T, u U) Pair[T, U] { return Pair[T, U]{ first: t, @@ -12,18 +14,22 @@ func MakePair[T, U any](t T, u U) Pair[T, U] { } } +// Swap returns a new Pair swapping the place of the values. func (p Pair[T, U]) Swap() Pair[U, T] { return MakePair(p.second, p.first) } +// First returns the first value. func (p Pair[T, U]) First() T { return p.first } +// Second returns the second value. func (p Pair[T, U]) Second() U { return p.second } +// Both returns both values at the same time. func (p Pair[T, U]) Both() (T, U) { return p.first, p.second } diff --git a/queue.go b/queue.go index 689446d..07c996b 100644 --- a/queue.go +++ b/queue.go @@ -5,16 +5,19 @@ type element[T any] struct { next *element[T] } +// Queue defines a queue data structure. type Queue[T any] struct { first *element[T] last *element[T] } +// Reset resets the queue. func (q *Queue[T]) Reset() { q.first = nil q.last = nil } +// Front returns the first element if any. func (q *Queue[T]) Front() (v Optional[T]) { if q.first != nil { v.Set(q.first.data) @@ -23,6 +26,7 @@ func (q *Queue[T]) Front() (v Optional[T]) { return } +// PushFront pushes `data` to the beginning of the queue. func (q *Queue[T]) PushFront(data T) { if q.first == nil { q.first = &element[T]{ @@ -38,6 +42,7 @@ func (q *Queue[T]) PushFront(data T) { } } +// PushBack pushes to the back of the queue. func (q *Queue[T]) PushBack(data T) { if q.first == nil { q.first = &element[T]{ @@ -52,6 +57,7 @@ func (q *Queue[T]) PushBack(data T) { } } +// Pop pops from the beginning of the queue. func (q *Queue[T]) Pop() (v Optional[T]) { if q.first != nil { v.Set(q.first.data) diff --git a/ring.go b/ring.go index 7af0712..709911e 100644 --- a/ring.go +++ b/ring.go @@ -40,7 +40,10 @@ func NewRing[T any](size int) *Ring[T] { return ring } -func (ring *Ring[T]) Push(fn T) bool { +// Push adds a value to the ring. +// +// If the ring is full Push returns false. If the task has been pushed it will return true. +func (ring *Ring[T]) Push(value T) bool { for { head := atomic.LoadUint32(&ring.head) tail := atomic.LoadUint32(&ring.tail) @@ -52,7 +55,7 @@ func (ring *Ring[T]) Push(fn T) bool { index := atomic.LoadUint32(&ring.index[head&ring.mask]) if index == head { if atomic.CompareAndSwapUint32(&ring.head, head, head+1) { - ring.values[head&ring.mask] = fn + ring.values[head&ring.mask] = value atomic.StoreUint32(&ring.index[head&ring.mask], head+1) @@ -62,6 +65,7 @@ func (ring *Ring[T]) Push(fn T) bool { } } +// Pop takes a value from the ring. Returns the (value, true) or (value, false) func (ring *Ring[T]) Pop() (value T, ok bool) { for { head := ring.head diff --git a/slices.go b/slices.go index 0122866..89c79da 100644 --- a/slices.go +++ b/slices.go @@ -1,5 +1,6 @@ package tl +// Contains returns where `e` is present in `vs`. func Contains[T comparable](vs []T, e T) bool { for i := range vs { if vs[i] == e { @@ -10,6 +11,9 @@ func Contains[T comparable](vs []T, e T) bool { return false } +// SearchFn iterates over `vs` comparing the values using `cmpFn`. +// +// Returns the index to the element if found, -1 otherwise. func SearchFn[T any](vs []T, cmpFn CompareFunc[T]) int { for i := range vs { if cmpFn(vs[i]) { @@ -20,6 +24,7 @@ func SearchFn[T any](vs []T, cmpFn CompareFunc[T]) int { return -1 } +// ContainsFn returns where `vs` contains an element using `cmpFn`. func ContainsFn[T any](vs []T, cmpFn CompareFunc[T]) bool { for i := range vs { if cmpFn(vs[i]) { @@ -30,6 +35,7 @@ func ContainsFn[T any](vs []T, cmpFn CompareFunc[T]) bool { return false } +// Map maps the values of `set` using `fn`. func Map[T, E any](set []T, fn func(T) E) []E { r := make([]E, len(set)) for i := range set { @@ -39,6 +45,7 @@ func Map[T, E any](set []T, fn func(T) E) []E { return r } +// Filter filters a set of values using `cmpFn`. func Filter[T any](set []T, cmpFn CompareFunc[T]) []T { r := make([]T, 0) for i := range set { @@ -50,6 +57,7 @@ func Filter[T any](set []T, cmpFn CompareFunc[T]) []T { return r } +// FilterInPlace filters the set in-place, meaning that it will not create a new slice like in Filter. func FilterInPlace[T any](set []T, cmpFn CompareFunc[T]) []T { for i := 0; i < len(set); i++ { if !cmpFn(set[i]) { @@ -61,10 +69,16 @@ func FilterInPlace[T any](set []T, cmpFn CompareFunc[T]) []T { return set } +// Delete removes an element from a set. Notice that this function only removes the first occurrence. func Delete[T comparable](set []T, value T) []T { for i := 0; i < len(set); i++ { if set[i] == value { - set = append(set[:i], set[i:]...) + if i == len(set)-1 { + set = set[:i] + } else { + set = append(set[:i], set[i+1:]...) + } + break } } @@ -72,6 +86,33 @@ func Delete[T comparable](set []T, value T) []T { return set } +// DeleteAll deletes all occurrences of a matching value. +func DeleteAll[T comparable](set []T, value T) []T { + for i := 0; i < len(set); i++ { + if set[i] == value { + if i == len(set)-1 { + set = set[:i] + } else { + set = append(set[:i], set[i+1:]...) + } + + i-- + } + } + + return set +} + +// Join returns a slice containing the elements that are present in `a` and `b`. +func Join[T comparable](a, b []T) []T { + return JoinFn(a, b, func(a, b T) bool { + return a == b + }) +} + +// JoinFn performs an Join operation for non-comparable types. +// +// See Join for more. func JoinFn[T any](a, b []T, cmpFn func(a, b T) bool) (r []T) { for i := range a { if ContainsFn(b, func(e T) bool { @@ -84,12 +125,16 @@ func JoinFn[T any](a, b []T, cmpFn func(a, b T) bool) (r []T) { return r } -func Join[T comparable](a, b []T) []T { - return JoinFn(a, b, func(a, b T) bool { +// AntiJoin returns a slice containing the elements that are present in `a` but not in `b`. +func AntiJoin[T comparable](a, b []T) []T { + return AntiJoinFn(a, b, func(a, b T) bool { return a == b }) } +// AntiJoinFn performs an AntiJoin operation for non-comparable types. +// +// See AntiJoin for more. func AntiJoinFn[T any](a, b []T, cmpFn func(a, b T) bool) (r []T) { for i := range a { if !ContainsFn(b, func(e T) bool { @@ -102,12 +147,18 @@ func AntiJoinFn[T any](a, b []T, cmpFn func(a, b T) bool) (r []T) { return r } -func AntiJoin[T comparable](a, b []T) []T { - return AntiJoinFn(a, b, func(a, b T) bool { +// Merge merges multiple slices into one avoiding duplicates. +// +// Returns a slice containing all the elements in a, and more... without duplicates. +func Merge[T comparable](a []T, more ...[]T) (r []T) { + return MergeFn(func(a, b T) bool { return a == b - }) + }, a, more...) } +// MergeFn performs a Merge operation for non-comparable types. +// +// See Merge for more. func MergeFn[T any](cmpFn func(a, b T) bool, a []T, more ...[]T) (r []T) { r = append(r, a...) for _, b := range more { @@ -122,9 +173,3 @@ func MergeFn[T any](cmpFn func(a, b T) bool, a []T, more ...[]T) (r []T) { return } - -func Merge[T comparable](a, b []T) (r []T) { - return MergeFn(func(a, b T) bool { - return a == b - }, a, b) -} diff --git a/slices_test.go b/slices_test.go new file mode 100644 index 0000000..4402066 --- /dev/null +++ b/slices_test.go @@ -0,0 +1,87 @@ +package tl_test + +import ( + "fmt" + "strconv" + "strings" + + "github.com/dgrr/tl" +) + +func ExampleMap() { + numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + + numbersToString := tl.Map(numbers, func(number int) string { + return strconv.Itoa(number) + }) + + fmt.Println(numbers) + fmt.Println(numbersToString) +} + +func ExampleFilter() { + filterThis := []string{ + "Each type parameter has a type", + "constraint that acts as a kind of", + "meta-type for the type parameter", + "Each type constraint specifies the permissible", + "type arguments that calling", + "code can use for the respective", + "type parameter", + } + + // filter out the strings containing `type`. + afterFilter := tl.Filter(filterThis, func(x string) bool { + return !strings.Contains(x, "type") + }) + + fmt.Println(strings.Join(filterThis, "\n")) + fmt.Println("--- after ----") + fmt.Println(strings.Join(afterFilter, "\n")) +} + +func ExampleFilterInPlace() { + filterThis := []string{ + "Each type parameter has a type", + "constraint that acts as a kind of", + "meta-type for the type parameter", + "Each type constraint specifies the permissible", + "type arguments that calling", + "code can use for the respective", + "type parameter", + } + + // filter out the strings containing `type`. + filterThis = tl.FilterInPlace(filterThis, func(x string) bool { + return !strings.Contains(x, "type") + }) + + fmt.Println(strings.Join(filterThis, "\n")) +} + +func ExampleJoin() { + a := []int{1, 2, 3, 4, 5, 6, 7, 8} + b := []int{5, 7, 9, 11, 13} + + joined := tl.Join(a, b) + + fmt.Println("All", joined) +} + +func ExampleAntiJoin() { + a := []int{1, 2, 3, 4, 5, 6, 7, 8} + b := []int{5, 7, 9, 11, 13} + + antijoined := tl.AntiJoin(a, b) + + fmt.Println("All", antijoined) +} + +func ExampleMerge() { + a := []int{1, 2, 3, 4, 5, 6, 7, 8} + b := []int{5, 7, 9, 11, 13} + + merged := tl.Merge(a, b) + + fmt.Println("All", merged) +} diff --git a/vector.go b/vector.go index a658fb9..369a502 100644 --- a/vector.go +++ b/vector.go @@ -1,7 +1,9 @@ package tl +// Vec defines a slice of type T. type Vec[T any] []T +// MakeVec returns a vector of type T with the elements `elmnts`. func MakeVec[T any](elmnts ...T) Vec[T] { vc := Vec[T]{} vc.Append(elmnts...) @@ -9,6 +11,7 @@ func MakeVec[T any](elmnts ...T) Vec[T] { return vc } +// MakeVecSize returns a vector with size `size` and capacity `capacity`. func MakeVecSize[T any](size, capacity int) Vec[T] { return (Vec[T])(make([]T, size, capacity)) }