1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-03-01 00:35:28 +08:00

Compare commits

..

99 Commits

Author SHA1 Message Date
dudaodong 5a8ff17b52 release v1.3.9 2023-06-01 10:06:48 +08:00
dudaodong 6b46a0c05c feat: add WriteBytesToFile and WriteStringToFile 2023-05-31 17:36:12 +08:00
dudaodong 4b8b624b4c feat: add ContainsAll and ContainsAny 2023-05-31 17:27:25 +08:00
dudaodong f274375e62 feat: add IsWeekend 2023-05-31 17:23:47 +08:00
dudaodong 6dc017a5fa feat: add BetweenSeconds and DayOfYear 2023-05-31 10:12:17 +08:00
dudaodong e1fb97095d feat: add ReplaceWithMap, Trim, SplitAndTrim, HideString 2023-05-30 14:12:56 +08:00
dudaodong d8f5a15590 feat: add AddYear and IsLeapYear 2023-05-30 14:07:11 +08:00
dudaodong 1202ac955d fix: fix timeFormat issue 2023-05-30 11:59:46 +08:00
dudaodong 84b2cec9b5 fix: fix PingConnected failed in win os 2023-05-30 11:58:29 +08:00
dudaodong 2d01a13787 feat: add ToInterface and CopyProperties 2023-05-30 11:54:57 +08:00
dudaodong db9b045500 doc: add Cos, Sin, LCM, GCD function 2023-05-30 11:47:00 +08:00
dudaodong 2701bcc4d2 feat: add Cos, Sin, LCM, GCD function 2023-05-30 11:41:54 +08:00
dudaodong b9745fd08b fix: comment TestMTime 2023-05-30 11:02:03 +08:00
dudaodong 3b1597d6f7 fix: fix body param bug when send post request 2023-05-30 11:01:39 +08:00
dudaodong 40ab5e8f7b release v1.3.8 2023-04-26 18:04:50 +08:00
dudaodong cacedf2a05 doc: add document for compare package 2023-04-26 11:25:04 +08:00
dudaodong 4fc391895b feat: add new function for fileutil package 2023-04-26 11:12:48 +08:00
dudaodong b419319e66 doc: update doc for netutil package 2023-04-19 16:19:42 +08:00
dudaodong db34b5f69c update readme file 2023-04-19 15:50:01 +08:00
dudaodong ee44526d9e feat: move new functions from v2 version 2023-04-19 15:49:07 +08:00
dudaodong 6576b1f0cb feat: add new function for system and strutil package 2023-04-19 14:36:33 +08:00
dudaodong 93108bafb9 feat: add option support for ExecCommand 2023-04-19 14:26:15 +08:00
dudaodong 07f5e0697f feat: add option support for ExecCommand 2023-04-19 14:25:31 +08:00
dudaodong 4ba91d7e4c feat: add IsPingConnected and IsTelnetConnected 2023-04-19 14:07:11 +08:00
dudaodong ab81d9c283 fix: fix StructToUrlValues failed when tag contain omitempty 2023-03-06 17:23:54 +08:00
dudaodong a74038466f release v1.3.7 2023-03-01 10:04:15 +08:00
dudaodong 02daa7f6cb doc: add new function docs 2023-02-28 15:09:05 +08:00
dudaodong fef6fd7b9d fix: fix issue #75 2023-02-23 11:51:26 +08:00
dudaodong f6cd98086f doc: add doc for Pipeline function 2023-02-23 10:52:07 +08:00
dudaodong 24eb2bbacd doc: format all markdown doc 2023-02-23 10:36:54 +08:00
dudaodong 15c1537bf0 doc: add doc for SplitWords and WordCount 2023-02-23 10:23:38 +08:00
dudaodong c02654559a doc: add pad function 2023-02-23 10:19:05 +08:00
dudaodong 634ca09e8c feat: add CopyProperties for merge properties between structs 2023-02-20 14:03:02 +08:00
dudaodong f2e743dcf4 release v1.3.6 2023-02-16 11:56:11 +08:00
dudaodong f8f58cae10 doc: add doc for DeepClone function 2023-02-16 11:53:28 +08:00
dudaodong 215b79140d feat: add DeepClone 2023-02-16 11:50:11 +08:00
dudaodong 0bd675340f fix: fix AesEcbEncrypt failed with key lenght is 24 or 32 2023-02-16 11:45:08 +08:00
dudaodong f3d73899b1 release v1.3.5 2022-12-15 16:36:15 +08:00
dudaodong d4a20b239a add new function 2022-12-15 16:35:33 +08:00
dudaodong 4c28431451 fix: fix lint issue 2022-12-15 16:31:04 +08:00
dudaodong 168ed096c7 fix: fix ExecCommand bug forwindows 2022-12-15 16:29:36 +08:00
dudaodong a060769635 clean code 2022-12-15 16:27:21 +08:00
dudaodong 0a99492cf6 feat: add IsGBK 2022-12-15 16:21:09 +08:00
dudaodong fb3de03f37 clean document 2022-12-15 16:13:32 +08:00
dudaodong 43c2fd2a22 feat: add UpperKebabCase/UpperSnakeCase 2022-12-15 16:05:02 +08:00
dudaodong 279d0754ba release v1.3.4 2022-11-17 16:14:42 +08:00
dudaodong f133b32faa fix: issue#62: fix ZipSlip bug 2022-11-17 16:14:03 +08:00
dudaodong b98d5edbb5 release v1.3.3 2022-11-08 15:14:34 +08:00
dudaodong 9e39c31087 docs: update doc for random package 2022-11-08 15:03:42 +08:00
dudaodong 26bc40c614 feat: add new random function 2022-11-08 14:54:17 +08:00
dudaodong 76d68e326b release v1.3.2 2022-08-31 17:05:38 +08:00
dudaodong 67b4782ac2 doc: add document for functions in netutil/http_client.go 2022-08-31 15:53:18 +08:00
dudaodong 1d8b9a2625 feat: add http client for sending http request 2022-08-31 11:49:27 +08:00
dudaodong 94ae1acc78 doc: update readme file 2022-08-29 15:31:19 +08:00
dudaodong aece2995d6 refactor: change ReverseStr to Reverse in strutil package 2022-08-29 15:11:15 +08:00
dudaodong f5ec5eb58d feat: add EncodeByte and DecodeByte 2022-08-29 15:08:50 +08:00
dudaodong d62284e9a6 feat: add IsZeroValue function 2022-08-29 14:59:36 +08:00
dudaodong b6815224fd release v1.3.1 2022-08-02 17:52:18 +08:00
dudaodong 5931b882ee doc: update document for system package 2022-07-29 13:33:23 +08:00
dudaodong f8096e3585 doc: update slice document 2022-07-29 13:31:04 +08:00
dudaodong 979381bfb7 doc: update convertor document 2022-07-29 13:28:25 +08:00
dudaodong 3e2c25f827 doc: update netutil document 2022-07-29 13:23:30 +08:00
dudaodong 2c7bcc9fbb doc: update slice document 2022-07-29 13:17:05 +08:00
dudaodong 3a944ab12f test: update slice unit test 2022-07-27 15:31:12 +08:00
dudaodong 387079d034 feat: os.go, add GetOsBits 2022-07-27 15:27:39 +08:00
dudaodong 33e3631b72 fix: fix aes/des cbc crypto iv bug 2022-07-27 15:26:45 +08:00
dudaodong b3149ea619 feat: convertor.go, add ToChannel 2022-07-27 15:22:43 +08:00
dudaodong 116ff284c3 feat: net.go, add IsInternalIP, GetRequestPublicIp, EncodeUrl 2022-07-27 15:18:20 +08:00
dudaodong 0cb251f7b8 feat: add ToSlice and ToSlicePointer and AppendIfAbsent 2022-07-27 15:12:14 +08:00
dudaodong 683def2242 docs: update go version badge 2022-06-24 09:41:46 +08:00
dudaodong d4a90f2869 release v1.3.0 2022-06-22 16:30:45 +08:00
dudaodong be67de3b40 release v1.3.0 2022-06-22 15:58:41 +08:00
dudaodong 6898ed413e docs: add doc for UniqueBy function 2022-06-22 15:47:48 +08:00
dudaodong 5dbdbcd651 docs: add doc for UniqueBy function 2022-06-22 15:45:29 +08:00
dudaodong ae0facd32d refactor: clean code for slice/slice.go 2022-06-22 14:21:45 +08:00
dudaodong 2d7e19fb87 feat: add UniqueBy function in slice.go 2022-06-22 12:00:01 +08:00
dudaodong 24d4a03227 update .gitignore file 2022-06-22 11:27:31 +08:00
dudaodong 93fb089f6e docs: add CreateDir function for fileutil 2022-06-17 17:25:16 +08:00
dudaodong 2fe272f2ef docs: add CreateDir function for fileutil 2022-06-17 17:22:08 +08:00
dudaodong 77859ffa15 docs: add doc for SplitEx function 2022-06-17 17:19:59 +08:00
dudaodong f83f47df3a feat: add SplitEx function 2022-06-17 17:13:58 +08:00
dudaodong 885c08847d docs: add doc for function IndexOf and LastIndexOf 2022-06-17 17:11:09 +08:00
dudaodong cc4a20751f test: add unit test for funcation IndexOf and LastIndexOf 2022-06-17 17:02:44 +08:00
dudaodong b0d1d39452 feat: add IndexOf and LastIndexOf function in slice.go 2022-06-17 17:01:37 +08:00
dudaodong 02fa7bc8be docs: add doc for function Equal and EqualWithFunc 2022-06-17 16:57:42 +08:00
dudaodong 433eb63b86 feat: add EqualWith function for slice 2022-06-17 15:47:36 +08:00
dudaodong a2541dac03 feat: add Equal function for slice 2022-06-17 15:37:36 +08:00
dudaodong 690e746811 update readme file 2022-04-29 14:50:29 +08:00
dudaodong 7cb97a26c5 release v1.2.9 2022-04-14 11:41:46 +08:00
dudaodong 39d373d37b fix: fix http post to support multipart/form-data header 2022-04-14 11:39:21 +08:00
dudaodong 1aefd6aa12 release v1.2.8 2022-04-13 11:46:14 +08:00
dudaodong c7aa44b8a4 fix: fix http post fucntion 2022-04-13 11:38:45 +08:00
dudaodong 0e3dc68de5 release v1.2.7 2022-03-29 10:52:55 +08:00
dudaodong 4083e75ed4 fix: fix ToBytes bug 2022-03-26 21:09:28 +08:00
dudaodong 1327eff62f docs: add doc for unix time 2022-03-24 16:09:19 +08:00
dudaodong eb24c37143 docs: add doc for unix time 2022-03-24 16:07:17 +08:00
dudaodong b7a6c91064 feat: add unix date conversion 2022-03-24 16:03:57 +08:00
dudaodong 555e185871 feat: add unix date conversion 2022-03-24 16:01:41 +08:00
dudaodong cb0efc5cc7 docs: replace path '/main' with '/v1' 2022-03-16 16:18:28 +08:00
261 changed files with 15145 additions and 74321 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
fetch-depth: 2
- uses: actions/setup-go@v2
with:
go-version: "1.18"
go-version: "1.16"
- name: Run coverage
run: go test -v ./... -coverprofile=coverage.txt -covermode=atomic
- name: Upload coverage to Codecov
+1 -5
View File
@@ -6,9 +6,5 @@ fileutil/*.txt
fileutil/*.zip
fileutil/*.link
fileutil/unzip/*
fileutil/tempdir/*
slice/testdata/*
cryptor/*.pem
test
docs/node_modules
docs/.vitepress/cache
cryptor/*.pem
+331 -1716
View File
File diff suppressed because it is too large Load Diff
+346 -1739
View File
File diff suppressed because it is too large Load Diff
-15
View File
@@ -1,15 +0,0 @@
# Security Policy
## Supported Versions
Here is the lancet version and compatibility with go language version.
| Version | Supported |
| ------- | ------------------|
| 2.x.x | +go v1.18 |
| 1.x.x | +go v1.12 |
## Reporting a Vulnerability
For now, there is no public website to report a vulnerability, If you find security issue in lancet, you can send it to me via my email `lanliddd.2007@163.com`.
we can discuss it. I am appreciate if someone can create a public page for reporting vulnerability.
-121
View File
@@ -1,121 +0,0 @@
package algorithm
type lruNode[K comparable, V any] struct {
key K
value V
pre *lruNode[K, V]
next *lruNode[K, V]
}
// newLruNode return a lruNode pointer
func newLruNode[K comparable, V any](key K, value V) *lruNode[K, V] {
return &lruNode[K, V]{
key: key,
value: value,
pre: nil,
next: nil,
}
}
// LRUCache lru cache (thread unsafe)
type LRUCache[K comparable, V any] struct {
cache map[K]*lruNode[K, V]
head *lruNode[K, V]
tail *lruNode[K, V]
capacity int
length int
}
// NewLRUCache creates a LRUCache pointer instance.
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
return &LRUCache[K, V]{
cache: make(map[K]*lruNode[K, V], capacity),
head: nil,
tail: nil,
capacity: capacity,
length: 0,
}
}
// Get value of key from lru cache.
// Play: https://go.dev/play/p/iUynEfOP8G0
func (l *LRUCache[K, V]) Get(key K) (V, bool) {
var value V
node, ok := l.cache[key]
if ok {
l.moveToHead(node)
return node.value, true
}
return value, false
}
// Put value of key into lru cache.
// Play: https://go.dev/play/p/iUynEfOP8G0
func (l *LRUCache[K, V]) Put(key K, value V) {
node, ok := l.cache[key]
if !ok {
newNode := newLruNode(key, value)
l.cache[key] = newNode
l.addNode(newNode)
if len(l.cache) > l.capacity {
oldKey := l.deleteNode(l.head)
delete(l.cache, oldKey)
}
} else {
node.value = value
l.moveToHead(node)
}
l.length = len(l.cache)
}
// Delete item from lru cache.
func (l *LRUCache[K, V]) Delete(key K) bool {
node, ok := l.cache[key]
if ok {
key := l.deleteNode(node)
delete(l.cache, key)
return true
}
return false
}
// Len returns the number of items in the cache.
func (l *LRUCache[K, V]) Len() int {
return l.length
}
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
if l.tail != nil {
l.tail.next = node
node.pre = l.tail
node.next = nil
}
l.tail = node
if l.head == nil {
l.head = node
}
}
func (l *LRUCache[K, V]) deleteNode(node *lruNode[K, V]) K {
if node == l.tail {
l.tail = l.tail.pre
} else if node == l.head {
l.head = l.head.next
} else {
node.pre.next = node.next
node.next.pre = node.pre
}
return node.key
}
func (l *LRUCache[K, V]) moveToHead(node *lruNode[K, V]) {
if l.tail == node {
return
}
l.deleteNode(node)
l.addNode(node)
}
-79
View File
@@ -1,79 +0,0 @@
package algorithm
import "fmt"
func ExampleLRUCache_Put() {
cache := NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
fmt.Println(result1, ok1)
fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
// Output:
// 1 true
// 2 true
// 0 false
}
func ExampleLRUCache_Get() {
cache := NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
fmt.Println(result1, ok1)
fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
// Output:
// 1 true
// 2 true
// 0 false
}
func ExampleLRUCache_Delete() {
cache := NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result1, ok1 := cache.Get(1)
ok2 := cache.Delete(2)
_, ok3 := cache.Get(2)
fmt.Println(result1, ok1)
fmt.Println(ok2)
fmt.Println(ok3)
// Output:
// 1 true
// true
// false
}
func ExampleLRUCache_Len() {
cache := NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result := cache.Len()
fmt.Println(result)
// Output:
// 2
}
-34
View File
@@ -1,34 +0,0 @@
package algorithm
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestLRUCache(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestLRUCache")
cache := NewLRUCache[int, int](3)
cache.Put(1, 1)
cache.Put(2, 2)
cache.Put(3, 3)
asssert.Equal(3, cache.Len())
v, ok := cache.Get(1)
asssert.Equal(true, ok)
asssert.Equal(1, v)
v, ok = cache.Get(2)
asssert.Equal(true, ok)
asssert.Equal(2, v)
ok = cache.Delete(2)
asssert.Equal(true, ok)
_, ok = cache.Get(2)
asssert.Equal(false, ok)
}
-66
View File
@@ -1,66 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph.
package algorithm
import "github.com/duke-git/lancet/v2/lancetconstraints"
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
// LinearSearch return the index of target in slice base on equal function.
// If not found return -1
// Play: https://go.dev/play/p/IsS7rgn5s3x
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
for i, v := range slice {
if equal(v, target) {
return i
}
}
return -1
}
// BinarySearch return the index of target within a sorted slice, use binary search (recursive call itself).
// If not found return -1.
// Play: https://go.dev/play/p/t6MeGiUSN47
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
if highIndex < lowIndex || len(sortedSlice) == 0 {
return -1
}
midIndex := int(lowIndex + (highIndex-lowIndex)/2)
isMidValGreatTarget := comparator.Compare(sortedSlice[midIndex], target) == 1
isMidValLessTarget := comparator.Compare(sortedSlice[midIndex], target) == -1
if isMidValGreatTarget {
return BinarySearch(sortedSlice, target, lowIndex, midIndex-1, comparator)
} else if isMidValLessTarget {
return BinarySearch(sortedSlice, target, midIndex+1, highIndex, comparator)
}
return midIndex
}
// BinaryIterativeSearch return the index of target within a sorted slice, use binary search (no recursive).
// If not found return -1.
// Play: https://go.dev/play/p/Anozfr8ZLH3
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
startIndex := lowIndex
endIndex := highIndex
var midIndex int
for startIndex <= endIndex {
midIndex = int(startIndex + (endIndex-startIndex)/2)
isMidValGreatTarget := comparator.Compare(sortedSlice[midIndex], target) == 1
isMidValLessTarget := comparator.Compare(sortedSlice[midIndex], target) == -1
if isMidValGreatTarget {
endIndex = midIndex - 1
} else if isMidValLessTarget {
startIndex = midIndex + 1
} else {
return midIndex
}
}
return -1
}
-51
View File
@@ -1,51 +0,0 @@
package algorithm
import "fmt"
func ExampleLinearSearch() {
numbers := []int{3, 4, 5, 3, 2, 1}
equalFunc := func(a, b int) bool {
return a == b
}
result1 := LinearSearch(numbers, 3, equalFunc)
result2 := LinearSearch(numbers, 6, equalFunc)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// -1
}
func ExampleBinarySearch() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
result1 := BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
result2 := BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
}
func ExampleBinaryIterativeSearch() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
result1 := BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
result2 := BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
}
-41
View File
@@ -1,41 +0,0 @@
package algorithm
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestLinearSearch(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestLinearSearch")
numbers := []int{3, 4, 5, 3, 2, 1}
equalFunc := func(a, b int) bool {
return a == b
}
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
}
func TestBinarySearch(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestBinarySearch")
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
}
func TestBinaryIterativeSearch(t *testing.T) {
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
}
-199
View File
@@ -1,199 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
package algorithm
import "github.com/duke-git/lancet/v2/lancetconstraints"
// BubbleSort applys the bubble sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/GNdv7Jg2Taj
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
for j := 0; j < len(slice)-1-i; j++ {
isCurrGreatThanNext := comparator.Compare(slice[j], slice[j+1]) == 1
if isCurrGreatThanNext {
swap(slice, j, j+1)
}
}
}
}
// InsertionSort applys the insertion sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/G5LJiWgJJW6
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
for j := i; j > 0; j-- {
isPreLessThanCurrent := comparator.Compare(slice[j], slice[j-1]) == -1
if isPreLessThanCurrent {
swap(slice, j, j-1)
} else {
break
}
}
}
}
// SelectionSort applys the selection sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/oXovbkekayS
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
min := i
for j := i + 1; j < len(slice); j++ {
if comparator.Compare(slice[j], slice[min]) == -1 {
min = j
}
}
swap(slice, i, min)
}
}
// ShellSort applys the shell sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/3ibkszpJEu3
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
size := len(slice)
gap := 1
for gap < size/3 {
gap = 3*gap + 1
}
for gap >= 1 {
for i := gap; i < size; i++ {
for j := i; j >= gap && comparator.Compare(slice[j], slice[j-gap]) == -1; j -= gap {
swap(slice, j, j-gap)
}
}
gap = gap / 3
}
}
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1.
// Play: https://go.dev/play/p/7Y7c1Elk3ax
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
quickSort(slice, 0, len(slice)-1, comparator)
}
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
if lowIndex < highIndex {
p := partition(slice, lowIndex, highIndex, comparator)
quickSort(slice, lowIndex, p-1, comparator)
quickSort(slice, p+1, highIndex, comparator)
}
}
// partition split slice into two parts
func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
p := slice[highIndex]
i := lowIndex
for j := lowIndex; j < highIndex; j++ {
if comparator.Compare(slice[j], p) == -1 { //slice[j] < p
swap(slice, i, j)
i++
}
}
swap(slice, i, highIndex)
return i
}
// HeapSort applys the heap sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/u6Iwa1VZS_f
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
size := len(slice)
for i := size/2 - 1; i >= 0; i-- {
sift(slice, i, size-1, comparator)
}
for j := size - 1; j > 0; j-- {
swap(slice, 0, j)
sift(slice, 0, j-1, comparator)
}
}
func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
i := lowIndex
j := 2*i + 1
temp := slice[i]
for j <= highIndex {
if j < highIndex && comparator.Compare(slice[j], slice[j+1]) == -1 { //slice[j] < slice[j+1]
j++
}
if comparator.Compare(temp, slice[j]) == -1 { //tmp < slice[j]
slice[i] = slice[j]
i = j
j = 2*i + 1
} else {
break
}
}
slice[i] = temp
}
// MergeSort applys the merge sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/ydinn9YzUJn
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
mergeSort(slice, 0, len(slice)-1, comparator)
}
func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
if lowIndex < highIndex {
mid := (lowIndex + highIndex) / 2
mergeSort(slice, lowIndex, mid, comparator)
mergeSort(slice, mid+1, highIndex, comparator)
merge(slice, lowIndex, mid, highIndex, comparator)
}
}
func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lancetconstraints.Comparator) {
i := lowIndex
j := midIndex + 1
temp := []T{}
for i <= midIndex && j <= highIndex {
//slice[i] < slice[j]
if comparator.Compare(slice[i], slice[j]) == -1 {
temp = append(temp, slice[i])
i++
} else {
temp = append(temp, slice[j])
j++
}
}
if i <= midIndex {
temp = append(temp, slice[i:midIndex+1]...)
} else {
temp = append(temp, slice[j:highIndex+1]...)
}
for k := 0; k < len(temp); k++ {
slice[lowIndex+k] = temp[k]
}
}
// CountSort applys the count sort algorithm to sort the collection, don't change the original collection data.
// Play: https://go.dev/play/p/tB-Umgm0DrP
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
size := len(slice)
out := make([]T, size)
for i := 0; i < size; i++ {
count := 0
for j := 0; j < size; j++ {
//slice[i] > slice[j]
if comparator.Compare(slice[i], slice[j]) == 1 {
count++
}
}
out[count] = slice[i]
}
return out
}
// swap two slice value at index i and j
func swap[T any](slice []T, i, j int) {
slice[i], slice[j] = slice[j], slice[i]
}
-93
View File
@@ -1,93 +0,0 @@
package algorithm
import "fmt"
func ExampleBubbleSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
BubbleSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleCountSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
sortedNumber := CountSort(numbers, comparator)
fmt.Println(numbers)
fmt.Println(sortedNumber)
// Output:
// [2 1 5 3 6 4]
// [1 2 3 4 5 6]
}
func ExampleHeapSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
HeapSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleMergeSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
MergeSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleInsertionSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
InsertionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleSelectionSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
SelectionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleShellSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
ShellSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleQuickSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
QuickSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
-217
View File
@@ -1,217 +0,0 @@
package algorithm
import (
"fmt"
"testing"
"github.com/duke-git/lancet/v2/internal"
)
// People test mock data
type people struct {
Name string
Age int
}
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/v2/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
//ascending order
if p1.Age < p2.Age {
return -1
} else if p1.Age > p2.Age {
return 1
}
return 0
}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func TestBubbleSortForStructSlice(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
BubbleSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestBubbleSortForIntSlice(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
BubbleSort(numbers, comparator)
asssert.Equal([]int{1, 2, 3, 4, 5, 6}, numbers)
}
func TestInsertionSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestInsertionSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
InsertionSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestSelectionSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestSelectionSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
SelectionSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestShellSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestShellSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
ShellSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestQuickSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestQuickSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
QuickSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestHeapSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestHeapSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
HeapSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestMergeSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestMergeSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
MergeSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestCountSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestCountSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
sortedPeopleByAge := CountSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", sortedPeopleByAge)
asssert.Equal(expected, actual)
}
+8 -22
View File
@@ -1,7 +1,7 @@
// Copyright 2023 dudaodong@gmail.com. All rights resulterved.
// Use of this source code is governed by MIT license
// Package compare provides a lightweight comparison function on any type.
// Package compare provides a lightweight comparison function on interface{} type.
// reference: https://github.com/stretchr/testify
package compare
@@ -9,9 +9,7 @@ import (
"reflect"
"time"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/mathutil"
"golang.org/x/exp/constraints"
"github.com/duke-git/lancet/convertor"
)
// operator type
@@ -29,44 +27,32 @@ var (
)
// Equal checks if two values are equal or not. (check both type and value)
// Play: https://go.dev/play/p/wmVxR-to4lz
func Equal(left, right any) bool {
func Equal(left, right interface{}) bool {
return compareValue(equal, left, right)
}
// EqualValue checks if two values are equal or not. (check value only)
// Play: https://go.dev/play/p/fxnna_LLD9u
func EqualValue(left, right any) bool {
func EqualValue(left, right interface{}) bool {
ls, rs := convertor.ToString(left), convertor.ToString(right)
return ls == rs
}
// LessThan checks if value `left` less than value `right`.
// Play: https://go.dev/play/p/cYh7FQQj0ne
func LessThan(left, right any) bool {
func LessThan(left, right interface{}) bool {
return compareValue(lessThan, left, right)
}
// GreaterThan checks if value `left` greater than value `right`.
// Play: https://go.dev/play/p/9-NYDFZmIMp
func GreaterThan(left, right any) bool {
func GreaterThan(left, right interface{}) bool {
return compareValue(greaterThan, left, right)
}
// LessOrEqual checks if value `left` less than or equal to value `right`.
// Play: https://go.dev/play/p/e4T_scwoQzp
func LessOrEqual(left, right any) bool {
func LessOrEqual(left, right interface{}) bool {
return compareValue(lessOrEqual, left, right)
}
// GreaterOrEqual checks if value `left` greater than or equal to value `right`.
// Play: https://go.dev/play/p/vx8mP0U8DFk
func GreaterOrEqual(left, right any) bool {
func GreaterOrEqual(left, right interface{}) bool {
return compareValue(greaterOrEqual, left, right)
}
// InDelta checks if two values are equal or not within a delta.
// Play: https://go.dev/play/p/TuDdcNtMkjo
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool {
return float64(mathutil.Abs(left-right)) <= delta
}
-26
View File
@@ -168,29 +168,3 @@ func ExampleGreaterOrEqual() {
// false
// false
}
func ExampleInDelta() {
result1 := InDelta(1, 1, 0)
result2 := InDelta(1, 2, 0)
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
result4 := InDelta(2.0/3.0, 0.0, 0.001)
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// false
// true
// false
// false
// true
}
+4 -4
View File
@@ -6,10 +6,10 @@ import (
"reflect"
"time"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/convertor"
)
func compareValue(operator string, left, right any) bool {
func compareValue(operator string, left, right interface{}) bool {
leftType, rightType := reflect.TypeOf(left), reflect.TypeOf(right)
if leftType.Kind() != rightType.Kind() {
@@ -29,7 +29,7 @@ func compareValue(operator string, left, right any) bool {
return false
}
func compareRefValue(operator string, leftObj, rightObj any, kind reflect.Kind) bool {
func compareRefValue(operator string, leftObj, rightObj interface{}, kind reflect.Kind) bool {
leftVal, rightVal := reflect.ValueOf(leftObj), reflect.ValueOf(rightObj)
switch kind {
@@ -149,7 +149,7 @@ func objectsAreEqual(expected, actual interface{}) bool {
}
// compareBasic compare basic value: integer, float, string, bool
func compareBasicValue(operator string, leftValue, rightValue any) bool {
func compareBasicValue(operator string, leftValue, rightValue interface{}) bool {
if leftValue == nil && rightValue == nil && operator == equal {
return true
}
+1 -23
View File
@@ -4,11 +4,10 @@ import (
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
"github.com/duke-git/lancet/internal"
)
func TestEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqual")
assert.Equal(true, Equal(1, 1))
@@ -61,7 +60,6 @@ func TestEqual(t *testing.T) {
}
func TestEqualValue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqualValue")
assert.Equal(true, EqualValue(1, 1))
@@ -72,7 +70,6 @@ func TestEqualValue(t *testing.T) {
}
func TestLessThan(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLessThan")
assert.Equal(true, LessThan(1, 2))
@@ -88,7 +85,6 @@ func TestLessThan(t *testing.T) {
}
func TestGreaterThan(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGreaterThan")
assert.Equal(true, GreaterThan(2, 1))
@@ -105,7 +101,6 @@ func TestGreaterThan(t *testing.T) {
}
func TestLessOrEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLessOrEqual")
assert.Equal(true, LessOrEqual(1, 2))
@@ -122,7 +117,6 @@ func TestLessOrEqual(t *testing.T) {
}
func TestGreaterOrEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGreaterThan")
assert.Equal(true, GreaterOrEqual(2, 1))
@@ -138,19 +132,3 @@ func TestGreaterOrEqual(t *testing.T) {
assert.Equal(false, GreaterOrEqual(int64(2), 1))
assert.Equal(false, GreaterOrEqual("b", "c"))
}
func TestInDelta(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInDelta")
assert.Equal(true, InDelta(1, 1, 0))
assert.Equal(false, InDelta(1, 2, 0))
assert.Equal(true, InDelta(2.0/3.0, 0.66667, 0.001))
assert.Equal(false, InDelta(2.0/3.0, 0.0, 0.001))
assert.Equal(false, InDelta(float64(74.96)-float64(20.48), 54.48, 0))
assert.Equal(true, InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14))
assert.Equal(false, InDelta(float64(float32(80.45)), float64(80.45), 0))
assert.Equal(true, InDelta(float64(float32(80.45)), float64(80.45), 1e-5))
}
-247
View File
@@ -1,247 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
package concurrency
import (
"context"
"sync"
)
// Channel is a logic object which can generate or manipulate go channel
// all methods of Channel are in the book tilted《Concurrency in Go》
type Channel[T any] struct {
}
// NewChannel return a Channel instance
func NewChannel[T any]() *Channel[T] {
return &Channel[T]{}
}
// Generate creates channel, then put values into the channel.
// Play: https://go.dev/play/p/7aB4KyMMp9A
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T {
dataStream := make(chan T)
go func() {
defer close(dataStream)
for _, v := range values {
select {
case <-ctx.Done():
return
case dataStream <- v:
}
}
}()
return dataStream
}
// Repeat create channel, put values into the channel repeatly until cancel the context.
// Play: https://go.dev/play/p/k5N_ALVmYjE
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T {
dataStream := make(chan T)
go func() {
defer close(dataStream)
for {
for _, v := range values {
select {
case <-ctx.Done():
return
case dataStream <- v:
}
}
}
}()
return dataStream
}
// RepeatFn create a channel, excutes fn repeatly, and put the result into the channel
// until close context.
// Play: https://go.dev/play/p/4J1zAWttP85
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T {
dataStream := make(chan T)
go func() {
defer close(dataStream)
for {
select {
case <-ctx.Done():
return
case dataStream <- fn():
}
}
}()
return dataStream
}
// Take create a channel whose values are taken from another channel with limit number.
// Play: https://go.dev/play/p/9Utt-1pDr2J
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T {
takeStream := make(chan T)
go func() {
defer close(takeStream)
for i := 0; i < number; i++ {
select {
case <-ctx.Done():
return
case takeStream <- <-valueStream:
}
}
}()
return takeStream
}
// FanIn merge multiple channels into one channel.
// Play: https://go.dev/play/p/2VYFMexEvTm
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T {
out := make(chan T)
go func() {
var wg sync.WaitGroup
wg.Add(len(channels))
for _, c := range channels {
go func(c <-chan T) {
defer wg.Done()
for v := range c {
select {
case <-ctx.Done():
return
case out <- v:
}
}
}(c)
}
wg.Wait()
close(out)
}()
return out
}
// Tee split one chanel into two channels, until cancel the context.
// Play: https://go.dev/play/p/3TQPKnCirrP
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) {
out1 := make(chan T)
out2 := make(chan T)
go func() {
defer close(out1)
defer close(out2)
for val := range c.OrDone(ctx, in) {
var out1, out2 = out1, out2
for i := 0; i < 2; i++ {
select {
case <-ctx.Done():
case out1 <- val:
out1 = nil
case out2 <- val:
out2 = nil
}
}
}
}()
return out1, out2
}
// Bridge link multiply channels into one channel.
// Play: https://go.dev/play/p/qmWSy1NVF-Y
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
valStream := make(chan T)
go func() {
defer close(valStream)
for {
var stream <-chan T
select {
case maybeStream, ok := <-chanStream:
if !ok {
return
}
stream = maybeStream
case <-ctx.Done():
return
}
for val := range c.OrDone(ctx, stream) {
select {
case valStream <- val:
case <-ctx.Done():
}
}
}
}()
return valStream
}
// Or read one or more channels into one channel, will close when any readin channel is closed.
// Play: https://go.dev/play/p/Wqz9rwioPww
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T {
switch len(channels) {
case 0:
return nil
case 1:
return channels[0]
}
orDone := make(chan T)
go func() {
defer close(orDone)
switch len(channels) {
case 2:
select {
case <-channels[0]:
case <-channels[1]:
}
default:
select {
case <-channels[0]:
case <-channels[1]:
case <-channels[2]:
case <-c.Or(append(channels[3:], orDone)...):
}
}
}()
return orDone
}
// OrDone read a channel into another channel, will close until cancel context.
// Play: https://go.dev/play/p/lm_GoS6aDjo
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T {
valStream := make(chan T)
go func() {
defer close(valStream)
for {
select {
case <-ctx.Done():
return
case v, ok := <-channel:
if !ok {
return
}
select {
case valStream <- v:
case <-ctx.Done():
}
}
}
}()
return valStream
}
-196
View File
@@ -1,196 +0,0 @@
package concurrency
import (
"context"
"fmt"
"time"
)
func ExampleChannel_Generate() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
// Output:
// 1
// 2
// 3
}
func ExampleChannel_Repeat() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 1
// 2
}
func ExampleChannel_RepeatFn() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() string {
return "hello"
}
c := NewChannel[string]()
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// hello
// hello
// hello
}
func ExampleChannel_Take() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}
func ExampleChannel_FanIn() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
channels := make([]<-chan int, 2)
for i := 0; i < 2; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
}
chs := c.FanIn(ctx, channels...)
for v := range chs {
fmt.Println(v) //1 1 0 0 or 0 0 1 1
}
}
func ExampleChannel_Or() {
sig := func(after time.Duration) <-chan any {
c := make(chan any)
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := NewChannel[any]()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
)
if time.Since(start).Seconds() < 2 {
fmt.Println("ok")
}
// Output:
// ok
}
func ExampleChannel_OrDone() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for v := range c.OrDone(ctx, intStream) {
fmt.Println(v)
}
// Output:
// 1
// 1
// 1
}
func ExampleChannel_Tee() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
ch1, ch2 := c.Tee(ctx, intStream)
for v := range ch1 {
fmt.Println(v)
fmt.Println(<-ch2)
}
// Output:
// 1
// 1
// 1
// 1
}
func ExampleChannel_Bridge() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
genVals := func() <-chan <-chan int {
out := make(chan (<-chan int))
go func() {
defer close(out)
for i := 1; i <= 5; i++ {
stream := make(chan int, 1)
stream <- i
close(stream)
out <- stream
}
}()
return out
}
for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
-196
View File
@@ -1,196 +0,0 @@
package concurrency
import (
"context"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
func TestGenerate(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGenerate")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(3, <-intStream)
}
func TestRepeat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRepeat")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(1, <-intStream)
}
func TestRepeatFn(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRepeatFn")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() string {
s := "a"
return s
}
c := NewChannel[string]()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
assert.Equal("a", <-dataStream)
assert.Equal("a", <-dataStream)
assert.Equal("a", <-dataStream)
}
func TestTake(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTake")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(3, <-intStream)
}
func TestFanIn(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFanIn")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
channels := make([]<-chan int, 3)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
}
mergedChannel := c.FanIn(ctx, channels...)
for val := range mergedChannel {
t.Logf("\t%d\n", val)
}
assert.Equal(1, 1)
}
func TestOr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOr")
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := NewChannel[any]()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
sig(4*time.Second),
sig(5*time.Second),
)
assert.Equal(true, time.Since(start).Seconds() < 2)
}
func TestOrDone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOrDone")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for val := range c.OrDone(ctx, intStream) {
assert.Equal(1, val)
}
}
func TestTee(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTee")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
inStream := c.Take(ctx, c.Repeat(ctx, 1), 4)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
val1 := val
val2 := <-out2
assert.Equal(1, val1)
assert.Equal(1, val2)
}
}
func TestBridge(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBridge")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
genVals := func() <-chan <-chan int {
chanStream := make(chan (<-chan int))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan int, 1)
stream <- i
close(stream)
chanStream <- stream
}
}()
return chanStream
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
assert.Equal(index, val)
index++
}
}
-85
View File
@@ -1,85 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package condition contains some functions for conditional judgment. eg. And, Or, TernaryOperator ...
// The implementation of this package refers to the implementation of carlmjohnson's truthy package, you may find more
// useful information in truthy(https://github.com/carlmjohnson/truthy), thanks carlmjohnson.
package condition
import "reflect"
// Bool returns the truthy value of anything.
// If the value's type has a Bool() bool method, the method is called and returned.
// If the type has an IsZero() bool method, the opposite value is returned.
// Slices and maps are truthy if they have a length greater than zero.
// All other types are truthy if they are not their zero value.
// Play: https://go.dev/play/p/ETzeDJRSvhm
func Bool[T any](value T) bool {
switch m := any(value).(type) {
case interface{ Bool() bool }:
return m.Bool()
case interface{ IsZero() bool }:
return !m.IsZero()
}
return reflectValue(&value)
}
func reflectValue(vp any) bool {
switch rv := reflect.ValueOf(vp).Elem(); rv.Kind() {
case reflect.Map, reflect.Slice:
return rv.Len() != 0
default:
is := rv.IsZero()
return !is
}
}
// And returns true if both a and b are truthy.
// Play: https://go.dev/play/p/W1SSUmt6pvr
func And[T, U any](a T, b U) bool {
return Bool(a) && Bool(b)
}
// Or returns false if neither a nor b is truthy.
// Play: https://go.dev/play/p/UlQTxHaeEkq
func Or[T, U any](a T, b U) bool {
return Bool(a) || Bool(b)
}
// Xor returns true if a or b but not both is truthy.
// Play: https://go.dev/play/p/gObZrW7ZbG8
func Xor[T, U any](a T, b U) bool {
valA := Bool(a)
valB := Bool(b)
return (valA || valB) && valA != valB
}
// Nor returns true if neither a nor b is truthy.
// Play: https://go.dev/play/p/g2j08F_zZky
func Nor[T, U any](a T, b U) bool {
return !(Bool(a) || Bool(b))
}
// Xnor returns true if both a and b or neither a nor b are truthy.
// Play: https://go.dev/play/p/OuDB9g51643
func Xnor[T, U any](a T, b U) bool {
valA := Bool(a)
valB := Bool(b)
return (valA && valB) || (!valA && !valB)
}
// Nand returns false if both a and b are truthy.
// Play: https://go.dev/play/p/vSRMLxLIbq8
func Nand[T, U any](a T, b U) bool {
return !Bool(a) || !Bool(b)
}
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
// Play: https://go.dev/play/p/ElllPZY0guT
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
if Bool(isTrue) {
return ifValue
} else {
return elseValue
}
}
-163
View File
@@ -1,163 +0,0 @@
package condition
import "fmt"
func ExampleBool() {
// bool
result1 := Bool(false)
result2 := Bool(true)
fmt.Println(result1)
fmt.Println(result2)
// integer
result3 := Bool(0)
result4 := Bool(1)
fmt.Println(result3)
fmt.Println(result4)
// string
result5 := Bool("")
result6 := Bool(" ")
fmt.Println(result5)
fmt.Println(result6)
// slice
var nums = []int{}
result7 := Bool(nums)
nums = append(nums, 1, 2)
result8 := Bool(nums)
fmt.Println(result7)
fmt.Println(result8)
// Output:
// false
// true
// false
// true
// false
// true
// false
// true
}
func ExampleAnd() {
result1 := And(0, 1)
result2 := And(0, "")
result3 := And(0, "0")
result4 := And(1, "0")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
}
func ExampleOr() {
result1 := Or(0, "")
result2 := Or(0, 1)
result3 := Or(0, "0")
result4 := Or(1, "0")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// true
// true
// true
}
func ExampleXor() {
result1 := Xor(0, 0)
result2 := Xor(1, 1)
result3 := Xor(0, 1)
result4 := Xor(1, 0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// true
// true
}
func ExampleNor() {
result1 := Nor(0, 0)
result2 := Nor(1, 1)
result3 := Nor(0, 1)
result4 := Nor(1, 0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// false
// false
// false
}
func ExampleXnor() {
result1 := Xnor(0, 0)
result2 := Xnor(1, 1)
result3 := Xnor(0, 1)
result4 := Xnor(1, 0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// false
// false
}
func ExampleNand() {
result1 := Nand(0, 0)
result2 := Nand(1, 0)
result3 := Nand(0, 1)
result4 := Nand(1, 1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// true
// false
}
func ExampleTernaryOperator() {
conditionTrue := 2 > 1
result1 := TernaryOperator(conditionTrue, 0, 1)
fmt.Println(result1)
conditionFalse := 2 > 3
result2 := TernaryOperator(conditionFalse, 0, 1)
fmt.Println(result2)
// Output:
// 0
// 1
}
-136
View File
@@ -1,136 +0,0 @@
package condition
import (
"errors"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
type TestStruct struct{}
func TestBool(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBool")
// bool
assert.Equal(false, Bool(false))
assert.Equal(true, Bool(true))
// integer
assert.Equal(false, Bool(0))
assert.Equal(true, Bool(1))
// float
assert.Equal(false, Bool(0.0))
assert.Equal(true, Bool(0.1))
// string
assert.Equal(false, Bool(""))
assert.Equal(true, Bool(" "))
assert.Equal(true, Bool("0"))
// slice
var nums [2]int
assert.Equal(false, Bool(nums))
nums = [2]int{0, 1}
assert.Equal(true, Bool(nums))
// map
assert.Equal(false, Bool(map[string]string{}))
assert.Equal(true, Bool(map[string]string{"a": "a"}))
// channel
var ch chan int
assert.Equal(false, Bool(ch))
ch = make(chan int)
assert.Equal(true, Bool(ch))
// interface
var err error
assert.Equal(false, Bool(err))
err = errors.New("error message")
assert.Equal(true, Bool(err))
// struct
assert.Equal(false, Bool(struct{}{}))
assert.Equal(true, Bool(time.Now()))
// struct pointer
ts := TestStruct{}
assert.Equal(false, Bool(ts))
assert.Equal(true, Bool(&ts))
}
func TestAnd(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAnd")
assert.Equal(false, And(0, 1))
assert.Equal(false, And(0, ""))
assert.Equal(false, And(0, "0"))
assert.Equal(true, And(1, "0"))
}
func TestOr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOr")
assert.Equal(false, Or(0, ""))
assert.Equal(true, Or(0, 1))
assert.Equal(true, Or(0, "0"))
assert.Equal(true, Or(1, "0"))
}
func TestXor(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOr")
assert.Equal(false, Xor(0, 0))
assert.Equal(true, Xor(0, 1))
assert.Equal(true, Xor(1, 0))
assert.Equal(false, Xor(1, 1))
}
func TestNor(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestNor")
assert.Equal(true, Nor(0, 0))
assert.Equal(false, Nor(0, 1))
assert.Equal(false, Nor(1, 0))
assert.Equal(false, Nor(1, 1))
}
func TestXnor(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestXnor")
assert.Equal(true, Xnor(0, 0))
assert.Equal(false, Xnor(0, 1))
assert.Equal(false, Xnor(1, 0))
assert.Equal(true, Xnor(1, 1))
}
func TestNand(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestNand")
assert.Equal(true, Nand(0, 0))
assert.Equal(true, Nand(0, 1))
assert.Equal(true, Nand(1, 0))
assert.Equal(false, Nand(1, 1))
}
func TestTernaryOperator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TernaryOperator")
trueValue := "1"
falseValue := "0"
assert.Equal(trueValue, TernaryOperator(true, trueValue, falseValue))
}
+150 -170
View File
@@ -11,26 +11,20 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"math"
"reflect"
"regexp"
"strconv"
"strings"
"github.com/duke-git/lancet/v2/structs"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
)
// ToBool convert string to boolean.
// Play: https://go.dev/play/p/ARht2WnGdIN
// ToBool convert string to a boolean
func ToBool(s string) (bool, error) {
return strconv.ParseBool(s)
}
// ToBytes convert value to byte slice.
// Play: https://go.dev/play/p/fAMXYFDvOvr
func ToBytes(value any) ([]byte, error) {
// ToBytes convert interface to bytes
func ToBytes(value interface{}) ([]byte, error) {
v := reflect.ValueOf(value)
switch value.(type) {
@@ -70,8 +64,7 @@ func ToBytes(value any) ([]byte, error) {
}
}
// ToChar convert string to char slice.
// Play: https://go.dev/play/p/JJ1SvbFkVdM
// ToChar convert string to char slice
func ToChar(s string) []string {
c := make([]string, 0)
if len(s) == 0 {
@@ -83,179 +76,133 @@ func ToChar(s string) []string {
return c
}
// ToChannel convert a slice of elements to a read-only channel.
// Play: https://go.dev/play/p/hOx_oYZbAnL
func ToChannel[T any](array []T) <-chan T {
ch := make(chan T)
go func() {
for _, item := range array {
ch <- item
}
close(ch)
}()
return ch
}
// ToString convert value to string
// for number, string, []byte, will convert to string
// for other type (slice, map, array, struct) will call json.Marshal.
// Play: https://go.dev/play/p/nF1zOOslpQq
func ToString(value any) string {
func ToString(value interface{}) string {
res := ""
if value == nil {
return ""
return res
}
switch val := value.(type) {
case float32:
return strconv.FormatFloat(float64(val), 'f', -1, 32)
case float64:
return strconv.FormatFloat(val, 'f', -1, 64)
case int:
return strconv.FormatInt(int64(val), 10)
case int8:
return strconv.FormatInt(int64(val), 10)
case int16:
return strconv.FormatInt(int64(val), 10)
case int32:
return strconv.FormatInt(int64(val), 10)
case int64:
return strconv.FormatInt(val, 10)
case uint:
return strconv.FormatUint(uint64(val), 10)
case uint8:
return strconv.FormatUint(uint64(val), 10)
case uint16:
return strconv.FormatUint(uint64(val), 10)
case uint32:
return strconv.FormatUint(uint64(val), 10)
case uint64:
return strconv.FormatUint(val, 10)
case string:
return val
case []byte:
return string(val)
default:
b, err := json.Marshal(val)
if err != nil {
return ""
}
return string(b)
v := reflect.ValueOf(value)
// todo: maybe we should't supprt other type conversion
// v := reflect.ValueOf(value)
// log.Panicf("Unsupported data type: %s ", v.String())
// return ""
switch value.(type) {
case float32, float64:
res = strconv.FormatFloat(v.Float(), 'f', -1, 64)
return res
case int, int8, int16, int32, int64:
res = strconv.FormatInt(v.Int(), 10)
return res
case uint, uint8, uint16, uint32, uint64:
res = strconv.FormatUint(v.Uint(), 10)
return res
case string:
res = v.String()
return res
case []byte:
res = string(v.Bytes())
return res
default:
newValue, _ := json.Marshal(value)
res = string(newValue)
return res
}
}
// ToJson convert value to a json string.
// Play: https://go.dev/play/p/2rLIkMmXWvR
func ToJson(value any) (string, error) {
result, err := json.Marshal(value)
// ToJson convert value to a valid json string
func ToJson(value interface{}) (string, error) {
res, err := json.Marshal(value)
if err != nil {
return "", err
}
return string(result), nil
return string(res), nil
}
// ToFloat convert value to float64, if input is not a float return 0.0 and error.
// Play: https://go.dev/play/p/4YTmPCibqHJ
func ToFloat(value any) (float64, error) {
// ToFloat convert value to a float64, if input is not a float return 0.0 and error
func ToFloat(value interface{}) (float64, error) {
v := reflect.ValueOf(value)
result := 0.0
res := 0.0
err := fmt.Errorf("ToInt: unvalid interface type %T", value)
switch value.(type) {
case int, int8, int16, int32, int64:
result = float64(v.Int())
return result, nil
res = float64(v.Int())
return res, nil
case uint, uint8, uint16, uint32, uint64:
result = float64(v.Uint())
return result, nil
res = float64(v.Uint())
return res, nil
case float32, float64:
result = v.Float()
return result, nil
res = v.Float()
return res, nil
case string:
result, err = strconv.ParseFloat(v.String(), 64)
res, err = strconv.ParseFloat(v.String(), 64)
if err != nil {
result = 0.0
res = 0.0
}
return result, err
return res, err
default:
return result, err
return res, err
}
}
// ToInt convert value to int64 value, if input is not numerical, return 0 and error.
// Play: https://go.dev/play/p/9_h9vIt-QZ_b
func ToInt(value any) (int64, error) {
// ToInt convert value to a int64, if input is not a numeric format return 0 and error
func ToInt(value interface{}) (int64, error) {
v := reflect.ValueOf(value)
var result int64
err := fmt.Errorf("ToInt: invalid value type %T", value)
var res int64
err := fmt.Errorf("ToInt: invalid interface type %T", value)
switch value.(type) {
case int, int8, int16, int32, int64:
result = v.Int()
return result, nil
res = v.Int()
return res, nil
case uint, uint8, uint16, uint32, uint64:
result = int64(v.Uint())
return result, nil
res = int64(v.Uint())
return res, nil
case float32, float64:
result = int64(v.Float())
return result, nil
res = int64(v.Float())
return res, nil
case string:
result, err = strconv.ParseInt(v.String(), 0, 64)
res, err = strconv.ParseInt(v.String(), 0, 64)
if err != nil {
result = 0
res = 0
}
return result, err
return res, err
default:
return result, err
return res, err
}
}
// ToPointer returns a pointer to passed value.
// Play: https://go.dev/play/p/ASf_etHNlw1
func ToPointer[T any](value T) *T {
return &value
}
// ToMap convert a slice of structs to a map based on iteratee function.
// Play: https://go.dev/play/p/tVFy7E-t24l
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
result := make(map[K]V, len(array))
for _, item := range array {
k, v := iteratee(item)
result[k] = v
}
return result
}
// StructToMap convert struct to map, only convert exported struct field
// map key is specified same as struct field tag `json` value.
// Play: https://go.dev/play/p/KYGYJqNUBOI
func StructToMap(value any) (map[string]any, error) {
return structs.ToMap(value)
}
// map key is specified same as struct field tag `json` value
func StructToMap(value interface{}) (map[string]interface{}, error) {
v := reflect.ValueOf(value)
t := reflect.TypeOf(value)
// MapToSlice convert map to slice based on iteratee function.
// Play: https://go.dev/play/p/dmX4Ix5V6Wl
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
result := make([]T, 0, len(aMap))
for k, v := range aMap {
result = append(result, iteratee(k, v))
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
}
return result
res := make(map[string]interface{})
fieldNum := t.NumField()
pattern := `^[A-Z]`
regex := regexp.MustCompile(pattern)
for i := 0; i < fieldNum; i++ {
name := t.Field(i).Name
tag := t.Field(i).Tag.Get("json")
if regex.MatchString(name) && tag != "" {
//res[name] = v.Field(i).Interface()
res[tag] = v.Field(i).Interface()
}
}
return res, nil
}
// ColorHexToRGB convert hex color to rgb color.
// Play: https://go.dev/play/p/o7_ft-JCJBV
// ColorHexToRGB convert hex color to rgb color
func ColorHexToRGB(colorHex string) (red, green, blue int) {
colorHex = strings.TrimPrefix(colorHex, "#")
color64, err := strconv.ParseInt(colorHex, 16, 32)
@@ -266,8 +213,7 @@ func ColorHexToRGB(colorHex string) (red, green, blue int) {
return color >> 16, (color & 0x00FF00) >> 8, color & 0x0000FF
}
// ColorRGBToHex convert rgb color to hex color.
// Play: https://go.dev/play/p/nzKS2Ro87J1
// ColorRGBToHex convert rgb color to hex color
func ColorRGBToHex(red, green, blue int) string {
r := strconv.FormatInt(int64(red), 16)
g := strconv.FormatInt(int64(green), 16)
@@ -286,9 +232,22 @@ func ColorRGBToHex(red, green, blue int) string {
return "#" + r + g + b
}
// EncodeByte encode data to byte slice.
// Play: https://go.dev/play/p/DVmM1G5JfuP
func EncodeByte(data any) ([]byte, error) {
// ToChannel convert a array of elements to a read-only channels
func ToChannel(array []interface{}) <-chan interface{} {
ch := make(chan interface{})
go func() {
for _, item := range array {
ch <- item
}
close(ch)
}()
return ch
}
// EncodeByte encode data to byte
func EncodeByte(data interface{}) ([]byte, error) {
buffer := bytes.NewBuffer(nil)
encoder := gob.NewEncoder(buffer)
err := encoder.Encode(data)
@@ -298,9 +257,8 @@ func EncodeByte(data any) ([]byte, error) {
return buffer.Bytes(), nil
}
// DecodeByte decode byte slice data to target object.
// Play: https://go.dev/play/p/zI6xsmuQRbn
func DecodeByte(data []byte, target any) error {
// DecodeByte decode byte data to target object
func DecodeByte(data []byte, target interface{}) error {
buffer := bytes.NewBuffer(data)
decoder := gob.NewDecoder(buffer)
return decoder.Decode(target)
@@ -308,24 +266,63 @@ func DecodeByte(data []byte, target any) error {
// DeepClone creates a deep copy of passed item.
// can't clone unexported field of struct
// Play: https://go.dev/play/p/j4DP5dquxnk
func DeepClone[T any](src T) T {
func DeepClone(src interface{}) interface{} {
c := cloner{
ptrs: map[reflect.Type]map[uintptr]reflect.Value{},
}
result := c.clone(reflect.ValueOf(src))
if result.Kind() == reflect.Invalid {
var zeroValue T
return zeroValue
return nil
}
return result.Interface().(T)
return result.Interface()
}
// // CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
// func CopyProperties(dst, src interface{}) (err error) {
// defer func() {
// if e := recover(); e != nil {
// err = errors.New(fmt.Sprintf("%v", e))
// }
// }()
// dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
// srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
// if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
// return errors.New("CopyProperties: param dst should be struct pointer")
// }
// if srcType.Kind() == reflect.Ptr {
// srcType, srcValue = srcType.Elem(), srcValue.Elem()
// }
// if srcType.Kind() != reflect.Struct {
// return errors.New("CopyProperties: param src should be a struct or struct pointer")
// }
// dstType, dstValue = dstType.Elem(), dstValue.Elem()
// propertyNums := dstType.NumField()
// for i := 0; i < propertyNums; i++ {
// property := dstType.Field(i)
// propertyValue := srcValue.FieldByName(property.Name)
// if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
// continue
// }
// if dstValue.Field(i).CanSet() {
// dstValue.Field(i).Set(propertyValue)
// }
// }
// return nil
// }
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
// Play: https://go.dev/play/p/oZujoB5Sgg5
func CopyProperties[T, U any](dst T, src U) error {
func CopyProperties(dst, src interface{}) error {
dstType, srcType := reflect.TypeOf(dst), reflect.TypeOf(src)
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
@@ -352,7 +349,6 @@ func CopyProperties[T, U any](dst T, src U) error {
}
// ToInterface converts reflect value to its interface type.
// Play: https://go.dev/play/p/syqw0-WG7Xd
func ToInterface(v reflect.Value) (value interface{}, ok bool) {
if v.IsValid() && v.CanInterface() {
return v.Interface(), true
@@ -378,19 +374,3 @@ func ToInterface(v reflect.Value) (value interface{}, ok bool) {
return nil, false
}
}
// Utf8ToGbk convert utf8 encoding data to GBK encoding data.
// Play: https://go.dev/play/p/9FlIaFLArIL
func Utf8ToGbk(bs []byte) ([]byte, error) {
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewEncoder())
b, err := io.ReadAll(r)
return b, err
}
// GbkToUtf8 convert GBK encoding data to utf8 encoding data.
// Play: https://go.dev/play/p/OphmHCN_9u8
func GbkToUtf8(bs []byte) ([]byte, error) {
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewDecoder())
b, err := io.ReadAll(r)
return b, err
}
-393
View File
@@ -1,393 +0,0 @@
package convertor
import (
"fmt"
"reflect"
"strconv"
"unicode/utf8"
"github.com/duke-git/lancet/v2/validator"
)
func ExampleToBool() {
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
for i := 0; i < len(cases); i++ {
result, _ := ToBool(cases[i])
fmt.Println(result)
}
// Output:
// true
// true
// true
// false
// false
// false
// false
// false
// false
}
func ExampleToBytes() {
result1, _ := ToBytes(1)
result2, _ := ToBytes("abc")
result3, _ := ToBytes(true)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [0 0 0 0 0 0 0 1]
// [97 98 99]
// [116 114 117 101]
}
func ExampleToChar() {
result1 := ToChar("")
result2 := ToChar("abc")
result3 := ToChar("1 2#3")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// []
// [a b c]
// [1 2 # 3]
}
func ExampleToChannel() {
ch := ToChannel([]int{1, 2, 3})
result1 := <-ch
result2 := <-ch
result3 := <-ch
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 3
}
func ExampleToString() {
result1 := ToString("")
result2 := ToString(nil)
result3 := ToString(0)
result4 := ToString(1.23)
result5 := ToString(true)
result6 := ToString(false)
result7 := ToString([]int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
//
//
// 0
// 1.23
// true
// false
// [1,2,3]
}
func ExampleToJson() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result1, err := ToJson(aMap)
if err != nil {
fmt.Printf("%v", err)
}
fmt.Println(result1)
// Output:
// {"a":1,"b":2,"c":3}
}
func ExampleToFloat() {
result1, _ := ToFloat("")
result2, _ := ToFloat("abc")
result3, _ := ToFloat("-1")
result4, _ := ToFloat("-.11")
result5, _ := ToFloat("1.23e3")
result6, _ := ToFloat(true)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// 0
// 0
// -1
// -0.11
// 1230
// 0
}
func ExampleToInt() {
result1, _ := ToInt("123")
result2, _ := ToInt("-123")
result3, _ := ToInt(float64(12.3))
result4, _ := ToInt("abc")
result5, _ := ToInt(true)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 123
// -123
// 12
// 0
// 0
}
func ExampleToPointer() {
result := ToPointer(123)
fmt.Println(*result)
// Output:
// 123
}
func ExampleToMap() {
type Message struct {
name string
code int
}
messages := []Message{
{name: "Hello", code: 100},
{name: "Hi", code: 101},
}
result := ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name
})
fmt.Println(result)
// Output:
// map[100:Hello 101:Hi]
}
func ExampleStructToMap() {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := StructToMap(p)
fmt.Println(pm)
// Output:
// map[name:test]
}
func ExampleMapToSlice() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result := MapToSlice(aMap, func(key string, value int) string {
return key + ":" + strconv.Itoa(value)
})
fmt.Println(result) //[]string{"a:1", "c:3", "b:2"} (random order)
}
func ExampleColorHexToRGB() {
colorHex := "#003366"
r, g, b := ColorHexToRGB(colorHex)
fmt.Println(r, g, b)
// Output:
// 0 51 102
}
func ExampleColorRGBToHex() {
r := 0
g := 51
b := 102
colorHex := ColorRGBToHex(r, g, b)
fmt.Println(colorHex)
// Output:
// #003366
}
func ExampleEncodeByte() {
byteData, _ := EncodeByte("abc")
fmt.Println(byteData)
// Output:
// [6 12 0 3 97 98 99]
}
func ExampleDecodeByte() {
var obj string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
err := DecodeByte(byteData, &obj)
if err != nil {
return
}
fmt.Println(obj)
// Output:
// abc
}
func ExampleDeepClone() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
// unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for _, item := range cases {
cloned := DeepClone(item)
isPointerEqual := &cloned == &item
fmt.Println(cloned, isPointerEqual)
}
// Output:
// true false
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil>} false
}
func ExampleCopyProperties() {
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
CopyProperties(&indicatorVO, indicator)
fmt.Println(indicatorVO.Id)
fmt.Println(indicatorVO.Ip)
fmt.Println(len(indicatorVO.Disk))
// Output:
// 001
// 127.0.0.1
// 3
}
func ExampleToInterface() {
val := reflect.ValueOf("abc")
iVal, ok := ToInterface(val)
fmt.Printf("%T\n", iVal)
fmt.Printf("%v\n", iVal)
fmt.Println(ok)
// Output:
// string
// abc
// true
}
func ExampleUtf8ToGbk() {
utf8Data := []byte("hello")
gbkData, _ := Utf8ToGbk(utf8Data)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(validator.IsGBK(gbkData))
// Output:
// true
// true
}
func ExampleGbkToUtf8() {
gbkData, _ := Utf8ToGbk([]byte("hello"))
utf8Data, _ := GbkToUtf8(gbkData)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(string(utf8Data))
// Output:
// true
// hello
}
+39 -160
View File
@@ -3,18 +3,12 @@ package convertor
import (
"fmt"
"reflect"
"strconv"
"testing"
"unicode/utf8"
"github.com/duke-git/lancet/v2/internal"
"github.com/duke-git/lancet/v2/slice"
"github.com/duke-git/lancet/v2/validator"
"github.com/duke-git/lancet/internal"
)
func TestToChar(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToChar")
cases := []string{"", "abc", "1 2#3"}
@@ -28,23 +22,7 @@ func TestToChar(t *testing.T) {
}
}
func TestToChannel(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToChannel")
ch := ToChannel([]int{1, 2, 3})
assert.Equal(1, <-ch)
assert.Equal(2, <-ch)
assert.Equal(3, <-ch)
_, ok := <-ch
assert.Equal(false, ok)
}
func TestToBool(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToBool")
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
@@ -57,11 +35,9 @@ func TestToBool(t *testing.T) {
}
func TestToBytes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToBytes")
cases := []any{
cases := []interface{}{
0,
false,
"1",
@@ -85,11 +61,9 @@ func TestToBytes(t *testing.T) {
}
func TestToInt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToInt")
cases := []any{"123", "-123", 123,
cases := []interface{}{"123", "-123", 123,
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float32(12.3), float64(12.3),
"abc", false, "111111111111111111111111111111111111111"}
@@ -103,11 +77,9 @@ func TestToInt(t *testing.T) {
}
func TestToFloat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToFloat")
cases := []any{
cases := []interface{}{
"", "-1", "-.11", "1.23e3", ".123e10", "abc",
int(0), int8(1), int16(-1), int32(123), int64(123),
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
@@ -123,8 +95,6 @@ func TestToFloat(t *testing.T) {
}
func TestToString(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToString")
aMap := make(map[string]int)
@@ -137,7 +107,7 @@ func TestToString(t *testing.T) {
}
aStruct := TestStruct{Name: "TestStruct"}
cases := []any{
cases := []interface{}{
"", nil,
int(0), int8(1), int16(-1), int32(123), int64(123),
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
@@ -149,10 +119,9 @@ func TestToString(t *testing.T) {
"", "",
"0", "1", "-1",
"123", "123", "123", "123", "123", "123", "123",
"12.3", "12.3",
"12.3", "12.300000190734863",
"true", "false",
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello",
}
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
for i := 0; i < len(cases); i++ {
actual := ToString(cases[i])
@@ -160,8 +129,6 @@ func TestToString(t *testing.T) {
}
}
func TestToJson(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToJson")
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
@@ -176,83 +143,23 @@ func TestToJson(t *testing.T) {
assert.Equal("{\"Name\":\"TestStruct\"}", structJsonStr)
}
func TestToMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToMap")
type Message struct {
name string
code int
}
messages := []Message{
{name: "Hello", code: 100},
{name: "Hi", code: 101},
}
result := ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name
})
expected := map[int]string{100: "Hello", 101: "Hi"}
assert.Equal(expected, result)
}
func TestStructToMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStructToMap")
t.Run("StructToMap", func(_ *testing.T) {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := StructToMap(p)
var expected = map[string]any{"name": "test"}
assert.Equal(expected, pm)
})
t.Run("StructToMapWithJsonAttr", func(_ *testing.T) {
type People struct {
Name string `json:"name,omitempty"` // json tag with attribute
Phone string `json:"phone"` // json tag without attribute
Sex string `json:"-"` // ignore
age int // no tag
}
p := People{
Phone: "1111",
Sex: "male",
age: 100,
}
pm, _ := StructToMap(p)
var expected = map[string]any{"phone": "1111"}
assert.Equal(expected, pm)
})
}
func TestMapToSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMapToSlice")
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result := MapToSlice(aMap, func(key string, value int) string {
return key + ":" + strconv.Itoa(value)
})
assert.Equal(3, len(result))
assert.Equal(true, slice.Contain(result, "a:1"))
assert.Equal(true, slice.Contain(result, "b:2"))
assert.Equal(true, slice.Contain(result, "c:3"))
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := StructToMap(p)
var expected = map[string]interface{}{"name": "test"}
assert.Equal(expected, pm)
}
func TestColorHexToRGB(t *testing.T) {
t.Parallel()
colorHex := "#003366"
r, g, b := ColorHexToRGB(colorHex)
colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b)
@@ -263,8 +170,6 @@ func TestColorHexToRGB(t *testing.T) {
}
func TestColorRGBToHex(t *testing.T) {
t.Parallel()
r := 0
g := 51
b := 102
@@ -275,18 +180,24 @@ func TestColorRGBToHex(t *testing.T) {
assert.Equal(expected, colorHex)
}
func TestToPointer(t *testing.T) {
t.Parallel()
func TestToChannel(t *testing.T) {
assert := internal.NewAssert(t, "TestToChannel")
assert := internal.NewAssert(t, "TestToPointer")
result := ToPointer(123)
ch := ToChannel([]interface{}{1, 2, 3})
val1, _ := <-ch
assert.Equal(1, val1)
assert.Equal(*result, 123)
val2, _ := <-ch
assert.Equal(2, val2)
val3, _ := <-ch
assert.Equal(3, val3)
_, ok := <-ch
assert.Equal(false, ok)
}
func TestEncodeByte(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEncodeByte")
byteData, _ := EncodeByte("abc")
@@ -296,29 +207,24 @@ func TestEncodeByte(t *testing.T) {
}
func TestDecodeByte(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDecodeByte")
var obj string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
err := DecodeByte(byteData, &obj)
assert.IsNil(err)
DecodeByte(byteData, &obj)
assert.Equal("abc", obj)
}
func TestDeepClone(t *testing.T) {
t.Parallel()
// assert := internal.NewAssert(t, "TestDeepClone")
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
// unexported string
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
@@ -342,6 +248,7 @@ func TestDeepClone(t *testing.T) {
for i, item := range cases {
cloned := DeepClone(item)
t.Log(cloned)
if &cloned == &item {
t.Fatalf("[TestDeepClone case #%d failed]: equal pointer", i)
}
@@ -353,8 +260,6 @@ func TestDeepClone(t *testing.T) {
}
func TestCopyProperties(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCopyProperties")
type Disk struct {
@@ -407,8 +312,6 @@ func TestCopyProperties(t *testing.T) {
}
func TestToInterface(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToInterface")
cases := []reflect.Value{
@@ -436,27 +339,3 @@ func TestToInterface(t *testing.T) {
assert.EqualValues(nil, nilVal)
assert.Equal(false, ok)
}
func TestUtf8ToGbk(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUtf8ToGbk")
utf8Data := []byte("hello")
gbkData, err := Utf8ToGbk(utf8Data)
assert.Equal(true, utf8.Valid(utf8Data))
assert.Equal(true, validator.IsGBK(gbkData))
assert.IsNil(err)
}
func TestGbkToUtf8(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGbkToUtf8")
gbkData, err := Utf8ToGbk([]byte("hello"))
utf8Data, err := GbkToUtf8(gbkData)
assert.IsNil(err)
assert.Equal(true, utf8.Valid(utf8Data))
assert.Equal("hello", string(utf8Data))
}
+188
View File
@@ -0,0 +1,188 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package cryptor implements some util functions to encrypt and decrypt.
// Note:
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
package cryptor
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
)
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32
func AesEcbEncrypt(data, key []byte) []byte {
size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
cipher, _ := aes.NewCipher(generateAesKey(key, size))
length := (len(data) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, data)
pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32
func AesEcbDecrypt(encrypted, key []byte) []byte {
size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
cipher, _ := aes.NewCipher(generateAesKey(key, size))
decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim]
}
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32
func AesCbcEncrypt(data, key []byte) []byte {
block, _ := aes.NewCipher(key)
data = pkcs7Padding(data, block.BlockSize())
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32
func AesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := aes.NewCipher(key)
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypted, encrypted)
decrypted := pkcs7UnPadding(encrypted)
return decrypted
}
// AesCtrCrypt encrypt data with key use AES CTR algorithm
// len(key) should be 16, 24 or 32
func AesCtrCrypt(data, key []byte) []byte {
block, _ := aes.NewCipher(key)
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
dst := make([]byte, len(data))
stream.XORKeyStream(dst, data)
return dst
}
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
// len(key) should be 16, 24 or 32
func AesCfbEncrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
func AesCfbDecrypt(encrypted, key []byte) []byte {
block, _ := aes.NewCipher(key)
if len(encrypted) < aes.BlockSize {
panic("encrypted data is too short")
}
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
// len(key) should be 16, 24 or 32
func AesOfbEncrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
data = pkcs7Padding(data, aes.BlockSize)
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
// len(key) should be 16, 24 or 32
func AesOfbDecrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
iv := data[:aes.BlockSize]
data = data[aes.BlockSize:]
if len(data)%aes.BlockSize != 0 {
return nil
}
decrypted := make([]byte, len(data))
mode := cipher.NewOFB(block, iv)
mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}
+62
View File
@@ -0,0 +1,62 @@
package cryptor
import (
"testing"
"github.com/duke-git/lancet/internal"
)
func TestAesEcbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
assert.Equal(data, string(aesEcbDecrypt))
}
func TestAesCbcEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
assert.Equal(data, string(aesCbcDecrypt))
}
func TestAesCtrCrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCtrCrypt")
assert.Equal(data, string(aesCtrDeCrypt))
}
func TestAesCfbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
assert.Equal(data, string(aesCfbDecrypt))
}
func TestAesOfbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
assert.Equal(data, string(aesOfbDecrypt))
}
+25 -115
View File
@@ -19,52 +19,25 @@ import (
"os"
)
// Base64StdEncode encode string with base64 encoding.
// Play: https://go.dev/play/p/VOaUyQUreoK
// Base64StdEncode encode string with base64 encoding
func Base64StdEncode(s string) string {
return base64.StdEncoding.EncodeToString([]byte(s))
}
// Base64StdDecode decode a base64 encoded string.
// Play: https://go.dev/play/p/RWQylnJVgIe
// Base64StdDecode decode a base64 encoded string
func Base64StdDecode(s string) string {
b, _ := base64.StdEncoding.DecodeString(s)
return string(b)
}
// Md5String return the md5 value of string.
// Play: https://go.dev/play/p/1bLcVetbTOI
// Md5String return the md5 value of string
func Md5String(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
// Md5StringWithBase64 return the md5 value of string with base64.
// Play: https://go.dev/play/p/Lx4gH7Vdr5_y
func Md5StringWithBase64(s string) string {
h := md5.New()
h.Write([]byte(s))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
// Md5Byte return the md5 string of byte slice.
// Play: https://go.dev/play/p/suraalH8lyC
func Md5Byte(data []byte) string {
h := md5.New()
h.Write(data)
return hex.EncodeToString(h.Sum(nil))
}
// Md5ByteWithBase64 return the md5 string of byte slice with base64.
// Play: https://go.dev/play/p/Tcb-Z7LN2ax
func Md5ByteWithBase64(data []byte) string {
h := md5.New()
h.Write(data)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
// Md5File return the md5 value of file.
// Md5File return the md5 value of file
func Md5File(filename string) (string, error) {
if fileInfo, err := os.Stat(filename); err != nil {
return "", err
@@ -96,114 +69,51 @@ func Md5File(filename string) (string, error) {
return checksum, nil
}
// HmacMd5 return the hmac hash of string use md5.
// Play: https://go.dev/play/p/uef0q1fz53I
func HmacMd5(str, key string) string {
h := hmac.New(md5.New, []byte(key))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacMd5WithBase64 return the hmac hash of string use md5 with base64.
// https://go.dev/play/p/UY0ng2AefFC
func HmacMd5WithBase64(data, key string) string {
// HmacMd5 return the hmac hash of string use md5
func HmacMd5(data, key string) string {
h := hmac.New(md5.New, []byte(key))
h.Write([]byte(data))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha1 return the hmac hash of string use sha1.
// Play: https://go.dev/play/p/1UI4oQ4WXKM
func HmacSha1(str, key string) string {
// HmacSha1 return the hmac hash of string use sha1
func HmacSha1(data, key string) string {
h := hmac.New(sha1.New, []byte(key))
h.Write([]byte(str))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha1WithBase64 return the hmac hash of string use sha1 with base64.
// Play: https://go.dev/play/p/47JmmGrnF7B
func HmacSha1WithBase64(str, key string) string {
h := hmac.New(sha1.New, []byte(key))
h.Write([]byte(str))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// HmacSha256 return the hmac hash of string use sha256.
// Play: https://go.dev/play/p/HhpwXxFhhC0
func HmacSha256(str, key string) string {
// HmacSha256 return the hmac hash of string use sha256
func HmacSha256(data, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(str))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha256WithBase64 return the hmac hash of string use sha256 with base64.
// Play: https://go.dev/play/p/EKbkUvPTLwO
func HmacSha256WithBase64(str, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(str))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// HmacSha512 return the hmac hash of string use sha512.
// Play: https://go.dev/play/p/59Od6m4A0Ud
func HmacSha512(str, key string) string {
// HmacSha512 return the hmac hash of string use sha512
func HmacSha512(data, key string) string {
h := hmac.New(sha512.New, []byte(key))
h.Write([]byte(str))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha512WithBase64 return the hmac hash of string use sha512 with base64.
// Play: https://go.dev/play/p/c6dSe3E2ydU
func HmacSha512WithBase64(str, key string) string {
h := hmac.New(sha512.New, []byte(key))
h.Write([]byte(str))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string.
// Play: https://go.dev/play/p/_m_uoD1deMT
func Sha1(str string) string {
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string
func Sha1(data string) string {
sha1 := sha1.New()
sha1.Write([]byte(str))
sha1.Write([]byte(data))
return hex.EncodeToString(sha1.Sum([]byte("")))
}
// Sha1WithBase64 return the sha1 value (SHA-1 hash algorithm) of base64 string.
// Play: https://go.dev/play/p/fSyx-Gl2l2-
func Sha1WithBase64(str string) string {
sha1 := sha1.New()
sha1.Write([]byte(str))
return base64.StdEncoding.EncodeToString(sha1.Sum([]byte("")))
}
// Sha256 return the sha256 value (SHA256 hash algorithm) of string.
// Play: https://go.dev/play/p/tU9tfBMIAr1
func Sha256(str string) string {
// Sha256 return the sha256 value (SHA256 hash algorithm) of string
func Sha256(data string) string {
sha256 := sha256.New()
sha256.Write([]byte(str))
sha256.Write([]byte(data))
return hex.EncodeToString(sha256.Sum([]byte("")))
}
// Sha256WithBase64 return the sha256 value (SHA256 hash algorithm) of base64 string.
// Play: https://go.dev/play/p/85IXJHIal1k
func Sha256WithBase64(str string) string {
sha256 := sha256.New()
sha256.Write([]byte(str))
return base64.StdEncoding.EncodeToString(sha256.Sum([]byte("")))
}
// Sha512 return the sha512 value (SHA512 hash algorithm) of string.
// Play: https://go.dev/play/p/3WsvLYZxsHa
func Sha512(str string) string {
// Sha512 return the sha512 value (SHA512 hash algorithm) of string
func Sha512(data string) string {
sha512 := sha512.New()
sha512.Write([]byte(str))
sha512.Write([]byte(data))
return hex.EncodeToString(sha512.Sum([]byte("")))
}
// Sha512WithBase64 return the sha512 value (SHA512 hash algorithm) of base64 string.
// Play: https://go.dev/play/p/q_fY2rA-k5I
func Sha512WithBase64(str string) string {
sha512 := sha512.New()
sha512.Write([]byte(str))
return base64.StdEncoding.EncodeToString(sha512.Sum([]byte("")))
}
+3 -120
View File
@@ -3,55 +3,25 @@ package cryptor
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
"github.com/duke-git/lancet/internal"
)
func TestBase64StdEncode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBase64StdEncode")
assert.Equal("aGVsbG8gd29ybGQ=", Base64StdEncode("hello world"))
}
func TestBase64StdDecode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBase64StdDecode")
assert.Equal("hello world", Base64StdDecode("aGVsbG8gd29ybGQ="))
}
func TestMd5String(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5String")
assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
}
func TestMd5StringWithBase64(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5StringWithBase64")
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5StringWithBase64("hello"))
}
func TestMd5Byte(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5Byte")
data := []byte{'a'}
assert.Equal("0cc175b9c0f1b6a831c399e269772661", Md5Byte(data))
}
func TestMd5ByteWithBase64(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5ByteWithBase64")
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5ByteWithBase64([]byte("hello")))
}
func TestMd5File(t *testing.T) {
t.Parallel()
fileMd5, err := Md5File("./basic.go")
assert := internal.NewAssert(t, "TestMd5File")
assert.IsNotNil(fileMd5)
@@ -59,22 +29,11 @@ func TestMd5File(t *testing.T) {
}
func TestHmacMd5(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHmacMd5")
assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345"))
}
func TestHmacMd5WithBase64(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHmacMd5WithBase64")
assert.Equal("6DQwbquJLYclJdSRinpjmg==", HmacMd5WithBase64("hello", "12345"))
}
func TestHmacSha1(t *testing.T) {
t.Parallel()
s := "hello world"
key := "12345"
hmacSha1 := HmacSha1(s, key)
@@ -84,45 +43,17 @@ func TestHmacSha1(t *testing.T) {
assert.Equal(expected, hmacSha1)
}
func TestHmacSha1WithBase64(t *testing.T) {
t.Parallel()
s := "hello"
key := "12345"
hmacSha1 := HmacSha1WithBase64(s, key)
expected := "XGqdsMzLkuNu0DI/0Jt/k23prOA="
assert := internal.NewAssert(t, "TestHmacSha1")
assert.Equal(expected, hmacSha1)
}
func TestHmacSha256(t *testing.T) {
t.Parallel()
str := "hello world"
s := "hello world"
key := "12345"
hmacSha256 := HmacSha256(str, key)
hmacSha256 := HmacSha256(s, key)
expected := "9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8"
assert := internal.NewAssert(t, "TestHmacSha256")
assert.Equal(expected, hmacSha256)
}
func TestHmacSha256WithBase64(t *testing.T) {
t.Parallel()
str := "hello"
key := "12345"
hms := HmacSha256WithBase64(str, key)
expected := "MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU="
assert := internal.NewAssert(t, "TestHmacSha256WithBase64")
assert.Equal(expected, hms)
}
func TestHmacSha512(t *testing.T) {
t.Parallel()
s := "hello world"
key := "12345"
hmacSha512 := HmacSha512(s, key)
@@ -132,21 +63,7 @@ func TestHmacSha512(t *testing.T) {
assert.Equal(expected, hmacSha512)
}
func TestHmacSha512WithBase64(t *testing.T) {
t.Parallel()
str := "hello"
key := "12345"
hms := HmacSha512WithBase64(str, key)
expected := "3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A=="
assert := internal.NewAssert(t, "TestHmacSha512WithBase64")
assert.Equal(expected, hms)
}
func TestSha1(t *testing.T) {
t.Parallel()
s := "hello world"
sha1 := Sha1(s)
expected := "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"
@@ -155,19 +72,7 @@ func TestSha1(t *testing.T) {
assert.Equal(expected, sha1)
}
func TestSha1WithBase64(t *testing.T) {
t.Parallel()
str := Sha1WithBase64("hello")
expected := "qvTGHdzF6KLavt4PO0gs2a6pQ00="
assert := internal.NewAssert(t, "TestSha1WithBase64")
assert.Equal(expected, str)
}
func TestSha256(t *testing.T) {
t.Parallel()
s := "hello world"
sha256 := Sha256(s)
expected := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
@@ -176,19 +81,7 @@ func TestSha256(t *testing.T) {
assert.Equal(expected, sha256)
}
func TestSha256WithBase64(t *testing.T) {
t.Parallel()
str := Sha256WithBase64("hello")
expected := "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="
assert := internal.NewAssert(t, "TestSha256WithBase64")
assert.Equal(expected, str)
}
func TestSha512(t *testing.T) {
t.Parallel()
s := "hello world"
sha512 := Sha512(s)
expected := "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"
@@ -196,13 +89,3 @@ func TestSha512(t *testing.T) {
assert := internal.NewAssert(t, "TestSha512")
assert.Equal(expected, sha512)
}
func TestSha512WithBase64(t *testing.T) {
t.Parallel()
str := Sha512WithBase64("hello")
expected := "m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw=="
assert := internal.NewAssert(t, "TestSha512WithBase64")
assert.Equal(expected, str)
}
-507
View File
@@ -1,507 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package cryptor implements some util functions to encrypt and decrypt.
// Note:
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
package cryptor
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/des"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"io"
"os"
)
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/jT5irszHx-j
func AesEcbEncrypt(data, key []byte) []byte {
size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
length := (len(data) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, data)
pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
cipher, _ := aes.NewCipher(generateAesKey(key, size))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/jT5irszHx-j
func AesEcbDecrypt(encrypted, key []byte) []byte {
size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
cipher, _ := aes.NewCipher(generateAesKey(key, size))
decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim]
}
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/IOq_g8_lKZD
func AesCbcEncrypt(data, key []byte) []byte {
block, _ := aes.NewCipher(key)
data = pkcs7Padding(data, block.BlockSize())
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/IOq_g8_lKZD
func AesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := aes.NewCipher(key)
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypted, encrypted)
decrypted := pkcs7UnPadding(encrypted)
return decrypted
}
// AesCtrCrypt encrypt data with key use AES CTR algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/SpaZO0-5Nsp
func AesCtrCrypt(data, key []byte) []byte {
block, _ := aes.NewCipher(key)
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
dst := make([]byte, len(data))
stream.XORKeyStream(dst, data)
return dst
}
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/tfkF10B13kH
func AesCfbEncrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/tfkF10B13kH
func AesCfbDecrypt(encrypted, key []byte) []byte {
if len(encrypted) < aes.BlockSize {
panic("encrypted data is too short")
}
block, _ := aes.NewCipher(key)
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/VtHxtkUj-3F
func AesOfbEncrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
data = pkcs7Padding(data, aes.BlockSize)
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/VtHxtkUj-3F
func AesOfbDecrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
iv := data[:aes.BlockSize]
data = data[aes.BlockSize:]
if len(data)%aes.BlockSize != 0 {
return nil
}
decrypted := make([]byte, len(data))
mode := cipher.NewOFB(block, iv)
mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/8qivmPeZy4P
func DesEcbEncrypt(data, key []byte) []byte {
length := (len(data) + des.BlockSize) / des.BlockSize
plain := make([]byte, length*des.BlockSize)
copy(plain, data)
pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
cipher, _ := des.NewCipher(generateDesKey(key))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/8qivmPeZy4P
func DesEcbDecrypt(encrypted, key []byte) []byte {
cipher, _ := des.NewCipher(generateDesKey(key))
decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim]
}
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/4cC4QvWfe3_1
func DesCbcEncrypt(data, key []byte) []byte {
block, _ := des.NewCipher(key)
data = pkcs7Padding(data, block.BlockSize())
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(encrypted[des.BlockSize:], data)
return encrypted
}
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/4cC4QvWfe3_1
func DesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := des.NewCipher(key)
iv := encrypted[:des.BlockSize]
encrypted = encrypted[des.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypted, encrypted)
decrypted := pkcs7UnPadding(encrypted)
return decrypted
}
// DesCtrCrypt encrypt data with key use DES CTR algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/9-T6OjKpcdw
func DesCtrCrypt(data, key []byte) []byte {
block, _ := des.NewCipher(key)
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
dst := make([]byte, len(data))
stream.XORKeyStream(dst, data)
return dst
}
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/y-eNxcFBlxL
func DesCfbEncrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
// len(encrypted) should be great than 16, len(key) should be 8.
// Play: https://go.dev/play/p/y-eNxcFBlxL
func DesCfbDecrypt(encrypted, key []byte) []byte {
block, _ := des.NewCipher(key)
if len(encrypted) < des.BlockSize {
panic("encrypted data is too short")
}
iv := encrypted[:des.BlockSize]
encrypted = encrypted[des.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/74KmNadjN1J
func DesOfbEncrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
data = pkcs7Padding(data, des.BlockSize)
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/74KmNadjN1J
func DesOfbDecrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
iv := data[:des.BlockSize]
data = data[des.BlockSize:]
if len(data)%des.BlockSize != 0 {
return nil
}
decrypted := make([]byte, len(data))
mode := cipher.NewOFB(block, iv)
mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}
// GenerateRsaKey create rsa private and public pemo file.
// Play: https://go.dev/play/p/zutRHrDqs0X
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
// private key
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
if err != nil {
return err
}
derText := x509.MarshalPKCS1PrivateKey(privateKey)
block := pem.Block{
Type: "rsa private key",
Bytes: derText,
}
file, err := os.Create(priKeyFile)
if err != nil {
panic(err)
}
err = pem.Encode(file, &block)
if err != nil {
return err
}
file.Close()
// public key
publicKey := privateKey.PublicKey
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
if err != nil {
return err
}
block = pem.Block{
Type: "rsa public key",
Bytes: derpText,
}
file, err = os.Create(pubKeyFile)
if err != nil {
return err
}
err = pem.Encode(file, &block)
if err != nil {
return err
}
file.Close()
return nil
}
// RsaEncrypt encrypt data with ras algorithm.
// Play: https://go.dev/play/p/rDqTT01SPkZ
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
file, err := os.Open(pubKeyFileName)
if err != nil {
panic(err)
}
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
defer file.Close()
buf := make([]byte, fileInfo.Size())
_, err = file.Read(buf)
if err != nil {
panic(err)
}
block, _ := pem.Decode(buf)
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic(err)
}
pubKey := pubInterface.(*rsa.PublicKey)
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
if err != nil {
panic(err)
}
return cipherText
}
// RsaDecrypt decrypt data with ras algorithm.
// Play: https://go.dev/play/p/rDqTT01SPkZ
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
file, err := os.Open(privateKeyFileName)
if err != nil {
panic(err)
}
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
buf := make([]byte, fileInfo.Size())
defer file.Close()
_, err = file.Read(buf)
if err != nil {
panic(err)
}
block, _ := pem.Decode(buf)
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
panic(err)
}
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
if err != nil {
panic(err)
}
return plainText
}
-486
View File
@@ -1,486 +0,0 @@
package cryptor
import "fmt"
func ExampleAesEcbEncrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesEcbEncrypt([]byte(data), []byte(key))
decrypted := AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesEcbDecrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesEcbEncrypt([]byte(data), []byte(key))
decrypted := AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCbcEncrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCbcEncrypt([]byte(data), []byte(key))
decrypted := AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCbcDecrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCbcEncrypt([]byte(data), []byte(key))
decrypted := AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCtrCrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCtrCrypt([]byte(data), []byte(key))
decrypted := AesCtrCrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCfbEncrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCfbEncrypt([]byte(data), []byte(key))
decrypted := AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCfbDecrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCfbEncrypt([]byte(data), []byte(key))
decrypted := AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesOfbEncrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesOfbEncrypt([]byte(data), []byte(key))
decrypted := AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesOfbDecrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesOfbEncrypt([]byte(data), []byte(key))
decrypted := AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesEcbEncrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesEcbEncrypt([]byte(data), []byte(key))
decrypted := DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesEcbDecrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesEcbEncrypt([]byte(data), []byte(key))
decrypted := DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCbcEncrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCbcEncrypt([]byte(data), []byte(key))
decrypted := DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCbcDecrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCbcEncrypt([]byte(data), []byte(key))
decrypted := DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCtrCrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCtrCrypt([]byte(data), []byte(key))
decrypted := DesCtrCrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCfbEncrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCfbEncrypt([]byte(data), []byte(key))
decrypted := DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCfbDecrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCfbEncrypt([]byte(data), []byte(key))
decrypted := DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesOfbEncrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesOfbEncrypt([]byte(data), []byte(key))
decrypted := DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesOfbDecrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesOfbEncrypt([]byte(data), []byte(key))
decrypted := DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleGenerateRsaKey() {
// Create ras private and public pem file
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
return
}
fmt.Println("foo")
// Output:
// foo
}
func ExampleRsaEncrypt() {
// Create ras private and public pem file
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
return
}
data := []byte("hello")
encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleRsaDecrypt() {
// Create ras private and public pem file
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
return
}
data := []byte("hello")
encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleBase64StdEncode() {
base64Str := Base64StdEncode("hello")
fmt.Println(base64Str)
// Output:
// aGVsbG8=
}
func ExampleBase64StdDecode() {
str := Base64StdDecode("aGVsbG8=")
fmt.Println(str)
// Output:
// hello
}
func ExampleHmacMd5() {
str := "hello"
key := "12345"
hms := HmacMd5(str, key)
fmt.Println(hms)
// Output:
// e834306eab892d872525d4918a7a639a
}
func ExampleHmacMd5WithBase64() {
str := "hello"
key := "12345"
hms := HmacMd5WithBase64(str, key)
fmt.Println(hms)
// Output:
// 6DQwbquJLYclJdSRinpjmg==
}
func ExampleHmacSha1() {
str := "hello"
key := "12345"
hms := HmacSha1(str, key)
fmt.Println(hms)
// Output:
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
}
func ExampleHmacSha1WithBase64() {
str := "hello"
key := "12345"
hms := HmacSha1WithBase64(str, key)
fmt.Println(hms)
// Output:
// XGqdsMzLkuNu0DI/0Jt/k23prOA=
}
func ExampleHmacSha256() {
str := "hello"
key := "12345"
hms := HmacSha256(str, key)
fmt.Println(hms)
// Output:
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
}
func ExampleHmacSha256WithBase64() {
str := "hello"
key := "12345"
hms := HmacSha256WithBase64(str, key)
fmt.Println(hms)
// Output:
// MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU=
}
func ExampleHmacSha512() {
str := "hello"
key := "12345"
hms := HmacSha512(str, key)
fmt.Println(hms)
// Output:
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
}
func ExampleHmacSha512WithBase64() {
str := "hello"
key := "12345"
hms := HmacSha512WithBase64(str, key)
fmt.Println(hms)
// Output:
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
}
func ExampleMd5String() {
md5Str := Md5String("hello")
fmt.Println(md5Str)
// Output:
// 5d41402abc4b2a76b9719d911017c592
}
func ExampleMd5StringWithBase64() {
md5Str := Md5StringWithBase64("hello")
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
func ExampleMd5Byte() {
md5Str := Md5Byte([]byte{'a'})
fmt.Println(md5Str)
// Output:
// 0cc175b9c0f1b6a831c399e269772661
}
func ExampleMd5ByteWithBase64() {
md5Str := Md5ByteWithBase64([]byte("hello"))
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
func ExampleSha1() {
result := Sha1("hello")
fmt.Println(result)
// Output:
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
}
func ExampleSha1WithBase64() {
result := Sha1WithBase64("hello")
fmt.Println(result)
// Output:
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
}
func ExampleSha256() {
result := Sha256("hello")
fmt.Println(result)
// Output:
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
}
func ExampleSha256WithBase64() {
result := Sha256WithBase64("hello")
fmt.Println(result)
// Output:
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
}
func ExampleSha512() {
result := Sha512("hello")
fmt.Println(result)
// Output:
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
}
func ExampleSha512WithBase64() {
result := Sha512WithBase64("hello")
fmt.Println(result)
// Output:
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
}
+4 -4
View File
@@ -3,14 +3,14 @@ package cryptor
import "bytes"
func generateAesKey(key []byte, size int) []byte {
genKey := make([]byte, size)
copy(genKey, key)
aesKey := make([]byte, size)
copy(aesKey, key)
for i := size; i < len(key); {
for j := 0; j < size && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
aesKey[j] ^= key[i]
}
}
return genKey
return aesKey
}
func generateDesKey(key []byte) []byte {
-152
View File
@@ -1,152 +0,0 @@
package cryptor
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestAesEcbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
assert.Equal(data, string(aesEcbDecrypt))
}
func TestAesCbcEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
assert.Equal(data, string(aesCbcDecrypt))
}
func TestAesCtrCrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCtrCrypt")
assert.Equal(data, string(aesCtrDeCrypt))
}
func TestAesCfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
assert.Equal(data, string(aesCfbDecrypt))
}
func TestAesOfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
assert.Equal(data, string(aesOfbDecrypt))
}
func TestDesEcbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
assert.Equal(data, string(desEcbDecrypt))
}
func TestDesCbcEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
assert.Equal(data, string(desCbcDecrypt))
}
func TestDesCtrCrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCtrCrypt")
assert.Equal(data, string(desCtrDeCrypt))
}
func TestDesCfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
assert.Equal(data, string(desCfbDecrypt))
}
func TestDesOfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
assert.Equal(data, string(desOfbDecrypt))
}
func TestRsaEncrypt(t *testing.T) {
t.Parallel()
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
t.FailNow()
}
data := []byte("hello world")
encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
assert := internal.NewAssert(t, "TestRsaEncrypt")
assert.Equal(string(data), string(decrypted))
}
+178
View File
@@ -0,0 +1,178 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package cryptor implements some util functions to encrypt and decrypt.
package cryptor
import (
"bytes"
"crypto/cipher"
"crypto/des"
"crypto/rand"
"io"
)
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
// len(key) should be 8
func DesEcbEncrypt(data, key []byte) []byte {
cipher, _ := des.NewCipher(generateDesKey(key))
length := (len(data) + des.BlockSize) / des.BlockSize
plain := make([]byte, length*des.BlockSize)
copy(plain, data)
pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
// len(key) should be 8
func DesEcbDecrypt(encrypted, key []byte) []byte {
cipher, _ := des.NewCipher(generateDesKey(key))
decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim]
}
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
// len(key) should be 8
func DesCbcEncrypt(data, key []byte) []byte {
block, _ := des.NewCipher(key)
data = pkcs7Padding(data, block.BlockSize())
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(encrypted[des.BlockSize:], data)
return encrypted
}
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
// len(key) should be 8
func DesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := des.NewCipher(key)
iv := encrypted[:des.BlockSize]
encrypted = encrypted[des.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypted, encrypted)
decrypted := pkcs7UnPadding(encrypted)
return decrypted
}
// DesCtrCrypt encrypt data with key use DES CTR algorithm
// len(key) should be 8
func DesCtrCrypt(data, key []byte) []byte {
block, _ := des.NewCipher(key)
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
dst := make([]byte, len(data))
stream.XORKeyStream(dst, data)
return dst
}
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
// len(key) should be 8
func DesCfbEncrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
// len(encrypted) should be great than 16, len(key) should be 8
func DesCfbDecrypt(encrypted, key []byte) []byte {
block, _ := des.NewCipher(key)
if len(encrypted) < des.BlockSize {
panic("encrypted data is too short")
}
iv := encrypted[:des.BlockSize]
encrypted = encrypted[des.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
// len(key) should be 16, 24 or 32
func DesOfbEncrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
data = pkcs7Padding(data, des.BlockSize)
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
// len(key) should be 8
func DesOfbDecrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
iv := data[:des.BlockSize]
data = data[des.BlockSize:]
if len(data)%des.BlockSize != 0 {
return nil
}
decrypted := make([]byte, len(data))
mode := cipher.NewOFB(block, iv)
mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}
+62
View File
@@ -0,0 +1,62 @@
package cryptor
import (
"testing"
"github.com/duke-git/lancet/internal"
)
func TestDesEcbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
assert.Equal(data, string(desEcbDecrypt))
}
func TestDesCbcEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
assert.Equal(data, string(desCbcDecrypt))
}
func TestDesCtrCrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCtrCrypt")
assert.Equal(data, string(desCtrDeCrypt))
}
func TestDesCfbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
assert.Equal(data, string(desCfbDecrypt))
}
func TestDesOfbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
assert.Equal(data, string(desOfbDecrypt))
}
+118
View File
@@ -0,0 +1,118 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package cryptor implements some util functions to encrypt and decrypt.
package cryptor
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"os"
)
// GenerateRsaKey make a rsa private key, and return key file name
// Generated key file is `rsa_private.pem` and `rsa_public.pem` in current path
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
// private key
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
if err != nil {
return err
}
derText := x509.MarshalPKCS1PrivateKey(privateKey)
block := pem.Block{
Type: "rsa private key",
Bytes: derText,
}
//file,err := os.Create("rsa_private.pem")
file, err := os.Create(priKeyFile)
if err != nil {
panic(err)
}
pem.Encode(file, &block)
file.Close()
// public key
publicKey := privateKey.PublicKey
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
if err != nil {
return err
}
block = pem.Block{
Type: "rsa public key",
Bytes: derpText,
}
//file,err = os.Create("rsa_public.pem")
file, err = os.Create(pubKeyFile)
if err != nil {
return err
}
pem.Encode(file, &block)
file.Close()
return nil
}
// RsaEncrypt encrypt data with ras algorithm
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
file, err := os.Open(pubKeyFileName)
if err != nil {
panic(err)
}
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
defer file.Close()
buf := make([]byte, fileInfo.Size())
file.Read(buf)
block, _ := pem.Decode(buf)
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic(err)
}
pubKey := pubInterface.(*rsa.PublicKey)
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
if err != nil {
panic(err)
}
return cipherText
}
// RsaDecrypt decrypt data with ras algorithm
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
file, err := os.Open(privateKeyFileName)
if err != nil {
panic(err)
}
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
buf := make([]byte, fileInfo.Size())
defer file.Close()
file.Read(buf)
block, _ := pem.Decode(buf)
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
panic(err)
}
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
if err != nil {
panic(err)
}
return plainText
}
+20
View File
@@ -0,0 +1,20 @@
package cryptor
import (
"testing"
"github.com/duke-git/lancet/internal"
)
func TestRsaEncrypt(t *testing.T) {
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
t.FailNow()
}
data := []byte("hello world")
encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
assert := internal.NewAssert(t, "TestRsaEncrypt")
assert.Equal(string(data), string(decrypted))
}
-193
View File
@@ -1,193 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. hashmap structure.
package datastructure
import (
"fmt"
"hash/fnv"
"reflect"
)
var defaultMapCapacity uint64 = 1 << 10
type mapNode struct {
key any
value any
next *mapNode
}
// HashMap implements a hash map
type HashMap struct {
capacity uint64
size uint64
table []*mapNode
}
// NewHashMap return a HashMap instance
func NewHashMap() *HashMap {
return &HashMap{
capacity: defaultMapCapacity,
table: make([]*mapNode, defaultMapCapacity),
}
}
// NewHashMapWithCapacity return a HashMap instance with given size and capacity
func NewHashMapWithCapacity(size, capacity uint64) *HashMap {
return &HashMap{
size: size,
capacity: capacity,
table: make([]*mapNode, capacity),
}
}
// Get return the value of given key in hashmap
func (hm *HashMap) Get(key any) any {
hashValue := hm.hash(key)
node := hm.table[hashValue]
for node != nil {
if reflect.DeepEqual(node.key, key) {
return node.value
}
node = node.next
}
return nil
}
// GetOrDefault return the value of given key in hashmap, if not found return default value
func (hm *HashMap) GetOrDefault(key any, defaultValue any) any {
value := hm.Get(key)
if value == nil {
return defaultValue
}
return value
}
// Put new key value in hashmap
func (hm *HashMap) Put(key any, value any) {
hm.putValue(hm.hash(key), key, value)
}
func (hm *HashMap) putValue(hash uint64, key, value any) {
if hm.capacity == 0 {
hm.capacity = defaultMapCapacity
hm.table = make([]*mapNode, defaultMapCapacity)
}
node := hm.table[hash]
if node == nil {
hm.table[hash] = newMapNode(key, value)
} else if node.key == key {
hm.table[hash] = newMapNodeWithNext(key, value, node)
} else {
hm.resize()
hm.putValue(hash, value, value)
}
hm.size++
}
// Delete item by given key in hashmap
func (hm *HashMap) Delete(key any) {
hash := hm.hash(key)
node := hm.table[hash]
if node == nil {
return
}
hm.table = append(hm.table[:hash], hm.table[hash+1:]...)
hm.size--
}
// Contains checks if given key is in hashmap or not
func (hm *HashMap) Contains(key any) bool {
node := hm.table[hm.hash(key)]
for node != nil {
if reflect.DeepEqual(node.key, key) {
return true
}
node = node.next
}
return false
}
// Iterate executes iteratee funcation for every key and value pair of hashmap (random order)
func (hm *HashMap) Iterate(iteratee func(key, value any)) {
if hm.size > 0 {
for i := 0; i < len(hm.table); i++ {
item := hm.table[i]
if item != nil {
iteratee(item.key, item.value)
}
}
}
}
// Keys returns a slice of the hashmap's keys (random order)
func (hm *HashMap) Keys() []any {
keys := make([]any, int(hm.size))
index := 0
if hm.size > 0 {
hm.Iterate(func(key, value any) {
keys[index] = key
index++
})
}
return keys
}
// Values returns a slice of the hashmap's keys (random order)
func (hm *HashMap) Values() []any {
values := make([]any, int(hm.size))
index := 0
if hm.size > 0 {
hm.Iterate(func(key, value any) {
values[index] = value
index++
})
}
return values
}
func (hm *HashMap) resize() {
hm.capacity <<= 1
tempTable := hm.table
hm.table = make([]*mapNode, hm.capacity)
for i := 0; i < len(tempTable); i++ {
node := tempTable[i]
if node == nil {
continue
}
hm.table[hm.hash(node.key)] = node
}
}
func (hm *HashMap) hash(key any) uint64 {
h := fnv.New64a()
_, _ = h.Write([]byte(fmt.Sprintf("%v", key)))
hashValue := h.Sum64()
return (hm.capacity - 1) & (hashValue ^ (hashValue >> 16))
}
func newMapNode(key, value any) *mapNode {
return &mapNode{
key: key,
value: value,
}
}
func newMapNodeWithNext(key, value any, next *mapNode) *mapNode {
return &mapNode{
key: key,
value: value,
next: next,
}
}
-107
View File
@@ -1,107 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestHashMap_PutAndGet(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_PutAndGet")
hm := NewHashMap()
hm.Put("abc", 3)
assert.Equal(3, hm.Get("abc"))
assert.IsNil(hm.Get("abcd"))
hm.Put("abc", 4)
assert.Equal(4, hm.Get("abc"))
}
func TestHashMap_Resize(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_Resize")
hm := NewHashMapWithCapacity(3, 3)
for i := 0; i < 20; i++ {
hm.Put(i, 10)
}
assert.Equal(10, hm.Get(5))
}
func TestHashMap_Delete(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_Delete")
hm := NewHashMap()
hm.Put("abc", 3)
assert.Equal(3, hm.Get("abc"))
hm.Delete("abc")
assert.IsNil(hm.Get("abc"))
}
func TestHashMap_Contains(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_Contains")
hm := NewHashMap()
assert.Equal(false, hm.Contains("abc"))
hm.Put("abc", 3)
assert.Equal(true, hm.Contains("abc"))
}
func TestHashMap_KeysValues(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_KeysValues")
hm := NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
values := hm.Values()
assert.Equal(3, len(values))
assert.Equal(3, len(keys))
}
func TestHashMap_Keys(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_Keys")
hm := NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
assert.Equal(3, len(keys))
}
func TestHashMap_GetOrDefault(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_GetOrDefault")
hm := NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
assert.Equal(1, hm.GetOrDefault("a", 5))
assert.Equal(5, hm.GetOrDefault("d", 5))
}
-203
View File
@@ -1,203 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. MaxHeap is a binary max heap.
package datastructure
import (
"fmt"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
// MaxHeap implements a binary max heap
// type T should implements Compare function in lancetconstraints.Comparator interface.
type MaxHeap[T any] struct {
data []T
comparator lancetconstraints.Comparator
}
// NewMaxHeap returns a MaxHeap instance with the given comparator.
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] {
return &MaxHeap[T]{
data: make([]T, 0),
comparator: comparator,
}
}
// BuildMaxHeap builds a MaxHeap instance with data and given comparator.
func BuildMaxHeap[T any](data []T, comparator lancetconstraints.Comparator) *MaxHeap[T] {
heap := &MaxHeap[T]{
data: make([]T, 0, len(data)),
comparator: comparator,
}
for _, v := range data {
heap.Push(v)
}
return heap
}
// Push value into the heap
func (h *MaxHeap[T]) Push(value T) {
h.data = append(h.data, value)
h.heapifyUp(len(h.data) - 1)
}
// heapifyUp heapify the data from bottom to top
func (h *MaxHeap[T]) heapifyUp(i int) {
for h.comparator.Compare(h.data[parentIndex(i)], h.data[i]) < 0 {
h.swap(parentIndex(i), i)
i = parentIndex(i)
}
}
// Pop return the largest value, and remove it from the heap
// if heap is empty, return zero value and fasle
func (h *MaxHeap[T]) Pop() (T, bool) {
var val T
if h.Size() == 0 {
return val, false
}
val = h.data[0]
l := len(h.data) - 1
h.data[0] = h.data[l]
h.data = h.data[:l]
h.heapifyDown(0)
return val, true
}
// heapifyDown heapify the data from top to bottom
func (h *MaxHeap[T]) heapifyDown(i int) {
lastIndex := len(h.data) - 1
l, r := leftChildIndex(i), rightChildIndex(i)
childToCompare := 0
for l <= lastIndex {
if l == lastIndex {
childToCompare = l
} else if h.comparator.Compare(h.data[l], h.data[r]) > 0 {
childToCompare = l
} else {
childToCompare = r
}
if h.comparator.Compare(h.data[i], h.data[childToCompare]) < 0 {
h.swap(i, childToCompare)
i = childToCompare
l, r = leftChildIndex(i), rightChildIndex(i)
} else {
break
}
}
}
// Peek returns the largest element from the heap without removing it.
// if heap is empty, it returns zero value and false.
func (h *MaxHeap[T]) Peek() (T, bool) {
if h.Size() == 0 {
var val T
return val, false
}
return h.data[0], true
}
// Size return the number of elements in the heap
func (h *MaxHeap[T]) Size() int {
return len(h.data)
}
// Data return data of the heap
func (h *MaxHeap[T]) Data() []T {
return h.data
}
// PrintStructure print the structure of the heap
func (h *MaxHeap[T]) PrintStructure() {
level := 1
data := h.data
length := len(h.data)
index := 0
list := [][]string{}
temp := []string{}
for index < length {
start := powerTwo(level-1) - 1
end := start + powerTwo(level-1) - 1
temp = append(temp, fmt.Sprintf("%v", data[index]))
index++
if index > end || index >= length {
list = append(list, temp)
temp = []string{}
if index < length {
level++
}
}
}
lastNum := powerTwo(level - 1)
lastLen := lastNum + (lastNum - 1)
heapTree := make([][]string, level)
for i := 0; i < level; i++ {
heapTree[i] = make([]string, lastLen)
for j := 0; j < lastLen; j++ {
heapTree[i][j] = ""
}
}
for k := 0; k < len(list); k++ {
vals := list[k]
tempLevel := level - k
st := powerTwo(tempLevel-1) - 1
for _, v := range vals {
heapTree[k][st] = v
gap := powerTwo(tempLevel)
st = st + gap
}
}
for m := 0; m < level; m++ {
for n := 0; n < lastLen; n++ {
val := heapTree[m][n]
if val == "" {
fmt.Print(" ")
} else {
fmt.Print(val)
}
}
fmt.Println()
}
}
// parentIndex get parent index of the given index
func parentIndex(i int) int {
return (i - 1) / 2
}
// leftChildIndex get left child index of the given index
func leftChildIndex(i int) int {
return 2*i + 1
}
// rightChildIndex get right child index of the given index
func rightChildIndex(i int) int {
return 2*i + 2
}
// swap two elements in the heap
func (h *MaxHeap[T]) swap(i, j int) {
h.data[i], h.data[j] = h.data[j], h.data[i]
}
func powerTwo(n int) int {
return 1 << n
}
-98
View File
@@ -1,98 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func TestMaxHeap_BuildMaxHeap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_BuildMaxHeap")
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
heap := BuildMaxHeap(values, &intComparator{})
expected := []int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
assert.Equal(expected, heap.data)
assert.Equal(12, heap.Size())
}
func TestMaxHeap_Push(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_Push")
heap := NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
heap.Push(v)
}
expected := []int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
assert.Equal(expected, heap.data)
assert.Equal(12, heap.Size())
heap.PrintStructure()
}
func TestMaxHeap_Pop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_Pop")
heap := NewMaxHeap[int](&intComparator{})
_, ok := heap.Pop()
assert.Equal(false, ok)
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
heap.Push(v)
}
val, ok := heap.Pop()
assert.Equal(12, val)
assert.Equal(true, ok)
assert.Equal(11, heap.Size())
}
func TestMaxHeap_Peek(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_Peek")
heap := NewMaxHeap[int](&intComparator{})
_, ok := heap.Peek()
assert.Equal(false, ok)
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
heap.Push(v)
}
val, ok := heap.Peek()
assert.Equal(12, val)
assert.Equal(true, ok)
assert.Equal(12, heap.Size())
}
-242
View File
@@ -1,242 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Link structure contains SinglyLink and DoublyLink.
package datastructure
import (
"fmt"
"github.com/duke-git/lancet/v2/datastructure"
)
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the dl, Next pointer points to a next node of the dl.
type DoublyLink[T any] struct {
Head *datastructure.LinkNode[T]
length int
}
// NewDoublyLink return *DoublyLink instance
func NewDoublyLink[T any]() *DoublyLink[T] {
return &DoublyLink[T]{Head: nil}
}
// InsertAtHead insert value into doubly linklist at head index
func (dl *DoublyLink[T]) InsertAtHead(value T) {
newNode := datastructure.NewLinkNode(value)
size := dl.Size()
if size == 0 {
dl.Head = newNode
dl.length++
return
}
newNode.Next = dl.Head
newNode.Pre = nil
dl.Head.Pre = newNode
dl.Head = newNode
dl.length++
}
// InsertAtTail insert value into doubly linklist at tail index
func (dl *DoublyLink[T]) InsertAtTail(value T) {
current := dl.Head
if current == nil {
dl.InsertAtHead(value)
return
}
for current.Next != nil {
current = current.Next
}
newNode := datastructure.NewLinkNode(value)
newNode.Next = nil
newNode.Pre = current
current.Next = newNode
dl.length++
}
// InsertAt insert value into doubly linklist at index
// param `index` should between [0, length], if index do not meet the conditions, do nothing
func (dl *DoublyLink[T]) InsertAt(index int, value T) {
size := dl.length
if index < 0 || index > size {
return
}
if index == 0 {
dl.InsertAtHead(value)
return
}
if index == size {
dl.InsertAtTail(value)
return
}
i := 0
current := dl.Head
for current != nil {
if i == index-1 {
newNode := datastructure.NewLinkNode(value)
newNode.Next = current.Next
newNode.Pre = current
current.Next = newNode
dl.length++
return
}
i++
current = current.Next
}
}
// DeleteAtHead delete value in doubly linklist at head index
func (dl *DoublyLink[T]) DeleteAtHead() {
if dl.Head == nil {
return
}
current := dl.Head
dl.Head = current.Next
dl.Head.Pre = nil
dl.length--
}
// DeleteAtTail delete value in doubly linklist at tail
func (dl *DoublyLink[T]) DeleteAtTail() {
if dl.Head == nil {
return
}
current := dl.Head
if current.Next == nil {
dl.DeleteAtHead()
}
for current.Next.Next != nil {
current = current.Next
}
current.Next = nil
dl.length--
}
// DeleteAt delete value in doubly linklist at index
// param `index` should be [0, len(DoublyLink)-1]
func (dl *DoublyLink[T]) DeleteAt(index int) {
if dl.Head == nil {
return
}
current := dl.Head
if current.Next == nil || index == 0 {
dl.DeleteAtHead()
}
if index == dl.length-1 {
dl.DeleteAtTail()
}
if index < 0 || index > dl.length-1 {
return
}
i := 0
for current != nil {
if i == index-1 {
current.Next = current.Next.Next
dl.length--
return
}
i++
current = current.Next
}
}
// Reverse the linked list
func (dl *DoublyLink[T]) Reverse() {
current := dl.Head
var temp *datastructure.LinkNode[T]
for current != nil {
temp = current.Pre
current.Pre = current.Next
current.Next = temp
current = current.Pre
}
if temp != nil {
dl.Head = temp.Pre
}
}
// GetMiddleNode return node at middle index of linked list
func (dl *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if dl.Head == nil {
return nil
}
if dl.Head.Next == nil {
return dl.Head
}
fast := dl.Head
slow := dl.Head
for fast != nil {
fast = fast.Next
if fast != nil {
fast = fast.Next
slow = slow.Next
} else {
return slow
}
}
return slow
}
// Size return the count of doubly linked list
func (dl *DoublyLink[T]) Size() int {
return dl.length
}
// Values return slice of all doubly linklist node value
func (dl *DoublyLink[T]) Values() []T {
result := []T{}
current := dl.Head
for current != nil {
result = append(result, current.Value)
current = current.Next
}
return result
}
// Print all nodes info of a linked list
func (dl *DoublyLink[T]) Print() {
current := dl.Head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
current = current.Next
}
info += " ]"
fmt.Println(info)
}
// IsEmpty checks if dl is empty or not
func (dl *DoublyLink[T]) IsEmpty() bool {
return dl.length == 0
}
// Clear all nodes in doubly linklist
func (dl *DoublyLink[T]) Clear() {
dl.Head = nil
dl.length = 0
}
-181
View File
@@ -1,181 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestDoublyLink_InsertAtFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtFirst")
link := NewDoublyLink[int]()
link.InsertAtHead(1)
link.InsertAtHead(2)
link.InsertAtHead(3)
link.Print()
expected := []int{3, 2, 1}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_InsertAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtTail")
link := NewDoublyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_InsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_InsertAt")
link := NewDoublyLink[int]()
link.InsertAt(1, 1) //do nothing
link.InsertAt(0, 1)
link.InsertAt(1, 2)
link.InsertAt(2, 4)
link.InsertAt(2, 3)
expected := []int{1, 2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_DeleteAtHead(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
link := NewDoublyLink[int]()
link.DeleteAtHead()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteAtHead()
expected := []int{2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_DeleteAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
link := NewDoublyLink[int]()
link.DeleteAtTail()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteAtTail()
expected := []int{1, 2, 3}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_DeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
link := NewDoublyLink[int]()
link.DeleteAt(0)
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.InsertAtTail(5)
link.DeleteAt(0)
assert.Equal([]int{2, 3, 4, 5}, link.Values())
link.DeleteAt(3)
assert.Equal([]int{2, 3, 4}, link.Values())
link.DeleteAt(1)
assert.Equal(2, link.Size())
assert.Equal([]int{2, 4}, link.Values())
}
func TestDoublyLink_Reverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_Reverse")
link := NewDoublyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.Reverse()
link.Print()
assert.Equal([]int{4, 3, 2, 1}, link.Values())
}
func TestDoublyLink_GetMiddleNode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_GetMiddleNode")
link := NewDoublyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
middle1 := link.GetMiddleNode()
assert.Equal(3, middle1.Value)
link.InsertAtTail(5)
link.InsertAtTail(6)
link.InsertAtTail(7)
middle2 := link.GetMiddleNode()
assert.Equal(4, middle2.Value)
}
func TestDoublyLink_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_Clear")
link := NewDoublyLink[int]()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())
link.InsertAtTail(1)
assert.Equal(false, link.IsEmpty())
assert.Equal(1, link.Size())
link.Clear()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())
}
-245
View File
@@ -1,245 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Link structure contains SinglyLink and DoublyLink.
package datastructure
import (
"fmt"
"reflect"
"github.com/duke-git/lancet/v2/datastructure"
)
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the sl.
type SinglyLink[T any] struct {
Head *datastructure.LinkNode[T]
length int
}
// NewSinglyLink return *SinglyLink instance
func NewSinglyLink[T any]() *SinglyLink[T] {
return &SinglyLink[T]{Head: nil}
}
// InsertAtHead insert value into singly linklist at head index
func (sl *SinglyLink[T]) InsertAtHead(value T) {
newNode := datastructure.NewLinkNode(value)
newNode.Next = sl.Head
sl.Head = newNode
sl.length++
}
// InsertAtTail insert value into singly linklist at tail index
func (sl *SinglyLink[T]) InsertAtTail(value T) {
current := sl.Head
if current == nil {
sl.InsertAtHead(value)
return
}
for current.Next != nil {
current = current.Next
}
newNode := datastructure.NewLinkNode(value)
newNode.Next = nil
current.Next = newNode
sl.length++
}
// InsertAt insert value into singly linklist at index
// param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing
func (sl *SinglyLink[T]) InsertAt(index int, value T) {
size := sl.length
if index < 0 || index > size {
return
}
if index == 0 {
sl.InsertAtHead(value)
return
}
if index == size {
sl.InsertAtTail(value)
return
}
i := 0
current := sl.Head
for current != nil {
if i == index-1 {
newNode := datastructure.NewLinkNode(value)
newNode.Next = current.Next
current.Next = newNode
sl.length++
return
}
i++
current = current.Next
}
}
// DeleteAtHead delete value in singly linklist at head index
func (sl *SinglyLink[T]) DeleteAtHead() {
if sl.Head == nil {
return
}
current := sl.Head
sl.Head = current.Next
sl.length--
}
// DeleteAtTail delete value in singly linklist at tail
func (sl *SinglyLink[T]) DeleteAtTail() {
if sl.Head == nil {
return
}
current := sl.Head
if current.Next == nil {
sl.DeleteAtHead()
}
for current.Next.Next != nil {
current = current.Next
}
current.Next = nil
sl.length--
}
// DeleteAt delete value in singly linklist at index
// param `index` should be [0, len(SinglyLink)-1]
func (sl *SinglyLink[T]) DeleteAt(index int) {
if sl.Head == nil {
return
}
current := sl.Head
if current.Next == nil || index == 0 {
sl.DeleteAtHead()
}
if index == sl.length-1 {
sl.DeleteAtTail()
}
if index < 0 || index > sl.length-1 {
return
}
i := 0
for current != nil {
if i == index-1 {
current.Next = current.Next.Next
sl.length--
return
}
i++
current = current.Next
}
}
// DeleteValue delete value in singly linklist
func (sl *SinglyLink[T]) DeleteValue(value T) {
if sl.Head == nil {
return
}
dummyHead := datastructure.NewLinkNode(value)
dummyHead.Next = sl.Head
current := dummyHead
for current.Next != nil {
if reflect.DeepEqual(current.Next.Value, value) {
current.Next = current.Next.Next
sl.length--
} else {
current = current.Next
}
}
sl.Head = dummyHead.Next
}
// Reverse the linked list
func (sl *SinglyLink[T]) Reverse() {
var pre, next *datastructure.LinkNode[T]
current := sl.Head
for current != nil {
next = current.Next
current.Next = pre
pre = current
current = next
}
sl.Head = pre
}
// GetMiddleNode return node at middle index of linked list
func (sl *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if sl.Head == nil {
return nil
}
if sl.Head.Next == nil {
return sl.Head
}
fast := sl.Head
slow := sl.Head
for fast != nil {
fast = fast.Next
if fast != nil {
fast = fast.Next
slow = slow.Next
} else {
return slow
}
}
return slow
}
// Size return the count of singly linked list
func (sl *SinglyLink[T]) Size() int {
return sl.length
}
// Values return slice of all singly linklist node value
func (sl *SinglyLink[T]) Values() []T {
result := []T{}
current := sl.Head
for current != nil {
result = append(result, current.Value)
current = current.Next
}
return result
}
// IsEmpty checks if sl is empty or not
func (sl *SinglyLink[T]) IsEmpty() bool {
return sl.length == 0
}
// Clear all the node in singly linklist
func (sl *SinglyLink[T]) Clear() {
sl.Head = nil
sl.length = 0
}
// Print all nodes info of a linked list
func (sl *SinglyLink[T]) Print() {
current := sl.Head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
current = current.Next
}
info += " ]"
fmt.Println(info)
}
-201
View File
@@ -1,201 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestSinglyLink_InsertAtFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtFirst")
link := NewSinglyLink[int]()
link.InsertAtHead(1)
link.InsertAtHead(2)
link.InsertAtHead(3)
link.Print()
expected := []int{3, 2, 1}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_InsertAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtTail")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_InsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_InsertAt")
link := NewSinglyLink[int]()
link.InsertAt(1, 1) //do nothing
link.InsertAt(0, 1)
link.InsertAt(1, 2)
link.InsertAt(2, 4)
link.InsertAt(2, 3)
link.Print()
expected := []int{1, 2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_DeleteAtHead(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
link := NewSinglyLink[int]()
link.DeleteAtHead()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteAtHead()
link.Print()
expected := []int{2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_DeleteAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteAtTail()
expected := []int{1, 2, 3}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_DeleteValue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteValue")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteValue(2)
assert.Equal([]int{1, 3, 4}, link.Values())
link.DeleteValue(1)
assert.Equal([]int{3, 4}, link.Values())
}
func TestSinglyLink_DeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.InsertAtTail(5)
link.DeleteAt(0)
assert.Equal([]int{2, 3, 4, 5}, link.Values())
link.DeleteAt(3)
assert.Equal([]int{2, 3, 4}, link.Values())
link.DeleteAt(1)
assert.Equal(2, link.Size())
assert.Equal([]int{2, 4}, link.Values())
}
func TestSinglyLink_Reverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_Reverse")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.Reverse()
assert.Equal([]int{4, 3, 2, 1}, link.Values())
}
func TestSinglyLink_GetMiddleNode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_GetMiddleNode")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
middle1 := link.GetMiddleNode()
assert.Equal(3, middle1.Value)
link.InsertAtTail(5)
link.InsertAtTail(6)
link.InsertAtTail(7)
middle2 := link.GetMiddleNode()
assert.Equal(4, middle2.Value)
}
func TestSinglyLink_Clear(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_Clear")
link := NewSinglyLink[int]()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())
link.InsertAtTail(1)
assert.Equal(false, link.IsEmpty())
assert.Equal(1, link.Size())
link.Clear()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())
}
-350
View File
@@ -1,350 +0,0 @@
package datastructure
import (
"reflect"
"sort"
"sync"
)
type CopyOnWriteList[T any] struct {
data []T
lock sync.Locker
}
// NewCopyOnWriteList Creates an empty list.
func NewCopyOnWriteList[T any](data []T) *CopyOnWriteList[T] {
return &CopyOnWriteList[T]{data: data, lock: &sync.RWMutex{}}
}
func (c *CopyOnWriteList[T]) getList() []T {
return c.data
}
func (c *CopyOnWriteList[T]) setList(data []T) {
c.data = data
}
// Size returns the number of elements in this list.
func (c *CopyOnWriteList[T]) Size() int {
return len(c.getList())
}
// IsEmpty returns true if this list contains no elements.
func (c *CopyOnWriteList[T]) IsEmpty() bool {
return c.Size() == 0
}
// Contain returns true if this list contains the specified element.
func (c *CopyOnWriteList[T]) Contain(e T) bool {
list := c.getList()
return indexOf(e, list, 0, c.Size()) >= 0
}
// ValueOf returns the index of the first occurrence of the specified element in this list, or null if this list does not contain the element.
func (c *CopyOnWriteList[T]) ValueOf(index int) (*T, bool) {
list := c.getList()
if index < 0 || index >= len(c.data) {
return nil, false
}
return get(list, index), true
}
// IndexOf returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
func (c *CopyOnWriteList[T]) IndexOf(e T) int {
list := c.getList()
return indexOf(e, list, 0, c.Size())
}
// indexOf returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
// start the start position of the search (inclusive)
// end the end position of the search (exclusive)
func indexOf[T any](o T, e []T, start int, end int) int {
if start >= end {
return -1
}
for i := start; i < end; i++ {
if reflect.DeepEqual(e[i], o) {
return i
}
}
return -1
}
// LastIndexOf returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
func (c *CopyOnWriteList[T]) LastIndexOf(e T) int {
list := c.getList()
return lastIndexOf(e, list, 0, c.Size())
}
// lastIndexOf returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
// start the start position of the search (inclusive)
// end the end position of the search (exclusive)
func lastIndexOf[T any](o T, e []T, start int, end int) int {
if start >= end {
return -1
}
for i := end - 1; i >= start; i-- {
if reflect.DeepEqual(e[i], o) {
return i
}
}
return -1
}
// get returns the element at the specified position in this list.
func get[T any](o []T, index int) *T {
return &o[index]
}
// Get returns the element at the specified position in this list.
func (c *CopyOnWriteList[T]) Get(index int) *T {
list := c.getList()
if index < 0 || index >= len(list) {
return nil
}
return get(list, index)
}
func (c *CopyOnWriteList[T]) set(index int, e T) (oldValue *T) {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
oldValue = get(list, index)
if reflect.DeepEqual(oldValue, e) {
c.setList(list)
} else {
newList := make([]T, len(list))
copy(newList, list)
newList[index] = e
c.setList(newList)
}
return
}
// Set replaces the element at the specified position in this list with the specified element.
func (c *CopyOnWriteList[T]) Set(index int, e T) (oldValue *T, ok bool) {
list := c.getList()
if index < 0 || index >= len(list) {
return oldValue, false
}
return c.set(index, e), true
}
// Add appends the specified element to the end of this list.
func (c *CopyOnWriteList[T]) Add(e T) bool {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
newList := make([]T, len(list)+1)
copy(newList, list)
newList[len(list)] = e
c.setList(newList)
return true
}
// AddAll appends all the elements in the specified collection to the end of this list
func (c *CopyOnWriteList[T]) AddAll(e []T) bool {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
newList := make([]T, len(list)+len(e))
copy(newList, list)
copy(newList[len(list):], e)
c.setList(newList)
return true
}
// AddByIndex inserts the specified element at the specified position in this list.
func (c *CopyOnWriteList[T]) AddByIndex(index int, e T) bool {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
length := len(list)
if index < 0 || index > length {
return false
}
var newList []T
var numMove = length - index
if numMove == 0 {
newList = make([]T, length+1)
copy(newList, list)
} else {
newList = make([]T, length+1)
copy(newList, list[:index])
copy(newList[index+1:], list[index:])
}
newList[index] = e
c.setList(newList)
return true
}
// delete removes the element at the specified position in this list.
func (c *CopyOnWriteList[T]) delete(index int) *T {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
length := len(list)
oldValue := get(list, index)
numMove := length - index - 1
var newList []T
if numMove == 0 {
newList = make([]T, length-1)
copy(newList, list[:index])
} else {
newList = make([]T, length-1)
copy(newList, list[:index])
copy(newList[index:], list[index+1:])
}
c.setList(newList)
return oldValue
}
// DeleteAt removes the element at the specified position in this list.
func (c *CopyOnWriteList[T]) DeleteAt(index int) (*T, bool) {
list := c.getList()
if index < 0 || index >= len(list) {
return nil, false
}
return c.delete(index), true
}
// DeleteBy removes the first occurrence of the specified element from this list, if it is present.
func (c *CopyOnWriteList[T]) DeleteBy(o T) (*T, bool) {
list := c.getList()
index := indexOf(o, list, 0, len(list))
if index == -1 {
return nil, false
}
return c.delete(index), true
}
// DeleteRange removes from this list all the elements whose index is between fromIndex, inclusive, and toIndex, exclusive.
// left close and right open
func (c *CopyOnWriteList[T]) DeleteRange(start int, end int) {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
length := len(list)
if start < 0 || end > length || start > end {
return
}
var newList []T
numMove := length - end
if numMove == 0 {
newList = make([]T, length-(end-start))
copy(newList, list[:start])
} else {
newList = make([]T, length-(end-start))
copy(newList, list[:start])
copy(newList[start:], list[end:])
}
c.setList(newList)
}
// DeleteIf removes all the elements of this collection that satisfy the given predicate.
func (c *CopyOnWriteList[T]) DeleteIf(f func(T) bool) {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
length := len(list)
var newList []T
for i := 0; i < length; i++ {
if !f(list[i]) {
newList = append(newList, list[i])
}
}
c.setList(newList)
}
// Equal returns true if the specified object is equal to this list.
func (c *CopyOnWriteList[T]) Equal(other *[]T) bool {
if other == nil {
return false
}
if c.Size() != len(*other) {
return false
}
list := c.getList()
otherList := NewCopyOnWriteList(*other).getList()
for i := 0; i < len(list); i++ {
if !reflect.DeepEqual(list[i], otherList[i]) {
return false
}
}
return true
}
// Clear removes all the elements from this list.
func (c *CopyOnWriteList[T]) Clear() {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
list = make([]T, 0)
c.setList(list)
}
// Merge a tow list to one, change the list
func (c *CopyOnWriteList[T]) Merge(other []T) {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
list = append(list, other...)
c.setList(list)
}
// ForEach performs the given action for each element of the Iterable until all elements have been processed
// or the action throws an exception.
func (c *CopyOnWriteList[T]) ForEach(f func(T)) {
list := c.getList()
for i := 0; i < len(list); i++ {
f(list[i])
}
}
// Sort sorts this list according to the order induced by the specified Comparator.
func (c *CopyOnWriteList[T]) Sort(compare func(o1 T, o2 T) bool) {
lock := c.lock
lock.Lock()
list := c.getList()
sort.Slice(list, func(i, j int) bool {
return compare(list[i], list[j])
})
c.setList(list)
}
func (c *CopyOnWriteList[T]) SubList(start int, end int) (newList []T) {
lock := c.lock
lock.Lock()
list := c.getList()
length := len(list)
defer lock.Unlock()
if start < 0 || end > length || start > end {
return []T{}
}
newList = make([]T, end-start)
copy(newList, list[start:end])
c.setList(newList)
return
}
-235
View File
@@ -1,235 +0,0 @@
package datastructure
import (
"github.com/duke-git/lancet/v2/internal"
"testing"
)
func TestCopyOnWriteList_ValueOf(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_IndexOf")
of, ok := list.ValueOf(3)
assert.Equal(4, *of)
assert.Equal(true, ok)
_, ok = list.ValueOf(6)
assert.Equal(false, ok)
}
func TestCopyOnWriteList_Contain(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_Contains")
assert.Equal(true, list.Contain(3))
}
func TestCopyOnWriteList_IsEmpty(t *testing.T) {
list := NewCopyOnWriteList([]int{})
assert := internal.NewAssert(t, "CopyOnWriteList_IsEmpty")
assert.Equal(true, list.IsEmpty())
}
func TestCopyOnWriteList_Size(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_size")
assert.Equal(5, list.Size())
}
func TestCopyOnWriteList_GetList(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_GetList")
assert.Equal([]int{1, 2, 3, 4, 5}, list.getList())
}
func TestCopyOnWriteList_Get(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_Get")
i := list.Get(2)
assert.Equal(3, *i)
}
func TestCopyOnWriteList_Set(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_Set")
list.Set(2, 6)
assert.Equal(6, list.getList()[2])
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.Set(0, 6)
assert.Equal(6, list.getList()[0])
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.Set(0, 1)
assert.Equal(1, list.getList()[0])
}
func TestCopyOnWriteList_Add(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_Add")
list.Add(6)
assert.Equal([]int{1, 2, 3, 4, 5, 6}, list.getList())
}
func TestCopyOnWriteList_AddAll(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_AddAll")
list.AddAll([]int{6, 7, 8})
assert.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8}, list.getList())
}
func TestCopyOnWriteList_AddByIndex(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_AddByIndex")
list.AddByIndex(2, 6)
assert.Equal([]int{1, 2, 6, 3, 4, 5}, list.getList())
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.AddByIndex(0, 6)
assert.Equal([]int{6, 1, 2, 3, 4, 5}, list.getList())
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.AddByIndex(5, 6)
assert.Equal([]int{1, 2, 3, 4, 5, 6}, list.getList())
}
func TestCopyOnWriteList_DeleteAt2(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_RemoveByIndex")
list.DeleteAt(2)
assert.Equal([]int{1, 2, 4, 5}, list.getList())
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.DeleteAt(4)
assert.Equal([]int{1, 2, 3, 4}, list.getList())
}
func TestCopyOnWriteList_RemoveByValue(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_RemoveByValue")
list.DeleteBy(3)
assert.Equal([]int{1, 2, 4, 5}, list.getList())
}
func TestCopyOnWriteList_DeleteRange(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_RemoveRange")
list.DeleteRange(1, 3)
assert.Equal([]int{1, 4, 5}, list.getList())
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.DeleteRange(0, 5)
assert.Equal([]int{}, list.getList())
}
func TestCopyOnWriteList_LastIndexOf(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3})
assert := internal.NewAssert(t, "CopyOnWriteList_LastIndexOf")
assert.Equal(5, list.LastIndexOf(3))
}
func TestCopyOnWriteList_DeleteAt(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3})
assert := internal.NewAssert(t, "CopyOnWriteList_DeleteAt")
list.DeleteAt(2)
assert.Equal([]int{1, 2, 4, 5, 3}, list.getList())
}
func TestCopyOnWriteList_DeleteBy(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3})
assert := internal.NewAssert(t, "CopyOnWriteList_DeleteBy")
list.DeleteBy(3)
assert.Equal([]int{1, 2, 4, 5, 3}, list.getList())
}
func TestCopyOnWriteList_DeleteIf(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
assert := internal.NewAssert(t, "CopyOnWriteList_DeleteIf")
list.DeleteIf(func(i int) bool {
return i%2 == 0
})
assert.Equal([]int{1, 3, 5, 3}, list.getList())
}
func TestCopyOnWriteList_Equal(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
assert := internal.NewAssert(t, "CopyOnWriteList_Equal")
assert.Equal(true, list.Equal(&[]int{1, 2, 3, 4, 5, 3, 6}))
}
func TestCopyOnWriteList_ForEach(t *testing.T) {
testList := make([]int, 0)
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
assert := internal.NewAssert(t, "CopyOnWriteList_ForEach")
list.ForEach(func(i int) {
testList = append(testList, i)
})
assert.Equal([]int{1, 2, 3, 4, 5, 3, 6}, testList)
list.ForEach(func(i int) {
list.Add(i)
})
assert.Equal([]int{1, 2, 3, 4, 5, 3, 6, 1, 2, 3, 4, 5, 3, 6}, list.getList())
}
func TestCopyOnWriteList_Clear(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
assert := internal.NewAssert(t, "CopyOnWriteList_Clear")
list.Clear()
assert.Equal([]int{}, list.getList())
}
func TestCopyOnWriteList_Merge(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9})
assert := internal.NewAssert(t, "CopyOnWriteList_Merge")
list.Merge([]int{2, 4, 6, 8, 10})
assert.Equal([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10}, list.getList())
}
func TestCopyOnWriteList_Sort(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
assert := internal.NewAssert(t, "CopyOnWriteList_Sort")
list.Sort(func(i, j int) bool {
return i < j
})
assert.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, list.getList())
}
func TestCopyOnWriteList_IndexOf(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
assert := internal.NewAssert(t, "CopyOnWriteList_IndexOf")
assert.Equal(0, list.IndexOf(1))
assert.Equal(9, list.IndexOf(10))
assert.Equal(-1, list.IndexOf(11))
}
func TestCopyOnWriteList_SubList(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
assert := internal.NewAssert(t, "CopyOnWriteList_SubList")
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
subList := list.SubList(1, 3)
assert.Equal([]int{3, 5}, subList)
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
subList = list.SubList(1, 1)
assert.Equal([]int{}, subList)
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
assert.Equal(10, list.Size())
subList = list.SubList(1, 10)
assert.Equal([]int{3, 5, 7, 9, 2, 4, 6, 8, 10}, subList)
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
subList = list.SubList(11, 1)
assert.Equal([]int{}, subList)
}
-418
View File
@@ -1,418 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. list is a linear table, implemented with slice.
package datastructure
import (
"reflect"
"github.com/duke-git/lancet/v2/iterator"
)
// List is a linear table, implemented with slice.
type List[T any] struct {
data []T
}
// NewList return a pointer of List.
func NewList[T any](data []T) *List[T] {
return &List[T]{data: data}
}
// Data return list data.
func (l *List[T]) Data() []T {
return l.data
}
// ValueOf return the value pointer at index of list data.
func (l *List[T]) ValueOf(index int) (*T, bool) {
if index < 0 || index >= len(l.data) {
return nil, false
}
return &l.data[index], true
}
// IndexOf returns the index of value. if not found return -1.
func (l *List[T]) IndexOf(value T) int {
index := -1
data := l.data
for i, v := range data {
if reflect.DeepEqual(v, value) {
index = i
break
}
}
return index
}
// LastIndexOf returns the index of the last occurrence of the value in this list.
// if not found return -1.
func (l *List[T]) LastIndexOf(value T) int {
index := -1
data := l.data
for i := len(data) - 1; i >= 0; i-- {
if reflect.DeepEqual(data[i], value) {
index = i
break
}
}
return index
}
// IndexOfFunc returns the first index satisfying f(v)
// if not found return -1.
func (l *List[T]) IndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
for i, v := range data {
if f(v) {
index = i
break
}
}
return index
}
// LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i])
// if not found return -1.
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
for i := len(data) - 1; i >= 0; i-- {
if f(data[i]) {
index = i
break
}
}
return index
}
// Contain checks if the value in the list or not.
func (l *List[T]) Contain(value T) bool {
data := l.data
for _, v := range data {
if reflect.DeepEqual(v, value) {
return true
}
}
return false
}
// Push append value to the list data.
func (l *List[T]) Push(value T) {
l.data = append(l.data, value)
}
// InsertAtFirst insert value into list at first index.
func (l *List[T]) InsertAtFirst(value T) {
l.InsertAt(0, value)
}
// InsertAtLast insert value into list at last index.
func (l *List[T]) InsertAtLast(value T) {
l.InsertAt(len(l.data), value)
}
// InsertAt insert value into list at index.
func (l *List[T]) InsertAt(index int, value T) {
data := l.data
size := len(data)
if index < 0 || index > size {
return
}
l.data = append(data[:index], append([]T{value}, data[index:]...)...)
}
// PopFirst delete the first value of list and return it.
func (l *List[T]) PopFirst() (*T, bool) {
if len(l.data) == 0 {
return nil, false
}
v := l.data[0]
l.DeleteAt(0)
return &v, true
}
// PopLast delete the last value of list and return it.
func (l *List[T]) PopLast() (*T, bool) {
size := len(l.data)
if size == 0 {
return nil, false
}
v := l.data[size-1]
l.DeleteAt(size - 1)
return &v, true
}
// DeleteAt delete the value of list at index.
func (l *List[T]) DeleteAt(index int) {
data := l.data
size := len(data)
if index < 0 || index > size-1 {
return
}
if index == size-1 {
data = data[:index]
} else {
data = append(data[:index], data[index+1:]...)
}
l.data = data
}
// DeleteIf delete all satisfying f(data[i]), returns count of removed elements
func (l *List[T]) DeleteIf(f func(T) bool) int {
data := l.data
size := len(data)
var c int
for index := 0; index < len(data); index++ {
if !f(data[index]) {
continue
}
if index == size-1 {
data = data[:index]
} else {
data = append(data[:index], data[index+1:]...)
index--
}
c++
}
if c > 0 {
l.data = data
}
return c
}
// UpdateAt update value of list at index, index shoud between 0 and list size -1
func (l *List[T]) UpdateAt(index int, value T) {
data := l.data
size := len(data)
if index < 0 || index >= size {
return
}
l.data = append(data[:index], append([]T{value}, data[index+1:]...)...)
}
// Equal compare list to other list, use reflect.DeepEqual.
func (l *List[T]) Equal(other *List[T]) bool {
if len(l.data) != len(other.data) {
return false
}
for i := 0; i < len(l.data); i++ {
if !reflect.DeepEqual(l.data[i], other.data[i]) {
return false
}
}
return true
}
// IsEmpty check if the list is empty or not.
func (l *List[T]) IsEmpty() bool {
return len(l.data) == 0
}
// Clear the data of list.
func (l *List[T]) Clear() {
l.data = make([]T, 0)
}
// Clone return a copy of list.
func (l *List[T]) Clone() *List[T] {
cl := NewList(make([]T, len(l.data)))
copy(cl.data, l.data)
return cl
}
// Merge two list, return new list, don't change original list.
func (l *List[T]) Merge(other *List[T]) *List[T] {
l1, l2 := len(l.data), len(other.data)
ml := NewList(make([]T, l1+l2))
data := append([]T{}, append(l.data, other.data...)...)
ml.data = data
return ml
}
// Size return number of list data items.
func (l *List[T]) Size() int {
return len(l.data)
}
// Cap return cap of the inner data.
func (l *List[T]) Cap() int {
return cap(l.data)
}
// Swap the value of index i and j in list.
func (l *List[T]) Swap(i, j int) {
size := len(l.data)
if i < 0 || i >= size || j < 0 || j >= size {
return
}
l.data[i], l.data[j] = l.data[j], l.data[i]
}
// Reverse the item order of list.
func (l *List[T]) Reverse() {
for i, j := 0, len(l.data)-1; i < j; i, j = i+1, j-1 {
l.data[i], l.data[j] = l.data[j], l.data[i]
}
}
// Unique delete duplicate items in list.
func (l *List[T]) Unique() {
data := l.data
size := len(data)
uniqueData := make([]T, 0)
for i := 0; i < size; i++ {
value := data[i]
skip := true
for _, v := range uniqueData {
if reflect.DeepEqual(value, v) {
skip = false
break
}
}
if skip {
uniqueData = append(uniqueData, value)
}
}
l.data = uniqueData
}
// Union creates a new list contain all element in list l and other, delete duplicate element.
func (l *List[T]) Union(other *List[T]) *List[T] {
result := NewList([]T{})
result.data = append(result.data, l.data...)
result.data = append(result.data, other.data...)
result.Unique()
return result
}
// Intersection creates a new list whose element both be contained in list l and other.
func (l *List[T]) Intersection(other *List[T]) *List[T] {
result := NewList(make([]T, 0))
for _, v := range l.data {
if other.Contain(v) {
result.data = append(result.data, v)
}
}
return result
}
// Difference returns the difference between two collections.
// return a list whose element in the original list, not in the given list.
func (l *List[T]) Difference(other *List[T]) *List[T] {
result := NewList(make([]T, 0))
intersectList := l.Intersection(other)
for _, v := range l.data {
if !intersectList.Contain(v) {
result.data = append(result.data, v)
}
}
return result
}
// SymmetricDifference oppoiste operation of intersection function.
func (l *List[T]) SymmetricDifference(other *List[T]) *List[T] {
result := NewList(make([]T, 0))
intersectList := l.Intersection(other)
for _, v := range l.data {
if !intersectList.Contain(v) {
result.data = append(result.data, v)
}
}
for _, v := range other.data {
if !intersectList.Contain(v) {
result.data = append(result.data, v)
}
}
return result
}
// SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T] {
data := l.data[fromIndex:toIndex]
subList := make([]T, len(data))
copy(subList, data)
return NewList(subList)
}
// ForEach performs the given action for each element of the list.
func (l *List[T]) ForEach(consumer func(T)) {
for _, it := range l.data {
consumer(it)
}
}
// RetainAll retains only the elements in this list that are contained in the given list.
func (l *List[T]) RetainAll(list *List[T]) bool {
return l.batchRemove(list, true)
}
// DeleteAll removes from this list all of its elements that are contained in the given list.
func (l *List[T]) DeleteAll(list *List[T]) bool {
return l.batchRemove(list, false)
}
func (l *List[T]) batchRemove(list *List[T], complement bool) bool {
var (
w = 0
data = l.data
size = len(data)
)
for i := 0; i < size; i++ {
if list.Contain(data[i]) == complement {
data[w] = data[i]
w++
}
}
if w != size {
l.data = data[:w]
return true
}
return false
}
// Iterator returns an iterator over the elements in this list in proper sequence.
func (l *List[T]) Iterator() iterator.Iterator[T] {
return iterator.FromSlice(l.data)
}
// ListToMap convert a list to a map based on iteratee function.
func ListToMap[T any, K comparable, V any](list *List[T], iteratee func(T) (K, V)) map[K]V {
result := make(map[K]V, list.Size())
for _, item := range list.data {
k, v := iteratee(item)
result[k] = v
}
return result
}
-531
View File
@@ -1,531 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestListData(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestListData")
list := NewList([]int{1, 2, 3})
assert.Equal([]int{1, 2, 3}, list.Data())
}
func TestValueOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestValueOf")
list := NewList([]int{1, 2, 3})
v, ok := list.ValueOf(0)
assert.Equal(1, *v)
assert.Equal(true, ok)
_, ok = list.ValueOf(3)
assert.Equal(false, ok)
}
func TestIndexOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3})
i := list.IndexOf(1)
assert.Equal(0, i)
i = list.IndexOf(4)
assert.Equal(-1, i)
}
func TestIndexOfFunc(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3})
i := list.IndexOfFunc(func(a int) bool { return a == 1 })
assert.Equal(0, i)
i = list.IndexOfFunc(func(a int) bool { return a == 4 })
assert.Equal(-1, i)
}
func TestLastIndexOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
i := list.LastIndexOf(3)
assert.Equal(5, i)
i = list.LastIndexOf(10)
assert.Equal(-1, i)
i = list.LastIndexOf(4)
assert.Equal(6, i)
i = list.LastIndexOf(1)
assert.Equal(0, i)
}
func TestLastIndexOfFunc(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
i := list.LastIndexOfFunc(func(a int) bool { return a == 3 })
assert.Equal(5, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 10 })
assert.Equal(-1, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 4 })
assert.Equal(6, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 1 })
assert.Equal(0, i)
}
func TestContain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestContain")
list := NewList([]int{1, 2, 3})
assert.Equal(true, list.Contain(1))
assert.Equal(false, list.Contain(0))
}
func TestPush(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPush")
list := NewList([]int{1, 2, 3})
list.Push(4)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
}
func TestInsertAtFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAtFirst")
list := NewList([]int{1, 2, 3})
list.InsertAtFirst(0)
assert.Equal([]int{0, 1, 2, 3}, list.Data())
}
func TestInsertAtLast(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAtLast")
list := NewList([]int{1, 2, 3})
list.InsertAtLast(4)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
}
func TestInsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAt")
list := NewList([]int{1, 2, 3})
list.InsertAt(-1, 0)
assert.Equal([]int{1, 2, 3}, list.Data())
list.InsertAt(4, 0)
assert.Equal([]int{1, 2, 3}, list.Data())
list.InsertAt(0, 0)
assert.Equal([]int{0, 1, 2, 3}, list.Data())
list.InsertAt(4, 4)
assert.Equal([]int{0, 1, 2, 3, 4}, list.Data())
}
func TestPopFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPopFirst")
list := NewList([]int{1, 2, 3})
v, ok := list.PopFirst()
assert.Equal(1, *v)
assert.Equal(true, ok)
assert.Equal([]int{2, 3}, list.Data())
list2 := NewList([]int{})
_, ok = list2.PopFirst()
assert.Equal(false, ok)
assert.Equal([]int{}, list2.Data())
}
func TestPopLast(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPopLast")
list := NewList([]int{1, 2, 3})
v, ok := list.PopLast()
assert.Equal(3, *v)
assert.Equal(true, ok)
assert.Equal([]int{1, 2}, list.Data())
list2 := NewList([]int{})
_, ok = list2.PopLast()
assert.Equal(false, ok)
assert.Equal([]int{}, list2.Data())
}
func TestDeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteAt")
list := NewList([]int{1, 2, 3, 4})
list.DeleteAt(-1)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
list.DeleteAt(4)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
list.DeleteAt(0)
assert.Equal([]int{2, 3, 4}, list.Data())
list.DeleteAt(2)
assert.Equal([]int{2, 3}, list.Data())
}
func TestUpdateAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUpdateAt")
list := NewList([]int{1, 2, 3, 4})
list.UpdateAt(-1, 0)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
list.UpdateAt(4, 0)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
list.UpdateAt(0, 5)
assert.Equal([]int{5, 2, 3, 4}, list.Data())
list.UpdateAt(3, 1)
assert.Equal([]int{5, 2, 3, 1}, list.Data())
}
func TestEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqual")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
list3 := NewList([]int{1, 2, 3})
assert.Equal(true, list1.Equal(list2))
assert.Equal(false, list1.Equal(list3))
}
func TestIsEmpty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsEmpty")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{})
assert.Equal(false, list1.IsEmpty())
assert.Equal(true, list2.IsEmpty())
}
func TestIsClear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsClear")
list1 := NewList([]int{1, 2, 3, 4})
list1.Clear()
empty := NewList([]int{})
assert.Equal(empty, list1)
}
func TestClone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestClone")
list1 := NewList([]int{1, 2, 3, 4})
list2 := list1.Clone()
assert.Equal(true, list1.Equal(list2))
}
func TestMerge(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMerge")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{4, 5, 6})
expected := NewList([]int{1, 2, 3, 4, 4, 5, 6})
list3 := list1.Merge(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSize(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSize")
list := NewList([]int{1, 2, 3, 4})
empty := NewList([]int{})
assert.Equal(4, list.Size())
assert.Equal(0, empty.Size())
}
func TestCap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCap")
data := make([]int, 0, 100)
list := NewList(data)
assert.Equal(100, list.Cap())
data = make([]int, 0)
list = NewList(data)
assert.Equal(0, list.Cap())
}
func TestSwap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSwap")
list := NewList([]int{1, 2, 3, 4})
expected := NewList([]int{4, 2, 3, 1})
list.Swap(0, 3)
assert.Equal(true, expected.Equal(list))
}
func TestReverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReverse")
list := NewList([]int{1, 2, 3, 4})
expected := NewList([]int{4, 3, 2, 1})
list.Reverse()
assert.Equal(true, expected.Equal(list))
}
func TestUnique(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnique")
list := NewList([]int{1, 2, 2, 3, 4})
expected := NewList([]int{1, 2, 3, 4})
list.Unique()
assert.Equal(true, expected.Equal(list))
}
func TestUnion(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnion")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{4, 5, 6})
expected := NewList([]int{1, 2, 3, 4, 5, 6})
list3 := list1.Union(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestIntersection(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIntersection")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{4, 5, 6})
expected := NewList([]int{4})
list3 := list1.Intersection(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDifference")
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
expected := NewList([]int{3})
list3 := list1.Difference(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSymmetricDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSymmetricDifference")
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
expected := NewList([]int{3, 4})
list3 := list1.SymmetricDifference(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSubSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSubSlice")
list := NewList([]int{1, 2, 3, 4, 5, 8})
subList := list.SubList(2, 5)
assert.Equal([]int{3, 4, 5}, subList.Data())
}
func BenchmarkSubSlice(b *testing.B) {
list := NewList([]int{1, 2, 3, 4, 5, 8})
for n := 0; n < b.N; n++ {
list.SubList(2, 5)
}
}
func TestDeleteIf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteIf")
list := NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
count := list.DeleteIf(func(a int) bool { return a == 1 })
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal(12, count)
count = list.DeleteIf(func(a int) bool { return a == 5 })
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal(0, count)
}
func TestForEach(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestForEach")
list := NewList([]int{1, 2, 3, 4})
rs := make([]int, 0)
list.ForEach(func(i int) {
rs = append(rs, i)
})
assert.Equal([]int{1, 2, 3, 4}, rs)
}
func TestRetainAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRetainAll")
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
retain := NewList([]int{1, 2})
retain1 := NewList([]int{2, 3})
retain2 := NewList([]int{1, 2, 5})
list.RetainAll(retain)
list1.RetainAll(retain1)
list2.RetainAll(retain2)
assert.Equal([]int{1, 2}, list.Data())
assert.Equal([]int{2, 3}, list1.Data())
assert.Equal([]int{1, 2}, list2.Data())
}
func TestDeleteAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteAll")
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
del := NewList([]int{1})
del1 := NewList([]int{2, 3})
del2 := NewList([]int{1, 2, 5})
list.DeleteAll(del)
list1.DeleteAll(del1)
list2.DeleteAll(del2)
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal([]int{1, 4}, list1.Data())
assert.Equal([]int{3, 4}, list2.Data())
}
func TestIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIterator")
list := NewList([]int{1, 2, 3, 4})
iterator := list.Iterator()
rs := make([]int, 0)
for iterator.HasNext() {
item, _ := iterator.Next()
rs = append(rs, item)
}
assert.Equal([]int{1, 2, 3, 4}, rs)
}
func TestListToMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "ListToMap")
list := NewList([]int{1, 2, 3, 4})
result := ListToMap(list, func(n int) (int, bool) {
return n, n > 1
})
expected := map[int]bool{1: false, 2: true, 3: true, 4: true}
assert.Equal(expected, result)
}
-51
View File
@@ -1,51 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure.
package datastructure
// LinkNode is a linkedlist node, which have a Value and Pre points to previous node, Next points to a next node of the link.
type LinkNode[T any] struct {
Value T
Pre *LinkNode[T]
Next *LinkNode[T]
}
// NewLinkNode return a LinkNode pointer
func NewLinkNode[T any](value T) *LinkNode[T] {
return &LinkNode[T]{value, nil, nil}
}
// StackNode is a node in stack, which have a Value and Next pointer points to next node in the stack.
type StackNode[T any] struct {
Value T
Next *StackNode[T]
}
// NewStackNode return a StackNode pointer
func NewStackNode[T any](value T) *StackNode[T] {
return &StackNode[T]{value, nil}
}
// QueueNode is a node in a queue, which have a Value and Next pointer points to next node in the queue.
type QueueNode[T any] struct {
Value T
Next *QueueNode[T]
}
// NewQueueNode return a QueueNode pointer
func NewQueueNode[T any](value T) *QueueNode[T] {
return &QueueNode[T]{value, nil}
}
// TreeNode is node of tree
type TreeNode[T any] struct {
Value T
Left *TreeNode[T]
Right *TreeNode[T]
}
// NewTreeNode return a TreeNode pointer
func NewTreeNode[T any](val T) *TreeNode[T] {
return &TreeNode[T]{val, nil, nil}
}
-124
View File
@@ -1,124 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure.
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
package datastructure
import (
"fmt"
"reflect"
)
// ArrayQueue implements queue with slice
type ArrayQueue[T any] struct {
items []T
head int
tail int
capacity int
size int
}
func NewArrayQueue[T any](capacity int) *ArrayQueue[T] {
return &ArrayQueue[T]{
items: make([]T, 0, capacity),
head: 0,
tail: 0,
capacity: capacity,
size: 0,
}
}
// Data return slice of queue data
func (q *ArrayQueue[T]) Data() []T {
items := []T{}
for i := q.head; i < q.tail; i++ {
items = append(items, q.items[i])
}
return items
}
// Size return number of elements in queue
func (q *ArrayQueue[T]) Size() int {
return q.size
}
// IsEmpty checks if queue is empty or not
func (q *ArrayQueue[T]) IsEmpty() bool {
return q.size == 0
}
// IsFull checks if queue is full or not
func (q *ArrayQueue[T]) IsFull() bool {
return q.size == q.capacity
}
// Front return front value of queue
func (q *ArrayQueue[T]) Front() T {
return q.items[0]
}
// Back return back value of queue
func (q *ArrayQueue[T]) Back() T {
return q.items[q.size-1]
}
// EnQueue put element into queue
func (q *ArrayQueue[T]) Enqueue(item T) bool {
if q.head == 0 && q.tail == q.capacity {
return false
} else if q.head != 0 && q.tail == q.capacity {
for i := q.head; i < q.tail; i++ {
q.items[i-q.head] = q.items[i]
}
q.tail = q.tail - q.head
q.head = 0
}
q.items = append(q.items, item)
q.tail++
q.size++
return true
}
// DeQueue remove head element of queue and return it, if queue is empty, return nil and error
func (q *ArrayQueue[T]) Dequeue() (T, bool) {
var item T
if q.head == q.tail {
return item, false
}
item = q.items[q.head]
q.head++
q.size--
return item, true
}
// Clear the queue data
func (q *ArrayQueue[T]) Clear() {
capacity := q.capacity
q.items = make([]T, 0, capacity)
q.head = 0
q.tail = 0
q.size = 0
q.capacity = capacity
}
// Contain checks if the value is in queue or not
func (q *ArrayQueue[T]) Contain(value T) bool {
for _, v := range q.items {
if reflect.DeepEqual(v, value) {
return true
}
}
return false
}
// Print queue data
func (q *ArrayQueue[T]) Print() {
info := "["
for i := q.head; i < q.tail; i++ {
info += fmt.Sprintf("%+v, ", q.items[i])
}
info += "]"
fmt.Println(info)
}
-119
View File
@@ -1,119 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestArrayQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Enqueue")
queue := NewArrayQueue[int](5)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
data := queue.Data()
size := queue.Size()
assert.Equal([]int{1, 2, 3}, data)
assert.Equal(3, size)
}
func TestArrayQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Dequeue")
queue := NewArrayQueue[int](4)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
val, ok := queue.Dequeue()
assert.Equal(true, ok)
assert.Equal(1, val)
assert.Equal([]int{2, 3}, queue.Data())
}
func TestArrayQueue_Front(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Front")
queue := NewArrayQueue[int](4)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
val := queue.Front()
assert.Equal(1, val)
assert.Equal([]int{1, 2, 3}, queue.Data())
}
func TestArrayQueue_Back(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Back")
queue := NewArrayQueue[int](4)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
val := queue.Back()
assert.Equal(3, val)
assert.Equal([]int{1, 2, 3}, queue.Data())
}
func TestArrayQueue_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Contain")
queue := NewArrayQueue[int](4)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
assert.Equal(true, queue.Contain(1))
assert.Equal(false, queue.Contain(4))
}
func TestArrayQueue_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Clear")
queue := NewArrayQueue[int](4)
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Size())
queue.Enqueue(1)
assert.Equal(false, queue.IsEmpty())
assert.Equal(1, queue.Size())
queue.Clear()
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Size())
}
func TestArrayQueue_IsFull(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_IsFull")
queue := NewArrayQueue[int](3)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
assert.Equal(true, queue.IsFull())
}
-123
View File
@@ -1,123 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure.
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
package datastructure
import (
"errors"
"fmt"
"reflect"
)
// CircularQueue implements circular queue with slice,
// last index of CircularQueue don't contain value, so acturl capacity is capacity - 1
type CircularQueue[T any] struct {
data []T
front int
rear int
capacity int
}
// NewCircularQueue return a empty CircularQueue pointer
func NewCircularQueue[T any](capacity int) *CircularQueue[T] {
data := make([]T, capacity)
return &CircularQueue[T]{data: data, front: 0, rear: 0, capacity: capacity}
}
// Data return slice of queue data
func (q *CircularQueue[T]) Data() []T {
data := []T{}
front := q.front
rear := q.rear
if front <= rear {
return q.data[front:rear]
}
data = append(data, q.data[front:]...)
data = append(data, q.data[0:rear]...)
return data
}
// Size return number of elements in circular queue
func (q *CircularQueue[T]) Size() int {
if q.capacity == 0 {
return 0
}
return (q.rear - q.front + q.capacity) % q.capacity
}
// IsEmpty checks if queue is empty or not
func (q *CircularQueue[T]) IsEmpty() bool {
return q.front == q.rear
}
// IsFull checks if queue is full or not
func (q *CircularQueue[T]) IsFull() bool {
return (q.rear+1)%q.capacity == q.front
}
// Front return front value of queue
func (q *CircularQueue[T]) Front() T {
return q.data[q.front]
}
// Back return back value of queue
func (q *CircularQueue[T]) Back() T {
if q.rear-1 >= 0 {
return q.data[q.rear-1]
}
return q.data[q.capacity-1]
}
// Enqueue put element into queue
func (q *CircularQueue[T]) Enqueue(value T) error {
if q.IsFull() {
return errors.New("queue is full!")
}
q.data[q.rear] = value
q.rear = (q.rear + 1) % q.capacity
return nil
}
// Dequeue remove head element of queue and return it, if queue is empty, return nil and error
func (q *CircularQueue[T]) Dequeue() (*T, error) {
if q.IsEmpty() {
return nil, errors.New("queue is empty")
}
headItem := q.data[q.front]
var t T
q.data[q.front] = t
q.front = (q.front + 1) % q.capacity
return &headItem, nil
}
// Clear the queue data
func (q *CircularQueue[T]) Clear() {
q.data = []T{}
q.front = 0
q.rear = 0
q.capacity = 0
}
// Contain checks if the value is in queue or not
func (q *CircularQueue[T]) Contain(value T) bool {
for _, v := range q.data {
if reflect.DeepEqual(v, value) {
return true
}
}
return false
}
// Print queue data
func (q *CircularQueue[T]) Print() {
fmt.Printf("%+v\n", q)
}
-159
View File
@@ -1,159 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestCircularQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Enqueue")
queue := NewCircularQueue[int](6)
err := queue.Enqueue(1)
assert.IsNil(err)
err = queue.Enqueue(2)
assert.IsNil(err)
err = queue.Enqueue(3)
assert.IsNil(err)
err = queue.Enqueue(4)
assert.IsNil(err)
err = queue.Enqueue(5)
assert.IsNil(err)
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
assert.Equal(5, queue.Size())
err = queue.Enqueue(6)
assert.IsNotNil(err)
}
func TestCircularQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
queue := NewCircularQueue[int](4)
assert.Equal(true, queue.IsEmpty())
err := queue.Enqueue(1)
assert.IsNil(err)
err = queue.Enqueue(2)
assert.IsNil(err)
err = queue.Enqueue(3)
assert.IsNil(err)
val, err := queue.Dequeue()
assert.IsNil(err)
assert.Equal(1, *val)
assert.Equal(false, queue.IsFull())
val, _ = queue.Dequeue()
assert.Equal(2, *val)
assert.Equal(false, queue.IsFull())
}
func TestCircularQueue_Front(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Front")
queue := NewCircularQueue[int](6)
err := queue.Enqueue(1)
assert.IsNil(err)
err = queue.Enqueue(2)
assert.IsNil(err)
err = queue.Enqueue(3)
assert.IsNil(err)
val := queue.Front()
assert.IsNil(err)
assert.Equal(1, val)
assert.Equal(3, queue.Size())
}
func TestCircularQueue_Back(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Back")
queue := NewCircularQueue[int](3)
assert.Equal(true, queue.IsEmpty())
err := queue.Enqueue(1)
assert.IsNil(err)
err = queue.Enqueue(2)
assert.IsNil(err)
assert.Equal(2, queue.Back())
val, _ := queue.Dequeue()
assert.Equal(1, *val)
err = queue.Enqueue(3)
assert.IsNil(err)
assert.Equal(3, queue.Back())
}
func TestCircularQueue_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
queue := NewCircularQueue[int](2)
err := queue.Enqueue(1)
assert.IsNil(err)
assert.Equal(true, queue.Contain(1))
assert.Equal(false, queue.Contain(2))
}
func TestCircularQueue_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Clear")
queue := NewCircularQueue[int](3)
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Size())
err := queue.Enqueue(1)
assert.IsNil(err)
assert.Equal(false, queue.IsEmpty())
assert.Equal(1, queue.Size())
queue.Clear()
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Size())
}
func TestCircularQueue_Data(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Data")
queue := NewCircularQueue[int](3)
err := queue.Enqueue(1)
assert.IsNil(err)
err = queue.Enqueue(2)
assert.IsNil(err)
assert.Equal([]int{1, 2}, queue.Data())
}
-122
View File
@@ -1,122 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure.
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
package datastructure
import (
"errors"
"fmt"
"reflect"
"github.com/duke-git/lancet/v2/datastructure"
)
// LinkedQueue implements queue with link list
type LinkedQueue[T any] struct {
head *datastructure.QueueNode[T]
tail *datastructure.QueueNode[T]
length int
}
// NewLinkedQueue return a empty LinkedQueue pointer
func NewLinkedQueue[T any]() *LinkedQueue[T] {
return &LinkedQueue[T]{head: nil, tail: nil, length: 0}
}
// Data return slice of queue data
func (q *LinkedQueue[T]) Data() []T {
res := []T{}
current := q.head
for current != nil {
res = append(res, current.Value)
current = current.Next
}
return res
}
// Size return length of queue data
func (q *LinkedQueue[T]) Size() int {
return q.length
}
// IsEmpty checks if queue is empty or not
func (q *LinkedQueue[T]) IsEmpty() bool {
return q.length == 0
}
// Enqueue put element into queue
func (q *LinkedQueue[T]) Enqueue(value T) {
newNode := datastructure.NewQueueNode(value)
if q.IsEmpty() {
q.head = newNode
q.tail = newNode
} else {
q.tail.Next = newNode
q.tail = newNode
}
q.length++
}
// Dequeue delete head element of queue then return it, if queue is empty, return nil and error
func (q *LinkedQueue[T]) Dequeue() (*T, error) {
if q.IsEmpty() {
return nil, errors.New("queue is empty")
}
head := q.head
q.head = q.head.Next
q.length--
return &head.Value, nil
}
// Front return front value of queue
func (q *LinkedQueue[T]) Front() (*T, error) {
if q.IsEmpty() {
return nil, errors.New("queue is empty")
}
return &q.head.Value, nil
}
// Back return back value of queue
func (q *LinkedQueue[T]) Back() (*T, error) {
if q.IsEmpty() {
return nil, errors.New("queue is empty")
}
return &q.tail.Value, nil
}
// Clear clear the queue data
func (q *LinkedQueue[T]) Clear() {
q.head = nil
q.tail = nil
q.length = 0
}
// Print all nodes info of queue link
func (q *LinkedQueue[T]) Print() {
current := q.head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
current = current.Next
}
info += " ]"
fmt.Println(info)
}
// Contain checks if the value is in queue or not
func (q *LinkedQueue[T]) Contain(value T) bool {
current := q.head
for current != nil {
if reflect.DeepEqual(current.Value, value) {
return true
}
current = current.Next
}
return false
}
-106
View File
@@ -1,106 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestLinkedQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Enqueue")
queue := NewLinkedQueue[int]()
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
assert.Equal([]int{1, 2, 3}, queue.Data())
assert.Equal(3, queue.Size())
}
func TestLinkedQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_DeQueue")
queue := NewLinkedQueue[int]()
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
val, _ := queue.Dequeue()
queue.Print()
assert.Equal([]int{2, 3}, queue.Data())
assert.Equal(1, *val)
}
func TestLinkedQueue_Front(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Front")
queue := NewLinkedQueue[int]()
_, err := queue.Front()
assert.IsNotNil(err)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
val, err := queue.Front()
assert.Equal(1, *val)
assert.IsNil(err)
}
func TestLinkedQueue_Back(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
queue := NewLinkedQueue[int]()
_, err := queue.Back()
assert.IsNotNil(err)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
val, err := queue.Back()
assert.Equal(3, *val)
assert.IsNil(err)
}
func TestLinkedQueue_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
queue := NewLinkedQueue[int]()
assert.Equal(true, queue.IsEmpty())
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
assert.Equal(false, queue.IsEmpty())
queue.Clear()
assert.Equal(true, queue.IsEmpty())
}
func TestLinkedQueue_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Contain")
queue := NewLinkedQueue[int]()
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
assert.Equal(true, queue.Contain(1))
assert.Equal(false, queue.Contain(4))
}
-118
View File
@@ -1,118 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure.
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
package datastructure
import (
"errors"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
// PriorityQueue is a priority queue implemented by binary heap tree
// type T should implements Compare function in lancetconstraints.Comparator interface.
type PriorityQueue[T any] struct {
items []T
size int
comparator lancetconstraints.Comparator
}
// NewPriorityQueue return a pointer of PriorityQueue
// param `comparator` is used to compare values in the queue
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T] {
return &PriorityQueue[T]{
items: make([]T, capacity+1),
size: 0,
comparator: comparator,
}
}
// IsEmpty checks if the queue is empty or not
func (q *PriorityQueue[T]) IsEmpty() bool {
return q.size == 0
}
// Size get number of items in the queue
func (q *PriorityQueue[T]) Size() int {
return q.size
}
// IsFull checks if the queue capacity is full or not
func (q *PriorityQueue[T]) IsFull() bool {
return q.size == len(q.items)-1
}
// Data return a slice of queue data
func (q *PriorityQueue[T]) Data() []T {
data := make([]T, q.size)
for i := 1; i < q.size+1; i++ {
data[i-1] = q.items[i]
}
return data
}
// Enqueue insert value into queue
func (q *PriorityQueue[T]) Enqueue(val T) error {
if q.IsFull() {
return errors.New("queue is already full.")
}
q.size++
q.items[q.size] = val
q.swim(q.size)
return nil
}
// Dequeue delete and return max value in queue
func (q *PriorityQueue[T]) Dequeue() (T, bool) {
var val T
if q.IsEmpty() {
return val, false
}
max := q.items[1]
q.swap(1, q.size)
q.size--
q.sink(1)
//set zero value for rest values of the queue
q.items[q.size+1] = val
return max, true
}
// swim when child's key is larger than parent's key, exchange them.
func (q *PriorityQueue[T]) swim(index int) {
for index > 1 && q.comparator.Compare(q.items[index/2], q.items[index]) < 0 {
q.swap(index, index/2)
index = index / 2
}
}
// sink when parent's key smaller than child's key, exchange parent's key with larger child's key.
func (q *PriorityQueue[T]) sink(index int) {
for 2*index <= q.size {
j := 2 * index
// get larger child node index
if j < q.size && q.comparator.Compare(q.items[j], q.items[j+1]) < 0 {
j++
}
// if parent larger than child, stop
if !(q.comparator.Compare(q.items[index], q.items[j]) < 0) {
break
}
q.swap(index, j)
index = j
}
}
// swap the two values at index i and j
func (q *PriorityQueue[T]) swap(i, j int) {
q.items[i], q.items[j] = q.items[j], q.items[i]
}
-74
View File
@@ -1,74 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func TestPriorityQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
comparator := &intComparator{}
pq := NewPriorityQueue[int](3, comparator)
assert.Equal(true, pq.IsEmpty())
assert.Equal(false, pq.IsFull())
err := pq.Enqueue(1)
assert.IsNil(err)
err = pq.Enqueue(2)
assert.IsNil(err)
err = pq.Enqueue(3)
assert.IsNil(err)
assert.Equal(true, pq.IsFull())
queueData := pq.Data()
assert.Equal([]int{3, 1, 2}, queueData)
}
func TestPriorityQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
comparator := &intComparator{}
pq := NewPriorityQueue[int](3, comparator)
_, ok := pq.Dequeue()
assert.Equal(false, ok)
err := pq.Enqueue(1)
assert.IsNil(err)
err = pq.Enqueue(2)
assert.IsNil(err)
err = pq.Enqueue(3)
assert.IsNil(err)
assert.Equal(3, pq.Size())
val, ok := pq.Dequeue()
assert.Equal(true, ok)
assert.Equal(3, val)
}
-199
View File
@@ -1,199 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Set is a data container, like slice, but element of set is not duplicate.
package datastructure
// Set is a data container, like slice, but element of set is not duplicate.
type Set[T comparable] map[T]struct{}
// NewSet return a instance of set
func NewSet[T comparable](items ...T) Set[T] {
set := make(Set[T])
set.Add(items...)
return set
}
// NewSetFromSlice create a set from slice
func NewSetFromSlice[T comparable](items []T) Set[T] {
set := make(Set[T])
for _, item := range items {
set.Add(item)
}
return set
}
// Add items to set
func (s Set[T]) Add(items ...T) {
for _, v := range items {
s[v] = struct{}{}
}
}
// AddIfNotExist checks if item exists in the set,
// it adds the item to set and returns true if it does not exist in the set,
// or else it does nothing and returns false.
func (s Set[T]) AddIfNotExist(item T) bool {
if !s.Contain(item) {
if _, ok := s[item]; !ok {
s[item] = struct{}{}
return true
}
}
return false
}
// AddIfNotExistBy checks if item exists in the set and pass the `checker` function
// it adds the item to set and returns true if it does not exists in the set and
// function `checker` returns true, or else it does nothing and returns false.
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool {
if !s.Contain(item) {
if checker(item) {
if _, ok := s[item]; !ok {
s[item] = struct{}{}
return true
}
}
}
return false
}
// Contain checks if set contains item or not
func (s Set[T]) Contain(item T) bool {
_, ok := s[item]
return ok
}
// ContainAll checks if set contains other set
func (s Set[T]) ContainAll(other Set[T]) bool {
for k := range other {
_, ok := s[k]
if !ok {
return false
}
}
return true
}
// Clone return a copy of set
func (s Set[T]) Clone() Set[T] {
set := NewSet[T]()
set.Add(s.Values()...)
return set
}
// Delete item of set
func (s Set[T]) Delete(items ...T) {
for _, v := range items {
delete(s, v)
}
}
// Equal checks if two set has same elements or not
func (s Set[T]) Equal(other Set[T]) bool {
if s.Size() != other.Size() {
return false
}
return s.ContainAll(other) && other.ContainAll(s)
}
// Iterate call function by every element of set
func (s Set[T]) Iterate(fn func(item T)) {
for v := range s {
fn(v)
}
}
// IsEmpty checks the set is empty or not
func (s Set[T]) IsEmpty() bool {
return len(s) == 0
}
// Size get the number of elements in set
func (s Set[T]) Size() int {
return len(s)
}
// Values return all values of set
func (s Set[T]) Values() []T {
result := make([]T, 0, len(s))
s.Iterate(func(value T) {
result = append(result, value)
})
return result
}
// Union creates a new set contain all element of set s and other
func (s Set[T]) Union(other Set[T]) Set[T] {
set := s.Clone()
set.Add(other.Values()...)
return set
}
// Intersection creates a new set whose element both be contained in set s and other
func (s Set[T]) Intersection(other Set[T]) Set[T] {
set := NewSet[T]()
s.Iterate(func(value T) {
if other.Contain(value) {
set.Add(value)
}
})
return set
}
// SymmetricDifference creates a new set whose element is in set1 or set2, but not in both sets
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T] {
set := NewSet[T]()
s.Iterate(func(value T) {
if !other.Contain(value) {
set.Add(value)
}
})
other.Iterate(func(value T) {
if !s.Contain(value) {
set.Add(value)
}
})
return set
}
// Minus creates an set of whose element in origin set but not in compared set
func (s Set[T]) Minus(comparedSet Set[T]) Set[T] {
set := NewSet[T]()
s.Iterate(func(value T) {
if !comparedSet.Contain(value) {
set.Add(value)
}
})
return set
}
// EachWithBreak iterates over elements of a set and invokes function for each element,
// when iteratee return false, will break the for each loop.
func (s Set[T]) EachWithBreak(iteratee func(item T) bool) {
for _, v := range s.Values() {
if !iteratee(v) {
break
}
}
}
// Pop delete the top element of set then return it, if set is empty, return nil-value of T and false.
func (s Set[T]) Pop() (v T, ok bool) {
if len(s) > 0 {
items := s.Values()
item := items[len(s)-1]
delete(s, item)
return item, true
}
return v, false
}
-262
View File
@@ -1,262 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestSet_NewSetFromSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_NewSetFromSlice")
s1 := NewSetFromSlice([]int{1, 2, 2, 3})
assert.Equal(3, s1.Size())
assert.Equal(true, s1.Contain(1))
assert.Equal(true, s1.Contain(2))
assert.Equal(true, s1.Contain(3))
s2 := NewSetFromSlice([]int{})
assert.Equal(0, s2.Size())
}
func TestSet_Add(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Add")
set := NewSet[int]()
set.Add(1, 2, 3)
cmpSet := NewSet(1, 2, 3)
assert.Equal(true, set.Equal(cmpSet))
}
func TestSet_AddIfNotExist(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_AddIfNotExist")
set := NewSet[int]()
set.Add(1, 2, 3)
assert.Equal(false, set.AddIfNotExist(1))
assert.Equal(true, set.AddIfNotExist(4))
assert.Equal(NewSet(1, 2, 3, 4), set)
}
func TestSet_AddIfNotExistBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_AddIfNotExistBy")
set := NewSet[int]()
set.Add(1, 2)
ok := set.AddIfNotExistBy(3, func(val int) bool {
return val%2 != 0
})
notOk := set.AddIfNotExistBy(4, func(val int) bool {
return val%2 != 0
})
assert.Equal(true, ok)
assert.Equal(false, notOk)
assert.Equal(true, set.Contain(3))
assert.Equal(false, set.Contain(4))
}
func TestSet_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Contain")
set := NewSet[int]()
set.Add(1, 2, 3)
assert.Equal(true, set.Contain(1))
assert.Equal(false, set.Contain(4))
}
func TestSet_ContainAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_ContainAll")
set1 := NewSet(1, 2, 3)
set2 := NewSet(1, 2)
set3 := NewSet(1, 2, 3, 4)
assert.Equal(true, set1.ContainAll(set2))
assert.Equal(false, set1.ContainAll(set3))
}
func TestSet_Clone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Clone")
set1 := NewSet(1, 2, 3)
set2 := set1.Clone()
assert.Equal(true, set1.Size() == set2.Size())
assert.Equal(true, set1.ContainAll(set2))
}
func TestSet_Delete(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Delete")
set := NewSet[int]()
set.Add(1, 2, 3)
set.Delete(3)
assert.Equal(true, set.Equal(NewSet(1, 2)))
}
func TestSet_Equal(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Equal")
set1 := NewSet(1, 2, 3)
set2 := NewSet(1, 2, 3)
set3 := NewSet(1, 2, 3, 4)
assert.Equal(true, set1.Equal(set2))
assert.Equal(false, set1.Equal(set3))
}
func TestSet_Iterate(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Iterate")
set := NewSet(1, 2, 3)
arr := []int{}
set.Iterate(func(value int) {
arr = append(arr, value)
})
assert.Equal(3, len(arr))
}
func TestSet_IsEmpty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_IsEmpty")
set := NewSet[int]()
assert.Equal(true, set.IsEmpty())
}
func TestSet_Size(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Size")
set := NewSet(1, 2, 3)
assert.Equal(3, set.Size())
}
func TestSet_Values(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Values")
set := NewSet(1, 2, 3)
values := set.Values()
assert.Equal(3, len(values))
}
func TestSet_Union(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Union")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
unionSet := set1.Union(set2)
assert.Equal(NewSet(1, 2, 3, 4, 5), unionSet)
}
func TestSet_Intersection(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Intersection")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
intersectionSet := set1.Intersection(set2)
assert.Equal(NewSet(2, 3), intersectionSet)
}
func TestSet_SymmetricDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_SymmetricDifference")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
assert.Equal(NewSet(1, 4, 5), set1.SymmetricDifference(set2))
}
func TestSet_Minus(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Minus")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
set3 := NewSet(2, 3)
assert.Equal(NewSet(1), set1.Minus(set2))
assert.Equal(NewSet(4, 5), set2.Minus(set3))
}
func TestEachWithBreak(t *testing.T) {
// s := NewSet(1, 2, 3, 4, 5)
// var sum int
// s.EachWithBreak(func(n int) bool {
// if n > 3 {
// return false
// }
// sum += n
// return true
// })
// assert := internal.NewAssert(t, "TestEachWithBreak")
// assert.Equal(6, sum)
}
// func TestPop(t *testing.T) {
// assert := internal.NewAssert(t, "TestPop")
// s := NewSet[int]()
// val, ok := s.Pop()
// assert.Equal(0, val)
// assert.Equal(false, ok)
// s.Add(1)
// s.Add(2)
// s.Add(3)
// // s = NewSet(1, 2, 3, 4, 5)
// val, ok = s.Pop()
// assert.Equal(3, val)
// assert.Equal(true, ok)
// }
-66
View File
@@ -1,66 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Stack structure contains ArrayStack and LinkedStack.
package datastructure
import "errors"
// ArrayStack implements stack with slice
type ArrayStack[T any] struct {
data []T
length int
}
// NewArrayStack return a empty ArrayStack pointer
func NewArrayStack[T any]() *ArrayStack[T] {
return &ArrayStack[T]{data: []T{}, length: 0}
}
// Data return stack data
func (s *ArrayStack[T]) Data() []T {
return s.data
}
// Size return length of stack data
func (s *ArrayStack[T]) Size() int {
return s.length
}
// IsEmpty checks if stack is empty or not
func (s *ArrayStack[T]) IsEmpty() bool {
return s.length == 0
}
// Push element into stack
func (s *ArrayStack[T]) Push(value T) {
s.data = append([]T{value}, s.data...)
s.length++
}
// Pop delete the top element of stack then return it, if stack is empty, return nil and error
func (s *ArrayStack[T]) Pop() (*T, error) {
if s.IsEmpty() {
return nil, errors.New("stack is empty")
}
topItem := s.data[0]
s.data = s.data[1:]
s.length--
return &topItem, nil
}
// Peak return the top element of stack
func (s *ArrayStack[T]) Peak() (*T, error) {
if s.IsEmpty() {
return nil, errors.New("stack is empty")
}
return &s.data[0], nil
}
// Clear the stack data
func (s *ArrayStack[T]) Clear() {
s.data = []T{}
s.length = 0
}
-82
View File
@@ -1,82 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestArrayStack_Push(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Push")
stack := NewArrayStack[int]()
stack.Push(1)
stack.Push(2)
stack.Push(3)
values := stack.Data()
length := stack.Size()
assert.Equal([]int{3, 2, 1}, values)
assert.Equal(3, length)
}
func TestArrayStack_Pop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Pop")
stack := NewArrayStack[int]()
_, err := stack.Pop()
assert.IsNotNil(err)
stack.Push(1)
stack.Push(2)
stack.Push(3)
topItem, err := stack.Pop()
assert.IsNil(err)
assert.Equal(3, *topItem)
assert.Equal([]int{2, 1}, stack.Data())
}
func TestArrayStack_Peak(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Peak")
stack := NewArrayStack[int]()
_, err := stack.Peak()
assert.IsNotNil(err)
stack.Push(1)
stack.Push(2)
stack.Push(3)
topItem, err := stack.Peak()
assert.IsNil(err)
assert.Equal(3, *topItem)
assert.Equal([]int{3, 2, 1}, stack.Data())
}
func TestArrayStack_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Clear")
stack := NewArrayStack[int]()
assert.Equal(true, stack.IsEmpty())
assert.Equal(0, stack.Size())
stack.Push(1)
assert.Equal(false, stack.IsEmpty())
assert.Equal(1, stack.Size())
stack.Clear()
assert.Equal(true, stack.IsEmpty())
assert.Equal(0, stack.Size())
}
-98
View File
@@ -1,98 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Stack structure contains ArrayStack and LinkedStack.
package datastructure
import (
"errors"
"fmt"
"github.com/duke-git/lancet/v2/datastructure"
)
// LinkedStack implements stack with link list
type LinkedStack[T any] struct {
top *datastructure.StackNode[T]
length int
}
// NewLinkedStack return a empty LinkedStack pointer
func NewLinkedStack[T any]() *LinkedStack[T] {
return &LinkedStack[T]{top: nil, length: 0}
}
// Data return stack data
func (s *LinkedStack[T]) Data() []T {
res := []T{}
current := s.top
for current != nil {
res = append(res, current.Value)
current = current.Next
}
return res
}
// Size return length of stack data
func (s *LinkedStack[T]) Size() int {
return s.length
}
// IsEmpty checks if stack is empty or not
func (s *LinkedStack[T]) IsEmpty() bool {
return s.length == 0
}
// Push element into stack
func (s *LinkedStack[T]) Push(value T) {
newNode := datastructure.NewStackNode(value)
top := s.top
if top == nil {
s.top = newNode
} else {
newNode.Next = top
s.top = newNode
}
s.length++
}
// Pop delete the top element of stack then return it, if stack is empty, return nil and error
func (s *LinkedStack[T]) Pop() (*T, error) {
if s.IsEmpty() {
return nil, errors.New("stack is empty")
}
top := s.top
s.top = s.top.Next
s.length--
return &top.Value, nil
}
// Peak return the top element of stack then return it
func (s *LinkedStack[T]) Peak() (*T, error) {
if s.IsEmpty() {
return nil, errors.New("stack is empty")
}
return &s.top.Value, nil
}
// Clear clear the stack data
func (s *LinkedStack[T]) Clear() {
s.top = nil
s.length = 0
}
// Print all nodes info of stack link
func (s *LinkedStack[T]) Print() {
current := s.top
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
current = current.Next
}
info += " ]"
fmt.Println(info)
}
-83
View File
@@ -1,83 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestLinkedStack_Push(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Push")
stack := NewLinkedStack[int]()
stack.Push(1)
stack.Push(2)
stack.Push(3)
values := stack.Data()
size := stack.Size()
assert.Equal([]int{3, 2, 1}, values)
assert.Equal(3, size)
}
func TestLinkedStack_Pop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Pop")
stack := NewLinkedStack[int]()
_, err := stack.Pop()
assert.IsNotNil(err)
stack.Push(1)
stack.Push(2)
stack.Push(3)
topItem, err := stack.Pop()
assert.IsNil(err)
assert.Equal(3, *topItem)
stack.Print()
assert.Equal([]int{2, 1}, stack.Data())
}
func TestLinkedStack_Peak(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Peak")
stack := NewLinkedStack[int]()
_, err := stack.Peak()
assert.IsNotNil(err)
stack.Push(1)
stack.Push(2)
stack.Push(3)
topItem, err := stack.Peak()
assert.IsNil(err)
assert.Equal(3, *topItem)
assert.Equal([]int{3, 2, 1}, stack.Data())
}
func TestLinkedStack_Empty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Empty")
stack := NewLinkedStack[int]()
assert.Equal(true, stack.IsEmpty())
assert.Equal(0, stack.Size())
stack.Push(1)
assert.Equal(false, stack.IsEmpty())
assert.Equal(1, stack.Size())
stack.Clear()
assert.Equal(true, stack.IsEmpty())
assert.Equal(0, stack.Size())
}
-112
View File
@@ -1,112 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. BSTree is binary search tree.
package datastructure
import (
"math"
"github.com/duke-git/lancet/v2/datastructure"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
// BSTree is a binary search tree data structure in which each node has at most two children,
// which are referred to as the left child and the right child.
// In BSTree: leftNode < rootNode < rightNode
// type T should implements Compare function in lancetconstraints.Comparator interface.
type BSTree[T any] struct {
root *datastructure.TreeNode[T]
comparator lancetconstraints.Comparator
}
// NewBSTree create a BSTree pointer
// param `comparator` is used to compare values in the tree
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T] {
root := datastructure.NewTreeNode(rootData)
return &BSTree[T]{root, comparator}
}
// InsertNode insert data into BSTree
func (t *BSTree[T]) Insert(data T) {
root := t.root
newNode := datastructure.NewTreeNode(data)
if root == nil {
t.root = newNode
} else {
insertTreeNode(root, newNode, t.comparator)
}
}
// DeletetNode delete data into BSTree
func (t *BSTree[T]) Delete(data T) {
deleteTreeNode(t.root, data, t.comparator)
}
// NodeLevel get node level in BSTree
func (t *BSTree[T]) NodeLevel(node *datastructure.TreeNode[T]) int {
if node == nil {
return 0
}
left := float64(t.NodeLevel(node.Left))
right := float64(t.NodeLevel(node.Right))
return int(math.Max(left, right)) + 1
}
// PreOrderTraverse traverse tree node in pre order
func (t *BSTree[T]) PreOrderTraverse() []T {
return preOrderTraverse(t.root)
}
// PostOrderTraverse traverse tree node in post order
func (t *BSTree[T]) PostOrderTraverse() []T {
return postOrderTraverse(t.root)
}
// InOrderTraverse traverse tree node in mid order
func (t *BSTree[T]) InOrderTraverse() []T {
return inOrderTraverse(t.root)
}
// LevelOrderTraverse traverse tree node in level order
func (t *BSTree[T]) LevelOrderTraverse() []T {
traversal := make([]T, 0)
levelOrderTraverse(t.root, &traversal)
return traversal
}
// Depth returns the calculated depth of a binary saerch tree
func (t *BSTree[T]) Depth() int {
return calculateDepth(t.root, 0)
}
// IsSubTree checks if the tree `t` has `subTree` or not
func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool {
return hasSubTree(t.root, subTree.root, t.comparator)
}
func hasSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T],
comparator lancetconstraints.Comparator) bool {
result := false
if superTreeRoot != nil && subTreeRoot != nil {
if comparator.Compare(superTreeRoot.Value, subTreeRoot.Value) == 0 {
result = isSubTree(superTreeRoot, subTreeRoot, comparator)
}
if !result {
result = hasSubTree(superTreeRoot.Left, subTreeRoot, comparator)
}
if !result {
result = hasSubTree(superTreeRoot.Right, subTreeRoot, comparator)
}
}
return result
}
// Print the bstree structure
func (t *BSTree[T]) Print() {
maxLevel := t.NodeLevel(t.root)
nodes := []*datastructure.TreeNode[T]{t.root}
printTreeNodes(nodes, 1, maxLevel)
}
-146
View File
@@ -1,146 +0,0 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func TestBSTree_PreOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_PreOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
acturl := bstree.PreOrderTraverse()
assert.Equal([]int{6, 5, 2, 4, 7}, acturl)
}
func TestBSTree_PostOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_PostOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
acturl := bstree.PostOrderTraverse()
assert.Equal([]int{5, 2, 4, 7, 6}, acturl)
}
func TestBSTree_InOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_InOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
acturl := bstree.InOrderTraverse()
assert.Equal([]int{2, 4, 5, 6, 7}, acturl)
}
func TestBSTree_LevelOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_LevelOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
acturl := bstree.LevelOrderTraverse()
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
}
func TestBSTree_Delete(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_Delete")
bstree := NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
bstree.Delete(4)
acturl1 := bstree.InOrderTraverse()
assert.Equal([]int{2, 5, 6, 7}, acturl1)
//todo
// bstree.DeletetNode(6, comparator)
// bstree.Print()
// acturl2 := bstree.InOrderTraverse()
// assert.Equal([]int{2, 5, 7}, acturl2)
}
func TestBSTree_Depth(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_Depth")
bstree := NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
assert.Equal(bstree.Depth(), 4)
}
func TestBSTree_IsSubTree(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_IsSubTree")
superTree := NewBSTree(8, &intComparator{})
superTree.Insert(4)
superTree.Insert(5)
superTree.Insert(6)
superTree.Insert(9)
superTree.Insert(4)
superTree.Print()
subTree := NewBSTree(5, &intComparator{})
subTree.Insert(4)
subTree.Insert(6)
assert.Equal(true, superTree.HasSubTree(subTree))
assert.Equal(false, subTree.HasSubTree(superTree))
}
-238
View File
@@ -1,238 +0,0 @@
package datastructure
import (
"fmt"
"math"
"github.com/duke-git/lancet/v2/datastructure"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
func preOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
data := []T{}
if node != nil {
data = append(data, node.Value)
data = append(data, preOrderTraverse(node.Left)...)
data = append(data, preOrderTraverse(node.Right)...)
}
return data
}
func postOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
data := []T{}
if node != nil {
data = append(data, preOrderTraverse(node.Left)...)
data = append(data, preOrderTraverse(node.Right)...)
data = append(data, node.Value)
}
return data
}
func inOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
data := []T{}
if node != nil {
data = append(data, inOrderTraverse(node.Left)...)
data = append(data, node.Value)
data = append(data, inOrderTraverse(node.Right)...)
}
return data
}
// func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
// if node == nil {
// return
// }
// fmt.Printf("%v, ", node.Value)
// preOrderPrint(node.Left)
// preOrderPrint(node.Right)
// }
// func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
// if node == nil {
// return
// }
// postOrderPrint(node.Left)
// postOrderPrint(node.Right)
// fmt.Printf("%v, ", node.Value)
// }
// func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
// if node == nil {
// return
// }
// inOrderPrint(node.Left)
// fmt.Printf("%v, ", node.Value)
// inOrderPrint(node.Right)
// }
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
var q []*datastructure.TreeNode[T] // queue
var n *datastructure.TreeNode[T] // temp node
q = append(q, root)
for len(q) != 0 {
n, q = q[0], q[1:]
*traversal = append(*traversal, n.Value)
if n.Left != nil {
q = append(q, n.Left)
}
if n.Right != nil {
q = append(q, n.Right)
}
}
}
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) {
if comparator.Compare(newNode.Value, rootNode.Value) == -1 {
if rootNode.Left == nil {
rootNode.Left = newNode
} else {
insertTreeNode(rootNode.Left, newNode, comparator)
}
} else {
if rootNode.Right == nil {
rootNode.Right = newNode
} else {
insertTreeNode(rootNode.Right, newNode, comparator)
}
}
}
// todo, delete root node failed
func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator lancetconstraints.Comparator) *datastructure.TreeNode[T] {
if node == nil {
return nil
}
if comparator.Compare(data, node.Value) == -1 {
node.Left = deleteTreeNode(node.Left, data, comparator)
} else if comparator.Compare(data, node.Value) == 1 {
node.Right = deleteTreeNode(node.Right, data, comparator)
} else {
if node.Left == nil {
node = node.Right
} else if node.Right == nil {
node = node.Left
} else {
l := node.Right
d := inOrderSuccessor(l)
d.Left = node.Left
return node.Right
}
}
return node
}
func inOrderSuccessor[T any](root *datastructure.TreeNode[T]) *datastructure.TreeNode[T] {
cur := root
for cur.Left != nil {
cur = cur.Left
}
return cur
}
func printTreeNodes[T any](nodes []*datastructure.TreeNode[T], level, maxLevel int) {
if len(nodes) == 0 || isAllNil(nodes) {
return
}
floor := maxLevel - level
endgeLines := int(math.Pow(float64(2), (math.Max(float64(floor)-1, 0))))
firstSpaces := int(math.Pow(float64(2), float64(floor))) - 1
betweenSpaces := int(math.Pow(float64(2), float64(floor)+1)) - 1
printSpaces(firstSpaces)
newNodes := []*datastructure.TreeNode[T]{}
for _, node := range nodes {
if node != nil {
fmt.Printf("%v", node.Value)
newNodes = append(newNodes, node.Left)
newNodes = append(newNodes, node.Right)
} else {
newNodes = append(newNodes, nil)
newNodes = append(newNodes, nil)
printSpaces(1)
}
printSpaces(betweenSpaces)
}
fmt.Println("")
for i := 1; i <= endgeLines; i++ {
for j := 0; j < len(nodes); j++ {
printSpaces(firstSpaces - i)
if nodes[j] == nil {
printSpaces(endgeLines + endgeLines + i + 1)
continue
}
if nodes[j].Left != nil {
fmt.Print("/")
} else {
printSpaces(1)
}
printSpaces(i + i - 1)
if nodes[j].Right != nil {
fmt.Print("\\")
} else {
printSpaces(1)
}
printSpaces(endgeLines + endgeLines - 1)
}
fmt.Println("")
}
printTreeNodes(newNodes, level+1, maxLevel)
}
// printSpaces
func printSpaces(n int) {
for i := 0; i < n; i++ {
fmt.Print(" ")
}
}
func isAllNil[T any](nodes []*datastructure.TreeNode[T]) bool {
for _, v := range nodes {
if v != nil {
return false
}
}
return true
}
func calculateDepth[T any](node *datastructure.TreeNode[T], depth int) int {
if node == nil {
return depth
}
return max(calculateDepth(node.Left, depth+1), calculateDepth(node.Right, depth+1))
}
func isSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) bool {
if subTreeRoot == nil {
return true
}
if superTreeRoot == nil {
return false
}
if comparator.Compare(superTreeRoot.Value, subTreeRoot.Value) != 0 {
return false
}
result := isSubTree(superTreeRoot.Left, subTreeRoot.Left, comparator) && isSubTree(superTreeRoot.Right, subTreeRoot.Right, comparator)
return result
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
+8 -16
View File
@@ -9,20 +9,17 @@ type theTime struct {
unix int64
}
// NewUnixNow return unix timestamp of current time.
// Play: https://go.dev/play/p/U4PPx-9D0oz
// NewUnixNow return unix timestamp of current time
func NewUnixNow() *theTime {
return &theTime{unix: time.Now().Unix()}
}
// NewUnix return unix timestamp of specified time.
// Play: https://go.dev/play/p/psoSuh_kLRt
// NewUnix return unix timestamp of specified time
func NewUnix(unix int64) *theTime {
return &theTime{unix: unix}
}
// NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss".
// Play: https://go.dev/play/p/VkW08ZOaXPZ
// NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss"
func NewFormat(t string) (*theTime, error) {
timeLayout := "2006-01-02 15:04:05"
loc := time.FixedZone("CST", 8*3600)
@@ -33,8 +30,7 @@ func NewFormat(t string) (*theTime, error) {
return &theTime{unix: tt.Unix()}, nil
}
// NewISO8601 return unix timestamp of specified iso8601 time string.
// Play: https://go.dev/play/p/mkhOHQkdeA2
// NewISO8601 return unix timestamp of specified iso8601 time string
func NewISO8601(iso8601 string) (*theTime, error) {
t, err := time.ParseInLocation(time.RFC3339, iso8601, time.UTC)
if err != nil {
@@ -43,26 +39,22 @@ func NewISO8601(iso8601 string) (*theTime, error) {
return &theTime{unix: t.Unix()}, nil
}
// ToUnix return unix timestamp.
// Play: https://go.dev/play/p/_LUiwAdocjy
// ToUnix return unix timestamp
func (t *theTime) ToUnix() int64 {
return t.unix
}
// ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time.
// Play: https://go.dev/play/p/VkW08ZOaXPZ
// ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time
func (t *theTime) ToFormat() string {
return time.Unix(t.unix, 0).Format("2006-01-02 15:04:05")
}
// ToFormatForTpl return the time string which format is specified tpl.
// Play: https://go.dev/play/p/nyXxXcQJ8L5
// ToFormatForTpl return the time string which format is specified tpl
func (t *theTime) ToFormatForTpl(tpl string) string {
return time.Unix(t.unix, 0).Format(tpl)
}
// ToFormatForTpl return iso8601 time string.
// Play: https://go.dev/play/p/mkhOHQkdeA2
// ToFormatForTpl return iso8601 time string
func (t *theTime) ToIso8601() string {
return time.Unix(t.unix, 0).Format(time.RFC3339)
}
+16 -17
View File
@@ -3,12 +3,10 @@ package datetime
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
"github.com/duke-git/lancet/internal"
)
func TestToUnix(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToUnix")
tm1 := NewUnixNow()
@@ -19,37 +17,38 @@ func TestToUnix(t *testing.T) {
}
func TestToFormat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToFormat")
tm, err := NewFormat("2022-03-18 17:04:05")
t.Log("TestToFormat", tm.ToFormat())
tm, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err = NewFormat("2022-03-18 17:04:05")
assert.IsNil(err)
t.Log("ToFormat -> ", tm.ToFormat())
}
func TestToFormatForTpl(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToFormatForTpl")
_, err := NewFormat("2022/03/18 17:04:05")
tm, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err := NewFormat("2022-03-18 17:04:05")
t.Log("TestToFormatForTpl", tm.ToFormatForTpl("2006/01/02 15:04:05"))
tm, err = NewFormat("2022-03-18 17:04:05")
assert.IsNil(err)
t.Log("ToFormatForTpl -> ", tm.ToFormatForTpl("2006/01/02 15:04:05"))
}
func TestToIso8601(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToIso8601")
_, err := NewISO8601("2022-03-18 17:04:05")
tm, err := NewISO8601("2022-03-18 17:04:05")
assert.IsNotNil(err)
tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
t.Log("TestToIso8601", tm.ToIso8601())
tm, err = NewISO8601("2006-01-02T15:04:05.999Z")
assert.IsNil(err)
t.Log("ToIso8601 -> ", tm.ToIso8601())
}
+35 -206
View File
@@ -3,7 +3,7 @@
// Package datetime implements some functions to format date and time.
// Note:
// 1. `format` param in FormatTimeToStr function should be as flow (case no sensitive):
// 1. `format` param in FormatTimeToStr function should be as flow:
// "yyyy-mm-dd hh:mm:ss"
// "yyyy-mm-dd hh:mm"
// "yyyy-mm-dd hh"
@@ -18,19 +18,14 @@
// "yyyy/mm"
// "mm/dd"
// "dd/mm/yy hh:mm:ss"
// "yyyymmdd"
// "mmddyy"
// "yyyy"
// "yy"
// "mm"
// "hh:mm:ss"
// "hh:mm"
// "mm:ss"
package datetime
import (
"fmt"
"strings"
"time"
)
@@ -52,236 +47,157 @@ func init() {
"yyyy/mm": "2006/01",
"mm/dd": "01/02",
"dd/mm/yy hh:mm:ss": "02/01/06 15:04:05",
"yyyymmdd": "20060102",
"mmddyy": "010206",
"yyyy": "2006",
"yy": "06",
"mm": "01",
"hh:mm:ss": "15:04:05",
"hh:mm": "15:04",
"mm:ss": "04:05",
}
}
// AddMinute add or sub minute to the time.
// Play: https://go.dev/play/p/nT1heB1KUUK
// AddMinute add or sub minute to the time
func AddMinute(t time.Time, minute int64) time.Time {
return t.Add(time.Minute * time.Duration(minute))
}
// AddHour add or sub hour to the time.
// Play: https://go.dev/play/p/rcMjd7OCsi5
// AddHour add or sub hour to the time
func AddHour(t time.Time, hour int64) time.Time {
return t.Add(time.Hour * time.Duration(hour))
}
// AddDay add or sub day to the time.
// Play: https://go.dev/play/p/dIGbs_uTdFa
// AddDay add or sub day to the time
func AddDay(t time.Time, day int64) time.Time {
return t.Add(24 * time.Hour * time.Duration(day))
}
// AddYear add or sub year to the time.
// Play: https://go.dev/play/p/MqW2ujnBx10
func AddYear(t time.Time, year int64) time.Time {
return t.Add(365 * 24 * time.Hour * time.Duration(year))
}
// GetNowDate return format yyyy-mm-dd of current date.
// Play: https://go.dev/play/p/PvfkPpcpBBf
// GetNowDate return format yyyy-mm-dd of current date
func GetNowDate() string {
return time.Now().Format("2006-01-02")
}
// GetNowTime return format hh-mm-ss of current time.
// Play: https://go.dev/play/p/l7BNxCkTmJS
// GetNowTime return format hh-mm-ss of current time
func GetNowTime() string {
return time.Now().Format("15:04:05")
}
// GetNowDateTime return format yyyy-mm-dd hh-mm-ss of current datetime.
// Play: https://go.dev/play/p/pI4AqngD0al
// GetNowDateTime return format yyyy-mm-dd hh-mm-ss of current datetime
func GetNowDateTime() string {
return time.Now().Format("2006-01-02 15:04:05")
}
// GetTodayStartTime return the start time of today, format: yyyy-mm-dd 00:00:00.
// Play: https://go.dev/play/p/84siyYF7t99
func GetTodayStartTime() string {
return time.Now().Format("2006-01-02") + " 00:00:00"
}
// GetTodayEndTime return the end time of today, format: yyyy-mm-dd 23:59:59.
// Play: https://go.dev/play/p/jjrLnfoqgn3
func GetTodayEndTime() string {
return time.Now().Format("2006-01-02") + " 23:59:59"
}
// GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00).
// Play: https://go.dev/play/p/QmL2oIaGE3q
// GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00)
func GetZeroHourTimestamp() int64 {
ts := time.Now().Format("2006-01-02")
t, _ := time.Parse("2006-01-02", ts)
return t.UTC().Unix() - 8*3600
}
// GetNightTimestamp return timestamp of zero hour (timestamp of 23:59).
// Play: https://go.dev/play/p/UolysR3MYP1
// GetNightTimestamp return timestamp of zero hour (timestamp of 23:59)
func GetNightTimestamp() int64 {
return GetZeroHourTimestamp() + 86400 - 1
}
// FormatTimeToStr convert time to string.
// Play: https://go.dev/play/p/_Ia7M8H_OvE
func FormatTimeToStr(t time.Time, format string, timezone ...string) string {
tf, ok := timeFormat[strings.ToLower(format)]
if !ok {
return ""
}
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return ""
}
return t.In(loc).Format(tf)
}
return t.Format(tf)
// FormatTimeToStr convert time to string
func FormatTimeToStr(t time.Time, format string) string {
return t.Format(timeFormat[format])
}
// FormatStrToTime convert string to time.
// Play: https://go.dev/play/p/1h9FwdU8ql4
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error) {
tf, ok := timeFormat[strings.ToLower(format)]
// FormatStrToTime convert string to time
func FormatStrToTime(str, format string) (time.Time, error) {
v, ok := timeFormat[format]
if !ok {
return time.Time{}, fmt.Errorf("format %s not support", format)
return time.Time{}, fmt.Errorf("format %s not found", format)
}
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return time.Time{}, err
}
return time.ParseInLocation(tf, str, loc)
}
return time.Parse(tf, str)
return time.Parse(v, str)
}
// BeginOfMinute return beginning minute time of day.
// Play: https://go.dev/play/p/ieOLVJ9CiFT
// BeginOfMinute return beginning minute time of day
func BeginOfMinute(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), t.Minute(), 0, 0, t.Location())
}
// EndOfMinute return end minute time of day.
// Play: https://go.dev/play/p/yrL5wGzPj4z
// EndOfMinute return end minute time of day
func EndOfMinute(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), t.Minute(), 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfHour return beginning hour time of day.
// Play: https://go.dev/play/p/GhdGFnDWpYs
// BeginOfHour return beginning hour time of day
func BeginOfHour(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), 0, 0, 0, t.Location())
}
// EndOfHour return end hour time of day.
// Play: https://go.dev/play/p/6ce3j_6cVqN
// EndOfHour return end hour time of day
func EndOfHour(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), 59, 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfDay return beginning hour time of day.
// Play: https://go.dev/play/p/94m_UT6cWs9
// BeginOfDay return beginning hour time of day
func BeginOfDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}
// EndOfDay return end time of day.
// Play: https://go.dev/play/p/eMBOvmq5Ih1
// EndOfDay return end time of day
func EndOfDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfWeek return beginning week, default week begin from Sunday.
// Play: https://go.dev/play/p/ynjoJPz7VNV
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time {
var beginFromWeekday = time.Sunday
if len(beginFrom) > 0 {
beginFromWeekday = beginFrom[0]
}
y, m, d := t.AddDate(0, 0, int(beginFromWeekday-t.Weekday())).Date()
beginOfWeek := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
if beginOfWeek.After(t) {
return beginOfWeek.AddDate(0, 0, -7)
}
return beginOfWeek
// BeginOfWeek return beginning week, week begin from Sunday
func BeginOfWeek(t time.Time) time.Time {
y, m, d := t.AddDate(0, 0, 0-int(BeginOfDay(t).Weekday())).Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}
// EndOfWeek return end week time, default week end with Saturday.
// Play: https://go.dev/play/p/i08qKXD9flf
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
var endWithWeekday = time.Saturday
if len(endWith) > 0 {
endWithWeekday = endWith[0]
}
y, m, d := t.AddDate(0, 0, int(endWithWeekday-t.Weekday())).Date()
var endWithWeek = time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
if endWithWeek.Before(t) {
endWithWeek = endWithWeek.AddDate(0, 0, 7)
}
return endWithWeek
// EndOfWeek return end week time, week end with Saturday
func EndOfWeek(t time.Time) time.Time {
y, m, d := BeginOfWeek(t).AddDate(0, 0, 7).Add(-time.Nanosecond).Date()
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfMonth return beginning of month.
// Play: https://go.dev/play/p/bWXVFsmmzwL
// BeginOfMonth return beginning of month
func BeginOfMonth(t time.Time) time.Time {
y, m, _ := t.Date()
return time.Date(y, m, 1, 0, 0, 0, 0, t.Location())
}
// EndOfMonth return end of month.
// Play: https://go.dev/play/p/_GWh10B3Nqi
// EndOfMonth return end of month
func EndOfMonth(t time.Time) time.Time {
return BeginOfMonth(t).AddDate(0, 1, 0).Add(-time.Nanosecond)
}
// BeginOfYear return the date time at the begin of year.
// Play: https://go.dev/play/p/i326DSwLnV8
// BeginOfYear return beginning of year
func BeginOfYear(t time.Time) time.Time {
y, _, _ := t.Date()
return time.Date(y, time.January, 1, 0, 0, 0, 0, t.Location())
}
// EndOfYear return the date time at the end of year.
// Play: https://go.dev/play/p/G01cKlMCvNm
// EndOfYear return end of year
func EndOfYear(t time.Time) time.Time {
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
}
// IsLeapYear check if param year is leap year or not.
// Play: https://go.dev/play/p/xS1eS2ejGew
func IsLeapYear(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
// BetweenSeconds returns the number of seconds between two times.
// Play: https://go.dev/play/p/n3YDRyfyXJu
func BetweenSeconds(t1 time.Time, t2 time.Time) int64 {
index := t2.Unix() - t1.Unix()
return index
}
// DayOfYear returns which day of the year the parameter date `t` is.
// Play: https://go.dev/play/p/0hjqhTwFNlH
func DayOfYear(t time.Time) int {
y, m, d := t.Date()
firstDay := time.Date(y, 1, 1, 0, 0, 0, 0, t.Location())
@@ -291,93 +207,6 @@ func DayOfYear(t time.Time) int {
}
// IsWeekend checks if passed time is weekend or not.
// Play: https://go.dev/play/p/cupRM5aZOIY
// Deprecated Use '== Weekday' instead
func IsWeekend(t time.Time) bool {
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
}
// NowDateOrTime return current datetime with specific format and timezone.
// Play: https://go.dev/play/p/EZ-begEjtT0
func NowDateOrTime(format string, timezone ...string) string {
tf, ok := timeFormat[strings.ToLower(format)]
if !ok {
return ""
}
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return ""
}
return time.Now().In(loc).Format(tf)
}
return time.Now().Format(tf)
}
// Timestamp return current second timestamp.
// Play: https://go.dev/play/p/iU5b7Vvjx6x
func Timestamp(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return t.Unix()
}
// TimestampMilli return current mill second timestamp.
// Play: https://go.dev/play/p/4gvEusOTu1T
func TimestampMilli(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)
}
// TimestampMicro return current micro second timestamp.
// Play: https://go.dev/play/p/2maANglKHQE
func TimestampMicro(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Microsecond)
}
// TimestampNano return current nano second timestamp.
// Play: https://go.dev/play/p/A9Oq_COrcCF
func TimestampNano(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return t.UnixNano()
}
-410
View File
@@ -1,410 +0,0 @@
package datetime
import (
"fmt"
"reflect"
"time"
)
func ExampleAddDay() {
now := time.Now()
tomorrow := AddDay(now, 1)
diff1 := tomorrow.Sub(now)
yesterday := AddDay(now, -1)
diff2 := yesterday.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 24h0m0s
// -24h0m0s
}
func ExampleAddHour() {
now := time.Now()
after2Hours := AddHour(now, 2)
diff1 := after2Hours.Sub(now)
before2Hours := AddHour(now, -2)
diff2 := before2Hours.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2h0m0s
// -2h0m0s
}
func ExampleAddMinute() {
now := time.Now()
after2Minutes := AddMinute(now, 2)
diff1 := after2Minutes.Sub(now)
before2Minutes := AddMinute(now, -2)
diff2 := before2Minutes.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2m0s
// -2m0s
}
func ExampleAddYear() {
now := time.Now()
after1Year := AddYear(now, 1)
diff1 := after1Year.Sub(now)
before1Year := AddYear(now, -1)
diff2 := before1Year.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 8760h0m0s
// -8760h0m0s
}
func ExampleGetNowDate() {
result := GetNowDate()
expected := time.Now().Format("2006-01-02")
fmt.Println(result == expected)
// Output:
// true
}
func ExampleGetNowTime() {
result := GetNowTime()
expected := time.Now().Format("15:04:05")
fmt.Println(result == expected)
// Output:
// true
}
func ExampleGetNowDateTime() {
result := GetNowDateTime()
expected := time.Now().Format("2006-01-02 15:04:05")
fmt.Println(result == expected)
// Output:
// true
}
// func ExampleGetZeroHourTimestamp() {
// ts := GetZeroHourTimestamp()
// fmt.Println(ts)
// // Output:
// // 1673107200
// }
// func ExampleGetNightTimestamp() {
// ts := GetNightTimestamp()
// fmt.Println(ts)
// // Output:
// // 1673193599
// }
func ExampleFormatTimeToStr() {
datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
result1 := FormatTimeToStr(datetime, "yyyy-mm-dd hh:mm:ss")
result2 := FormatTimeToStr(datetime, "yyyy-mm-dd")
result3 := FormatTimeToStr(datetime, "dd-mm-yy hh:mm:ss")
result4 := FormatTimeToStr(datetime, "yyyy-mm-dd hh")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 2021-01-02 16:04:08
// 2021-01-02
// 02-01-21 16:04:08
// 2021-01-02 16
}
func ExampleFormatStrToTime() {
result1, _ := FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss")
result2, _ := FormatStrToTime("2021-01-02", "yyyy-mm-dd")
result3, _ := FormatStrToTime("02-01-21 16:04:08", "dd-mm-yy hh:mm:ss")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 2021-01-02 16:04:08 +0000 UTC
// 2021-01-02 00:00:00 +0000 UTC
// 2021-01-02 16:04:08 +0000 UTC
}
func ExampleBeginOfMinute() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfMinute(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:50:00 +0000 UTC
}
func ExampleEndOfMinute() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfMinute(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:50:59.999999999 +0000 UTC
}
func ExampleBeginOfHour() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfHour(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:00:00 +0000 UTC
}
func ExampleEndOfHour() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfHour(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:59:59.999999999 +0000 UTC
}
func ExampleBeginOfDay() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfDay(input)
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
}
func ExampleEndOfDay() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfDay(input)
fmt.Println(result)
// Output:
// 2023-01-08 23:59:59.999999999 +0000 UTC
}
func ExampleBeginOfWeek() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfWeek(input)
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
}
func ExampleEndOfWeek() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfWeek(input)
fmt.Println(result)
// Output:
// 2023-01-14 23:59:59.999999999 +0000 UTC
}
func ExampleBeginOfMonth() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfMonth(input)
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
}
func ExampleEndOfMonth() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfMonth(input)
fmt.Println(result)
// Output:
// 2023-01-31 23:59:59.999999999 +0000 UTC
}
func ExampleBeginOfYear() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfYear(input)
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
}
func ExampleEndOfYear() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfYear(input)
fmt.Println(result)
// Output:
// 2023-12-31 23:59:59.999999999 +0000 UTC
}
func ExampleNewUnix() {
result := NewUnix(1647597438)
fmt.Println(result)
// Output:
// &{1647597438}
}
func ExampleNewUnixNow() {
tm1 := NewUnixNow()
unixTimestamp := tm1.ToUnix()
tm2 := NewUnix(unixTimestamp)
fmt.Println(reflect.DeepEqual(tm1, tm2))
// Output:
// true
}
// func ExampleNewFormat() {
// tm, err := NewFormat("2022-03-18 17:04:05")
// if err != nil {
// return
// }
// result := tm.ToFormat()
// fmt.Println(result)
// // Output:
// // 2022-03-18 17:04:05
// }
// func ExampleNewISO8601() {
// tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
// if err != nil {
// return
// }
// result := tm.ToIso8601()
// fmt.Println(result)
// // Output:
// // 2006-01-02T23:04:05+08:00
// }
func ExampleIsLeapYear() {
result1 := IsLeapYear(2000)
result2 := IsLeapYear(2001)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
func ExampleBetweenSeconds() {
today := time.Now()
tomorrow := AddDay(today, 1)
yesterday := AddDay(today, -1)
result1 := BetweenSeconds(today, tomorrow)
result2 := BetweenSeconds(today, yesterday)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 86400
// -86400
}
func ExampleDayOfYear() {
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
result1 := DayOfYear(date1)
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
result2 := DayOfYear(date2)
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
result3 := DayOfYear(date3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 31
// 1
// 0
}
func ExampleIsWeekend() {
date1 := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
date2 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
date3 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
result1 := IsWeekend(date1)
result2 := IsWeekend(date2)
result3 := IsWeekend(date3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
+36 -148
View File
@@ -4,43 +4,10 @@ import (
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
"github.com/duke-git/lancet/internal"
)
func TestAddYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
after2Years := AddYear(now, 1)
diff1 := after2Years.Sub(now)
assert.Equal(float64(8760), diff1.Hours())
before2Years := AddYear(now, -1)
diff2 := before2Years.Sub(now)
assert.Equal(float64(-8760), diff2.Hours())
}
func TestBetweenSeconds(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBetweenSeconds")
today := time.Now()
tomorrow := AddDay(today, 1)
yesterday := AddDay(today, -1)
result1 := BetweenSeconds(today, tomorrow)
result2 := BetweenSeconds(today, yesterday)
assert.Equal(int64(86400), result1)
assert.Equal(int64(-86400), result2)
}
func TestAddDay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
@@ -54,8 +21,6 @@ func TestAddDay(t *testing.T) {
}
func TestAddHour(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddHour")
now := time.Now()
@@ -69,8 +34,6 @@ func TestAddHour(t *testing.T) {
}
func TestAddMinute(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddMinute")
now := time.Now()
@@ -83,78 +46,59 @@ func TestAddMinute(t *testing.T) {
assert.Equal(float64(-2), diff2.Minutes())
}
func TestGetNowDate(t *testing.T) {
t.Parallel()
func TestAddYear(t *testing.T) {
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
after2Years := AddYear(now, 1)
diff1 := after2Years.Sub(now)
assert.Equal(float64(8760), diff1.Hours())
before2Years := AddYear(now, -1)
diff2 := before2Years.Sub(now)
assert.Equal(float64(-8760), diff2.Hours())
}
func TestGetNowDate(t *testing.T) {
assert := internal.NewAssert(t, "TestGetNowDate")
expected := time.Now().Format("2006-01-02")
assert.Equal(expected, GetNowDate())
}
func TestGetNowTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetNowTime")
func TestGetNotTime(t *testing.T) {
assert := internal.NewAssert(t, "TestGetNotTime")
expected := time.Now().Format("15:04:05")
assert.Equal(expected, GetNowTime())
}
func TestGetNowDateTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetNowDateTime")
expected := time.Now().Format("2006-01-02 15:04:05")
assert.Equal(expected, GetNowDateTime())
}
func TestGetTodayStartTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetTodayStartTime")
expected := time.Now().Format("2006-01-02") + " 00:00:00"
assert.Equal(expected, GetTodayStartTime())
}
func TestGetTodayEndTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetTodayEndTime")
expected := time.Now().Format("2006-01-02") + " 23:59:59"
assert.Equal(expected, GetTodayEndTime())
}
func TestFormatTimeToStr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFormatTimeToStr")
datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
cases := []string{
"yyyy-mm-dd hh:mm:ss", "yyyy-mm-dd",
"dd-mm-yy hh:mm:ss", "yyyy/mm/dd hh:mm:ss",
"hh:mm:ss", "yyyy/mm",
"yyyy-mm-dd hh",
}
"hh:mm:ss", "yyyy/mm"}
expected := []string{
"2021-01-02 16:04:08", "2021-01-02",
"02-01-21 16:04:08", "2021/01/02 16:04:08",
"16:04:08", "2021/01",
"2021-01-02 16",
}
"16:04:08", "2021/01"}
for i := 0; i < len(cases); i++ {
actual := FormatTimeToStr(datetime, cases[i])
assert.Equal(expected[i], actual)
}
ds := FormatTimeToStr(datetime, "yyyy-mm-dd hh:mm:ss", "EST")
t.Log(ds)
}
}
func TestFormatStrToTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFormatStrToTime")
formats := []string{
@@ -166,28 +110,22 @@ func TestFormatStrToTime(t *testing.T) {
"dd-mm-yy hh:mm:ss", "yyyy/mm/dd hh:mm:ss",
"yyyy/mm"}
expected := []string{
datetimeStr := []string{
"2021-01-02 16:04:08", "2021-01-02",
"02-01-21 16:04:08", "2021/01/02 16:04:08",
"2021/01"}
for i := 0; i < len(cases); i++ {
actual, err := FormatStrToTime(expected[i], cases[i])
actual, err := FormatStrToTime(datetimeStr[i], cases[i])
if err != nil {
t.Fatal(err)
}
expected, _ := time.Parse(formats[i], expected[i])
expected, _ := time.Parse(formats[i], datetimeStr[i])
assert.Equal(expected, actual)
}
estTime, err := FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss", "EST")
t.Log(estTime)
assert.IsNil(err)
}
func TestBeginOfMinute(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfMinute")
expected := time.Date(2022, 2, 15, 15, 48, 0, 0, time.Local)
@@ -198,8 +136,6 @@ func TestBeginOfMinute(t *testing.T) {
}
func TestEndOfMinute(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfMinute")
expected := time.Date(2022, 2, 15, 15, 48, 59, 999999999, time.Local)
@@ -210,8 +146,6 @@ func TestEndOfMinute(t *testing.T) {
}
func TestBeginOfHour(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfHour")
expected := time.Date(2022, 2, 15, 15, 0, 0, 0, time.Local)
@@ -222,8 +156,6 @@ func TestBeginOfHour(t *testing.T) {
}
func TestEndOfHour(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfHour")
expected := time.Date(2022, 2, 15, 15, 59, 59, 999999999, time.Local)
@@ -234,8 +166,6 @@ func TestEndOfHour(t *testing.T) {
}
func TestBeginOfDay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfDay")
expected := time.Date(2022, 2, 15, 0, 0, 0, 0, time.Local)
@@ -246,8 +176,6 @@ func TestBeginOfDay(t *testing.T) {
}
func TestEndOfDay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfDay")
expected := time.Date(2022, 2, 15, 23, 59, 59, 999999999, time.Local)
@@ -258,8 +186,6 @@ func TestEndOfDay(t *testing.T) {
}
func TestBeginOfWeek(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfWeek")
expected := time.Date(2022, 2, 13, 0, 0, 0, 0, time.Local)
@@ -270,8 +196,6 @@ func TestBeginOfWeek(t *testing.T) {
}
func TestEndOfWeek(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfWeek")
expected := time.Date(2022, 2, 19, 23, 59, 59, 999999999, time.Local)
@@ -282,8 +206,6 @@ func TestEndOfWeek(t *testing.T) {
}
func TestBeginOfMonth(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfMonth")
expected := time.Date(2022, 2, 1, 0, 0, 0, 0, time.Local)
@@ -294,8 +216,6 @@ func TestBeginOfMonth(t *testing.T) {
}
func TestEndOfMonth(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfMonth")
expected := time.Date(2022, 2, 28, 23, 59, 59, 999999999, time.Local)
@@ -306,8 +226,6 @@ func TestEndOfMonth(t *testing.T) {
}
func TestBeginOfYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfYear")
expected := time.Date(2022, 1, 1, 0, 0, 0, 0, time.Local)
@@ -318,8 +236,6 @@ func TestBeginOfYear(t *testing.T) {
}
func TestEndOfYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfYear")
expected := time.Date(2022, 12, 31, 23, 59, 59, 999999999, time.Local)
@@ -330,8 +246,6 @@ func TestEndOfYear(t *testing.T) {
}
func TestIsLeapYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfYear")
result1 := IsLeapYear(2000)
@@ -341,9 +255,21 @@ func TestIsLeapYear(t *testing.T) {
assert.Equal(false, result2)
}
func TestDayOfYear(t *testing.T) {
t.Parallel()
func TestBetweenSeconds(t *testing.T) {
assert := internal.NewAssert(t, "TestBetweenSeconds")
today := time.Now()
tomorrow := AddDay(today, 1)
yesterday := AddDay(today, -1)
result1 := BetweenSeconds(today, tomorrow)
result2 := BetweenSeconds(today, yesterday)
assert.Equal(int64(86400), result1)
assert.Equal(int64(-86400), result2)
}
func TestDayOfYear(t *testing.T) {
assert := internal.NewAssert(t, "TestDayOfYear")
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
result1 := DayOfYear(date1)
@@ -359,10 +285,7 @@ func TestDayOfYear(t *testing.T) {
}
func TestIsWeekend(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsWeekend")
date := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
result := IsWeekend(date)
assert.Equal(true, result)
@@ -375,38 +298,3 @@ func TestIsWeekend(t *testing.T) {
result2 := IsWeekend(date2)
assert.Equal(false, result2)
}
func TestNowDateOrTime(t *testing.T) {
t.Parallel()
formats := []string{
"yyyy-mm-dd hh:mm:ss",
"yyyy-mm-dd",
"dd-mm-yy hh:mm:ss",
"yyyy/mm/dd hh:mm:ss",
"hh:mm:ss",
"yyyy/mm",
"yyyy-mm-dd hh",
}
for i := 0; i < len(formats); i++ {
result := NowDateOrTime(formats[i], "UTC")
t.Log(result)
}
}
func TestTimestamp(t *testing.T) {
t.Parallel()
ts1 := Timestamp()
t.Log(ts1)
ts2 := TimestampMilli()
t.Log(ts2)
ts3 := TimestampMicro()
t.Log(ts3)
ts4 := TimestampNano()
t.Log(ts4)
}
-89
View File
@@ -1,89 +0,0 @@
import { defineConfig, HeadConfig } from 'vitepress'
export const META_IMAGE = '/lancet_logo.png'
export const isProduction = process.env.NETLIFY && process.env.CONTEXT === 'production'
if (process.env.NETLIFY) {
console.log('Netlify build', process.env.CONTEXT)
}
const productionHead: HeadConfig[] = [
[
'script',
{
src: 'https://unpkg.com/thesemetrics@latest',
async: '',
type: 'text/javascript',
},
],
]
const rControl = /[\u0000-\u001f]/g
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g
const rCombining = /[\u0300-\u036F]/g
/**
* Default slugification function
*/
export const slugify = (str: string): string =>
str
.normalize('NFKD')
// Remove accents
.replace(rCombining, '')
// Remove control characters
.replace(rControl, '')
// Replace special characters
.replace(rSpecial, '-')
// ensure it doesn't start with a number
.replace(/^(\d)/, '_$1')
export const commonConfig = defineConfig({
title: 'Lancet',
appearance: 'dark',
markdown: {
theme: {
dark: 'dracula-soft',
light: 'vitesse-light',
},
attrs: {
leftDelimiter: '%{',
rightDelimiter: '}%',
},
anchor: {
slugify,
},
},
head: [
// ['link', { rel: 'icon', type: 'image/svg+xml', href: '/logo.svg' }],
['link', { rel: 'icon', type: 'image/png', href: '/lancet_logo_mini.png' }],
['meta', { name: 'theme-color', content: '#5f67ee' }],
['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:locale', content: 'zh' }],
...(isProduction ? productionHead : []),
],
themeConfig: {
logo: { src: '/lancet_logo_mini.png', width: 24, height: 24 },
outline: [2, 3],
search: {
provider: 'local',
},
socialLinks: [
{
icon: 'github',
link: 'https://github.com/duke-git/lancet',
},
],
footer: {
copyright: 'Copyright © 2023-present Duke Du',
message: 'Released under the MIT License.',
},
},
})
-14
View File
@@ -1,14 +0,0 @@
import { defineConfig } from 'vitepress'
import { commonConfig } from './common'
import { zhConfig } from './zh'
import { enConfig } from './en'
// https://vitepress.dev/reference/site-config
export default defineConfig({
...commonConfig,
locales: {
root: { label: '简体中文', lang: 'zh-CN', link: '/', ...zhConfig },
en: { label: 'English', lang: 'en-US', link: '/en/', ...enConfig },
},
})
-102
View File
@@ -1,102 +0,0 @@
import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
export const META_URL = 'https://golancet.dev'
export const META_TITLE = 'Lancet'
export const META_DESCRIPTION = 'A powerful util function library of Go'
export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
description: META_DESCRIPTION,
head: [
['meta', { property: 'og:url', content: META_URL }],
['meta', { property: 'og:description', content: META_DESCRIPTION }],
['meta', { property: 'twitter:url', content: META_URL }],
['meta', { property: 'twitter:title', content: META_TITLE }],
['meta', { property: 'twitter:description', content: META_DESCRIPTION }],
],
themeConfig: {
nav: [
{
text: 'Home',
link: '/en/',
activeMatch: '^/en/',
},
{
text: 'Guide',
link: '/en/guide/introduction',
activeMatch: '^/en/guide/',
},
{ text: 'API', link: '/en/api/overview', activeMatch: '^/en/api/' },
{
text: 'Links',
items: [
{
text: 'Releaselog',
link: 'https://github.com/duke-git/lancet/releases',
},
],
},
],
sidebar: {
'/en/': [
{
text: 'Introduction',
collapsed: false,
items: [
{
text: 'What is Lancet',
link: '/en/guide/introduction',
},
{
text: 'getting started',
link: '/en/guide/getting_started',
},
],
},
],
'/en/api/': [
{
text: 'overview',
items: [{ text: 'overview of API', link: '/en/api/overview' }],
},
{
text: 'packages',
collapsed: false,
items: [
{ text: 'algorithm', link: '/en/api/packages/algorithm' },
{ text: 'compare', link: '/en/api/packages/compare' },
{ text: 'concurrency', link: '/en/api/packages/concurrency' },
{ text: 'condition', link: '/en/api/packages/condition' },
{ text: 'convertor', link: '/en/api/packages/convertor' },
{ text: 'cryptor', link: '/en/api/packages/cryptor' },
{
text: 'datastructure',
collapsed: true,
items: [
{ text: 'list', link: '/en/api/packages/datastructure/list' },
{ text: 'safelist', link: '/en/api/packages/datastructure/copyonwritelist' },
{ text: 'link', link: '/en/api/packages/datastructure/link' },
{ text: 'stack', link: '/en/api/packages/datastructure/stack' },
{ text: 'queue', link: '/en/api/packages/datastructure/queue' },
{ text: 'heap', link: '/en/api/packages/datastructure/heap' },
{ text: 'tree', link: '/en/api/packages/datastructure/tree' },
{ text: 'set', link: '/en/api/packages/datastructure/set' },
{ text: 'hashmap', link: '/en/api/packages/datastructure/hashmap' },
],
},
{ text: 'datetime', link: '/en/api/packages/datetime' },
{ text: 'fileutil', link: '/en/api/packages/fileutil' },
{ text: 'formatter', link: '/en/api/packages/formatter' },
{ text: 'function', link: '/en/api/packages/function' },
{ text: 'mathutil', link: '/en/api/packages/mathutil' },
{ text: 'maputil', link: '/en/api/packages/maputil' },
{ text: 'netutil', link: '/en/api/packages/netutil' },
{ text: 'pointer', link: '/en/api/packages/pointer' },
],
},
],
},
},
}
-115
View File
@@ -1,115 +0,0 @@
import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
export const META_URL = 'https://lancet.dev'
export const META_TITLE = 'Lancet'
export const META_DESCRIPTION = '一个强大的Go语言工具函数库'
export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
description: META_DESCRIPTION,
head: [
['meta', { property: 'og:url', content: META_URL }],
['meta', { property: 'og:description', content: META_DESCRIPTION }],
['meta', { property: 'twitter:url', content: META_URL }],
['meta', { property: 'twitter:title', content: META_TITLE }],
['meta', { property: 'twitter:description', content: META_DESCRIPTION }],
],
themeConfig: {
outline: {
label: '本页内容',
},
docFooter: {
prev: '上一页',
next: '下一页',
},
nav: [
{
text: '首页',
link: '/',
activeMatch: '^/',
},
{
text: '指南',
link: '/guide/introduction',
activeMatch: '^/guide/',
},
{ text: 'API', link: '/api/overview', activeMatch: '^/api/' },
{
text: '相关链接',
items: [
{
text: '更新日志',
link: 'https://github.com/duke-git/lancet/releases',
},
],
},
],
sidebar: {
'/': [
{
text: '介绍',
collapsed: true,
items: [
{
text: 'Lancet是什么?',
link: '/guide/introduction',
},
{
text: '开始',
link: '/guide/getting_started',
},
],
},
],
'/api/': [
{
text: '概览',
items: [{ text: 'API概述', link: '/api/overview' }],
},
{
text: 'API文档',
collapsed: false,
items: [
{ text: '算法', link: '/api/packages/algorithm' },
{ text: '比较器', link: '/api/packages/compare' },
{ text: '并发处理', link: '/api/packages/concurrency' },
{ text: '条件判断', link: '/api/packages/condition' },
{ text: '类型转换', link: '/api/packages/convertor' },
{ text: '加密&解密', link: '/api/packages/cryptor' },
{
text: '数据结构',
collapsed: true,
items: [
{ text: '线性表', link: '/api/packages/datastructure/list' },
{
text: '线性表(线程安全)',
link: '/api/packages/datastructure/copyonwritelist',
},
{ text: '链表', link: '/api/packages/datastructure/link' },
{ text: '栈', link: '/api/packages/datastructure/stack' },
{ text: '队列', link: '/api/packages/datastructure/queue' },
{ text: '堆', link: '/api/packages/datastructure/heap' },
{ text: '树', link: '/api/packages/datastructure/tree' },
{ text: '集合', link: '/api/packages/datastructure/set' },
{ text: 'HashMap', link: '/api/packages/datastructure/hashmap' },
],
},
{ text: '日期&时间', link: '/api/packages/datetime' },
{ text: '文件', link: '/api/packages/fileutil' },
{ text: '格式化工具', link: '/api/packages/formatter' },
{ text: '函数', link: '/api/packages/function' },
{ text: '数学工具', link: '/api/packages/mathutil' },
{ text: 'Map', link: '/api/packages/maputil' },
{ text: '网络', link: '/api/packages/netutil' },
{ text: '指针', link: '/api/packages/pointer' },
],
},
],
},
},
}
-69
View File
@@ -1,69 +0,0 @@
---
outline: deep
---
# API概述
<b>lancet(柳叶刀)是一个强大、全面、高效、可复用的go语言工具函数库。包含25个包,超过600个工具函数。功能涵盖字符串处理、切片处理、网络、并发、加解密、文件处理、时间/日期、流处理、迭代器等等。</b>
<style>
.package-title {
color: black;
font-size: 18px;
text-align: center;
font-weight: bold;
}
.package-container {
font-size: 16px;
border: 1px dashed;
padding: 10px;
text-align: center;
}
.package-cell {
height: 40px;
width: 140px;
display: inline-block;
vertical-align: middle;
line-height: 40px;
background: #ecefff;
border: 1px solid;
margin-right: 10px;
margin-bottom: 10px;
border-radius: 6px;
font-weight: bold;
}
</style>
<div>
<p class="package-title">lancet功能模块</p>
<div class="package-container">
<div class="package-cell">algorithm</div>
<div class="package-cell">compare</div>
<div class="package-cell">concurrency</div>
<div class="package-cell">condition</div>
<div class="package-cell">convertor</div>
<div class="package-cell">cryptor</div>
<div class="package-cell">datastructure</div>
<div class="package-cell">datetime</div>
<div class="package-cell">fileutil</div>
<div class="package-cell">formatter</div>
<div class="package-cell">function</div>
<div class="package-cell">iterator</div>
<div class="package-cell">maputil</div>
<div class="package-cell">mathutil</div>
<div class="package-cell">netutil</div>
<div class="package-cell">pointer</div>
<div class="package-cell">random</div>
<div class="package-cell">retry</div>
<div class="package-cell">slice</div>
<div class="package-cell">stream</div>
<div class="package-cell">structs</div>
<div class="package-cell">strutil</div>
<div class="package-cell">system</div>
<div class="package-cell">tuple</div>
<div class="package-cell">validator</div>
<div class="package-cell">xerror</div>
</div>
</div>
-638
View File
@@ -1,638 +0,0 @@
# Algorithm
algorithm 算法包实现一些基本算法,sortsearchlrucache。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
"github.com/duke-git/lancet/v2/algorithm"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [BubbleSort](#BubbleSort)
- [InsertionSort](#InsertionSort)
- [SelectionSort](#SelectionSort)
- [ShellSort](#ShellSort)
- [QuickSort](#QuickSort)
- [HeapSort](#HeapSort)
- [MergeSort](#MergeSort)
- [CountSort](#CountSort)
- [BinarySearch](#BinarySearch)
- [BinaryIterativeSearch](#BinaryIterativeSearch)
- [LinearSearch](#LinearSearch)
- [LRUCache](#LRUCache)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
### <span id="BubbleSort">BubbleSort</span>
<p>冒泡排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/GNdv7Jg2Taj)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.BubbleSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="InsertionSort">InsertionSort</span>
<p>插入排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/G5LJiWgJJW6)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type people struct {
Name string
Age int
}
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
//ascending order
if p1.Age < p2.Age {
return -1
} else if p1.Age > p2.Age {
return 1
}
return 0
}
func main() {
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator)
fmt.Println(peoples)
// Output:
// [{d 8} {b 10} {c 17} {a 20} {e 28}]
}
```
### <span id="SelectionSort">SelectionSort</span>
<p>选择排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/oXovbkekayS)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.SelectionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="ShellSort">ShellSort</span>
<p>希尔排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/3ibkszpJEu3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.ShellSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="QuickSort">QuickSort</span>
<p>快速排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/7Y7c1Elk3ax)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="HeapSort">HeapSort</span>
<p>堆排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/u6Iwa1VZS_f)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.HeapSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="MergeSort">MergeSort</span>
<p>归并排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ydinn9YzUJn)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.MergeSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="CountSort">CountSort</span>
<p>计数排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/tB-Umgm0DrP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
sortedNums := algorithm.CountSort(numbers, comparator)
fmt.Println(sortedNums)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="BinarySearch">BinarySearch</span>
<p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/t6MeGiUSN47)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
result1 := algorithm.BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
result2 := algorithm.BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
}
```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/Anozfr8ZLH3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
result1 := algorithm.BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
result2 := algorithm.BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
}
```
### <span id="LinearSearch">LinearSearch</span>
<p>基于传入的相等函数线性查找元素,返回元素索引,未找到元素返回-1。</p>
<b>函数签名:</b>
```go
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/IsS7rgn5s3x)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
numbers := []int{3, 4, 5, 3, 2, 1}
equalFunc := func(a, b int) bool {
return a == b
}
result1 := algorithm.LinearSearch(numbers, 3, equalFunc)
result2 := algorithm.LinearSearch(numbers, 6, equalFunc)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// -1
}
```
### <span id="LRUCache">LRUCache</span>
<p>lru算法实现缓存。</p>
<b>函数签名:</b>
```go
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
func (l *LRUCache[K, V]) Get(key K) (V, bool)
func (l *LRUCache[K, V]) Put(key K, value V)
func (l *LRUCache[K, V]) Delete(key K) bool
func (l *LRUCache[K, V]) Len() int
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/-EZjgOURufP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
cache := algorithm.NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
fmt.Println(result1, ok1)
fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
fmt.Println(cache.Len())
ok := cache.Delete(2)
fmt.Println(ok)
// Output:
// 1 true
// 2 true
// 0 false
// 2
// true
}
```
-443
View File
@@ -1,443 +0,0 @@
# Concurrency
并发包包含一些支持并发编程的功能。例如:goroutine, channel等。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/concurrency"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
### Channel
- [NewChannel](#NewChannel)
- [Bridge](#Bridge)
- [FanIn](#FanIn)
- [Generate](#Generate)
- [Or](#Or)
- [OrDone](#OrDone)
- [Repeat](#Repeat)
- [RepeatFn](#RepeatFn)
- [Take](#Take)
- [Tee](#Tee)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
### Channel
### <span id="NewChannel">NewChannel</span>
<p>返回一个Channel指针实例</p>
<b>函数签名:</b>
```go
type Channel[T any] struct
func NewChannel[T any]() *Channel[T]
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
c := concurrency.NewChannel[int]()
}
```
### <span id="Bridge">Bridge</span>
<p>将多个channel链接到一个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/qmWSy1NVF-Y)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
genVals := func() <-chan <-chan int {
out := make(chan (<-chan int))
go func() {
defer close(out)
for i := 1; i <= 5; i++ {
stream := make(chan int, 1)
stream <- i
close(stream)
out <- stream
}
}()
return out
}
for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
```
### <span id="FanIn">FanIn</span>
<p>将多个channel合并为一个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/2VYFMexEvTm)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
channels := make([]<-chan int, 2)
for i := 0; i < 2; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
}
chs := c.FanIn(ctx, channels...)
for v := range chs {
fmt.Println(v) //1 1 0 0 or 0 0 1 1
}
}
```
### <span id="Generate">Generate</span>
<p>根据传入的值,生成channel.</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
// Output:
// 1
// 2
// 3
}
```
### <span id="Repeat">Repeat</span>
<p>返回一个channel,将参数`values`重复放入channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/k5N_ALVmYjE)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 1
// 2
}
```
### <span id="RepeatFn">RepeatFn</span>
<p>返回一个channel,重复执行函数fn,并将结果放入返回的channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/4J1zAWttP85)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() string {
return "hello"
}
c := concurrency.NewChannel[string]()
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// hello
// hello
// hello
}
```
### <span id="Or">Or</span>
<p>将一个或多个channel读取到一个channel中,当任何读取channel关闭时将结束读取。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/Wqz9rwioPww)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan any)
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := concurrency.NewChannel[any]()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
)
fmt.Println("done after %v", time.Since(start)) //1.003s
}
```
### <span id="OrDone">OrDone</span>
<p>将一个channel读入另一个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/lm_GoS6aDjo)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for v := range c.OrDone(ctx, intStream) {
fmt.Println(v)
}
// Output:
// 1
// 1
// 1
}
```
### <span id="Take">Take</span>
<p>返回一个channel,其值从另一个channel获取,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/9Utt-1pDr2J)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}
```
### <span id="Tee">Tee</span>
<p>将一个channel分成两个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/3TQPKnCirrP)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
ch1, ch2 := c.Tee(ctx, intStream)
for v := range ch1 {
fmt.Println(v)
fmt.Println(<-ch2)
}
// Output:
// 1
// 1
// 1
// 1
}
```
-300
View File
@@ -1,300 +0,0 @@
# Condition
condition包含一些用于条件判断的函数。这个包的实现参考了carlmjohnson的truthy包的实现,更多有用的信息可以在[truthy](https://github.com/carlmjohnson/truthy)中找到,感谢carlmjohnson。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/condition/condition.go](https://github.com/duke-git/lancet/blob/main/condition/condition.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/condition"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Bool](#Bool)
- [And](#And)
- [Or](#Or)
- [Xor](#Generate)
- [Nor](#Nor)
- [Xnor](#Xnor)
- [Nand](#Nand)
- [TernaryOperator](#TernaryOperator)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
### <span id="Bool">Bool</span>
<p>返回传入参数的bool值.<br/>
如果出入类型参数含有Bool方法, 会调用该方法并返回<br/>
如果传入类型参数有IsZero方法, 返回IsZero方法返回值的取反<br/>
slices和map的length大于0时,返回true,否则返回false<br/>
其他类型会判断是否是零值</p>
<b>函数签名:</b>
```go
func Bool[T any](value T) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ETzeDJRSvhm)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
// bool
result1 := condition.Bool(false)
result2 := condition.Bool(true)
fmt.Println(result1) // false
fmt.Println(result2) // true
// integer
result3 := condition.Bool(0)
result4 := condition.Bool(1)
fmt.Println(result3) // false
fmt.Println(result4) // true
// string
result5 := condition.Bool("")
result6 := condition.Bool(" ")
fmt.Println(result5) // false
fmt.Println(result6) // true
// slice
nums := []int{}
result7 := condition.Bool(nums)
nums = append(nums, 1, 2)
result8 := condition.Bool(nums)
fmt.Println(result7) // false
fmt.Println(result8) // true
// struct
result9 = condition.Bool(struct{}{})
fmt.Println(result8) // false
// Output:
// false
// true
// false
// true
// false
// true
// false
// true
// false
}
```
### <span id="And">And</span>
<p>逻辑且操作,当切仅当a和b都为true时返回true</p>
<b>函数签名:</b>
```go
func And[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/W1SSUmt6pvr)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.And(0, 1)) // false
fmt.Println(condition.And(0, "")) // false
fmt.Println(condition.And(0, "0")) // false
fmt.Println(condition.And(1, "0")) // true
}
```
### <span id="Or">Or</span>
<p>逻辑或操作,当切仅当a和b都为false时返回false</p>
<b>函数签名:</b>
```go
func Or[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/UlQTxHaeEkq)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Or(0, "")) // false
fmt.Println(condition.Or(0, 1)) // true
fmt.Println(condition.Or(0, "0")) // true
fmt.Println(condition.Or(1, "0")) // true
}
```
### <span id="Xor">Xor</span>
<p>逻辑异或操作,a和b相同返回falsea和b不相同返回true</p>
<b>函数签名:</b>
```go
func Xor[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/gObZrW7ZbG8)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Xor(0, 0)) // false
fmt.Println(condition.Xor(0, 1)) // true
fmt.Println(condition.Xor(1, 0)) // true
fmt.Println(condition.Xor(1, 1)) // false
}
```
### <span id="Nor">Nor</span>
<p>异或的取反操作</p>
<b>函数签名:</b>
```go
func Nor[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/g2j08F_zZky)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Nor(0, 0)) // true
fmt.Println(condition.Nor(0, 1)) // false
fmt.Println(condition.Nor(1, 0)) // false
fmt.Println(condition.Nor(1, 1)) // false
}
```
### <span id="Xnor">Xnor</span>
<p>如果a和b都是真的或a和b均是假的,则返回true。</p>
<b>函数签名:</b>
```go
func Xnor[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/OuDB9g51643)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Xnor(0, 0)) // true
fmt.Println(condition.Xnor(0, 1)) // false
fmt.Println(condition.Xnor(1, 0)) // false
fmt.Println(condition.Xnor(1, 1)) // true
}
```
### <span id="Nand">Nand</span>
<p>如果a和b都为真,返回false,否则返回true</p>
<b>函数签名:</b>
```go
func Nand[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/vSRMLxLIbq8)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Nand(0, 0)) // true
fmt.Println(condition.Nand(0, 1)) // true
fmt.Println(condition.Nand(1, 0)) // true
fmt.Println(condition.Nand(1, 1)) // false
}
```
### <span id="TernaryOperator">TernaryOperator</span>
<p>三元运算符</p>
<b>函数签名:</b>
```go
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
conditionTrue := 2 > 1
result1 := condition.TernaryOperator(conditionTrue, 0, 1)
conditionFalse := 2 > 3
result2 := condition.TernaryOperator(conditionFalse, 0, 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// 1
}
```
-880
View File
@@ -1,880 +0,0 @@
# Convertor
convertor 转换器包支持一些常见的数据类型转换
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/convertor"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToChannel](#ToChannel)
- [ToFloat](#ToFloat)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToMap](#ToMap)
- [ToPointer](#ToPointer)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToSlice](#MapToSlice)
- [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte)
- [DeepClone](#DeepClone)
- [CopyProperties](#CopyProperties)
- [ToInterface](#ToInterface)
- [Utf8ToGbk](#Utf8ToGbk)
- [GbkToUtf8](#GbkToUtf8)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>颜色值十六进制转rgb。</p>
<b>函数签名:</b>
```go
func ColorHexToRGB(colorHex string) (red, green, blue int)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/o7_ft-JCJBV)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b)
// Output:
// 0 51 102
}
```
### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>颜色值rgb转十六进制。</p>
<b>函数签名:</b>
```go
func ColorRGBToHex(red, green, blue int) string
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/nzKS2Ro87J1)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
r := 0
g := 51
b := 102
colorHex := ColorRGBToHex(r, g, b)
fmt.Println(colorHex)
// Output:
// #003366
}
```
### <span id="ToBool">ToBool</span>
<p>字符串转布尔类型,使用strconv.ParseBool。</p>
<b>函数签名:</b>
```go
func ToBool(s string) (bool, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ARht2WnGdIN)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
for i := 0; i < len(cases); i++ {
result, _ := convertor.ToBool(cases[i])
fmt.Println(result)
}
// Output:
// true
// true
// true
// false
// false
// false
// false
// false
// false
}
```
### <span id="ToBytes">ToBytes</span>
<p>Interface转字节切片。</p>
<b>函数签名:</b>
```go
func ToBytes(data any) ([]byte, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/fAMXYFDvOvr)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
bytesData, err := convertor.ToBytes("abc")
if err != nil {
fmt.Println(err)
}
fmt.Println(bytesData)
// Output:
// [97 98 99]
}
```
### <span id="ToChar">ToChar</span>
<p>字符串转字符切片。</p>
<b>函数签名:</b>
```go
func ToChar(s string) []string
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/JJ1SvbFkVdM)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result1 := convertor.ToChar("")
result2 := convertor.ToChar("abc")
result3 := convertor.ToChar("1 2#3")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// []
// [a b c]
// [1 2 # 3]
}
```
### <span id="ToChannel">ToChannel</span>
<p>将切片转为只读channel。</p>
<b>函数签名:</b>
```go
func ToChannel[T any](array []T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/hOx_oYZbAnL)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
ch := convertor.ToChannel([]int{1, 2, 3})
result1 := <-ch
result2 := <-ch
result3 := <-ch
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 3
}
```
### <span id="ToFloat">ToFloat</span>
<p>将interface转成float64类型,如果参数无法转换,会返回0和error。</p>
<b>函数签名:</b>
```go
func ToFloat(value any) (float64, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/4YTmPCibqHJ)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result1, _ := convertor.ToFloat("")
result2, err := convertor.ToFloat("abc")
result3, _ := convertor.ToFloat("-1")
result4, _ := convertor.ToFloat("-.11")
result5, _ := convertor.ToFloat("1.23e3")
result6, _ := convertor.ToFloat(true)
fmt.Println(result1)
fmt.Println(result2, err)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// 0
// 0 strconv.ParseFloat: parsing "": invalid syntax
// -1
// -0.11
// 1230
// 0
}
```
### <span id="ToInt">ToInt</span>
<p>将interface转成int64类型,如果参数无法转换,会返回0和error。</p>
<b>函数签名:</b>
```go
func ToInt(value any) (int64, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/9_h9vIt-QZ_b)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result1, _ := convertor.ToInt("123")
result2, _ := convertor.ToInt("-123")
result3, _ := convertor.ToInt(float64(12.3))
result4, err := convertor.ToInt("abc")
result5, _ := convertor.ToInt(true)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4, err)
fmt.Println(result5)
// Output:
// 123
// -123
// 12
// 0 strconv.ParseInt: parsing "": invalid syntax
// 0
}
```
### <span id="ToJson">ToJson</span>
<p>将interface转成json字符串,如果参数无法转换,会返回""和error。</p>
<b>函数签名:</b>
```go
func ToJson(value any) (string, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/2rLIkMmXWvR)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result, err := ToJson(aMap)
if err != nil {
fmt.Printf("%v", err)
}
fmt.Println(result)
// Output:
// {"a":1,"b":2,"c":3}
}
```
### <span id="ToMap">ToMap</span>
<p>将切片转为map。</p>
<b>函数签名:</b>
```go
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/tVFy7E-t24l)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Message struct {
name string
code int
}
messages := []Message{
{name: "Hello", code: 100},
{name: "Hi", code: 101},
}
result := convertor.ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name
})
fmt.Println(result)
// Output:
// map[100:Hello 101:Hi]
}
```
### <span id="ToPointer">ToPointer</span>
<p>返回传入值的指针。</p>
<b>函数签名:</b>
```go
func ToPointer[T any](value T) *T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ASf_etHNlw1)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result := convertor.ToPointer(123)
fmt.Println(*result)
// Output:
// 123
}
```
### <span id="ToString">ToString</span>
<p>将值转换为字符串,对于数字、字符串、[]byte,将转换为字符串。 对于其他类型(切片、映射、数组、结构体)将调用 json.Marshal</p>
<b>函数签名:</b>
```go
func ToString(value any) string
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/nF1zOOslpQq)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result1 := convertor.ToString("")
result2 := convertor.ToString(nil)
result3 := convertor.ToString(0)
result4 := convertor.ToString(1.23)
result5 := convertor.ToString(true)
result6 := convertor.ToString(false)
result7 := convertor.ToString([]int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
//
//
// 0
// 1.23
// true
// false
// [1,2,3]
}
```
### <span id="StructToMap">StructToMap</span>
<p>将struct转成map,只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记。</p>
<b>函数签名:</b>
```go
func StructToMap(value any) (map[string]any, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/KYGYJqNUBOI)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := convertor.StructToMap(p)
fmt.Println(pm)
// Output:
// map[name:test]
}
```
### <span id="MapToSlice">MapToSlice</span>
<p>map中key和value执行函数iteratee后,转为切片。</p>
<b>函数签名:</b>
```go
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/dmX4Ix5V6Wl)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result := MapToSlice(aMap, func(key string, value int) string {
return key + ":" + strconv.Itoa(value)
})
fmt.Println(result) //[]string{"a:1", "b:2", "c:3"}
}
```
### <span id="EncodeByte">EncodeByte</span>
<p>将data编码成字节切片。</p>
<b>函数签名:</b>
```go
func EncodeByte(data any) ([]byte, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/DVmM1G5JfuP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData)
// Output:
// [6 12 0 3 97 98 99]
}
```
### <span id="DecodeByte">DecodeByte</span>
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例。</p>
<b>函数签名:</b>
```go
func DecodeByte(data []byte, target any) error
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/zI6xsmuQRbn)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
err := convertor.DecodeByte(byteData, &result)
if err != nil {
return
}
fmt.Println(result)
// Output:
// abc
}
```
### <span id="DeepClone">DeepClone</span>
<p>创建一个传入值的深拷贝, 无法克隆结构体的非导出字段。</p>
<b>函数签名:</b>
```go
func DeepClone[T any](src T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/j4DP5dquxnk)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for _, item := range cases {
cloned := convertor.DeepClone(item)
isPointerEqual := &cloned == &item
fmt.Println(cloned, isPointerEqual)
}
// Output:
// true false
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil> } false
}
```
### <span id="CopyProperties">CopyProperties</span>
<p>拷贝不同结构体之间的同名字段。使用json.Marshal序列化,需要设置dst和src struct字段的json tag。</p>
<b>函数签名:</b>
```go
func CopyProperties[T, U any](dst T, src U) (err error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/oZujoB5Sgg5)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
err := convertor.CopyProperties(&indicatorVO, indicator)
if err != nil {
return
}
fmt.Println(indicatorVO.Id)
fmt.Println(indicatorVO.Ip)
fmt.Println(len(indicatorVO.Disk))
// Output:
// 001
// 127.0.0.1
// 3
}
```
### <span id="ToInterface">ToInterface</span>
<p>将反射值转换成对应的interface类型。</p>
<b>函数签名:</b>
```go
func ToInterface(v reflect.Value) (value interface{}, ok bool)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/syqw0-WG7Xd)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
val := reflect.ValueOf("abc")
iVal, ok := convertor.ToInterface(val)
fmt.Printf("%T\n", iVal)
fmt.Printf("%v\n", iVal)
fmt.Println(ok)
// Output:
// string
// abc
// true
}
```
### <span id="Utf8ToGbk">Utf8ToGbk</span>
<p>utf8编码转GBK编码。</p>
<b>函数签名:</b>
```go
func Utf8ToGbk(bs []byte) ([]byte, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/9FlIaFLArIL)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
utf8Data := []byte("hello")
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(validator.IsGBK(gbkData))
// Output:
// true
// true
}
```
### <span id="GbkToUtf8">GbkToUtf8</span>
<p>GBK编码转utf8编码。</p>
<b>函数签名:</b>
```go
func GbkToUtf8(bs []byte) ([]byte, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/OphmHCN_9u8)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
utf8Data, _ := convertor.GbkToUtf8(gbkData)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(string(utf8Data))
// Output:
// true
// hello
}
```
File diff suppressed because it is too large Load Diff
@@ -1,471 +0,0 @@
# CopyOnWriteList
CopyOnWriteList 是一个线程安全的 List 实现,底层使用 go 切片。写入时,会复制一份新的切片,写入完成后,再将新的切片赋值给原来的切片。读取时,直接读取原来的切片。
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/list/copyonwritelist.go](https://github.com/duke-git/lancet/blob/main/datastructure/list/copyonwritelist.go)
## 用法
```go
import (
"github.com/duke-git/lancet/datastructure/list"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [NewCopyOnWriteList](#NewCopyOnWriteList)
- [Size](#Size)
- [Get](#Get)
- [Set](#Set)
- [Remove](#Remove)
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [IsEmpty](#IsEmpty)
- [Contain](#Contain)
- [ValueOf](#ValueOf)
- [Add](#Add)
- [AddAll](#AddAll)
- [AddByIndex](#AddByIndex)
- [DeleteAt](#DeleteAt)
- [DeleteIf](#DeleteIf)
- [DeleteBy](#DeleteBy)
- [DeleteRange](#DeleteRange)
- [Equal](#Equal)
## 文档
### NewCopyOnWriteList
返回一个具有空切片的 CopyOnWriteList。
```go
type CopyOnWriteList[T any] struct {
data []T
lock sync.Locker
}
func NewCopyOnWriteList() *CopyOnWriteList
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l)
}
```
### Size
返回 CopyOnWriteList 的长度。
```go
func (l *CopyOnWriteList[T]) Size() int
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Size())
}
```
### Get
返回列表中指定位置的元素
```go
func (c *CopyOnWriteList[T]) Get(index int) *T
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Get(2))
}
```
### Set
将此列表中指定位置的元素替换为指定元素。
```go
func (c *CopyOnWriteList[T]) Set(index int, e T) (oldValue *T, ok bool)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Set(2, 4))
}
```
### Remove
### IndexOf
返回列表中值的索引,如果没有找到返回-1。
```go
func (c *CopyOnWriteList[T]) IndexOf(e T) int
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.IndexOf(1))
}
```
### LastIndexOf
返回指定元素在此列表中最后出现的索引,如果此列表不包含该元素,则返回-1。
```go
func (c *CopyOnWriteList[T]) LastIndexOf(e T) int
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3,1})
fmt.Println(l.LastIndexOf(1))
}
```
### IsEmpty
如果此列表不包含任何元素,则返回 true。
```go
func (c *CopyOnWriteList[T]) IsEmpty() bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{})
fmt.Println(l.IsEmpty())
}
```
### Contain
判断 CopyOnWriteList 是否包含某个元素
```go
func (c *CopyOnWriteList[T]) Contain(e T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Contain(1))
}
```
### ValueOf
返回列表中索引处的值指针
```go
func (c *CopyOnWriteList[T]) ValueOf(index int) []T
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.ValueOf(2))
}
```
### Add
将指定的元素追加到此列表的末尾。
```go
func (c *CopyOnWriteList[T]) Add(e T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
l.Add(4)
fmt.Println(l.getList())
}
```
### AddAll
将指定集合中的所有元素追加到此列表的末尾
```go
func (c *CopyOnWriteList[T]) AddAll(e []T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
l.AddAll([]int{4,5,6})
fmt.Println(l.getList())
}
```
### AddByIndex
将指定元素插入此列表中的指定位置。
```go
func (c *CopyOnWriteList[T]) AddByIndex(index int, e T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.AddByIndex(2, 6)
fmt.Println(l.getList())
}
```
### DeleteAt
移除此列表中指定位置的元素。
```go
func (c *CopyOnWriteList[T]) DeleteAt(index int) (oldValue *T, ok bool)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.DeleteAt(2)
fmt.Println(l.getList())
}
```
### DeleteIf
从此列表中删除第一个出现的指定元素(如果该元素存在)。
```go
func (c *CopyOnWriteList[T]) DeleteIf(f func(T) bool) (oldValue *T, ok bool)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.DeleteIf(func(i int) bool {
return i == 2
})
fmt.Println(l.getList())
}
```
### DeleteBy
从此列表中删除第一个出现的指定元素(如果该元素存在)。
```go
func (c *CopyOnWriteList[T]) DeleteBy(e T) (*T bool)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.DeleteBy(2)
fmt.Println(l.getList())
}
```
### DeleteRange
从该列表中删除索引介于 fromIndex(包含)和 toIndex(不包含)之间的所有元素。
(左闭右开)。
```go
func (c *CopyOnWriteList[T]) DeleteRange(start int, end int)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3,4,5,6,7,8,9})
list.DeleteRange(2, 5)
fmt.Println(l.getList())
}
```
### Equal
如果指定的对象等于此列表,则返回 true。
```go
func (c *CopyOnWriteList[T]) Equal(e []T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3,4,5,6,7,8,9})
fmt.Println(l.Equal([]int{1,2,3,4,5,6,7,8,9}))
}
```
-308
View File
@@ -1,308 +0,0 @@
# HashMap
HashMap 数据结构实现
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/hashmap/hashmap.go](https://github.com/duke-git/lancet/blob/main/datastructure/hashmap/hashmap.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [NewHashMap](#NewHashMap)
- [NewHashMapWithCapacity](#NewHashMapWithCapacity)
- [Get](#Get)
- [Put](#Put)
- [Delete](#Delete)
- [Contains](#Contains)
- [Iterate](#Iterate)
- [Keys](#Keys)
- [Values](#Values)
<div STYLE="page-break-after: always;"></div>
## API 文档
### <span id="NewHashMap">NewHashMap</span>
<p>新建默认容量(1 << 10)的HashMap指针实例</p>
<b>函数签名:</b>
```go
func NewHashMap() *HashMap
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
fmt.Println(hm)
}
```
### <span id="NewHashMapWithCapacity">NewHashMapWithCapacity</span>
<p>新建指定容量和长度的HashMap指针实例.</p>
<b>函数签名:</b>
```go
func NewHashMapWithCapacity(size, capacity uint64) *HashMap
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMapWithCapacity(uint64(100), uint64(1000))
fmt.Println(hm)
}
```
### <span id="Get">Get</span>
<p>在hashmap中根据key获取值</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Get(key any) any
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
val := hm.Get("a")
fmt.Println(val) //nil
}
```
### <span id="Put">Put</span>
<p>将key-value放入hashmap中</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Put(key any, value any) any
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
val := hm.Get("a")
fmt.Println(val) //1
}
```
### <span id="Delete">Delete</span>
<p>将指定的key从hashmap中删除</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Delete(key any)
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
val := hm.Get("a")
fmt.Println(val) //1
hm.Delete("a")
val = hm.Get("a")
fmt.Println(val) //nil
}
```
### <span id="Contains">Contains</span>
<p>判断hashmap中是否包含指定的key</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Contains(key any) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
fmt.Println(hm.Contains("a")) //true
fmt.Println(hm.Contains("b")) //false
}
```
### <span id="Iterate">Iterate</span>
<p>迭代hashmap,对每个key和value执行iteratee函数</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Iterate(iteratee func(key, value any))
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
hm.Iterate(func(key, value any) {
fmt.Println(key)
fmt.Println(value)
})
}
```
### <span id="Keys">Keys</span>
<p>返回hashmap所有key的切片 (随机顺序)</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Keys() []any
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
fmt.Println(keys) //[]interface{"a", "b", "c"}
}
```
### <span id="Values">Values</span>
<p>返回hashmap所有值的切片 (随机顺序).</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Values() []any
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
values := hm.Values()
fmt.Println(values) //[]interface{2, 1, 3}
}
```
-364
View File
@@ -1,364 +0,0 @@
# Heap
堆,切片实现的二叉堆数据结构。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/heap/maxheap.go](https://github.com/duke-git/lancet/blob/main/datastructure/heap/maxheap.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [MaxHeap](#MaxHeap)
- [Push](#Push)
- [Pop](#Pop)
- [Peek](#Peek)
- [Data](#Data)
- [Size](#Size)
<div STYLE="page-break-after: always;"></div>
## API文档
### 1. MaxHeap
MaxHeap是通过slice实现的二叉堆树,根节点的key既大于等于左子树的key值且大于等于右子树的key值。
### <span id="NewMaxHeap">NewMaxHeap</span>
<p>返回NewMaxHeap指针实例</p>
<b>函数签名:</b>
```go
type MaxHeap[T any] struct {
data []T
comparator lancetconstraints.Comparator
}
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
fmt.Println(maxHeap)
}
```
### <span id="Push">Push</span>
<p>向堆中插入数据</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Push(value T)
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
fmt.Println(maxHeap.Data()) //[]int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
}
```
### <span id="Pop">Pop</span>
<p>返回堆中最大值并将其从堆中删除,如果堆为空,返回零值并返回false</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Pop() (T, bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
val, ok := maxHeap.Pop()
fmt.Println(val) //12
fmt.Println(ok) //true
}
```
### <span id="Peek">Peek</span>
<p>返回堆中最大值,如果堆为空,返回零值并返回false</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Peek() (T, bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
val, ok := maxHeap.Peek()
fmt.Println(val) //12
fmt.Println(maxHeap.Size()) //12
}
```
### <span id="Data">Data</span>
<p>返回堆中全部元素的切片</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Data() []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
fmt.Println(maxHeap.Data()) //[]int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
}
```
### <span id="Size">Size</span>
<p>返回堆中元素的数量</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Size() int
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2}
for _, v := range values {
maxHeap.Push(v)
}
fmt.Println(maxHeap.Size()) //3
}
```
### <span id="PrintStructure">PrintStructure</span>
<p>打印堆的树形结构</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) PrintStructure()
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
fmt.Println(maxHeap.PrintStructure())
// 12
// 9 11
// 4 8 10 7
// 1 3 5 6 2
}
```
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-649
View File
@@ -1,649 +0,0 @@
# Set
Set 集合数据结构,类似列表。Set 中元素不重复。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
set "github.com/duke-git/lancet/v2/datastructure/set"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [NewSet](#NewSet)
- [NewSetFromSlice](#NewSetFromSlice)
- [Values](#Values)
- [Add](#Add)
- [AddIfNotExist](#AddIfNotExist)
- [AddIfNotExistBy](#AddIfNotExistBy)
- [Delete](#Delete)
- [Contain](#Contain)
- [ContainAll](#ContainAll)
- [Clone](#Clone)
- [Size](#Size)
- [Equal](#Equal)
- [Iterate](#Iterate)
- [IsEmpty](#IsEmpty)
- [Union](#Union)
- [Intersection](#Intersection)
- [SymmetricDifference](#SymmetricDifference)
- [Minus](#Minus)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="NewSet">NewSet</span>
<p>返回Set结构体对象</p>
<b>函数签名:</b>
```go
type Set[T comparable] map[T]bool
func NewSet[T comparable](items ...T) Set[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSet[int](1,2,2,3)
fmt.Println(st.Values()) //1,2,3
}
```
### <span id="NewSetFromSlice">NewSetFromSlice</span>
<p>基于切片创建集合</p>
<b>函数签名:</b>
```go
func NewSetFromSlice[T comparable](items []T) Set[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSetFromSlice([]int{1, 2, 2, 3})
fmt.Println(st.Values()) //1,2,3
}
```
### <span id="Values">Values</span>
<p>获取集合中所有元素的切片</p>
<b>函数签名:</b>
```go
func (s Set[T]) Values() []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSet[int](1,2,2,3)
fmt.Println(st.Values()) //1,2,3
}
```
### <span id="Add">Add</span>
<p>向集合中添加元素</p>
<b>函数签名:</b>
```go
func (s Set[T]) Add(items ...T)
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSet[int]()
st.Add(1, 2, 3)
fmt.Println(st.Values()) //1,2,3
}
```
### <span id="AddIfNotExist">AddIfNotExist</span>
<p>如果集合中不存在元素,则添加该元素返回true, 如果集合中存在元素, 不做任何操作,返回false</p>
<b>函数签名:</b>
```go
func (s Set[T]) AddIfNotExist(item T) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSet[int]()
st.Add(1, 2, 3)
r1 := st.AddIfNotExist(1)
r2 := st.AddIfNotExist(4)
fmt.Println(r1) // false
fmt.Println(r2) // true
fmt.Println(st.Values()) // 1,2,3,4
}
```
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
<p>根据checker函数判断元素是否在集合中,如果集合中不存在元素且checker返回true,则添加该元素返回true, 否则不做任何操作,返回false</p>
<b>函数签名:</b>
```go
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSet[int]()
st.Add(1, 2)
ok := st.AddIfNotExistBy(3, func(val int) bool {
return val%2 != 0
})
fmt.Println(ok) // true
notOk := st.AddIfNotExistBy(4, func(val int) bool {
return val%2 != 0
})
fmt.Println(notOk) // false
fmt.Println(st.Values()) // 1, 2, 3
}
```
### <span id="Delete">Delete</span>
<p>删除集合中元素</p>
<b>函数签名:</b>
```go
func (s Set[T]) Delete(items ...T)
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSet[int]()
st.Add(1, 2, 3)
set.Delete(3)
fmt.Println(st.Values()) //1,2
}
```
### <span id="Contain">Contain</span>
<p>判断集合是否包含某个值</p>
<b>函数签名:</b>
```go
func (s Set[T]) Contain(item T) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSet[int]()
st.Add(1, 2, 3)
fmt.Println(st.Contain(1)) //true
fmt.Println(st.Contain(4)) //false
}
```
### <span id="ContainAll">ContainAll</span>
<p>判断集合是否包含另一个集合</p>
<b>函数签名:</b>
```go
func (s Set[T]) ContainAll(other Set[T]) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(1, 2)
set3 := set.NewSet(1, 2, 3, 4)
fmt.Println(set1.ContainAll(set2)) //true
fmt.Println(set1.ContainAll(set3)) //false
}
```
### <span id="Size">Size</span>
<p>获取集合中元素的个数</p>
<b>函数签名:</b>
```go
func (s Set[T]) Size() int
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
fmt.Println(set1.Size()) //3
}
```
### <span id="Clone">Clone</span>
<p>克隆一个集合</p>
<b>函数签名:</b>
```go
func (s Set[T]) Clone() Set[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set1.Clone()
fmt.Println(set1.Size() == set2.Size()) //true
fmt.Println(set1.ContainAll(set2)) //true
}
```
### <span id="Equal">Equal</span>
<p>比较两个集合是否相等,包含相同元素为相等</p>
<b>函数签名:</b>
```go
func (s Set[T]) Equal(other Set[T]) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(1, 2, 3)
set3 := set.NewSet(1, 2, 3, 4)
fmt.Println(set1.Equal(set2)) //true
fmt.Println(set1.Equal(set3)) //false
}
```
### <span id="Iterate">Iterate</span>
<p>迭代结合,在每个元素上调用函数</p>
<b>函数签名:</b>
```go
func (s Set[T]) Iterate(fn func(item T))
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
arr := []int{}
set.Iterate(func(item int) {
arr = append(arr, item)
})
fmt.Println(arr) //1,2,3
}
```
### <span id="EachWithBreak">EachWithBreak</span>
<p>遍历集合的元素并为每个元素调用iteratee函数,当iteratee函数返回false时,终止遍历。</p>
<b>函数签名:</b>
```go
func (s Set[T]) EachWithBreak(iteratee func(item T) bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
s := set.NewSet(1, 2, 3, 4, 5)
var sum int
s.EachWithBreak(func(n int) bool {
if n > 3 {
return false
}
sum += n
return true
})
fmt.Println(sum) //6
}
```
### <span id="IsEmpty">IsEmpty</span>
<p>判断集合是否为空</p>
<b>函数签名:</b>
```go
func (s Set[T]) IsEmpty() bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet()
fmt.Println(set1.IsEmpty()) //false
fmt.Println(set2.IsEmpty()) //true
}
```
### <span id="Union">Union</span>
<p>求两个集合的并集</p>
<b>函数签名:</b>
```go
func (s Set[T]) Union(other Set[T]) Set[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set1.Union(set2)
fmt.Println(set3.Values()) //1,2,3,4,5
}
```
### <span id="Intersection">Intersection</span>
<p>求两个集合的交集</p>
<b>函数签名:</b>
```go
func (s Set[T]) Intersection(other Set[T]) Set[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set1.Intersection(set2)
fmt.Println(set3.Values()) //2,3
}
```
### <span id="SymmetricDifference">SymmetricDifference</span>
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>
<b>函数签名:</b>
```go
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set1.SymmetricDifference(set2)
fmt.Println(set3.Values()) //1,4,5
}
```
### <span id="Minus">Minus</span>
<p>创建一个集合,其元素在原始集中但不在比较集中</p>
<b>函数签名:</b>
```go
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set.NewSet(2, 3)
res1 := set1.Minus(set2)
fmt.Println(res1.Values()) //1
res2 := set2.Minus(set3)
fmt.Println(res2.Values()) //4,5
}
```
### <span id="Pop">Pop</span>
<p>删除并返回集合中的顶部元素</p>
<b>函数签名:</b>
```go
func (s Set[T]) Pop() (v T, ok bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
s := set.NewSet[int]()
s.Add(1)
s.Add(2)
s.Add(3)
val, ok = s.Pop()
fmt.Println(val) // 3
fmt.Println(ok) // true
}
```
-611
View File
@@ -1,611 +0,0 @@
# Stack
栈数据结构,包括ArrayStack(数组栈)和LinkedStack(链表栈)。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/stack/arraystack.go](https://github.com/duke-git/lancet/blob/main/datastructure/stack/arraystack.go)
- [https://github.com/duke-git/lancet/blob/main/datastructure/stack/linkedstack.go](https://github.com/duke-git/lancet/blob/main/datastructure/stack/linkedstack.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
### 1. ArrayStack(数组栈)
- [NewArrayStack](#NewArrayStack)
- [Push](#ArrayStack_Push)
- [Pop](#ArrayStack_Pop)
- [Peak](#ArrayStack_Peak)
- [Data](#ArrayStack_Data)
- [Size](#ArrayStack_Size)
- [IsEmpty](#ArrayStack_IsEmpty)
- [Clear](#ArrayStack_Clear)
### 2. LinkedStack(链表栈)
- [NewLinkedStack](#NewLinkedStack)
- [Push](#LinkedStack_Push)
- [Pop](#LinkedStack_Pop)
- [Peak](#LinkedStack_Peak)
- [Data](#LinkedStack_Data)
- [Size](#LinkedStack_Size)
- [IsEmpty](#LinkedStack_IsEmpty)
- [Clear](#LinkedStack_Clear)
- [Print](#LinkedStack_Print)
<div STYLE="page-break-after: always;"></div>
## 文档
### 1. ArrayStack
用切片实现栈结构
### <span id="NewArrayStack">NewArrayStack</span>
<p>返回ArrayStack指针实例</p>
<b>函数签名:</b>
```go
type ArrayStack[T any] struct {
data []T
length int
}
func NewArrayStack[T any]() *ArrayStack[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewArrayStack[int]()
fmt.Println(sk)
}
```
### <span id="ArrayStack_Push">Push</span>
<p>将元素加入数组栈</p>
<b>函数签名:</b>
```go
func (s *ArrayStack[T]) Push(value T)
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewArrayStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
fmt.Println(sk.Data()) //[]int{3, 2, 1}
}
```
### <span id="ArrayStack_Pop">Pop</span>
<p>删除栈顶元素并返回该元素指针</p>
<b>函数签名:</b>
```go
func (s *ArrayStack[T]) Pop() (*T, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewArrayStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
val, err := sk.Pop()
fmt.Println(err) //nil
fmt.Println(*val) //3
fmt.Println(sk.Data()) //[]int{2, 1}
}
```
### <span id="ArrayStack_Peak">Peak</span>
<p>返回栈顶元素指针</p>
<b>函数签名:</b>
```go
func (s *ArrayStack[T]) Peak() (*T, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewArrayStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
val, err := sk.Peak()
fmt.Println(err) //nil
fmt.Println(*val) //3
fmt.Println(sk.Data()) //[]int{3, 2, 1}
}
```
### <span id="ArrayStack_Data">Data</span>
<p>返回栈中所有元素组成的切片</p>
<b>函数签名:</b>
```go
func (s *ArrayStack[T]) Data() []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewArrayStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
fmt.Println(sk.Data()) //[]int{3, 2, 1}
}
```
### <span id="ArrayStack_Size">Size</span>
<p>返回栈中元素的数量</p>
<b>函数签名:</b>
```go
func (s *ArrayStack[T]) Size() int
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewArrayStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
fmt.Println(sk.Size()) //3
}
```
### <span id="ArrayStack_IsEmpty">IsEmpty</span>
<p>判断栈是否为空</p>
<b>函数签名:</b>
```go
func (s *ArrayStack[T]) IsEmpty() bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewArrayStack[int]()
fmt.Println(sk.IsEmpty()) //true
sk.Push(1)
sk.Push(2)
sk.Push(3)
fmt.Println(sk.IsEmpty()) //false
}
```
### <span id="ArrayStack_Clear">Clear</span>
<p>清空栈元素,使栈为空</p>
<b>函数签名:</b>
```go
func (s *ArrayStack[T]) Clear()
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewArrayStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
sk.Clear()
fmt.Println(sk.Data()) //[]int{}
}
```
### 2. LinkedStack
链表实现的栈结构。
### <span id="NewLinkedStack">NewLinkedStack</span>
<p>返回LinkedStack指针实例</p>
<b>函数签名:</b>
```go
type StackNode[T any] struct {
Value T
Next *StackNode[T]
}
type LinkedStack[T any] struct {
top *datastructure.StackNode[T]
length int
}
func NewLinkedStack[T any]() *LinkedStack[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewLinkedStack[int]()
fmt.Println(sk)
}
```
### <span id="LinkedStack_Push">Push</span>
<p>将元素加入链表栈</p>
<b>函数签名:</b>
```go
func (s *LinkedStack[T]) Push(value T)
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewLinkedStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
fmt.Println(sk.Data()) //[]int{3, 2, 1}
}
```
### <span id="LinkedStack_Pop">Pop</span>
<p>删除栈顶元素并返回该元素指针</p>
<b>函数签名:</b>
```go
func (s *LinkedStack[T]) Pop() (*T, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewLinkedStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
val, err := sk.Pop()
fmt.Println(err) //nil
fmt.Println(*val) //3
fmt.Println(sk.Data()) //[]int{2, 1}
}
```
### <span id="LinkedStack_Peak">Peak</span>
<p>返回栈顶元素指针</p>
<b>函数签名:</b>
```go
func (s *LinkedStack[T]) Peak() (*T, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewLinkedStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
val, err := sk.Peak()
fmt.Println(err) //nil
fmt.Println(*val) //3
fmt.Println(sk.Data()) //[]int{3, 2, 1}
}
```
### <span id="LinkedStack_Data">Data</span>
<p>返回栈中所有元素组成的切片</p>
<b>函数签名:</b>
```go
func (s *LinkedStack[T]) Data() []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewLinkedStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
fmt.Println(sk.Data()) //[]int{3, 2, 1}
}
```
### <span id="LinkedStack_Size">Size</span>
<p>返回栈中元素的数量</p>
<b>函数签名:</b>
```go
func (s *LinkedStack[T]) Size() int
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewLinkedStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
fmt.Println(sk.Size()) //3
}
```
### <span id="LinkedStack_IsEmpty">IsEmpty</span>
<p>判断栈是否为空</p>
<b>函数签名:</b>
```go
func (s *LinkedStack[T]) IsEmpty() bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewLinkedStack[int]()
fmt.Println(sk.IsEmpty()) //true
sk.Push(1)
sk.Push(2)
sk.Push(3)
fmt.Println(sk.IsEmpty()) //false
}
```
### <span id="LinkedStack_Clear">Clear</span>
<p>清空栈元素,使栈为空</p>
<b>函数签名:</b>
```go
func (s *LinkedStack[T]) Clear()
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewLinkedStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
sk.Clear()
fmt.Println(sk.Data()) //[]int{}
}
```
### <span id="LinkedStack_Print">Print</span>
<p>打印链表栈结构</p>
<b>函数签名:</b>
```go
func (s *LinkedStack[T]) Print()
```
<b>示例:</b>
```go
package main
import (
"fmt"
stack "github.com/duke-git/lancet/v2/datastructure/stack"
)
func main() {
sk := stack.NewLinkedStack[int]()
sk.Push(1)
sk.Push(2)
sk.Push(3)
sk.Print() //[ &{Value:3 Next:0xc000010260}, &{Value:2 Next:0xc000010250}, &{Value:1 Next:<nil>}, ]
}
```
-526
View File
@@ -1,526 +0,0 @@
# Tree
树是树节点的集合。 每个树节点都有一个值,一个指向左节点的左指针和一个指向右节点的右指针。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/tree/bstree.go](https://github.com/duke-git/lancet/blob/main/datastructure/tree/bstree.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
### 1. BSTree
- [NewBSTree](#NewBSTree)
- [Insert](#BSTree_Insert)
- [Delete](#BSTree_Delete)
- [PreOrderTraverse](#BSTree_PreOrderTraverse)
- [InOrderTraverse](#BSTree_InOrderTraverse)
- [PostOrderTraverse](#BSTree_PostOrderTraverse)
- [LevelOrderTraverse](#BSTree_LevelOrderTraverse)
- [Depth](#BSTree_Depth)
- [HasSubTree](#BSTree_HasSubTree)
- [Print](#BSTree_Print)
<div STYLE="page-break-after: always;"></div>
## 文档
## 1. BSTree
BSTree是一种二叉搜索树数据结构,其中每个节点有两个孩子,分别称为左孩子和右孩子。 在 BSTree 中:leftNode < rootNode < rightNode。 T类型应该实现lancetconstraints.Comparator。
### <span id="NewBSTree">NewBSTree</span>
<p>返回BSTree指针实例</p>
<b>函数签名:</b>
```go
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T]
type BSTree[T any] struct {
root *datastructure.TreeNode[T]
comparator lancetconstraints.Comparator
}
type TreeNode[T any] struct {
Value T
Left *TreeNode[T]
Right *TreeNode[T]
}
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
bstree := tree.NewBSTree(6, &intComparator{})
fmt.Println(bstree) //
}
```
### <span id="BSTree_Insert">Insert</span>
<p>将值插入二叉搜索树</p>
<b>函数签名:</b>
```go
func (t *BSTree[T]) Insert(data T)
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
bstree := tree.NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
fmt.Println(bstree.PreOrderTraverse()) //6, 5, 2, 4, 7
}
```
### <span id="BSTree_Delete">Delete</span>
<p>删除插入二叉搜索树中指定的值</p>
<b>函数签名:</b>
```go
func (t *BSTree[T]) Delete(data T)
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
bstree := tree.NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
bstree.Delete(4)
fmt.Println(bstree.PreOrderTraverse()) //2, 5, 6, 7
}
```
### <span id="BSTree_PreOrderTraverse">PreOrderTraverse</span>
<p>按前序遍历树节点</p>
<b>函数签名:</b>
```go
func (t *BSTree[T]) PreOrderTraverse() []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
bstree := tree.NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
fmt.Println(bstree.PreOrderTraverse()) //6, 5, 2, 4, 7
}
```
### <span id="BSTree_InOrderTraverse">InOrderTraverse</span>
<p>按中序遍历树节点</p>
<b>函数签名:</b>
```go
func (t *BSTree[T]) InOrderTraverse() []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
bstree := tree.NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
fmt.Println(bstree.InOrderTraverse()) //2, 4, 5, 6, 7
}
```
### <span id="BSTree_PostOrderTraverse">PostOrderTraverse</span>
<p>按后序遍历树节点</p>
<b>函数签名:</b>
```go
func (t *BSTree[T]) PostOrderTraverse() []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
bstree := tree.NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
fmt.Println(bstree.PostOrderTraverse()) //5, 2, 4, 7, 6
}
```
### <span id="BSTree_LevelOrderTraverse">LevelOrderTraverse</span>
<p>按节点层次遍历树节点</p>
<b>函数签名:</b>
```go
func (t *BSTree[T]) LevelOrderTraverse() []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
bstree := tree.NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
fmt.Println(bstree.LevelOrderTraverse()) //6, 5, 7, 2, 4
}
```
### <span id="BSTree_Depth">Depth</span>
<p>获取树的深度</p>
<b>函数签名:</b>
```go
func (t *BSTree[T]) Depth() int
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
bstree := tree.NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
fmt.Println(bstree.Depth()) //4
}
```
### <span id="BSTree_HasSubTree">HasSubTree</span>
<p>判断给定树是否是子树</p>
<b>函数签名:</b>
```go
func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
superTree := tree.NewBSTree(8, &intComparator{})
superTree.Insert(4)
superTree.Insert(5)
superTree.Insert(6)
superTree.Insert(9)
superTree.Insert(4)
subTree := tree.NewBSTree(5, &intComparator{})
subTree.Insert(4)
subTree.Insert(6)
fmt.Println(superTree.HasSubTree(subTree)) //true
fmt.Println(subTree.HasSubTree(superTree)) //false
}
```
### <span id="BSTree_Print">Print</span>
<p>打印树结构</p>
<b>函数签名:</b>
```go
func (t *BSTree[T]) Print()
```
<b>示例:</b>
```go
package main
import (
"fmt"
tree "github.com/duke-git/lancet/v2/datastructure/tree"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
bstree := tree.NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
fmt.Println(bstree.Print())
// 6
// / \
// / \
// / \
// / \
// 5 7
// /
// /
// 2
// \
// 4
}
```
File diff suppressed because it is too large Load Diff
-408
View File
@@ -1,408 +0,0 @@
# Function
function 函数包控制函数执行流程,包含部分函数式编程。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/function"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [After](#After)
- [Before](#Before)
- [CurryFn](#CurryFn)
- [Compose](#Compose)
- [Debounced](#Debounced)
- [Delay](#Delay)
- [Schedule](#Schedule)
- [Pipeline](#Pipeline)
- [Watcher](#Watcher)
<div STYLE="page-break-after: always;"></div>
## 文档
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
### <span id="After">After</span>
<p>创建一个函数,当他被调用n或更多次之后将马上触发fn</p>
<b>函数签名:</b>
```go
func After(n int, fn any) func(args ...any) []reflect.Value
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/eRD5k2vzUVX)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
fn := function.After(2, func() {
fmt.Println("hello")
})
fn()
fn()
// Output:
// hello
}
```
### <span id="Before">Before</span>
<p>创建一个函数,调用次数不超过n次,之后再调用这个函数,将返回一次最后调用fn的结果</p>
<b>函数签名:</b>
```go
func Before(n int, fn any) func(args ...any) []reflect.Value
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/0HqUDIFZ3IL)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
fn := function.Before(2, func() {
fmt.Println("hello")
})
fn()
fn()
fn()
fn()
// Output:
// hello
// hello
}
```
### <span id="CurryFn">CurryFn</span>
<p>创建柯里化函数</p>
<b>函数签名:</b>
```go
type CurryFn[T any] func(...T) T
func (cf CurryFn[T]) New(val T) func(...T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/5HopfDwANKX)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
add := func(a, b int) int {
return a + b
}
var addCurry function.CurryFn[int] = func(values ...int) int {
return add(values[0], values[1])
}
add1 := addCurry.New(1)
result := add1(2)
fmt.Println(result)
// Output:
// 3
}
```
### <span id="Compose">Compose</span>
<p>从右至左组合函数列表fnList,返回组合后的函数</p>
<b>函数签名:</b>
```go
func Compose[T any](fnList ...func(...T) T) func(...T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/KKfugD4PKYF)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
toUpper := func(strs ...string) string {
return strings.ToUpper(strs[0])
}
toLower := func(strs ...string) string {
return strings.ToLower(strs[0])
}
transform := function.Compose(toUpper, toLower)
result := transform("aBCde")
fmt.Println(result)
// Output:
// ABCDE
}
```
### <span id="Debounced">Debounced</span>
<p>创建一个debounced函数,该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。</p>
<b>函数签名:</b>
```go
func Debounced(fn func(), duration time.Duration) func()
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/absuEGB_GN7)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
count := 0
add := func() {
count++
}
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
debouncedAdd()
debouncedAdd()
debouncedAdd()
debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count)
debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count)
// Output:
// 1
// 2
}
```
### <span id="Delay">Delay</span>
<p>延迟delay时间后调用函数</p>
<b>函数签名:</b>
```go
func Delay(delay time.Duration, fn any, args ...any)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/Ivtc2ZE-Tye)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
var print = func(s string) {
fmt.Println(s)
}
function.Delay(2*time.Second, print, "hello")
// Output:
// hello
}
```
### <span id="Schedule">Schedule</span>
<p>每次持续时间调用函数,直到关闭返回的 bool chan</p>
<b>函数签名:</b>
```go
func Schedule(d time.Duration, fn any, args ...any) chan bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/hbON-Xeyn5N)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
count := 0
increase := func() {
count++
}
stop := function.Schedule(2*time.Second, increase)
time.Sleep(2 * time.Second)
close(stop)
fmt.Println(count)
// Output:
// 2
}
```
### <span id="Pipeline">Pipeline</span>
<p>执行函数pipeline.</p>
<b>函数签名:</b>
```go
func Pipeline[T any](funcs ...func(T) T) func(T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/mPdUVvj6HD6)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
addOne := func(x int) int {
return x + 1
}
double := func(x int) int {
return 2 * x
}
square := func(x int) int {
return x * x
}
fn := function.Pipeline(addOne, double, square)
result := fn(2)
fmt.Println(result)
// Output:
// 36
}
```
### <span id="Watcher">Watcher</span>
<p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p>
<b>函数签名:</b>
```go
type Watcher struct {
startTime int64
stopTime int64
excuting bool
}
func NewWatcher() *Watcher
func (w *Watcher) Start()
func (w *Watcher) Stop()
func (w *Watcher) Reset()
func (w *Watcher) GetElapsedTime() time.Duration
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/l2yrOpCLd1I)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
w := function.NewWatcher()
w.Start()
longRunningTask()
fmt.Println(w.excuting) //true
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
w.Reset()
}
func longRunningTask() {
var slice []int64
for i := 0; i < 10000000; i++ {
slice = append(slice, int64(i))
}
}
```
File diff suppressed because it is too large Load Diff
-982
View File
@@ -1,982 +0,0 @@
# Mathutil
mathutil 包实现了一些数学计算的函数.
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/mathutil"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Average](#Average)
- [Exponent](#Exponent)
- [Fibonacci](#Fibonacci)
- [Factorial](#Factorial)
- [Max](#Max)
- [MaxBy](#MaxBy)
- [Min](#Min)
- [MinBy](#MaxBy)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
- [Range](#Range)
- [RangeWithStep](#RangeWithStep)
- [AngleToRadian](#AngleToRadian)
- [RadianToAngle](#RadianToAngle)
- [PointDistance](#PointDistance)
- [IsPrime](#IsPrime)
- [GCD](#GCD)
- [LCM](#LCM)
- [Cos](#Cos)
- [Sin](#Sin)
- [Log](#Log)
- [Sum](#Sum)
- [Abs](#Abs)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="../../styles/api_doc.css">
## 文档
### <span id="Average">Average</span>
<p>计算平均数. 可能需要对结果调用RoundToFloat方法四舍五入</p>
<b>函数签名:</b>
```go
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/HFd70x4DrMj)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Average(1, 2)
avg := mathutil.Average(1.2, 1.4)
result2 := mathutil.RoundToFloat(avg, 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1
// 1.3
}
```
### <span id="Exponent">Exponent</span>
<p>指数计算(x的n次方)</p>
<b>函数签名:</b>
```go
func Exponent(x, n int64) int64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/Vv7LBwER-pz)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Exponent(10, 0)
result2 := mathutil.Exponent(10, 1)
result3 := mathutil.Exponent(10, 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 10
// 100
}
```
### <span id="Fibonacci">Fibonacci</span>
<p>计算斐波那契数列的第n个数</p>
<b>函数签名:</b>
```go
func Fibonacci(first, second, n int) int
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/IscseUNMuUc)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Fibonacci(1, 1, 1)
result2 := mathutil.Fibonacci(1, 1, 2)
result3 := mathutil.Fibonacci(1, 1, 5)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 1
// 5
}
```
### <span id="Factorial">Factorial</span>
<p>计算阶乘</p>
<b>函数签名:</b>
```go
func Factorial(x uint) uint
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/tt6LdOK67Nx)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Factorial(1)
result2 := mathutil.Factorial(2)
result3 := mathutil.Factorial(3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 6
}
```
### <span id="Max">Max</span>
<p>返回参数中的最大数</p>
<b>函数签名:</b>
```go
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/cN8DHI0rTkH)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Max(1, 2, 3)
result2 := mathutil.Max(1.2, 1.4, 1.1, 1.4)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 3
// 1.4
}
```
### <span id="MaxBy">MaxBy</span>
<p>使用给定的比较器函数返回切片的最大值</p>
<b>函数签名:</b>
```go
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/pbe2MT-7DV2)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
result2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
result3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// abc
// abd
//
}
```
### <span id="Min">Min</span>
<p>返回参数中的最小数</p>
<b>函数签名:</b>
```go
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/pbe2MT-7DV2)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Min(1, 2, 3)
result2 := mathutil.Min(1.2, 1.4, 1.1, 1.4)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1
// 1.1
}
```
### <span id="MinBy">MinBy</span>
<p>使用给定的比较器函数返回切片的最小值</p>
<b>函数签名:</b>
```go
func MinBy[T any](slice []T, comparator func(T, T) bool) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/N9qgYg_Ho6f)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
result2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
result3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// a
// ab
//
}
```
### <span id="Percent">Percent</span>
<p>计算百分比,保留n位小数</p>
<b>函数签名:</b>
```go
func Percent(val, total float64, n int) float64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/s0NdFCtwuyd)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Percent(1, 2, 2)
result2 := mathutil.Percent(0.1, 0.3, 2)
result3 := mathutil.Percent(-30305, 408420, 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 50
// 33.33
// -7.42
}
```
### <span id="RoundToFloat">RoundToFloat</span>
<p>四舍五入,保留n位小数</p>
<b>函数签名:</b>
```go
func RoundToFloat(x float64, n int) float64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ghyb528JRJL)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.RoundToFloat(0.124, 2)
result2 := mathutil.RoundToFloat(0.125, 2)
result3 := mathutil.RoundToFloat(0.125, 3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.13
// 0.125
}
```
### <span id="RoundToString">RoundToString</span>
<p>四舍五入,保留n位小数,返回字符串</p>
<b>函数签名:</b>
```go
func RoundToString(x float64, n int) string
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/kZwpBRAcllO)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.RoundToString(0.124, 2)
result2 := mathutil.RoundToString(0.125, 2)
result3 := mathutil.RoundToString(0.125, 3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.13
// 0.125
}
```
### <span id="TruncRound">TruncRound</span>
<p>截短n位小数(不进行四舍五入)</p>
<b>函数签名:</b>
```go
func TruncRound(x float64, n int) float64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/aumarSHIGzP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.TruncRound(0.124, 2)
result2 := mathutil.TruncRound(0.125, 2)
result3 := mathutil.TruncRound(0.125, 3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.12
// 0.125
}
```
### <span id="Range">Range</span>
<p>根据指定的起始值和数量,创建一个数字切片。</p>
<b>函数签名:</b>
```go
func Range[T constraints.Integer | constraints.Float](start T, count int) []T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/9ke2opxa8ZP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Range(1, 4)
result2 := mathutil.Range(1, -4)
result3 := mathutil.Range(-4, 4)
result4 := mathutil.Range(1.0, 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [1 2 3 4]
// [1 2 3 4]
// [-4 -3 -2 -1]
// [1 2 3 4]
}
```
### <span id="RangeWithStep">RangeWithStep</span>
<p>根据指定的起始值,结束值,步长,创建一个数字切片。</p>
<b>函数签名:</b>
```go
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/akLWz0EqOSM)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.RangeWithStep(1, 4, 1)
result2 := mathutil.RangeWithStep(1, -1, 0)
result3 := mathutil.RangeWithStep(-4, 1, 2)
result4 := mathutil.RangeWithStep(1.0, 4.0, 1.1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [1 2 3]
// []
// [-4 -2 0]
// [1 2.1 3.2]
}
```
### <span id="AngleToRadian">AngleToRadian</span>
<p>将角度值转为弧度值</p>
<b>函数签名:</b>
```go
func AngleToRadian(angle float64) float64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/CIvlICqrHql)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.AngleToRadian(45)
result2 := mathutil.AngleToRadian(90)
result3 := mathutil.AngleToRadian(180)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.7853981633974483
// 1.5707963267948966
// 3.141592653589793
}
```
### <span id="RadianToAngle">RadianToAngle</span>
<p>将弧度值转为角度值</p>
<b>函数签名:</b>
```go
func RadianToAngle(radian float64) float64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/dQtmOTUOMgi)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.RadianToAngle(math.Pi)
result2 := mathutil.RadianToAngle(math.Pi / 2)
result3 := mathutil.RadianToAngle(math.Pi / 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 180
// 90
// 45
}
```
### <span id="PointDistance">PointDistance</span>
<p>计算两个坐标点的距离</p>
<b>函数签名:</b>
```go
func PointDistance(x1, y1, x2, y2 float64) float64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/RrG4JIaziM8)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.PointDistance(1, 1, 4, 5)
fmt.Println(result1)
// Output:
// 5
}
```
### <span id="IsPrime">IsPrime</span>
<p>判断质数。</p>
<b>函数签名:</b>
```go
func IsPrime(n int) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/Rdd8UTHZJ7u)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.IsPrime(-1)
result2 := mathutil.IsPrime(0)
result3 := mathutil.IsPrime(1)
result4 := mathutil.IsPrime(2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
}
```
### <span id="GCD">GCD</span>
<p>计算最大公约数。</p>
<b>函数签名:</b>
```go
func GCD[T constraints.Integer](integers ...T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/CiEceLSoAKB)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.GCD(1, 1)
result2 := mathutil.GCD(1, -1)
result3 := mathutil.GCD(-1, 1)
result4 := mathutil.GCD(-1, -1)
result5 := mathutil.GCD(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// 1
// -1
// -1
// 3
}
```
### <span id="LCM">LCM</span>
<p>计算最小公倍数。</p>
<b>函数签名:</b>
```go
func LCM[T constraints.Integer](integers ...T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/EjcZxfY7G_g)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.LCM(1, 1)
result2 := mathutil.LCM(1, 2)
result3 := mathutil.LCM(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 18
}
```
### <span id="Cos">Cos</span>
<p>计算弧度的余弦值</p>
<b>函数签名:</b>
```go
func Cos(radian float64, precision ...int) float64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/Sm89LoIfvFq)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Cos(0)
result2 := mathutil.Cos(90)
result3 := mathutil.Cos(180)
result4 := mathutil.Cos(math.Pi)
result5 := mathutil.Cos(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// -0.447
// -0.598
// -1
// 0
}
```
### <span id="Sin">Sin</span>
<p>计算弧度的正弦值</p>
<b>函数签名:</b>
```go
func Sin(radian float64, precision ...int) float64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/TWMQlMywDsP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Sin(0)
result2 := mathutil.Sin(90)
result3 := mathutil.Sin(180)
result4 := mathutil.Sin(math.Pi)
result5 := mathutil.Sin(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 0
// 0.894
// -0.801
// 0
// 1
}
```
### <span id="Log">Log</span>
<p>计算以base为底n的对数。</p>
<b>函数签名:</b>
```go
func Log(n, base float64) float64
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/_d4bi8oyhat)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Log(8, 2)
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 3
// 2.32
// 3
}
```
### <span id="Sum">Sum</span>
<p>求传入参数之和。</p>
<b>函数签名:</b>
```go
func Sum[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/1To2ImAMJA7)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Sum(1, 2)
result2 := mathutil.Sum(0.1, float64(1))
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 3
// 1.1
}
```
### <span id="Abs">Abs</span>
<p>求绝对值。</p>
<b>函数签名:</b>
```go
func Abs[T constraints.Integer | constraints.Float](x T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/fsyBh1Os-1d)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := Abs(-1)
result2 := Abs(-0.1)
result3 := Abs(float32(0.2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 0.1
// 0.2
}
```
-229
View File
@@ -1,229 +0,0 @@
# Pointer
pointer 包支持一些指针类型的操作。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/pointer/pointer.go](https://github.com/duke-git/lancet/blob/main/pointer/pointer.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/pointer"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Of](#Of)
- [Unwrap](#Unwrap)
- [ExtractPointer](#ExtractPointer)
- [UnwarpOr](#UnwarpOr)
- [UnwarpOrDefault](#UnwarpOrDefault)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
### <span id="Of">Of</span>
<p>返回传入参数的指针值。</p>
<b>函数签名:</b>
```go
func Of[T any](v T) *T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/HFd70x4DrMj)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
result1 := pointer.Of(123)
result2 := pointer.Of("abc")
fmt.Println(*result1)
fmt.Println(*result2)
// Output:
// 123
// abc
}
```
### <span id="Unwrap">Unwrap</span>
<p>返回传入指针指向的值。</p>
<b>函数签名:</b>
```go
func Unwrap[T any](p *T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/cgeu3g7cjWb)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 123
b := "abc"
result1 := pointer.Unwrap(&a)
result2 := pointer.Unwrap(&b)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 123
// abc
}
```
### <span id="ExtractPointer">ExtractPointer</span>
<p>返回传入interface的底层值。</p>
<b>函数签名:</b>
```go
func ExtractPointer(value any) any
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/D7HFjeWU2ZP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 1
b := &a
c := &b
d := &c
result := pointer.ExtractPointer(d)
fmt.Println(result)
// Output:
// 1
}
```
### <span id="UnwarpOr">UnwarpOr</span>
<p>返回指针的值,如果指针为零值,则返回fallback。</p>
<b>函数签名:</b>
```go
UnwarpOr[T any](p *T, fallback T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/mmNaLC38W8C)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 123
b := "abc"
var c *int
var d *string
result1 := pointer.UnwarpOr(&a, 456)
result2 := pointer.UnwarpOr(&b, "abc")
result3 := pointer.UnwarpOr(c, 456)
result4 := pointer.UnwarpOr(d, "def")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 123
// abc
// 456
// def
}
```
### <span id="UnwarpOrDefault">UnwarpOrDefault</span>
<p>返回指针的值,如果指针为零值,则返回相应零值。</p>
<b>函数签名:</b>
```go
UnwarpOrDefault[T any](p *T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ZnGIHf8_o4E)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 123
b := "abc"
var c *int
var d *string
result1 := pointer.UnwarpOrDefault(&a)
result2 := pointer.UnwarpOrDefault(&b)
result3 := pointer.UnwarpOrDefault(c)
result4 := pointer.UnwarpOrDefault(d)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 123
// abc
// 0
//
}
```
@@ -6,9 +6,9 @@ Package compare provides a lightweight comparison function on any type.
## Source:
- [https://github.com/duke-git/lancet/blob/main/compare/compare.go](https://github.com/duke-git/lancet/blob/main/compare/compare.go)
- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go)
- [https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go)
- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go)
<div STYLE="page-break-after: always;"></div>
@@ -16,7 +16,7 @@ Package compare provides a lightweight comparison function on any type.
```go
import (
"github.com/duke-git/lancet/v2/condition"
"github.com/duke-git/lancet/condition"
)
```
@@ -30,19 +30,16 @@ import (
- [GreaterThan](#GreaterThan)
- [LessOrEqual](#LessOrEqual)
- [GreaterOrEqual](#GreaterOrEqual)
- [InDelta](#InDelta)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## Documentation
### <span id="Equal">Equal</span>
<p>Checks if two values are equal or not. (check both type and value)</p>
<b>Signature: <span class="run-container">[Run](https://go.dev/play/p/wmVxR-to4lz)</span></b>
<b>Signature:</b>
```go
func Equal(left, right any) bool
@@ -55,7 +52,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -91,7 +88,7 @@ func main() {
<p>Checks if two values are equal or not. (check value only)</p>
<b>Signature: <span class="run-container">[Run](https://go.dev/play/p/fxnna_LLD9u)</span></b>
<b>Signature:</b>
```go
func EqualValue(left, right any) bool
@@ -104,7 +101,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -130,7 +127,7 @@ func main() {
<p>Checks if value `left` less than value `right`.</p>
<b>Signature: <span class="run-container">[Run](https://go.dev/play/p/cYh7FQQj0ne)</span></b>
<b>Signature:</b>
```go
func LessThan(left, right any) bool
@@ -143,7 +140,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -185,14 +182,14 @@ func main() {
func GreaterThan(left, right any) bool
```
<b>Example: <span class="run-container">[Run](https://go.dev/play/p/9-NYDFZmIMp)</span></b>
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -237,14 +234,14 @@ func main() {
func LessOrEqual(left, right any) bool
```
<b>Example: <span class="run-container">[Run](https://go.dev/play/p/e4T_scwoQzp)</span></b>
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -280,7 +277,7 @@ func main() {
<p>Checks if value `left` less greater or equal than value `right`.</p>
<b>Signature: <span class="run-container">[Run](https://go.dev/play/p/vx8mP0U8DFk)</span></b>
<b>Signature:</b>
```go
func GreaterOrEqual(left, right any) bool
@@ -293,7 +290,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -327,50 +324,3 @@ func main() {
// false
}
```
### <span id="InDelta">InDelta</span>
<p>Checks if two values are equal or not within a delta.</p>
<b>Signature: <span class="run-container">[Run](https://go.dev/play/p/TuDdcNtMkjo)</span></b>
```go
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := InDelta(1, 1, 0)
result2 := InDelta(1, 2, 0)
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
result4 := InDelta(2.0/3.0, 0.0, 0.001)
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// false
// true
// false
// false
// true
}
```
@@ -6,9 +6,9 @@ compare包提供几个轻量级的类型比较函数。
## 源码:
- [https://github.com/duke-git/lancet/blob/main/compare/compare.go](https://github.com/duke-git/lancet/blob/main/compare/compare.go)
- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go)
- [https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go)
- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go)
<div STYLE="page-break-after: always;"></div>
@@ -16,7 +16,7 @@ compare包提供几个轻量级的类型比较函数。
```go
import (
"github.com/duke-git/lancet/v2/condition"
"github.com/duke-git/lancet/condition"
)
```
@@ -30,14 +30,10 @@ import (
- [GreaterThan](#GreaterThan)
- [LessOrEqual](#LessOrEqual)
- [GreaterOrEqual](#GreaterOrEqual)
- [InDelta](#InDelta)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
## Documentation
### <span id="Equal">Equal</span>
@@ -49,14 +45,14 @@ import (
func Equal(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/wmVxR-to4lz)</span></b>
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -98,14 +94,14 @@ func main() {
func EqualValue(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/fxnna_LLD9u)</span></b>
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -137,14 +133,14 @@ func main() {
func LessThan(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/cYh7FQQj0ne)</span></b>
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -186,14 +182,14 @@ func main() {
func GreaterThan(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/9-NYDFZmIMp)</span></b>
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -238,14 +234,14 @@ func main() {
func LessOrEqual(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/e4T_scwoQzp)</span></b>
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -287,14 +283,14 @@ func main() {
func GreaterOrEqual(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/vx8mP0U8DFk)</span></b>
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
"github.com/duke-git/lancet/compare"
)
func main() {
@@ -328,50 +324,3 @@ func main() {
// false
}
```
### <span id="InDelta">InDelta</span>
<p>检查增量内两个值是否相等。</p>
<b>函数签名:</b>
```go
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/TuDdcNtMkjo)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := InDelta(1, 1, 0)
result2 := InDelta(1, 2, 0)
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
result4 := InDelta(2.0/3.0, 0.0, 0.001)
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// false
// true
// false
// false
// true
}
```

Some files were not shown because too many files have changed in this diff Show More