mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-06 05:42:25 +08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91bc1a512c | ||
|
|
8753255026 | ||
|
|
9cf1f13fec | ||
|
|
5d78bae4bb | ||
|
|
27777eecc0 | ||
|
|
1a7e0e8792 | ||
|
|
02b7aa8f33 | ||
|
|
f188d3d08f | ||
|
|
0c924b859e | ||
|
|
c5a5a07462 | ||
|
|
1ff5dd6df0 | ||
|
|
b5f86a488c | ||
|
|
1390b7a964 | ||
|
|
c3e28a9fc0 | ||
|
|
e924429d6e | ||
|
|
7079b1f704 | ||
|
|
40cad365c0 | ||
|
|
6386ab908d | ||
|
|
bb563724c7 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@ fileutil/*.txt
|
||||
fileutil/*.zip
|
||||
fileutil/*.link
|
||||
fileutil/unzip/*
|
||||
fileutil/tempdir/*
|
||||
slice/testdata/*
|
||||
cryptor/*.pem
|
||||
test
|
||||
133
README.md
133
README.md
@@ -4,7 +4,7 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -75,33 +75,34 @@ func main() {
|
||||
|
||||
### <span id="index">Index<span>
|
||||
|
||||
- [Algorithm](#Algorithm)
|
||||
- [Compare](#Compare)
|
||||
- [Concurrency](#Concurrency)
|
||||
- [Condition](#Condition)
|
||||
- [Convertor](#Convertor)
|
||||
- [Cryptor](#Cryptor)
|
||||
- [Datetime](#Datetime)
|
||||
- [Datastructure](#Datastructure)
|
||||
- [Fileutil](#Fileutil)
|
||||
- [Formatter](#Formatter)
|
||||
- [Function](#Function)
|
||||
- [Maputil](#Maputil)
|
||||
- [Mathutil](#Mathutil)
|
||||
- [Netutil](#Netutil)
|
||||
- [Pointer](#Pointer)
|
||||
- [Random](#Random)
|
||||
- [Retry](#Retry)
|
||||
- [Slice](#Slice)
|
||||
- [Stream](#Stream)
|
||||
- [Structs](#Structs)
|
||||
- [Strutil](#Strutil)
|
||||
- [System](#System)
|
||||
- [Tuple](#Tuple)
|
||||
- [Validator](#Validator)
|
||||
- [Xerror](#Xerror)
|
||||
- [Algorithm](#user-content-algorithm)
|
||||
- [Compare](#user-content-compare)
|
||||
- [Concurrency](#user-content-concurrency)
|
||||
- [Condition](#user-content-condition)
|
||||
- [Convertor](#user-content-convertor)
|
||||
- [Cryptor](#user-content-cryptor)
|
||||
- [Datetime](#user-content-datetime)
|
||||
- [Datastructure](#user-content-datastructure)
|
||||
- [Fileutil](#user-content-fileutil)
|
||||
- [Formatter](#user-content-formatter)
|
||||
- [Function](#user-content-function)
|
||||
- [Maputil](#user-content-maputil)
|
||||
- [Mathutil](#user-content-mathutil)
|
||||
- [Netutil](#user-content-netutil)
|
||||
- [Pointer](#user-content-pointer)
|
||||
- [Random](#user-content-random)
|
||||
- [Retry](#user-content-retry)
|
||||
- [Slice](#user-content-slice)
|
||||
- [Stream](#user-content-stream)
|
||||
- [Structs](#user-content-structs)
|
||||
- [Strutil](#user-content-strutil)
|
||||
- [System](#user-content-system)
|
||||
- [Tuple](#user-content-tuple)
|
||||
- [Validator](#user-content-validator)
|
||||
- [Xerror](#user-content-xerror)
|
||||
|
||||
<h3 id="Algorithm"> 1. Algorithm package implements some basic algorithm. eg. sort, search. <a href="#index">index</span> </h3>
|
||||
|
||||
<h3 id="algorithm">1. Algorithm package implements some basic algorithm. eg. sort, search. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/algorithm"
|
||||
@@ -146,7 +147,7 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)]
|
||||
[[play](https://go.dev/play/p/-EZjgOURufP)]
|
||||
|
||||
<h3 id="Compare"> 2. Compare package provides a lightweight comparison function on any type. <a href="#index">index</span> </h3>
|
||||
<h3 id="compare"> 2. Compare package provides a lightweight comparison function on any type. <a href="#index">index</a> </h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/compare"
|
||||
@@ -172,8 +173,10 @@ import "github.com/duke-git/lancet/v2/compare"
|
||||
- **<big>GreaterOrEqual</big>** : Checks if value `left` less greater or equal than value `right`.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#GreaterOrEqual)]
|
||||
[[play](https://go.dev/play/p/vx8mP0U8DFk)]
|
||||
- **<big>InDelta</big>** : Checks if two values are equal or not within a delta.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#InDelta)]
|
||||
|
||||
<h3 id="Concurrency"> 3. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async. <a href="#index">index</span> </h3>
|
||||
<h3 id="concurrency"> 3. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async. <a href="#index">index</a> </h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/concurrency"
|
||||
@@ -212,7 +215,7 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)]
|
||||
[[play](https://go.dev/play/p/3TQPKnCirrP)]
|
||||
|
||||
<h3 id="Condition"> 4. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator... <a href="#index">index</span> </h3>
|
||||
<h3 id="condition"> 4. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator... <a href="#index">index</a> </h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/condition"
|
||||
@@ -245,7 +248,7 @@ import "github.com/duke-git/lancet/v2/condition"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#TernaryOperator)]
|
||||
[[play](https://go.dev/play/p/ElllPZY0guT)]
|
||||
|
||||
<h3 id="Convertor"> 5. Convertor package contains some functions for data convertion. <a href="#index">index</span> </h3>
|
||||
<h3 id="convertor"> 5. Convertor package contains some functions for data convertion. <a href="#index">index</a> </h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/convertor"
|
||||
@@ -317,7 +320,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#GbkToUtf8)]
|
||||
[[play](https://go.dev/play/p/OphmHCN_9u8)]
|
||||
|
||||
<h3 id="Cryptor"> 6. Cryptor package is for data encryption and decryption.</span> <a href="#index">index</span></h3>
|
||||
<h3 id="cryptor"> 6. Cryptor package is for data encryption and decryption. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/cryptor"
|
||||
@@ -395,26 +398,31 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/1UI4oQ4WXKM)]
|
||||
- **<big>HmacSha1WithBase64</big>** : return the hmac hash of string use sha1 with base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha1WithBase64)]
|
||||
[[play](https://go.dev/play/p/47JmmGrnF7B)]
|
||||
- **<big>HmacSha256</big>** : return the hmac hash of string use sha256.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha256)]
|
||||
[[play](https://go.dev/play/p/HhpwXxFhhC0)]
|
||||
- **<big>HmacSha256WithBase64</big>** : return the hmac hash of string use sha256 with base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha256WithBase64)]
|
||||
[[play](https://go.dev/play/p/EKbkUvPTLwO)]
|
||||
- **<big>HmacSha512</big>** : return the hmac hash of string use sha512.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha512)]
|
||||
[[play](https://go.dev/play/p/59Od6m4A0Ud)]
|
||||
- **<big>HmacSha512WithBase64</big>** : return the hmac hash of string use sha512 with base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha512WithBase64)]
|
||||
[[play](https://go.dev/play/p/c6dSe3E2ydU)]
|
||||
- **<big>Md5Byte</big>** : return the md5 string of byte slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5Byte)]
|
||||
[[play](https://go.dev/play/p/suraalH8lyC)]
|
||||
- **<big>Md5ByteWithBase64</big>** : return the md5 string of byte slice with base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5ByteWithBase64)]
|
||||
[[play](https://go.dev/play/p/Tcb-Z7LN2ax)]
|
||||
- **<big>Md5String</big>** : return the md5 value of string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5String)]
|
||||
[[play](https://go.dev/play/p/1bLcVetbTOI)]
|
||||
- **<big>Md5StringWithBase64</big>** : return the md5 value of string with base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5StringWithBase64)]
|
||||
[[play](https://go.dev/play/p/Lx4gH7Vdr5_y)]
|
||||
- **<big>Md5File</big>** : return the md5 value of file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5File)]
|
||||
- **<big>Sha1</big>** : return the sha1 value (SHA-1 hash algorithm) of base64 string.
|
||||
@@ -422,16 +430,19 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/_m_uoD1deMT)]
|
||||
- **<big>Sha1WithBase64</big>** : return the sha1 value (SHA-1 hash algorithm) of string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha1WithBase64)]
|
||||
[[play](https://go.dev/play/p/fSyx-Gl2l2-)]
|
||||
- **<big>Sha256</big>** : return the sha256 value (SHA-256 hash algorithm) of string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha256)]
|
||||
[[play](https://go.dev/play/p/tU9tfBMIAr1)]
|
||||
- **<big>Sha256WithBase64</big>** : return the sha256 value (SHA256 hash algorithm) of base64 string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha256WithBase64)]
|
||||
[[play](https://go.dev/play/p/85IXJHIal1k)]
|
||||
- **<big>Sha512</big>** : return the sha512 value (SHA-512 hash algorithm) of string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha512)]
|
||||
[[play](https://go.dev/play/p/3WsvLYZxsHa)]
|
||||
- **<big>Sha512WithBase64</big>** : return the sha512 value (SHA-512 hash algorithm) of base64 string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha512WithBase64)]
|
||||
[[play](https://go.dev/play/p/q_fY2rA-k5I)]
|
||||
- **<big>GenerateRsaKey</big>** : create rsa private and public pemo file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#GenerateRsaKey)]
|
||||
[[play](https://go.dev/play/p/zutRHrDqs0X)]
|
||||
@@ -442,7 +453,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaDecrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
|
||||
<h3 id="Datetime"> 7. Datetime package supports date and time format and compare. <a href="#index">index</span></h3>
|
||||
<h3 id="datetime"> 7. Datetime package supports date and time format and compare. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/datetime"
|
||||
@@ -563,19 +574,25 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[play](https://go.dev/play/p/cupRM5aZOIY)]
|
||||
- **<big>NowDateOrTime</big>** : returns current datetime with specific format and timezone.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NowDateOrTime)]
|
||||
[[play](https://go.dev/play/p/EZ-begEjtT0)]
|
||||
- **<big>Timestamp</big>** : returns current second timestamp.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#Timestamp)]
|
||||
- **<big>TimestampMilli</big>** : returns current mill second timestamp.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#TimestampMilli)]
|
||||
[[play](https://go.dev/play/p/4gvEusOTu1T)]
|
||||
- **<big>TimestampMicro</big>** : returns current micro second timestamp.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#TimestampMicro)]
|
||||
[[play](https://go.dev/play/p/2maANglKHQE)]
|
||||
- **<big>TimestampNano</big>** : returns current nano second timestamp.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#TimestampNano)]
|
||||
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
|
||||
|
||||
<h3 id="Datastructure"> 8. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph. <a href="#index">index</span></h3>
|
||||
|
||||
<h3 id="datastructure"> 8. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
import copyonwritelist "github.com/duke-git/lancet/v2/datastructure/copyonwritelist"
|
||||
import link "github.com/duke-git/lancet/v2/datastructure/link"
|
||||
import stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
import queue "github.com/duke-git/lancet/v2/datastructure/queue"
|
||||
@@ -589,6 +606,8 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
|
||||
- **<big>List</big>** : a linear table, implemented with slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/list.md)]
|
||||
- **<big>CopyOnWriteList</big>** : a thread-safe list implementation that uses go slicing as its base.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/copyonwritelist.md)]
|
||||
- **<big>Link</big>** : link list structure, contains singly link and doubly link.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/link.md)]
|
||||
- **<big>Stack</big>** : stack structure(fifo), contains array stack and link stack.
|
||||
@@ -604,7 +623,7 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
- **<big>Hashmap</big>** : hash map structure.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)]
|
||||
|
||||
<h3 id="Fileutil"> 9. Fileutil package implements some basic functions for file operations. <a href="#index">index</span></h3>
|
||||
<h3 id="fileutil"> 9. Fileutil package implements some basic functions for file operations. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -687,7 +706,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteStringToFile)]
|
||||
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
|
||||
|
||||
<h3 id="Formatter"> 10. Formatter contains some functions for data formatting. <a href="#index">index</span></h3>
|
||||
<h3 id="formatter"> 10. Formatter contains some functions for data formatting. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/formatter"
|
||||
@@ -717,7 +736,7 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#ParseBinaryBytes)]
|
||||
[[play](https://go.dev/play/p/69v1tTT62x8)]
|
||||
|
||||
<h3 id="Function"> 11. Function package can control the flow of function execution and support part of functional programming. <a href="#index">index</span></h3>
|
||||
<h3 id="function"> 11. Function package can control the flow of function execution and support part of functional programming. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/function"
|
||||
@@ -753,7 +772,7 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
|
||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||
|
||||
<h3 id="Maputil"> 12. Maputil package includes some functions to manipulate map. <a href="#index">index</span></h3>
|
||||
<h3 id="maputil"> 12. Maputil package includes some functions to manipulate map. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -826,24 +845,34 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
- **<big>HasKey</big>** : checks if map has key or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#HasKey)]
|
||||
[[play](https://go.dev/play/p/isZZHOsDhFc)]
|
||||
- **<big>NewConcurrentMap</big>** : creates a ConcurrentMap with specific shard count.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#NewConcurrentMap)]
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
- **<big>ConcurrentMap_Set</big>** : set the value for a key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Set)]
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
- **<big>ConcurrentMap_Get</big>** : get the value stored in the map for a key, or nil if no.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Get)]
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
- **<big>ConcurrentMap_GetOrSet</big>** : returns the existing value for the key if present.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_GetOrSet)]
|
||||
[[play](https://go.dev/play/p/aDcDApOK01a)]
|
||||
- **<big>ConcurrentMap_Delete</big>** : delete the value for a key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Delete)]
|
||||
[[play](https://go.dev/play/p/uTIJZYhpVMS)]
|
||||
- **<big>ConcurrentMap_GetAndDelete</big>** :returns the existing value for the key if present and then delete the value for the key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_GetAndDelete)]
|
||||
[[play](https://go.dev/play/p/ZyxeIXSZUiM)]
|
||||
- **<big>ConcurrentMap_Has</big>** : checks if map has the value for a key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Has)]
|
||||
[[play](https://go.dev/play/p/C8L4ul9TVwf)]
|
||||
- **<big>ConcurrentMap_Range</big>** : calls iterator sequentially for each key and value present in each of the shards in the map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Range)]
|
||||
[[play](https://go.dev/play/p/iqcy7P8P0Pr)]
|
||||
|
||||
<h3 id="Mathutil"> 13. Mathutil package implements some functions for math calculation. <a href="#index">index</span></h3>
|
||||
|
||||
<h3 id="mathutil"> 13. Mathutil package implements some functions for math calculation. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/mathutil"
|
||||
@@ -924,7 +953,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Sum)]
|
||||
[[play](https://go.dev/play/p/1To2ImAMJA7)]
|
||||
|
||||
<h3 id="Netutil"> 14. Netutil package contains functions to get net information and send http request. <a href="#index">index</a></h3>
|
||||
<h3 id="netutil"> 14. Netutil package contains functions to get net information and send http request. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/netutil"
|
||||
@@ -997,7 +1026,7 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsTelnetConnected)]
|
||||
[[play](https://go.dev/play/p/yiLCGtQv_ZG)]
|
||||
|
||||
<h3 id="Pointer"> 15. Pointer package contains some util functions to operate go pointer. <a href="#index">index</a></h3>
|
||||
<h3 id="pointer"> 15. Pointer package contains some util functions to operate go pointer. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/pointer"
|
||||
@@ -1021,7 +1050,7 @@ import "github.com/duke-git/lancet/v2/pointer"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer.md#UnwrapOrDefault)]
|
||||
[[play](https://go.dev/play/p/ZnGIHf8_o4E)]
|
||||
|
||||
<h3 id="Random"> 16. Random package implements some basic functions to generate random int and string. <a href="#index">index</a></h3>
|
||||
<h3 id="random"> 16. Random package implements some basic functions to generate random int and string. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/random"
|
||||
@@ -1057,7 +1086,7 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandUniqueIntSlice)]
|
||||
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
|
||||
|
||||
<h3 id="Retry"> 17. Retry package is for executing a function repeatedly until it was successful or canceled by the context. <a href="#index">index</a></h3>
|
||||
<h3 id="retry"> 17. Retry package is for executing a function repeatedly until it was successful or canceled by the context. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/retry"
|
||||
@@ -1081,7 +1110,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)]
|
||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||
|
||||
<h3 id="Slice"> 18. Slice contains some functions to manipulate slice. <a href="#index">index</a></h3>
|
||||
<h3 id="slice"> 18. Slice contains some functions to manipulate slice. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
@@ -1295,8 +1324,10 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||
- **<big>Join</big>** : join the slice item with specify separator.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Join)]
|
||||
[[play](https://go.dev/play/p/huKzqwNDD7V)]
|
||||
|
||||
<h3 id="Stream"> 19. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited. <a href="#index">index</a></h3>
|
||||
|
||||
<h3 id="stream"> 19. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/stream"
|
||||
@@ -1383,7 +1414,7 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
|
||||
<h3 id="Structs"> 20. Structs package provides several high level functions to manipulate struct, tag, and field. <a href="#index">index</a></h3>
|
||||
<h3 id="structs"> 20. Structs package provides several high level functions to manipulate struct, tag, and field. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/structs"
|
||||
@@ -1416,7 +1447,7 @@ import "github.com/duke-git/lancet/v2/structs"
|
||||
- **<big>IsSlice</big>** : check if the field is a slice
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsSlice)]
|
||||
|
||||
<h3 id="Strutil"> 21. Strutil package contains some functions to manipulate string. <a href="#index">index</a></h3>
|
||||
<h3 id="strutil"> 21. Strutil package contains some functions to manipulate string. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
@@ -1534,7 +1565,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- **<big>RemoveWhiteSpace</big>** : remove whitespace characters from a string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#RemoveWhiteSpace)]
|
||||
|
||||
<h3 id="System"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
||||
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -1570,7 +1601,7 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)]
|
||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||
|
||||
<h3 id="Tuple"> 23. Tuple package implements tuple data type and some operations on it. <a href="#index">index</a></h3>
|
||||
<h3 id="tuple"> 23. Tuple package implements tuple data type and some operations on it. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/tuple"
|
||||
@@ -1687,7 +1718,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip10)]
|
||||
[[play](https://go.dev/play/p/-taQB6Wfre_z)]
|
||||
|
||||
<h3 id="Validator"> 24. Validator package contains some functions for data validation. <a href="#index">index</a></h3>
|
||||
<h3 id="validator"> 24. Validator package contains some functions for data validation. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
@@ -1795,7 +1826,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsPrintable)]
|
||||
[[play](https://go.dev/play/p/Pe1FE2gdtTP)]
|
||||
|
||||
<h3 id="Xerror"> 25. Xerror package implements helpers for errors. <a href="#index">index</a></h3>
|
||||
<h3 id="xerror"> 25. Xerror package implements helpers for errors. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
|
||||
149
README_zh-CN.md
149
README_zh-CN.md
@@ -4,7 +4,7 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -74,33 +74,33 @@ func main() {
|
||||
|
||||
### <span id="index">目录<span>
|
||||
|
||||
- [Algorithm](#Algorithm)
|
||||
- [Compare](#Compare)
|
||||
- [Concurrency](#Concurrency)
|
||||
- [Condition](#Condition)
|
||||
- [Convertor](#Convertor)
|
||||
- [Cryptor](#Cryptor)
|
||||
- [Datetime](#Datetime)
|
||||
- [Datastructure](#Datastructure)
|
||||
- [Fileutil](#Fileutil)
|
||||
- [Formatter](#Formatter)
|
||||
- [Function](#Function)
|
||||
- [Maputil](#Maputil)
|
||||
- [Mathutil](#Mathutil)
|
||||
- [Netutil](#Netutil)
|
||||
- [Pointer](#Pointer)
|
||||
- [Random](#Random)
|
||||
- [Retry](#Retry)
|
||||
- [Slice](#Slice)
|
||||
- [Stream](#Stream)
|
||||
- [Structs](#Structs)
|
||||
- [Strutil](#Strutil)
|
||||
- [System](#System)
|
||||
- [Tuple](#Tuple)
|
||||
- [Validator](#Validator)
|
||||
- [Xerror](#Xerror)
|
||||
- [Algorithm](#user-content-algorithm)
|
||||
- [Compare](#user-content-compare)
|
||||
- [Concurrency](#user-content-concurrency)
|
||||
- [Condition](#user-content-condition)
|
||||
- [Convertor](#user-content-convertor)
|
||||
- [Cryptor](#user-content-cryptor)
|
||||
- [Datetime](#user-content-datetime)
|
||||
- [Datastructure](#user-content-datastructure)
|
||||
- [Fileutil](#user-content-fileutil)
|
||||
- [Formatter](#user-content-formatter)
|
||||
- [Function](#user-content-function)
|
||||
- [Maputil](#user-content-maputil)
|
||||
- [Mathutil](#user-content-mathutil)
|
||||
- [Netutil](#user-content-netutil)
|
||||
- [Pointer](#user-content-pointer)
|
||||
- [Random](#user-content-random)
|
||||
- [Retry](#user-content-retry)
|
||||
- [Slice](#user-content-slice)
|
||||
- [Stream](#user-content-stream)
|
||||
- [Structs](#user-content-structs)
|
||||
- [Strutil](#user-content-strutil)
|
||||
- [System](#user-content-system)
|
||||
- [Tuple](#user-content-tuple)
|
||||
- [Validator](#user-content-validator)
|
||||
- [Xerror](#user-content-xerror)
|
||||
|
||||
<h3 id="Algorithm"> 1. algorithm 包实现一些基本查找和排序算法。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="algorithm"> 1. algorithm 包实现一些基本查找和排序算法。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/algorithm"
|
||||
@@ -145,7 +145,7 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)]
|
||||
[[play](https://go.dev/play/p/-EZjgOURufP)]
|
||||
|
||||
<h3 id="Compare"> 2. compare 包提供几个轻量级的类型比较函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="compare"> 2. compare 包提供几个轻量级的类型比较函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/compare"
|
||||
@@ -171,8 +171,10 @@ import "github.com/duke-git/lancet/v2/compare"
|
||||
- **<big>GreaterOrEqual</big>** : 验证参数`left`的值是否大于或等于参数`right`的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#GreaterOrEqual)]
|
||||
[[play](https://go.dev/play/p/vx8mP0U8DFk)]
|
||||
- **<big>InDelta</big>** : 检查增量内两个值是否相等。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#InDelta)]
|
||||
|
||||
<h3 id="Concurrency"> 3. concurrency 包含一些支持并发编程的功能。例如:goroutine, channel, async 等。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="concurrency"> 3. concurrency 包含一些支持并发编程的功能。例如:goroutine, channel, async 等。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/concurrency"
|
||||
@@ -211,7 +213,7 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)]
|
||||
[[play](https://go.dev/play/p/3TQPKnCirrP)]
|
||||
|
||||
<h3 id="Condition"> 4. condition 包含一些用于条件判断的函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="condition"> 4. condition 包含一些用于条件判断的函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/condition"
|
||||
@@ -244,7 +246,7 @@ import "github.com/duke-git/lancet/v2/condition"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#TernaryOperator)]
|
||||
[[play](https://go.dev/play/p/ElllPZY0guT)]
|
||||
|
||||
<h3 id="Convertor"> 5. convertor 转换器包支持一些常见的数据类型转换。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="convertor"> 5. convertor 转换器包支持一些常见的数据类型转换。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/convertor"
|
||||
@@ -316,7 +318,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#GbkToUtf8)]
|
||||
[[play](https://go.dev/play/p/OphmHCN_9u8)]
|
||||
|
||||
<h3 id="Cryptor"> 6. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="cryptor"> 6. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/cryptor"
|
||||
@@ -389,31 +391,37 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
- **<big>HmacMd5WithBase64</big>** : 获取字符串 md5 hmac base64 字符串值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacMd5WithBase64)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacMd5WithBase64)]
|
||||
- **<big>HmacSha1</big>** : 返回字符串 sha1 hmac 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha1)]
|
||||
[[play](https://go.dev/play/p/1UI4oQ4WXKM)]
|
||||
- **<big>HmacSha1WithBase64</big>** : 获取字符串的 sha1 base64 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha1WithBase64)]
|
||||
[[play](https://go.dev/play/p/47JmmGrnF7B)]
|
||||
- **<big>HmacSha256</big>** : 返回字符串 sha256 hmac 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha256)]
|
||||
[[play](https://go.dev/play/p/HhpwXxFhhC0)]
|
||||
- **<big>HmacSha256WithBase64</big>** : 获取字符串 sha256 hmac base64 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha256WithBase64)]
|
||||
[[play](https://go.dev/play/p/EKbkUvPTLwO)]
|
||||
- **<big>HmacSha512</big>** : 返回字符串 sha256 hmac 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha512)]
|
||||
[[play](https://go.dev/play/p/59Od6m4A0Ud)]
|
||||
- **<big>HmacSha512WithBase64</big>** : 获取字符串 sha512 hmac base64 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha512WithBase64)]
|
||||
[[play](https://go.dev/play/p/c6dSe3E2ydU)]
|
||||
- **<big>Md5Byte</big>** : 返回 byte slice 的 md5 值.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5Byte)]
|
||||
[[play](https://go.dev/play/p/suraalH8lyC)]
|
||||
- **<big>Md5ByteWithBase64</big>** : 获取 byte slice 的 md5 base64 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5ByteWithBase64)]
|
||||
[[play](https://go.dev/play/p/Tcb-Z7LN2ax)]
|
||||
- **<big>Md5String</big>** : 返回字符串 md5 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5String)]
|
||||
[[play](https://go.dev/play/p/1bLcVetbTOI)]
|
||||
- **<big>Md5StringWithBase64</big>** : 获取字符串 md5 base64 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5StringWithBase64)]
|
||||
[[play](https://go.dev/play/p/Lx4gH7Vdr5_y)]
|
||||
- **<big>Md5File</big>** : 返回文件 md5 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5File)]
|
||||
- **<big>Sha1</big>** : 返回字符串 sha1 哈希值。
|
||||
@@ -421,16 +429,19 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/_m_uoD1deMT)]
|
||||
- **<big>Sha1WithBase64</big>** : 获取字符串 sha1 base64 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha1WithBase64)]
|
||||
[[play](https://go.dev/play/p/fSyx-Gl2l2-)]
|
||||
- **<big>Sha256</big>** :返回字符串 sha256 哈希值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha256)]
|
||||
[[play](https://go.dev/play/p/tU9tfBMIAr1)]
|
||||
- **<big>Sha256WithBase64</big>** : 获取字符串 sha256 base64 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha256WithBase64)]
|
||||
[[play](https://go.dev/play/p/85IXJHIal1k)]
|
||||
- **<big>Sha512</big>** : 返回字符串 sha512 哈希值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha512)]
|
||||
[[play](https://go.dev/play/p/3WsvLYZxsHa)]
|
||||
- **<big>Sha512WithBase64</big>** : 获取字符串 sha512 base64 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha512WithBase64)]
|
||||
[[play](https://go.dev/play/p/q_fY2rA-k5I)]
|
||||
- **<big>GenerateRsaKey</big>** : 在当前目录下创建 rsa 私钥文件和公钥文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#GenerateRsaKey)]
|
||||
[[play](https://go.dev/play/p/zutRHrDqs0X)]
|
||||
@@ -441,7 +452,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
|
||||
<h3 id="Datetime"> 7. datetime 日期时间处理包,格式化日期,比较日期。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="datetime"> 7. datetime 日期时间处理包,格式化日期,比较日期。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/datetime"
|
||||
@@ -565,19 +576,25 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[play](https://go.dev/play/p/cupRM5aZOIY)]
|
||||
- **<big>NowDateOrTime</big>** : 根据指定的格式和时区返回当前时间字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NowDateOrTime)]
|
||||
[[play](https://go.dev/play/p/EZ-begEjtT0)]
|
||||
- **<big>Timestamp</big>** : 返回当前秒级时间戳。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#Timestamp)]
|
||||
[[play](https://go.dev/play/p/iU5b7Vvjx6x)]
|
||||
- **<big>TimestampMilli</big>** : 返回当前毫秒级时间戳。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#TimestampMilli)]
|
||||
[[play](https://go.dev/play/p/4gvEusOTu1T)]
|
||||
- **<big>TimestampMicro</big>** : 返回当前微秒级时间戳。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#TimestampMicro)]
|
||||
[[play](https://go.dev/play/p/2maANglKHQE)]
|
||||
- **<big>TimestampNano</big>** : 返回当前纳秒级时间戳。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#TimestampNano)]
|
||||
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
|
||||
|
||||
<h3 id="Datastructure"> 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="datastructure"> 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
import copyonwritelist "github.com/duke-git/lancet/v2/datastructure/copyonwritelist"
|
||||
import link "github.com/duke-git/lancet/v2/datastructure/link"
|
||||
import stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
import queue "github.com/duke-git/lancet/v2/datastructure/queue"
|
||||
@@ -591,6 +608,8 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
|
||||
- **<big>List</big>** : 线性表结构, 用切片实现。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/list_zh-CN.md)]
|
||||
- **<big>CopyOnWriteList</big>** : 是一个线程安全的 List 实现,底层使用 go 切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/copyonwritelist_zh-CN.md)]
|
||||
- **<big>Link</big>** : 链表解构, 包括单链表和双向链表。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/link_zh-CN.md)]
|
||||
- **<big>Stack</big>** : 栈结构(fifo), 包括数组栈和链表栈。
|
||||
@@ -606,7 +625,7 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
- **<big>Hashmap</big>** : 哈希映射。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap_zh-CN.md)]
|
||||
|
||||
<h3 id="Fileutil"> 9. fileutil 包含文件基本操作。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="fileutil"> 9. fileutil 包含文件基本操作。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -689,7 +708,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteStringToFile)]
|
||||
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
|
||||
|
||||
<h3 id="Formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/formatter"
|
||||
@@ -719,7 +738,7 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseBinaryBytes)]
|
||||
[[play](https://go.dev/play/p/69v1tTT62x8)]
|
||||
|
||||
<h3 id="Function"> 11. function 函数包控制函数执行流程,包含部分函数式编程。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="function"> 11. function 函数包控制函数执行流程,包含部分函数式编程。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/function"
|
||||
@@ -755,7 +774,7 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
|
||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||
|
||||
<h3 id="Maputil"> 12. maputil 包括一些操作 map 的函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="maputil"> 12. maputil 包括一些操作 map 的函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -826,26 +845,35 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
- **<big>HasKey</big>** : 检查map是否包含某个key。
|
||||
- **<big>HasKey</big>** : 检查 map 是否包含某个 key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#HasKey)]
|
||||
- **<big>NewConcurrentMap</big>** : ConcurrentMap协程安全的map结构。
|
||||
[[play](https://go.dev/play/p/isZZHOsDhFc)]
|
||||
- **<big>NewConcurrentMap</big>** : ConcurrentMap 协程安全的 map 结构。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#NewConcurrentMap)]
|
||||
- **<big>ConcurrentMap_Set</big>** : 在map中设置key和value。
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
- **<big>ConcurrentMap_Set</big>** : 在 map 中设置 key 和 value。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Set)]
|
||||
- **<big>ConcurrentMap_Get</big>** : 根据key获取value, 如果不存在key,返回零值。
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
- **<big>ConcurrentMap_Get</big>** : 根据 key 获取 value, 如果不存在 key,返回零值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Get)]
|
||||
- **<big>ConcurrentMap_GetOrSet</big>** : 返回键的现有值(如果存在),否则,设置key并返回给定值。
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
- **<big>ConcurrentMap_GetOrSet</big>** : 返回键的现有值(如果存在),否则,设置 key 并返回给定值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_GetOrSet)]
|
||||
- **<big>ConcurrentMap_Delete</big>** : 删除key。
|
||||
[[play](https://go.dev/play/p/aDcDApOK01a)]
|
||||
- **<big>ConcurrentMap_Delete</big>** : 删除 key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Delete)]
|
||||
- **<big>ConcurrentMap_GetAndDelete</big>** :获取key,然后删除。
|
||||
[[play](https://go.dev/play/p/uTIJZYhpVMS)]
|
||||
- **<big>ConcurrentMap_GetAndDelete</big>** :获取 key,然后删除。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_GetAndDelete)]
|
||||
- **<big>ConcurrentMap_Has</big>** : 验证是否包含key。
|
||||
[[play](https://go.dev/play/p/ZyxeIXSZUiM)]
|
||||
- **<big>ConcurrentMap_Has</big>** : 验证是否包含 key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Has)]
|
||||
- **<big>ConcurrentMap_Range</big>** : 为map中每个键和值顺序调用迭代器。 如果iterator返回false,则停止迭代。
|
||||
[[play](https://go.dev/play/p/C8L4ul9TVwf)]
|
||||
- **<big>ConcurrentMap_Range</big>** : 为 map 中每个键和值顺序调用迭代器。 如果 iterator 返回 false,则停止迭代。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Range)]
|
||||
[[play](https://go.dev/play/p/iqcy7P8P0Pr)]
|
||||
|
||||
<h3 id="Mathutil"> 13. mathutil 包实现了一些数学计算的函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="mathutil"> 13. mathutil 包实现了一些数学计算的函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/mathutil"
|
||||
@@ -926,7 +954,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Sum)]
|
||||
[[play](https://go.dev/play/p/1To2ImAMJA7)]
|
||||
|
||||
<h3 id="Netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/netutil"
|
||||
@@ -999,7 +1027,7 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsTelnetConnected)]
|
||||
[[play](https://go.dev/play/p/yiLCGtQv_ZG)]
|
||||
|
||||
<h3 id="Pointer"> 15. pointer 包支持一些指针类型的操作。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="pointer"> 15. pointer 包支持一些指针类型的操作。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/pointer"
|
||||
@@ -1023,7 +1051,7 @@ import "github.com/duke-git/lancet/v2/pointer"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer_zh-CN.md#UnwrapOrDefault)]
|
||||
[[play](https://go.dev/play/p/ZnGIHf8_o4E)]
|
||||
|
||||
<h3 id="Random"> 16. random 随机数生成器包,可以生成随机[]bytes, int, string。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="random"> 16. random 随机数生成器包,可以生成随机[]bytes, int, string。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/random"
|
||||
@@ -1059,7 +1087,7 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandUniqueIntSlice)]
|
||||
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
|
||||
|
||||
<h3 id="Retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/retry"
|
||||
@@ -1083,7 +1111,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)]
|
||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||
|
||||
<h3 id="Slice"> 18. slice 包含操作切片的方法集合。</span> [回到目录](#index)
|
||||
<h3 id="slice"> 18. slice 包含操作切片的方法集合。 [回到目录](#index)
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
@@ -1297,8 +1325,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||
- **<big>Join</big>** : 用指定的分隔符链接切片元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Join)]
|
||||
[[play](https://go.dev/play/p/huKzqwNDD7V)]
|
||||
|
||||
<h3 id="Stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/stream"
|
||||
@@ -1385,7 +1414,7 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
|
||||
<h3 id="Structs"> 20. structs 提供操作 struct, tag, field 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="structs"> 20. structs 提供操作 struct, tag, field 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/structs"
|
||||
@@ -1420,7 +1449,7 @@ import "github.com/duke-git/lancet/v2/structs"
|
||||
- **<big>IsSlice</big>** : 判断属性是否是切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsSlice)]
|
||||
|
||||
<h3 id="Strutil"> 21. strutil 包含字符串处理的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="strutil"> 21. strutil 包含字符串处理的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
@@ -1539,7 +1568,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- **<big>RemoveWhiteSpace</big>** : 删除字符串中的空格。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#RemoveWhiteSpace)]
|
||||
|
||||
<h3 id="System"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -1575,7 +1604,7 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#GetOsBits)]
|
||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||
|
||||
<h3 id="Tuple"> 23. Tuple 包实现一个元组数据类型。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="tuple"> 23. Tuple 包实现一个元组数据类型。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/tuple"
|
||||
@@ -1692,7 +1721,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip10)]
|
||||
[[play](https://go.dev/play/p/-taQB6Wfre_z)]
|
||||
|
||||
<h3 id="Validator"> 24. validator 验证器包,包含常用字符串格式验证函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="validator"> 24. validator 验证器包,包含常用字符串格式验证函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
@@ -1800,7 +1829,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsPrintable)]
|
||||
[[play](https://go.dev/play/p/Pe1FE2gdtTP)]
|
||||
|
||||
<h3 id="Xerror"> 25. xerror 包实现一些错误处理函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="xerror"> 25. xerror 包实现一些错误处理函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// operator type
|
||||
@@ -62,3 +64,8 @@ func LessOrEqual(left, right any) bool {
|
||||
func GreaterOrEqual(left, right any) bool {
|
||||
return compareValue(greaterOrEqual, left, right)
|
||||
}
|
||||
|
||||
// InDelta checks if two values are equal or not within a delta.
|
||||
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool {
|
||||
return float64(mathutil.Abs(left-right)) <= delta
|
||||
}
|
||||
|
||||
@@ -168,3 +168,29 @@ 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
|
||||
}
|
||||
|
||||
@@ -138,3 +138,19 @@ 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))
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func Md5Byte(data []byte) string {
|
||||
}
|
||||
|
||||
// Md5ByteWithBase64 return the md5 string of byte slice with base64.
|
||||
// Play: https://go.dev/play/p/CkN9hYKGeAy
|
||||
// Play: https://go.dev/play/p/Tcb-Z7LN2ax
|
||||
func Md5ByteWithBase64(data []byte) string {
|
||||
h := md5.New()
|
||||
h.Write(data)
|
||||
@@ -153,7 +153,7 @@ func HmacSha512(str, key string) string {
|
||||
}
|
||||
|
||||
// HmacSha512WithBase64 return the hmac hash of string use sha512 with base64.
|
||||
// Play: https://go.dev/play/p/61wBBOKO-GH
|
||||
// Play: https://go.dev/play/p/c6dSe3E2ydU
|
||||
func HmacSha512WithBase64(str, key string) string {
|
||||
h := hmac.New(sha512.New, []byte(key))
|
||||
h.Write([]byte(str))
|
||||
@@ -169,7 +169,7 @@ func Sha1(str string) string {
|
||||
}
|
||||
|
||||
// Sha1WithBase64 return the sha1 value (SHA-1 hash algorithm) of base64 string.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/fSyx-Gl2l2-
|
||||
func Sha1WithBase64(str string) string {
|
||||
sha1 := sha1.New()
|
||||
sha1.Write([]byte(str))
|
||||
|
||||
@@ -7,6 +7,7 @@ package datastructure
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var defaultMapCapacity uint64 = 1 << 10
|
||||
@@ -45,13 +46,24 @@ func NewHashMapWithCapacity(size, capacity uint64) *HashMap {
|
||||
func (hm *HashMap) Get(key any) any {
|
||||
hashValue := hm.hash(key)
|
||||
node := hm.table[hashValue]
|
||||
if node != nil {
|
||||
return node.value
|
||||
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)
|
||||
@@ -90,7 +102,13 @@ func (hm *HashMap) Delete(key any) {
|
||||
// Contains checks if given key is in hashmap or not
|
||||
func (hm *HashMap) Contains(key any) bool {
|
||||
node := hm.table[hm.hash(key)]
|
||||
return node != nil
|
||||
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)
|
||||
|
||||
@@ -74,3 +74,34 @@ func TestHashMap_KeysValues(t *testing.T) {
|
||||
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))
|
||||
}
|
||||
|
||||
350
datastructure/list/copyonwritelist.go
Normal file
350
datastructure/list/copyonwritelist.go
Normal file
@@ -0,0 +1,350 @@
|
||||
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
datastructure/list/copyonwritelist_test.go
Normal file
235
datastructure/list/copyonwritelist_test.go
Normal file
@@ -0,0 +1,235 @@
|
||||
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)
|
||||
}
|
||||
@@ -271,7 +271,7 @@ func (l *List[T]) Reverse() {
|
||||
}
|
||||
}
|
||||
|
||||
// Unique remove duplicate items in list.
|
||||
// Unique delete duplicate items in list.
|
||||
func (l *List[T]) Unique() {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
@@ -294,7 +294,7 @@ func (l *List[T]) Unique() {
|
||||
l.data = uniqueData
|
||||
}
|
||||
|
||||
// Union creates a new list contain all element in list l and other, remove duplicate element.
|
||||
// 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{})
|
||||
|
||||
|
||||
@@ -298,7 +298,7 @@ func IsWeekend(t time.Time) bool {
|
||||
}
|
||||
|
||||
// NowDateOrTime return current datetime with specific format and timezone.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/EZ-begEjtT0
|
||||
func NowDateOrTime(format string, timezone ...string) string {
|
||||
tf, ok := timeFormat[strings.ToLower(format)]
|
||||
if !ok {
|
||||
@@ -318,7 +318,7 @@ func NowDateOrTime(format string, timezone ...string) string {
|
||||
}
|
||||
|
||||
// Timestamp return current second timestamp.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/iU5b7Vvjx6x
|
||||
func Timestamp(timezone ...string) int64 {
|
||||
t := time.Now()
|
||||
|
||||
@@ -335,7 +335,7 @@ func Timestamp(timezone ...string) int64 {
|
||||
}
|
||||
|
||||
// TimestampMilli return current mill second timestamp.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/4gvEusOTu1T
|
||||
func TimestampMilli(timezone ...string) int64 {
|
||||
t := time.Now()
|
||||
|
||||
@@ -351,7 +351,7 @@ func TimestampMilli(timezone ...string) int64 {
|
||||
}
|
||||
|
||||
// TimestampMicro return current micro second timestamp.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/2maANglKHQE
|
||||
func TimestampMicro(timezone ...string) int64 {
|
||||
t := time.Now()
|
||||
|
||||
@@ -367,7 +367,7 @@ func TimestampMicro(timezone ...string) int64 {
|
||||
}
|
||||
|
||||
// TimestampNano return current nano second timestamp.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/A9Oq_COrcCF
|
||||
func TimestampNano(timezone ...string) int64 {
|
||||
t := time.Now()
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
- [GreaterThan](#GreaterThan)
|
||||
- [LessOrEqual](#LessOrEqual)
|
||||
- [GreaterOrEqual](#GreaterOrEqual)
|
||||
- [InDelta](#InDelta)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -324,3 +325,50 @@ func main() {
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="InDelta">InDelta</span>
|
||||
|
||||
<p>Checks if two values are equal or not within a delta.</p>
|
||||
|
||||
<b>Signature:</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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -30,6 +30,8 @@ import (
|
||||
- [GreaterThan](#GreaterThan)
|
||||
- [LessOrEqual](#LessOrEqual)
|
||||
- [GreaterOrEqual](#GreaterOrEqual)
|
||||
- [InDelta](#InDelta)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -324,3 +326,50 @@ 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>示例:</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
|
||||
}
|
||||
```
|
||||
|
||||
470
docs/datastructure/copyonwritelist.md
Normal file
470
docs/datastructure/copyonwritelist.md
Normal file
@@ -0,0 +1,470 @@
|
||||
# CopyOnWriteList
|
||||
|
||||
CopyOnWriteList is a thread-safe list implementation that uses go slicing as its base. When writing, a new slice is copied and assigned to the original slice when writing is complete. When reading, the original slice is read directly.
|
||||
|
||||
## 源码
|
||||
|
||||
- [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)
|
||||
|
||||
## Documentation
|
||||
|
||||
### NewCopyOnWriteList
|
||||
|
||||
Returns a CopyOnWriteList with empty slices.
|
||||
|
||||
```go
|
||||
type CopyOnWriteList[T any] struct {
|
||||
data []T
|
||||
lock sync.
|
||||
}
|
||||
|
||||
func NewCopyOnWriteList() *CopyOnWriteList
|
||||
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Returns the length of the CopyOnWriteList.
|
||||
|
||||
```go
|
||||
func (l *CopyOnWriteList[T]) Size() int
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Returns the element at the specified position in the list
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Get(index int) *T
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Replaces the element at the specified position in this list with the specified element.
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Set(index int, e T) (oldValue *T, ok bool)
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Returns the index of the value in the list, or -1 if not found.
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) IndexOf(e T) int
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain that element.
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) LastIndexOf(e T) int
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Returns true if this list does not contain any elements.
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) IsEmpty() bool
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{})
|
||||
fmt.Println(l.IsEmpty())
|
||||
}
|
||||
```
|
||||
|
||||
### Contain
|
||||
|
||||
Determines if a CopyOnWriteList contains an element.
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Contain(e T) bool
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Returns a pointer to the value at the index in the list
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) ValueOf(index int) []T
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Appends the specified element to the end of the list.
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Add(e T) bool
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Appends all the elements of the specified collection to the end of this list
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) AddAll(e []T) bool
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Inserts the specified element into the list at the specified position.
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) AddByIndex(index int, e T) bool
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Removes the element at the specified position in this list.
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) DeleteAt(index int) (oldValue *T, ok bool)
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Removes the first occurrence of the specified element from this list (if it exists).
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) DeleteIf(func(T) bool) (oldValue *T, ok bool)
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Deletes the first occurrence of the specified element from this list (if it exists).
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) DeleteBy(e T) (*T bool)
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Deletes all elements from this list with indexes between fromIndex (included) and toIndex (not included).
|
||||
(leftCloseRightOpen)
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) DeleteRange(start int, end int)
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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
|
||||
|
||||
Returns true if the specified object is equal to this list
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Equal(e []T) bool
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```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}))
|
||||
}
|
||||
```
|
||||
471
docs/datastructure/copyonwritelist_zh-CN.md
Normal file
471
docs/datastructure/copyonwritelist_zh-CN.md
Normal file
@@ -0,0 +1,471 @@
|
||||
# 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}))
|
||||
}
|
||||
```
|
||||
@@ -980,8 +980,8 @@ func main() {
|
||||
"b": 2,
|
||||
}
|
||||
|
||||
result1 := HasKey(m, "a")
|
||||
result2 := HasKey(m, "c")
|
||||
result1 := maputil.HasKey(m, "a")
|
||||
result2 := maputil.HasKey(m, "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -1054,12 +1054,16 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
}(j)
|
||||
}
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
|
||||
// output: (order may change)
|
||||
// 1 true
|
||||
@@ -1105,12 +1109,16 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
}(j)
|
||||
}
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
|
||||
// output: (order may change)
|
||||
// 1 true
|
||||
@@ -1199,13 +1207,16 @@ func main() {
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
cm.Delete(fmt.Sprintf("%d", n))
|
||||
wg2.Done()
|
||||
}(i)
|
||||
}(j)
|
||||
}
|
||||
|
||||
wg2.Wait()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1244,7 +1255,8 @@ func main() {
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
|
||||
@@ -1252,8 +1264,12 @@ func main() {
|
||||
|
||||
_, ok = cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok) //false
|
||||
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
|
||||
wg2.Wait()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1292,13 +1308,16 @@ func main() {
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
ok := cm.Has(fmt.Sprintf("%d", n))
|
||||
fmt.Println(ok) // true
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1337,7 +1356,7 @@ func main() {
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
|
||||
cm.Range(func(key string, value int) bool {
|
||||
fmt.Println(value)
|
||||
return true
|
||||
|
||||
@@ -977,8 +977,8 @@ func main() {
|
||||
"b": 2,
|
||||
}
|
||||
|
||||
result1 := HasKey(m, "a")
|
||||
result2 := HasKey(m, "c")
|
||||
result1 := maputil.HasKey(m, "a")
|
||||
result2 := maputil.HasKey(m, "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -1050,13 +1050,16 @@ func main() {
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
|
||||
// output: (order may change)
|
||||
// 1 true
|
||||
@@ -1101,13 +1104,16 @@ func main() {
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
|
||||
// output: (order may change)
|
||||
// 1 true
|
||||
@@ -1196,13 +1202,15 @@ func main() {
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
cm.Delete(fmt.Sprintf("%d", n))
|
||||
wg2.Done()
|
||||
}(i)
|
||||
}
|
||||
wg2.Wait()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1241,7 +1249,8 @@ func main() {
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
|
||||
@@ -1249,8 +1258,11 @@ func main() {
|
||||
|
||||
_, ok = cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok) //false
|
||||
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1280,7 +1292,6 @@ func main() {
|
||||
|
||||
var wg1 sync.WaitGroup
|
||||
wg1.Add(5)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
go func(n int) {
|
||||
cm.Set(fmt.Sprintf("%d", n), n)
|
||||
@@ -1289,13 +1300,18 @@ func main() {
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
ok := cm.Has(fmt.Sprintf("%d", n))
|
||||
fmt.Println(ok) // true
|
||||
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -199,7 +199,15 @@ func IsZipFile(filepath string) bool {
|
||||
|
||||
// Zip create zip file, fpath could be a single file or a directory.
|
||||
// Play: https://go.dev/play/p/j-3sWBp8ik_P
|
||||
func Zip(fpath string, destPath string) error {
|
||||
func Zip(path string, destPath string) error {
|
||||
if IsDir(path) {
|
||||
return zipFolder(path, destPath)
|
||||
}
|
||||
|
||||
return zipFile(path, destPath)
|
||||
}
|
||||
|
||||
func zipFile(filePath string, destPath string) error {
|
||||
zipFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -209,10 +217,32 @@ func Zip(fpath string, destPath string) error {
|
||||
archive := zip.NewWriter(zipFile)
|
||||
defer archive.Close()
|
||||
|
||||
return addFileToArchive(fpath, archive)
|
||||
return addFileToArchive1(filePath, archive)
|
||||
}
|
||||
|
||||
func addFileToArchive(fpath string, archive *zip.Writer) error {
|
||||
func zipFolder(folderPath string, destPath string) error {
|
||||
outFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
w := zip.NewWriter(outFile)
|
||||
|
||||
err = addFileToArchive2(w, folderPath, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addFileToArchive1(fpath string, archive *zip.Writer) error {
|
||||
err := filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -247,10 +277,42 @@ func addFileToArchive(fpath string, archive *zip.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func addFileToArchive2(w *zip.Writer, basePath, baseInZip string) error {
|
||||
files, err := os.ReadDir(basePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.HasSuffix(basePath, "/") {
|
||||
basePath = basePath + "/"
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if !file.IsDir() {
|
||||
dat, err := os.ReadFile(basePath + file.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := w.Create(baseInZip + file.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(dat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if file.IsDir() {
|
||||
newBase := basePath + file.Name() + "/"
|
||||
addFileToArchive2(w, newBase, baseInZip+file.Name()+"/")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnZip unzip the file and save it to destPath.
|
||||
// Play: https://go.dev/play/p/g0w34kS7B8m
|
||||
func UnZip(zipFile string, destPath string) error {
|
||||
|
||||
zipReader, err := zip.OpenReader(zipFile)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -333,7 +395,7 @@ func ZipAppendEntry(fpath string, destPath string) error {
|
||||
}
|
||||
}
|
||||
|
||||
err = addFileToArchive(fpath, archive)
|
||||
err = addFileToArchive1(fpath, archive)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -241,6 +241,19 @@ func TestZipAppendEntry(t *testing.T) {
|
||||
os.RemoveAll(unZipPath)
|
||||
}
|
||||
|
||||
func TestZipFolder(t *testing.T) {
|
||||
// assert := internal.NewAssert(t, "TestZipFolder")
|
||||
|
||||
// toZipFolder := "./tempdir/a/b"
|
||||
// zipFolder := "./tempdir/a/b.zip"
|
||||
|
||||
// err := Zip(toZipFolder, zipFolder)
|
||||
// assert.IsNil(err)
|
||||
// assert.Equal(true, IsExist(zipFolder))
|
||||
|
||||
// os.Remove(zipFolder)
|
||||
}
|
||||
|
||||
func TestFileMode(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFileMode")
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ type ConcurrentMap[K comparable, V any] struct {
|
||||
}
|
||||
|
||||
// NewConcurrentMap create a ConcurrentMap with specific shard count.
|
||||
// Play: https://go.dev/play/p/3PenTPETJT0
|
||||
func NewConcurrentMap[K comparable, V any](shardCount int) *ConcurrentMap[K, V] {
|
||||
if shardCount <= 0 {
|
||||
shardCount = defaultShardCount
|
||||
@@ -38,7 +39,7 @@ func NewConcurrentMap[K comparable, V any](shardCount int) *ConcurrentMap[K, V]
|
||||
}
|
||||
|
||||
// Set the value for a key.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/3PenTPETJT0
|
||||
func (cm *ConcurrentMap[K, V]) Set(key K, value V) {
|
||||
shard := cm.getShard(key)
|
||||
|
||||
@@ -49,7 +50,7 @@ func (cm *ConcurrentMap[K, V]) Set(key K, value V) {
|
||||
}
|
||||
|
||||
// Get the value stored in the map for a key, or nil if no.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/3PenTPETJT0
|
||||
func (cm *ConcurrentMap[K, V]) Get(key K) (V, bool) {
|
||||
shard := cm.getShard(key)
|
||||
|
||||
@@ -62,7 +63,7 @@ func (cm *ConcurrentMap[K, V]) Get(key K) (V, bool) {
|
||||
|
||||
// GetOrSet returns the existing value for the key if present.
|
||||
// Otherwise, it sets and returns the given value.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/aDcDApOK01a
|
||||
func (cm *ConcurrentMap[K, V]) GetOrSet(key K, value V) (actual V, ok bool) {
|
||||
shard := cm.getShard(key)
|
||||
|
||||
@@ -87,7 +88,7 @@ func (cm *ConcurrentMap[K, V]) GetOrSet(key K, value V) (actual V, ok bool) {
|
||||
}
|
||||
|
||||
// Delete the value for a key.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/uTIJZYhpVMS
|
||||
func (cm *ConcurrentMap[K, V]) Delete(key K) {
|
||||
shard := cm.getShard(key)
|
||||
|
||||
@@ -98,7 +99,7 @@ func (cm *ConcurrentMap[K, V]) Delete(key K) {
|
||||
|
||||
// GetAndDelete returns the existing value for the key if present and then delete the value for the key.
|
||||
// Otherwise, do nothing, just return false
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/ZyxeIXSZUiM
|
||||
func (cm *ConcurrentMap[K, V]) GetAndDelete(key K) (actual V, ok bool) {
|
||||
shard := cm.getShard(key)
|
||||
|
||||
@@ -114,7 +115,7 @@ func (cm *ConcurrentMap[K, V]) GetAndDelete(key K) (actual V, ok bool) {
|
||||
}
|
||||
|
||||
// Has checks if map has the value for a key.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/C8L4ul9TVwf
|
||||
func (cm *ConcurrentMap[K, V]) Has(key K) bool {
|
||||
_, ok := cm.Get(key)
|
||||
return ok
|
||||
@@ -122,6 +123,7 @@ func (cm *ConcurrentMap[K, V]) Has(key K) bool {
|
||||
|
||||
// Range calls iterator sequentially for each key and value present in each of the shards in the map.
|
||||
// If iterator returns false, range stops the iteration.
|
||||
// Play: https://go.dev/play/p/iqcy7P8P0Pr
|
||||
func (cm *ConcurrentMap[K, V]) Range(iterator func(key K, value V) bool) {
|
||||
for shard := range cm.locks {
|
||||
cm.locks[shard].RLock()
|
||||
|
||||
@@ -100,12 +100,18 @@ func TestConcurrentMap_GetAndDelete(t *testing.T) {
|
||||
|
||||
cm := NewConcurrentMap[string, int](100)
|
||||
|
||||
var wg1 sync.WaitGroup
|
||||
wg1.Add(10)
|
||||
for i := 0; i < 10; i++ {
|
||||
go func(n int) {
|
||||
cm.Set(fmt.Sprintf("%d", n), n)
|
||||
wg1.Done()
|
||||
}(i)
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(10)
|
||||
for j := 0; j < 10; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
|
||||
@@ -114,8 +120,11 @@ func TestConcurrentMap_GetAndDelete(t *testing.T) {
|
||||
|
||||
_, ok = cm.Get(fmt.Sprintf("%d", n))
|
||||
assert.Equal(false, ok)
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
|
||||
wg2.Wait()
|
||||
}
|
||||
|
||||
func TestConcurrentMap_Has(t *testing.T) {
|
||||
|
||||
@@ -298,7 +298,7 @@ func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value
|
||||
// fmt.Println("map has key baz")
|
||||
// }
|
||||
//
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/isZZHOsDhFc
|
||||
func HasKey[K comparable, V any](m map[K]V, key K) bool {
|
||||
_, haskey := m[key]
|
||||
return haskey
|
||||
|
||||
@@ -1191,7 +1191,7 @@ func KeyBy[T any, U comparable](slice []T, iteratee func(item T) U) map[U]T {
|
||||
}
|
||||
|
||||
// Join the slice item with specify separator.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/huKzqwNDD7V
|
||||
func Join[T any](s []T, separator string) string {
|
||||
str := Map(s, func(_ int, item T) string {
|
||||
return fmt.Sprint(item)
|
||||
|
||||
Reference in New Issue
Block a user