Repository: chen3feng/stl4go Branch: master Commit: 1aa2d0c16ab8 Files: 67 Total size: 250.5 KB Directory structure: gitextract_wl0h18v1/ ├── .github/ │ └── workflows/ │ ├── check-markdown-links.yml │ ├── go.yml │ └── gosec.yml ├── .gitignore ├── LICENSE ├── README.md ├── README_zh.md ├── binary_search.go ├── binary_search_test.go ├── builtin_set.go ├── builtin_set_test.go ├── check.bat ├── check.sh ├── compare.go ├── compare_test.go ├── compute.go ├── compute_test.go ├── container.go ├── container_test.go ├── dlist.go ├── dlist_queue.go ├── dlist_queue_test.go ├── dlist_test.go ├── doc.go ├── functor.go ├── generate.go ├── generate_test.go ├── generated_doc.md ├── go.mod ├── go.sum ├── heap.go ├── heap.md ├── heap_bench_test.go ├── heap_test.go ├── helper.go ├── iterator.go ├── lookup.go ├── lookup_test.go ├── mlc_config.json ├── pool.go ├── pool_test.go ├── priority_queue.go ├── priority_queue_test.go ├── skiplist.go ├── skiplist.md ├── skiplist_bench_test.go ├── skiplist_newnode.go ├── skiplist_newnode_generate.sh ├── skiplist_set.go ├── skiplist_set_test.go ├── skiplist_test.go ├── slist.go ├── slist_test.go ├── sort.go ├── sort_test.go ├── stack.go ├── stack_test.go ├── test_helper.go ├── transform.go ├── transform_fillzero_clear.go ├── transform_fillzero_old.go ├── transform_test.go ├── types.go ├── updatedoc.bat ├── updatedoc.sh ├── vector.go └── vector_test.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/check-markdown-links.yml ================================================ name: Check Markdown links on: push jobs: markdown-link-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@master - uses: gaurav-nelson/github-action-markdown-link-check@v1 with: use-quiet-mode: 'yes' check-modified-files-only: 'yes' config-file: mlc_config.json ================================================ FILE: .github/workflows/go.yml ================================================ name: Go on: push: branches: [ "master" ] pull_request: branches: [ "master" ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Go uses: actions/setup-go@v3 with: go-version: 1.18 - name: Build run: go build -v ./... - name: Test run: go test -v ./... -covermode=count -coverprofile=coverage.out.tmp - name: Filter out test_helper run: grep -E -v "/(test_helper)\.go:" coverage.out.tmp > coverage.out - name: Convert coverage.out to coverage.lcov uses: jandelgado/gcov2lcov-action@v1.0.9 - name: Coveralls uses: coverallsapp/github-action@v1.1.2 with: github-token: ${{ secrets.github_token }} path-to-lcov: coverage.lcov ================================================ FILE: .github/workflows/gosec.yml ================================================ name: Run Gosec on: push: branches: - master pull_request: branches: - master jobs: tests: runs-on: ubuntu-latest env: GO111MODULE: on steps: - name: Checkout Source uses: actions/checkout@v2 - name: Run Gosec Security Scanner uses: securego/gosec@master with: args: ./... ================================================ FILE: .gitignore ================================================ # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib __debug_bin # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out *.tmp *.bak *.old # Dependency directories (remove the comment below to include it) # vendor/ ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # 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+. ```go import "github.com/chen3feng/stl4go" ``` Package stl4go is a generic container and algorithm 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 There are following container interfaces: - `Container` is the base interface for all containers - `Map` is a key-value associative container - `Set` is set container - `SortedMap` is a ordered key-value associative container - `SortedSet` is a ordered set container - `Queue` is a FIFO Queue - `Deque` is a double ended queue Different interface has different methods. The `Container` interface has following methods: - `IsEmpty() bool` returns whether the container is empty - `Len() int` returns the number of elements in the container - `Clear()` to clear the container Read [source code](container.go) for details. Currently container implementations are: - [x] `BuiltinSet` provided a set funtionality based on Go's own `map`. It provides basic operations such as insert, search and remove, as well as advanced functions such as union, intersection, difference, subset, superset, and disjoint. - [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, supports push/popup at both ending. - [x] `SList` is a singly linked list, supports push/popup at the head and push at the tail. - [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] `SkipList` is a `SortedSet` container based on the skiplist. - [x] `Stack`, is a FILO container based on Slice implementation - [x] `DListQueue` is a bidirectional FIFO queue, implemented based on linked list. - [x] `PriorityQuque` is a priority queue based on heap. Much easier to use and faster than [container/heap](https://pkg.go.dev/container/heap). ### Non-Container Components - [x] `Pool` A type safe Pool, is implemented based on `sync.Pool`. ### Iterators Vector, DList and SkipList support iterators. ```go // Iterator is the interface for container's iterator. type Iterator[T any] interface { IsNotEnd() bool // Whether it is point to the end of the range. MoveToNext() // Let it point to the next element. Value() T // Return the value of current element. } // MutableIterator is the interface for container's mutable iterator. type MutableIterator[T any] interface { Iterator[T] Pointer() *T // Return the pointer to the value of current element. } ``` ```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() } } ``` The iterator of SkipList is `MutableMapIterator`: ```go // MapIterator is the interface for map's iterator. type MapIterator[K any, V any] interface { Iterator[V] Key() K // The key of the element } // MutableMapIterator is the interface for map's mutable iterator. type MutableMapIterator[K any, V any] interface { MutableIterator[V] Key() K // The key of the element } ``` SkipList also supports range iteration: ```go sl := stl4go.NewSkipList[int, int]() for i := 0; i < 1000; i++ { sl.Insert(i, 0) } it := sl.FindRange(120, 350) ``` Iterating over `it` only yields the keys 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` or `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 #### Data manipulation - `Copy` return a copies of specified slice - `CopyTo` copies all elements in slice a to slice to, return the copied slice. - `Fill` repeatedly fills a slice with the specified value - `FillZero` fills each element in slice a with zero value. - `FillPattern` repeatedly fills a slice with the specified pattern - `Replace` replaces every element that equals to old with new - `ReplaceIf` replaces every element that make preq returns true with new - `Transform` passes the value at each position of the slice to the specified function and sets it back with its return value - `TransformTo` passes the value at each position of slice `a` to the specified function, sets its return value to the corresponding position in slice `b`, and returns a slice of corresponding length of slice `b` - `TransformCopy` passes the value at each position of the slice to the specified function, sets its return value to the corresponding position in a new slice and returns - `Unique` removes adjacent duplicate elements from a slice and returns a slice with new length containing the remaining elements, `UniqueCopy` returns a copy without modifying the original slice - `Remove` removes all elements in the slice equal to the specified value, `RemoveCopy` returns a copy without modifying the original slice - `RemoveIf` removes all elements in the slice that are equivalent to making the specified function return `true`, `RemoveIfCopy` does not modify the original slice but returns a copy - `Shuffle` random shuffle elements in the slice - `Reverse` reverses a slice, `ReverseCopy` returns a copy without modifying the original 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 #### heap [Heap](heap.md) provides basic min heap algorithms: - `MakeMinHeap` Convert a slice to a min heap - `IsMinHeap` Check whether a slice is a min heap - `PushMinHeap` Pushes an element in to the heap - `PopMinHeap` Popups an element from the top of the heap - `RemoveMinHeap` Removes an element at index from the heap and variants with custome comparasion function: - `MakeHeapFunc` - `IsHeapFunc` - `PushHeapFunc` - `PopHeapFunc` - `RemoveHeapFunc` both of them are mush faster and easier to use than [container/heap](https://pkg.go.dev/container/heap). See detailed usage and benchmark report in the [document of heap](heap.md)。 ### 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 Click 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) ================================================ FILE: README_zh.md ================================================ # stl4go -- Go 语言的 STL [English](README.md) | 简体中文 本库包含 Go 语言实现的泛型容器和算法库,就像 C++ 中的 STL。 [![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) ```go import "github.com/chen3feng/stl4go" ``` ## 简介 本库是在 Go 1.18 开始支持泛型后,尝试借鉴 C++ STL 实现的一个通用容器和算法库。(我个人完全无法接受没有泛型的语言,因此直到 go 1.18 才开始尝试用它) 本库代码质量高,遵循了业界最新的最佳实践。测试覆盖率接近 💯%,✅,设置了 CI、 [gosec](https://securego.io/) 检查, [![GoReport](https://goreportcard.com/badge/github.com/securego/gosec)](https://goreportcard.com/report/github.com/chen3feng/stl4go) 评分。 ## 主要功能 众所周知,C++ 的 STL 包括容器、算法,并以迭代器关联两者。 受语言限制,在 Go 中无法也没有必要完全模仿 C++的接口,因此 C++ 用户可能会感觉似曾相识相识,有时候也会感觉更方便。 ### 容器 定义了如下容器接口: - `Container` 是所有容器的基础接口 - `Map` 定义了 key-value 关联容器的接口 - `Set` 定义了集合容器的接口 - `SortedMap` 定义了有序 key-value 关联容器的接口 - `SortedSet` 定义了有序集合容器的接口 - `Queue` 定义了先进先出的队列的接口 - `Deque` 定义了双端队列的接口 不同的容器接口支持的方法不同,下面是 `Container` 接口的方法: - `IsEmpty() bool` 返回容器是否为空 - `Len() int` 返回容器中的元素个数 - `Clear()` 清空容器 具体请参考[源代码](container.go)。 提供的具体容器实现有: - [x] `BuiltinSet` 是基于 Go 自己的 map 封装的集合。提供了插入查找删除等基本操作,以及并集、交集、差集、子集、超集、不交集等高级功能。 - [x] `Vector` 是基于切片封装的向量。提供了中间插入删除、区间删除等功能,依然与切片兼容。 - [x] `DList` 是双链表容器,支持两端插入删除。 - [x] `SList` 是单链表容器,支持头部插入删除及尾部插入。 - [x] [跳表(SkipList)](skiplist.md) 是一种有序的关联容器,可以填补 Go `map` 只支持无序的的空白。这是目前全 GitHub 最快的跳表,参见 [skiplist-survey](https://github.com/chen3feng/skiplist-survey)的性能比较 - [x] `SkipListSet` 是基于跳表实现的有序集合容器 - [x] `Stack`,栈基于 Slice 实现 - [x] `DListQueue` 双向进出的队列,基于双链表实现 - [x] `PriorityQuque` 优先队列,基于堆实现,比 [container/heap](https://pkg.go.dev/container/heap) 更易用而且快不少。 ### 非容器组件 - [x] `Pool` 类型安全的 Pool,基于对 `sync.Pool` 的封装而实现。 ### 迭代器 Vector、DList 和 SkipList 支持迭代器。 ```go // Iterator is the interface for container's iterator. type Iterator[T any] interface { IsNotEnd() bool // Whether it is point to the end of the range. MoveToNext() // Let it point to the next element. Value() T // Return the value of current element. } // MutableIterator is the interface for container's mutable iterator. type MutableIterator[T any] interface { Iterator[T] Pointer() *T // Return the pointer to the value of current element. } ``` ```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 的迭代器是 `MutableMapIterator`: ```go // MapIterator is the interface for map's iterator. type MapIterator[K any, V any] interface { Iterator[V] Key() K // The key of the element } // MutableMapIterator is the interface for map's mutable iterator. type MutableMapIterator[K any, V any] interface { MutableIterator[V] Key() K // The key of the element } ``` SkipList 还支持区间迭代: ```go sl := stl4go.NewSkipList[int, int]() for i := 0; i < 1000; i++ { sl.Insert(i, 0) } it := sl.FindRange(120, 350) ``` 对 `it` 迭代可以只会得到 120~349 之间的数。 更多时候,使用容器提供的 `ForEach` 和 `ForEachIf` 更方便,往往性能也更好一些: ```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` 用于遍历时候提前结束的场景: ```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) } ``` 使用 `ForEachMutable` 或 `ForEachMutable` 可以在遍历时候修改元素的值: ```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) } } ``` ### 算法 受语言功能限制,绝大部分算法只支持 Slice。算法的函数名以 `If`、`Func` 结尾的,表示可以传递一个自定义的比较函数。 #### 生成型 - Range 返回一个 [begin, end) 的整数构成的 Slice - Generate 用给定的函数生成一个序列填充到 Slice 中 #### 数据操作 - `Copy` 返回切片的拷贝 - `CopyTo` 拷贝切片的内容到另一个切片 - `Fill` 用指定的值重复填充一个切片 - `FillZero` 用类型的零值重复填充一个切片 - `FillPattern` 用指定的模式重复填充一个切片 - `Replace` 替换所有等于指定值的元素为新值 - `ReplaceIf` 替换所有让函数返回 `true` 的元素为新值 - `Transform` 把切片的每个位置的值传给指定的函数,用其返回值设置回去 - `TransformTo` 把切片 a 的每个位置的值传给指定的函数,将其返回值设置到切片 b 中相应的位置,并返回 b 的相应长度的切片 - `TransformCopy` 把切片的每个位置的值传给指定的函数,将其返回值设置到一个新的切片中相应的位置并返回 - `Unique` 去除切片中相邻的重复元素,返回包含剩余元素的新长度的切片,`UniqueCopy` 则不修改原切片而是返回一个拷贝 - `Remove` 去除切片中等于指定值的所有元素,`RemoveCopy` 则不修改原切片而是返回一个拷贝 - `RemoveIf` 去除切片中等于让指定函数返回 `true` 的所有元素,`RemoveIfCopy` 则不修改原切片而是返回一个拷贝 - `Shuffle` 随机洗牌 - `Reverse` 反转一个切片,`ReverseCopy` 则不修改原切片而是返回一个拷贝 #### 计算型 - `Sum` 求和 - `SumAs` 求和并以另一种类型的结果返回(比如以 `int64` 类型返回 `[]int32` 的和) - `Average` 求平均值。 - `AverageAs` 求平均值并以另一种类型的结果返回(比如 `float64` 返回 `[]int` 的和) - `Count` 返回和指定值相当的个数 - `CountIf` 返回让指定函数返回 `true` 的元素的个数 #### 比较 - `Equal` 判断两个序列是否相等 - `Compare` 比较两个序列,按字典序返回 -1、0、1 分别表示起大小关系 #### 查找 - `Min`, `Max` 求最大最小值 - `MinN`、`MaxN`、`MinMax` 返回 slice 中的最大和最小值 - `Find` 线性查找第一个指定的值,返回其下标 - `FindIf` 线性查找指定函数返回 `true` 的值,返回其下标 - `AllOf`、`AnyOf`、`NoneOf` 返回区间中是否全部、任何一个、没有一个元素能使传入的函数返回 `true` #### 二分查找 参考 C++STL。 - `BinarySearch` - `LowerBound` - `UpperBound` #### 排序 - `Sort` 升序排序 - `DescSort` 降序排序 - `StableSort` 升序稳定排序 - `DescStableSort` 降序稳定排序 - `IsSorted` 是否是升序排序的 - `IsDescSorted` 是否是降序排序的 #### 堆 提供基本的堆算法: - `MakeMinHeap` 在一个切片上构造出一个最小堆 - `IsMinHeap` 判断一个切片是不是一个最小堆 - `PushMinHeap` 把一个元素压入最小堆 - `PopMinHeap` 弹出堆顶的元素 - `RemoveMinHeap` 从切片的指定位置删除一个元素 以及相应的自定义比较函数的版本: - `MakeHeapFunc` - `IsHeapFunc` - `PushHeapFunc` - `PopHeapFunc` - `RemoveHeapFunc` 都比 go 标准库 [container/heap](https://pkg.go.dev/container/heap) 更容易使用且更快。 用法和测试详情参见[heap的文档](heap.md)。 ### 接口设计和命名 较多地参考了 C++ STL。T 表示模板。是的,Go 的泛型不是模板,但是谁让 C++ 那么影响力,而 STL 又那么有名呢。 很多库的设计采用小的代码仓库或者一个仓库中拆分成多个子包。 比如 ```go import ( "github.com/someone/awesomelib/skiplist" "github.com/someone/awesomelib/binarysearch" ) func main() { sl := skiplist.New() } ``` 这种写法看似优雅,但是由于好的名字大家都喜欢,在使用中又不得不引入 import 重命名,而不同的使用者别名不一样,增加代码读写的心智负担。 我不太喜欢这种风格。 因此本库全部在 `stl4go` 包下,期望不会和别人的库重名。 ### TODO 参见 [Issue](https://github.com/chen3feng/stl4go/issues)。 以及更详细的文档。 ## Go 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) ================================================ FILE: binary_search.go ================================================ package stl4go // LowerBound returns an index to the first element in the ascending ordered slice a that // does not satisfy element < value (i.e. greater or equal to), // or len(a) if no such element is found. // // Complexity: O(log(len(a))). func LowerBound[T Ordered](a []T, value T) int { loc := 0 count := len(a) for count > 0 { i := loc step := count / 2 i += step if a[i] < value { i++ loc = i count -= step + 1 } else { count = step } } return loc } // 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. // // The elements in the slice a should sorted according with compare func less. // // Complexity: O(log(len(a))). func LowerBoundFunc[T any](a []T, value T, less LessFn[T]) int { loc := 0 count := len(a) for count > 0 { i := loc step := count / 2 i += step if less(a[i], value) { i++ loc = i count -= step + 1 } else { count = step } } return loc } // UpperBound returns an index to the first element in the ascending ordered slice a such that // value < element (i.e. strictly greater), or len(a) if no such element is found. // // Complexity: O(log(len(a))). func UpperBound[T Ordered](a []T, value T) int { loc := 0 count := len(a) for count > 0 { i := loc step := count / 2 i += step if !(value < a[i]) { i++ loc = i count -= step + 1 } else { count = step } } return loc } // UpperBoundFunc returns an index to the first element in the ordered slice a such that // less(value, element)) is true (i.e. strictly greater), or len(a) if no such element is found. // // The elements in the slice a should sorted according with compare func less. // // Complexity: O(log(len(a))). func UpperBoundFunc[T any](a []T, value T, less LessFn[T]) int { loc := 0 count := len(a) for count > 0 { i := loc step := count / 2 i += step if !less(value, a[i]) { i++ loc = i count -= step + 1 } else { count = step } } return loc } // 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. // // Complexity: O(log(len(a))). func BinarySearch[T Ordered](a []T, value T) (index int, ok bool) { loc := LowerBound(a, value) if loc < len(a) && a[loc] == value { return loc, true } return -1, false } // 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. // // The elements in the slice a should sorted according with compare func less. // // Complexity: O(log(len(a))). func BinarySearchFunc[T any](a []T, value T, less LessFn[T]) (index int, ok bool) { loc := LowerBoundFunc(a, value, less) if loc < len(a) && !less(value, a[loc]) { return loc, true } return -1, false } ================================================ FILE: binary_search_test.go ================================================ package stl4go import "testing" func TestLowerBound(t *testing.T) { a := []int{1, 2, 4, 5, 5, 6} expectEq(t, LowerBound(a, 1), 0) expectEq(t, LowerBound(a, 5), 3) expectEq(t, LowerBound(a, 7), len(a)) } func TestLowerBoundFunc(t *testing.T) { a := []int{1, 2, 4, 5, 5, 6} expectEq(t, LowerBoundFunc(a, 1, Less[int]), 0) expectEq(t, LowerBoundFunc(a, 5, Less[int]), 3) expectEq(t, LowerBoundFunc(a, 7, Less[int]), len(a)) } func TestUpperBound(t *testing.T) { a := []int{1, 2, 4, 5, 5, 6} expectEq(t, UpperBound(a, 1), 1) expectEq(t, UpperBound(a, 5), 5) expectEq(t, UpperBound(a, 7), len(a)) } func TestUpperBoundFunc(t *testing.T) { a := []int{1, 2, 4, 5, 5, 6} expectEq(t, UpperBoundFunc(a, 1, Less[int]), 1) expectEq(t, UpperBoundFunc(a, 5, Less[int]), 5) expectEq(t, UpperBoundFunc(a, 7, Less[int]), len(a)) } func TestBinarySearch(t *testing.T) { a := []int{1, 2, 4, 5, 5, 6} i, ok := BinarySearch(a, 4) expectTrue(t, ok) expectEq(t, i, 2) i, ok = BinarySearch(a, 5) expectTrue(t, ok) expectEq(t, i, 3) i, ok = BinarySearch(a, 3) expectFalse(t, ok) } func TestBinarySearchFunc(t *testing.T) { a := []int{1, 2, 4, 5, 5, 6} i, ok := BinarySearchFunc(a, 4, Less[int]) expectTrue(t, ok) expectEq(t, i, 2) i, ok = BinarySearchFunc(a, 5, Less[int]) expectTrue(t, ok) expectEq(t, i, 3) i, ok = BinarySearchFunc(a, 3, Less[int]) expectFalse(t, ok) } ================================================ FILE: builtin_set.go ================================================ package stl4go import ( "fmt" ) // BuiltinSet is an associative container that contains an unordered set of unique objects of type K. type BuiltinSet[K comparable] map[K]struct{} // SetOf creates a new BuiltinSet object with the initial content from ks. func SetOf[K comparable](ks ...K) BuiltinSet[K] { s := make(BuiltinSet[K]) s.InsertN(ks...) return s } // IsEmpty implements the Container interface. func (s BuiltinSet[K]) IsEmpty() bool { return len(s) == 0 } // Len implements the Container interface. func (s BuiltinSet[K]) Len() int { return len(s) } // Clear implements the Container interface. func (s BuiltinSet[K]) Clear() { for k := range s { delete(s, k) } } // Has implements the Set interface. func (s BuiltinSet[K]) Has(k K) bool { _, ok := s[k] return ok } // Insert implements the Set interface. func (s BuiltinSet[K]) Insert(k K) bool { oldLen := len(s) s[k] = struct{}{} return len(s) > oldLen } // InsertN implements the Set interface. func (s BuiltinSet[K]) InsertN(ks ...K) int { oldLen := len(s) for _, key := range ks { s[key] = struct{}{} } return len(s) - oldLen } // Remove implements the Set interface. func (s BuiltinSet[K]) Remove(k K) bool { _, ok := s[k] delete(s, k) return ok } // Delete deletes an element from the set. // It returns nothing, so it's faster than Remove. func (s BuiltinSet[K]) Delete(k K) { delete(s, k) } // RemoveN implements the Set interface. func (s BuiltinSet[K]) RemoveN(ks ...K) int { oldLen := len(s) for _, k := range ks { delete(s, k) } return oldLen - len(s) } // Keys return a copy of all keys as a slice. func (s BuiltinSet[K]) Keys() []K { keys := make([]K, 0, len(s)) for k := range s { keys = append(keys, k) } return keys } // ForEach implements the Set interface. func (s BuiltinSet[K]) ForEach(cb func(k K)) { for k := range s { cb(k) } } // ForEachIf implements the Container interface. func (s BuiltinSet[K]) ForEachIf(cb func(k K) bool) { for k := range s { if !cb(k) { break } } } // String implements the fmt.Stringer interface. func (s BuiltinSet[K]) String() string { return fmt.Sprintf("BuiltinSet[%s]%v", nameOfType[K](), s.Keys()) } // Update adds all elements from other to set. set |= other. func (s BuiltinSet[K]) Update(other BuiltinSet[K]) { for k := range other { s[k] = struct{}{} } } // Union returns a new set with elements from the set and other. func (s BuiltinSet[K]) Union(other BuiltinSet[K]) BuiltinSet[K] { result := BuiltinSet[K]{} result.Update(s) result.Update(other) return result } func orderSet[K comparable](a, b BuiltinSet[K]) (small, large BuiltinSet[K]) { if a.Len() < b.Len() { return a, b } return b, a } // Intersection returns a new set with elements common to the set and other. func (s BuiltinSet[K]) Intersection(other BuiltinSet[K]) BuiltinSet[K] { result := BuiltinSet[K]{} small, large := orderSet(s, other) for k := range small { if large.Has(k) { result.Insert(k) } } return result } // Difference returns a new set with elements in the set that are not in other. func (s BuiltinSet[K]) Difference(other BuiltinSet[K]) BuiltinSet[K] { result := BuiltinSet[K]{} for k := range s { if !other.Has(k) { result.Insert(k) } } return result } // IsDisjointOf return True if the set has no elements in common with other. // Sets are disjoint if and only if their intersection is the empty set. func (s BuiltinSet[K]) IsDisjointOf(other BuiltinSet[K]) bool { small, large := orderSet(s, other) for k := range small { if large.Has(k) { return false } } return true } // IsSubsetOf tests whether every element in the set is in other. func (s BuiltinSet[K]) IsSubsetOf(other BuiltinSet[K]) bool { if s.Len() > other.Len() { return false } for k := range s { if !other.Has(k) { return false } } return true } // IsSupersetOf tests whether every element in other is in the set. func (s BuiltinSet[K]) IsSupersetOf(other BuiltinSet[K]) bool { return other.IsSubsetOf(s) } ================================================ FILE: builtin_set_test.go ================================================ package stl4go import ( "fmt" "strings" "testing" ) func Test_BuiltinSet_Interface(t *testing.T) { s := make(BuiltinSet[int]) _ = Set[int](&s) } func Test_MakeBuiltinSet(t *testing.T) { s := make(BuiltinSet[string]) expectEq(t, s.Len(), 0) expectEq(t, s.IsEmpty(), true) } func Test_MakeBuiltinSet2(t *testing.T) { s := BuiltinSet[string]{} expectEq(t, s.Len(), 0) expectEq(t, s.IsEmpty(), true) } func Test_SetOf(t *testing.T) { s := SetOf("hello", "world") expectEq(t, s.Len(), 2) } func Test_BuiltinSet_IsEmpty(t *testing.T) { s := make(BuiltinSet[string]) expectEq(t, s.IsEmpty(), true) s.Insert("hello") expectEq(t, s.IsEmpty(), false) } func Test_BuiltinSet_Clear(t *testing.T) { s := SetOf("hello", "world") s.Clear() expectTrue(t, s.IsEmpty()) } func Test_BuiltinSet_String(t *testing.T) { s := SetOf("hello", "world") expectTrue(t, strings.HasPrefix(fmt.Sprintf("%v", s), "BuiltinSet[string]")) } func Test_BuiltinSet_Has(t *testing.T) { s := SetOf("hello", "world") expectTrue(t, s.Has("hello")) expectTrue(t, s.Has("world")) expectFalse(t, s.Has("!")) } func Test_BuiltinSet_Insert(t *testing.T) { s := make(BuiltinSet[string]) expectTrue(t, s.Insert("hello")) expectFalse(t, s.Insert("hello")) expectEq(t, s.Has("world"), false) expectTrue(t, s.Insert("world")) expectEq(t, s.Has("hello"), true) expectEq(t, s.Len(), 2) } func Test_BuiltinSet_InsertN(t *testing.T) { s := make(BuiltinSet[string]) expectEq(t, s.InsertN("hello", "world"), 2) expectEq(t, s.Len(), 2) } func Test_BuiltinSet_Remove(t *testing.T) { s := SetOf("hello", "world") expectTrue(t, s.Remove("hello")) expectEq(t, s.Len(), 1) expectFalse(t, s.Remove("hello")) expectEq(t, s.Len(), 1) expectTrue(t, s.Remove("world")) expectEq(t, s.Len(), 0) } func Test_BuiltinSet_Delete(t *testing.T) { s := SetOf("hello", "world") s.Delete("hello") expectEq(t, s.Len(), 1) s.Delete("hello") expectEq(t, s.Len(), 1) s.Delete("world") expectEq(t, s.Len(), 0) } func Test_BuiltinSet_RemoveN(t *testing.T) { s := SetOf("hello", "world") expectEq(t, s.RemoveN("hello", "world"), 2) expectFalse(t, s.Remove("world")) expectTrue(t, s.IsEmpty()) } func Test_BuiltinSet_Keys(t *testing.T) { s := SetOf("hello", "world") ks := s.Keys() expectEq(t, 2, len(ks)) } func Test_BuiltinSet_For(t *testing.T) { s := SetOf("hello", "world") for v := range s { expectTrue(t, v == "hello" || v == "world") } } func Test_BuiltinSet_ForEach(t *testing.T) { s := SetOf("hello", "world") c := 0 s.ForEach(func(string) { c++ }) expectEq(t, c, 2) } func Test_BuiltinSet_ForEachIf(t *testing.T) { s := SetOf("hello", "world") c := 0 s.ForEachIf(func(string) bool { c++ return false }) expectLt(t, c, 2) } func Test_BuiltinSet_Update(t *testing.T) { s := SetOf(1, 2, 3) s.Update(SetOf(3, 4)) expectEq(t, s.Len(), 4) expectTrue(t, s.Has(4)) } func Test_BuiltinSet_Union(t *testing.T) { s := SetOf(1, 2, 3) s2 := s.Union(SetOf(3, 4)) expectEq(t, s2.Len(), 4) expectTrue(t, s2.Has(4)) } func Test_BuiltinSet_Intersection(t *testing.T) { s := SetOf(1, 2, 3).Intersection(SetOf(3, 4)) expectEq(t, s.Len(), 1) expectTrue(t, s.Has(3)) s = SetOf(3, 4).Intersection(SetOf(1, 2, 3)) expectEq(t, s.Len(), 1) expectTrue(t, s.Has(3)) } func Test_BuiltinSet_Difference(t *testing.T) { s := SetOf(1, 2, 3).Difference(SetOf(3, 4)) expectEq(t, s.Len(), 2) expectTrue(t, s.Has(1)) expectTrue(t, s.Has(2)) s = SetOf(1, 2).Difference(SetOf(3, 4)) expectEq(t, s.Len(), 2) expectTrue(t, s.Has(1)) expectTrue(t, s.Has(2)) } func Test_BuiltinSet_IsDisjointOf(t *testing.T) { s1 := SetOf(1, 2, 3) s2 := SetOf(3, 4) expectFalse(t, s1.IsDisjointOf(s2)) expectTrue(t, s1.IsDisjointOf(SetOf(4, 5))) } func Test_BuiltinSet_IsSubsetOf(t *testing.T) { expectTrue(t, SetOf[int]().IsSubsetOf(SetOf[int]())) expectTrue(t, SetOf[int]().IsSubsetOf(SetOf(1))) expectTrue(t, SetOf(1, 2, 3).IsSubsetOf(SetOf(1, 2, 3))) expectTrue(t, SetOf(1, 2).IsSubsetOf(SetOf(1, 2, 3))) expectFalse(t, SetOf(1, 2, 3).IsSubsetOf(SetOf(1, 2))) expectFalse(t, SetOf(1, 2).IsSubsetOf(SetOf(2, 3))) } func Test_BuiltinSet_IsSupersetOf(t *testing.T) { expectTrue(t, SetOf[int]().IsSupersetOf(SetOf[int]())) expectTrue(t, SetOf(1).IsSupersetOf(SetOf[int]())) expectTrue(t, SetOf(1, 2, 3).IsSupersetOf(SetOf(1, 2, 3))) expectTrue(t, SetOf(1, 2, 3).IsSupersetOf(SetOf(1, 2))) expectFalse(t, SetOf(1, 2).IsSupersetOf(SetOf(1, 2, 3))) expectFalse(t, SetOf(1, 2).IsSupersetOf(SetOf(2, 3))) } ================================================ FILE: check.bat ================================================ go build go test ./... -coverprofile=coverage.out golint gosec . go tool cover -html=coverage.out ================================================ FILE: check.sh ================================================ #!/bin/bash set -e go build go test ./... -coverprofile=coverage.out golint gosec . go tool cover -html=coverage.out ================================================ FILE: compare.go ================================================ package stl4go // Equal returns whether two slices are equal. // Return true if they are the same length and all elements are equal. // // Complexity: O(min(len(a), len(b))). func Equal[T comparable](a, b []T) bool { if len(a) != len(b) { return false } for i := range a { if a[i] != b[i] { return false } } return true } // Compare compares each elements in a and b. // // return 0 if they are equals, // return 1 if a > b, // return -1 if a < b. // // Complexity: O(min(len(a), len(b))). func Compare[E Ordered](a, b []E) int { bl := len(b) for i, v1 := range a { if i >= bl { return 1 } v2 := b[i] switch { case v1 < v2: return -1 case v1 > v2: return 1 } } if len(a) < bl { return -1 } return 0 } ================================================ FILE: compare_test.go ================================================ package stl4go import "testing" func Test_Equal(t *testing.T) { expectTrue(t, Equal([]int{}, []int{})) expectTrue(t, Equal([]int{1, 2, 3}, []int{1, 2, 3})) expectFalse(t, Equal([]int{1, 2}, []int{1, 2, 3})) expectFalse(t, Equal([]int{1, 2, 2}, []int{1, 2, 3})) } func Test_Compare(t *testing.T) { expectEq(t, Compare([]int{}, []int{}), 0) expectEq(t, Compare([]int{1, 2, 3}, []int{1, 2, 3}), 0) expectEq(t, Compare([]int{1, 2, 2}, []int{1, 2, 3}), -1) expectEq(t, Compare([]int{1, 2, 4}, []int{1, 2, 3}), 1) expectEq(t, Compare([]int{1, 2}, []int{1, 2, 3}), -1) expectEq(t, Compare([]int{1, 2, 3}, []int{1, 2}), 1) } ================================================ FILE: compute.go ================================================ package stl4go // SumAs summarize all elements in a. // returns the result as type R, this is useful when T is too small to hold the result. // Complexity: O(len(a)). func SumAs[R, T Numeric](a []T) R { switch zero := T(0); any(zero).(type) { case int8, int16, int32, int, int64: var total int64 for _, v := range a { total += int64(v) } return R(total) case uint8, uint16, uint32, uint, uint64, uintptr: var total uint64 for _, v := range a { total += uint64(v) } return R(total) default: var total float64 for _, v := range a { total += float64(v) } return R(total) } } // Sum summarize all elements in a. // returns the result as type R, you should use SumAs if T can't hold the result. // Complexity: O(len(a)). func Sum[T Numeric](a []T) T { return SumAs[T](a) } // AverageAs returns the average value of a as type R. func AverageAs[R, T Numeric](a []T) R { return SumAs[R](a) / R(len(a)) } // Average returns the average value of a. func Average[T Numeric](a []T) T { var zero T // NOTE: convert 0 to interface have no malloc switch any(zero).(type) { case int, int8, uint8, int16, uint16, int32, uint32: return T(AverageAs[int64](a)) case uint64: return T(AverageAs[uint64](a)) case float32, float64: return T(AverageAs[float64](a)) } // int64, uint64, uintptr ... return AverageAs[T](a) } // Count returns the number of elements in the slice equals to x. // // Complexity: O(len(a)). func Count[T comparable](a []T, x T) int { c := 0 for _, v := range a { if v == x { c++ } } return c } // CountIf returns the number of elements in the slice which pred returns true. // // Complexity: O(len(a)). func CountIf[T comparable](a []T, pred func(T) bool) int { c := 0 for _, v := range a { if pred(v) { c++ } } return c } ================================================ FILE: compute_test.go ================================================ package stl4go import ( "testing" ) func Test_SumAs(t *testing.T) { t.Run("sum uint8 to int", func(t *testing.T) { a := Range[uint8](1, 101) expectEq(t, SumAs[int](a), 5050) }) t.Run("sum int to uint8", func(t *testing.T) { a := Range[int](1, 101) expectEq(t, SumAs[uint8](a), uint8(5050%256)) }) t.Run("sum int64 to float64", func(t *testing.T) { a := Range[int64](1, 101) expectEq(t, SumAs[float64](a), 5050.) }) t.Run("sum float64 to int64", func(t *testing.T) { a := Range[float64](1.1, 101.1) expectEq(t, SumAs[int](a), 101.2*50) // 5060 }) } func Test_Sum(t *testing.T) { a := Range(1, 101) expectEq(t, Sum(a), 5050) } func Test_Average(t *testing.T) { a := Range(1, 101) expectEq(t, Average(a), 50) } func Test_AverageAs(t *testing.T) { a := []int{1, 0} expectEq(t, AverageAs[float64](a), 0.5) } func Test_Average_U64(t *testing.T) { a := Range[uint64](0, 101) expectEq(t, Average(a), 50) } func Test_Average_Float(t *testing.T) { a := Range(0.0, 101.0) expectEq(t, Average(a), 50.0) } func Test_Average_SmallType(t *testing.T) { a := Range[uint8](0, 101) expectEq(t, Average(a), 50) } func Test_Average_UintPtr(t *testing.T) { a := Range[uintptr](0, 101) expectEq(t, Average(a), 50) } func Test_Average_Signed(t *testing.T) { a := []int{-2, 1, -1, 2, 1, -1, 0} expectEq(t, Average(a), 0) } func Test_Count(t *testing.T) { a := []int{1, 2, 3, 4, 3} expectEq(t, Count(a, 3), 2) expectEq(t, CountIf(pos, isNegative), 0) expectEq(t, CountIf(neg, isNegative), 5) expectEq(t, CountIf(mix, isNegative), 2) } ================================================ FILE: container.go ================================================ package stl4go // Container is a holder object that stores a collection of other objects. type Container interface { IsEmpty() bool // IsEmpty checks if the container has no elements. Len() int // Len returns the number of elements in the container. Clear() // Clear erases all elements from the container. After this call, Len() returns zero. } // Map is a associative container that contains key-value pairs with unique keys. type Map[K any, V any] interface { Container Has(K) bool // Checks whether the container contains element with specific key. Find(K) *V // Finds element with specific key. Insert(K, V) // Inserts a key-value pair in to the container or replace existing value. Remove(K) bool // Remove element with specific key. ForEach(func(K, V)) // Iterate the container. ForEachIf(func(K, V) bool) // Iterate the container, stops when the callback returns false. ForEachMutable(func(K, *V)) // Iterate the container, *V is mutable. ForEachMutableIf(func(K, *V) bool) // Iterate the container, *V is mutable, stops when the callback returns false. } // Set is a containers that store unique elements. type Set[K any] interface { Container Has(K) bool // Checks whether the container contains element with specific key. Insert(K) bool // Inserts a element in to the container or replace existing value. InsertN(...K) int // Inserts multiple elements in to the container or replace existing value. Remove(K) bool // Remove specific element, return true if element was in the container. RemoveN(...K) int // Remove multiple elements, return the number of removed elements. ForEach(func(K)) // Iterate the container. ForEachIf(func(K) bool) // Iterate the container, stops when the callback returns false. } // SortedMap is a Map that provides a total ordering on its keys. type SortedMap[K any, V any] interface { Map[K, V] // LowerBound returns an iterator to the first element in the container that // does not satisfy element.key < value (i.e. greater or equal to), // or a end iterator if no such element is found. LowerBound(K) MutableMapIterator[K, V] // UpperBound returns an iterator to the first element in the container that // does not satisfy value < element.key (i.e. strictly greater), // or a end iterator if no such element is found. UpperBound(K) MutableMapIterator[K, V] // FindRange returns an iterator in range [first, last) (last is not included). FindRange(K, K) MutableMapIterator[K, V] } // SortedSet is a Set that provides a total ordering on its elements. type SortedSet[K any] interface { Set[K] // LowerBound returns an iterator to the first element in the container that // does not satisfy element < value (i.e. greater or equal to), // or a end iterator if no such element is found. LowerBound(K) Iterator[K] // UpperBound returns an iterator to the first element in the container that // does not satisfy value < element (i.e. strictly greater), // or a end iterator if no such element is found. UpperBound(K) Iterator[K] // FindRange returns an iterator in range [first, last) (last is not included). FindRange(K, K) Iterator[K] } // Queue is a container that can add elements to one end and remove elements from the other end. type Queue[T any] interface { Container Front() // Front returns the first element in the container. Back() // Back returns the last element in the container. Push(T) // Push pushes an element at the back of the container. Pop() T // Pop popups a front from the back of the container. TryPop() (T, bool) // TryPop tries to popup a element from the front of the container. } // Deque is a container that can add and remove elements from both ends. type Deque[T any] interface { Container Front() T // Front returns the first element in the container. Back() T // Back returns the last element in the container. PushFront(T) // PushBack pushes an element at the front of the container. PushBack(T) // PushBack pushes an element at the back of the container. PopFront() T // PopBack popups a front from the back of the container. PopBack() T // PopBack popups a element from the back of the container. TryPopFront() (T, bool) // TryPopFront tries to popup a element from the front of the container. TryPopBack() (T, bool) // TryPopBack tries to popup a element from the back of the container. } ================================================ FILE: container_test.go ================================================ package stl4go ================================================ FILE: dlist.go ================================================ package stl4go import "fmt" // DList is a doubly linked list. type DList[T any] struct { head *dListNode[T] length int } type dListNode[T any] struct { prev, next *dListNode[T] value T } // DListOf make a new DList from a serial of values. func DListOf[T any](vs ...T) DList[T] { l := DList[T]{} for _, v := range vs { l.PushBack(v) } return l } // Clear cleanup the list. func (l *DList[T]) Clear() { if l.head != nil { l.head.prev = l.head l.head.next = l.head } l.length = 0 } // Len return the length of the list. func (l *DList[T]) Len() int { return l.length } // IsEmpty return whether the list is empty. func (l *DList[T]) IsEmpty() bool { return l.length == 0 } // String convert the list to string. func (l *DList[T]) String() string { return fmt.Sprintf("DList[%v]", nameOfType[T]()) } type dlistIterator[T any] struct { dl *DList[T] node *dListNode[T] } func (it *dlistIterator[T]) IsNotEnd() bool { return it.node != it.dl.head } func (it *dlistIterator[T]) MoveToNext() { it.node = it.node.next } func (it *dlistIterator[T]) Value() T { return it.node.value } func (it *dlistIterator[T]) Pointer() *T { return &it.node.value } // Iterate returns an iterator to the first element in the list. func (l *DList[T]) Iterate() MutableIterator[T] { node := l.head if node != nil { node = node.next } return &dlistIterator[T]{l, node} } // Front returns the first element in the container. func (l *DList[T]) Front() T { if l.IsEmpty() { panic("!IsEmpty") } return l.head.next.value } // Back returns the last element in the container. func (l *DList[T]) Back() T { if l.IsEmpty() { panic("!IsEmpty") } return l.head.prev.value } // PushFront pushes an element at the front of the list. func (l *DList[T]) PushFront(val T) { l.ensureHead() n := dListNode[T]{l.head, l.head.next, val} l.head.next.prev = &n l.head.next = &n l.length++ } // PushBack pushes an element at the back of the list. func (l *DList[T]) PushBack(val T) { l.ensureHead() n := dListNode[T]{l.head.prev, l.head, val} l.head.prev.next = &n l.head.prev = &n l.length++ } // PopFront popups an element from the front of the list. func (l *DList[T]) PopFront() T { r, ok := l.TryPopFront() if !ok { panic("DList.PopFront: empty list") } return r } // PopBack popups an element from the back of the list. func (l *DList[T]) PopBack() T { r, ok := l.TryPopBack() if !ok { panic("DList.PopBack: empty list") } return r } // TryPopFront tries to pop up an element from the front of the list. func (l *DList[T]) TryPopFront() (T, bool) { var val T if l.IsEmpty() { return val, false } node := l.head.next val = node.value l.head.next = node.next l.head.next.prev = l.head node.prev = nil node.next = nil l.length-- return val, true } // TryPopBack tries to pop up an element from the back of the list. func (l *DList[T]) TryPopBack() (T, bool) { var val T if l.IsEmpty() { return val, false } node := l.head.prev val = node.value l.head.prev = l.head.prev.prev l.head.prev.next = l.head node.prev = nil node.next = nil l.length-- return val, true } // ForEach iterate the list, apply each element to the cb callback function. func (l *DList[T]) ForEach(cb func(val T)) { if l.IsEmpty() { return } for n := l.head.next; n != l.head; n = n.next { cb(n.value) } } // ForEachIf iterate the list, apply each element to the cb callback function, // stop if cb returns false. func (l *DList[T]) ForEachIf(cb func(val T) bool) { if l.IsEmpty() { return } for n := l.head.next; n != l.head; n = n.next { if !cb(n.value) { break } } } // ForEachMutable iterate the list, apply pointer of each element to the cb callback function. func (l *DList[T]) ForEachMutable(cb func(val *T)) { if l.IsEmpty() { return } for n := l.head.next; n != l.head; n = n.next { cb(&n.value) } } // ForEachMutableIf iterate the list, apply pointer of each element to the cb callback function, // stop if cb returns false. func (l *DList[T]) ForEachMutableIf(cb func(val *T) bool) { if l.IsEmpty() { return } for n := l.head.next; n != l.head; n = n.next { if !cb(&n.value) { break } } } // ensureHead ensure head is valid. func (l *DList[T]) ensureHead() { if l.head == nil { l.head = &dListNode[T]{} l.head.prev = l.head l.head.next = l.head } } ================================================ FILE: dlist_queue.go ================================================ package stl4go import ( "fmt" ) // DListQueue is a FIFO container type DListQueue[T any] struct { list DList[T] } // NewDListQueue create a new Queue object. func NewDListQueue[T any]() *DListQueue[T] { q := DListQueue[T]{} return &q } // Len implements the Container interface. func (q *DListQueue[T]) Len() int { return q.list.Len() } // IsEmpty implements the Container interface. func (q *DListQueue[T]) IsEmpty() bool { return q.list.IsEmpty() } // Clear implements the Container interface. func (q *DListQueue[T]) Clear() { q.list.Clear() } // Len implements the fmt.Stringer interface. func (q *DListQueue[T]) String() string { return fmt.Sprintf("Queue[%v]", nameOfType[T]()) } // Front returns the first element in the container. func (q *DListQueue[T]) Front() T { return q.list.Front() } // Back returns the last element in the container. func (q *DListQueue[T]) Back() T { return q.list.Back() } // PushFront pushed an element to the front of the queue. func (q *DListQueue[T]) PushFront(val T) { q.list.PushFront(val) } // PushBack pushed an element to the back of the queue. func (q *DListQueue[T]) PushBack(val T) { q.list.PushBack(val) } // PopFront popups an element from the front of the queue. func (q *DListQueue[T]) PopFront() T { return q.list.PopFront() } // PopBack popups an element from the back of the queue. func (q *DListQueue[T]) PopBack() T { return q.list.PopBack() } // TryPopFront tries popuping an element from the front of the queue. func (q *DListQueue[T]) TryPopFront() (T, bool) { return q.list.TryPopFront() } // TryPopBack tries popuping an element from the back of the queue. func (q *DListQueue[T]) TryPopBack() (T, bool) { return q.list.TryPopBack() } ================================================ FILE: dlist_queue_test.go ================================================ package stl4go import ( "testing" ) func Test_Queue_Interface(t *testing.T) { q := NewDListQueue[int]() _ = Deque[int](q) } func Test_Queue_New(t *testing.T) { q := NewDListQueue[int]() expectTrue(t, q.IsEmpty()) expectEq(t, q.Len(), 0) } func Test_Queue_Clear(t *testing.T) { q := NewDListQueue[int]() q.PushBack(1) q.Clear() expectTrue(t, q.IsEmpty()) expectEq(t, q.Len(), 0) } func Test_Queue_String(t *testing.T) { q := NewDListQueue[int]() expectEq(t, q.String(), "Queue[int]") } func Test_Queue_Front_Back(t *testing.T) { q := NewDListQueue[int]() expectPanic(t, func() { q.Front() }) expectPanic(t, func() { q.Back() }) q.PushBack(1) q.PushBack(2) expectEq(t, q.Front(), 1) expectEq(t, q.Back(), 2) } func Test_Queue_PushFront(t *testing.T) { q := NewDListQueue[int]() q.PushFront(1) expectFalse(t, q.IsEmpty()) expectEq(t, q.Len(), 1) } func Test_Queue_PushBack(t *testing.T) { q := NewDListQueue[int]() q.PushBack(1) expectFalse(t, q.IsEmpty()) expectEq(t, q.Len(), 1) } func Test_Queue_TryPopFront(t *testing.T) { q := NewDListQueue[int]() _, ok := q.TryPopFront() expectFalse(t, ok) } func Test_Queue_TryPopBack(t *testing.T) { q := NewDListQueue[int]() _, ok := q.TryPopBack() expectFalse(t, ok) } func Test_Queue_PushFront_PopFront(t *testing.T) { q := NewDListQueue[int]() q.PushFront(1) q.PushFront(2) expectEq(t, q.PopFront(), 2) expectEq(t, q.PopFront(), 1) } func Test_Queue_PushFront_PopBack(t *testing.T) { q := NewDListQueue[int]() q.PushFront(1) expectEq(t, q.PopBack(), 1) } func Test_Queue_PushBack_PopFront(t *testing.T) { q := NewDListQueue[int]() q.PushBack(1) expectEq(t, q.PopFront(), 1) } func Test_Queue_PushBack_PopBack(t *testing.T) { q := NewDListQueue[int]() q.PushBack(1) expectEq(t, q.PopBack(), 1) } ================================================ FILE: dlist_test.go ================================================ package stl4go import ( "testing" ) func Test_Dlist_Interface(t *testing.T) { _ = Container(&DList[int]{}) } func Test_DList_New(t *testing.T) { l := DList[int]{} expectTrue(t, l.IsEmpty()) expectEq(t, l.Len(), 0) } func Test_DListOf(t *testing.T) { l := DListOf(1, 2, 3) expectFalse(t, l.IsEmpty()) expectEq(t, l.Len(), 3) } func Test_DList_String(t *testing.T) { l := DList[int]{} expectEq(t, l.String(), "DList[int]") } func Test_DList_Iterate(t *testing.T) { l := DListOf(1, 2, 3) i := 1 for it := l.Iterate(); it.IsNotEnd(); it.MoveToNext() { expectEq(t, it.Value(), i) expectEq(t, *it.Pointer(), i) i++ } expectEq(t, i, 4) } func Test_DList_Iterate_Empty(t *testing.T) { l := DList[int]{} i := 0 for it := l.Iterate(); it.IsNotEnd(); it.MoveToNext() { i++ } expectEq(t, i, 0) } func Test_DList_FrontBack(t *testing.T) { l := DListOf(1, 2, 3) expectEq(t, l.Front(), 1) expectEq(t, l.Back(), 3) } func Test_DList_PushFront(t *testing.T) { l := DList[int]{} l.PushFront(1) expectFalse(t, l.IsEmpty()) expectEq(t, l.Len(), 1) } func Test_DList_PushBack(t *testing.T) { l := DList[int]{} l.PushBack(1) expectFalse(t, l.IsEmpty()) expectEq(t, l.Len(), 1) } func Test_DList_PopFront(t *testing.T) { l := DListOf(1, 2, 3, 4) expectEq(t, l.PopFront(), 1) expectEq(t, l.PopFront(), 2) n, ok := l.TryPopFront() expectEq(t, n, 3) expectTrue(t, ok) n, ok = l.TryPopBack() expectEq(t, n, 4) expectTrue(t, ok) n, ok = l.TryPopFront() expectFalse(t, ok) expectPanic(t, func() { l.PopFront() }) } func Test_DList_PopBack(t *testing.T) { l := DListOf(1, 2, 3, 4) expectEq(t, l.PopBack(), 4) expectEq(t, l.PopBack(), 3) n, ok := l.TryPopBack() expectTrue(t, ok) expectEq(t, n, 2) n, ok = l.TryPopFront() expectTrue(t, ok) expectEq(t, n, 1) n, ok = l.TryPopBack() expectFalse(t, ok) expectPanic(t, func() { l.PopBack() }) } func Test_DList_PushBack_PopFront(t *testing.T) { l := DList[int]{} l.PushBack(1) l.PushBack(2) v := l.PopFront() expectEq(t, v, 1) expectEq(t, l.PopFront(), 2) } func Test_DList_PushBack_PopBack(t *testing.T) { l := DList[int]{} l.PushBack(1) v := l.PopBack() expectEq(t, v, 1) } func Test_DList_PushFront_PopBack(t *testing.T) { l := DList[int]{} l.PushFront(1) v := l.PopBack() expectEq(t, v, 1) } func Test_DList_PushFront_PopFront(t *testing.T) { l := DList[int]{} l.PushFront(1) v := l.PopFront() expectEq(t, v, 1) } func Test_DList_ForEach(t *testing.T) { a := []int{1, 2, 3} l := DListOf(a...) var b []int l.ForEach(func(n int) { b = append(b, n) }) expectEq(t, len(b), 3) expectTrue(t, Equal(a, b)) } func Test_DList_ForEachIf(t *testing.T) { l := DListOf(1, 2, 3) c := 0 l.ForEachIf(func(n int) bool { c = n return n != 2 }) expectEq(t, c, 2) } func Test_DList_ForEachMutable(t *testing.T) { a := []int{1, 2, 3} l := DListOf(a...) l.ForEachMutable(func(n *int) { *n = -*n }) var b []int l.ForEach(func(n int) { b = append(b, n) }) expectEq(t, len(b), 3) for i := range b { expectEq(t, a[i], -b[i]) } } func Test_DList_ForEachMutableIf(t *testing.T) { l := DListOf(1, 2, 3) c := 0 l.ForEachMutableIf(func(n *int) bool { c = *n return *n != 2 }) expectEq(t, c, 2) } func Test_DList_ForEach_EmptyOK(t *testing.T) { l := DList[int]{} l.ForEach(func(n int) {}) l.ForEachIf(func(n int) bool { return true }) l.ForEachMutable(func(n *int) {}) l.ForEachMutableIf(func(n *int) bool { return true }) } func Benchmark_DList_Iterate(b *testing.B) { l := DListOf(Range(1, 10000)...) b.Run("Iterator", func(b *testing.B) { sum := 0 for i := 0; i < b.N; i++ { for it := l.Iterate(); it.IsNotEnd(); it.MoveToNext() { sum += it.Value() } } }) b.Run("ForEach", func(b *testing.B) { sum := 0 for i := 0; i < b.N; i++ { l.ForEach(func(val int) { sum += val }) } }) } ================================================ FILE: doc.go ================================================ // Package stl4go is a generic container and algorithm library for go. package stl4go ================================================ FILE: functor.go ================================================ package stl4go // Less wraps the '<' operator for ordered types. func Less[T Ordered](a, b T) bool { return a < b } // Greater wraps the '>' operator for ordered types. func Greater[T Ordered](a, b T) bool { return a > b } // OrderedCompare provide default CompareFn for ordered types. func OrderedCompare[T Ordered](a, b T) int { if a < b { return -1 } if a > b { return 1 } return 0 } ================================================ FILE: generate.go ================================================ package stl4go // Range make a []T filled with values in the `[first, last)` sequence. // NOTE: the last is not included in the result. // // Complexity: O(last-first). func Range[T Numeric](first, last T) []T { a := make([]T, 0, int(last-first)) for v := first; v < last; v++ { a = append(a, v) } return a } // Generate fill each element of `a`` with `gen()`. // // Complexity: O(len(a)). func Generate[T any](a []T, gen func() T) { for i := range a { a[i] = gen() } } ================================================ FILE: generate_test.go ================================================ package stl4go import "testing" func Test_Range(t *testing.T) { a := Range(0, 100) expectEq(t, len(a), 100) expectEq(t, a[0], 0) expectEq(t, a[99], 99) } func Test_Generate(t *testing.T) { a := make([]int, 100) i := -1 Generate(a, func() int { i++; return i }) for i, v := range a { expectEq(t, v, i) } } ================================================ FILE: generated_doc.md ================================================ # stl4go ```go import "github.com/chen3feng/stl4go" ``` Package stl4go is a generic container and algorithm library for go. ## Index - [func AllOf\[T any\]\(a \[\]T, pred func\(T\) bool\) bool](<#AllOf>) - [func AnyOf\[T any\]\(a \[\]T, pred func\(T\) bool\) bool](<#AnyOf>) - [func Average\[T Numeric\]\(a \[\]T\) T](<#Average>) - [func AverageAs\[R, T Numeric\]\(a \[\]T\) R](<#AverageAs>) - [func BinarySearch\[T Ordered\]\(a \[\]T, value T\) \(index int, ok bool\)](<#BinarySearch>) - [func BinarySearchFunc\[T any\]\(a \[\]T, value T, less LessFn\[T\]\) \(index int, ok bool\)](<#BinarySearchFunc>) - [func Compare\[E Ordered\]\(a, b \[\]E\) int](<#Compare>) - [func Copy\[T any\]\(a \[\]T\) \[\]T](<#Copy>) - [func CopyTo\[T any\]\(a \[\]T, to \[\]T\) \[\]T](<#CopyTo>) - [func Count\[T comparable\]\(a \[\]T, x T\) int](<#Count>) - [func CountIf\[T comparable\]\(a \[\]T, pred func\(T\) bool\) int](<#CountIf>) - [func DescSort\[T Ordered\]\(a \[\]T\)](<#DescSort>) - [func DescStableSort\[T Ordered\]\(a \[\]T\)](<#DescStableSort>) - [func Equal\[T comparable\]\(a, b \[\]T\) bool](<#Equal>) - [func Fill\[T any\]\(a \[\]T, v T\)](<#Fill>) - [func FillPattern\[T any\]\(a \[\]T, pattern \[\]T\)](<#FillPattern>) - [func FillZero\[T any\]\(a \[\]T\)](<#FillZero>) - [func Find\[T comparable\]\(a \[\]T, x T\) \(index int, ok bool\)](<#Find>) - [func FindIf\[T any\]\(a \[\]T, cond func\(T\) bool\) \(index int, ok bool\)](<#FindIf>) - [func Generate\[T any\]\(a \[\]T, gen func\(\) T\)](<#Generate>) - [func Greater\[T Ordered\]\(a, b T\) bool](<#Greater>) - [func Index\[T comparable\]\(a \[\]T, x T\) int](<#Index>) - [func IsDescSorted\[T Ordered\]\(a \[\]T\) bool](<#IsDescSorted>) - [func IsHeapFunc\[T any\]\(array \[\]T, less LessFn\[T\]\) bool](<#IsHeapFunc>) - [func IsMinHeap\[T Ordered\]\(array \[\]T\) bool](<#IsMinHeap>) - [func IsSorted\[T Ordered\]\(a \[\]T\) bool](<#IsSorted>) - [func Less\[T Ordered\]\(a, b T\) bool](<#Less>) - [func LowerBound\[T Ordered\]\(a \[\]T, value T\) int](<#LowerBound>) - [func LowerBoundFunc\[T any\]\(a \[\]T, value T, less LessFn\[T\]\) int](<#LowerBoundFunc>) - [func MakeHeapFunc\[T any\]\(array \[\]T, less LessFn\[T\]\)](<#MakeHeapFunc>) - [func MakeMinHeap\[T Ordered\]\(array \[\]T\)](<#MakeMinHeap>) - [func Max\[T Ordered\]\(a, b T\) T](<#Max>) - [func MaxN\[T Ordered\]\(a ...T\) T](<#MaxN>) - [func Min\[T Ordered\]\(a, b T\) T](<#Min>) - [func MinMax\[T Ordered\]\(a, b T\) \(min, max T\)](<#MinMax>) - [func MinMaxN\[T Ordered\]\(a ...T\) \(min, max T\)](<#MinMaxN>) - [func MinN\[T Ordered\]\(a ...T\) T](<#MinN>) - [func NoneOf\[T any\]\(a \[\]T, pred func\(T\) bool\) bool](<#NoneOf>) - [func OrderedCompare\[T Ordered\]\(a, b T\) int](<#OrderedCompare>) - [func PopHeapFunc\[T any\]\(heap \*\[\]T, less LessFn\[T\]\) T](<#PopHeapFunc>) - [func PopMinHeap\[T Ordered\]\(heap \*\[\]T\) T](<#PopMinHeap>) - [func PushHeapFunc\[T any\]\(heap \*\[\]T, v T, less LessFn\[T\]\)](<#PushHeapFunc>) - [func PushMinHeap\[T Ordered\]\(heap \*\[\]T, v T\)](<#PushMinHeap>) - [func Range\[T Numeric\]\(first, last T\) \[\]T](<#Range>) - [func Remove\[T comparable\]\(a \[\]T, x T\) \[\]T](<#Remove>) - [func RemoveCopy\[T comparable\]\(a \[\]T, x T\) \[\]T](<#RemoveCopy>) - [func RemoveHeapFunc\[T any\]\(heap \*\[\]T, i int, less LessFn\[T\]\) T](<#RemoveHeapFunc>) - [func RemoveIf\[T any\]\(a \[\]T, cond func\(T\) bool\) \[\]T](<#RemoveIf>) - [func RemoveIfCopy\[T any\]\(a \[\]T, cond func\(T\) bool\) \[\]T](<#RemoveIfCopy>) - [func RemoveMinHeap\[T Ordered\]\(heap \*\[\]T, i int\) T](<#RemoveMinHeap>) - [func Replace\[T comparable\]\(a \[\]T, old, new T\)](<#Replace>) - [func ReplaceIf\[T any\]\(a \[\]T, pred func\(v T\) bool, new T\)](<#ReplaceIf>) - [func Reverse\[T any\]\(a \[\]T\)](<#Reverse>) - [func ReverseCopy\[T any\]\(a \[\]T\) \[\]T](<#ReverseCopy>) - [func Shuffle\[T any\]\(a \[\]T\)](<#Shuffle>) - [func Sort\[T Ordered\]\(a \[\]T\)](<#Sort>) - [func SortFunc\[T any\]\(a \[\]T, less func\(x, y T\) bool\)](<#SortFunc>) - [func StableSort\[T Ordered\]\(a \[\]T\)](<#StableSort>) - [func StableSortFunc\[T any\]\(a \[\]T, less func\(x, y T\) bool\)](<#StableSortFunc>) - [func Sum\[T Numeric\]\(a \[\]T\) T](<#Sum>) - [func SumAs\[R, T Numeric\]\(a \[\]T\) R](<#SumAs>) - [func Transform\[T any\]\(a \[\]T, op func\(T\) T\)](<#Transform>) - [func TransformCopy\[R any, T any\]\(a \[\]T, op func\(T\) R\) \[\]R](<#TransformCopy>) - [func TransformTo\[R any, T any\]\(a \[\]T, op func\(T\) R, b \[\]R\) \[\]R](<#TransformTo>) - [func Unique\[T comparable\]\(a \[\]T\) \[\]T](<#Unique>) - [func UniqueCopy\[T comparable\]\(a \[\]T\) \[\]T](<#UniqueCopy>) - [func UpperBound\[T Ordered\]\(a \[\]T, value T\) int](<#UpperBound>) - [func UpperBoundFunc\[T any\]\(a \[\]T, value T, less LessFn\[T\]\) int](<#UpperBoundFunc>) - [type BuiltinSet](<#BuiltinSet>) - [func SetOf\[K comparable\]\(ks ...K\) BuiltinSet\[K\]](<#SetOf>) - [func \(s BuiltinSet\[K\]\) Clear\(\)](<#BuiltinSet[K].Clear>) - [func \(s BuiltinSet\[K\]\) Delete\(k K\)](<#BuiltinSet[K].Delete>) - [func \(s BuiltinSet\[K\]\) Difference\(other BuiltinSet\[K\]\) BuiltinSet\[K\]](<#BuiltinSet[K].Difference>) - [func \(s BuiltinSet\[K\]\) ForEach\(cb func\(k K\)\)](<#BuiltinSet[K].ForEach>) - [func \(s BuiltinSet\[K\]\) ForEachIf\(cb func\(k K\) bool\)](<#BuiltinSet[K].ForEachIf>) - [func \(s BuiltinSet\[K\]\) Has\(k K\) bool](<#BuiltinSet[K].Has>) - [func \(s BuiltinSet\[K\]\) Insert\(k K\) bool](<#BuiltinSet[K].Insert>) - [func \(s BuiltinSet\[K\]\) InsertN\(ks ...K\) int](<#BuiltinSet[K].InsertN>) - [func \(s BuiltinSet\[K\]\) Intersection\(other BuiltinSet\[K\]\) BuiltinSet\[K\]](<#BuiltinSet[K].Intersection>) - [func \(s BuiltinSet\[K\]\) IsDisjointOf\(other BuiltinSet\[K\]\) bool](<#BuiltinSet[K].IsDisjointOf>) - [func \(s BuiltinSet\[K\]\) IsEmpty\(\) bool](<#BuiltinSet[K].IsEmpty>) - [func \(s BuiltinSet\[K\]\) IsSubsetOf\(other BuiltinSet\[K\]\) bool](<#BuiltinSet[K].IsSubsetOf>) - [func \(s BuiltinSet\[K\]\) IsSupersetOf\(other BuiltinSet\[K\]\) bool](<#BuiltinSet[K].IsSupersetOf>) - [func \(s BuiltinSet\[K\]\) Keys\(\) \[\]K](<#BuiltinSet[K].Keys>) - [func \(s BuiltinSet\[K\]\) Len\(\) int](<#BuiltinSet[K].Len>) - [func \(s BuiltinSet\[K\]\) Remove\(k K\) bool](<#BuiltinSet[K].Remove>) - [func \(s BuiltinSet\[K\]\) RemoveN\(ks ...K\) int](<#BuiltinSet[K].RemoveN>) - [func \(s BuiltinSet\[K\]\) String\(\) string](<#BuiltinSet[K].String>) - [func \(s BuiltinSet\[K\]\) Union\(other BuiltinSet\[K\]\) BuiltinSet\[K\]](<#BuiltinSet[K].Union>) - [func \(s BuiltinSet\[K\]\) Update\(other BuiltinSet\[K\]\)](<#BuiltinSet[K].Update>) - [type CompareFn](<#CompareFn>) - [type Container](<#Container>) - [type DList](<#DList>) - [func DListOf\[T any\]\(vs ...T\) DList\[T\]](<#DListOf>) - [func \(l \*DList\[T\]\) Back\(\) T](<#DList[T].Back>) - [func \(l \*DList\[T\]\) Clear\(\)](<#DList[T].Clear>) - [func \(l \*DList\[T\]\) ForEach\(cb func\(val T\)\)](<#DList[T].ForEach>) - [func \(l \*DList\[T\]\) ForEachIf\(cb func\(val T\) bool\)](<#DList[T].ForEachIf>) - [func \(l \*DList\[T\]\) ForEachMutable\(cb func\(val \*T\)\)](<#DList[T].ForEachMutable>) - [func \(l \*DList\[T\]\) ForEachMutableIf\(cb func\(val \*T\) bool\)](<#DList[T].ForEachMutableIf>) - [func \(l \*DList\[T\]\) Front\(\) T](<#DList[T].Front>) - [func \(l \*DList\[T\]\) IsEmpty\(\) bool](<#DList[T].IsEmpty>) - [func \(l \*DList\[T\]\) Iterate\(\) MutableIterator\[T\]](<#DList[T].Iterate>) - [func \(l \*DList\[T\]\) Len\(\) int](<#DList[T].Len>) - [func \(l \*DList\[T\]\) PopBack\(\) T](<#DList[T].PopBack>) - [func \(l \*DList\[T\]\) PopFront\(\) T](<#DList[T].PopFront>) - [func \(l \*DList\[T\]\) PushBack\(val T\)](<#DList[T].PushBack>) - [func \(l \*DList\[T\]\) PushFront\(val T\)](<#DList[T].PushFront>) - [func \(l \*DList\[T\]\) String\(\) string](<#DList[T].String>) - [func \(l \*DList\[T\]\) TryPopBack\(\) \(T, bool\)](<#DList[T].TryPopBack>) - [func \(l \*DList\[T\]\) TryPopFront\(\) \(T, bool\)](<#DList[T].TryPopFront>) - [type DListQueue](<#DListQueue>) - [func NewDListQueue\[T any\]\(\) \*DListQueue\[T\]](<#NewDListQueue>) - [func \(q \*DListQueue\[T\]\) Back\(\) T](<#DListQueue[T].Back>) - [func \(q \*DListQueue\[T\]\) Clear\(\)](<#DListQueue[T].Clear>) - [func \(q \*DListQueue\[T\]\) Front\(\) T](<#DListQueue[T].Front>) - [func \(q \*DListQueue\[T\]\) IsEmpty\(\) bool](<#DListQueue[T].IsEmpty>) - [func \(q \*DListQueue\[T\]\) Len\(\) int](<#DListQueue[T].Len>) - [func \(q \*DListQueue\[T\]\) PopBack\(\) T](<#DListQueue[T].PopBack>) - [func \(q \*DListQueue\[T\]\) PopFront\(\) T](<#DListQueue[T].PopFront>) - [func \(q \*DListQueue\[T\]\) PushBack\(val T\)](<#DListQueue[T].PushBack>) - [func \(q \*DListQueue\[T\]\) PushFront\(val T\)](<#DListQueue[T].PushFront>) - [func \(q \*DListQueue\[T\]\) String\(\) string](<#DListQueue[T].String>) - [func \(q \*DListQueue\[T\]\) TryPopBack\(\) \(T, bool\)](<#DListQueue[T].TryPopBack>) - [func \(q \*DListQueue\[T\]\) TryPopFront\(\) \(T, bool\)](<#DListQueue[T].TryPopFront>) - [type Deque](<#Deque>) - [type Float](<#Float>) - [type HashFn](<#HashFn>) - [type Integer](<#Integer>) - [type Iterator](<#Iterator>) - [type LessFn](<#LessFn>) - [type Map](<#Map>) - [type MapIterator](<#MapIterator>) - [type MutableIterator](<#MutableIterator>) - [type MutableMapIterator](<#MutableMapIterator>) - [type Numeric](<#Numeric>) - [type Ordered](<#Ordered>) - [type Pool](<#Pool>) - [func MakePool\[T any\]\(\) Pool\[T\]](<#MakePool>) - [func MakePoolWithNew\[T any\]\(new func\(\) \*T\) Pool\[T\]](<#MakePoolWithNew>) - [func \(pool \*Pool\[T\]\) Get\(\) \*T](<#Pool[T].Get>) - [func \(pool \*Pool\[T\]\) Put\(x \*T\)](<#Pool[T].Put>) - [type PriorityQueue](<#PriorityQueue>) - [func NewPriorityQueue\[T Ordered\]\(\) \*PriorityQueue\[T\]](<#NewPriorityQueue>) - [func NewPriorityQueueFunc\[T any\]\(less LessFn\[T\]\) \*PriorityQueue\[T\]](<#NewPriorityQueueFunc>) - [func NewPriorityQueueOf\[T Ordered\]\(elements ...T\) \*PriorityQueue\[T\]](<#NewPriorityQueueOf>) - [func NewPriorityQueueOn\[T Ordered\]\(slice \[\]T\) \*PriorityQueue\[T\]](<#NewPriorityQueueOn>) - [func \(pq \*PriorityQueue\[T\]\) Clear\(\)](<#PriorityQueue[T].Clear>) - [func \(pq \*PriorityQueue\[T\]\) IsEmpty\(\) bool](<#PriorityQueue[T].IsEmpty>) - [func \(pq \*PriorityQueue\[T\]\) Len\(\) int](<#PriorityQueue[T].Len>) - [func \(pq \*PriorityQueue\[T\]\) Pop\(\) T](<#PriorityQueue[T].Pop>) - [func \(pq \*PriorityQueue\[T\]\) Push\(v T\)](<#PriorityQueue[T].Push>) - [func \(pq \*PriorityQueue\[T\]\) Top\(\) T](<#PriorityQueue[T].Top>) - [type Queue](<#Queue>) - [type SList](<#SList>) - [func SListOf\[T any\]\(values ...T\) SList\[T\]](<#SListOf>) - [func \(l \*SList\[T\]\) Back\(\) T](<#SList[T].Back>) - [func \(l \*SList\[T\]\) Clear\(\)](<#SList[T].Clear>) - [func \(l \*SList\[T\]\) ForEach\(cb func\(T\)\)](<#SList[T].ForEach>) - [func \(l \*SList\[T\]\) ForEachIf\(cb func\(T\) bool\)](<#SList[T].ForEachIf>) - [func \(l \*SList\[T\]\) ForEachMutable\(cb func\(\*T\)\)](<#SList[T].ForEachMutable>) - [func \(l \*SList\[T\]\) ForEachMutableIf\(cb func\(\*T\) bool\)](<#SList[T].ForEachMutableIf>) - [func \(l \*SList\[T\]\) Front\(\) T](<#SList[T].Front>) - [func \(l \*SList\[T\]\) IsEmpty\(\) bool](<#SList[T].IsEmpty>) - [func \(l \*SList\[T\]\) Iterate\(\) MutableIterator\[T\]](<#SList[T].Iterate>) - [func \(l \*SList\[T\]\) Len\(\) int](<#SList[T].Len>) - [func \(l \*SList\[T\]\) PopFront\(\) T](<#SList[T].PopFront>) - [func \(l \*SList\[T\]\) PushBack\(v T\)](<#SList[T].PushBack>) - [func \(l \*SList\[T\]\) PushFront\(v T\)](<#SList[T].PushFront>) - [func \(l \*SList\[T\]\) Reverse\(\)](<#SList[T].Reverse>) - [func \(l \*SList\[T\]\) Values\(\) \[\]T](<#SList[T].Values>) - [type Set](<#Set>) - [type Signed](<#Signed>) - [type SkipList](<#SkipList>) - [func NewSkipList\[K Ordered, V any\]\(\) \*SkipList\[K, V\]](<#NewSkipList>) - [func NewSkipListFromMap\[K Ordered, V any\]\(m map\[K\]V\) \*SkipList\[K, V\]](<#NewSkipListFromMap>) - [func NewSkipListFunc\[K any, V any\]\(keyCmp CompareFn\[K\]\) \*SkipList\[K, V\]](<#NewSkipListFunc>) - [func \(sl \*SkipList\[K, V\]\) Clear\(\)](<#SkipList[K, V].Clear>) - [func \(sl \*SkipList\[K, V\]\) Find\(key K\) \*V](<#SkipList[K, V].Find>) - [func \(sl \*SkipList\[K, V\]\) FindRange\(first, last K\) MutableMapIterator\[K, V\]](<#SkipList[K, V].FindRange>) - [func \(sl \*SkipList\[K, V\]\) ForEach\(op func\(K, V\)\)](<#SkipList[K, V].ForEach>) - [func \(sl \*SkipList\[K, V\]\) ForEachIf\(op func\(K, V\) bool\)](<#SkipList[K, V].ForEachIf>) - [func \(sl \*SkipList\[K, V\]\) ForEachMutable\(op func\(K, \*V\)\)](<#SkipList[K, V].ForEachMutable>) - [func \(sl \*SkipList\[K, V\]\) ForEachMutableIf\(op func\(K, \*V\) bool\)](<#SkipList[K, V].ForEachMutableIf>) - [func \(sl \*SkipList\[K, V\]\) Has\(key K\) bool](<#SkipList[K, V].Has>) - [func \(sl \*SkipList\[K, V\]\) Insert\(key K, value V\)](<#SkipList[K, V].Insert>) - [func \(sl \*SkipList\[K, V\]\) IsEmpty\(\) bool](<#SkipList[K, V].IsEmpty>) - [func \(sl \*SkipList\[K, V\]\) Iterate\(\) MutableMapIterator\[K, V\]](<#SkipList[K, V].Iterate>) - [func \(sl \*SkipList\[K, V\]\) Len\(\) int](<#SkipList[K, V].Len>) - [func \(sl \*SkipList\[K, V\]\) LowerBound\(key K\) MutableMapIterator\[K, V\]](<#SkipList[K, V].LowerBound>) - [func \(sl \*SkipList\[K, V\]\) Remove\(key K\) bool](<#SkipList[K, V].Remove>) - [func \(sl \*SkipList\[K, V\]\) UpperBound\(key K\) MutableMapIterator\[K, V\]](<#SkipList[K, V].UpperBound>) - [type SkipListSet](<#SkipListSet>) - [func NewSkipListSet\[K Ordered\]\(\) \*SkipListSet\[K\]](<#NewSkipListSet>) - [func NewSkipListSetFunc\[K any\]\(cmp CompareFn\[K\]\) \*SkipListSet\[K\]](<#NewSkipListSetFunc>) - [func NewSkipListSetOf\[K Ordered\]\(elements ...K\) \*SkipListSet\[K\]](<#NewSkipListSetOf>) - [func \(s \*SkipListSet\[K\]\) Clear\(\)](<#SkipListSet[K].Clear>) - [func \(s \*SkipListSet\[K\]\) FindRange\(first, last K\) Iterator\[K\]](<#SkipListSet[K].FindRange>) - [func \(s \*SkipListSet\[K\]\) ForEach\(f func\(K\)\)](<#SkipListSet[K].ForEach>) - [func \(s \*SkipListSet\[K\]\) ForEachIf\(f func\(K\) bool\)](<#SkipListSet[K].ForEachIf>) - [func \(s \*SkipListSet\[K\]\) Has\(key K\) bool](<#SkipListSet[K].Has>) - [func \(s \*SkipListSet\[K\]\) Insert\(key K\) bool](<#SkipListSet[K].Insert>) - [func \(s \*SkipListSet\[K\]\) InsertN\(keys ...K\) int](<#SkipListSet[K].InsertN>) - [func \(s \*SkipListSet\[K\]\) IsEmpty\(\) bool](<#SkipListSet[K].IsEmpty>) - [func \(s \*SkipListSet\[K\]\) Keys\(\) \[\]K](<#SkipListSet[K].Keys>) - [func \(s \*SkipListSet\[K\]\) Len\(\) int](<#SkipListSet[K].Len>) - [func \(s \*SkipListSet\[K\]\) LowerBound\(key K\) Iterator\[K\]](<#SkipListSet[K].LowerBound>) - [func \(s \*SkipListSet\[K\]\) Remove\(key K\) bool](<#SkipListSet[K].Remove>) - [func \(s \*SkipListSet\[K\]\) RemoveN\(keys ...K\) int](<#SkipListSet[K].RemoveN>) - [func \(s \*SkipListSet\[K\]\) UpperBound\(key K\) Iterator\[K\]](<#SkipListSet[K].UpperBound>) - [type SortedMap](<#SortedMap>) - [type SortedSet](<#SortedSet>) - [type Stack](<#Stack>) - [func NewStack\[T any\]\(\) \*Stack\[T\]](<#NewStack>) - [func NewStackCap\[T any\]\(capicity int\) \*Stack\[T\]](<#NewStackCap>) - [func \(s Stack\[T\]\) Cap\(\) int](<#Stack[T].Cap>) - [func \(s \*Stack\[T\]\) Clear\(\)](<#Stack[T].Clear>) - [func \(s Stack\[T\]\) IsEmpty\(\) bool](<#Stack[T].IsEmpty>) - [func \(s Stack\[T\]\) Len\(\) int](<#Stack[T].Len>) - [func \(s \*Stack\[T\]\) Pop\(\) T](<#Stack[T].Pop>) - [func \(s \*Stack\[T\]\) Push\(t T\)](<#Stack[T].Push>) - [func \(s Stack\[T\]\) Top\(\) T](<#Stack[T].Top>) - [func \(s \*Stack\[T\]\) TryPop\(\) \(val T, ok bool\)](<#Stack[T].TryPop>) - [type Unsigned](<#Unsigned>) - [type Vector](<#Vector>) - [func AsVector\[T any\]\(s \[\]T\) Vector\[T\]](<#AsVector>) - [func MakeVector\[T any\]\(\) Vector\[T\]](<#MakeVector>) - [func MakeVectorCap\[T any\]\(c int\) Vector\[T\]](<#MakeVectorCap>) - [func VectorOf\[T any\]\(v ...T\) Vector\[T\]](<#VectorOf>) - [func \(v \*Vector\[T\]\) Append\(x ...T\)](<#Vector[T].Append>) - [func \(v \*Vector\[T\]\) At\(i int\) T](<#Vector[T].At>) - [func \(v Vector\[T\]\) Back\(\) T](<#Vector[T].Back>) - [func \(v \*Vector\[T\]\) Cap\(\) int](<#Vector[T].Cap>) - [func \(v \*Vector\[T\]\) Clear\(\)](<#Vector[T].Clear>) - [func \(v Vector\[T\]\) ForEach\(cb func\(val T\)\)](<#Vector[T].ForEach>) - [func \(v Vector\[T\]\) ForEachIf\(cb func\(val T\) bool\)](<#Vector[T].ForEachIf>) - [func \(v Vector\[T\]\) ForEachMutable\(cb func\(val \*T\)\)](<#Vector[T].ForEachMutable>) - [func \(v Vector\[T\]\) ForEachMutableIf\(cb func\(val \*T\) bool\)](<#Vector[T].ForEachMutableIf>) - [func \(v \*Vector\[T\]\) Insert\(i int, x ...T\)](<#Vector[T].Insert>) - [func \(v \*Vector\[T\]\) IsEmpty\(\) bool](<#Vector[T].IsEmpty>) - [func \(v Vector\[T\]\) Iterate\(\) MutableIterator\[T\]](<#Vector[T].Iterate>) - [func \(v Vector\[T\]\) IterateRange\(i, j int\) MutableIterator\[T\]](<#Vector[T].IterateRange>) - [func \(v \*Vector\[T\]\) Len\(\) int](<#Vector[T].Len>) - [func \(v \*Vector\[T\]\) PopBack\(\) T](<#Vector[T].PopBack>) - [func \(v \*Vector\[T\]\) PushBack\(x T\)](<#Vector[T].PushBack>) - [func \(v \*Vector\[T\]\) Remove\(i int\)](<#Vector[T].Remove>) - [func \(v \*Vector\[T\]\) RemoveIf\(cond func\(T\) bool\)](<#Vector[T].RemoveIf>) - [func \(v \*Vector\[T\]\) RemoveLength\(i int, len int\)](<#Vector[T].RemoveLength>) - [func \(v \*Vector\[T\]\) RemoveRange\(i, j int\)](<#Vector[T].RemoveRange>) - [func \(v \*Vector\[T\]\) Reserve\(l int\)](<#Vector[T].Reserve>) - [func \(v \*Vector\[T\]\) Set\(i int, x T\)](<#Vector[T].Set>) - [func \(v \*Vector\[T\]\) Shrink\(\)](<#Vector[T].Shrink>) - [func \(v \*Vector\[T\]\) TryPopBack\(\) \(T, bool\)](<#Vector[T].TryPopBack>) ## func [AllOf]() ```go func AllOf[T any](a []T, pred func(T) bool) bool ``` AllOf return true if pred\(e\) returns true for all elements e in a. Complexity: O\(len\(a\)\). ## func [AnyOf]() ```go func AnyOf[T any](a []T, pred func(T) bool) bool ``` AnyOf return true if pred\(e\) returns true for any elements e in a. Complexity: O\(len\(a\)\). ## func [Average]() ```go func Average[T Numeric](a []T) T ``` Average returns the average value of a. ## func [AverageAs]() ```go func AverageAs[R, T Numeric](a []T) R ``` AverageAs returns the average value of a as type R. ## func [BinarySearch]() ```go func BinarySearch[T Ordered](a []T, value T) (index int, ok bool) ``` 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. Complexity: O\(log\(len\(a\)\)\). ## func [BinarySearchFunc]() ```go func BinarySearchFunc[T any](a []T, value T, less LessFn[T]) (index int, ok bool) ``` 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. The elements in the slice a should sorted according with compare func less. Complexity: O\(log\(len\(a\)\)\). ## func [Compare]() ```go func Compare[E Ordered](a, b []E) int ``` Compare compares each elements in a and b. return 0 if they are equals, return 1 if a \> b, return \-1 if a \< b. Complexity: O\(min\(len\(a\), len\(b\)\)\). ## func [Copy]() ```go func Copy[T any](a []T) []T ``` Copy make a copy of slice a. Complexity: O\(len\(a\)\). ## func [CopyTo]() ```go func CopyTo[T any](a []T, to []T) []T ``` CopyTo copies all elements in slice a to slice to, return the copied slice. if slice to is large enough, no memory allocation occurs. Complexity: O\(len\(a\)\). ## func [Count]() ```go func Count[T comparable](a []T, x T) int ``` Count returns the number of elements in the slice equals to x. Complexity: O\(len\(a\)\). ## func [CountIf]() ```go func CountIf[T comparable](a []T, pred func(T) bool) int ``` CountIf returns the number of elements in the slice which pred returns true. Complexity: O\(len\(a\)\). ## func [DescSort]() ```go func DescSort[T Ordered](a []T) ``` DescSort sorts data in descending order. The order of equal elements is not guaranteed to be preserved. Complexity: O\(N\*log\(N\)\), N=len\(a\). ## func [DescStableSort]() ```go func DescStableSort[T Ordered](a []T) ``` DescStableSort sorts data in descending order stably. The order of equivalent elements is guaranteed to be preserved. Complexity: O\(N\*log\(N\)\), N=len\(a\). ## func [Equal]() ```go func Equal[T comparable](a, b []T) bool ``` Equal returns whether two slices are equal. Return true if they are the same length and all elements are equal. Complexity: O\(min\(len\(a\), len\(b\)\)\). ## func [Fill]() ```go func Fill[T any](a []T, v T) ``` Fill fills each element in slice a with new value v. Complexity: O\(len\(a\)\). ## func [FillPattern]() ```go func FillPattern[T any](a []T, pattern []T) ``` FillPattern fills elements in slice a with specified pattern. Complexity: O\(len\(a\)\). ## func [FillZero]() ```go func FillZero[T any](a []T) ``` FillZero fills each element in slice a with zero value. Complexity: O\(len\(a\)\). ## func [Find]() ```go func Find[T comparable](a []T, x T) (index int, ok bool) ``` Find find the first value x in the given slice a linearly. return \(index, true\) if found, return \(\_, false\) if not found. Complexity: O\(len\(a\)\). ## func [FindIf]() ```go func FindIf[T any](a []T, cond func(T) bool) (index int, ok bool) ``` FindIf find the first value x satisfying function cond in the given slice a linearly. return \(index, true\) if found, return \(\_, false\) if not found. Complexity: O\(len\(a\)\). ## func [Generate]() ```go func Generate[T any](a []T, gen func() T) ``` Generate fill each element of \`a“ with \`gen\(\)\`. Complexity: O\(len\(a\)\). ## func [Greater]() ```go func Greater[T Ordered](a, b T) bool ``` Greater wraps the '\>' operator for ordered types. ## func [Index]() ```go func Index[T comparable](a []T, x T) int ``` Index find the value x in the given slice a linearly. Return index if found, \-1 if not found. Complexity: O\(len\(a\)\). ## func [IsDescSorted]() ```go func IsDescSorted[T Ordered](a []T) bool ``` IsDescSorted returns whether the slice a is sorted in descending order. Complexity: O\(len\(a\)\). ## func [IsHeapFunc]() ```go func IsHeapFunc[T any](array []T, less LessFn[T]) bool ``` IsHeapFunc checks whether the elements in slice array are a min heap \(accord to less\). Complexity: O\(len\(array\)\). ## func [IsMinHeap]() ```go func IsMinHeap[T Ordered](array []T) bool ``` IsMinHeap checks whether the elements in slice array are a min heap. Complexity: O\(len\(array\)\). ## func [IsSorted]() ```go func IsSorted[T Ordered](a []T) bool ``` IsSorted returns whether the slice a is sorted in ascending order. Complexity: O\(len\(a\)\). ## func [Less]() ```go func Less[T Ordered](a, b T) bool ``` Less wraps the '\<' operator for ordered types. ## func [LowerBound]() ```go func LowerBound[T Ordered](a []T, value T) int ``` LowerBound returns an index to the first element in the ascending ordered slice a that does not satisfy element \< value \(i.e. greater or equal to\), or len\(a\) if no such element is found. Complexity: O\(log\(len\(a\)\)\). ## func [LowerBoundFunc]() ```go func LowerBoundFunc[T any](a []T, value T, less LessFn[T]) int ``` 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. The elements in the slice a should sorted according with compare func less. Complexity: O\(log\(len\(a\)\)\). ## func [MakeHeapFunc]() ```go func MakeHeapFunc[T any](array []T, less LessFn[T]) ``` MakeHeapFunc build a min\-heap on slice array with compare function less. Complexity: O\(len\(array\)\) ## func [MakeMinHeap]() ```go func MakeMinHeap[T Ordered](array []T) ``` MakeMinHeap build a min\-heap on slice array. Complexity: O\(len\(array\)\) ## func [Max]() ```go func Max[T Ordered](a, b T) T ``` Max return the larger value between \`a\` and \`b\`. Complexity: O\(1\). ## func [MaxN]() ```go func MaxN[T Ordered](a ...T) T ``` MaxN return the maximum value in the sequence \`a\`. Complexity: O\(len\(a\)\). ## func [Min]() ```go func Min[T Ordered](a, b T) T ``` Min return the smaller value between \`a\` and \`b\`. Complexity: O\(1\). ## func [MinMax]() ```go func MinMax[T Ordered](a, b T) (min, max T) ``` MinMax returns both min and max between a and b. Complexity: O\(1\). ## func [MinMaxN]() ```go func MinMaxN[T Ordered](a ...T) (min, max T) ``` MinMaxN returns both min and max in slice a. Complexity: O\(len\(a\)\) ## func [MinN]() ```go func MinN[T Ordered](a ...T) T ``` MinN return the minimum value in the sequence \`a\`. Complexity: O\(len\(a\)\). ## func [NoneOf]() ```go func NoneOf[T any](a []T, pred func(T) bool) bool ``` NoneOf return true pred\(e\) returns true for none elements e in a. Complexity: O\(len\(a\)\). ## func [OrderedCompare]() ```go func OrderedCompare[T Ordered](a, b T) int ``` OrderedCompare provide default CompareFn for ordered types. ## func [PopHeapFunc]() ```go func PopHeapFunc[T any](heap *[]T, less LessFn[T]) T ``` PopHeapFunc removes and returns the minimum \(according to less\) element from the heap. Complexity: O\(log n\) where n = len\(\*heap\). ## func [PopMinHeap]() ```go func PopMinHeap[T Ordered](heap *[]T) T ``` PopMinHeap removes and returns the minimum element from the heap. Complexity: O\(log n\) where n = len\(\*heap\). ## func [PushHeapFunc]() ```go func PushHeapFunc[T any](heap *[]T, v T, less LessFn[T]) ``` PushHeapFunc pushes a element v into the heap. Complexity: O\(log\(len\(\*heap\)\)\). ## func [PushMinHeap]() ```go func PushMinHeap[T Ordered](heap *[]T, v T) ``` PushMinHeap pushes a element v into the min heap. Complexity: O\(log\(len\(\*heap\)\)\). ## func [Range]() ```go func Range[T Numeric](first, last T) []T ``` Range make a \[\]T filled with values in the \`\[first, last\)\` sequence. NOTE: the last is not included in the result. Complexity: O\(last\-first\). ## func [Remove]() ```go func Remove[T comparable](a []T, x T) []T ``` Remove remove the elements which equals to x from the input slice. return the processed slice with new length. Complexity: O\(len\(a\)\). ## func [RemoveCopy]() ```go func RemoveCopy[T comparable](a []T, x T) []T ``` RemoveCopy remove all elements which equals to x from the input slice. return a new slice with processed results. The input slice is kept unchanged. Complexity: O\(len\(a\)\). ## func [RemoveHeapFunc]() ```go func RemoveHeapFunc[T any](heap *[]T, i int, less LessFn[T]) T ``` RemoveHeapFunc removes and returns the element at index i from the heap. Complexity: is O\(log\(n\)\) where n = len\(\*heap\). ## func [RemoveIf]() ```go func RemoveIf[T any](a []T, cond func(T) bool) []T ``` RemoveIf remove each element which make cond\(x\) returns true from the input slice, copy other elements to a new slice and return it. Complexity: O\(len\(a\)\). ## func [RemoveIfCopy]() ```go func RemoveIfCopy[T any](a []T, cond func(T) bool) []T ``` RemoveIfCopy drops each element which make cond\(x\) returns true from the input slice, copy other elements to a new slice and return it. The input slice is kept unchanged. Complexity: O\(len\(a\)\). ## func [RemoveMinHeap]() ```go func RemoveMinHeap[T Ordered](heap *[]T, i int) T ``` RemoveMinHeap removes and returns the element at index i from the min heap. Complexity: is O\(log\(n\)\) where n = len\(\*heap\). ## func [Replace]() ```go func Replace[T comparable](a []T, old, new T) ``` Replace replaces every element that equals to old with new. Complexity: O\(len\(a\)\). ## func [ReplaceIf]() ```go func ReplaceIf[T any](a []T, pred func(v T) bool, new T) ``` ReplaceIf replaces every element that make preq returns true with new. Complexity: O\(len\(a\)\). ## func [Reverse]() ```go func Reverse[T any](a []T) ``` Reverse reverses the order of the elements in the slice a. Complexity: O\(len\(a\)\). ## func [ReverseCopy]() ```go func ReverseCopy[T any](a []T) []T ``` ReverseCopy returns a reversed copy of slice a. Complexity: O\(len\(a\)\). ## func [Shuffle]() ```go func Shuffle[T any](a []T) ``` Shuffle pseudo\-randomizes the order of elements. Complexity: O\(len\(a\)\). ## func [Sort]() ```go func Sort[T Ordered](a []T) ``` Sort sorts data in ascending order. The order of equal elements is not guaranteed to be preserved. Complexity: O\(N\*log\(N\)\), where N=len\(a\). ## func [SortFunc]() ```go func SortFunc[T any](a []T, less func(x, y T) bool) ``` SortFunc sorts data in ascending order with compare func less. The order of equal elements is not guaranteed to be preserved. Complexity: O\(N\*log\(N\)\), N=len\(a\). ## func [StableSort]() ```go func StableSort[T Ordered](a []T) ``` StableSort sorts data in ascending order stably. The order of equivalent elements is guaranteed to be preserved. Complexity: O\(N\*log\(N\)^2\), where N=len\(a\). ## func [StableSortFunc]() ```go func StableSortFunc[T any](a []T, less func(x, y T) bool) ``` StableSortFunc sorts data in ascending order with compare func less stably. The order of equivalent elements is guaranteed to be preserved. Complexity: O\(N\*log\(N\)\), N=len\(a\). ## func [Sum]() ```go func Sum[T Numeric](a []T) T ``` Sum summarize all elements in a. returns the result as type R, you should use SumAs if T can't hold the result. Complexity: O\(len\(a\)\). ## func [SumAs]() ```go func SumAs[R, T Numeric](a []T) R ``` SumAs summarize all elements in a. returns the result as type R, this is useful when T is too small to hold the result. Complexity: O\(len\(a\)\). ## func [Transform]() ```go func Transform[T any](a []T, op func(T) T) ``` Transform applies the function op to each element in slice a and set it back to the same place in a. Complexity: O\(len\(a\)\). ## func [TransformCopy]() ```go func TransformCopy[R any, T any](a []T, op func(T) R) []R ``` TransformCopy applies the function op to each element in slice a and return all the result as a slice. Complexity: O\(len\(a\)\). ## func [TransformTo]() ```go func TransformTo[R any, T any](a []T, op func(T) R, b []R) []R ``` TransformTo applies the function op to each element in slice a and fill it to slice b, return the transformed slice. If cap\(b\) \>= len\(a\), no memory allocation. Complexity: O\(len\(a\)\). ## func [Unique]() ```go func Unique[T comparable](a []T) []T ``` Unique remove adjacent repeated elements from the input slice. return the processed slice with new length. Complexity: O\(len\(a\)\). ## func [UniqueCopy]() ```go func UniqueCopy[T comparable](a []T) []T ``` UniqueCopy remove adjacent repeated elements from the input slice. return the result slice, and the input slice is kept unchanged. Complexity: O\(len\(a\)\). ## func [UpperBound]() ```go func UpperBound[T Ordered](a []T, value T) int ``` UpperBound returns an index to the first element in the ascending ordered slice a such that value \< element \(i.e. strictly greater\), or len\(a\) if no such element is found. Complexity: O\(log\(len\(a\)\)\). ## func [UpperBoundFunc]() ```go func UpperBoundFunc[T any](a []T, value T, less LessFn[T]) int ``` UpperBoundFunc returns an index to the first element in the ordered slice a such that less\(value, element\)\) is true \(i.e. strictly greater\), or len\(a\) if no such element is found. The elements in the slice a should sorted according with compare func less. Complexity: O\(log\(len\(a\)\)\). ## type [BuiltinSet]() BuiltinSet is an associative container that contains an unordered set of unique objects of type K. ```go type BuiltinSet[K comparable] map[K]struct{} ``` ### func [SetOf]() ```go func SetOf[K comparable](ks ...K) BuiltinSet[K] ``` SetOf creates a new BuiltinSet object with the initial content from ks. ### func \(BuiltinSet\[K\]\) [Clear]() ```go func (s BuiltinSet[K]) Clear() ``` Clear implements the Container interface. ### func \(BuiltinSet\[K\]\) [Delete]() ```go func (s BuiltinSet[K]) Delete(k K) ``` Delete deletes an element from the set. It returns nothing, so it's faster than Remove. ### func \(BuiltinSet\[K\]\) [Difference]() ```go func (s BuiltinSet[K]) Difference(other BuiltinSet[K]) BuiltinSet[K] ``` Difference returns a new set with elements in the set that are not in other. ### func \(BuiltinSet\[K\]\) [ForEach]() ```go func (s BuiltinSet[K]) ForEach(cb func(k K)) ``` ForEach implements the Set interface. ### func \(BuiltinSet\[K\]\) [ForEachIf]() ```go func (s BuiltinSet[K]) ForEachIf(cb func(k K) bool) ``` ForEachIf implements the Container interface. ### func \(BuiltinSet\[K\]\) [Has]() ```go func (s BuiltinSet[K]) Has(k K) bool ``` Has implements the Set interface. ### func \(BuiltinSet\[K\]\) [Insert]() ```go func (s BuiltinSet[K]) Insert(k K) bool ``` Insert implements the Set interface. ### func \(BuiltinSet\[K\]\) [InsertN]() ```go func (s BuiltinSet[K]) InsertN(ks ...K) int ``` InsertN implements the Set interface. ### func \(BuiltinSet\[K\]\) [Intersection]() ```go func (s BuiltinSet[K]) Intersection(other BuiltinSet[K]) BuiltinSet[K] ``` Intersection returns a new set with elements common to the set and other. ### func \(BuiltinSet\[K\]\) [IsDisjointOf]() ```go func (s BuiltinSet[K]) IsDisjointOf(other BuiltinSet[K]) bool ``` IsDisjointOf return True if the set has no elements in common with other. Sets are disjoint if and only if their intersection is the empty set. ### func \(BuiltinSet\[K\]\) [IsEmpty]() ```go func (s BuiltinSet[K]) IsEmpty() bool ``` IsEmpty implements the Container interface. ### func \(BuiltinSet\[K\]\) [IsSubsetOf]() ```go func (s BuiltinSet[K]) IsSubsetOf(other BuiltinSet[K]) bool ``` IsSubsetOf tests whether every element in the set is in other. ### func \(BuiltinSet\[K\]\) [IsSupersetOf]() ```go func (s BuiltinSet[K]) IsSupersetOf(other BuiltinSet[K]) bool ``` IsSupersetOf tests whether every element in other is in the set. ### func \(BuiltinSet\[K\]\) [Keys]() ```go func (s BuiltinSet[K]) Keys() []K ``` Keys return a copy of all keys as a slice. ### func \(BuiltinSet\[K\]\) [Len]() ```go func (s BuiltinSet[K]) Len() int ``` Len implements the Container interface. ### func \(BuiltinSet\[K\]\) [Remove]() ```go func (s BuiltinSet[K]) Remove(k K) bool ``` Remove implements the Set interface. ### func \(BuiltinSet\[K\]\) [RemoveN]() ```go func (s BuiltinSet[K]) RemoveN(ks ...K) int ``` RemoveN implements the Set interface. ### func \(BuiltinSet\[K\]\) [String]() ```go func (s BuiltinSet[K]) String() string ``` String implements the fmt.Stringer interface. ### func \(BuiltinSet\[K\]\) [Union]() ```go func (s BuiltinSet[K]) Union(other BuiltinSet[K]) BuiltinSet[K] ``` Union returns a new set with elements from the set and other. ### func \(BuiltinSet\[K\]\) [Update]() ```go func (s BuiltinSet[K]) Update(other BuiltinSet[K]) ``` Update adds all elements from other to set. set |= other. ## type [CompareFn]() CompareFn is a 3 way compare function that returns 1 if a \> b, returns 0 if a == b, returns \-1 if a \< b. ```go type CompareFn[T any] func(a, b T) int ``` ## type [Container]() Container is a holder object that stores a collection of other objects. ```go type Container interface { IsEmpty() bool // IsEmpty checks if the container has no elements. Len() int // Len returns the number of elements in the container. Clear() // Clear erases all elements from the container. After this call, Len() returns zero. } ``` ## type [DList]() DList is a doubly linked list. ```go type DList[T any] struct { // contains filtered or unexported fields } ``` ### func [DListOf]() ```go func DListOf[T any](vs ...T) DList[T] ``` DListOf make a new DList from a serial of values. ### func \(\*DList\[T\]\) [Back]() ```go func (l *DList[T]) Back() T ``` Back returns the last element in the container. ### func \(\*DList\[T\]\) [Clear]() ```go func (l *DList[T]) Clear() ``` Clear cleanup the list. ### func \(\*DList\[T\]\) [ForEach]() ```go func (l *DList[T]) ForEach(cb func(val T)) ``` ForEach iterate the list, apply each element to the cb callback function. ### func \(\*DList\[T\]\) [ForEachIf]() ```go func (l *DList[T]) ForEachIf(cb func(val T) bool) ``` ForEachIf iterate the list, apply each element to the cb callback function, stop if cb returns false. ### func \(\*DList\[T\]\) [ForEachMutable]() ```go func (l *DList[T]) ForEachMutable(cb func(val *T)) ``` ForEachMutable iterate the list, apply pointer of each element to the cb callback function. ### func \(\*DList\[T\]\) [ForEachMutableIf]() ```go func (l *DList[T]) ForEachMutableIf(cb func(val *T) bool) ``` ForEachMutableIf iterate the list, apply pointer of each element to the cb callback function, stop if cb returns false. ### func \(\*DList\[T\]\) [Front]() ```go func (l *DList[T]) Front() T ``` Front returns the first element in the container. ### func \(\*DList\[T\]\) [IsEmpty]() ```go func (l *DList[T]) IsEmpty() bool ``` IsEmpty return whether the list is empty. ### func \(\*DList\[T\]\) [Iterate]() ```go func (l *DList[T]) Iterate() MutableIterator[T] ``` Iterate returns an iterator to the first element in the list. ### func \(\*DList\[T\]\) [Len]() ```go func (l *DList[T]) Len() int ``` Len return the length of the list. ### func \(\*DList\[T\]\) [PopBack]() ```go func (l *DList[T]) PopBack() T ``` PopBack popups an element from the back of the list. ### func \(\*DList\[T\]\) [PopFront]() ```go func (l *DList[T]) PopFront() T ``` PopFront popups an element from the front of the list. ### func \(\*DList\[T\]\) [PushBack]() ```go func (l *DList[T]) PushBack(val T) ``` PushBack pushes an element at the back of the list. ### func \(\*DList\[T\]\) [PushFront]() ```go func (l *DList[T]) PushFront(val T) ``` PushFront pushes an element at the front of the list. ### func \(\*DList\[T\]\) [String]() ```go func (l *DList[T]) String() string ``` String convert the list to string. ### func \(\*DList\[T\]\) [TryPopBack]() ```go func (l *DList[T]) TryPopBack() (T, bool) ``` TryPopBack tries to pop up an element from the back of the list. ### func \(\*DList\[T\]\) [TryPopFront]() ```go func (l *DList[T]) TryPopFront() (T, bool) ``` TryPopFront tries to pop up an element from the front of the list. ## type [DListQueue]() DListQueue is a FIFO container ```go type DListQueue[T any] struct { // contains filtered or unexported fields } ``` ### func [NewDListQueue]() ```go func NewDListQueue[T any]() *DListQueue[T] ``` NewDListQueue create a new Queue object. ### func \(\*DListQueue\[T\]\) [Back]() ```go func (q *DListQueue[T]) Back() T ``` Back returns the last element in the container. ### func \(\*DListQueue\[T\]\) [Clear]() ```go func (q *DListQueue[T]) Clear() ``` Clear implements the Container interface. ### func \(\*DListQueue\[T\]\) [Front]() ```go func (q *DListQueue[T]) Front() T ``` Front returns the first element in the container. ### func \(\*DListQueue\[T\]\) [IsEmpty]() ```go func (q *DListQueue[T]) IsEmpty() bool ``` IsEmpty implements the Container interface. ### func \(\*DListQueue\[T\]\) [Len]() ```go func (q *DListQueue[T]) Len() int ``` Len implements the Container interface. ### func \(\*DListQueue\[T\]\) [PopBack]() ```go func (q *DListQueue[T]) PopBack() T ``` PopBack popups an element from the back of the queue. ### func \(\*DListQueue\[T\]\) [PopFront]() ```go func (q *DListQueue[T]) PopFront() T ``` PopFront popups an element from the front of the queue. ### func \(\*DListQueue\[T\]\) [PushBack]() ```go func (q *DListQueue[T]) PushBack(val T) ``` PushBack pushed an element to the back of the queue. ### func \(\*DListQueue\[T\]\) [PushFront]() ```go func (q *DListQueue[T]) PushFront(val T) ``` PushFront pushed an element to the front of the queue. ### func \(\*DListQueue\[T\]\) [String]() ```go func (q *DListQueue[T]) String() string ``` Len implements the fmt.Stringer interface. ### func \(\*DListQueue\[T\]\) [TryPopBack]() ```go func (q *DListQueue[T]) TryPopBack() (T, bool) ``` TryPopBack tries popuping an element from the back of the queue. ### func \(\*DListQueue\[T\]\) [TryPopFront]() ```go func (q *DListQueue[T]) TryPopFront() (T, bool) ``` TryPopFront tries popuping an element from the front of the queue. ## type [Deque]() Deque is a container that can add and remove elements from both ends. ```go type Deque[T any] interface { Container Front() T // Front returns the first element in the container. Back() T // Back returns the last element in the container. PushFront(T) // PushBack pushes an element at the front of the container. PushBack(T) // PushBack pushes an element at the back of the container. PopFront() T // PopBack popups a front from the back of the container. PopBack() T // PopBack popups a element from the back of the container. TryPopFront() (T, bool) // TryPopFront tries to popup a element from the front of the container. TryPopBack() (T, bool) // TryPopBack tries to popup a element from the back of the container. } ``` ## type [Float]() Float is a constraint that permits any floating\-point type. If future releases of Go add new predeclared floating\-point types, this constraint will be modified to include them. ```go type Float interface { // contains filtered or unexported methods } ``` ## type [HashFn]() HashFn is a function that returns the hash of 't'. ```go type HashFn[T any] func(t T) uint64 ``` ## type [Integer]() Integer is a constraint that permits any integer type. If future releases of Go add new predeclared integer types, this constraint will be modified to include them. ```go type Integer interface { // contains filtered or unexported methods } ``` ## type [Iterator]() Iterator is the interface for container's iterator. ```go type Iterator[T any] interface { IsNotEnd() bool // Whether it is point to the end of the range. MoveToNext() // Let it point to the next element. Value() T // Return the value of current element. } ``` ## type [LessFn]() LessFn is a function that returns whether 'a' is less than 'b'. ```go type LessFn[T any] func(a, b T) bool ``` ## type [Map]() Map is a associative container that contains key\-value pairs with unique keys. ```go type Map[K any, V any] interface { Container Has(K) bool // Checks whether the container contains element with specific key. Find(K) *V // Finds element with specific key. Insert(K, V) // Inserts a key-value pair in to the container or replace existing value. Remove(K) bool // Remove element with specific key. ForEach(func(K, V)) // Iterate the container. ForEachIf(func(K, V) bool) // Iterate the container, stops when the callback returns false. ForEachMutable(func(K, *V)) // Iterate the container, *V is mutable. ForEachMutableIf(func(K, *V) bool) // Iterate the container, *V is mutable, stops when the callback returns false. } ``` ## type [MapIterator]() MapIterator is the interface for map's iterator. ```go type MapIterator[K any, V any] interface { Key() K // The key of the element // contains filtered or unexported methods } ``` ## type [MutableIterator]() MutableIterator is the interface for container's mutable iterator. ```go type MutableIterator[T any] interface { Pointer() *T // Return the pointer to the value of current element. // contains filtered or unexported methods } ``` ## type [MutableMapIterator]() MutableMapIterator is the interface for map's mutable iterator. ```go type MutableMapIterator[K any, V any] interface { Key() K // The key of the element // contains filtered or unexported methods } ``` ## type [Numeric]() Numeric is a constraint that permits any numeric type. ```go type Numeric interface { // contains filtered or unexported methods } ``` ## type [Ordered]() Ordered is a constraint that permits any ordered type: any type that supports the operators \< \<= \>= \>. If future releases of Go add new ordered types, this constraint will be modified to include them. ```go type Ordered interface { // contains filtered or unexported methods } ``` ## type [Pool]() Pool is a type safed sync.Pool. ```go type Pool[T any] sync.Pool ``` ### func [MakePool]() ```go func MakePool[T any]() Pool[T] ``` MakePool returns a Pool object ### func [MakePoolWithNew]() ```go func MakePoolWithNew[T any](new func() *T) Pool[T] ``` MakePoolWithNew returns a Pool object with specified new function. ### func \(\*Pool\[T\]\) [Get]() ```go func (pool *Pool[T]) Get() *T ``` Get selects an arbitrary item from the Pool, removes it from the Pool, and returns it to the caller. ### func \(\*Pool\[T\]\) [Put]() ```go func (pool *Pool[T]) Put(x *T) ``` Put puts x to the pool. ## type [PriorityQueue]() PriorityQueue is an queue with priority. The elements of the priority queue are ordered according to their natural ordering, or by a less function provided at construction time, depending on which constructor is used. ```go type PriorityQueue[T any] struct { // contains filtered or unexported fields } ```
Example

This example inserts several ints into an IntHeap, checks the minimum, and removes them in order of priority. ```go h := NewPriorityQueue[int]() h.Push(3) h.Push(2) h.Push(1) h.Push(5) fmt.Printf("minimum: %d\n", h.Top()) for h.Len() > 0 { fmt.Printf("%d ", h.Pop()) } // Output: // minimum: 1 // 1 2 3 5 ``` #### Output ``` minimum: 1 1 2 3 5 ```

### func [NewPriorityQueue]() ```go func NewPriorityQueue[T Ordered]() *PriorityQueue[T] ``` NewPriorityQueue creates an empty priority object. ### func [NewPriorityQueueFunc]() ```go func NewPriorityQueueFunc[T any](less LessFn[T]) *PriorityQueue[T] ``` NewPriorityQueueFunc creates an empty priority object with specified compare function less. ### func [NewPriorityQueueOf]() ```go func NewPriorityQueueOf[T Ordered](elements ...T) *PriorityQueue[T] ``` NewPriorityQueueOf creates a new priority object with specified initial elements. ### func [NewPriorityQueueOn]() ```go func NewPriorityQueueOn[T Ordered](slice []T) *PriorityQueue[T] ``` NewPriorityQueueOn creates a new priority object on the specified slices. The slice become a heap after the call. ### func \(\*PriorityQueue\[T\]\) [Clear]() ```go func (pq *PriorityQueue[T]) Clear() ``` Clear clear the priority queue. ### func \(\*PriorityQueue\[T\]\) [IsEmpty]() ```go func (pq *PriorityQueue[T]) IsEmpty() bool ``` IsEmpty checks whether priority queue has no elements. ### func \(\*PriorityQueue\[T\]\) [Len]() ```go func (pq *PriorityQueue[T]) Len() int ``` Len returns the number of elements in the priority queue. ### func \(\*PriorityQueue\[T\]\) [Pop]() ```go func (pq *PriorityQueue[T]) Pop() T ``` Pop removes the top element in the priority queue. ### func \(\*PriorityQueue\[T\]\) [Push]() ```go func (pq *PriorityQueue[T]) Push(v T) ``` Push pushes the given element v to the priority queue. ### func \(\*PriorityQueue\[T\]\) [Top]() ```go func (pq *PriorityQueue[T]) Top() T ``` Top returns the top element in the priority queue. ## type [Queue]() Queue is a container that can add elements to one end and remove elements from the other end. ```go type Queue[T any] interface { Container Front() // Front returns the first element in the container. Back() // Back returns the last element in the container. Push(T) // Push pushes an element at the back of the container. Pop() T // Pop popups a front from the back of the container. TryPop() (T, bool) // TryPop tries to popup a element from the front of the container. } ``` ## type [SList]() SList is a singly linked list. ```go type SList[T any] struct { // contains filtered or unexported fields } ``` ### func [SListOf]() ```go func SListOf[T any](values ...T) SList[T] ``` SListOf return a SList that contains values. ### func \(\*SList\[T\]\) [Back]() ```go func (l *SList[T]) Back() T ``` Back returns the last element in the list. ### func \(\*SList\[T\]\) [Clear]() ```go func (l *SList[T]) Clear() ``` Clear erases all elements from the container. After this call, Len\(\) returns zero. ### func \(\*SList\[T\]\) [ForEach]() ```go func (l *SList[T]) ForEach(cb func(T)) ``` ForEach iterate the list, apply each element to the cb callback function. ### func \(\*SList\[T\]\) [ForEachIf]() ```go func (l *SList[T]) ForEachIf(cb func(T) bool) ``` ForEachIf iterate the container, apply each element to the cb callback function, stop if cb returns false. ### func \(\*SList\[T\]\) [ForEachMutable]() ```go func (l *SList[T]) ForEachMutable(cb func(*T)) ``` ForEachMutable iterate the container, apply pointer of each element to the cb callback function. ### func \(\*SList\[T\]\) [ForEachMutableIf]() ```go func (l *SList[T]) ForEachMutableIf(cb func(*T) bool) ``` ForEachMutableIf iterate the container, apply pointer of each element to the cb callback function, stop if cb returns false. ### func \(\*SList\[T\]\) [Front]() ```go func (l *SList[T]) Front() T ``` Front returns the first element in the list. ### func \(\*SList\[T\]\) [IsEmpty]() ```go func (l *SList[T]) IsEmpty() bool ``` IsEmpty checks if the container has no elements. ### func \(\*SList\[T\]\) [Iterate]() ```go func (l *SList[T]) Iterate() MutableIterator[T] ``` Iterate returns an iterator to the whole container. ### func \(\*SList\[T\]\) [Len]() ```go func (l *SList[T]) Len() int ``` Len returns the number of elements in the container. ### func \(\*SList\[T\]\) [PopFront]() ```go func (l *SList[T]) PopFront() T ``` PopFront popups an element from the front of the list. The list must be non\-empty\! ### func \(\*SList\[T\]\) [PushBack]() ```go func (l *SList[T]) PushBack(v T) ``` PushBack pushed an element to the tail of the list. ### func \(\*SList\[T\]\) [PushFront]() ```go func (l *SList[T]) PushFront(v T) ``` PushFront pushed an element to the front of the list. ### func \(\*SList\[T\]\) [Reverse]() ```go func (l *SList[T]) Reverse() ``` Reverse reverses the order of all elements in the container. ### func \(\*SList\[T\]\) [Values]() ```go func (l *SList[T]) Values() []T ``` Values copies all elements in the container to a slice and return it. ## type [Set]() Set is a containers that store unique elements. ```go type Set[K any] interface { Container Has(K) bool // Checks whether the container contains element with specific key. Insert(K) bool // Inserts a element in to the container or replace existing value. InsertN(...K) int // Inserts multiple elements in to the container or replace existing value. Remove(K) bool // Remove specific element, return true if element was in the container. RemoveN(...K) int // Remove multiple elements, return the number of removed elements. ForEach(func(K)) // Iterate the container. ForEachIf(func(K) bool) // Iterate the container, stops when the callback returns false. } ``` ## type [Signed]() Signed is a constraint that permits any signed integer type. If future releases of Go add new predeclared signed integer types, this constraint will be modified to include them. ```go type Signed interface { // contains filtered or unexported methods } ``` ## type [SkipList]() SkipList is a probabilistic data structure that seem likely to supplant balanced trees as the implementation method of choice for many applications. Skip list algorithms have the same asymptotic expected time bounds as balanced trees and are simpler, faster and use less space. See https://en.wikipedia.org/wiki/Skip_list for more details. ```go type SkipList[K any, V any] struct { // contains filtered or unexported fields } ``` ### func [NewSkipList]() ```go func NewSkipList[K Ordered, V any]() *SkipList[K, V] ``` NewSkipList creates a new SkipList for Ordered key type. ### func [NewSkipListFromMap]() ```go func NewSkipListFromMap[K Ordered, V any](m map[K]V) *SkipList[K, V] ``` NewSkipListFromMap creates a new SkipList from a map. ### func [NewSkipListFunc]() ```go func NewSkipListFunc[K any, V any](keyCmp CompareFn[K]) *SkipList[K, V] ``` NewSkipListFunc creates a new SkipList with specified compare function keyCmp. ### func \(\*SkipList\[K, V\]\) [Clear]() ```go func (sl *SkipList[K, V]) Clear() ``` Clear implements the Container interface. ### func \(\*SkipList\[K, V\]\) [Find]() ```go func (sl *SkipList[K, V]) Find(key K) *V ``` Find returns the value associated with the passed key if the key is in the skiplist, otherwise returns nil. ### func \(\*SkipList\[K, V\]\) [FindRange]() ```go func (sl *SkipList[K, V]) FindRange(first, last K) MutableMapIterator[K, V] ``` FindRange returns an iterator in range \[first, last\) \(last is not included\). ### func \(\*SkipList\[K, V\]\) [ForEach]() ```go func (sl *SkipList[K, V]) ForEach(op func(K, V)) ``` ForEach implements the Map interface. ### func \(\*SkipList\[K, V\]\) [ForEachIf]() ```go func (sl *SkipList[K, V]) ForEachIf(op func(K, V) bool) ``` ForEachIf implements the Map interface. ### func \(\*SkipList\[K, V\]\) [ForEachMutable]() ```go func (sl *SkipList[K, V]) ForEachMutable(op func(K, *V)) ``` ForEachMutable implements the Map interface. ### func \(\*SkipList\[K, V\]\) [ForEachMutableIf]() ```go func (sl *SkipList[K, V]) ForEachMutableIf(op func(K, *V) bool) ``` ForEachMutableIf implements the Map interface. ### func \(\*SkipList\[K, V\]\) [Has]() ```go func (sl *SkipList[K, V]) Has(key K) bool ``` Has implement the Map interface. ### func \(\*SkipList\[K, V\]\) [Insert]() ```go func (sl *SkipList[K, V]) Insert(key K, value V) ``` Insert inserts a key\-value pair into the skiplist. If the key is already in the skip list, it's value will be updated. ### func \(\*SkipList\[K, V\]\) [IsEmpty]() ```go func (sl *SkipList[K, V]) IsEmpty() bool ``` IsEmpty implements the Container interface. ### func \(\*SkipList\[K, V\]\) [Iterate]() ```go func (sl *SkipList[K, V]) Iterate() MutableMapIterator[K, V] ``` Iterate return an iterator to the skiplist. ### func \(\*SkipList\[K, V\]\) [Len]() ```go func (sl *SkipList[K, V]) Len() int ``` Len implements the Container interface. ### func \(\*SkipList\[K, V\]\) [LowerBound]() ```go func (sl *SkipList[K, V]) LowerBound(key K) MutableMapIterator[K, V] ``` LowerBound returns an iterator to the first element in the skiplist that does not satisfy element \< value \(i.e. greater or equal to\), or a end iterator if no such element is found. ### func \(\*SkipList\[K, V\]\) [Remove]() ```go func (sl *SkipList[K, V]) Remove(key K) bool ``` Remove removes the key\-value pair associated with the passed key and returns true if the key is in the skiplist, otherwise returns false. ### func \(\*SkipList\[K, V\]\) [UpperBound]() ```go func (sl *SkipList[K, V]) UpperBound(key K) MutableMapIterator[K, V] ``` UpperBound returns an iterator to the first element in the skiplist that does not satisfy value \< element \(i.e. strictly greater\), or a end iterator if no such element is found. ## type [SkipListSet]() SkipListSet is a SortedSet implemented with skiplist. ```go type SkipListSet[K any] SkipList[K, struct{}] ``` ### func [NewSkipListSet]() ```go func NewSkipListSet[K Ordered]() *SkipListSet[K] ``` NewSkipListSet creates a new SkipListSet object. ### func [NewSkipListSetFunc]() ```go func NewSkipListSetFunc[K any](cmp CompareFn[K]) *SkipListSet[K] ``` NewSkipListSetFunc creates a new SkipListSet object with specified compare function. ### func [NewSkipListSetOf]() ```go func NewSkipListSetOf[K Ordered](elements ...K) *SkipListSet[K] ``` NewSkipListSetOf creates a new SkipListSet object with specified elements. ### func \(\*SkipListSet\[K\]\) [Clear]() ```go func (s *SkipListSet[K]) Clear() ``` Clear implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [FindRange]() ```go func (s *SkipListSet[K]) FindRange(first, last K) Iterator[K] ``` FindRange implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [ForEach]() ```go func (s *SkipListSet[K]) ForEach(f func(K)) ``` ForEach implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [ForEachIf]() ```go func (s *SkipListSet[K]) ForEachIf(f func(K) bool) ``` ForEachIf implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [Has]() ```go func (s *SkipListSet[K]) Has(key K) bool ``` Has implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [Insert]() ```go func (s *SkipListSet[K]) Insert(key K) bool ``` Insert implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [InsertN]() ```go func (s *SkipListSet[K]) InsertN(keys ...K) int ``` InsertN implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [IsEmpty]() ```go func (s *SkipListSet[K]) IsEmpty() bool ``` IsEmpty implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [Keys]() ```go func (s *SkipListSet[K]) Keys() []K ``` Keys return a copy of sorted keys as slice. ### func \(\*SkipListSet\[K\]\) [Len]() ```go func (s *SkipListSet[K]) Len() int ``` Len implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [LowerBound]() ```go func (s *SkipListSet[K]) LowerBound(key K) Iterator[K] ``` LowerBound implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [Remove]() ```go func (s *SkipListSet[K]) Remove(key K) bool ``` Remove implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [RemoveN]() ```go func (s *SkipListSet[K]) RemoveN(keys ...K) int ``` RemoveN implements the SortedSet interface. ### func \(\*SkipListSet\[K\]\) [UpperBound]() ```go func (s *SkipListSet[K]) UpperBound(key K) Iterator[K] ``` UpperBound implements the SortedSet interface. ## type [SortedMap]() SortedMap is a Map that provides a total ordering on its keys. ```go type SortedMap[K any, V any] interface { // LowerBound returns an iterator to the first element in the container that // does not satisfy element.key < value (i.e. greater or equal to), // or a end iterator if no such element is found. LowerBound(K) MutableMapIterator[K, V] // UpperBound returns an iterator to the first element in the container that // does not satisfy value < element.key (i.e. strictly greater), // or a end iterator if no such element is found. UpperBound(K) MutableMapIterator[K, V] // FindRange returns an iterator in range [first, last) (last is not included). FindRange(K, K) MutableMapIterator[K, V] // contains filtered or unexported methods } ``` ## type [SortedSet]() SortedSet is a Set that provides a total ordering on its elements. ```go type SortedSet[K any] interface { // LowerBound returns an iterator to the first element in the container that // does not satisfy element < value (i.e. greater or equal to), // or a end iterator if no such element is found. LowerBound(K) Iterator[K] // UpperBound returns an iterator to the first element in the container that // does not satisfy value < element (i.e. strictly greater), // or a end iterator if no such element is found. UpperBound(K) Iterator[K] // FindRange returns an iterator in range [first, last) (last is not included). FindRange(K, K) Iterator[K] // contains filtered or unexported methods } ``` ## type [Stack]() Stack s is a container adaptor that provides the functionality of a stack, a LIFO \(last\-in, first\-out\) data structure. ```go type Stack[T any] struct { // contains filtered or unexported fields } ``` ### func [NewStack]() ```go func NewStack[T any]() *Stack[T] ``` NewStack creates a new Stack object. ### func [NewStackCap]() ```go func NewStackCap[T any](capicity int) *Stack[T] ``` NewStackCap creates a new Stack object with the specified capicity. ### func \(Stack\[T\]\) [Cap]() ```go func (s Stack[T]) Cap() int ``` Cap returns the capacity of the stack. ### func \(\*Stack\[T\]\) [Clear]() ```go func (s *Stack[T]) Clear() ``` Clear implements the Container interface. ### func \(Stack\[T\]\) [IsEmpty]() ```go func (s Stack[T]) IsEmpty() bool ``` IsEmpty implements the Container interface. ### func \(Stack\[T\]\) [Len]() ```go func (s Stack[T]) Len() int ``` Len implements the Container interface. ### func \(\*Stack\[T\]\) [Pop]() ```go func (s *Stack[T]) Pop() T ``` Pop popups an element from the top of the stack. It must be called when IsEmpty\(\) returned false, otherwise it will panic. ### func \(\*Stack\[T\]\) [Push]() ```go func (s *Stack[T]) Push(t T) ``` Push pushes the element to the top of the stack. ### func \(Stack\[T\]\) [Top]() ```go func (s Stack[T]) Top() T ``` Top returns the top element in the stack. It must be called when s.IsEmpty\(\) returned false, otherwise it will panic. ### func \(\*Stack\[T\]\) [TryPop]() ```go func (s *Stack[T]) TryPop() (val T, ok bool) ``` TryPop tries to popup an element from the top of the stack. ## type [Unsigned]() Unsigned is a constraint that permits any unsigned integer type. If future releases of Go add new predeclared unsigned integer types, this constraint will be modified to include them. ```go type Unsigned interface { // contains filtered or unexported methods } ``` ## type [Vector]() Vector is a sequence container representing array that can change in size. ```go type Vector[T any] []T ``` ### func [AsVector]() ```go func AsVector[T any](s []T) Vector[T] ``` AsVector casts a slice as a Vector object. ### func [MakeVector]() ```go func MakeVector[T any]() Vector[T] ``` MakeVector creates an empty Vector object. ### func [MakeVectorCap]() ```go func MakeVectorCap[T any](c int) Vector[T] ``` MakeVectorCap creates an empty Vector object with specified capacity. ### func [VectorOf]() ```go func VectorOf[T any](v ...T) Vector[T] ``` VectorOf creates a Vector object with initial values. ### func \(\*Vector\[T\]\) [Append]() ```go func (v *Vector[T]) Append(x ...T) ``` Append appends the values x... to the tail of the vector. ### func \(\*Vector\[T\]\) [At]() ```go func (v *Vector[T]) At(i int) T ``` At returns the element value at the index i. You can also use the \[\] operator, and it's better. ### func \(Vector\[T\]\) [Back]() ```go func (v Vector[T]) Back() T ``` Back returns the element at the end of the vector. It must be called when IsEmpty\(\) returned false, otherwise it will panic. ### func \(\*Vector\[T\]\) [Cap]() ```go func (v *Vector[T]) Cap() int ``` Cap returns the capacity of the vector. ### func \(\*Vector\[T\]\) [Clear]() ```go func (v *Vector[T]) Clear() ``` Clear erases all elements from the vector. After this call, Len\(\) returns zero. Leaves the Cap\(\) of the vector unchanged. ### func \(Vector\[T\]\) [ForEach]() ```go func (v Vector[T]) ForEach(cb func(val T)) ``` ForEach iterate the container, apply each element to the cb callback function. ### func \(Vector\[T\]\) [ForEachIf]() ```go func (v Vector[T]) ForEachIf(cb func(val T) bool) ``` ForEachIf iterate the container, apply each element to the cb callback function, stop if cb returns false. ### func \(Vector\[T\]\) [ForEachMutable]() ```go func (v Vector[T]) ForEachMutable(cb func(val *T)) ``` ForEachMutable iterate the container, apply pointer of each element to the cb callback function. ### func \(Vector\[T\]\) [ForEachMutableIf]() ```go func (v Vector[T]) ForEachMutableIf(cb func(val *T) bool) ``` ForEachMutableIf iterate the container, apply pointer of each element to the cb callback function, stop if cb returns false. ### func \(\*Vector\[T\]\) [Insert]() ```go func (v *Vector[T]) Insert(i int, x ...T) ``` Insert inserts the values x... into the vector at index i. After the insertion, \(\*v\)\[i\] == x\[0\]. Insert panics if i is out of range. Complexity: O\(len\(s\) \+ len\(v\)\). ### func \(\*Vector\[T\]\) [IsEmpty]() ```go func (v *Vector[T]) IsEmpty() bool ``` IsEmpty implements the Container interface. ### func \(Vector\[T\]\) [Iterate]() ```go func (v Vector[T]) Iterate() MutableIterator[T] ``` Iterate returns an iterator to the whole container. ### func \(Vector\[T\]\) [IterateRange]() ```go func (v Vector[T]) IterateRange(i, j int) MutableIterator[T] ``` IterateRange returns an iterator to the range \[i, j\) of the container. ### func \(\*Vector\[T\]\) [Len]() ```go func (v *Vector[T]) Len() int ``` Len implements the Container interface. ### func \(\*Vector\[T\]\) [PopBack]() ```go func (v *Vector[T]) PopBack() T ``` PopBack popups an element from the end of the vector. It must be called when IsEmpty\(\) returned false, otherwise it will panic. ### func \(\*Vector\[T\]\) [PushBack]() ```go func (v *Vector[T]) PushBack(x T) ``` PushBack pushs an element to the end of the vector. Complexity: O\(1\) if v.Len\(\) \< v.Cap\(\), therwise O\(len\(v\)\). ### func \(\*Vector\[T\]\) [Remove]() ```go func (v *Vector[T]) Remove(i int) ``` Remove removes 1 element in the vector. Complexity: O\(len\(s\) \- i\). ### func \(\*Vector\[T\]\) [RemoveLength]() ```go func (v *Vector[T]) RemoveLength(i int, len int) ``` RemoveLength removes the elements in the range\[i, i\+len\) from the vector. ### func \(\*Vector\[T\]\) [RemoveRange]() ```go func (v *Vector[T]) RemoveRange(i, j int) ``` RemoveRange removes the elements in the range\[i, j\) from the vector. ### func \(\*Vector\[T\]\) [Reserve]() ```go func (v *Vector[T]) Reserve(l int) ``` Reserve increases the capacity of the vector \(the total number of elements that the vector can hold without requiring reallocation\)to a value that's greater or equal to l. If l is greater than the current Cap\(\), new storage is allocated, otherwise the function does nothing. Reserve\(\) does not change the size of the vector. ### func \(\*Vector\[T\]\) [Set]() ```go func (v *Vector[T]) Set(i int, x T) ``` Set sets the value of the element at the index i. You can also use the \[\] operator, and it's better. ### func \(\*Vector\[T\]\) [Shrink]() ```go func (v *Vector[T]) Shrink() ``` Shrink removes unused capacity from the vector. ### func \(\*Vector\[T\]\) [TryPopBack]() ```go func (v *Vector[T]) TryPopBack() (T, bool) ``` TryPopBack popups an element from the end of the vector. Generated by [gomarkdoc]() ================================================ FILE: go.mod ================================================ module github.com/chen3feng/stl4go go 1.18 ================================================ FILE: go.sum ================================================ ================================================ FILE: heap.go ================================================ // Fast generic heap algorithms, faster than [container/heap] package stl4go // MakeMinHeap build a min-heap on slice array. // // Complexity: O(len(array)) func MakeMinHeap[T Ordered](array []T) { // heapify n := len(array) for i := n/2 - 1; i >= 0; i-- { heapDown(array, i, n) } } // IsMinHeap checks whether the elements in slice array are a min heap. // // Complexity: O(len(array)). func IsMinHeap[T Ordered](array []T) bool { parent := 0 for child := 1; child < len(array); child++ { if array[parent] > array[child] { return false } if (child & 1) == 0 { parent++ } } return true } // PushMinHeap pushes a element v into the min heap. // // Complexity: O(log(len(*heap))). func PushMinHeap[T Ordered](heap *[]T, v T) { *heap = append(*heap, v) heapUp(*heap, len(*heap)-1) } // PopMinHeap removes and returns the minimum element from the heap. // // Complexity: O(log n) where n = len(*heap). func PopMinHeap[T Ordered](heap *[]T) T { h := *heap n := len(h) - 1 heapSwap(h, 0, n) heapDown(h, 0, n) *heap = h[0:n] return h[n] } // RemoveMinHeap removes and returns the element at index i from the min heap. // // Complexity: is O(log(n)) where n = len(*heap). func RemoveMinHeap[T Ordered](heap *[]T, i int) T { h := *heap n := len(h) - 1 if n != i { heapSwap(h, i, n) if !heapDown(h, i, n) { heapUp(h, i) } } *heap = h[0:n] return h[n] } func heapSwap[T any](heap []T, i, j int) { heap[i], heap[j] = heap[j], heap[i] } func heapUp[T Ordered](heap []T, j int) { for { i := (j - 1) / 2 // parent if i == j || !(heap[j] < heap[i]) { break } heapSwap(heap, i, j) j = i } } func heapDown[T Ordered](heap []T, i0, n int) bool { i := i0 for { j1 := 2*i + 1 if j1 >= n || j1 < 0 { // j1 < 0 after int overflow break } j := j1 // left child if j2 := j1 + 1; j2 < n && heap[j2] < heap[j1] { j = j2 // = 2*i + 2 // right child } if !(heap[j] < heap[i]) { break } heapSwap(heap, i, j) i = j } return i > i0 } // MakeHeapFunc build a min-heap on slice array with compare function less. // // Complexity: O(len(array)) func MakeHeapFunc[T any](array []T, less LessFn[T]) { // heapify n := len(array) for i := n/2 - 1; i >= 0; i-- { heapDownFunc(array, i, n, less) } } // IsHeapFunc checks whether the elements in slice array are a min heap (accord to less). // // Complexity: O(len(array)). func IsHeapFunc[T any](array []T, less LessFn[T]) bool { parent := 0 for child := 1; child < len(array); child++ { if !less(array[parent], array[child]) { return false } if (child & 1) == 0 { parent++ } } return true } // PushHeapFunc pushes a element v into the heap. // // Complexity: O(log(len(*heap))). func PushHeapFunc[T any](heap *[]T, v T, less LessFn[T]) { *heap = append(*heap, v) heapUpFunc(*heap, len(*heap)-1, less) } // PopHeapFunc removes and returns the minimum (according to less) element from the heap. // // Complexity: O(log n) where n = len(*heap). func PopHeapFunc[T any](heap *[]T, less LessFn[T]) T { h := *heap n := len(h) - 1 heapSwap(h, 0, n) heapDownFunc(h, 0, n, less) *heap = h[0:n] return h[n] } // RemoveHeapFunc removes and returns the element at index i from the heap. // // Complexity: is O(log(n)) where n = len(*heap). func RemoveHeapFunc[T any](heap *[]T, i int, less LessFn[T]) T { h := *heap n := len(h) - 1 if n != i { heapSwap(h, i, n) if !heapDownFunc(h, i, n, less) { heapUpFunc(h, i, less) } } *heap = h[0:n] return h[n] } func heapUpFunc[T any](heap []T, j int, less LessFn[T]) { for { i := (j - 1) / 2 // parent if i == j || !less(heap[j], heap[i]) { break } heapSwap(heap, i, j) j = i } } func heapDownFunc[T any](heap []T, i0, n int, less LessFn[T]) bool { i := i0 for { j1 := 2*i + 1 if j1 >= n || j1 < 0 { // j1 < 0 after int overflow break } j := j1 // left child if j2 := j1 + 1; j2 < n && less(heap[j2], heap[j1]) { j = j2 // = 2*i + 2 // right child } if !less(heap[j], heap[i]) { break } heapSwap(heap, i, j) i = j } return i > i0 } ================================================ FILE: heap.md ================================================ # Heap stl4go provides a group of [heap](https://en.wikipedia.org/wiki/Heap_(data_structure)) algorithms. ## Easy to use For ordered types, you can easily use the heap algorithms, for example, with `int` type: ```go func Example() { heap := []int {5, 4, 3, 2, 1} stl4go.MakeMinHeap(heap) stl4go.PushMinHeap(&heap, 6) n := stl4go.PopMinHeap(&heap) // get 1 } ``` Please compare it with [container/heap](https://pkg.go.dev/container/heap#example-package-IntHeap): ```go // This example demonstrates an integer heap built using the heap interface. package main import ( "container/heap" "fmt" ) // An IntHeap is a min-heap of ints. type IntHeap []int func (h IntHeap) Len() int { return len(h) } func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] } func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *IntHeap) Push(x any) { // Push and Pop use pointer receivers because they modify the slice's length, // not just its contents. *h = append(*h, x.(int)) } func (h *IntHeap) Pop() any { old := *h n := len(old) x := old[n-1] *h = old[0 : n-1] return x } // This example inserts several ints into an IntHeap, checks the minimum, // and removes them in order of priority. func main() { h := &IntHeap{2, 1, 5} heap.Init(h) heap.Push(h, 3) fmt.Printf("minimum: %d\n", (*h)[0]) for h.Len() > 0 { fmt.Printf("%d ", heap.Pop(h)) } } ``` You must define a new type `IntHeap` and five methods before to use the standard library, these boilerplate codes are verbose, tedious, and boring. ## Benchmark The heap algorithms are also much faster than `container/heap`, even for the `Func` version.: ```console % go test -bench BenchmarkHeap -benchmem goos: darwin goarch: arm64 pkg: github.com/chen3feng/stl4go BenchmarkHeapInit/container/heap.Init-10 360126 3195 ns/op 0 B/op 0 allocs/op BenchmarkHeapInit/stlgo.MakeMinHeap-10 998325 1127 ns/op 0 B/op 0 allocs/op BenchmarkHeapInit/stlgo.MakeHeapFunc-10 488419 2355 ns/op 0 B/op 0 allocs/op ... BenchmarkHeapPush/container/heap.Push-10 101260 11630 ns/op 5952 B/op 744 allocs/op BenchmarkHeapPush/stlgo.PushMinHeap-10 511680 2261 ns/op 0 B/op 0 allocs/op BenchmarkHeapPush/stlgo.PushHeapFunc-10 445850 2625 ns/op 0 B/op 0 allocs/op ... BenchmarkHeapPop/container/heap.Pop-10 14709 81153 ns/op 5952 B/op 744 allocs/op BenchmarkHeapPop/stlgo.PopMinHeap-10 61608 19516 ns/op 0 B/op 0 allocs/op BenchmarkHeapPop/stlgo.PopHeapFunc-10 22887 52440 ns/op 0 B/op 0 allocs/op PASS ok github.com/chen3feng/stl4go 19.827s ``` ================================================ FILE: heap_bench_test.go ================================================ package stl4go import ( "container/heap" "testing" ) // An intHeap is a min-heap of ints. type intHeap []int func (h intHeap) Len() int { return len(h) } func (h intHeap) Less(i, j int) bool { return h[i] < h[j] } func (h intHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *intHeap) Push(x any) { *h = append(*h, x.(int)) } func (h *intHeap) Pop() any { old := *h n := len(old) x := old[n-1] *h = old[0 : n-1] return x } func BenchmarkHeapInit(b *testing.B) { data := Range(1, 1000) Shuffle(data) b.Run("container/heap.Init", func(b *testing.B) { data = Copy(data) h := intHeap(data) b.ResetTimer() for i := 0; i < b.N; i++ { heap.Init(&h) } }) b.Run("stlgo.MakeMinHeap", func(b *testing.B) { data = Copy(data) b.ResetTimer() for i := 0; i < b.N; i++ { MakeMinHeap(data) } }) b.Run("stlgo.MakeHeapFunc", func(b *testing.B) { data = Copy(data) b.ResetTimer() for i := 0; i < b.N; i++ { MakeHeapFunc(data, Less[int]) } }) } func BenchmarkHeapPush(b *testing.B) { const count = 1000 b.Run("container/heap.Push", func(b *testing.B) { h := intHeap([]int{}) for i := 0; i < b.N; i++ { h = h[0:0] for n := 0; n < count; n++ { heap.Push(&h, n) } } }) b.Run("stlgo.PushMinHeap", func(b *testing.B) { h := []int{} for i := 0; i < b.N; i++ { h = h[0:0] for n := 0; n < count; n++ { PushMinHeap(&h, n) } } }) b.Run("stlgo.PushHeapFunc", func(b *testing.B) { h := []int{} for i := 0; i < b.N; i++ { h = h[0:0] for n := 0; n < count; n++ { PushHeapFunc(&h, n, Less[int]) } } }) } func BenchmarkHeapPop(b *testing.B) { s := Range(1, 1000) b.Run("container/heap.Pop", func(b *testing.B) { for i := 0; i < b.N; i++ { b.StopTimer() h := intHeap(Copy(s)) heap.Init(&h) b.StartTimer() for len(h) > 0 { _ = heap.Pop(&h).(int) } } }) b.Run("stlgo.PopMinHeap", func(b *testing.B) { for i := 0; i < b.N; i++ { b.StopTimer() h := Copy(s) MakeMinHeap(h) b.StartTimer() for len(h) > 0 { _ = PopMinHeap(&h) } } }) b.Run("stlgo.PopHeapFunc", func(b *testing.B) { for i := 0; i < b.N; i++ { b.StopTimer() h := Copy(s) MakeMinHeap(h) b.StartTimer() for len(h) > 0 { _ = PopHeapFunc(&h, Less[int]) } } }) } ================================================ FILE: heap_test.go ================================================ package stl4go import ( "testing" ) func TestMakeMinHeap(t *testing.T) { data := []int{5, 4, 3, 2, 1} expectFalse(t, IsMinHeap(data)) MakeMinHeap(data) expectTrue(t, IsMinHeap(data)) } func TestIsMinHeap(t *testing.T) { heap := []int{} expectTrue(t, IsMinHeap(heap)) heap = append(heap, 1) expectTrue(t, IsMinHeap(heap)) } func TestMakeHeapFunc(t *testing.T) { data := []int{1, 2, 3, 4, 5} expectFalse(t, IsHeapFunc(data, Greater[int])) MakeHeapFunc(data, Greater[int]) expectTrue(t, IsHeapFunc(data, Greater[int])) } func Test_MinHeap_PushPop(t *testing.T) { heap := []int{} PushMinHeap(&heap, 1) expectEq(t, PopMinHeap(&heap), 1) expectTrue(t, IsMinHeap(heap)) } func Test_HeapFunc_PushPop(t *testing.T) { heap := []int{} cmp := Greater[int] PushHeapFunc(&heap, 1, cmp) expectTrue(t, IsHeapFunc(heap, cmp)) expectEq(t, PopHeapFunc(&heap, cmp), 1) expectTrue(t, IsHeapFunc(heap, cmp)) } func Test_MinHeap_Remove(t *testing.T) { heap := []int{5, 4, 3, 2, 1} MakeMinHeap(heap) RemoveMinHeap(&heap, 1) expectTrue(t, IsMinHeap(heap)) } func Test_HeapFunc_Remove(t *testing.T) { heap := []int{1, 2, 3, 4, 5} cmp := Greater[int] MakeHeapFunc(heap, cmp) RemoveHeapFunc(&heap, 1, cmp) expectTrue(t, IsHeapFunc(heap, cmp)) } ================================================ FILE: helper.go ================================================ package stl4go import ( "reflect" ) // nameOfType return type name as a string. func nameOfType[T any]() string { var t *T return reflect.TypeOf(t).String()[1:] } ================================================ FILE: iterator.go ================================================ package stl4go // Iterator is the interface for container's iterator. type Iterator[T any] interface { IsNotEnd() bool // Whether it is point to the end of the range. MoveToNext() // Let it point to the next element. Value() T // Return the value of current element. } // MutableIterator is the interface for container's mutable iterator. type MutableIterator[T any] interface { Iterator[T] Pointer() *T // Return the pointer to the value of current element. } // MapIterator is the interface for map's iterator. type MapIterator[K any, V any] interface { Iterator[V] Key() K // The key of the element } // MutableMapIterator is the interface for map's mutable iterator. type MutableMapIterator[K any, V any] interface { MutableIterator[V] Key() K // The key of the element } ================================================ FILE: lookup.go ================================================ package stl4go // Max return the larger value between `a` and `b`. // // Complexity: O(1). func Max[T Ordered](a, b T) T { if a > b { return a } return b } // Min return the smaller value between `a` and `b`. // // Complexity: O(1). func Min[T Ordered](a, b T) T { if a < b { return a } return b } // MaxN return the maximum value in the sequence `a`. // // Complexity: O(len(a)). func MaxN[T Ordered](a ...T) T { if len(a) == 0 { panic("can't call MaxN() with empty arguments list") } v := a[0] for i := 1; i < len(a); i++ { if a[i] > v { v = a[i] } } return v } // MinN return the minimum value in the sequence `a`. // // Complexity: O(len(a)). func MinN[T Ordered](a ...T) T { if len(a) == 0 { panic("can't call MaxN() with empty arguments list") } v := a[0] for i := 1; i < len(a); i++ { if a[i] < v { v = a[i] } } return v } // MinMax returns both min and max between a and b. // // Complexity: O(1). func MinMax[T Ordered](a, b T) (min, max T) { if a < b { return a, b } return b, a } // MinMaxN returns both min and max in slice a. // // Complexity: O(len(a)) func MinMaxN[T Ordered](a ...T) (min, max T) { if len(a) == 0 { panic("can't call MaxN() with empty arguments list") } min = a[0] max = a[0] for i := 1; i < len(a); i++ { if a[i] < min { min = a[i] } if a[i] > max { max = a[i] } } return } // Find find the first value x in the given slice a linearly. // return (index, true) if found, // return (_, false) if not found. // // Complexity: O(len(a)). func Find[T comparable](a []T, x T) (index int, ok bool) { for i, v := range a { if v == x { return i, true } } return -1, false } // FindIf find the first value x satisfying function cond in the given slice a linearly. // return (index, true) if found, // return (_, false) if not found. // // Complexity: O(len(a)). func FindIf[T any](a []T, cond func(T) bool) (index int, ok bool) { for i, v := range a { if cond(v) { return i, true } } return -1, false } // Index find the value x in the given slice a linearly. // // Return index if found, -1 if not found. // // Complexity: O(len(a)). func Index[T comparable](a []T, x T) int { for i, v := range a { if v == x { return i } } return -1 } // AllOf return true if pred(e) returns true for all elements e in a. // // Complexity: O(len(a)). func AllOf[T any](a []T, pred func(T) bool) bool { for _, v := range a { if !pred(v) { return false } } return true } // AnyOf return true if pred(e) returns true for any elements e in a. // // Complexity: O(len(a)). func AnyOf[T any](a []T, pred func(T) bool) bool { for _, v := range a { if pred(v) { return true } } return false } // NoneOf return true pred(e) returns true for none elements e in a. // // Complexity: O(len(a)). func NoneOf[T any](a []T, pred func(T) bool) bool { return !AnyOf(a, pred) } ================================================ FILE: lookup_test.go ================================================ package stl4go import "testing" func Test_Min(t *testing.T) { expectEq(t, Min(1, 2), 1) expectEq(t, Min(2, 1), 1) expectEq(t, Min(1, 1), 1) expectEq(t, Min("hello", "world"), "hello") } func Test_Max(t *testing.T) { expectEq(t, Max(1, 2), 2) expectEq(t, Max(2, 1), 2) expectEq(t, Max(2, 2), 2) expectEq(t, Max("hello", "world"), "world") } func Test_MinN(t *testing.T) { expectEq(t, MinN(1, 2, 3), 1) expectEq(t, MinN(2, 1, 3), 1) expectEq(t, MinN(1, 1, 1), 1) expectEq(t, MinN("hello", "world"), "hello") expectPanic(t, func() { MinN(emptyInts...) }) } func Test_MaxN(t *testing.T) { expectEq(t, MaxN(1, 2), 2) expectEq(t, MaxN(2, 1), 2) expectEq(t, MaxN(2, 2), 2) expectEq(t, MaxN("hello", "world"), "world") expectPanic(t, func() { MaxN(emptyInts...) }) } func Test_MinMax(t *testing.T) { min, max := MinMax(1, 2) expectEq(t, min, 1) expectEq(t, max, 2) min, max = MinMax(2, 1) expectEq(t, min, 1) expectEq(t, max, 2) } func Test_MinMaxN(t *testing.T) { min, max := MinMaxN(3, 4, 1, 2) expectEq(t, min, 1) expectEq(t, max, 4) expectPanic(t, func() { MinMaxN(emptyInts...) }) } func Test_Find(t *testing.T) { a := []int{1, 2, 3, 4, 3} i, ok := Find(a, 3) expectTrue(t, ok) expectEq(t, i, 2) i, ok = Find(a, 5) expectFalse(t, ok) } func Test_FindIf(t *testing.T) { isNeg := func(x int) bool { return x < 0 } a := []int{1, 2, -3, 4, 3} i, ok := FindIf(a, isNeg) expectTrue(t, ok) expectEq(t, i, 2) i, ok = FindIf([]int{1, 2, 3, 4, 3}, isNeg) expectFalse(t, ok) } func Test_Index(t *testing.T) { a := []int{1, 2, 3, 4, 3} expectEq(t, Index(a, 3), 2) expectEq(t, Index(a, 5), -1) } var ( pos = []int{1, 2, 3, 4, 5} neg = []int{-1, -2, -3, -4, -5} mix = []int{1, -2, 3, -4, 5} ) func isNegative(n int) bool { return n < 0 } func Test_AllOf(t *testing.T) { expectFalse(t, AllOf(pos, isNegative)) expectTrue(t, AllOf(neg, isNegative)) expectFalse(t, AllOf(mix, isNegative)) } func Test_AnyOf(t *testing.T) { expectFalse(t, AnyOf(pos, isNegative)) expectTrue(t, AnyOf(neg, isNegative)) expectTrue(t, AnyOf(mix, isNegative)) } func Test_NoneOf(t *testing.T) { expectTrue(t, NoneOf(pos, isNegative)) expectFalse(t, NoneOf(neg, isNegative)) expectFalse(t, NoneOf(mix, isNegative)) } ================================================ FILE: mlc_config.json ================================================ { "aliveStatusCodes": [ 400, 429, 200 ] } ================================================ FILE: pool.go ================================================ package stl4go import "sync" // Pool is a type safed sync.Pool. type Pool[T any] sync.Pool // MakePool returns a Pool object func MakePool[T any]() Pool[T] { return Pool[T]{New: func() any { return new(T) }} } // MakePoolWithNew returns a Pool object with specified new function. func MakePoolWithNew[T any](new func() *T) Pool[T] { if new != nil { return Pool[T]{New: func() any { return new() }} } return Pool[T]{} } // Get selects an arbitrary item from the Pool, removes it from the Pool, and returns it to the caller. func (pool *Pool[T]) Get() *T { i := pool.untyped().Get() if i == nil { return nil } return i.(*T) } // Put puts x to the pool. func (pool *Pool[T]) Put(x *T) { if x != nil { pool.untyped().Put(x) } } func (pool *Pool[T]) untyped() *sync.Pool { return (*sync.Pool)(pool) } ================================================ FILE: pool_test.go ================================================ package stl4go import "testing" func TestPool(t *testing.T) { p := MakePool[int]() x := p.Get() p.Put(x) } func TestMakePoolWithNew(t *testing.T) { p := MakePoolWithNew(func() *int { return new(int) }) x := p.Get() p.Put(x) } func TestMakePoolNil(t *testing.T) { p := MakePoolWithNew[int](nil) x := p.Get() expectEq(t, x, nil) p.Put(x) } ================================================ FILE: priority_queue.go ================================================ package stl4go // PriorityQueue is an queue with priority. // The elements of the priority queue are ordered according to their natural ordering, // or by a less function provided at construction time, depending on which constructor is used. type PriorityQueue[T any] struct { heap []T impl pqImpl[T] } // NewPriorityQueue creates an empty priority object. func NewPriorityQueue[T Ordered]() *PriorityQueue[T] { pq := pqOrdered[T]{} pq.impl = (pqImpl[T])(&pq) return &pq.PriorityQueue } // NewPriorityQueueOn creates a new priority object on the specified slices. // The slice become a heap after the call. func NewPriorityQueueOn[T Ordered](slice []T) *PriorityQueue[T] { MakeMinHeap(slice) pq := pqOrdered[T]{} pq.heap = slice pq.impl = pqImpl[T](&pq) return &pq.PriorityQueue } // NewPriorityQueueOf creates a new priority object with specified initial elements. func NewPriorityQueueOf[T Ordered](elements ...T) *PriorityQueue[T] { return NewPriorityQueueOn(elements) } // NewPriorityQueueFunc creates an empty priority object with specified compare function less. func NewPriorityQueueFunc[T any](less LessFn[T]) *PriorityQueue[T] { pq := pqFunc[T]{} pq.less = less pq.impl = (pqImpl[T])(&pq) return &pq.PriorityQueue } // Len returns the number of elements in the priority queue. func (pq *PriorityQueue[T]) Len() int { return len(pq.heap) } // IsEmpty checks whether priority queue has no elements. func (pq *PriorityQueue[T]) IsEmpty() bool { return len(pq.heap) == 0 } // Clear clear the priority queue. func (pq *PriorityQueue[T]) Clear() { pq.heap = pq.heap[0:0] } // Top returns the top element in the priority queue. func (pq *PriorityQueue[T]) Top() T { return pq.heap[0] } // Push pushes the given element v to the priority queue. func (pq *PriorityQueue[T]) Push(v T) { pq.impl.Push(v) } // Pop removes the top element in the priority queue. func (pq *PriorityQueue[T]) Pop() T { return pq.impl.Pop() } type pqImpl[T any] interface { Push(v T) Pop() T } type pqOrdered[T Ordered] struct { PriorityQueue[T] } func (pq *pqOrdered[T]) Push(v T) { PushMinHeap(&pq.heap, v) } func (pq *pqOrdered[T]) Pop() T { return PopMinHeap(&pq.heap) } // funcHeap is a min-heap of T compared with less. type pqFunc[T any] struct { PriorityQueue[T] less LessFn[T] } func (pq *pqFunc[T]) Push(v T) { PushHeapFunc(&pq.heap, v, pq.less) } func (pq *pqFunc[T]) Pop() T { return PopHeapFunc(&pq.heap, pq.less) } ================================================ FILE: priority_queue_test.go ================================================ package stl4go import ( "fmt" "testing" ) func TestInterface(t *testing.T) { _ = (Container)(NewPriorityQueue[int]()) } func TestNewPriorityQueue(t *testing.T) { pq := NewPriorityQueue[int]() expectTrue(t, pq.IsEmpty()) expectEq(t, pq.Len(), 0) } func TestNewPriorityQueueOf(t *testing.T) { pq := NewPriorityQueueOf(5, 4, 3, 2, 1) expectEq(t, pq.Len(), 5) } func TestPriorityQueue_PushPop(t *testing.T) { less := Less[int] pq := NewPriorityQueueFunc(less) for i := 5; i > 0; i-- { pq.Push(i) expectFalse(t, pq.IsEmpty()) } var elements []int for !pq.IsEmpty() { elements = append(elements, pq.Pop()) } expectTrue(t, pq.IsEmpty()) expectTrue(t, IsSorted(elements)) expectEq(t, len(elements), 5) } func TestPriorityQueueFunc_PushPop(t *testing.T) { pq := NewPriorityQueueFunc(Less[int]) for i := 5; i > 0; i-- { pq.Push(i) } var elements []int for !pq.IsEmpty() { elements = append(elements, pq.Pop()) } expectTrue(t, pq.IsEmpty()) expectTrue(t, IsSorted(elements)) expectEq(t, len(elements), 5) } func TestPriorityQueue_Clear(t *testing.T) { pq := NewPriorityQueue[int]() pq.Clear() expectTrue(t, pq.IsEmpty()) expectEq(t, pq.Len(), 0) pq = NewPriorityQueueOf(1, 2, 3) pq.Clear() expectTrue(t, pq.IsEmpty()) expectEq(t, pq.Len(), 0) } // This example inserts several ints into an IntHeap, checks the minimum, // and removes them in order of priority. func ExamplePriorityQueue() { h := NewPriorityQueue[int]() h.Push(3) h.Push(2) h.Push(1) h.Push(5) fmt.Printf("minimum: %d\n", h.Top()) for h.Len() > 0 { fmt.Printf("%d ", h.Pop()) } // Output: // minimum: 1 // 1 2 3 5 } ================================================ FILE: skiplist.go ================================================ // This implementation is based on https://github.com/liyue201/gostl/tree/master/ds/skiplist // (many thanks), added many optimizations, such as: // // - adaptive level // - lesser search for prevs when key already exists. // - reduce memory allocations // - richer interface. // // etc. package stl4go import ( "math/bits" "math/rand" "time" ) const ( skipListMaxLevel = 40 ) // SkipList is a probabilistic data structure that seem likely to supplant balanced trees as the // implementation method of choice for many applications. Skip list algorithms have the same // asymptotic expected time bounds as balanced trees and are simpler, faster and use less space. // // See https://en.wikipedia.org/wiki/Skip_list for more details. type SkipList[K any, V any] struct { level int // Current level, may increase dynamically during insertion len int // Total elements number in the skiplist. head skipListNode[K, V] // head.next[level] is the head of each level. // This cache is used to save the previous nodes when modifying the skip list to avoid // allocating memory each time it is called. prevsCache []*skipListNode[K, V] rander *rand.Rand impl skipListImpl[K, V] } // NewSkipList creates a new SkipList for Ordered key type. func NewSkipList[K Ordered, V any]() *SkipList[K, V] { sl := skipListOrdered[K, V]{} sl.init() sl.impl = (skipListImpl[K, V])(&sl) return &sl.SkipList } // NewSkipListFromMap creates a new SkipList from a map. func NewSkipListFromMap[K Ordered, V any](m map[K]V) *SkipList[K, V] { sl := NewSkipList[K, V]() for k, v := range m { sl.Insert(k, v) } return sl } // NewSkipListFunc creates a new SkipList with specified compare function keyCmp. func NewSkipListFunc[K any, V any](keyCmp CompareFn[K]) *SkipList[K, V] { sl := skipListFunc[K, V]{} sl.init() sl.keyCmp = keyCmp sl.impl = skipListImpl[K, V](&sl) return &sl.SkipList } // IsEmpty implements the Container interface. func (sl *SkipList[K, V]) IsEmpty() bool { return sl.len == 0 } // Len implements the Container interface. func (sl *SkipList[K, V]) Len() int { return sl.len } // Clear implements the Container interface. func (sl *SkipList[K, V]) Clear() { for i := range sl.head.next { sl.head.next[i] = nil } sl.level = 1 sl.len = 0 } // Iterate return an iterator to the skiplist. func (sl *SkipList[K, V]) Iterate() MutableMapIterator[K, V] { return &skipListIterator[K, V]{sl.head.next[0], nil} } // Insert inserts a key-value pair into the skiplist. // If the key is already in the skip list, it's value will be updated. func (sl *SkipList[K, V]) Insert(key K, value V) { node, prevs := sl.impl.findInsertPoint(key) if node != nil { // Already exist, update the value node.value = value return } level := sl.randomLevel() node = newSkipListNode(level, key, value) // Insert node to each level for i := 0; i < Min(level, sl.level); i++ { node.next[i] = prevs[i].next[i] prevs[i].next[i] = node } if level > sl.level { // Increase the level for i := sl.level; i < level; i++ { sl.head.next[i] = node } sl.level = level } sl.len++ } // Find returns the value associated with the passed key if the key is in the skiplist, otherwise // returns nil. func (sl *SkipList[K, V]) Find(key K) *V { node := sl.impl.findNode(key) if node != nil { return &node.value } return nil } // Has implement the Map interface. func (sl *SkipList[K, V]) Has(key K) bool { return sl.impl.findNode(key) != nil } // LowerBound returns an iterator to the first element in the skiplist that // does not satisfy element < value (i.e. greater or equal to), // or a end iterator if no such element is found. func (sl *SkipList[K, V]) LowerBound(key K) MutableMapIterator[K, V] { return &skipListIterator[K, V]{sl.impl.lowerBound(key), nil} } // UpperBound returns an iterator to the first element in the skiplist that // does not satisfy value < element (i.e. strictly greater), // or a end iterator if no such element is found. func (sl *SkipList[K, V]) UpperBound(key K) MutableMapIterator[K, V] { return &skipListIterator[K, V]{sl.impl.upperBound(key), nil} } // FindRange returns an iterator in range [first, last) (last is not included). func (sl *SkipList[K, V]) FindRange(first, last K) MutableMapIterator[K, V] { return &skipListIterator[K, V]{sl.impl.lowerBound(first), sl.impl.upperBound(last)} } // Remove removes the key-value pair associated with the passed key and returns true if the key is // in the skiplist, otherwise returns false. func (sl *SkipList[K, V]) Remove(key K) bool { node, prevs := sl.impl.findRemovePoint(key) if node == nil { return false } for i, v := range node.next { // Nomove the node from each level's links. prevs[i].next[i] = v } // Decrease the level if the top level become empty for sl.level > 1 && sl.head.next[sl.level-1] == nil { sl.level-- } sl.len-- return true } // ForEach implements the Map interface. func (sl *SkipList[K, V]) ForEach(op func(K, V)) { for e := sl.head.next[0]; e != nil; e = e.next[0] { op(e.key, e.value) } } // ForEachMutable implements the Map interface. func (sl *SkipList[K, V]) ForEachMutable(op func(K, *V)) { for e := sl.head.next[0]; e != nil; e = e.next[0] { op(e.key, &e.value) } } // ForEachIf implements the Map interface. func (sl *SkipList[K, V]) ForEachIf(op func(K, V) bool) { for e := sl.head.next[0]; e != nil; e = e.next[0] { if !op(e.key, e.value) { return } } } // ForEachMutableIf implements the Map interface. func (sl *SkipList[K, V]) ForEachMutableIf(op func(K, *V) bool) { for e := sl.head.next[0]; e != nil; e = e.next[0] { if !op(e.key, &e.value) { return } } } /// SkipList implementation part. type skipListNode[K any, V any] struct { key K value V next []*skipListNode[K, V] } //go:generate bash ./skiplist_newnode_generate.sh skipListMaxLevel skiplist_newnode.go // func newSkipListNode[K Ordered, V any](level int, key K, value V) *skipListNode[K, V] type skipListIterator[K any, V any] struct { node, end *skipListNode[K, V] } func (it *skipListIterator[K, V]) IsNotEnd() bool { return it.node != it.end } func (it *skipListIterator[K, V]) MoveToNext() { it.node = it.node.next[0] } func (it *skipListIterator[K, V]) Key() K { return it.node.key } func (it *skipListIterator[K, V]) Value() V { return it.node.value } func (it *skipListIterator[K, V]) Pointer() *V { return &it.node.value } // skipListImpl is an interface to provide different implementation for Ordered key or CompareFn. // // We can use CompareFn to compare Ordered keys, but a separated implementation is much faster. // We don't make the whole skip list an interface, in order to share the type independented method. // And because these methods are called directly without going through the interface, they are also // much faster. type skipListImpl[K any, V any] interface { findNode(key K) *skipListNode[K, V] lowerBound(key K) *skipListNode[K, V] upperBound(key K) *skipListNode[K, V] findInsertPoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) findRemovePoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) } func (sl *SkipList[K, V]) init() { sl.level = 1 // #nosec G404 -- This is not a security condition sl.rander = rand.New(rand.NewSource(time.Now().Unix())) sl.prevsCache = make([]*skipListNode[K, V], skipListMaxLevel) sl.head.next = make([]*skipListNode[K, V], skipListMaxLevel) } func (sl *SkipList[K, V]) randomLevel() int { total := uint64(1)< 3 && 1<<(level-3) > sl.len { level-- } if (level > skipListMaxLevel) { level = skipListMaxLevel } return level } /// skipListOrdered part // skipListOrdered is the skip list implementation for Ordered types. type skipListOrdered[K Ordered, V any] struct { SkipList[K, V] } func (sl *skipListOrdered[K, V]) findNode(key K) *skipListNode[K, V] { return sl.doFindNode(key, true) } func (sl *skipListOrdered[K, V]) doFindNode(key K, eq bool) *skipListNode[K, V] { // This function execute the job of findNode if eq is true, otherwise lowBound. // Passing the control variable eq is ugly but it's faster than testing node // again outside the function in findNode. prev := &sl.head for i := sl.level - 1; i >= 0; i-- { for cur := prev.next[i]; cur != nil; cur = cur.next[i] { if cur.key == key { return cur } if cur.key > key { // All other node in this level must be greater than the key, // search the next level. break } prev = cur } } if eq { return nil } return prev.next[0] } func (sl *skipListOrdered[K, V]) lowerBound(key K) *skipListNode[K, V] { return sl.doFindNode(key, false) } func (sl *skipListOrdered[K, V]) upperBound(key K) *skipListNode[K, V] { node := sl.lowerBound(key) if node != nil && node.key == key { return node.next[0] } return node } // findInsertPoint returns (*node, nil) to the existed node if the key exists, // or (nil, []*node) to the previous nodes if the key doesn't exist func (sl *skipListOrdered[K, V]) findInsertPoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) { prevs := sl.prevsCache[0:sl.level] prev := &sl.head for i := sl.level - 1; i >= 0; i-- { for next := prev.next[i]; next != nil; next = next.next[i] { if next.key == key { // The key is already existed, prevs are useless because no new node insertion. // stop searching. return next, nil } if next.key > key { // All other node in this level must be greater than the key, // search the next level. break } prev = next } prevs[i] = prev } return nil, prevs } // findRemovePoint finds the node which match the key and it's previous nodes. func (sl *skipListOrdered[K, V]) findRemovePoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) { prevs := sl.findPrevNodes(key) node := prevs[0].next[0] if node == nil || node.key != key { return nil, nil } return node, prevs } func (sl *skipListOrdered[K, V]) findPrevNodes(key K) []*skipListNode[K, V] { prevs := sl.prevsCache[0:sl.level] prev := &sl.head for i := sl.level - 1; i >= 0; i-- { for next := prev.next[i]; next != nil; next = next.next[i] { if next.key >= key { break } prev = next } prevs[i] = prev } return prevs } /// skipListFunc part // skipListFunc is the skip list implementation which compare keys with func. type skipListFunc[K any, V any] struct { SkipList[K, V] keyCmp CompareFn[K] } func (sl *skipListFunc[K, V]) findNode(key K) *skipListNode[K, V] { node := sl.lowerBound(key) if node != nil && sl.keyCmp(node.key, key) == 0 { return node } return nil } func (sl *skipListFunc[K, V]) lowerBound(key K) *skipListNode[K, V] { var prev = &sl.head for i := sl.level - 1; i >= 0; i-- { cur := prev.next[i] for ; cur != nil; cur = cur.next[i] { cmpRet := sl.keyCmp(cur.key, key) if cmpRet == 0 { return cur } if cmpRet > 0 { break } prev = cur } } return prev.next[0] } func (sl *skipListFunc[K, V]) upperBound(key K) *skipListNode[K, V] { node := sl.lowerBound(key) if node != nil && sl.keyCmp(node.key, key) == 0 { return node.next[0] } return node } // findInsertPoint returns (*node, nil) to the existed node if the key exists, // or (nil, []*node) to the previous nodes if the key doesn't exist func (sl *skipListFunc[K, V]) findInsertPoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) { prevs := sl.prevsCache[0:sl.level] prev := &sl.head for i := sl.level - 1; i >= 0; i-- { for cur := prev.next[i]; cur != nil; cur = cur.next[i] { r := sl.keyCmp(cur.key, key) if r == 0 { // The key is already existed, prevs are useless because no new node insertion. // stop searching. return cur, nil } if r > 0 { // All other node in this level must be greater than the key, // search the next level. break } prev = cur } prevs[i] = prev } return nil, prevs } // findRemovePoint finds the node which match the key and it's previous nodes. func (sl *skipListFunc[K, V]) findRemovePoint(key K) (*skipListNode[K, V], []*skipListNode[K, V]) { prevs := sl.findPrevNodes(key) node := prevs[0].next[0] if node == nil || sl.keyCmp(node.key, key) != 0 { return nil, nil } return node, prevs } func (sl *skipListFunc[K, V]) findPrevNodes(key K) []*skipListNode[K, V] { prevs := sl.prevsCache[0:sl.level] prev := &sl.head for i := sl.level - 1; i >= 0; i-- { for next := prev.next[i]; next != nil; next = next.next[i] { if sl.keyCmp(next.key, key) >= 0 { break } prev = next } prevs[i] = prev } return prevs } ================================================ FILE: skiplist.md ================================================ # SkipList TODO,See tests. ================================================ FILE: skiplist_bench_test.go ================================================ package stl4go import ( "strconv" "testing" ) const ( benchInitSize = 1000000 benchBatchSize = 10 ) func newMapN(n int) map[int]int { m := map[int]int{} for i := 0; i < n; i++ { m[i] = i } return m } func BenchmarkSkipList_Iterate(b *testing.B) { sl := newSkipListN(100) b.ResetTimer() for n := 0; n < b.N; n++ { for i := sl.Iterate(); i.IsNotEnd(); i.MoveToNext() { _, _ = i.Key(), i.Value() } } } func BenchmarkSkipList_Insert(b *testing.B) { start := benchInitSize sl := newSkipListN(start) b.ResetTimer() for n := 0; n < b.N; n++ { for i := 0; i < benchBatchSize; i++ { sl.Insert(start+i, i) } start += benchBatchSize } } func BenchmarkMap_Insert(b *testing.B) { start := benchInitSize m := newMapN(start) b.ResetTimer() for n := 0; n < b.N; n++ { for i := 0; i < benchBatchSize; i++ { m[start+i] = i } start += benchBatchSize } } func BenchmarkSkipList_Insert_Dup(b *testing.B) { sl := newSkipListN(benchInitSize) b.ResetTimer() for n := 0; n < b.N; n++ { for i := 0; i < benchBatchSize; i++ { sl.Insert(i, i) } } } func BenchmarkMap_Insert_Dup(b *testing.B) { m := newMapN(benchInitSize) b.ResetTimer() for n := 0; n < b.N; n++ { for i := 0; i < benchBatchSize; i++ { m[i] = i } } } func BenchmarkMap_Find(b *testing.B) { m := newMapN(benchInitSize) b.ResetTimer() for n := 0; n < b.N; n++ { for i := 0; i < benchBatchSize; i++ { _, _ = m[i] } } } func BenchmarkSkipList_Find(b *testing.B) { sl := newSkipListN(benchInitSize) b.ResetTimer() b.Run("Find", func(b *testing.B) { for i := 0; i < b.N; i++ { for n := 0; n < benchBatchSize; n++ { _ = sl.Find(n) } } }) b.Run("LowerBound", func(b *testing.B) { for i := 0; i < b.N; i++ { for n := 0; n < benchBatchSize; n++ { _ = sl.impl.lowerBound(n) } } }) b.Run("FindEnd", func(b *testing.B) { for i := 0; i < b.N; i++ { for n := 0; n < benchBatchSize; n++ { _ = sl.Find(benchInitSize) } } }) } func BenchmarkSkipListString(b *testing.B) { sl := NewSkipList[string, int]() sl.rander.Seed(0) var a []string for i := 0; i < benchBatchSize; i++ { a = append(a, strconv.Itoa(benchInitSize+i)) } end := strconv.Itoa(2 * benchInitSize) b.ResetTimer() b.Run("Insert", func(b *testing.B) { for i := 0; i < b.N; i++ { for n := 0; n < benchBatchSize; n++ { sl.Insert(a[n], n) } } }) b.Run("Find", func(b *testing.B) { for i := 0; i < b.N; i++ { for n := 0; n < benchBatchSize; n++ { sl.Find(a[n]) } } }) b.Run("FindEnd", func(b *testing.B) { for i := 0; i < b.N; i++ { for n := 0; n < benchBatchSize; n++ { sl.Find(end) } } }) b.Run("RemoveEnd", func(b *testing.B) { for i := 0; i < b.N; i++ { for n := 0; n < benchBatchSize; n++ { sl.Remove(end) } } }) b.Run("Remove", func(b *testing.B) { for i := 0; i < b.N; i++ { for n := 0; n < benchBatchSize; n++ { sl.Remove(a[n]) } } }) } ================================================ FILE: skiplist_newnode.go ================================================ // AUTO GENERATED CODE, DO NOT EDIT!!! // EDIT skiplist_newnode_generate.sh accordingly. package stl4go // newSkipListNode creates a new node initialized with specified key, value and next slice. func newSkipListNode[K any, V any](level int, key K, value V) *skipListNode[K, V] { // For nodes with each levels, point their next slice to the nexts array allocated together, // which can reduce 1 memory allocation and improve performance. // // The generics of the golang doesn't support non-type parameters like in C++, // so we have to generate it manually. switch level { case 1: n := struct { head skipListNode[K, V] nexts [1]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 2: n := struct { head skipListNode[K, V] nexts [2]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 3: n := struct { head skipListNode[K, V] nexts [3]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 4: n := struct { head skipListNode[K, V] nexts [4]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 5: n := struct { head skipListNode[K, V] nexts [5]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 6: n := struct { head skipListNode[K, V] nexts [6]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 7: n := struct { head skipListNode[K, V] nexts [7]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 8: n := struct { head skipListNode[K, V] nexts [8]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 9: n := struct { head skipListNode[K, V] nexts [9]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 10: n := struct { head skipListNode[K, V] nexts [10]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 11: n := struct { head skipListNode[K, V] nexts [11]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 12: n := struct { head skipListNode[K, V] nexts [12]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 13: n := struct { head skipListNode[K, V] nexts [13]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 14: n := struct { head skipListNode[K, V] nexts [14]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 15: n := struct { head skipListNode[K, V] nexts [15]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 16: n := struct { head skipListNode[K, V] nexts [16]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 17: n := struct { head skipListNode[K, V] nexts [17]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 18: n := struct { head skipListNode[K, V] nexts [18]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 19: n := struct { head skipListNode[K, V] nexts [19]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 20: n := struct { head skipListNode[K, V] nexts [20]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 21: n := struct { head skipListNode[K, V] nexts [21]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 22: n := struct { head skipListNode[K, V] nexts [22]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 23: n := struct { head skipListNode[K, V] nexts [23]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 24: n := struct { head skipListNode[K, V] nexts [24]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 25: n := struct { head skipListNode[K, V] nexts [25]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 26: n := struct { head skipListNode[K, V] nexts [26]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 27: n := struct { head skipListNode[K, V] nexts [27]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 28: n := struct { head skipListNode[K, V] nexts [28]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 29: n := struct { head skipListNode[K, V] nexts [29]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 30: n := struct { head skipListNode[K, V] nexts [30]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 31: n := struct { head skipListNode[K, V] nexts [31]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 32: n := struct { head skipListNode[K, V] nexts [32]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 33: n := struct { head skipListNode[K, V] nexts [33]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 34: n := struct { head skipListNode[K, V] nexts [34]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 35: n := struct { head skipListNode[K, V] nexts [35]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 36: n := struct { head skipListNode[K, V] nexts [36]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 37: n := struct { head skipListNode[K, V] nexts [37]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 38: n := struct { head skipListNode[K, V] nexts [38]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 39: n := struct { head skipListNode[K, V] nexts [39]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head case 40: n := struct { head skipListNode[K, V] nexts [40]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head } panic("should not reach here") } ================================================ FILE: skiplist_newnode_generate.sh ================================================ #!/bin/bash # The go generics sucks! # We have to generate skiplist_newnode.go by myself. generate() { # NOTE the tab chars, they are used to follow the go style guides. echo "package $GOPACKAGE" echo " // newSkipListNode creates a new node initialized with specified key, value and next slice. func newSkipListNode[K any, V any](level int, key K, value V) *skipListNode[K, V] { // For nodes with each levels, point their next slice to the nexts array allocated together, // which can reduce 1 memory allocation and improve performance. // // The generics of the golang doesn't support non-type parameters like in C++, // so we have to generate it manually. switch level {" for i in $(seq 1 $1); do echo "\ case $i: n := struct { head skipListNode[K, V] nexts [$i]*skipListNode[K, V] }{head: skipListNode[K, V]{key, value, nil}} n.head.next = n.nexts[:] return &n.head" done echo "\ } panic(\"should not reach here\") }" } max_level=$(grep -E "^\s*$1\s*=\s*\d+" $GOFILE | grep -Eo "\d+") output_file=$2 echo -e "// AUTO GENERATED CODE, DO NOT EDIT!!!\n// EDIT $(basename $0) accordingly.\n" > $output_file generate $max_level >> $output_file ================================================ FILE: skiplist_set.go ================================================ package stl4go // SkipListSet is a SortedSet implemented with skiplist. type SkipListSet[K any] SkipList[K, struct{}] // NewSkipListSet creates a new SkipListSet object. func NewSkipListSet[K Ordered]() *SkipListSet[K] { return (*SkipListSet[K])(NewSkipList[K, struct{}]()) } // NewSkipListSetFunc creates a new SkipListSet object with specified compare function. func NewSkipListSetFunc[K any](cmp CompareFn[K]) *SkipListSet[K] { return (*SkipListSet[K])(NewSkipListFunc[K, struct{}](cmp)) } // NewSkipListSetOf creates a new SkipListSet object with specified elements. func NewSkipListSetOf[K Ordered](elements ...K) *SkipListSet[K] { s := NewSkipListSet[K]() for i := range elements { s.Insert(elements[i]) } return s } // IsEmpty implements the SortedSet interface. func (s *SkipListSet[K]) IsEmpty() bool { return s.asMap().IsEmpty() } // Len implements the SortedSet interface. func (s *SkipListSet[K]) Len() int { return s.asMap().Len() } // Clear implements the SortedSet interface. func (s *SkipListSet[K]) Clear() { s.asMap().Clear() } // Has implements the SortedSet interface. func (s *SkipListSet[K]) Has(key K) bool { return s.asMap().Has(key) } // Insert implements the SortedSet interface. func (s *SkipListSet[K]) Insert(key K) bool { oldLen := s.Len() s.asMap().Insert(key, struct{}{}) return s.Len() > oldLen } // InsertN implements the SortedSet interface. func (s *SkipListSet[K]) InsertN(keys ...K) int { oldLen := s.Len() for i := range keys { s.Insert(keys[i]) } return s.Len() - oldLen } // Remove implements the SortedSet interface. func (s *SkipListSet[K]) Remove(key K) bool { return s.asMap().Remove(key) } // RemoveN implements the SortedSet interface. func (s *SkipListSet[K]) RemoveN(keys ...K) int { oldLen := s.Len() for i := range keys { s.Remove(keys[i]) } return oldLen - s.Len() } // Keys return a copy of sorted keys as slice. func (s *SkipListSet[K]) Keys() []K { keys := make([]K, 0, s.Len()) s.ForEach(func(k K) { keys = append(keys, k) }) return keys } // ForEach implements the SortedSet interface. func (s *SkipListSet[K]) ForEach(f func(K)) { s.asMap().ForEach(func(k K, s struct{}) { f(k) }) } // ForEachIf implements the SortedSet interface. func (s *SkipListSet[K]) ForEachIf(f func(K) bool) { s.asMap().ForEachIf(func(k K, s struct{}) bool { return f(k) }) } // LowerBound implements the SortedSet interface. func (s *SkipListSet[K]) LowerBound(key K) Iterator[K] { return &skipListSetIterator[K]{s.asMap().impl.lowerBound(key), nil} } // UpperBound implements the SortedSet interface. func (s *SkipListSet[K]) UpperBound(key K) Iterator[K] { return &skipListSetIterator[K]{s.asMap().impl.upperBound(key), nil} } // FindRange implements the SortedSet interface. func (s *SkipListSet[K]) FindRange(first, last K) Iterator[K] { m := s.asMap().impl return &skipListSetIterator[K]{m.lowerBound(first), m.upperBound(last)} } func (s *SkipListSet[K]) asMap() *SkipList[K, struct{}] { return (*SkipList[K, struct{}])(s) } type skipListSetIterator[K any] skipListIterator[K, struct{}] func (it *skipListSetIterator[K]) IsNotEnd() bool { return it.node != it.end } func (it *skipListSetIterator[K]) MoveToNext() { it.node = it.node.next[0] } func (it *skipListSetIterator[K]) Value() K { return it.node.key } ================================================ FILE: skiplist_set_test.go ================================================ package stl4go import ( "testing" ) func TestNewSkipList_Interface(t *testing.T) { s := NewSkipListSet[int]() _ = SortedSet[int](s) } func TestNewSkipListSet(t *testing.T) { s := NewSkipListSet[int]() expectTrue(t, s.IsEmpty()) expectEq(t, s.Len(), 0) } func TestNewSkipListSetOf(t *testing.T) { s := NewSkipListSetOf(1, 2, 3, 4, 5) expectTrue(t, Equal(s.Keys(), []int{1, 2, 3, 4, 5})) } func TestNewSkipListSetFunc(t *testing.T) { s := NewSkipListSetFunc(OrderedCompare[int]) s.InsertN(1, 2, 3, 4, 5) expectTrue(t, Equal(s.Keys(), []int{1, 2, 3, 4, 5})) } func TestNewSkipListSet_Insert_Remove_Has(t *testing.T) { s := NewSkipListSet[int]() expectFalse(t, s.Remove(1)) expectFalse(t, s.Has(1)) expectTrue(t, s.Insert(1)) expectFalse(t, s.Insert(1)) expectTrue(t, s.Has(1)) expectFalse(t, s.IsEmpty()) expectEq(t, s.Len(), 1) expectTrue(t, s.Remove(1)) expectFalse(t, s.Remove(1)) expectFalse(t, s.Has(1)) expectTrue(t, s.IsEmpty()) expectEq(t, s.Len(), 0) } func TestNewSkipListSet_Clear(t *testing.T) { s := NewSkipListSetOf(1, 2, 3, 4, 5) s.Clear() expectTrue(t, s.IsEmpty()) expectEq(t, s.Len(), 0) } func TestNewSkipListSet_InsertN(t *testing.T) { s := NewSkipListSet[int]() expectEq(t, s.InsertN(1, 2, 3, 1), 3) expectFalse(t, s.IsEmpty()) expectEq(t, s.Len(), 3) } func TestNewSkipListSet_RemoveN(t *testing.T) { s := NewSkipListSetOf(1, 2, 3, 4) expectEq(t, s.RemoveN(2, 4, 6), 2) expectFalse(t, s.IsEmpty()) expectEq(t, s.Len(), 2) expectTrue(t, Equal(s.Keys(), []int{1, 3})) } func TestNewSkipListSet_ForEach(t *testing.T) { s := NewSkipListSetOf(1, 2, 3, 4) var a []int s.ForEach(func(i int) { a = append(a, i) }) expectTrue(t, Equal(a, []int{1, 2, 3, 4})) } func TestNewSkipListSet_ForEachIf(t *testing.T) { s := NewSkipListSetOf(1, 2, 3, 4) var a []int s.ForEachIf(func(i int) bool { a = append(a, i); return i < 2 }) expectTrue(t, Equal(a, []int{1, 2})) } func TestNewSkipList_Iterate(t *testing.T) { sl := newSkipListN(10) i := 0 for it := sl.Iterate(); it.IsNotEnd(); it.MoveToNext() { expectEq(t, it.Key(), i) expectEq(t, it.Value(), i) expectEq(t, *it.Pointer(), i) i++ } } func TestSkipListSet_Iterater(t *testing.T) { s := NewSkipListSetOf(1, 2, 4) t.Run("LowerBound", func(t *testing.T) { expectEq(t, s.LowerBound(1).Value(), 1) expectEq(t, s.LowerBound(3).Value(), 4) expectEq(t, s.LowerBound(4).Value(), 4) expectFalse(t, s.LowerBound(5).IsNotEnd()) }) t.Run("UpperBound", func(t *testing.T) { expectEq(t, s.UpperBound(0).Value(), 1) expectEq(t, s.UpperBound(1).Value(), 2) expectEq(t, s.UpperBound(3).Value(), 4) expectFalse(t, s.UpperBound(4).IsNotEnd()) expectFalse(t, s.UpperBound(5).IsNotEnd()) }) t.Run("FindRange", func(t *testing.T) { it := s.FindRange(1, 3) expectEq(t, it.Value(), 1) it.MoveToNext() expectEq(t, it.Value(), 2) }) } ================================================ FILE: skiplist_test.go ================================================ package stl4go import ( "math" "testing" ) func TestSkipList_Interface(t *testing.T) { sl := NewSkipList[int, int]() _ = Map[int, int](sl) _ = SortedMap[int, int](sl) _ = MapIterator[int, int](sl.Iterate()) _ = MutableMapIterator[int, int](sl.Iterate()) } func TestNewSkipListString(t *testing.T) { sl := NewSkipList[string, int]() sl.Insert("hello", 1) expectTrue(t, sl.Has("hello")) expectEq(t, *sl.Find("hello"), 1) expectFalse(t, sl.Has("world")) expectEq(t, sl.Find("world"), nil) } func testNewSkipListType[T Numeric](t *testing.T) { sl := NewSkipList[T, int]() var n T = 1 sl.Insert(n, 1) expectTrue(t, sl.Has(n)) expectEq(t, *sl.Find(n), 1) expectFalse(t, sl.Has(n+1)) expectEq(t, sl.Find(n+1), nil) } func TestNewSkipListInt8(t *testing.T) { testNewSkipListType[int8](t) } func TestNewSkipListInt16(t *testing.T) { testNewSkipListType[int16](t) } func TestNewSkipListInt32(t *testing.T) { testNewSkipListType[int32](t) } func TestNewSkipListInt64(t *testing.T) { testNewSkipListType[int64](t) } func TestNewSkipListUInt8(t *testing.T) { testNewSkipListType[uint8](t) } func TestNewSkipListUInt16(t *testing.T) { testNewSkipListType[uint16](t) } func TestNewSkipListUInt32(t *testing.T) { testNewSkipListType[uint32](t) } func TestNewSkipListUInt64(t *testing.T) { testNewSkipListType[uint64](t) } func TestNewSkipListUIntPtr(t *testing.T) { testNewSkipListType[uintptr](t) } func TestNewSkipListFloat32(t *testing.T) { testNewSkipListType[float32](t) } func TestNewSkipListFloat64(t *testing.T) { testNewSkipListType[float64](t) } func TestNewSkipListFunc(t *testing.T) { type Person struct { name string age int } personCmp := func(a, b Person) int { r := OrderedCompare(a.age, b.age) if r != 0 { return r } return OrderedCompare(a.name, b.name) } sl := NewSkipListFunc[Person, int](personCmp) sl.Insert(Person{"zhangsan", 20}, 1) sl.Insert(Person{"lisi", 20}, 1) sl.Insert(Person{"wangwu", 30}, 1) expectTrue(t, sl.Has(Person{"zhangsan", 20})) expectFalse(t, sl.Has(Person{"zhangsan", 30})) expectEq(t, sl.Len(), 3) sl.Insert(Person{"zhangsan", 20}, 1) expectEq(t, sl.Len(), 3) var ps []Person sl.ForEach(func(p Person, _ int) { ps = append(ps, p) }) expectEq(t, ps[0].name, "lisi") expectEq(t, ps[1].name, "zhangsan") expectEq(t, ps[2].name, "wangwu") sl.Remove(Person{"zhangsan", 20}) expectEq(t, sl.Len(), 2) sl.Remove(Person{"zhaoliu", 40}) expectEq(t, sl.Len(), 2) } func TestNewSkipListFromMap(t *testing.T) { m := map[int]int{1: -1, 2: -2, 3: -3} sl := NewSkipListFromMap(m) for k := range m { expectTrue(t, sl.Has(k)) } } func TestSkipList_Iterate(t *testing.T) { sl := newSkipListN(10) i := 0 for it := sl.Iterate(); it.IsNotEnd(); it.MoveToNext() { expectEq(t, it.Key(), i) expectEq(t, it.Value(), i) expectEq(t, *it.Pointer(), i) i++ } } func testSkipListIterater(t *testing.T, sl *SkipList[int, int]) { t.Run("LowerBound", func(t *testing.T) { expectEq(t, sl.LowerBound(1).Key(), 1) expectEq(t, sl.LowerBound(3).Key(), 4) expectEq(t, sl.LowerBound(4).Key(), 4) expectFalse(t, sl.LowerBound(5).IsNotEnd()) }) t.Run("UpperBound", func(t *testing.T) { expectEq(t, sl.UpperBound(0).Key(), 1) expectEq(t, sl.UpperBound(1).Key(), 2) expectEq(t, sl.UpperBound(3).Key(), 4) expectFalse(t, sl.UpperBound(4).IsNotEnd()) expectFalse(t, sl.UpperBound(5).IsNotEnd()) }) t.Run("FindRange", func(t *testing.T) { it := sl.FindRange(1, 3) expectEq(t, it.Key(), 1) it.MoveToNext() expectEq(t, it.Key(), 2) }) } func TestSkipList_Iterater(t *testing.T) { sl := NewSkipListFromMap(map[int]int{1: 1, 2: 2, 4: 4}) testSkipListIterater(t, sl) } func TestSkipList_Func_Iterater(t *testing.T) { sl := NewSkipListFunc[int, int](OrderedCompare[int]) m := map[int]int{1: 1, 2: 2, 4: 4} for k, v := range m { sl.Insert(k, v) } testSkipListIterater(t, sl) } func TestSkipList_Insert(t *testing.T) { sl := NewSkipList[int, int]() for i := 0; i < 100; i++ { expectEq(t, sl.Len(), i) sl.Insert(i, i) expectEq(t, sl.Len(), i+1) } } func TestSkipList_Insert_Reverse(t *testing.T) { sl := NewSkipList[int, int]() for i := 100; i > 0; i-- { oldlen := sl.Len() sl.Insert(i, i) expectEq(t, sl.Len(), oldlen+1) } } func TestSkipList_Insert_Dup(t *testing.T) { sl := NewSkipList[int, int]() sl.Insert(1, 1) expectEq(t, sl.Len(), 1) sl.Insert(1, 2) expectEq(t, sl.Len(), 1) } func newSkipListN(n int) *SkipList[int, int] { sl := NewSkipList[int, int]() sl.rander.Seed(0) for i := 0; i < n; i++ { sl.Insert(i, i) } return sl } func TestSkipList_Remove(t *testing.T) { sl := newSkipListN(100) for i := 0; i < 100; i++ { sl.Remove(i) } expectTrue(t, sl.IsEmpty()) expectEq(t, sl.Len(), 0) } func TestSkipList_Remove_Nonexist(t *testing.T) { sl := NewSkipList[int, int]() sl.Insert(1, 1) sl.Insert(2, 2) sl.Remove(0) sl.Remove(3) expectEq(t, sl.Len(), 2) } func TestSkipList_Remove_Level(t *testing.T) { sl := newSkipListN(100) expectGe(t, sl.level, 4) for i := 0; i < 100; i++ { sl.Remove(i) } expectEq(t, sl.level, 1) } func TestSkipList_Clean(t *testing.T) { sl := NewSkipList[int, int]() for i := 0; i < 100; i++ { sl.Insert(i, i) } sl.Clear() expectTrue(t, sl.IsEmpty()) expectEq(t, sl.Len(), 0) expectEq(t, sl.level, 1) } func TestSkipList_level(t *testing.T) { var diffs []int for i := 0; i < 1000; i++ { for size := 1; size < 10000; size *= 10 { sl := newSkipListN(size) log2Len := int(math.Ceil(math.Log2(float64(sl.Len())))) diffs = append(diffs, log2Len-sl.level) } } expectLt(t, math.Abs(float64(Average(diffs))), 2) } func TestSkipList_newnode(t *testing.T) { for level := 1; level <= skipListMaxLevel; level++ { node := newSkipListNode(level, 1, 1) expectEq(t, len(node.next), level) } expectPanic(t, func() { newSkipListNode(0, 1, 1) }) expectPanic(t, func() { newSkipListNode(skipListMaxLevel+1, 1, 1) }) } func TestSkipList_Find(t *testing.T) { sl := newSkipListN(100) for i := 0; i < 100; i++ { p := sl.Find(i) expectEq(t, *p, i) } expectEq(t, sl.Find(100), nil) } func TestSkipList_Has(t *testing.T) { sl := NewSkipList[int, int]() expectFalse(t, sl.Has(1)) sl.Insert(1, 2) expectTrue(t, sl.Has(1)) } 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)) } func TestSkipList_ForEachIf(t *testing.T) { sl := newSkipListN(100) a := []int{} sl.ForEachIf(func(k int, v int) bool { if k < 50 { a = append(a, k) return true } return false }) expectLt(t, MaxN(a...), 50) } 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) } } func TestSkipList_ForEachMutableIf(t *testing.T) { sl := newSkipListN(100) sl.ForEachMutableIf(func(k int, v *int) bool { if k > 50 { *v = 0 return false } return true }) expectEq(t, *sl.Find(51), 0) } ================================================ FILE: slist.go ================================================ package stl4go // SList is a singly linked list. type SList[T any] struct { head *sListNode[T] tail *sListNode[T] // To support Back and PushBack length int } type sListNode[T any] struct { next *sListNode[T] value T } // SListOf return a SList that contains values. func SListOf[T any](values ...T) SList[T] { l := SList[T]{} for i := range values { l.PushBack(values[i]) } return l } // IsEmpty checks if the container has no elements. func (l *SList[T]) IsEmpty() bool { return l.length == 0 } // Len returns the number of elements in the container. func (l *SList[T]) Len() int { return l.length } // Clear erases all elements from the container. After this call, Len() returns zero. func (l *SList[T]) Clear() { l.head = nil l.tail = nil l.length = 0 } // Front returns the first element in the list. func (l *SList[T]) Front() T { if l.IsEmpty() { panic("!IsEmpty") } return l.head.value } // Back returns the last element in the list. func (l *SList[T]) Back() T { if l.IsEmpty() { panic("!IsEmpty") } return l.tail.value } // PushFront pushed an element to the front of the list. func (l *SList[T]) PushFront(v T) { node := sListNode[T]{l.head, v} l.head = &node if l.tail == nil { l.tail = &node } l.length++ } // PushBack pushed an element to the tail of the list. func (l *SList[T]) PushBack(v T) { node := sListNode[T]{nil, v} if l.tail != nil { l.tail.next = &node } l.tail = &node if l.head == nil { l.head = &node } l.length++ } // PopFront popups an element from the front of the list. // The list must be non-empty! func (l *SList[T]) PopFront() T { if l.IsEmpty() { panic("!IsEmpty") } node := l.head l.head = node.next if l.head == nil { l.tail = nil } l.length-- return node.value } // Reverse reverses the order of all elements in the container. func (l *SList[T]) Reverse() { var head, tail *sListNode[T] for node := l.head; node != nil; { next := node.next node.next = head head = node if tail == nil { tail = node } node = next } l.head = head l.tail = tail } // Values copies all elements in the container to a slice and return it. func (l *SList[T]) Values() []T { s := make([]T, l.Len()) for node, i := l.head, 0; node != nil; node = node.next { s[i] = node.value i++ } return s } // InsertAfter inserts an element after the iterator into the list, // return an iterator to the inserted element. // func (l *SList[T]) InsertAfter(it Iterator[T], value T) MutableIterator[T] { // // cause internal compiler error: panic: runtime error: invalid memory address or nil pointer dereference // itp := it.(*sListIterator[T]) // node := itp.node // newNode := sListNode[T]{node.next, value} // node.next = &newNode // return &sListIterator[T]{&newNode} // } // ForEach iterate the list, apply each element to the cb callback function. func (l *SList[T]) ForEach(cb func(T)) { for node := l.head; node != nil; node = node.next { cb(node.value) } } // ForEachIf iterate the container, apply each element to the cb callback function, // stop if cb returns false. func (l *SList[T]) ForEachIf(cb func(T) bool) { for node := l.head; node != nil; node = node.next { if !cb(node.value) { break } } } // ForEachMutable iterate the container, apply pointer of each element to the cb callback function. func (l *SList[T]) ForEachMutable(cb func(*T)) { for node := l.head; node != nil; node = node.next { cb(&node.value) } } // ForEachMutableIf iterate the container, apply pointer of each element to the cb callback function, // stop if cb returns false. func (l *SList[T]) ForEachMutableIf(cb func(*T) bool) { for node := l.head; node != nil; node = node.next { if !cb(&node.value) { break } } } // Iterate returns an iterator to the whole container. func (l *SList[T]) Iterate() MutableIterator[T] { it := sListIterator[T]{l.head} return &it } type sListIterator[T any] struct { node *sListNode[T] } func (it *sListIterator[T]) IsNotEnd() bool { return it.node != nil } func (it *sListIterator[T]) MoveToNext() { it.node = it.node.next } func (it *sListIterator[T]) Value() T { return it.node.value } func (it *sListIterator[T]) Pointer() *T { return &it.node.value } // TODO: Sort ================================================ FILE: slist_test.go ================================================ package stl4go import ( "testing" ) func Test_SList_Interface(t *testing.T) { sl := SList[int]{} _ = Container(&sl) } func Test_SList_Clean(t *testing.T) { sl := SList[int]{} sl.PushFront(1) sl.Clear() expectTrue(t, sl.IsEmpty()) expectEq(t, sl.Len(), 0) } func Test_SList_Front(t *testing.T) { t.Run("empty", func(t *testing.T) { sl := SList[int]{} expectPanic(t, func() { sl.Front() }) }) t.Run("normal", func(t *testing.T) { sl := SList[int]{} sl.PushFront(1) expectEq(t, sl.Front(), 1) sl.PushBack(2) expectEq(t, sl.Front(), 1) sl.PushFront(3) expectEq(t, sl.Front(), 3) }) } func Test_SList_Back(t *testing.T) { t.Run("empty", func(t *testing.T) { sl := SList[int]{} expectPanic(t, func() { sl.Back() }) }) t.Run("normal", func(t *testing.T) { sl := SList[int]{} sl.PushBack(1) expectEq(t, sl.Back(), 1) sl.PushFront(2) expectEq(t, sl.Back(), 1) sl.PushBack(3) expectEq(t, sl.Back(), 3) }) } func Test_SList_PushFront(t *testing.T) { sl := SList[int]{} for i := 1; i < 10; i++ { sl.PushFront(i) expectEq(t, sl.Front(), i) expectEq(t, sl.Len(), i) } } func Test_SList_PushBack(t *testing.T) { sl := SList[int]{} for i := 1; i < 10; i++ { sl.PushBack(i) expectEq(t, sl.Back(), i) expectEq(t, sl.Len(), i) expectFalse(t, sl.IsEmpty()) } } func Test_SList_PopFront(t *testing.T) { sl := SList[int]{} expectPanic(t, func() { sl.PopFront() }) sl.PushFront(1) sl.PushFront(2) expectEq(t, sl.PopFront(), 2) expectEq(t, sl.PopFront(), 1) expectPanic(t, func() { sl.PopFront() }) } func Test_SList_Reverse(t *testing.T) { sl := SListOf(1, 2, 3, 4) sl.Reverse() expectTrue(t, Equal(sl.Values(), []int{4, 3, 2, 1})) } func Test_SList_ForEach(t *testing.T) { sl := SListOf(1, 2, 3, 4) i := 0 sl.ForEach(func(v int) { i++ expectEq(t, v, i) }) expectEq(t, i, sl.Len()) } func Test_SList_ForEachIf(t *testing.T) { sl := SListOf(1, 2, 3, 4) i := 0 sl.ForEachIf(func(v int) bool { i++ expectEq(t, v, i) return i < 3 }) expectEq(t, i, 3) } func Test_SList_ForEachMutable(t *testing.T) { sl := SListOf(1, 2, 3, 4) i := 0 sl.ForEachMutable(func(v *int) { i++ expectEq(t, *v, i) *v = -*v }) expectEq(t, i, sl.Len()) sl.ForEachMutable(func(v *int) { expectLt(t, *v, 0) }) } func Test_SList_ForEachMutableIf(t *testing.T) { sl := SListOf(1, 2, 3, 4) i := 0 sl.ForEachMutableIf(func(v *int) bool { i++ expectEq(t, *v, i) return i < 3 }) expectEq(t, i, 3) } func Test_SList_Iterate(t *testing.T) { sl := SList[int]{} sl.PushBack(1) sl.PushBack(2) sl.PushBack(3) i := 0 for it := sl.Iterate(); it.IsNotEnd(); it.MoveToNext() { i++ expectEq(t, it.Value(), i) expectEq(t, *it.Pointer(), i) } expectEq(t, i, 3) } ================================================ FILE: sort.go ================================================ package stl4go import ( "sort" ) // IsSorted returns whether the slice a is sorted in ascending order. // // Complexity: O(len(a)). func IsSorted[T Ordered](a []T) bool { if len(a) == 0 { return true } prev := a[0] for _, v := range a[1:] { if v < prev { return false } prev = v } return true } // IsDescSorted returns whether the slice a is sorted in descending order. // // Complexity: O(len(a)). func IsDescSorted[T Ordered](a []T) bool { if len(a) == 0 { return true } prev := a[0] for _, v := range a[1:] { if v > prev { return false } prev = v } return true } type ascSlice[T Ordered] []T func (x ascSlice[T]) Len() int { return len(x) } func (x ascSlice[T]) Less(i, j int) bool { return x[i] < x[j] } func (x ascSlice[T]) Swap(i, j int) { x[i], x[j] = x[j], x[i] } // Sort sorts data in ascending order. // The order of equal elements is not guaranteed to be preserved. // // Complexity: O(N*log(N)), where N=len(a). func Sort[T Ordered](a []T) { sort.Sort(ascSlice[T](a)) } // StableSort sorts data in ascending order stably. // The order of equivalent elements is guaranteed to be preserved. // // Complexity: O(N*log(N)^2), where N=len(a). func StableSort[T Ordered](a []T) { sort.Stable(ascSlice[T](a)) } type descSlice[T Ordered] []T func (x descSlice[T]) Len() int { return len(x) } func (x descSlice[T]) Less(i, j int) bool { return x[i] > x[j] } func (x descSlice[T]) Swap(i, j int) { x[i], x[j] = x[j], x[i] } // DescSort sorts data in descending order. // The order of equal elements is not guaranteed to be preserved. // // Complexity: O(N*log(N)), N=len(a). func DescSort[T Ordered](a []T) { sort.Sort(descSlice[T](a)) } // DescStableSort sorts data in descending order stably. // The order of equivalent elements is guaranteed to be preserved. // // Complexity: O(N*log(N)), N=len(a). func DescStableSort[T Ordered](a []T) { sort.Stable(descSlice[T](a)) } type funcSortable[T any] struct { e []T less LessFn[T] } func (x funcSortable[T]) Len() int { return len(x.e) } func (x funcSortable[T]) Less(i, j int) bool { return x.less(x.e[i], x.e[j]) } func (x funcSortable[T]) Swap(i, j int) { x.e[i], x.e[j] = x.e[j], x.e[i] } // SortFunc sorts data in ascending order with compare func less. // The order of equal elements is not guaranteed to be preserved. // // Complexity: O(N*log(N)), N=len(a). func SortFunc[T any](a []T, less func(x, y T) bool) { sort.Sort(funcSortable[T]{a, less}) } // StableSortFunc sorts data in ascending order with compare func less stably. // The order of equivalent elements is guaranteed to be preserved. // // Complexity: O(N*log(N)), N=len(a). func StableSortFunc[T any](a []T, less func(x, y T) bool) { sort.Stable(funcSortable[T]{a, less}) } ================================================ FILE: sort_test.go ================================================ package stl4go import ( "testing" ) func Test_IsSorted(t *testing.T) { expectTrue(t, IsSorted([]int{})) expectTrue(t, IsSorted([]int{1, 2, 3, 4})) expectTrue(t, IsSorted([]int{1, 2, 2, 3, 4})) expectFalse(t, IsSorted([]int{1, 2, 2, 3, 2})) } func Test_IsDescSorted(t *testing.T) { expectTrue(t, IsDescSorted([]int{})) expectFalse(t, IsDescSorted([]int{1, 2, 3, 4})) expectFalse(t, IsDescSorted([]int{1, 2, 2, 3, 4})) expectTrue(t, IsDescSorted([]int{5, 4, 3, 3, 2})) } func Test_Sort(t *testing.T) { a := []int{5, 4, 3, 2, 1} Sort(a) expectTrue(t, IsSorted(a)) } func Test_DescSort(t *testing.T) { a := []int{1, 2, 3, 4} DescSort(a) expectTrue(t, IsDescSorted(a)) } func Test_StableSort(t *testing.T) { a := []int{5, 4, 3, 2, 1} StableSort(a) expectTrue(t, IsSorted(a)) } func Test_DescStableSort(t *testing.T) { a := []int{1, 2, 3, 4, 5} DescStableSort(a) expectTrue(t, IsDescSorted(a)) } func greater(x, y int) bool { return x > y } func Test_SortFunc(t *testing.T) { a := []int{1, 2, 3, 4, 5} SortFunc(a, greater) expectTrue(t, IsDescSorted(a)) } func Test_StableSortFunc(t *testing.T) { a := []int{1, 2, 3, 4, 5} StableSortFunc(a, greater) expectTrue(t, IsDescSorted(a)) } ================================================ FILE: stack.go ================================================ package stl4go // Stack s is a container adaptor that provides the functionality of a stack, // a LIFO (last-in, first-out) data structure. type Stack[T any] struct { elements []T } // NewStack creates a new Stack object. func NewStack[T any]() *Stack[T] { return &Stack[T]{nil} } // NewStackCap creates a new Stack object with the specified capicity. func NewStackCap[T any](capicity int) *Stack[T] { return &Stack[T]{make([]T, 0, capicity)} } // IsEmpty implements the Container interface. func (s Stack[T]) IsEmpty() bool { return len(s.elements) == 0 } // Len implements the Container interface. func (s Stack[T]) Len() int { return len(s.elements) } // Cap returns the capacity of the stack. func (s Stack[T]) Cap() int { return cap(s.elements) } // Clear implements the Container interface. func (s *Stack[T]) Clear() { s.elements = s.elements[0:0] } // Push pushes the element to the top of the stack. func (s *Stack[T]) Push(t T) { s.elements = append(s.elements, t) } // TryPop tries to popup an element from the top of the stack. func (s *Stack[T]) TryPop() (val T, ok bool) { var t T if len(s.elements) == 0 { return t, false } t = s.elements[len(s.elements)-1] s.elements = s.elements[:len(s.elements)-1] return t, true } // Pop popups an element from the top of the stack. // It must be called when IsEmpty() returned false, // otherwise it will panic. func (s *Stack[T]) Pop() T { t := s.elements[len(s.elements)-1] s.elements = s.elements[:len(s.elements)-1] return t } // Top returns the top element in the stack. // It must be called when s.IsEmpty() returned false, // otherwise it will panic. func (s Stack[T]) Top() T { return s.elements[len(s.elements)-1] } ================================================ FILE: stack_test.go ================================================ package stl4go import ( "testing" ) func Test_Stack_Interface(t *testing.T) { _ = Container(NewStack[int]()) } func Test_NewStack(t *testing.T) { si := NewStack[int]() ss := NewStack[string]() expectEq(t, si.Len(), 0) expectEq(t, ss.Len(), 0) } func Test_NewStackCap(t *testing.T) { s := NewStackCap[int](10) expectEq(t, s.Len(), 0) expectEq(t, s.Cap(), 10) } func Test_StackCap(t *testing.T) { s := NewStackCap[int](10) s.Push(1) expectEq(t, s.Len(), 1) expectEq(t, s.Cap(), 10) } func Test_Stack_Clear(t *testing.T) { s := NewStack[int]() s.Push(1) s.Push(2) s.Clear() expectEq(t, s.Len(), 0) expectTrue(t, s.IsEmpty()) } func Test_Stack_Push(t *testing.T) { s := NewStack[int]() s.Push(1) expectEq(t, s.Len(), 1) s.Push(2) expectEq(t, s.Len(), 2) } func Test_Stack_TryPop(t *testing.T) { s := NewStack[int]() _, ok := s.TryPop() expectFalse(t, ok) s.Push(1) v, ok := s.TryPop() expectTrue(t, ok) expectEq(t, v, 1) } func Test_Stack_Pop(t *testing.T) { s := NewStack[int]() s.Push(1) v := s.Pop() expectEq(t, v, 1) expectPanic(t, func() { s.Pop() }) } func Test_Stack_Top(t *testing.T) { s := NewStack[int]() s.Push(1) v := s.Top() expectEq(t, v, 1) s.Pop() expectPanic(t, func() { s.Top() }) } ================================================ FILE: test_helper.go ================================================ package stl4go import ( "fmt" "testing" ) func report(t *testing.T, msg string) { t.Helper() t.Errorf("Wrong: %v\n", msg) } func reportMismatch[T comparable](t *testing.T, a T, op string, b T) { t.Helper() report(t, fmt.Sprintf("%v %v %v", a, op, b)) } func expectEq[T comparable](t *testing.T, a, b T) { t.Helper() if a != b { reportMismatch(t, a, "==", b) } } func expectNe[T comparable](t *testing.T, a, b T) { t.Helper() if !(a != b) { reportMismatch(t, a, "!=", b) } } func expectLt[T Ordered](t *testing.T, a, b T) { t.Helper() if !(a < b) { reportMismatch(t, a, "<", b) } } func expectGt[T Ordered](t *testing.T, a, b T) { t.Helper() if !(a > b) { reportMismatch(t, a, ">", b) } } func expectLe[T Ordered](t *testing.T, a, b T) { t.Helper() if !(a <= b) { reportMismatch(t, a, "<=", b) } } func expectGe[T Ordered](t *testing.T, a, b T) { t.Helper() if !(a >= b) { reportMismatch(t, a, ">=", b) } } func expectTrue(t *testing.T, actual bool) { t.Helper() if !actual { reportMismatch(t, actual, "==", true) } } func expectFalse(t *testing.T, actual bool) { t.Helper() if actual { reportMismatch(t, actual, "==", false) } } func expectPanic(t *testing.T, f func()) { t.Helper() defer func() { t.Helper() if r := recover(); r == nil { report(t, "din't panic") } }() f() } ================================================ FILE: transform.go ================================================ package stl4go import "math/rand" // Copy make a copy of slice a. // // Complexity: O(len(a)). func Copy[T any](a []T) []T { return append([]T{}, a...) } // CopyTo copies all elements in slice a to slice to, return the copied slice. // if slice to is large enough, no memory allocation occurs. // // Complexity: O(len(a)). func CopyTo[T any](a []T, to []T) []T { b := append(to[0:0], a...) return b } // Fill fills each element in slice a with new value v. // // Complexity: O(len(a)). func Fill[T any](a []T, v T) { if len(a) == 0 { return } // Preload the first value into the array/slice. a[0] = v // Incrementally duplicate the value into the rest of the container. // About 2~3 times faster than naive fill. // https://gist.github.com/taylorza/df2f89d5f9ab3ffd06865062a4cf015d for j := 1; j < len(a); j *= 2 { copy(a[j:], a[:j]) } } // FillPattern fills elements in slice a with specified pattern. // // Complexity: O(len(a)). func FillPattern[T any](a []T, pattern []T) { if len(pattern) == 0 { panic("pattern can't be empty") } // Copy the pattern into the start of the container copy(a, pattern) // Incrementally duplicate the pattern throughout the container for j := len(pattern); j < len(a); j *= 2 { copy(a[j:], a[:j]) } } // TransformTo applies the function op to each element in slice a and fill it to slice b, // return the transformed slice. // If cap(b) >= len(a), no memory allocation. // // Complexity: O(len(a)). func TransformTo[R any, T any](a []T, op func(T) R, b []R) []R { b = b[0:0] for i := range a { b = append(b, op(a[i])) } return b } // Transform applies the function op to each element in slice a and set it back to the same place in a. // // Complexity: O(len(a)). func Transform[T any](a []T, op func(T) T) { for i, v := range a { a[i] = op(v) } } // TransformCopy applies the function op to each element in slice a and return all the result as a slice. // // Complexity: O(len(a)). func TransformCopy[R any, T any](a []T, op func(T) R) []R { r := make([]R, len(a)) for i, v := range a { r[i] = op(v) } return r } // Replace replaces every element that equals to old with new. // // Complexity: O(len(a)). func Replace[T comparable](a []T, old, new T) { for i := range a { if a[i] == old { a[i] = new } } } // ReplaceIf replaces every element that make preq returns true with new. // // Complexity: O(len(a)). func ReplaceIf[T any](a []T, pred func(v T) bool, new T) { for i := range a { if pred(a[i]) { a[i] = new } } } // Unique remove adjacent repeated elements from the input slice. // return the processed slice with new length. // // Complexity: O(len(a)). func Unique[T comparable](a []T) []T { if len(a) == 0 { return a } i := 1 prev := a[0] for _, v := range a[1:] { if v != prev { a[i] = v i++ prev = v } } return a[:i] } // UniqueCopy remove adjacent repeated elements from the input slice. // return the result slice, and the input slice is kept unchanged. // // Complexity: O(len(a)). func UniqueCopy[T comparable](a []T) []T { var r []T if len(a) == 0 { return r } for _, v := range a { if len(r) > 0 && r[len(r)-1] == v { continue } r = append(r, v) } return r } // Remove remove the elements which equals to x from the input slice. // return the processed slice with new length. // // Complexity: O(len(a)). func Remove[T comparable](a []T, x T) []T { j := 0 for _, v := range a { if v != x { a[j] = v j++ } } return a[:j] } // RemoveCopy remove all elements which equals to x from the input slice. // return a new slice with processed results. The input slice is kept unchanged. // // Complexity: O(len(a)). func RemoveCopy[T comparable](a []T, x T) []T { r := make([]T, 0, len(a)) for _, v := range a { if v != x { r = append(r, v) } } return r } // RemoveIf remove each element which make cond(x) returns true from the input slice, // copy other elements to a new slice and return it. // // Complexity: O(len(a)). func RemoveIf[T any](a []T, cond func(T) bool) []T { j := 0 for _, v := range a { if !cond(v) { a[j] = v j++ } } return a[:j] } // RemoveIfCopy drops each element which make cond(x) returns true from the input slice, // copy other elements to a new slice and return it. The input slice is kept unchanged. // // Complexity: O(len(a)). func RemoveIfCopy[T any](a []T, cond func(T) bool) []T { r := make([]T, 0, len(a)) for _, v := range a { if !cond(v) { r = append(r, v) } } return r } // Shuffle pseudo-randomizes the order of elements. // // Complexity: O(len(a)). func Shuffle[T any](a []T) { rand.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] }) } // Reverse reverses the order of the elements in the slice a. // // Complexity: O(len(a)). func Reverse[T any](a []T) { for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { a[i], a[j] = a[j], a[i] } } // ReverseCopy returns a reversed copy of slice a. // // Complexity: O(len(a)). func ReverseCopy[T any](a []T) []T { b := make([]T, 0, len(a)) for i := len(a) - 1; i >= 0; i-- { b = append(b, a[i]) } return b } ================================================ FILE: transform_fillzero_clear.go ================================================ //go:build go1.21 // +build go1.21 package stl4go // FillZero fills each element in slice a with zero value. // // Complexity: O(len(a)). func FillZero[T any](a []T) { clear(a) } ================================================ FILE: transform_fillzero_old.go ================================================ //go:build !go1.21 // +build !go1.21 package stl4go // FillZero fills each element in slice a with zero value. // // Complexity: O(len(a)). func FillZero[T any](a []T) { var zero T Fill(a, zero) } ================================================ FILE: transform_test.go ================================================ package stl4go import ( "strconv" "testing" ) var ( emptyInts = []int{} ) func Test_Copy(t *testing.T) { a := []int{1, 2, 3, 4} b := Copy(a) expectTrue(t, Equal(a, b)) } func Test_CopyTo(t *testing.T) { a := []int{1, 2, 3, 4} tos := [][]int{nil, make([]int, 0), make([]int, 10)} for _, to := range tos { b := CopyTo(a, to) expectTrue(t, Equal(a, b)) } } func Test_Fill(t *testing.T) { a := []int{1, 2, 3, 4} Fill(a, 1) expectTrue(t, Equal(a, []int{1, 1, 1, 1})) b := a[:0] Fill(b, 2) expectTrue(t, Equal(a, []int{1, 1, 1, 1})) } func Test_FillZero(t *testing.T) { a := []int{1, 2, 3, 4} FillZero(a) expectTrue(t, Equal(a, []int{0, 0, 0, 0})) } func naiveFill[T any](a []T, v T) { for i := range a { a[i] = v } } func BenchmarkFill(b *testing.B) { a := make([]int, 10000) b.Run("Fill", func(b *testing.B) { for i := 0; i < b.N; i++ { Fill(a, 1) } }) b.Run("naiveFill", func(b *testing.B) { for i := 0; i < b.N; i++ { naiveFill(a, 1) } }) } func Test_FillPattern(t *testing.T) { a := make([]int, 10) p := []int{1, 2, 3} FillPattern(a, p) expectTrue(t, Equal(a, []int{1, 2, 3, 1, 2, 3, 1, 2, 3, 1})) expectPanic(t, func() { FillPattern(a, []int{}) }) } func Test_Transform(t *testing.T) { a := Range(0, 100) Transform(a, func(v int) int { return v * v }) for i, v := range a { expectEq(t, v, i*i) } } func Test_TransformTo(t *testing.T) { a := Range(0, 100) b := make([]string, len(a)) r1 := TransformTo(a, func(v int) string { return strconv.Itoa(v) }, b) for i, v := range a { expectEq(t, b[i], strconv.Itoa(v)) } expectEq(t, &r1[0], &b[0]) c := make([]string, len(a)-1) r2 := TransformTo(a, func(v int) string { return strconv.Itoa(v) }, c) expectEq(t, len(a), len(r2)) expectNe(t, &r2[0], &c[0]) } func Test_TransformCopy(t *testing.T) { a := Range(0, 100) b := TransformCopy(a, func(v int) string { return strconv.Itoa(v) }) for i, v := range b { expectEq(t, v, strconv.Itoa(i)) } } func Test_Replace(t *testing.T) { a := []int{1, 2, 2, 4} Replace(a, 2, 3) expectTrue(t, Equal(a, []int{1, 3, 3, 4})) } func Test_ReplaceIf(t *testing.T) { a := []int{1, 2, 2, 4} ReplaceIf(a, func(n int) bool { return n == 2 }, 3) expectTrue(t, Equal(a, []int{1, 3, 3, 4})) } func Test_Unique(t *testing.T) { expectTrue(t, Equal(Unique(emptyInts), emptyInts)) a := []int{1, 2, 2, 3, 2, 4} b := []int{1, 2, 3, 2, 4} expectTrue(t, Equal(Unique(a), b)) expectTrue(t, Equal(Unique(a[:len(b)]), b)) } func Test_UniqueCopy(t *testing.T) { expectTrue(t, Equal(UniqueCopy(emptyInts), emptyInts)) a := []int{1, 2, 2, 3, 2, 4} a1 := append([]int{}, a...) b := []int{1, 2, 3, 2, 4} expectTrue(t, Equal(UniqueCopy(a), b)) expectTrue(t, Equal(a, a1)) } func Test_Remove(t *testing.T) { a := []int{1, 2, 2, 3, 2, 4} b := Remove(a, 2) expectTrue(t, Equal([]int{1, 3, 4}, b)) expectTrue(t, Equal([]int{1, 3, 4}, a[:len(b)])) } func Test_RemoveCopy(t *testing.T) { a := []int{1, 2, 2, 3, 2, 4} a1 := []int{1, 2, 2, 3, 2, 4} b := RemoveCopy(a, 2) expectTrue(t, Equal([]int{1, 3, 4}, b)) expectTrue(t, Equal(a1, a)) } func Test_RemoveIf(t *testing.T) { a := []int{1, 2, 2, 3, 2, 4} b := RemoveIf(a, func(v int) bool { return v == 2 }) expectTrue(t, Equal([]int{1, 3, 4}, b)) expectTrue(t, Equal([]int{1, 3, 4}, a[:len(b)])) } func Test_RemoveIfCopy(t *testing.T) { a := []int{1, 2, 2, 3, 2, 4} a1 := []int{1, 2, 2, 3, 2, 4} b := RemoveIfCopy(a, func(v int) bool { return v == 2 }) expectTrue(t, Equal([]int{1, 3, 4}, b)) expectTrue(t, Equal(a1, a)) } func Test_Shuffle(t *testing.T) { a := []int{1, 2, 3, 4, 5, 6} Shuffle(a) } func Test_Reverse(t *testing.T) { a := []int{1, 2, 3, 4} Reverse(a) expectTrue(t, Equal(a, []int{4, 3, 2, 1})) } func Test_Reverse_Odd(t *testing.T) { a := []int{1, 2, 3, 4, 5} Reverse(a) expectTrue(t, Equal(a, []int{5, 4, 3, 2, 1})) } func Test_ReverseCopy(t *testing.T) { a := []int{1, 2, 3, 4, 5} b := ReverseCopy(a) expectTrue(t, Equal(b, []int{5, 4, 3, 2, 1})) } ================================================ FILE: types.go ================================================ package stl4go // Signed is a constraint that permits any signed integer type. // If future releases of Go add new predeclared signed integer types, // this constraint will be modified to include them. type Signed interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 } // Unsigned is a constraint that permits any unsigned integer type. // If future releases of Go add new predeclared unsigned integer types, // this constraint will be modified to include them. type Unsigned interface { ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr } // Integer is a constraint that permits any integer type. // If future releases of Go add new predeclared integer types, // this constraint will be modified to include them. type Integer interface { Signed | Unsigned } // Float is a constraint that permits any floating-point type. // If future releases of Go add new predeclared floating-point types, // this constraint will be modified to include them. type Float interface { ~float32 | ~float64 } // Ordered is a constraint that permits any ordered type: any type // that supports the operators < <= >= >. // If future releases of Go add new ordered types, // this constraint will be modified to include them. type Ordered interface { Integer | Float | ~string } // Numeric is a constraint that permits any numeric type. type Numeric interface { Integer | Float } // LessFn is a function that returns whether 'a' is less than 'b'. type LessFn[T any] func(a, b T) bool // CompareFn is a 3 way compare function that // returns 1 if a > b, // returns 0 if a == b, // returns -1 if a < b. type CompareFn[T any] func(a, b T) int // HashFn is a function that returns the hash of 't'. type HashFn[T any] func(t T) uint64 ================================================ FILE: updatedoc.bat ================================================ @echo off gomarkdoc -o generated_doc.md -e . ================================================ FILE: updatedoc.sh ================================================ #!/bin/bash gomarkdoc -o generated_doc.md -e . ================================================ FILE: vector.go ================================================ package stl4go // Many tricks are from: // https://github.com/golang/go/wiki/SliceTricks#in-place-deduplicate-comparable // Vector is a sequence container representing array that can change in size. type Vector[T any] []T // MakeVector creates an empty Vector object. func MakeVector[T any]() Vector[T] { return (Vector[T])([]T{}) } // MakeVectorCap creates an empty Vector object with specified capacity. func MakeVectorCap[T any](c int) Vector[T] { v := make([]T, 0, c) return (Vector[T])(v) } // VectorOf creates a Vector object with initial values. func VectorOf[T any](v ...T) Vector[T] { return (Vector[T])(v) } // AsVector casts a slice as a Vector object. func AsVector[T any](s []T) Vector[T] { return (Vector[T])(s) } // IsEmpty implements the Container interface. func (v *Vector[T]) IsEmpty() bool { return len(*v) == 0 } // Len implements the Container interface. func (v *Vector[T]) Len() int { return len(*v) } // Cap returns the capacity of the vector. func (v *Vector[T]) Cap() int { return cap(*v) } // Clear erases all elements from the vector. After this call, Len() returns zero. // Leaves the Cap() of the vector unchanged. func (v *Vector[T]) Clear() { FillZero(*v) *v = (*v)[0:0] } // Reserve increases the capacity of the vector (the total number of elements // that the vector can hold without requiring reallocation)to a value that's // greater or equal to l. If l is greater than the current Cap(), new storage // is allocated, otherwise the function does nothing. // // Reserve() does not change the size of the vector. func (v *Vector[T]) Reserve(l int) { if cap(*v) < l { t := make([]T, len(*v), l) copy(t, *v) *v = t } } // Shrink removes unused capacity from the vector. func (v *Vector[T]) Shrink() { if cap(*v) > len(*v) { *v = append([]T{}, *v...) } } // At returns the element value at the index i. // You can also use the [] operator, and it's better. func (v *Vector[T]) At(i int) T { return (*v)[i] } // Set sets the value of the element at the index i. // You can also use the [] operator, and it's better. func (v *Vector[T]) Set(i int, x T) { (*v)[i] = x } // PushBack pushs an element to the end of the vector. // // Complexity: O(1) if v.Len() < v.Cap(), therwise O(len(v)). func (v *Vector[T]) PushBack(x T) { *v = append(*v, x) } // PopBack popups an element from the end of the vector. // It must be called when IsEmpty() returned false, // otherwise it will panic. func (v *Vector[T]) PopBack() T { var zero T e := (*v)[v.Len()-1] (*v)[len(*v)-1] = zero *v = (*v)[0 : v.Len()-1] return e } // TryPopBack popups an element from the end of the vector. func (v *Vector[T]) TryPopBack() (T, bool) { if v.IsEmpty() { var zero T return zero, false } return v.PopBack(), true } // Back returns the element at the end of the vector. // It must be called when IsEmpty() returned false, // otherwise it will panic. func (v Vector[T]) Back() T { return v[len(v)-1] } // Append appends the values x... to the tail of the vector. func (v *Vector[T]) Append(x ...T) { *v = append(*v, x...) } // Insert inserts the values x... into the vector at index i. // After the insertion, (*v)[i] == x[0]. // Insert panics if i is out of range. // // Complexity: O(len(s) + len(v)). func (v *Vector[T]) Insert(i int, x ...T) { s := *v total := len(s) + len(x) if total <= cap(s) { s2 := s[:total] copy(s2[i+len(x):], s[i:]) copy(s2[i:], x) *v = s2 return } s2 := make([]T, total) copy(s2, s[:i]) copy(s2[i:], x) copy(s2[i+len(x):], s[i:]) *v = s2 } // Remove removes 1 element in the vector. // // Complexity: O(len(s) - i). func (v *Vector[T]) Remove(i int) { v.RemoveRange(i, i+1) } // RemoveRange removes the elements in the range[i, j) from the vector. func (v *Vector[T]) RemoveRange(i, j int) { oldV := *v *v = append((*v)[:i], (*v)[j:]...) FillZero(oldV[v.Len():]) } // RemoveLength removes the elements in the range[i, i+len) from the vector. func (v *Vector[T]) RemoveLength(i int, len int) { v.RemoveRange(i, i+len) } // RemoveIf removes the elements which make cond(x) returns true from the vector. func (v *Vector[T]) RemoveIf(cond func(T) bool) { oldV := *v *v = RemoveIf(*v, cond) FillZero(oldV[v.Len():]) } // ForEach iterate the container, apply each element to the cb callback function. func (v Vector[T]) ForEach(cb func(val T)) { for _, e := range v { cb(e) } } // ForEachIf iterate the container, apply each element to the cb callback function, // stop if cb returns false. func (v Vector[T]) ForEachIf(cb func(val T) bool) { for _, e := range v { if !cb(e) { break } } } // ForEachMutable iterate the container, apply pointer of each element to the cb callback function. func (v Vector[T]) ForEachMutable(cb func(val *T)) { for i := range v { cb(&v[i]) } } // ForEachMutableIf iterate the container, apply pointer of each element to the cb callback function, // stop if cb returns false. func (v Vector[T]) ForEachMutableIf(cb func(val *T) bool) { for i := range v { if !cb(&v[i]) { break } } } // Iterate returns an iterator to the whole container. func (v Vector[T]) Iterate() MutableIterator[T] { return &vectorIterator[T]{v, 0} } // IterateRange returns an iterator to the range [i, j) of the container. func (v Vector[T]) IterateRange(i, j int) MutableIterator[T] { return &vectorIterator[T]{v[i:j], 0} } type vectorIterator[T any] struct { v Vector[T] i int } func (it vectorIterator[T]) Value() T { return it.v[it.i] } func (it vectorIterator[T]) Pointer() *T { return &it.v[it.i] } func (it vectorIterator[T]) IsNotEnd() bool { return it.i < len(it.v) } func (it *vectorIterator[T]) MoveToNext() { it.i++ } ================================================ FILE: vector_test.go ================================================ package stl4go import ( "testing" ) func Test_Vector_Interface(t *testing.T) { v := MakeVector[int]() _ = Container(&v) } func Test_MakeVector(t *testing.T) { MakeVector[int]() _ = make(Vector[int], 1) _ = make(Vector[int], 1, 2) var v Vector[int] _ = v v = Vector[int]{1, 2, 3} } func Test_MakeVectorCap(t *testing.T) { v := MakeVectorCap[int](10) expectEq(t, v.Len(), 0) expectEq(t, v.Cap(), 10) } func Test_VectorOf(t *testing.T) { v := VectorOf(1, 2, 3) expectEq(t, v.Len(), 3) expectEq(t, v.Cap(), 3) expectEq(t, v[0], 1) expectEq(t, v[1], 2) expectEq(t, v[2], 3) } func Test_AsVector(t *testing.T) { s := []int{1, 2, 3} v := AsVector(s) expectTrue(t, Equal(s, v)) expectEq(t, &s[0], &v[0]) } func Test_VectorCap(t *testing.T) { v := MakeVectorCap[int](10) v.PushBack(1) expectEq(t, v.Len(), 1) expectFalse(t, v.IsEmpty()) expectEq(t, v.Cap(), 10) } func Test_Vector_Clear(t *testing.T) { v := VectorOf(1, 2, 3) v.Clear() expectEq(t, v.Len(), 0) expectTrue(t, v.IsEmpty()) expectGt(t, v.Cap(), 0) } func Test_Vector_Reserve(t *testing.T) { v := VectorOf(1, 2, 3) v.Reserve(1) expectEq(t, v.Cap(), 3) v.Reserve(5) expectEq(t, v.Cap(), 5) expectEq(t, v.Len(), 3) } func Test_Vector_Shrink(t *testing.T) { v := MakeVectorCap[int](10) v.Append(1, 2, 3) expectEq(t, v.Cap(), 10) v.Shrink() expectEq(t, v.Len(), v.Cap()) } func Test_Vector_At_Set(t *testing.T) { v := VectorOf(1, 2, 3) expectEq(t, v.At(0), 1) expectEq(t, v[0], 1) v[0] = 2 expectEq(t, v[0], 2) expectPanic(t, func() { v.Set(3, 2) }) } func Test_Vector_PushBack(t *testing.T) { v := VectorOf(1, 2, 3) v.PushBack(4) expectTrue(t, Equal(v, []int{1, 2, 3, 4})) } func Test_Vector_PopBack(t *testing.T) { v := VectorOf(1, 2) expectEq(t, v.PopBack(), 2) n, ok := v.TryPopBack() expectEq(t, n, 1) expectTrue(t, ok) n, ok = v.TryPopBack() expectEq(t, n, 0) expectFalse(t, ok) expectPanic(t, func() { v.PopBack() }) } func Test_Vector_PopBack_Clear(t *testing.T) { v := VectorOf(1, 2) oldV := v v.PopBack() expectEq(t, oldV[1], 0) } func Test_Vector_Back(t *testing.T) { v := VectorOf(1) expectEq(t, v.Back(), 1) v.PopBack() expectPanic(t, func() { v.Back() }) } func Test_Vector_Insert(t *testing.T) { v := VectorOf(1, 2, 3) v.Insert(0, 1, 2, 3) expectTrue(t, Equal(v, []int{1, 2, 3, 1, 2, 3})) } func Test_Vector_Insert_Tail(t *testing.T) { v := VectorOf(1, 2, 3) v.Insert(3, 1, 2, 3) expectTrue(t, Equal(v, []int{1, 2, 3, 1, 2, 3})) } func Test_Vector_Insert_Mid(t *testing.T) { v := VectorOf(1, 2, 3) v.Insert(2, 1, 2) expectTrue(t, Equal(v, []int{1, 2, 1, 2, 3})) } func Test_Vector_Insert_Cap(t *testing.T) { v := VectorOf(1, 2, 3) v.Reserve(8) v.Insert(2, 1, 2) expectTrue(t, Equal(v, []int{1, 2, 1, 2, 3})) } func Test_Vector_Remove(t *testing.T) { v := VectorOf(1, 2, 3) oldV := v v.Remove(1) expectEq(t, v.Len(), 2) expectEq(t, v.Cap(), 3) expectEq(t, v[0], 1) expectEq(t, v[1], 3) expectEq(t, oldV[2], 0) } func Test_Vector_RemoveRange(t *testing.T) { v := VectorOf(1, 2, 3, 4) oldV := v v.RemoveRange(1, 3) expectEq(t, v.Len(), 2) expectEq(t, v.Cap(), 4) expectEq(t, v[0], 1) expectEq(t, v[1], 4) expectEq(t, oldV[2], 0) expectEq(t, oldV[3], 0) } func Test_Vector_RemoveLength(t *testing.T) { v := VectorOf(1, 2, 3, 4) oldV := v v.RemoveLength(1, 2) expectEq(t, v.Len(), 2) expectEq(t, v.Cap(), 4) expectEq(t, v[0], 1) expectEq(t, v[1], 4) expectEq(t, oldV[2], 0) expectEq(t, oldV[3], 0) } func Test_Vector_RemoveIf(t *testing.T) { v := VectorOf(1, 2, 3, 4) oldV := v v.RemoveIf(func(i int) bool { return i%2 == 0 }) expectEq(t, v.Len(), 2) expectEq(t, v.Cap(), 4) expectEq(t, v[0], 1) expectEq(t, v[1], 3) expectEq(t, oldV[2], 0) expectEq(t, oldV[3], 0) } func Test_Vector_ForEach(t *testing.T) { a := []int{1, 2, 3} v := VectorOf(a...) var b []int v.ForEach(func(n int) { b = append(b, n) }) expectEq(t, len(b), 3) expectTrue(t, Equal(a, b)) } func Test_Vector_ForEachIf(t *testing.T) { v := VectorOf(1, 2, 3) c := 0 v.ForEachIf(func(n int) bool { c = n return n != 2 }) expectEq(t, c, 2) } func Test_Vector_ForEachMutable(t *testing.T) { a := []int{1, 2, 3} v := VectorOf(1, 2, 3) v.ForEachMutable(func(n *int) { *n = -*n }) expectEq(t, v.Len(), 3) for i := range v { expectEq(t, a[i], -v[i]) } } func Test_Vector_ForEachMutableIf(t *testing.T) { v := VectorOf(1, 2, 3) c := 0 v.ForEachMutableIf(func(n *int) bool { c = *n return *n != 2 }) expectEq(t, c, 2) } func Test_Vector_Iterate(t *testing.T) { v := VectorOf(1, 2, 3, 4) i := 1 for it := v.Iterate(); it.IsNotEnd(); it.MoveToNext() { expectEq(t, it.Value(), i) expectEq(t, *it.Pointer(), it.Value()) i++ } expectEq(t, i, 5) } func Test_Vector_IterateRange(t *testing.T) { v := VectorOf(1, 2, 3, 4) i := 2 for it := v.IterateRange(1, 3); it.IsNotEnd(); it.MoveToNext() { expectEq(t, it.Value(), i) expectEq(t, *it.Pointer(), it.Value()) i++ } expectEq(t, i, 4) }