Categorygithub.com/chen3feng/stl4go
modulepackage
0.1.1
Repository: https://github.com/chen3feng/stl4go.git
Documentation: pkg.go.dev

# README

stl4go -- STL for Golang

English | 简体中文

This library contains generic containers and algorithms, it is designed to be STL for Golang.

License Apache 2.0 Golang Build Status Coverage Status GoReport Go Reference

This library depends on go generics, which is introduced in 1.18+.

import "github.com/chen3feng/stl4go"

Package stl4go is a generic container and algo rithm library for go.

Introduce

This library is a general container and algorithm library that attempts to learn from the C++ STL implementation after Go 1.18 began to support generics. (Personally I's totally unacceptable for me use to languages without generics, so I didn't try it until go 1.18).

The code quality of this library is quite high and follows the latest best practices in the industry. Test coverage is close💯%, ✅,CI, and gosec check are both set up, got GoReport score。

Features

As we all know, C++'s STL includes containers, algorithms, and iterators relate the two.

Due to language limitations, it is impossible and unnecessary to completely imitate the interface of C++ STL in Go, so C++ users may feel familiar, and sometimes (maybe) feel more convenient.

Containers

Currently implemented containers are:

  • BuiltinSet provided a set funtionality based on Go's own map
  • Vector is a thin encapsulation based on slice. It provides functions such as insertion and deletion in the middle, range deletion, etc., and is still compatible with slices.
  • DList is a doubly linked list.
  • SkipList is an ordered associative container that fills the gap where Go map only supports unordered. This is currently the fastest skip list I tested in GitHub, see skiplist-survey for performance comparison
  • Stack, is a FILO container based on Slice implementation
  • Queue is a bidirectional FIFO queue, implemented based on linked list.

Different containers support different methods. The following are the methods supported by all containers:

  • IsEmpty() bool Returns whether the container is empty
  • Len() int returns the number of elements in the container
  • Clear() to clear the container

Iterators

DList and SkipList support simple iterators.

    l := stl4go.NewDListOf(Range(1, 10000)...)
    sum := 0
    for i := 0; i < b.N; i++ {
        for it := l.Iterate(); it.IsNotEnd(); it.MoveToNext() {
            sum += it.Value()
        }
    }

SkipList also supports interval iteration:

    l := stl4go.NewDListOf(Range(1, 1000)...)
    it := sl.FindRange(120, 350)

Iterating over it yields numbers between 120 and 349.

In many cases, it is more convenient to use the ForEach and ForEachIf methods provided by the container, and the performance is often better:

func TestSkipList_ForEach(t *testing.T) {
    sl := newSkipListN(100)
    a := []int{}
    sl.ForEach(func(k int, v int) {
        a = append(a, k)
    })
    expectEq(t, len(a), 100)
    expectTrue(t, IsSorted(a))
}

ForEachIf is used for scenarios that you want to end early during the iteration:

func Test_DList_ForEachIf(t *testing.T) {
   l := NewDListOf(1, 2, 3)
   c := 0
   l.ForEachIf(func(n int) bool {
       c = n
       return n != 2
   })
   expectEq(t, c, 2)
}

You can use ForEachMutable or ForEachMutable to modify the value of an element during the iteration:

func TestSkipList_ForEachMutable(t *testing.T) {
    sl := newSkipListN(100)
    sl.ForEachMutable(func(k int, v *int) {
        *v = -*v
    })
    for i := 0; i < sl.Len(); i++ {
        expectEq(t, *sl.Find(i), -i)
    }
}

Algorithms

Due to the limitations of language, most algorithms only support Slice. The functions name of the algorithms ends with If, Func, indicating that a custom comparison function can be passed.

Generate

  • Range returns a Slice of contains integers in the range of [begin, end)
  • Generate generates a sequence with the given function to fill the Slice

Compute

  • Sum Sum
  • SumAs sums and returns a result as another type (eg. use int64 to return the sum of []int32).
  • Average finds the average value.
  • AverageAs averages and returns the result as another type (eg. use float64 to return the sum of []int).
  • Count returns the number equivalent to the specified value
  • CountIf returns the number of elements for which the specified function returns true

Compare

  • Equal checks whether two sequences are equal
  • Compare compares two sequences and returns -1, 0, and 1 in lexicographical order, respectively indicating the relationship of 2 slices.

Lookup

  • Min, Max find the maximum and minimum
  • MinN, MaxN, MinMax return the maximum and minimum values in the slice
  • Find linearly finds the first specified value and returns its index
  • FindIf linearly finds the first value that make specified function returns true and returns its index
  • AllOf, AnyOf, NoneOf return whether all, any, or none of the elements in the range can make the passed function return true accordingly.

Binary Search

See C++ STL.

  • BinarySearch
  • LowerBound
  • UpperBound

Sort

  • Sort sorting
  • DescSort descending sorting
  • StableSort stable sorting
  • DescStableSort descending stable sorting
  • IsSorted check whether the slice is sorted
  • IsDescSorted check whether the slice is sorted in descending order

Interface Design and Naming

The design leart much from the C++ STL. The T here represents template. Yes, Go's generic is not template. but who made C++ so influential and STL so famous?

Many libraries are designed for small code repositories or split into multiple subpackages in one repository. For example:

import (
    "github.com/someone/awesomelib/skiplist"
    "github.com/someone/awesomelib/binarysearch"
)

func main() {
    sl := skiplist.New()
}

