# stl4go -- STL for Golang

English | [简体中文](README_zh.md)

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

[![License Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-red.svg)](COPYING)
[![Golang](https://img.shields.io/badge/Language-go1.18+-blue.svg)](https://go.dev/)
![Build Status](https://github.com/chen3feng/stl4go/actions/workflows/go.yml/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/chen3feng/stl4go/badge.svg?branch=master)](https://coveralls.io/github/chen3feng/stl4go?branch=master)
[![GoReport](https://goreportcard.com/badge/github.com/securego/gosec)](https://goreportcard.com/report/github.com/chen3feng/stl4go)
[![Go Reference](https://pkg.go.dev/badge/github.com/chen3feng/stl4go.svg)](https://pkg.go.dev/github.com/chen3feng/stl4go)

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

<!-- gomarkdoc:embed:start -->

<!-- Code generated by gomarkdoc. DO NOT EDIT -->

```go
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](https://securego.io/) check are both set up, got
[![GoReport](https://goreportcard.com/badge/github.com/securego/gosec)](https://goreportcard.com/report/github.com/chen3feng/stl4go) 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:

- [x] `BuiltinSet` provided a set funtionality based on Go's own `map`
- [x] `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.
- [x] `DList` is a doubly linked list.
- [x] [SkipList](skiplist.md) 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](https://github.com/chen3feng/skiplist-survey) for performance comparison
- [x] `Stack`, is a FILO container based on Slice implementation
- [x] `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.

```go
    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:

```go
    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:

```go
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:

 ```go
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:

```go
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:

```go
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](https://github.com/chen3feng/stl4go/issues)。

And add more detailed documents.

## Go Doc

Clock to view the [generated doc](generated_doc.md).

## Reference

- [C++ STL](https://en.wikipedia.org/wiki/Standard_Template_Library)
- [liyue201/gostl](https://github.com/liyue201/gostl)
- [zyedidia/generic](https://github.com/zyedidia/generic)
- [hlccd/goSTL](https://github.com/hlccd/goSTL)