This way of writing seems elegant, but because everyone likes good names, import renaming has to be introduced in use in case of package name conflict, and different users have different renaming style, which increases the mental burden of code reading and writing.

I don't like this style, especially in a larger repository.

Therefore, this library is all under the stl4go package, and it is expected that it will not namesake in other people's libraries.

TODO

See Issue

And add more detailed documents.

Go Doc

Clock to view the generated doc.

Reference

# Functions

AllOf return true if pred(e) returns true for all emements e in a.
AnyOf return true if pred(e) returns true for any emements e in a.
Average returns the average value of a.
AverageAs returns the average value of a as type R.
BinarySearch returns the (index, true) to the first element in the ascending ordered slice a such that element == value, or (-1, false) if no such element is found.
BinarySearchFunc returns the (index, true) to the first element in the ordered slice a such that less(element, value) and less(value, element) are both false, or (-1, false) if no such element is found.
Compare compares each elements in a and b.
Copy make a copy of slice a.
Count returns the number of elements in the slice equals to x.
CountIf returns the number of elements in the slice which pred returns true.
DescSort sorts data in descending order.
DescStableSort sorts data in descending order stably.
Equal returns whether two slices are equal.
Equals wraps the '==' operator for comparable types.
Find find the first value x in the given slice a linearly.
FindIf find the first value x satisfying function cond in the given slice a linearly.
Generate fill each element of `a`` with `gen()`.
Index find the value x in the given slice a linearly.
IsDescSorted returns whether the slice a is sorted in descending order.
IsSorted returns whether the slice a is sorted in ascending order.
Less wraps the '<' operator for ordered types.
LowerBound returns an index to the first element in the ascending ordered slice a that does not satisfy element < value (i.e.
LowerBoundFunc returns an index to the first element in the ordered slice a that does not satisfy less(element, value)), or len(a) if no such element is found.
MakeBuiltinSetOf creates a new BuiltinSet object with the initial content from ks.
MakeVector creates an empty Vector object.
MakeVectorCap creates an empty Vector object with specified capacity.
MakeVectorOf creates an Vector object with initial values.
Max return the larger value between `a` and `b`.
MaxN return the maximum value in the sequence `a`.
Min return the smaller value between `a` and `b`.
MinMax returns both min and max between a and b.
MinMaxN returns both min and max in slice a.
MinN return the minimum value in the sequence `a`.
NewDList make a new DList object.
NewDListOf make a new DList from a serial of values.
NewQueue create a new Queue object.
NewSkipList creates a new SkipList for Ordered key type.
NewSkipListFromMap creates a new SkipList from a map.
NewSkipListFunc creates a new SkipList with specified compare function keyCmp.
NewStack creates a new Stack object.
NewStackCap creates a new Stack object with the specified capicity.
NoneOf return true pred(e) returns true for none emements e in a.
OrderedCompare provide default CompareFn for ordered types.
Range make a []T filled with values in the `[first, last)` sequence.
Remove remove the elements which equals to x from the input slice.
RemoveCopy remove all elements which equals to x from the input slice.
RemoveIf remove each element which make cond(x) returns true from the input slice, copy other elements to a new slice and return it.
RemoveIfCopy drops each element which make cond(x) returns true from the input slice, copy other elements to a new slice and return it.
Reverse reverses the order of the elements in the slice a.
ReverseCopy returns a reversed copy of slice a.
Shuffle pseudo-randomizes the order of elements.
Sort sorts data in ascending order.
SortFunc sorts data in ascending order with compare func less.
StableSort sorts data in ascending order stably.
StableSortFunc sorts data in ascending order with compare func less stably.
Sum summarize all elements in a.
SumAs summarize all elements in a.
Transform applies the function op to each element in slice a and set it back to the same place in a.
TransformCopy applies the function op to each element in slice a and return all the result as a slice.
TransformTo applies the function op to each element in slice a and fill it to slice b.
Unique remove adjacent repeated elements from the input slice.
UniqueCopy remove adjacent repeated elements from the input slice.
UpperBound returns an index to the first element in the ascending ordered slice a such that value < element (i.e.
UpperBoundFunc returns an index to the first element in the ordered slice a such that less(value, element)) is true (i.e.

# Structs

DList is a doubly linked list.
Queue is a FIFO container.
SkipList is a probabilistic data structure that seem likely to supplant balanced trees as the implementation method of choice for many applications.
Stack s is a container adaptor that provides the functionality of a stack, a LIFO (last-in, first-out) data structure.

# Interfaces

Container is a holder object that stores a collection of other objects.
Float is a constraint that permits any floating-point type.
Integer is a constraint that permits any integer type.
Iterator is the interface for container's iterator.
Map is a associative container that contains key-value pairs with unique keys.
MapIterator is the interface for map's iterator.
Numeric is a constraint that permits any numeric type.
Ordered is a constraint that permits any ordered type: any type that supports the operators < <= >= >.
Set is a containers that store unique elements.
Signed is a constraint that permits any signed integer type.
Unsigned is a constraint that permits any unsigned integer type.

# Type aliases

BuiltinSet is an associative container that contains a unordered set of unique objects of type K.
CompareFn is a 3 way compare function that returns 1 if a > b, returns 0 if a == b, returns -1 if a < b.
HashFn is a function that returns the hash of 't'.
LessFn is a function that returns whether 'a' is less than 'b'.
Vector is a sequence container representing array that can change in size.