1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-23 13:52:26 +08:00

Compare commits

..

657 Commits

Author SHA1 Message Date
dudaodong
8ad374bb21 doc: update doc for datastructure package 2023-08-25 11:05:33 +08:00
dudaodong
a69d886565 doc: add go playground demo 2023-08-25 10:49:16 +08:00
dudaodong
cf58542b4a doc: add new doc for convertor and cryptor 2023-08-25 10:47:16 +08:00
dudaodong
51f166d1d9 doc: update doc styles 2023-08-24 19:27:47 +08:00
dudaodong
fbeb031b40 doc: update doc 2023-08-24 19:07:24 +08:00
dudaodong
095cfc0aab doc: add new site for doc 2023-08-24 17:47:03 +08:00
ggymm
e66ab154bc fix: 覆盖写入字符串到文件问题 (#128) 2023-08-24 16:36:44 +08:00
dudaodong
91bc1a512c test: update TestZipFolder 2023-08-22 10:49:46 +08:00
dudaodong
8753255026 doc: update link in readme 2023-08-22 10:43:52 +08:00
dudaodong
9cf1f13fec doc: update link in readme 2023-08-22 10:39:37 +08:00
dudaodong
5d78bae4bb doc: update link in readme 2023-08-22 10:34:16 +08:00
dudaodong
27777eecc0 doc: update copyonwritelist doc 2023-08-22 10:26:39 +08:00
dudaodong
1a7e0e8792 doc: add copyonwritelist 2023-08-22 10:25:21 +08:00
dudaodong
02b7aa8f33 update version 2023-08-22 10:18:21 +08:00
dudaodong
f188d3d08f doc: add doc for InDelta 2023-08-21 11:05:11 +08:00
dudaodong
0c924b859e Merge branch 'main' into v2 2023-08-21 11:00:23 +08:00
warpmatrix
c5a5a07462 feat: InDelta (#127) 2023-08-15 09:53:16 +08:00
dudaodong
1ff5dd6df0 Merge branch 'main' into v2 2023-08-03 15:06:15 +08:00
Faucherwind
b5f86a488c feat: CopyOnWriteList adds more functions such as ForEach, Sort... (#126)
* feat: CopyOnWriteList adds more functions such as ForEach, Sort

* feat: CopyOnWriteList adds more functions such as ForEach, Sort
2023-08-03 15:05:30 +08:00
dudaodong
1390b7a964 fix: fix bug of Zip 2023-08-03 10:45:48 +08:00
dudaodong
c3e28a9fc0 fix: fix bug of Zip 2023-08-02 20:17:55 +08:00
dudaodong
e924429d6e fix: fix test case TestConcurrentMap_GetAndDelete 2023-08-02 11:33:27 +08:00
dudaodong
7079b1f704 format doc 2023-08-02 11:29:51 +08:00
Faucherwind
40cad365c0 feat: add CopyOnWriteList. A thread-safe list. (#125)
* fix: use loop to get value . On Get() and Contains()

* fix: Use reflect. DeepEqual() determines whether the keys are equal

* feat: add CopyOnWriteList. A thread-safe list.

* fix: fix failed unit test

* feat: add Equal() in CopyOnWriteList.

fix: update some function`s  names

* doc: add copyonwritelist.md and copyonwritelist_zh-CN.md
2023-08-02 11:10:10 +08:00
Faucherwind
6386ab908d fix: use loop to get value . On Get() and Contains() (#124)
* fix: use loop to get value . On Get() and Contains()

* fix: Use reflect. DeepEqual() determines whether the keys are equal
2023-08-01 11:14:45 +08:00
dudaodong
bb563724c7 doc: add go playground demo 2023-08-01 11:01:57 +08:00
dudaodong
72924d4486 release v2.2.4 2023-08-01 09:58:53 +08:00
dudaodong
231f8b04b4 doc: add new function doc for v2.2.4 2023-07-30 13:22:32 +08:00
dudaodong
daa932fee3 update: make IsWeekend deprecated 2023-07-30 12:47:00 +08:00
dudaodong
1b0691f1d5 Merge branch 'main' into v2 2023-07-30 12:41:03 +08:00
CyJaySong
0b6a00bd99 IsWeekend func Deprecated (#123)
* expand BeginOfWeek、EndOfWeek

* IsWeekend func Deprecated
2023-07-30 12:39:26 +08:00
dudaodong
4ab98664bb refactor: rename file name 2023-07-28 17:55:36 +08:00
dudaodong
31eb5f4d1f feat: add HmacMd5WithBase64 2023-07-28 17:53:46 +08:00
dudaodong
0ae5d17a06 doc: add doc for CurrentMap 2023-07-27 15:08:55 +08:00
dudaodong
4558d7a3c2 test: add test for currentmap 2023-07-27 11:54:52 +08:00
dudaodong
4715301240 doc: update doc for cryptor package 2023-07-27 11:20:06 +08:00
dudaodong
1c58ee23f1 feat: add Timestamp,TimestampMilli,TimestampMicro, TimestampNano 2023-07-26 17:28:15 +08:00
dudaodong
2a303d5e4b doc: update format 2023-07-26 15:28:20 +08:00
dudaodong
326e7881a6 feat: add NowDateOrTime 2023-07-26 15:03:59 +08:00
dudaodong
31e8b12674 feat: add timezone support for FormatTimeToStr and FormatStrToTime 2023-07-26 14:40:12 +08:00
dudaodong
a0431d9435 fix: fix TestConcurrentMap_Delete test failed 2023-07-25 10:21:11 +08:00
dudaodong
0456b65cc7 test: add example for cryptor package new functions 2023-07-25 10:18:54 +08:00
dudaodong
989b4dd791 test: add test for cryptor package new functions 2023-07-25 10:06:25 +08:00
dudaodong
a76b02fbba Merge branch 'main' into v2 2023-07-24 17:28:41 +08:00
hoslo
2d7747738a feat: add base cryptor method (#119)
Co-authored-by: shuai_yang <shuai_yang@intsig.net>
2023-07-24 17:24:17 +08:00
dudaodong
fe0cb04137 feat: add ConcurrentMap 2023-07-24 17:10:45 +08:00
dudaodong
fe0264f628 refactor: clean code 2023-07-24 15:42:36 +08:00
dudaodong
65396cee32 Merge branch 'main' into v2 2023-07-23 15:43:35 +08:00
Ta
544702b460 fix: remove unused message in pointer.md (#117) 2023-07-23 15:42:54 +08:00
dudaodong
d8936cdcb5 doc: add doc for pointer 2023-07-23 13:26:07 +08:00
dudaodong
d4b97d6b20 Merge branch 'main' into v2 2023-07-23 13:13:56 +08:00
Ta
5caa14c838 feat: add UnwarpOr and UnwarpOrDefault to pointer pkg (#116) 2023-07-23 13:09:50 +08:00
dudaodong
0d0848ac67 refactor: use for loop than for range 2023-07-10 10:56:53 +08:00
dudaodong
d5334f892f feat: add Join 2023-07-10 10:51:43 +08:00
dudaodong
36ef5b3bd3 doc: add doc for HasKey 2023-07-10 10:39:55 +08:00
dudaodong
6f48b00c88 feat: add HasKey 2023-07-10 10:33:04 +08:00
dudaodong
7b744c299e fix: fix bug of CreateDir 2023-07-10 10:13:23 +08:00
dudaodong
154ec56780 doc: add go playground demo 2023-07-04 16:31:13 +08:00
dudaodong
584aabdf62 release v2.2.3 2023-07-03 14:09:04 +08:00
dudaodong
1b754a6264 doc: update link in readme 2023-07-03 11:57:50 +08:00
dudaodong
06a558d797 doc: update link in readme 2023-07-03 11:21:49 +08:00
dudaodong
423779d3ff doc: update link in readme 2023-07-03 11:14:55 +08:00
dudaodong
78c17a9e7b doc: update link in readme 2023-07-03 10:52:26 +08:00
dudaodong
529b9317d0 doc: update link in readme 2023-07-03 10:48:04 +08:00
dudaodong
dc838f645b doc: update link in readme 2023-07-03 10:43:05 +08:00
dudaodong
7f559c4940 doc: update link in readme 2023-07-03 10:42:22 +08:00
dudaodong
acb08dfd90 doc: update link in readme 2023-07-03 10:40:50 +08:00
dudaodong
ffe46fd06d update readme file 2023-07-02 22:31:17 +08:00
dudaodong
b419e46b9b doc: add package index 2023-07-02 22:12:47 +08:00
dudaodong
8fbcdfd515 doc: add pointer and tuple package to readme file 2023-07-02 21:06:10 +08:00
dudaodong
f03f48210c doc: update system package 2023-06-30 15:12:18 +08:00
dudaodong
742944e2f0 doc: add doc for tuple package 2023-06-30 15:11:26 +08:00
dudaodong
c0b491ad78 doc: add example for tuple package 2023-06-30 11:20:46 +08:00
dudaodong
e9abae2a92 doc: add doc for pointer package 2023-06-30 10:31:22 +08:00
dudaodong
8229de2f10 test: add parallel running for all unit test functions 2023-06-30 10:18:45 +08:00
dudaodong
ab364744b6 test: add parallel running for all unit test functions 2023-06-29 14:49:28 +08:00
dudaodong
17ff84fa1f test: add test for Tuple Zip and Unzip 2023-06-29 11:34:43 +08:00
dudaodong
bf50baa07d feat: add GetTodayStartTime and GetTodayEndTime 2023-06-29 11:03:28 +08:00
dudaodong
7d56da8108 feat: add Md5Byte 2023-06-29 10:33:29 +08:00
dudaodong
16c2df711b feat: add unzip for tuple 2023-06-28 20:06:02 +08:00
dudaodong
015f8c3f5c feat: add zip 2023-06-28 19:41:46 +08:00
dudaodong
ba25701d89 feat: add zip 2023-06-28 17:52:12 +08:00
dudaodong
a0cb4bb266 doc: add example for tuple package 2023-06-28 16:25:43 +08:00
dudaodong
d6ba7497f9 feat: add Tuple package 2023-06-28 15:58:41 +08:00
dudaodong
7da931e0a0 feat: add Abs 2023-06-27 10:24:35 +08:00
dudaodong
8f49078eb3 doc: add go playground demo 2023-06-20 14:04:18 +08:00
dudaodong
3050d93703 release v2.2.2 2023-06-20 11:11:27 +08:00
dudaodong
efcfbfb6a1 fix: fix failed unit test 2023-06-20 11:10:33 +08:00
dudaodong
844b7a2c3b release v2.2.2 2023-06-20 10:59:12 +08:00
dudaodong
c8a536eafc doc: add doc for ZipAppendEntry 2023-06-17 19:54:09 +08:00
dudaodong
0fd268face Merge branch 'main' into v2 2023-06-17 19:38:53 +08:00
TheLastSunset
8ced7e887f feat: add ZipAppendEntry (#113) 2023-06-17 19:36:42 +08:00
dudaodong
957568ed5c doc: format code in doc file 2023-06-15 10:13:27 +08:00
dudaodong
fffabd0ffa Merge branch 'main' into v2 2023-06-13 13:58:29 +08:00
Mickls
e839af3ef9 feat: Add support for uploading files in SendRequest (#111) 2023-06-13 13:55:47 +08:00
dudaodong
1650e70d04 Merge branch 'main' into v2 2023-06-13 10:15:17 +08:00
Thijs Schreijer
23382b2b76 fix doc comment typo (#110) 2023-06-12 20:13:14 +08:00
dudaodong
daa3aa3da2 doc: update text error 2023-06-09 11:31:16 +08:00
dudaodong
be355a23f3 doc: add doc for Utf8ToGbk and GbkToUtf8 2023-06-09 11:29:29 +08:00
dudaodong
95af83b0cb doc: add doc for Sum 2023-06-09 11:23:24 +08:00
dudaodong
1efdbc0973 doc: add doc for RemoveWhiteSpace 2023-06-09 11:19:35 +08:00
dudaodong
9b829aa695 feat: add RemoveWhiteSpace 2023-06-08 16:47:31 +08:00
dudaodong
bfa9091c09 test: clean code 2023-06-08 16:25:48 +08:00
dudaodong
c11d63c2e2 feat: add Sum 2023-06-08 16:18:25 +08:00
dudaodong
83832daeb1 feat: add Utf8ToGbk and GbkToUtf8 2023-06-08 15:50:44 +08:00
dudaodong
7311f84772 test: add test file 2023-06-08 14:50:46 +08:00
dudaodong
a63d78111e test: update ExampleRandUniqueIntSlice 2023-06-08 14:41:17 +08:00
dudaodong
e2fc2f1bc9 feat: add WirteCsvFile 2023-06-08 14:40:37 +08:00
dudaodong
23a0135947 doc: add doc for RandUniqueIntSlice 2023-06-07 14:21:29 +08:00
dudaodong
013b6457bb Merge branch 'main' into v2 2023-06-07 11:38:20 +08:00
dudaodong
e08a62b0ba doc: add doc for Log function 2023-06-07 11:37:12 +08:00
Liu Shuang
850800a233 feat: add RandUniqueIntSlice (#108) 2023-06-07 11:33:37 +08:00
dudaodong
a6a8fd88bc feat: add Log function 2023-06-06 14:34:40 +08:00
dudaodong
2f6ee84443 feat: add Of and Unwrap 2023-06-02 11:48:17 +08:00
dudaodong
b1c6614549 refactor: clean code 2023-06-01 16:58:42 +08:00
dudaodong
a8761eefb0 doc: update package comment for datastructure package 2023-06-01 14:28:04 +08:00
dudaodong
cbf8cfdffa doc: add go playground demo 2023-06-01 14:11:57 +08:00
dudaodong
286a187942 fix: fix go report validation issue 2023-06-01 11:49:49 +08:00
dudaodong
b787e99528 release v2.2.1 2023-06-01 10:45:32 +08:00
dudaodong
e54c9b2850 doc: add new function to readme file 2023-06-01 10:44:00 +08:00
dudaodong
8944109c4c doc: add doc for WriteBytesToFile and WriteStringToFile 2023-05-31 17:42:34 +08:00
dudaodong
10e3732f32 feat: add IsWeekend 2023-05-31 17:13:06 +08:00
dudaodong
a415597c6b Merge branch 'main' into v2 2023-05-31 17:06:47 +08:00
hhhhhxm
69b32fd043 新增判断是否是周末的方法 (#105)
* 新增判断是否是周末的方法

* 新增判断是否是周末的方法

---------

Co-authored-by: huangxingming <huangxingming@kezaihui.com>
2023-05-31 17:05:20 +08:00
dudaodong
75ed359084 feat: add WriteBytesToFile and WriteStringToFile 2023-05-31 16:56:18 +08:00
dudaodong
2c71b6375c doc: add doc for ContainsAny and ContainsAll 2023-05-31 15:56:20 +08:00
dudaodong
2894bec80c feat: add ContainsAll and ContainsAny 2023-05-31 10:51:16 +08:00
dudaodong
09ec5b97a6 doc: add doc for DayOfYear 2023-05-31 10:04:59 +08:00
hhhhhxm
46ecb117a5 增加判断某个日期是一年当中的第几天的方法 (#103)
* 增加判断某个日期是一年当中的第几天的方法

* 修改下函数名字

---------

Co-authored-by: huangxingming <huangxingming@kezaihui.com>
2023-05-31 09:54:23 +08:00
dudaodong
388171e739 doc: add doc for BetweenSeconds 2023-05-30 17:47:16 +08:00
dudaodong
6fbaf2b005 refactor: update TestBetweenSeconds and ExampleBetweenSeconds 2023-05-30 17:44:28 +08:00
dudaodong
53a91cad71 Merge branch 'main' into v2 2023-05-30 17:38:58 +08:00
tlei995
a51a182fb2 feat:add betweenSeconds func (#102)
Co-authored-by: leitao <leitao@kezaihui.com>
2023-05-30 17:37:29 +08:00
dudaodong
64982f0c89 fix: fix body param bug when send post request 2023-05-30 10:51:33 +08:00
dudaodong
f38f69ce17 Merge branch 'main' into v2 2023-05-29 20:10:34 +08:00
燕归来
a33ea3d013 fix: timeFormat["yyyy-mm-dd hh"] should be "2006-01-02 15" (#99) (#100)
* fix: timeFormat["yyyy-mm-dd hh"] should be "2006-01-02 15" (#99)

* test: add use cases for FormatTimeToStr
2023-05-29 20:08:17 +08:00
dudaodong
e35462fb14 fix: fix format error in init function 2023-05-29 16:09:30 +08:00
dudaodong
af106a4a8e doc: add doc for Cos and Sin 2023-05-28 20:12:40 +08:00
dudaodong
ec7232ec40 update readme file 2023-05-25 19:29:59 +08:00
dudaodong
67c1b54b5a feat: add Cos and Sin function 2023-05-25 17:51:40 +08:00
dudaodong
e149ae2f72 feat: add HideString 2023-05-23 18:39:59 +08:00
dudaodong
b1fcfce188 doc: add go playground demo 2023-05-19 11:42:29 +08:00
dudaodong
259dbce85e doc: add go playground demo 2023-05-19 11:42:17 +08:00
will
78aa679670 feat: add ContainNumber for validator (#97)
Co-authored-by: sunyaoyao <sunyaoyao@kezaihui.com>
2023-05-19 11:23:19 +08:00
dudaodong
3beb769f09 release v2.2.0 2023-05-18 10:53:02 +08:00
dudaodong
8af02ff95b doc: update readme file 2023-05-18 10:51:33 +08:00
dudaodong
ba4485d8c0 merge main 2023-05-18 10:32:36 +08:00
dudaodong
8a1dd40738 doc: add doc for AddYear function 2023-05-18 10:27:37 +08:00
dudaodong
85e2806531 doc: add doc for FindLast 2023-05-18 10:21:24 +08:00
will
1616d3d1be feat:addFindLast for stream (#95)
Co-authored-by: sunyaoyao <sunyaoyao@kezaihui.com>
2023-05-18 10:17:15 +08:00
tlei995
aa8e0d5c12 feat:add AddYear func (#96)
Co-authored-by: leitao <leitao@kezaihui.com>
2023-05-18 10:14:23 +08:00
dudaodong
f05477d9cf fix: update logic of Percent function 2023-05-18 10:11:48 +08:00
dudaodong
cd91e16b26 doc: update document for strutil and convertor package 2023-05-11 10:06:32 +08:00
dudaodong
9fcf046fb3 feat: add Trim and SplitAndTrim 2023-05-10 10:53:17 +08:00
dudaodong
c3f1bc39d7 feat: add ReplaceWithMap 2023-05-10 10:29:26 +08:00
dudaodong
f5784b0f46 feat: add ReplaceByMap 2023-05-10 10:03:13 +08:00
dudaodong
c86a8a479d feat: add ToInterface 2023-05-09 12:01:57 +08:00
dudaodong
e2aeb8ec07 doc: add document for GCD and LCM function 2023-05-06 11:28:38 +08:00
dudaodong
654ba15aaf feat: add GCD and LCM function 2023-05-06 11:02:00 +08:00
dudaodong
945c59896b feat: add IsLeapYear 2023-04-28 14:42:25 +08:00
dudaodong
219e31d929 fix: fix format issue 2023-04-27 15:49:58 +08:00
dudaodong
82cb86b35c doc: add go playground demo for compare package 2023-04-27 14:15:25 +08:00
dudaodong
f93c561f5d doc: update go playground demo 2023-04-27 12:03:15 +08:00
dudaodong
4888909208 fix: fix IsPingConnected failed in windows 2023-04-26 19:53:53 +08:00
dudaodong
33c8875d14 test: update TestWordCount 2023-04-26 19:35:28 +08:00
dudaodong
99cb1b13a3 test: remove unstable test item 2023-04-26 18:14:27 +08:00
dudaodong
42ec189995 release v2.1.20 2023-04-26 18:03:52 +08:00
dudaodong
424c291813 test: add TestExecCommandWithOption 2023-04-26 17:53:20 +08:00
dudaodong
4311b9ac66 test: remove t.Log() 2023-04-26 14:59:45 +08:00
dudaodong
581e338889 doc: add new function to readme file 2023-04-26 14:31:47 +08:00
dudaodong
f399425c2a doc: add document for compare package 2023-04-26 11:02:11 +08:00
dudaodong
dcdb29334d doc: update fileutils package document 2023-04-26 10:44:12 +08:00
dudaodong
4859f3ca23 test: add examples for compare package 2023-04-26 10:19:42 +08:00
dudaodong
9f2528842e feat: add unit test for compare package 2023-04-26 10:05:09 +08:00
dudaodong
6066d6669f feat: add compare package 2023-04-25 18:01:05 +08:00
dudaodong
e3804e9534 test: add test.csv file 2023-04-25 11:34:09 +08:00
dudaodong
2f51397d2c feat: add ReadCsvFile 2023-04-25 11:28:43 +08:00
dudaodong
11217a11c7 feat: add FileSize, MTime, Sha 2023-04-25 11:16:00 +08:00
dudaodong
fa81ee143e refactor: update param name CopyFile 2023-04-25 10:49:12 +08:00
dudaodong
62891f20f8 feat: add IsZipFile 2023-04-24 14:00:53 +08:00
dudaodong
5e79eaa9dd feat: add IsZipFile 2023-04-24 11:00:58 +08:00
dudaodong
aaf45012e4 fix: refact CopyProperties 2023-04-22 14:14:13 +08:00
dudaodong
48c17ea1ce fix: update params in TestIsPingConnected 2023-04-19 17:40:55 +08:00
dudaodong
e90283c3f9 fix: update params in TestIsPingConnected 2023-04-19 17:35:17 +08:00
dudaodong
f82c4a305d fix: update params in TestIsPingConnected 2023-04-19 17:32:30 +08:00
dudaodong
05997603a9 doc: add document for DownloadFile and UploadFile 2023-04-19 16:16:47 +08:00
dudaodong
6d5ec807f7 test: comment some test case 2023-04-19 16:04:35 +08:00
dudaodong
f73c7e7e86 doc: add document and example for IsPingConnected and IsTelnetConnected 2023-04-19 11:48:28 +08:00
dudaodong
c137428b9e feat: add IsPingConnected and IsTelnetConnected 2023-04-19 11:14:10 +08:00
dudaodong
9f68620b37 feat: add IsPingConnected and IsTelnetConnected 2023-04-19 11:13:21 +08:00
dudaodong
2cdbba56a4 feat: add UploadFile and DownloadFile 2023-04-18 20:09:56 +08:00
dudaodong
01a3b139c0 doc: add document for new functions in slice and strutil package 2023-04-18 15:49:09 +08:00
dudaodong
fcb3b97b45 doc: add docment and playground demo for v2.1.19 2023-04-18 15:21:03 +08:00
dudaodong
52ea64bc33 feat: add FindLastBy function 2023-04-17 20:17:26 +08:00
燕归来
14bc08c6d6 feat: add FindBy that a result will be without unrefrence #88 (#90)
feat: add example for FindBy

chore: reduce code duplication
2023-04-17 20:11:56 +08:00
dudaodong
47bdd6718a fix: ExecCommand can't compile in macos 2023-04-17 17:03:46 +08:00
dudaodong
18d27604e6 update mod file 2023-04-17 17:00:53 +08:00
dudaodong
66bd339e3a doc: add example for strutil new functions 2023-04-17 16:35:26 +08:00
燕归来
04abb7a3ea feat: add some function for strutil package #88 (#89) 2023-04-17 16:07:14 +08:00
dudaodong
975c303a31 fix: ExampleListFileNames 2023-04-17 15:35:17 +08:00
dudaodong
3b8dd94a5c fix: TestListFileNames 2023-04-17 15:32:59 +08:00
dudaodong
815791c0b6 Merge branch 'main' into v2 2023-04-17 15:28:37 +08:00
dudaodong
a12a691ee6 release v2.1.19 2023-04-17 15:28:01 +08:00
Nothin
247cf89947 [FEATURE] system add option (#87) 2023-04-17 14:06:49 +08:00
dudaodong
c3fad62d8c doc: update stream package document 2023-04-17 13:53:47 +08:00
dudaodong
a8a96be21b doc: update doc for new added functions 2023-04-17 11:34:17 +08:00
dudaodong
8e297769b2 fix: fix example comment of MapTo function 2023-04-17 11:06:03 +08:00
dudaodong
98cdf1c040 Merge branch 'main' into v2 2023-04-17 10:38:28 +08:00
dudaodong
d7976e31a4 refactor: move typemap.go to maputil package and add document for it 2023-04-17 10:37:56 +08:00
dudaodong
5b11a8b457 refactor: move typemap.go to maputil package and add document for it 2023-04-17 10:36:59 +08:00
Nothin
d4a16534f2 add typemap (#85)
* [FEATURE] typemap, quick map any type to specified type

* [DOC] add more test case

---------

Co-authored-by: zhijian.chen <zhijian.chen@longsys.com>
2023-04-17 10:04:31 +08:00
dudaodong
ecf0688788 update readme file 2023-04-07 17:39:54 +08:00
dudaodong
90f9cad1ea update readme file 2023-04-07 15:23:34 +08:00
dudaodong
4a298876e9 doc: add docment and example for byte.go 2023-04-07 14:53:48 +08:00
dudaodong
74474cd9ef feat: add feature for humanize byte unit 2023-04-07 14:18:28 +08:00
dudaodong
f23f18457e feat: add Pretty and PrettyToWriter 2023-04-06 16:30:38 +08:00
dudaodong
18f01ffd75 doc: update doc and example for validator 2023-04-06 10:46:31 +08:00
dudaodong
c53d541a6b doc: add document for stream package 2023-04-05 20:17:41 +08:00
dudaodong
5b9b4c4344 test: add example for stream package 2023-04-05 18:52:27 +08:00
dudaodong
6e7300bbbf feat: add CurrentPath 2023-04-05 15:55:55 +08:00
dudaodong
3685aee02b fix: fix bug of Comma function 2023-04-05 14:26:42 +08:00
dudaodong
046f3e0bf9 feat: add IsInt, IsFloat, IsNumber 2023-04-05 14:07:23 +08:00
dudaodong
c01c9d14b4 feat: add ReduceRight 2023-04-04 17:54:54 +08:00
dudaodong
f198191063 feat: add ReduceBy 2023-04-04 17:41:37 +08:00
dudaodong
8bdd46bda4 doc: add play ground demo 2023-04-03 10:33:57 +08:00
dudaodong
e29b56c3c3 release v2.1.18 2023-04-03 10:12:50 +08:00
dudaodong
c357fc68c8 doc: update readme file for new feature 2023-04-03 10:12:13 +08:00
dudaodong
bc25e7a037 feat: add IsPrintable 2023-03-31 12:00:32 +08:00
dudaodong
217350042b feat: add RemoveNonPrintable 2023-03-30 14:52:32 +08:00
dudaodong
e56a8a1ef5 feat: add IsASCII 2023-03-30 14:41:32 +08:00
dudaodong
6453f755a6 doc: add doc for IsPrime 2023-03-30 14:09:05 +08:00
dudaodong
027abd6ad5 feat: add IsPrime 2023-03-30 11:54:20 +08:00
dudaodong
91503b1656 comment TestEachWithBreak 2023-03-29 10:31:38 +08:00
dudaodong
e2522cd29b fix: fix TestEachWithBreak case 2023-03-29 10:24:41 +08:00
dudaodong
da69b77892 Merge branch 'main' of github.com:duke-git/lancet 2023-03-29 10:15:56 +08:00
dudaodong
05772d8d7d comment TestEachWithBreak 2023-03-28 20:08:05 +08:00
Mickls
3b497532f3 fix: The LastIndexOf method can never return the index of the first element (#83)
Co-authored-by: JiangCheng <jiangcheng@kezaihui.com>
2023-03-28 20:02:57 +08:00
dudaodong
1cd3be508c refactor rename async package name to 2023-03-24 11:43:56 +08:00
dudaodong
a41d461910 doc: update mathutil package doc 2023-03-24 11:23:45 +08:00
dudaodong
cde5946bf0 feat: add PointDistance 2023-03-23 17:49:07 +08:00
dudaodong
c28803b25e feat: add AngleToRadian and RadianToAngle 2023-03-23 17:41:31 +08:00
dudaodong
f09e521783 doc: add go playground demo 2023-03-22 21:06:01 +08:00
dudaodong
0aa41f337d fix: test failed 2023-03-20 16:39:56 +08:00
dudaodong
48814a720a fix: test failed in promise test 2023-03-20 16:26:21 +08:00
dudaodong
04b79b3dfe release v2.1.17 2023-03-20 16:17:52 +08:00
dudaodong
302007ebdf doc: update readme file for new feature 2023-03-20 16:12:58 +08:00
dudaodong
965e5fbcda feat: add Pop for set 2023-03-20 11:10:35 +08:00
dudaodong
70d0adde42 feat: add EachWithBreak for set 2023-03-20 10:49:14 +08:00
dudaodong
0b80074bb7 refactor: remove unused code 2023-03-20 10:35:37 +08:00
dudaodong
90945a0399 Merge branch 'main' into v2 2023-03-18 19:35:48 +08:00
zm
47dccd63af add the struct package english docs (#82) 2023-03-18 19:33:07 +08:00
dudaodong
4ae7e59829 feat: add example for promise 2023-03-17 16:03:35 +08:00
dudaodong
8f0c60cade test: add unit test for promise Race and Any function 2023-03-17 13:59:18 +08:00
dudaodong
3f6aef1432 fix: fix bug of IsNotNil function 2023-03-16 19:15:36 +08:00
dudaodong
a714e04470 test: add unit test for promise.All function 2023-03-16 19:11:30 +08:00
dudaodong
7456621153 fix: fix bug of IsNil function 2023-03-16 17:01:28 +08:00
dudaodong
73ac9825e9 test: add unit test for Promise 2023-03-16 16:55:32 +08:00
dudaodong
930bb9c839 feat: complete promise Any function 2023-03-16 15:59:06 +08:00
dudaodong
3d8f1be212 feat: add error_join.go to support join error under go1.19, for internal use. 2023-03-16 15:56:54 +08:00
dudaodong
13a4ed59fa doc: update comment for concurrency package 2023-03-16 15:35:26 +08:00
dudaodong
c799d10ce9 feat: add promise All, Race, Any methods 2023-03-16 15:34:28 +08:00
dudaodong
5ab322ade2 feat: add async package, promise implemention 2023-03-16 14:49:07 +08:00
dudaodong
d0ffc61842 doc: fix doc error 2023-03-16 10:36:06 +08:00
zm
5e66bc6227 [structs] change package structutil to structs (#81)
* refactor package structutil to structs

* add structs package zh-CN docs
2023-03-15 19:14:19 +08:00
dudaodong
7261b281ad refactor: add function comment for tag.go 2023-03-15 17:43:47 +08:00
dudaodong
f79693804b refactor: make package variable defaultTagName unexported 2023-03-15 15:08:56 +08:00
dudaodong
534c7a0abc refactor: make errInvalidStruct exported, change error.go to struct_internal.go 2023-03-15 14:58:34 +08:00
dudaodong
4eaff47d38 Merge branch 'main' into v2 2023-03-15 14:43:48 +08:00
dudaodong
3e019522c7 doc: add doc for ForEachWithBreak 2023-03-15 14:42:22 +08:00
dudaodong
0734f220b3 feat: add ForEachWithBreak support break for each loop 2023-03-15 14:38:33 +08:00
zm
2d2c277090 [StructUtil] add support that the Struct can nest any type to transform (#80)
* add support json tag attribute for StructToMap function

* add the structutil to provide more rich functions and fixed #77

* add support that the nested struct to map for structutil

* recover code

* add structutil unit test

* [StructUtil] add unit test
2023-03-15 14:26:34 +08:00
dudaodong
ef1e548dfc merge main 2023-03-13 19:44:44 +08:00
zm
924589d2da Add StructUtil for provide more rich functions (#79)
* add support json tag attribute for StructToMap function

* add the structutil to provide more rich functions and fixed #77
2023-03-13 19:28:37 +08:00
dudaodong
77f32f4cc6 Merge branch 'main' into v2 2023-03-11 20:14:32 +08:00
zm
1755dd249b add support json tag attribute for StructToMap function (#78) 2023-03-11 20:08:41 +08:00
dudaodong
7a25688ec1 doc: add doc for Range and RangeWithStep 2023-03-09 17:13:51 +08:00
dudaodong
51a6912eb3 feat: add RangeWithStep function 2023-03-06 18:05:58 +08:00
dudaodong
28d0428b50 feat: add Range function 2023-03-06 17:49:56 +08:00
dudaodong
6a9eb645bb fix: fix StructToUrlValues failed when tag contain omitempty 2023-03-06 17:07:57 +08:00
dudaodong
3857b342f6 fix: fix ExampleContext failed 2023-03-01 11:45:02 +08:00
dudaodong
71aa91a58d doc: add go playground demo 2023-03-01 11:39:27 +08:00
dudaodong
081908bce3 fix: fix goline error 2023-03-01 11:10:12 +08:00
dudaodong
66efe61834 release v2.1.16 2023-03-01 10:08:53 +08:00
dudaodong
94f7f3e0e5 doc: add new function docs 2023-02-28 15:03:02 +08:00
dudaodong
9d2c9806d1 feat: add ContainBy function 2023-02-24 14:19:10 +08:00
dudaodong
e523d4af6e doc: add doc for FilterMap and FlatMap 2023-02-24 11:23:02 +08:00
dudaodong
f3801bcd8f feat: add FlatMap 2023-02-24 11:14:59 +08:00
dudaodong
5767aad303 feat: add FilterMap 2023-02-24 10:55:27 +08:00
dudaodong
f7aaa1ed2a fix: fix issue #75 2023-02-23 11:43:41 +08:00
dudaodong
ef19a414bc doc: fix doc error 2023-02-23 10:58:43 +08:00
dudaodong
65704dea06 doc: fix doc error 2023-02-23 10:57:48 +08:00
dudaodong
5eac358bb0 doc: format code in doc file 2023-02-22 17:00:46 +08:00
dudaodong
8e36ef5cef doc: add doc for new map functions 2023-02-22 16:59:01 +08:00
dudaodong
21b0d2ec0e doc: add doc for WordCount and SplitWords function 2023-02-22 16:13:41 +08:00
dudaodong
32ca975204 feat: add OmitBy, OmitByKeys, OmitByValues 2023-02-21 14:52:10 +08:00
dudaodong
ec740e442c feat: add WordCount 2023-02-21 14:27:00 +08:00
dudaodong
ed98ad53ec feat: add SplitWords 2023-02-21 14:16:36 +08:00
dudaodong
af7b9d2710 doc: add doc for CopyProperties function 2023-02-20 14:10:55 +08:00
dudaodong
f08b368001 fix: update param type of CopyProperties 2023-02-20 14:04:45 +08:00
dudaodong
be8a0558f8 test: add examples for CopyProperties function 2023-02-20 12:00:49 +08:00
dudaodong
46de539e22 feat: add CopyProperties for merge properties between structs 2023-02-20 11:48:30 +08:00
dudaodong
36fb3abe9e test: add examples for maputil package function 2023-02-19 16:59:21 +08:00
dudaodong
fee8d325b7 doc: add doc for Pad function 2023-02-19 12:58:14 +08:00
dudaodong
8784be1583 feat: add Pad function 2023-02-19 12:37:26 +08:00
dudaodong
84cd68de7f fix: fix bugs of PadEnd and PadStart 2023-02-19 12:34:39 +08:00
dudaodong
a774c060ce feat: add MapKeys and MapValues 2023-02-17 15:41:58 +08:00
dudaodong
730f061b95 feat: add Entries FromEntries Transform 2023-02-17 15:24:46 +08:00
dudaodong
2eb08f3404 feat: add FilterByValues function 2023-02-17 11:59:44 +08:00
dudaodong
4c1496b648 feat: add FilterByKeys function 2023-02-17 11:57:09 +08:00
dudaodong
c2ae784f27 feat: add ValuesBy function 2023-02-17 11:48:11 +08:00
dudaodong
e71cecefea feat: add KeysBy function 2023-02-17 11:40:20 +08:00
dudaodong
572e53aa14 doc: add go playground demo for xerror package 2023-02-16 14:28:50 +08:00
dudaodong
ca9ecb9c8a update go playground demo 2023-02-16 14:10:24 +08:00
dudaodong
8bf0786abe release v2.1.15 2023-02-16 12:02:34 +08:00
dudaodong
61cb8395e3 doc: update doc for xerror package 2023-02-15 14:41:56 +08:00
dudaodong
dde8a41daf doc: update doc for xerror package 2023-02-15 14:41:41 +08:00
dudaodong
d7518e01af doc: fix ExampleXError_StackTrace bug 2023-02-15 12:04:14 +08:00
dudaodong
be9fa7acaa doc: update doc for xerror package 2023-02-15 11:58:33 +08:00
dudaodong
2629a731cc doc: update doc for xerror package 2023-02-15 11:53:21 +08:00
dudaodong
54c7f90b7f test: add examples for xerror package 2023-02-15 10:39:51 +08:00
dudaodong
770bc88b88 doc: update doc for xerror package 2023-02-15 10:14:26 +08:00
dudaodong
4cc1722f81 feat: fix AesEcbEncrypt and AesEcbDecrypt 2023-02-14 16:42:25 +08:00
dudaodong
d0260b2841 feat: add XError to support more contextual error handling 2023-02-14 16:32:57 +08:00
dudaodong
57bd64cae7 feat: add stack 2023-02-14 10:21:38 +08:00
dudaodong
c383719496 doc: add doc for DeepClone function 2023-02-12 19:24:56 +08:00
dudaodong
4b196a72b1 feat: add DeepClone 2023-02-10 15:50:28 +08:00
dudaodong
888381a06c doc: add drop and sort related function doc 2023-02-10 10:53:41 +08:00
dudaodong
a554eb7ef4 doc: add doc for sort function 2023-02-10 10:42:38 +08:00
dudaodong
26ff90122b doc: add doc for Drop function 2023-02-10 10:31:02 +08:00
dudaodong
75b27c6540 feat: add IsSortedByKey 2023-02-10 10:10:57 +08:00
dudaodong
a7e77fa98d feat: add IsSorted 2023-02-09 19:30:11 +08:00
dudaodong
abf392117a feat: add IsAscending, Isdescending 2023-02-09 19:25:58 +08:00
dudaodong
d231d9f572 feat: add DropRightWhile 2023-02-09 17:53:26 +08:00
dudaodong
97447d058e test: add test and example for DropWhile 2023-02-09 17:46:40 +08:00
dudaodong
040e112aa6 feat: add DropRight and DropWhile 2023-02-09 17:38:31 +08:00
dudaodong
afb021b4b5 feat: add Max, Min for stream 2023-02-08 15:20:29 +08:00
dudaodong
5075774000 feat: add Sorted for stream 2023-02-08 15:07:09 +08:00
dudaodong
6bba44dc50 feat: add Concat for stream 2023-02-07 10:47:28 +08:00
dudaodong
422022c74d feat: add Range for stream 2023-02-07 10:36:07 +08:00
dudaodong
87fcf97e2d feat: add FindFirst, Reverse for stream 2023-02-07 10:24:19 +08:00
dudaodong
05d1f348d4 refactor: update constant names 2023-02-06 19:39:31 +08:00
dudaodong
6f2f1f3004 fix: IsZeroValue support pointer 2023-02-06 19:36:36 +08:00
dudaodong
9cd9d1aeb5 release v2.1.14 2023-02-06 17:42:13 +08:00
dudaodong
71b27c0aa9 feat: add ForEach, Reduce for stream 2023-02-06 17:40:54 +08:00
dudaodong
09a379ec6d feat: add ForEach, Reduce for stream 2023-02-06 17:38:33 +08:00
dudaodong
b4b9b03835 feat: add NoneMatch, AllMatch, AnyMatch for stream 2023-02-06 17:24:17 +08:00
dudaodong
48c7794b01 feat: add Limit method of stream 2023-02-06 17:08:36 +08:00
dudaodong
8e3911833d doc: normalize documents 2023-02-06 11:42:03 +08:00
dudaodong
ebe494051b doc: add doc for some new methods of list 2023-02-06 11:35:32 +08:00
dudaodong
c35bda6a65 feat: add ListToMap for list 2023-02-06 11:06:46 +08:00
dudaodong
1fe4cdc429 feat: add Difference and SymmetricDifference for list 2023-02-06 10:55:42 +08:00
dudaodong
6a79e322e3 Merge branch 'main' into v2 2023-02-06 10:00:02 +08:00
Cai Zhijiang
17e8d2bb6d 部分城市有4位区号+8位号码 (#69) 2023-02-06 09:47:21 +08:00
燕归来
325be0d6a1 feat: add func Iterator, ForEach, RetainAll and DeleteAll for List structure (#71) 2023-02-06 09:46:25 +08:00
dudaodong
ea0f96a8c0 feat: add Skip for stream 2023-01-30 16:56:33 +08:00
dudaodong
82cbb54787 feat: add FromChannel for create stream 2023-01-17 16:47:20 +08:00
dudaodong
585d33cafa feat: add Generate for create stream 2023-01-17 16:31:44 +08:00
dudaodong
bc4cf35e15 feat: add Filter, Map, Count for stream 2023-01-17 14:59:47 +08:00
dudaodong
a3bc20af1d feat: add Distinct 2023-01-17 11:39:05 +08:00
dudaodong
61338b6b46 feat: add Stream package 2023-01-17 11:25:15 +08:00
dudaodong
bc3c080ac3 doc: normalize document 2023-01-15 12:43:00 +08:00
dudaodong
d3fab15af3 refactor: clean structure for netutil package 2023-01-14 14:39:06 +08:00
dudaodong
6e3e411d46 doc: normalize document 2023-01-14 12:48:39 +08:00
dudaodong
f976941e36 doc: normalize document 2023-01-14 12:32:27 +08:00
dudaodong
4c5524354c doc: normalize documents 2023-01-13 14:36:33 +08:00
dudaodong
2c6e9a3fb9 doc: format document 2023-01-13 11:01:22 +08:00
dudaodong
5f2c3edff4 doc: format document 2023-01-13 10:57:40 +08:00
dudaodong
b422d98702 doc: format document 2023-01-13 10:48:21 +08:00
dudaodong
6f27e0bfbf doc: format document 2023-01-13 10:47:47 +08:00
dudaodong
ce3b6b461e doc: format document 2023-01-13 10:43:16 +08:00
dudaodong
0d6ad4f0d2 doc: format document 2023-01-13 10:41:47 +08:00
dudaodong
c875a7f8b8 doc: format document 2023-01-13 10:39:39 +08:00
dudaodong
0c62d117a1 doc: format document 2023-01-13 10:12:37 +08:00
dudaodong
c260ce493d doc: normalize documents 2023-01-12 15:44:34 +08:00
dudaodong
9ffe96d3ef update readme file 2023-01-12 11:32:43 +08:00
dudaodong
d4bba76dc8 fix: fix ExampleSchedule failed 2023-01-09 11:25:14 +08:00
dudaodong
adaa3ebc43 Merge branch 'main' into v2 2023-01-09 11:16:13 +08:00
dudaodong
61d38ae3b8 doc: update doc for algorithm package 2023-01-09 11:15:25 +08:00
dudaodong
c85d910044 add playground demo 2023-01-09 11:02:41 +08:00
dudaodong
d95a7c6101 fix: fix example function bug in function package 2023-01-08 21:09:41 +08:00
dudaodong
bce3641ec6 fix: fix example function bug in datetime package 2023-01-08 21:04:39 +08:00
dudaodong
ceb134b2fd fix: fix example function bug in datetime package 2023-01-08 21:01:05 +08:00
dudaodong
4b9b1d32c5 release v2.1.13 2023-01-08 20:45:43 +08:00
dudaodong
395e0883c7 fix: fix example test failed of CreateFile 2023-01-08 20:44:23 +08:00
dudaodong
a930511054 test&doc: add example and update doc for xerror package 2023-01-08 20:36:32 +08:00
dudaodong
7380721ccc test&doc: add example and update doc for xerror package 2023-01-08 20:36:17 +08:00
dudaodong
936011dc3b fix: fix bug in file test 2023-01-08 20:25:11 +08:00
dudaodong
bc0ee08f38 test&doc: add example and update doc for datetime package 2023-01-08 20:16:04 +08:00
dudaodong
f1afd753d4 test&doc: add example and update doc for netutil package 2023-01-08 16:57:03 +08:00
dudaodong
b05a0a91c3 test&doc: add example and update doc for netutil package 2023-01-08 16:54:29 +08:00
dudaodong
da2eb66657 doc: update doc for datastructure package 2023-01-08 15:42:34 +08:00
dudaodong
ad20159de2 doc: update doc for datastructure package 2023-01-08 15:41:59 +08:00
dudaodong
278733d3d1 Todo: add todo for playground demo of function 2023-01-07 18:27:07 +08:00
dudaodong
2f184907ff doc: update document for cryptor package 2023-01-07 18:18:23 +08:00
dudaodong
50fcc718ee test: add example for cryptor package 2023-01-07 17:34:42 +08:00
dudaodong
cc68feb52d doc&test: add example and update doc for retry package 2023-01-07 14:22:07 +08:00
dudaodong
ca2a51b37e test&doc: add example and update doc for function package 2023-01-06 17:12:32 +08:00
dudaodong
be444f521d test: add examples for function package 2023-01-06 16:12:44 +08:00
dudaodong
e21dd07d46 doc: update doc for validator package 2023-01-06 14:14:00 +08:00
dudaodong
4044deac70 test: add examples for validator package 2023-01-06 11:31:51 +08:00
dudaodong
d9c6294775 fix: fix goline error 2023-01-05 14:55:47 +08:00
dudaodong
d8505d1a5f doc: update doc for slice package 2023-01-05 14:49:30 +08:00
dudaodong
6498c7d68a test: add examples for slice package 2023-01-05 11:26:56 +08:00
dudaodong
5f0211f0c4 test: add examples for slice package 2023-01-04 14:44:10 +08:00
dudaodong
1de2e2cedd test: add examples for random package 2023-01-03 15:10:42 +08:00
dudaodong
c8f8b1b7d9 doc: update doc for fileutil package 2023-01-03 14:33:29 +08:00
dudaodong
3062eb7789 test: add examples for fileutil package 2023-01-03 11:55:23 +08:00
dudaodong
64d5486cc6 doc: add example and update doc for formatter package 2023-01-02 15:35:09 +08:00
dudaodong
6d57891f66 doc: update document for mathutil package 2023-01-02 15:19:47 +08:00
dudaodong
927245e47f test: add example for mathutil package 2023-01-02 14:59:49 +08:00
dudaodong
31fdbee0b5 doc: update document for maputil function 2023-01-02 14:21:23 +08:00
dudaodong
3712819994 test: add exmaple for maputil package 2023-01-02 14:06:12 +08:00
dudaodong
6d7dec1cea doc: update doc for convertor package 2023-01-01 22:00:23 +08:00
dudaodong
9b6a004dbc test: add example for convertor package 2023-01-01 21:24:24 +08:00
dudaodong
3ad6f4bd9e doc: update doc for condition package 2022-12-31 16:47:18 +08:00
dudaodong
b8c6746f31 test: add example for condition package 2022-12-31 16:26:43 +08:00
dudaodong
0bf8bbf4cb doc: add example and update docment for channel 2022-12-31 13:38:52 +08:00
dudaodong
a6ba1028c5 doc: add example and update docment for channel 2022-12-31 13:35:44 +08:00
dudaodong
cc54dd7ec9 doc: add example and update docment for channel 2022-12-31 13:12:16 +08:00
dudaodong
54834dba4c doc: update doc for system package 2022-12-30 14:28:49 +08:00
dudaodong
e996d4c945 test: add examples for system package 2022-12-30 14:14:37 +08:00
dudaodong
ae92ae7666 test: add examples for system package 2022-12-30 14:14:22 +08:00
dudaodong
526e568d0e doc: add doc for Substring 2022-12-29 20:03:59 +08:00
dudaodong
1dc5e8ac23 feat: add Substring function 2022-12-29 19:55:40 +08:00
dudaodong
b5f7b0e670 doc: update document for algorithm package 2022-12-29 15:32:47 +08:00
dudaodong
39c576248c test: add examples for lrucache 2022-12-29 11:43:14 +08:00
dudaodong
eb164d1536 test: add examples for lrucache function 2022-12-29 11:43:04 +08:00
dudaodong
68e170080c test: add examples for sort function 2022-12-28 20:18:05 +08:00
dudaodong
652b09135c test: add examples for search function 2022-12-28 17:58:56 +08:00
dudaodong
bff24c89bc doc: update strutil document 2022-12-27 17:26:34 +08:00
dudaodong
49a460eef8 doc: update document and add playgound example for strutil package 2022-12-27 16:57:32 +08:00
dudaodong
a58e52e53c test: add example function for strutil package 2022-12-27 15:40:51 +08:00
dudaodong
b07356423f fix: update format 2022-12-26 17:57:06 +08:00
dudaodong
005dd9d2ab fix: fix word misspelling 2022-12-26 17:51:30 +08:00
dudaodong
65315dafb1 feat: add take iterator 2022-12-26 17:20:14 +08:00
dudaodong
b06fb6736d feat: add reduce for iterator 2022-12-26 16:55:24 +08:00
dudaodong
b9f0854950 feat: add join iterator 2022-12-26 15:58:44 +08:00
dudaodong
6a2dd328ad feat: add test for map iterator and filter iterator 2022-12-26 15:13:35 +08:00
dudaodong
dd1147f6d0 feat: add Channel iterator 2022-12-26 15:02:28 +08:00
dudaodong
6da7ce64af test: add unit test for RangeIterator 2022-12-26 14:24:23 +08:00
dudaodong
b7e5d946f1 release v2.1.12 2022-12-15 16:55:20 +08:00
dudaodong
687db4ce79 update readme file 2022-12-15 16:44:30 +08:00
dudaodong
a9a4bb8841 update readme file 2022-12-15 16:42:22 +08:00
dudaodong
bc6cb5f61b fix code issue in doc 2022-12-15 16:38:50 +08:00
dudaodong
2c57266f8e test: update some test functions 2022-12-15 15:22:01 +08:00
dudaodong
57e49c9520 doc: update document for funcations CamelCase/KebabCase/UpperKebabCase/SnakeCase/UpperSnakeCase 2022-12-14 21:42:43 +08:00
dudaodong
985c9a5d9a refactor: refact CamelCase function 2022-12-14 21:27:29 +08:00
dudaodong
5cfb11f036 feat: fix and add SnakeCase/UpperSnakeCase 2022-12-14 21:17:30 +08:00
dudaodong
5b3d48a1e7 feat: fix and add KebabCase/UpperKebabCase 2022-12-14 21:09:22 +08:00
dudaodong
d0576e028f clean code 2022-12-13 19:52:37 +08:00
dudaodong
76bdec2b54 test: add cases for Capitalize 2022-12-13 16:16:16 +08:00
dudaodong
fa20aba3a7 fix: fix CamelCase function bug 2022-12-13 14:23:32 +08:00
dudaodong
7a4a429e23 test: add cases for Capitalize 2022-12-12 21:11:19 +08:00
dudaodong
a70ec6ad1e refactor: use constraints from golang.org/x/exp/constraints 2022-12-11 11:25:34 +08:00
dudaodong
e435fa271b doc: update doc for Comma 2022-12-10 21:03:16 +08:00
dudaodong
1533d00891 refactor: update Comma function 2022-12-10 20:59:27 +08:00
dudaodong
8b99641de0 test: remove print info in test function 2022-12-10 19:19:49 +08:00
dudaodong
251f899f18 fix: TestExecCommand failed in linux/macos 2022-12-10 19:12:19 +08:00
dudaodong
00407e5182 fix: fix lint issue 2022-12-10 19:09:18 +08:00
dudaodong
4e457ad672 change: change update and insert function in link datastruture 2022-12-10 17:45:29 +08:00
dudaodong
7d8d9c3543 fix: fix lint issue 2022-12-10 16:55:06 +08:00
dudaodong
1197e8d1b6 fix: fix lint issue 2022-12-10 16:53:41 +08:00
dudaodong
13bbe19ab2 fix: fix lint issue 2022-12-10 16:41:40 +08:00
dudaodong
2725575d2f doc: add doc for IsGBK' 2022-12-09 19:28:45 +08:00
dudaodong
037d2729ce doc: update doc for ExecCommand 2022-12-09 19:20:15 +08:00
dudaodong
09d98745b0 fix: fix ExecCommand bug in windows 2022-12-09 19:10:55 +08:00
dudaodong
af5cfe6da1 feat: add IsGBK validator 2022-12-09 17:36:59 +08:00
Mickls
d59259bbe0 feat: A more reasonable IndexOf function (#66) 2022-12-09 11:31:40 +08:00
dudaodong
3189628d54 fix: fix AesCfbDecrypt 2022-12-08 15:07:40 +08:00
dudaodong
62c5e251a5 remove website 2022-12-08 14:55:21 +08:00
dudaodong
6e6444c8c0 refator: clean code 2022-12-06 20:20:36 +08:00
dudaodong
dd613e98b2 refator: clean code 2022-12-06 20:00:41 +08:00
dudaodong
2d905ab03e fix: fix word misspelling 2022-12-04 11:25:02 +08:00
dudaodong
205fedb197 release v2.1.11 2022-12-04 11:11:05 +08:00
dudaodong
4c864da62d doc: update readme file 2022-12-04 11:10:19 +08:00
dudaodong
263ab7e316 clean code 2022-12-03 14:41:58 +08:00
dudaodong
809b7a53df doc: update docment for slice package 2022-12-03 14:33:15 +08:00
dudaodong
61c43daabb doc: add doc for Count and CountBy function 2022-12-03 14:20:37 +08:00
dudaodong
18914ee2cd feat: add deprecat IntSlice, InterfaceSlice and StringSlice 2022-12-03 14:00:44 +08:00
dudaodong
0a8058956f feat: add Count and CountBy function 2022-12-03 13:04:12 +08:00
dudaodong
a044da7d2f refactor: clean code 2022-12-03 12:58:25 +08:00
dudaodong
f8b785c4cb doc: add doc for Sort and SortBy 2022-12-02 15:47:16 +08:00
dudaodong
82c8a04c35 make SortByField function deprecate 2022-12-02 15:17:08 +08:00
dudaodong
280ecb5cef feat: add SortBy function for slice 2022-12-02 14:53:57 +08:00
dudaodong
ec27ad4c40 feat: add Sort function for slice 2022-12-01 22:46:56 +08:00
dudaodong
d66f92cd68 doc: update slice and convertor document 2022-12-01 11:43:10 +08:00
dudaodong
d8ed692651 refactor: code improvement, ToString, Contain, Compact 2022-12-01 11:38:25 +08:00
dudaodong
a16de97d1d refactor: code improvement, ToString, Contain, Compact 2022-12-01 11:38:14 +08:00
dudaodong
6f458e4367 doc: add doc for NewSetFromSlice 2022-11-30 12:34:56 +08:00
dudaodong
37c7508ad0 feat: add NewSetFromSlice function for set 2022-11-30 12:00:55 +08:00
dudaodong
acb5844b15 docs: add doc for AddIfNotExist and AddIfNotExistBy 2022-11-30 11:54:04 +08:00
dudaodong
76f4eeea16 docs: add doc for Merge and Repeat 2022-11-30 11:35:32 +08:00
dudaodong
5466a23019 refactor: fix bad code smell 2022-11-30 11:20:13 +08:00
dudaodong
5692982dd1 feat: add AddIfNotExistBy function for set 2022-11-29 23:59:22 +08:00
dudaodong
c39c8914fb refactor: fix bad code smell 2022-11-29 23:50:17 +08:00
dudaodong
29bdca1bd2 feat: add AddIfNotExist function for set 2022-11-29 23:39:29 +08:00
dudaodong
eb66d038ac feat: update iterator package 2022-11-29 13:58:48 +08:00
dudaodong
a99ada5ee1 feat: add iterator package 2022-11-28 19:24:25 +08:00
dudaodong
a87faf5453 feat: add Repeate function for slice 2022-11-27 21:43:38 +08:00
dudaodong
ab6fec2f69 refactor: fix bad code smell 2022-11-27 21:36:30 +08:00
dudaodong
7b290989f5 feat: add Merge function 2022-11-27 20:20:00 +08:00
dudaodong
5722c724e6 Merge branch 'main' into v2 2022-11-27 19:29:33 +08:00
dudaodong
f84584ca04 doc: add website link 2022-11-27 18:44:25 +08:00
dudaodong
80cbbdc787 docs: format index content 2022-11-26 17:37:09 +08:00
dudaodong
be148e07ba fix: fix chunk slice bug 2022-11-26 16:21:57 +08:00
dudaodong
d36ab5cc3a fix: go report issue ineffassign 2022-11-18 17:05:54 +08:00
dudaodong
2b17329094 release v2.1.10 2022-11-17 16:11:48 +08:00
dudaodong
f869a0a670 fix: issue#62: fix ZipSlip bug 2022-11-16 16:04:38 +08:00
dudaodong
be000a4bd6 fix: issue#62: fix ZipSlip bug 2022-11-16 15:08:42 +08:00
DuDaoDong
81efa800ea Create SECURITY.md 2022-11-16 11:31:50 +08:00
dudaodong
a783de57a8 release v2.1.9 2022-11-08 15:22:37 +08:00
dudaodong
a622959a78 docs: add new functions readme 2022-11-08 15:21:31 +08:00
dudaodong
f709dd53ce docs: update doc for random package 2022-11-08 14:48:02 +08:00
dudaodong
ee9e9625e2 docs: add doc for UnionBy and KeyBy 2022-11-08 14:21:17 +08:00
dudaodong
84da7d4f27 feat: add RandUpper, RandLower, RandNumeral, and RandNumeralOrLetter 2022-11-06 20:04:52 +08:00
dudaodong
089fd4e13c feat: add UnionBy for slice 2022-11-05 19:45:34 +08:00
dudaodong
6c40e02324 refactor: clean code 2022-11-05 19:33:56 +08:00
dudaodong
a270b1b634 feat: make code clear 2022-11-05 17:09:56 +08:00
dudaodong
260fb795d3 feat: add KeyBy for slice 2022-11-05 16:52:31 +08:00
dudaodong
8c036f830c refactor: remove unuseful code 2022-11-05 16:39:42 +08:00
dudaodong
bf332b9f1c release v2.1.8 2022-10-21 16:22:52 +08:00
dudaodong
6b6cd66f9f Merge branch 'main' into v2 2022-10-19 17:31:51 +08:00
燕归来
5399c2290e feat: support type alias for Number constraint (#60) 2022-10-19 17:21:53 +08:00
dudaodong
6248293c49 doc: add docment for Replace and ReplaceAll 2022-10-17 10:40:35 +08:00
dudaodong
eced25b76d test: add unit test for Replace and ReplaceAll 2022-10-17 10:26:54 +08:00
dudaodong
96a4327aa7 fix: fix some static check issues 2022-10-15 15:03:24 +08:00
dudaodong
fcfbdea597 feat: add Replace and ReplaceAll for slice 2022-10-15 14:49:49 +08:00
dudaodong
87896f917a doc: add document for pipeline 2022-10-15 12:36:11 +08:00
dudaodong
b8563ed646 feat: add Pipeline function 2022-10-15 12:29:47 +08:00
dudaodong
1ccf0af2b3 doc: update document for datetime package 2022-10-14 10:20:38 +08:00
dudaodong
6314889c6a release v2.1.7 2022-10-14 10:08:43 +08:00
dudaodong
294bd5a5ed doc: update document for hashmap 2022-10-11 15:41:09 +08:00
dudaodong
ca44815fd5 Merge branch 'main' into v2 2022-10-11 15:02:28 +08:00
dudaodong
bcd1cabf80 feat: add Keys and Values function for hashmap 2022-10-10 16:34:05 +08:00
CyJaySong
4edefcca67 expand BeginOfWeek、EndOfWeek (#59) 2022-10-10 15:44:22 +08:00
dudaodong
fab24c8d12 feat: add Iterate for hashmap datastructure 2022-10-10 15:25:30 +08:00
dudaodong
604acd9b07 doc:add lancet api doc website 2022-09-29 18:41:22 +08:00
dudaodong
531cb19fd1 release v2.1.6 2022-08-31 17:07:32 +08:00
dudaodong
4f0161ca53 doc: add source code link for http_client 2022-08-31 15:56:41 +08:00
dudaodong
73362b7f69 doc: update readme file 2022-08-31 11:40:24 +08:00
dudaodong
b289f2975b doc: add document for functions in netutil/http_client.go 2022-08-31 11:20:22 +08:00
dudaodong
90ce2705ca test: add unit test for http client 2022-08-30 17:33:58 +08:00
dudaodong
35e1d09ce3 feat: add http client for sending http request 2022-08-30 17:22:17 +08:00
dudaodong
d67d8fad3a doc: fix missing word in file condition.md 2022-08-29 14:02:30 +08:00
dudaodong
c5e6d01a31 update readme file: add new package and function 2022-08-29 11:50:37 +08:00
dudaodong
6d6c3f692f refactor: change TernaryOperator signature 2022-08-29 11:27:51 +08:00
dudaodong
c695837b16 doc: add document for package condition 2022-08-29 11:23:02 +08:00
dudaodong
ef28b52963 fix: fix regex isChineseMobileRegexMatcher not work 2022-08-28 20:58:34 +08:00
dudaodong
18b2b6ff7c feat: add functons: And, Or, Xor, Nor, Xnor, Nand 2022-08-28 20:57:28 +08:00
dudaodong
6a05a123f4 feat: add Bool function to check if a value is truthy or falsy 2022-08-28 20:38:19 +08:00
dudaodong
f7c33f258d Merge branch 'main' into v2 2022-08-27 19:25:24 +08:00
dudaodong
04058dd7da refactor: change common package to condition package 2022-08-27 19:19:34 +08:00
郑一诺她爸
72e1d92fa1 TernaryOperator Reduce if else operations (#56)
* feat:(slice add AppendIfAbsent function)

* feat:(slice add TernaryOperator function)

Co-authored-by: george.zheng <george.zheng@ambergroup.io>
2022-08-27 19:12:03 +08:00
dudaodong
063df0f0d1 doc: add docment for IsZeroValue function 2022-08-27 19:04:57 +08:00
dudaodong
fc10689b25 feat: add IsZeroValue function 2022-08-27 18:57:45 +08:00
dudaodong
9239bcfdc3 doc: fmt code example 2022-08-26 16:34:20 +08:00
dudaodong
c984815dea doc: fmt code example 2022-08-26 16:29:55 +08:00
dudaodong
301cb5db87 doc: add hashmap 2022-08-26 16:26:16 +08:00
dudaodong
cc1bacff74 doc: add document for EncodeByte and DecodeByte 2022-08-26 10:54:51 +08:00
dudaodong
f49f75b371 test: add unit test for EncodeByte and DecodeByte 2022-08-26 10:47:25 +08:00
dudaodong
b30f4a7bab feat: add DecodeByte 2022-08-26 10:35:54 +08:00
dudaodong
982cb8932b feat: add EncodeByte 2022-08-26 10:34:42 +08:00
dudaodong
9107eb4b32 fix: fix resize bug in HashMap 2022-08-25 14:04:26 +08:00
dudaodong
1acf977b24 release v2.1.5 2022-08-25 11:11:36 +08:00
dudaodong
5c878d0873 doc: change ReverseStr to Reverse in all docment 2022-08-24 10:37:56 +08:00
dudaodong
ab0716a472 refactor: change ReverseStr to Reverse in strutil package 2022-08-24 10:35:18 +08:00
dudaodong
3c2e0ca5b3 doc: add document for hashmap 2022-08-24 10:28:57 +08:00
dudaodong
551e66ba29 refactor: update HashMap Put method 2022-08-24 10:20:02 +08:00
dudaodong
4eeeabb227 feat: add Delete method for hashmap 2022-08-23 15:07:54 +08:00
dudaodong
b3437fdddf feat: add Delete method for hashmap 2022-08-23 15:07:13 +08:00
dudaodong
312dcab369 feat: add Delete method for hashmap 2022-08-23 15:05:32 +08:00
dudaodong
0cb89f4f46 test: add unit test for HashMap 2022-08-23 14:15:51 +08:00
dudaodong
a2dec87995 feat: add Put method for hashmap 2022-08-23 14:11:14 +08:00
dudaodong
9094cb29bf feat: add new HashMap data structure 2022-08-22 15:21:30 +08:00
dudaodong
ddb992ad2f refactor: BuildMaxHeap 2022-08-22 11:10:17 +08:00
dudaodong
24f18aaaec refactor: change function sign for QuickSort 2022-08-22 11:02:25 +08:00
dudaodong
36169874e5 refactor: change sort file name 2022-08-22 10:58:47 +08:00
dudaodong
23aeb6ac99 refactor: change sort file name 2022-08-22 10:57:04 +08:00
dudaodong
a1984f0a59 feat: add BuildMaxHeap 2022-08-22 10:51:37 +08:00
IceCafeCup
c95db23d2c feat: Set struct uses empty struct as value (#55) 2022-08-13 12:39:30 +08:00
Abirdcfly
fbf251d805 delete minor unreachable code caused by log.Fatal (#54)
Signed-off-by: Abirdcfly <fp544037857@gmail.com>
2022-08-10 14:19:21 +08:00
dudaodong
337f08a04b fix: issue #53 2022-08-06 17:41:45 +08:00
dudaodong
c6a7371049 change lastest v1 version 2022-08-03 10:02:46 +08:00
dudaodong
b697858038 release v2.1.4 2022-08-03 09:56:02 +08:00
dudaodong
5446f7e33c doc: add document for list methods 2022-07-28 12:56:11 +08:00
dudaodong
553f63e76b refactor: update param name in AppendIfAbsent 2022-07-27 15:45:34 +08:00
dudaodong
fc3e94df58 doc: add document for AppendIfAbsent function 2022-07-27 15:44:54 +08:00
dudaodong
5c66f38a5b test: fix test function name TestAppendIfAbsent 2022-07-27 15:38:51 +08:00
郑一诺她爸
70e213b3f7 feat:(slice add AppendIfAbsent function) (#52)
Co-authored-by: george.zheng <george.zheng@ambergroup.io>
2022-07-25 20:52:33 +08:00
donutloop
c1b7500bcb List: add cap (#51)
Cap return cap of the inner data
2022-07-25 20:50:31 +08:00
donutloop
3d7600a9e4 list: add DeleteIf method (#50)
DeleteIf delete all satisfying f(data[i]), returns count of removed elements
2022-07-23 18:52:29 +08:00
donutloop
0299c454ab list: add sublist method (#49)
SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.
2022-07-23 15:00:04 +08:00
dudaodong
741af66404 test: add todo fix for TestSchedule 2022-07-22 10:30:44 +08:00
dudaodong
ef5d0379a1 doc: fix missing word 2022-07-22 10:24:34 +08:00
dudaodong
105ab49763 refactor: change slice Contain logic, convert to map first, then check existence 2022-07-22 10:22:34 +08:00
dudaodong
b5ba9ba573 fix: fix TestMapToSlice function result independent of order of elements 2022-07-22 10:17:23 +08:00
donutloop
ac3baac5c6 list: Add LastIndexOfFunc and IndexOfFunc method (#48)
* LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i])
* IndexOfFunc returns the first index satisfying f(v)
2022-07-22 10:04:31 +08:00
donutloop
a82b5dd206 list: add LastIndexOf (#46)
Add LastIndexOf method too List and fix doc

LastIndexOf returns the index of the last occurrence of the value in this list.
if not found return -1
2022-07-21 15:19:18 +08:00
CyJaySong
ac0fb5ef25 Update convertor_zh-CN.md (#45)
fix docs
2022-07-21 11:22:30 +08:00
dudaodong
9bd1c205fe release: update readme file and release v2.1.3 2022-07-21 11:16:19 +08:00
dudaodong
6ccf9fd3cf doc: add document for GetOsBits function 2022-07-21 11:05:17 +08:00
dudaodong
c02ef2c62d doc: format code in markdown file 2022-07-20 19:42:17 +08:00
dudaodong
6414031754 doc: fix mistaken link to map source file 2022-07-20 19:38:14 +08:00
dudaodong
5336130570 doc: add funcation IsDisjoint 2022-07-20 19:33:37 +08:00
dudaodong
bfa46d46a2 doc: format code in markdown file 2022-07-20 19:33:02 +08:00
dudaodong
aab28b914c Merge branch 'main' into v2 2022-07-20 17:48:26 +08:00
donutloop
336e454ce7 maputil: IsDisjoint (#43)
Verifies map a and map b have no keys in common.

if it returns true then the maps are disjoint otherwise a join in some form available
2022-07-20 17:26:54 +08:00
anyanfei
35a50bd792 System: Add the system bits judgment (#44)
Co-authored-by: anyanfei <anyanfei@yungengxin.com>
2022-07-20 17:25:14 +08:00
dudaodong
2fd23f02f6 doc: format code in markdown file 2022-07-20 15:44:33 +08:00
dudaodong
aad5b447c9 doc: format code in markdown file 2022-07-20 15:13:44 +08:00
dudaodong
cece13e929 fix: fix aes/des cbc crypto iv bug 2022-07-20 11:42:52 +08:00
donutloop
ecf325a06c maputil: preallocate len and cap for keys and values slice (#41)
Length of keys and values is know in advance, use this knowledge to preallocate memory.
Space usage increases by const factor
2022-07-19 15:04:19 +08:00
dudaodong
44370aef5e refactor: change variable name to 2022-07-18 15:52:51 +08:00
dudaodong
1782b11ec4 refactor: refact Intersection function 2022-07-18 15:33:45 +08:00
dudaodong
fe6495123c doc: add document for EncodeUrl function 2022-07-18 11:31:12 +08:00
dudaodong
d442f564ce Merge branch 'main' into v2 2022-07-17 13:35:12 +08:00
dudaodong
f35446cc13 docs: fix word mistaken 2022-07-17 13:34:19 +08:00
dudaodong
506a8b4776 feat: add EncodeUrl function 2022-07-15 16:29:41 +08:00
dudaodong
47ecfbfd5f docs: add doc for Flatten function 2022-07-14 17:25:47 +08:00
dudaodong
82f7401368 feat: add Flatten function 2022-07-14 11:53:16 +08:00
dudaodong
068c878d1e release v2.1.2 2022-07-13 10:40:03 +08:00
dudaodong
47b2402345 docs: update readme file add new functions 2022-07-13 10:32:03 +08:00
dudaodong
a245716f99 docs: add doc for new function: ToChannel ToMap MapToSlice 2022-07-13 10:26:49 +08:00
dudaodong
71c85bb8f0 docs: add doc for functions GetRequestPublicIp and IsInternalIP 2022-07-13 10:09:23 +08:00
dudaodong
5edafec393 Merge branch 'main' into v2 2022-07-13 09:55:04 +08:00
tangqiu0205
957878dd98 feat: add func GetRequestPublicIp and IsInternalIP (#40)
* add: add func GetRequestPublicIp and IsInternalIP

* fix: fix test fileutil fail

Co-authored-by: zhanghu <305835360@qq.com>
2022-07-13 09:52:35 +08:00
dudaodong
12e979cf3c feat: add ToMapToSlice function 2022-07-11 11:28:46 +08:00
dudaodong
ded42f8ff5 feat: add ToChannel function 2022-07-11 11:11:16 +08:00
dudaodong
d06cde3fcf feat: add ToMap function 2022-07-11 10:27:38 +08:00
dudaodong
9cd8bfb8e0 docs: compress log png 2022-07-08 10:52:53 +08:00
dudaodong
51c9877224 docs: update change param type to for some slice functions 2022-07-07 17:47:02 +08:00
dudaodong
f7f6427919 merge main branch 2022-07-07 16:35:46 +08:00
tangqiu0205
56b6844a2d update: update type constraint any -> Comparable. (#37)
* update: update type constraint any -> Comparable.

* update: update type constraint any -> Comparable.

Co-authored-by: zhanghu <305835360@qq.com>
2022-07-07 16:31:48 +08:00
dudaodong
cce56f0479 docs: update query string type in http request 2022-07-07 11:21:16 +08:00
dudaodong
3dbd7d8980 fix: sending post request with header multipart/form-data support query string type is map[string]string 2022-07-07 10:23:15 +08:00
dudaodong
3625921912 fix: fix missused function ToSlice -> ToSlicePointer 2022-07-06 11:31:11 +08:00
dudaodong
1faaf54986 release v2.1.1 2022-07-06 11:25:02 +08:00
dudaodong
efe1fba267 docs: add doc for heap datastructure 2022-07-06 11:22:00 +08:00
dudaodong
0c43cb3f68 docs: update convertor package doc 2022-07-06 11:17:45 +08:00
dudaodong
c25111e349 docs: add doc for ToSlice and ToSlicePointer function 2022-07-06 11:15:51 +08:00
dudaodong
a61ab5716e docs: add doc for ToPointer function 2022-07-06 11:04:30 +08:00
dudaodong
628404dc7f fix: fix lint error 2022-07-06 10:57:45 +08:00
tangqiu0205
bab0a27e40 Add ToPointer,ToSlicePointer,ToSlice func (#36)
* Add ToPointer func

* Add ToSlice and ToSlicePointer func

Co-authored-by: zhanghu <305835360@qq.com>
2022-07-05 19:15:54 +08:00
dudaodong
fc0e104591 Merge branch 'main' into v2 2022-06-30 14:12:54 +08:00
dudaodong
e83e9a1651 docs: add doc for MaxHeap 2022-06-29 16:43:56 +08:00
dudaodong
3d2e6295c4 docs: add doc for MaxHeap 2022-06-29 15:40:14 +08:00
dudaodong
221fe44e63 docs: add doc for MaxHeap 2022-06-29 15:37:42 +08:00
dudaodong
7930f517ae feat: add MaxHeap func PrintStructure 2022-06-29 11:08:07 +08:00
dudaodong
0f61321d5b test: add unit test for MaxHeap 2022-06-27 17:55:35 +08:00
dudaodong
7ddeeb51e5 feat: add MaxHeap 2022-06-27 17:01:17 +08:00
dudaodong
484d2845b3 feat: add MaxHeap 2022-06-27 16:27:34 +08:00
dudaodong
bbbc6b6941 docs: update go version badge 2022-06-24 09:39:38 +08:00
dudaodong
acf028cdcd release v2.1.0 2022-06-22 16:10:54 +08:00
dudaodong
31e43ec356 docs: add doc for UniqueBy function 2022-06-22 16:08:37 +08:00
dudaodong
9f45e68fef test: add fuzz test for Equal function 2022-06-21 14:17:33 +08:00
dudaodong
d2df99a6f0 feat: add UniqueBy function in slice.go 2022-06-17 15:18:04 +08:00
dudaodong
713c341831 docs: update comment for Size function of ArrayQueue 2022-06-16 18:03:50 +08:00
287 changed files with 72581 additions and 20522 deletions

7
.gitignore vendored
View File

@@ -6,4 +6,9 @@ fileutil/*.txt
fileutil/*.zip
fileutil/*.link
fileutil/unzip/*
cryptor/*.pem
fileutil/tempdir/*
slice/testdata/*
cryptor/*.pem
test
docs/node_modules
docs/.vitepress/cache

1977
README.md

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

15
SECURITY.md Normal file
View File

@@ -0,0 +1,15 @@
# Security Policy
## Supported Versions
Here is the lancet version and compatibility with go language version.
| Version | Supported |
| ------- | ------------------|
| 2.x.x | +go v1.18 |
| 1.x.x | +go v1.12 |
## Reporting a Vulnerability
For now, there is no public website to report a vulnerability, If you find security issue in lancet, you can send it to me via my email `lanliddd.2007@163.com`.
we can discuss it. I am appreciate if someone can create a public page for reporting vulnerability.

View File

@@ -26,7 +26,7 @@ type LRUCache[K comparable, V any] struct {
length int
}
// NewLRUCache return a LRUCache pointer
// NewLRUCache creates a LRUCache pointer instance.
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
return &LRUCache[K, V]{
cache: make(map[K]*lruNode[K, V], capacity),
@@ -37,7 +37,8 @@ func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
}
}
// Get value of key from lru cache
// Get value of key from lru cache.
// Play: https://go.dev/play/p/iUynEfOP8G0
func (l *LRUCache[K, V]) Get(key K) (V, bool) {
var value V
@@ -50,7 +51,8 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
return value, false
}
// Put value of key into lru cache
// Put value of key into lru cache.
// Play: https://go.dev/play/p/iUynEfOP8G0
func (l *LRUCache[K, V]) Put(key K, value V) {
node, ok := l.cache[key]
if !ok {
@@ -69,6 +71,23 @@ func (l *LRUCache[K, V]) Put(key K, value V) {
l.length = len(l.cache)
}
// Delete item from lru cache.
func (l *LRUCache[K, V]) Delete(key K) bool {
node, ok := l.cache[key]
if ok {
key := l.deleteNode(node)
delete(l.cache, key)
return true
}
return false
}
// Len returns the number of items in the cache.
func (l *LRUCache[K, V]) Len() int {
return l.length
}
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
if l.tail != nil {
l.tail.next = node

View File

@@ -0,0 +1,79 @@
package algorithm
import "fmt"
func ExampleLRUCache_Put() {
cache := NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
fmt.Println(result1, ok1)
fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
// Output:
// 1 true
// 2 true
// 0 false
}
func ExampleLRUCache_Get() {
cache := NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
fmt.Println(result1, ok1)
fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
// Output:
// 1 true
// 2 true
// 0 false
}
func ExampleLRUCache_Delete() {
cache := NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result1, ok1 := cache.Get(1)
ok2 := cache.Delete(2)
_, ok3 := cache.Get(2)
fmt.Println(result1, ok1)
fmt.Println(ok2)
fmt.Println(ok3)
// Output:
// 1 true
// true
// false
}
func ExampleLRUCache_Len() {
cache := NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result := cache.Len()
fmt.Println(result)
// Output:
// 2
}

View File

@@ -7,15 +7,16 @@ import (
)
func TestLRUCache(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestLRUCache")
cache := NewLRUCache[int, int](2)
cache := NewLRUCache[int, int](3)
cache.Put(1, 1)
cache.Put(2, 2)
cache.Put(3, 3)
_, ok := cache.Get(0)
asssert.Equal(false, ok)
asssert.Equal(3, cache.Len())
v, ok := cache.Get(1)
asssert.Equal(true, ok)
@@ -25,12 +26,9 @@ func TestLRUCache(t *testing.T) {
asssert.Equal(true, ok)
asssert.Equal(2, v)
cache.Put(3, 3)
v, ok = cache.Get(1)
asssert.Equal(false, ok)
asssert.NotEqual(1, v)
v, ok = cache.Get(3)
ok = cache.Delete(2)
asssert.Equal(true, ok)
asssert.Equal(3, v)
_, ok = cache.Get(2)
asssert.Equal(false, ok)
}

View File

@@ -1,26 +1,28 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph. TODO
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph.
package algorithm
import "github.com/duke-git/lancet/v2/lancetconstraints"
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
// LinearSearch Simple linear search algorithm that iterates over all elements of an slice
// If a target is found, the index of the target is returned. Else the function return -1
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int {
// LinearSearch return the index of target in slice base on equal function.
// If not found return -1
// Play: https://go.dev/play/p/IsS7rgn5s3x
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
for i, v := range slice {
if comparator.Compare(v, target) == 0 {
if equal(v, target) {
return i
}
}
return -1
}
// BinarySearch search for target within a sorted slice, recursive call itself.
// If a target is found, the index of the target is returned. Else the function return -1
// BinarySearch return the index of target within a sorted slice, use binary search (recursive call itself).
// If not found return -1.
// Play: https://go.dev/play/p/t6MeGiUSN47
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
if highIndex < lowIndex || len(sortedSlice) == 0 {
return -1
@@ -39,8 +41,9 @@ func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, com
return midIndex
}
// BinaryIterativeSearch search for target within a sorted slice.
// If a target is found, the index of the target is returned. Else the function return -1
// BinaryIterativeSearch return the index of target within a sorted slice, use binary search (no recursive).
// If not found return -1.
// Play: https://go.dev/play/p/Anozfr8ZLH3
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
startIndex := lowIndex
endIndex := highIndex

View File

@@ -0,0 +1,51 @@
package algorithm
import "fmt"
func ExampleLinearSearch() {
numbers := []int{3, 4, 5, 3, 2, 1}
equalFunc := func(a, b int) bool {
return a == b
}
result1 := LinearSearch(numbers, 3, equalFunc)
result2 := LinearSearch(numbers, 6, equalFunc)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// -1
}
func ExampleBinarySearch() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
result1 := BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
result2 := BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
}
func ExampleBinaryIterativeSearch() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
result1 := BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
result2 := BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
}

View File

@@ -6,20 +6,26 @@ import (
"github.com/duke-git/lancet/v2/internal"
)
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
func TestLinearSearch(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestLinearSearch")
comparator := &intComparator{}
asssert.Equal(4, LinearSearch(sortedNumbers, 5, comparator))
asssert.Equal(-1, LinearSearch(sortedNumbers, 9, comparator))
numbers := []int{3, 4, 5, 3, 2, 1}
equalFunc := func(a, b int) bool {
return a == b
}
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
}
func TestBinarySearch(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestBinarySearch")
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
}
@@ -27,7 +33,9 @@ func TestBinarySearch(t *testing.T) {
func TestBinaryIterativeSearch(t *testing.T) {
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
}

View File

@@ -1,12 +1,12 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package algorithm contain some basic algorithm functions. eg. sort, search
package algorithm
import "github.com/duke-git/lancet/v2/lancetconstraints"
// BubbleSort use bubble to sort slice.
// BubbleSort applys the bubble sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/GNdv7Jg2Taj
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
for j := 0; j < len(slice)-1-i; j++ {
@@ -18,7 +18,8 @@ func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
}
// InsertionSort use insertion to sort slice.
// InsertionSort applys the insertion sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/G5LJiWgJJW6
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
for j := i; j > 0; j-- {
@@ -32,7 +33,8 @@ func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
}
// SelectionSort use selection to sort slice.
// SelectionSort applys the selection sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/oXovbkekayS
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
min := i
@@ -45,7 +47,8 @@ func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
}
// ShellSort shell sort slice.
// ShellSort applys the shell sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/3ibkszpJEu3
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
size := len(slice)
@@ -64,12 +67,17 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
}
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1.
// Play: https://go.dev/play/p/7Y7c1Elk3ax
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
quickSort(slice, 0, len(slice)-1, comparator)
}
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
if lowIndex < highIndex {
p := partition(slice, lowIndex, highIndex, comparator)
QuickSort(slice, lowIndex, p-1, comparator)
QuickSort(slice, p+1, highIndex, comparator)
quickSort(slice, lowIndex, p-1, comparator)
quickSort(slice, p+1, highIndex, comparator)
}
}
@@ -89,7 +97,8 @@ func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
return i
}
// HeapSort use heap to sort slice
// HeapSort applys the heap sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/u6Iwa1VZS_f
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
size := len(slice)
@@ -122,7 +131,8 @@ func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraint
slice[i] = temp
}
// MergeSort merge sorting for slice
// MergeSort applys the merge sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/ydinn9YzUJn
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
mergeSort(slice, 0, len(slice)-1, comparator)
}
@@ -163,7 +173,8 @@ func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lance
}
}
// CountSort use count sorting for slice
// CountSort applys the count sort algorithm to sort the collection, don't change the original collection data.
// Play: https://go.dev/play/p/tB-Umgm0DrP
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
size := len(slice)
out := make([]T, size)

View File

@@ -0,0 +1,93 @@
package algorithm
import "fmt"
func ExampleBubbleSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
BubbleSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleCountSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
sortedNumber := CountSort(numbers, comparator)
fmt.Println(numbers)
fmt.Println(sortedNumber)
// Output:
// [2 1 5 3 6 4]
// [1 2 3 4 5 6]
}
func ExampleHeapSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
HeapSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleMergeSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
MergeSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleInsertionSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
InsertionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleSelectionSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
SelectionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleShellSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
ShellSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
func ExampleQuickSort() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
QuickSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}

View File

@@ -30,14 +30,6 @@ func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
return 0
}
// var peoples = []people{
// {Name: "a", Age: 20},
// {Name: "b", Age: 10},
// {Name: "c", Age: 17},
// {Name: "d", Age: 8},
// {Name: "e", Age: 28},
// }
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
@@ -53,9 +45,8 @@ func (c *intComparator) Compare(v1 any, v2 any) int {
return 0
}
// var intSlice = []int{2, 1, 5, 3, 6, 4}
func TestBubbleSortForStructSlice(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
peoples := []people{
@@ -75,7 +66,9 @@ func TestBubbleSortForStructSlice(t *testing.T) {
}
func TestBubbleSortForIntSlice(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
BubbleSort(numbers, comparator)
@@ -84,6 +77,7 @@ func TestBubbleSortForIntSlice(t *testing.T) {
}
func TestInsertionSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestInsertionSort")
peoples := []people{
@@ -103,6 +97,7 @@ func TestInsertionSort(t *testing.T) {
}
func TestSelectionSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestSelectionSort")
peoples := []people{
@@ -122,6 +117,7 @@ func TestSelectionSort(t *testing.T) {
}
func TestShellSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestShellSort")
peoples := []people{
@@ -141,6 +137,7 @@ func TestShellSort(t *testing.T) {
}
func TestQuickSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestQuickSort")
peoples := []people{
@@ -151,7 +148,7 @@ func TestQuickSort(t *testing.T) {
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
QuickSort(peoples, 0, len(peoples)-1, comparator)
QuickSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
@@ -160,6 +157,7 @@ func TestQuickSort(t *testing.T) {
}
func TestHeapSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestHeapSort")
peoples := []people{
@@ -179,6 +177,7 @@ func TestHeapSort(t *testing.T) {
}
func TestMergeSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestMergeSort")
peoples := []people{
@@ -198,6 +197,7 @@ func TestMergeSort(t *testing.T) {
}
func TestCountSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestCountSort")
peoples := []people{
@@ -209,7 +209,6 @@ func TestCountSort(t *testing.T) {
}
comparator := &peopleAgeComparator{}
sortedPeopleByAge := CountSort(peoples, comparator)
t.Log(sortedPeopleByAge)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", sortedPeopleByAge)

72
compare/compare.go Normal file
View File

@@ -0,0 +1,72 @@
// Copyright 2023 dudaodong@gmail.com. All rights resulterved.
// Use of this source code is governed by MIT license
// Package compare provides a lightweight comparison function on any type.
// reference: https://github.com/stretchr/testify
package compare
import (
"reflect"
"time"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/mathutil"
"golang.org/x/exp/constraints"
)
// operator type
const (
equal = "eq"
lessThan = "lt"
greaterThan = "gt"
lessOrEqual = "le"
greaterOrEqual = "ge"
)
var (
timeType = reflect.TypeOf(time.Time{})
bytesType = reflect.TypeOf([]byte{})
)
// Equal checks if two values are equal or not. (check both type and value)
// Play: https://go.dev/play/p/wmVxR-to4lz
func Equal(left, right any) bool {
return compareValue(equal, left, right)
}
// EqualValue checks if two values are equal or not. (check value only)
// Play: https://go.dev/play/p/fxnna_LLD9u
func EqualValue(left, right any) bool {
ls, rs := convertor.ToString(left), convertor.ToString(right)
return ls == rs
}
// LessThan checks if value `left` less than value `right`.
// Play: https://go.dev/play/p/cYh7FQQj0ne
func LessThan(left, right any) bool {
return compareValue(lessThan, left, right)
}
// GreaterThan checks if value `left` greater than value `right`.
// Play: https://go.dev/play/p/9-NYDFZmIMp
func GreaterThan(left, right any) bool {
return compareValue(greaterThan, left, right)
}
// LessOrEqual checks if value `left` less than or equal to value `right`.
// Play: https://go.dev/play/p/e4T_scwoQzp
func LessOrEqual(left, right any) bool {
return compareValue(lessOrEqual, left, right)
}
// GreaterOrEqual checks if value `left` greater than or equal to value `right`.
// Play: https://go.dev/play/p/vx8mP0U8DFk
func GreaterOrEqual(left, right any) bool {
return compareValue(greaterOrEqual, left, right)
}
// InDelta checks if two values are equal or not within a delta.
// Play: https://go.dev/play/p/TuDdcNtMkjo
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool {
return float64(mathutil.Abs(left-right)) <= delta
}

View File

@@ -0,0 +1,196 @@
package compare
import (
"fmt"
"time"
)
func ExampleEqual() {
result1 := Equal(1, 1)
result2 := Equal("1", "1")
result3 := Equal([]int{1, 2, 3}, []int{1, 2, 3})
result4 := Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
result5 := Equal(1, "1")
result6 := Equal(1, int64(1))
result7 := Equal([]int{1, 2}, []int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
func ExampleEqualValue() {
result1 := EqualValue(1, 1)
result2 := EqualValue(int(1), int64(1))
result3 := EqualValue(1, "1")
result4 := EqualValue(1, "2")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// true
// false
}
func ExampleLessThan() {
result1 := LessThan(1, 2)
result2 := LessThan(1.1, 2.2)
result3 := LessThan("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := LessThan(time1, time2)
result5 := LessThan(2, 1)
result6 := LessThan(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
func ExampleGreaterThan() {
result1 := GreaterThan(2, 1)
result2 := GreaterThan(2.2, 1.1)
result3 := GreaterThan("b", "a")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := GreaterThan(time2, time1)
result5 := GreaterThan(1, 2)
result6 := GreaterThan(int64(2), 1)
result7 := GreaterThan("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
func ExampleLessOrEqual() {
result1 := LessOrEqual(1, 1)
result2 := LessOrEqual(1.1, 2.2)
result3 := LessOrEqual("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := LessOrEqual(time1, time2)
result5 := LessOrEqual(2, 1)
result6 := LessOrEqual(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
func ExampleGreaterOrEqual() {
result1 := GreaterOrEqual(1, 1)
result2 := GreaterOrEqual(2.2, 1.1)
result3 := GreaterOrEqual("b", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := GreaterOrEqual(time2, time1)
result5 := GreaterOrEqual(1, 2)
result6 := GreaterOrEqual(int64(2), 1)
result7 := GreaterOrEqual("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// 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
}

323
compare/compare_internal.go Normal file
View File

@@ -0,0 +1,323 @@
package compare
import (
"bytes"
"encoding/json"
"reflect"
"time"
"github.com/duke-git/lancet/v2/convertor"
)
func compareValue(operator string, left, right any) bool {
leftType, rightType := reflect.TypeOf(left), reflect.TypeOf(right)
if leftType.Kind() != rightType.Kind() {
return false
}
switch leftType.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64, reflect.Bool, reflect.String:
return compareBasicValue(operator, left, right)
case reflect.Struct, reflect.Slice, reflect.Map:
return compareRefValue(operator, left, right, leftType.Kind())
}
return false
}
func compareRefValue(operator string, leftObj, rightObj any, kind reflect.Kind) bool {
leftVal, rightVal := reflect.ValueOf(leftObj), reflect.ValueOf(rightObj)
switch kind {
case reflect.Struct:
// compare time
if leftVal.CanConvert(timeType) {
timeObj1, ok := leftObj.(time.Time)
if !ok {
timeObj1 = leftVal.Convert(timeType).Interface().(time.Time)
}
timeObj2, ok := rightObj.(time.Time)
if !ok {
timeObj2 = rightVal.Convert(timeType).Interface().(time.Time)
}
return compareBasicValue(operator, timeObj1.UnixNano(), timeObj2.UnixNano())
}
// for other struct type, only process equal operator
switch operator {
case equal:
return objectsAreEqualValues(leftObj, rightObj)
}
case reflect.Slice:
// compare []byte
if leftVal.CanConvert(bytesType) {
bytesObj1, ok := leftObj.([]byte)
if !ok {
bytesObj1 = leftVal.Convert(bytesType).Interface().([]byte)
}
bytesObj2, ok := rightObj.([]byte)
if !ok {
bytesObj2 = rightVal.Convert(bytesType).Interface().([]byte)
}
switch operator {
case equal:
if bytes.Compare(bytesObj1, bytesObj2) == 0 {
return true
}
case lessThan:
if bytes.Compare(bytesObj1, bytesObj2) == -1 {
return true
}
case greaterThan:
if bytes.Compare(bytesObj1, bytesObj2) == 1 {
return true
}
case lessOrEqual:
if bytes.Compare(bytesObj1, bytesObj2) <= 0 {
return true
}
case greaterOrEqual:
if bytes.Compare(bytesObj1, bytesObj2) >= 0 {
return true
}
}
}
// for other type slice, only process equal operator
switch operator {
case equal:
return reflect.DeepEqual(leftObj, rightObj)
}
case reflect.Map:
// only process equal operator
switch operator {
case equal:
return reflect.DeepEqual(leftObj, rightObj)
}
}
return false
}
func objectsAreEqualValues(expected, actual interface{}) bool {
if objectsAreEqual(expected, actual) {
return true
}
actualType := reflect.TypeOf(actual)
if actualType == nil {
return false
}
expectedValue := reflect.ValueOf(expected)
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
// Attempt comparison after type conversion
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
}
return false
}
func objectsAreEqual(expected, actual interface{}) bool {
if expected == nil || actual == nil {
return expected == actual
}
exp, ok := expected.([]byte)
if !ok {
return reflect.DeepEqual(expected, actual)
}
act, ok := actual.([]byte)
if !ok {
return false
}
if exp == nil || act == nil {
return exp == nil && act == nil
}
return bytes.Equal(exp, act)
}
// compareBasic compare basic value: integer, float, string, bool
func compareBasicValue(operator string, leftValue, rightValue any) bool {
if leftValue == nil && rightValue == nil && operator == equal {
return true
}
switch leftVal := leftValue.(type) {
case json.Number:
if left, err := leftVal.Float64(); err == nil {
switch rightVal := rightValue.(type) {
case json.Number:
if right, err := rightVal.Float64(); err == nil {
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
right, err := convertor.ToFloat(rightValue)
if err != nil {
return false
}
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
}
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
left, err := convertor.ToFloat(leftValue)
if err != nil {
return false
}
switch rightVal := rightValue.(type) {
case json.Number:
if right, err := rightVal.Float64(); err == nil {
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
right, err := convertor.ToFloat(rightValue)
if err != nil {
return false
}
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
case string:
left := leftVal
switch right := rightValue.(type) {
case string:
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
case bool:
left := leftVal
switch right := rightValue.(type) {
case bool:
switch operator {
case equal:
if left == right {
return true
}
}
}
}
return false
}

156
compare/compare_test.go Normal file
View File

@@ -0,0 +1,156 @@
package compare
import (
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
func TestEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqual")
assert.Equal(true, Equal(1, 1))
assert.Equal(true, Equal(int64(1), int64(1)))
assert.Equal(true, Equal("a", "a"))
assert.Equal(true, Equal(true, true))
assert.Equal(true, Equal([]int{1, 2, 3}, []int{1, 2, 3}))
assert.Equal(true, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}))
assert.Equal(false, Equal(1, 2))
assert.Equal(false, Equal(1, int64(1)))
assert.Equal(false, Equal("a", "b"))
assert.Equal(false, Equal(true, false))
assert.Equal(false, Equal([]int{1, 2}, []int{1, 2, 3}))
assert.Equal(false, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}))
time1 := time.Now()
time2 := time1.Add(time.Second)
time3 := time1.Add(time.Second)
assert.Equal(false, Equal(time1, time2))
assert.Equal(true, Equal(time2, time3))
st1 := struct {
A string
B string
}{
A: "a",
B: "b",
}
st2 := struct {
A string
B string
}{
A: "a",
B: "b",
}
st3 := struct {
A string
B string
}{
A: "a1",
B: "b",
}
assert.Equal(true, Equal(st1, st2))
assert.Equal(false, Equal(st1, st3))
}
func TestEqualValue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqualValue")
assert.Equal(true, EqualValue(1, 1))
assert.Equal(true, EqualValue(int(1), int64(1)))
assert.Equal(true, EqualValue(1, "1"))
assert.Equal(false, EqualValue(1, "2"))
}
func TestLessThan(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLessThan")
assert.Equal(true, LessThan(1, 2))
assert.Equal(true, LessThan(1.1, 2.2))
assert.Equal(true, LessThan("a", "b"))
time1 := time.Now()
time2 := time1.Add(time.Second)
assert.Equal(true, LessThan(time1, time2))
assert.Equal(false, LessThan(1, 1))
assert.Equal(false, LessThan(1, int64(1)))
}
func TestGreaterThan(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGreaterThan")
assert.Equal(true, GreaterThan(2, 1))
assert.Equal(true, GreaterThan(2.2, 1.1))
assert.Equal(true, GreaterThan("b", "a"))
time1 := time.Now()
time2 := time1.Add(time.Second)
assert.Equal(true, GreaterThan(time2, time1))
assert.Equal(false, GreaterThan(1, 2))
assert.Equal(false, GreaterThan(int64(2), 1))
assert.Equal(false, GreaterThan("b", "c"))
}
func TestLessOrEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLessOrEqual")
assert.Equal(true, LessOrEqual(1, 2))
assert.Equal(true, LessOrEqual(1, 1))
assert.Equal(true, LessOrEqual(1.1, 2.2))
assert.Equal(true, LessOrEqual("a", "b"))
time1 := time.Now()
time2 := time1.Add(time.Second)
assert.Equal(true, LessOrEqual(time1, time2))
assert.Equal(false, LessOrEqual(2, 1))
assert.Equal(false, LessOrEqual(1, int64(2)))
}
func TestGreaterOrEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGreaterThan")
assert.Equal(true, GreaterOrEqual(2, 1))
assert.Equal(true, GreaterOrEqual(1, 1))
assert.Equal(true, GreaterOrEqual(2.2, 1.1))
assert.Equal(true, GreaterOrEqual("b", "b"))
time1 := time.Now()
time2 := time1.Add(time.Second)
assert.Equal(true, GreaterOrEqual(time2, time1))
assert.Equal(false, GreaterOrEqual(1, 2))
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))
}

View File

@@ -1,7 +1,7 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
package concurrency
import (
@@ -11,17 +11,18 @@ import (
// Channel is a logic object which can generate or manipulate go channel
// all methods of Channel are in the book tilted《Concurrency in Go》
type Channel struct {
type Channel[T any] struct {
}
// NewChannel return a Channel instance
func NewChannel() *Channel {
return &Channel{}
func NewChannel[T any]() *Channel[T] {
return &Channel[T]{}
}
// Generate a data of type any chan, put param `values` into the chan
func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
dataStream := make(chan any)
// Generate creates channel, then put values into the channel.
// Play: https://go.dev/play/p/7aB4KyMMp9A
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T {
dataStream := make(chan T)
go func() {
defer close(dataStream)
@@ -38,9 +39,10 @@ func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
return dataStream
}
// Repeat return a data of type any chan, put param `values` into the chan repeatly until cancel the context.
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
dataStream := make(chan any)
// Repeat create channel, put values into the channel repeatly until cancel the context.
// Play: https://go.dev/play/p/k5N_ALVmYjE
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T {
dataStream := make(chan T)
go func() {
defer close(dataStream)
@@ -57,10 +59,11 @@ func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
return dataStream
}
// RepeatFn return a chan, excutes fn repeatly, and put the result into retruned chan
// until close the `done` channel
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
dataStream := make(chan any)
// RepeatFn create a channel, excutes fn repeatly, and put the result into the channel
// until close context.
// Play: https://go.dev/play/p/4J1zAWttP85
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T {
dataStream := make(chan T)
go func() {
defer close(dataStream)
@@ -75,9 +78,10 @@ func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
return dataStream
}
// Take return a chan whose values are tahken from another chan
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any {
takeStream := make(chan any)
// Take create a channel whose values are taken from another channel with limit number.
// Play: https://go.dev/play/p/9Utt-1pDr2J
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T {
takeStream := make(chan T)
go func() {
defer close(takeStream)
@@ -94,16 +98,17 @@ func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int)
return takeStream
}
// FanIn merge multiple channels into one channel
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any {
out := make(chan any)
// FanIn merge multiple channels into one channel.
// Play: https://go.dev/play/p/2VYFMexEvTm
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T {
out := make(chan T)
go func() {
var wg sync.WaitGroup
wg.Add(len(channels))
for _, c := range channels {
go func(c <-chan any) {
go func(c <-chan T) {
defer wg.Done()
for v := range c {
select {
@@ -121,10 +126,11 @@ func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
return out
}
// Tee split one chanel into two channels
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any) {
out1 := make(chan any)
out2 := make(chan any)
// Tee split one chanel into two channels, until cancel the context.
// Play: https://go.dev/play/p/3TQPKnCirrP
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) {
out1 := make(chan T)
out2 := make(chan T)
go func() {
defer close(out1)
@@ -147,18 +153,19 @@ func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan an
return out1, out2
}
// Bridge link multiply channels into one channel
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any {
valStream := make(chan any)
// Bridge link multiply channels into one channel.
// Play: https://go.dev/play/p/qmWSy1NVF-Y
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
valStream := make(chan T)
go func() {
defer close(valStream)
for {
var stream <-chan any
var stream <-chan T
select {
case maybeStream, ok := <-chanStream:
if ok == false {
if !ok {
return
}
stream = maybeStream
@@ -178,8 +185,9 @@ func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-ch
return valStream
}
// Or read one or more channels into one channel, will close when any readin channel is closed
func (c *Channel) Or(channels ...<-chan any) <-chan any {
// Or read one or more channels into one channel, will close when any readin channel is closed.
// Play: https://go.dev/play/p/Wqz9rwioPww
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T {
switch len(channels) {
case 0:
return nil
@@ -187,7 +195,7 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
return channels[0]
}
orDone := make(chan any)
orDone := make(chan T)
go func() {
defer close(orDone)
@@ -199,17 +207,12 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
case <-channels[1]:
}
default:
m := len(channels) / 2
select {
case <-c.Or(channels[:m]...):
case <-c.Or(channels[m:]...):
case <-channels[0]:
case <-channels[1]:
case <-channels[2]:
case <-c.Or(append(channels[3:], orDone)...):
}
// select {
// case <-channels[0]:
// case <-channels[1]:
// case <-channels[2]:
// case <-c.Or(append(channels[3:], orDone)...):
// }
}
}()
@@ -217,8 +220,9 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
}
// OrDone read a channel into another channel, will close until cancel context.
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any {
valStream := make(chan any)
// Play: https://go.dev/play/p/lm_GoS6aDjo
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T {
valStream := make(chan T)
go func() {
defer close(valStream)

View File

@@ -0,0 +1,196 @@
package concurrency
import (
"context"
"fmt"
"time"
)
func ExampleChannel_Generate() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
// Output:
// 1
// 2
// 3
}
func ExampleChannel_Repeat() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 1
// 2
}
func ExampleChannel_RepeatFn() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() string {
return "hello"
}
c := NewChannel[string]()
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// hello
// hello
// hello
}
func ExampleChannel_Take() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}
func ExampleChannel_FanIn() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
channels := make([]<-chan int, 2)
for i := 0; i < 2; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
}
chs := c.FanIn(ctx, channels...)
for v := range chs {
fmt.Println(v) //1 1 0 0 or 0 0 1 1
}
}
func ExampleChannel_Or() {
sig := func(after time.Duration) <-chan any {
c := make(chan any)
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := NewChannel[any]()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
)
if time.Since(start).Seconds() < 2 {
fmt.Println("ok")
}
// Output:
// ok
}
func ExampleChannel_OrDone() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for v := range c.OrDone(ctx, intStream) {
fmt.Println(v)
}
// Output:
// 1
// 1
// 1
}
func ExampleChannel_Tee() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
ch1, ch2 := c.Tee(ctx, intStream)
for v := range ch1 {
fmt.Println(v)
fmt.Println(<-ch2)
}
// Output:
// 1
// 1
// 1
// 1
}
func ExampleChannel_Bridge() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel[int]()
genVals := func() <-chan <-chan int {
out := make(chan (<-chan int))
go func() {
defer close(out)
for i := 1; i <= 5; i++ {
stream := make(chan int, 1)
stream <- i
close(stream)
out <- stream
}
}()
return out
}
for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}

View File

@@ -9,34 +9,30 @@ import (
)
func TestGenerate(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGenerate")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
c := NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
// for v := range intStream {
// t.Log(v) //1, 2, 3
// }
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(3, <-intStream)
}
func TestRepeat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRepeat")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
// for v := range intStream {
// t.Log(v) //1, 2, 1, 2, 1
// }
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(1, <-intStream)
@@ -45,34 +41,32 @@ func TestRepeat(t *testing.T) {
}
func TestRepeatFn(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRepeatFn")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
fn := func() string {
s := "a"
return s
}
c := NewChannel()
c := NewChannel[string]()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
// for v := range dataStream {
// t.Log(v) //a, a, a
// }
assert.Equal("a", <-dataStream)
assert.Equal("a", <-dataStream)
assert.Equal("a", <-dataStream)
}
func TestTake(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTake")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
@@ -80,7 +74,7 @@ func TestTake(t *testing.T) {
numbers <- 5
defer close(numbers)
c := NewChannel()
c := NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
assert.Equal(1, <-intStream)
@@ -89,13 +83,14 @@ func TestTake(t *testing.T) {
}
func TestFanIn(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFanIn")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
channels := make([]<-chan any, 3)
c := NewChannel[int]()
channels := make([]<-chan int, 3)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
@@ -111,6 +106,7 @@ func TestFanIn(t *testing.T) {
}
func TestOr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOr")
sig := func(after time.Duration) <-chan any {
@@ -124,7 +120,7 @@ func TestOr(t *testing.T) {
start := time.Now()
c := NewChannel()
c := NewChannel[any]()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
@@ -133,62 +129,57 @@ func TestOr(t *testing.T) {
sig(5*time.Second),
)
t.Logf("done after %v", time.Since(start))
assert.Equal(1, 1)
assert.Equal(true, time.Since(start).Seconds() < 2)
}
func TestOrDone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOrDone")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
var res any
for val := range c.OrDone(ctx, intStream) {
t.Logf("%v", val)
res = val
assert.Equal(1, val)
}
assert.Equal(1, res)
}
func TestTee(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTee")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
c := NewChannel[int]()
inStream := c.Take(ctx, c.Repeat(ctx, 1), 4)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
val1 := val
val2 := <-out2
// t.Log("val1 is", val1)
// t.Log("val2 is", val2)
assert.Equal(1, val1)
assert.Equal(1, val2)
}
}
func TestBridge(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBridge")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
c := NewChannel[int]()
genVals := func() <-chan <-chan int {
chanStream := make(chan (<-chan int))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
stream := make(chan int, 1)
stream <- i
close(stream)
chanStream <- stream
@@ -199,7 +190,6 @@ func TestBridge(t *testing.T) {
index := 0
for val := range c.Bridge(ctx, genVals()) {
// t.Logf("%v ", val) //0 1 2 3 4 5 6 7 8 9
assert.Equal(index, val)
index++
}

85
condition/condition.go Normal file
View File

@@ -0,0 +1,85 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package condition contains some functions for conditional judgment. eg. And, Or, TernaryOperator ...
// The implementation of this package refers to the implementation of carlmjohnson's truthy package, you may find more
// useful information in truthy(https://github.com/carlmjohnson/truthy), thanks carlmjohnson.
package condition
import "reflect"
// Bool returns the truthy value of anything.
// If the value's type has a Bool() bool method, the method is called and returned.
// If the type has an IsZero() bool method, the opposite value is returned.
// Slices and maps are truthy if they have a length greater than zero.
// All other types are truthy if they are not their zero value.
// Play: https://go.dev/play/p/ETzeDJRSvhm
func Bool[T any](value T) bool {
switch m := any(value).(type) {
case interface{ Bool() bool }:
return m.Bool()
case interface{ IsZero() bool }:
return !m.IsZero()
}
return reflectValue(&value)
}
func reflectValue(vp any) bool {
switch rv := reflect.ValueOf(vp).Elem(); rv.Kind() {
case reflect.Map, reflect.Slice:
return rv.Len() != 0
default:
is := rv.IsZero()
return !is
}
}
// And returns true if both a and b are truthy.
// Play: https://go.dev/play/p/W1SSUmt6pvr
func And[T, U any](a T, b U) bool {
return Bool(a) && Bool(b)
}
// Or returns false if neither a nor b is truthy.
// Play: https://go.dev/play/p/UlQTxHaeEkq
func Or[T, U any](a T, b U) bool {
return Bool(a) || Bool(b)
}
// Xor returns true if a or b but not both is truthy.
// Play: https://go.dev/play/p/gObZrW7ZbG8
func Xor[T, U any](a T, b U) bool {
valA := Bool(a)
valB := Bool(b)
return (valA || valB) && valA != valB
}
// Nor returns true if neither a nor b is truthy.
// Play: https://go.dev/play/p/g2j08F_zZky
func Nor[T, U any](a T, b U) bool {
return !(Bool(a) || Bool(b))
}
// Xnor returns true if both a and b or neither a nor b are truthy.
// Play: https://go.dev/play/p/OuDB9g51643
func Xnor[T, U any](a T, b U) bool {
valA := Bool(a)
valB := Bool(b)
return (valA && valB) || (!valA && !valB)
}
// Nand returns false if both a and b are truthy.
// Play: https://go.dev/play/p/vSRMLxLIbq8
func Nand[T, U any](a T, b U) bool {
return !Bool(a) || !Bool(b)
}
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
// Play: https://go.dev/play/p/ElllPZY0guT
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
if Bool(isTrue) {
return ifValue
} else {
return elseValue
}
}

View File

@@ -0,0 +1,163 @@
package condition
import "fmt"
func ExampleBool() {
// bool
result1 := Bool(false)
result2 := Bool(true)
fmt.Println(result1)
fmt.Println(result2)
// integer
result3 := Bool(0)
result4 := Bool(1)
fmt.Println(result3)
fmt.Println(result4)
// string
result5 := Bool("")
result6 := Bool(" ")
fmt.Println(result5)
fmt.Println(result6)
// slice
var nums = []int{}
result7 := Bool(nums)
nums = append(nums, 1, 2)
result8 := Bool(nums)
fmt.Println(result7)
fmt.Println(result8)
// Output:
// false
// true
// false
// true
// false
// true
// false
// true
}
func ExampleAnd() {
result1 := And(0, 1)
result2 := And(0, "")
result3 := And(0, "0")
result4 := And(1, "0")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
}
func ExampleOr() {
result1 := Or(0, "")
result2 := Or(0, 1)
result3 := Or(0, "0")
result4 := Or(1, "0")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// true
// true
// true
}
func ExampleXor() {
result1 := Xor(0, 0)
result2 := Xor(1, 1)
result3 := Xor(0, 1)
result4 := Xor(1, 0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// true
// true
}
func ExampleNor() {
result1 := Nor(0, 0)
result2 := Nor(1, 1)
result3 := Nor(0, 1)
result4 := Nor(1, 0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// false
// false
// false
}
func ExampleXnor() {
result1 := Xnor(0, 0)
result2 := Xnor(1, 1)
result3 := Xnor(0, 1)
result4 := Xnor(1, 0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// false
// false
}
func ExampleNand() {
result1 := Nand(0, 0)
result2 := Nand(1, 0)
result3 := Nand(0, 1)
result4 := Nand(1, 1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// true
// false
}
func ExampleTernaryOperator() {
conditionTrue := 2 > 1
result1 := TernaryOperator(conditionTrue, 0, 1)
fmt.Println(result1)
conditionFalse := 2 > 3
result2 := TernaryOperator(conditionFalse, 0, 1)
fmt.Println(result2)
// Output:
// 0
// 1
}

136
condition/condition_test.go Normal file
View File

@@ -0,0 +1,136 @@
package condition
import (
"errors"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
type TestStruct struct{}
func TestBool(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBool")
// bool
assert.Equal(false, Bool(false))
assert.Equal(true, Bool(true))
// integer
assert.Equal(false, Bool(0))
assert.Equal(true, Bool(1))
// float
assert.Equal(false, Bool(0.0))
assert.Equal(true, Bool(0.1))
// string
assert.Equal(false, Bool(""))
assert.Equal(true, Bool(" "))
assert.Equal(true, Bool("0"))
// slice
var nums [2]int
assert.Equal(false, Bool(nums))
nums = [2]int{0, 1}
assert.Equal(true, Bool(nums))
// map
assert.Equal(false, Bool(map[string]string{}))
assert.Equal(true, Bool(map[string]string{"a": "a"}))
// channel
var ch chan int
assert.Equal(false, Bool(ch))
ch = make(chan int)
assert.Equal(true, Bool(ch))
// interface
var err error
assert.Equal(false, Bool(err))
err = errors.New("error message")
assert.Equal(true, Bool(err))
// struct
assert.Equal(false, Bool(struct{}{}))
assert.Equal(true, Bool(time.Now()))
// struct pointer
ts := TestStruct{}
assert.Equal(false, Bool(ts))
assert.Equal(true, Bool(&ts))
}
func TestAnd(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAnd")
assert.Equal(false, And(0, 1))
assert.Equal(false, And(0, ""))
assert.Equal(false, And(0, "0"))
assert.Equal(true, And(1, "0"))
}
func TestOr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOr")
assert.Equal(false, Or(0, ""))
assert.Equal(true, Or(0, 1))
assert.Equal(true, Or(0, "0"))
assert.Equal(true, Or(1, "0"))
}
func TestXor(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOr")
assert.Equal(false, Xor(0, 0))
assert.Equal(true, Xor(0, 1))
assert.Equal(true, Xor(1, 0))
assert.Equal(false, Xor(1, 1))
}
func TestNor(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestNor")
assert.Equal(true, Nor(0, 0))
assert.Equal(false, Nor(0, 1))
assert.Equal(false, Nor(1, 0))
assert.Equal(false, Nor(1, 1))
}
func TestXnor(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestXnor")
assert.Equal(true, Xnor(0, 0))
assert.Equal(false, Xnor(0, 1))
assert.Equal(false, Xnor(1, 0))
assert.Equal(true, Xnor(1, 1))
}
func TestNand(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestNand")
assert.Equal(true, Nand(0, 0))
assert.Equal(true, Nand(0, 1))
assert.Equal(true, Nand(1, 0))
assert.Equal(false, Nand(1, 1))
}
func TestTernaryOperator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TernaryOperator")
trueValue := "1"
falseValue := "0"
assert.Equal(trueValue, TernaryOperator(true, trueValue, falseValue))
}

View File

@@ -7,21 +7,29 @@ package convertor
import (
"bytes"
"encoding/binary"
"encoding/gob"
"encoding/json"
"errors"
"fmt"
"io"
"math"
"reflect"
"regexp"
"strconv"
"strings"
"github.com/duke-git/lancet/v2/structs"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
)
// ToBool convert string to a boolean
// ToBool convert string to boolean.
// Play: https://go.dev/play/p/ARht2WnGdIN
func ToBool(s string) (bool, error) {
return strconv.ParseBool(s)
}
// ToBytes convert interface to bytes
// ToBytes convert value to byte slice.
// Play: https://go.dev/play/p/fAMXYFDvOvr
func ToBytes(value any) ([]byte, error) {
v := reflect.ValueOf(value)
@@ -62,7 +70,8 @@ func ToBytes(value any) ([]byte, error) {
}
}
// ToChar convert string to char slice
// ToChar convert string to char slice.
// Play: https://go.dev/play/p/JJ1SvbFkVdM
func ToChar(s string) []string {
c := make([]string, 0)
if len(s) == 0 {
@@ -74,133 +83,179 @@ func ToChar(s string) []string {
return c
}
// ToChannel convert a slice of elements to a read-only channel.
// Play: https://go.dev/play/p/hOx_oYZbAnL
func ToChannel[T any](array []T) <-chan T {
ch := make(chan T)
go func() {
for _, item := range array {
ch <- item
}
close(ch)
}()
return ch
}
// ToString convert value to string
// for number, string, []byte, will convert to string
// for other type (slice, map, array, struct) will call json.Marshal.
// Play: https://go.dev/play/p/nF1zOOslpQq
func ToString(value any) string {
res := ""
if value == nil {
return res
return ""
}
v := reflect.ValueOf(value)
switch value.(type) {
case float32, float64:
res = strconv.FormatFloat(v.Float(), 'f', -1, 64)
return res
case int, int8, int16, int32, int64:
res = strconv.FormatInt(v.Int(), 10)
return res
case uint, uint8, uint16, uint32, uint64:
res = strconv.FormatUint(v.Uint(), 10)
return res
switch val := value.(type) {
case float32:
return strconv.FormatFloat(float64(val), 'f', -1, 32)
case float64:
return strconv.FormatFloat(val, 'f', -1, 64)
case int:
return strconv.FormatInt(int64(val), 10)
case int8:
return strconv.FormatInt(int64(val), 10)
case int16:
return strconv.FormatInt(int64(val), 10)
case int32:
return strconv.FormatInt(int64(val), 10)
case int64:
return strconv.FormatInt(val, 10)
case uint:
return strconv.FormatUint(uint64(val), 10)
case uint8:
return strconv.FormatUint(uint64(val), 10)
case uint16:
return strconv.FormatUint(uint64(val), 10)
case uint32:
return strconv.FormatUint(uint64(val), 10)
case uint64:
return strconv.FormatUint(val, 10)
case string:
res = v.String()
return res
return val
case []byte:
res = string(v.Bytes())
return res
return string(val)
default:
newValue, _ := json.Marshal(value)
res = string(newValue)
return res
b, err := json.Marshal(val)
if err != nil {
return ""
}
return string(b)
// todo: maybe we should't supprt other type conversion
// v := reflect.ValueOf(value)
// log.Panicf("Unsupported data type: %s ", v.String())
// return ""
}
}
// ToJson convert value to a valid json string
// ToJson convert value to a json string.
// Play: https://go.dev/play/p/2rLIkMmXWvR
func ToJson(value any) (string, error) {
res, err := json.Marshal(value)
result, err := json.Marshal(value)
if err != nil {
return "", err
}
return string(res), nil
return string(result), nil
}
// ToFloat convert value to a float64, if input is not a float return 0.0 and error
// ToFloat convert value to float64, if input is not a float return 0.0 and error.
// Play: https://go.dev/play/p/4YTmPCibqHJ
func ToFloat(value any) (float64, error) {
v := reflect.ValueOf(value)
res := 0.0
result := 0.0
err := fmt.Errorf("ToInt: unvalid interface type %T", value)
switch value.(type) {
case int, int8, int16, int32, int64:
res = float64(v.Int())
return res, nil
result = float64(v.Int())
return result, nil
case uint, uint8, uint16, uint32, uint64:
res = float64(v.Uint())
return res, nil
result = float64(v.Uint())
return result, nil
case float32, float64:
res = v.Float()
return res, nil
result = v.Float()
return result, nil
case string:
res, err = strconv.ParseFloat(v.String(), 64)
result, err = strconv.ParseFloat(v.String(), 64)
if err != nil {
res = 0.0
result = 0.0
}
return res, err
return result, err
default:
return res, err
return result, err
}
}
// ToInt convert value to a int64, if input is not a numeric format return 0 and error
// ToInt convert value to int64 value, if input is not numerical, return 0 and error.
// Play: https://go.dev/play/p/9_h9vIt-QZ_b
func ToInt(value any) (int64, error) {
v := reflect.ValueOf(value)
var res int64
err := fmt.Errorf("ToInt: invalid interface type %T", value)
var result int64
err := fmt.Errorf("ToInt: invalid value type %T", value)
switch value.(type) {
case int, int8, int16, int32, int64:
res = v.Int()
return res, nil
result = v.Int()
return result, nil
case uint, uint8, uint16, uint32, uint64:
res = int64(v.Uint())
return res, nil
result = int64(v.Uint())
return result, nil
case float32, float64:
res = int64(v.Float())
return res, nil
result = int64(v.Float())
return result, nil
case string:
res, err = strconv.ParseInt(v.String(), 0, 64)
result, err = strconv.ParseInt(v.String(), 0, 64)
if err != nil {
res = 0
result = 0
}
return res, err
return result, err
default:
return res, err
return result, err
}
}
// ToPointer returns a pointer to passed value.
// Play: https://go.dev/play/p/ASf_etHNlw1
func ToPointer[T any](value T) *T {
return &value
}
// ToMap convert a slice of structs to a map based on iteratee function.
// Play: https://go.dev/play/p/tVFy7E-t24l
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
result := make(map[K]V, len(array))
for _, item := range array {
k, v := iteratee(item)
result[k] = v
}
return result
}
// StructToMap convert struct to map, only convert exported struct field
// map key is specified same as struct field tag `json` value
// map key is specified same as struct field tag `json` value.
// Play: https://go.dev/play/p/KYGYJqNUBOI
func StructToMap(value any) (map[string]any, error) {
v := reflect.ValueOf(value)
t := reflect.TypeOf(value)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
}
res := make(map[string]any)
fieldNum := t.NumField()
pattern := `^[A-Z]`
regex := regexp.MustCompile(pattern)
for i := 0; i < fieldNum; i++ {
name := t.Field(i).Name
tag := t.Field(i).Tag.Get("json")
if regex.MatchString(name) && tag != "" {
//res[name] = v.Field(i).Interface()
res[tag] = v.Field(i).Interface()
}
}
return res, nil
return structs.ToMap(value)
}
// ColorHexToRGB convert hex color to rgb color
// MapToSlice convert map to slice based on iteratee function.
// Play: https://go.dev/play/p/dmX4Ix5V6Wl
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
result := make([]T, 0, len(aMap))
for k, v := range aMap {
result = append(result, iteratee(k, v))
}
return result
}
// ColorHexToRGB convert hex color to rgb color.
// Play: https://go.dev/play/p/o7_ft-JCJBV
func ColorHexToRGB(colorHex string) (red, green, blue int) {
colorHex = strings.TrimPrefix(colorHex, "#")
color64, err := strconv.ParseInt(colorHex, 16, 32)
@@ -211,7 +266,8 @@ func ColorHexToRGB(colorHex string) (red, green, blue int) {
return color >> 16, (color & 0x00FF00) >> 8, color & 0x0000FF
}
// ColorRGBToHex convert rgb color to hex color
// ColorRGBToHex convert rgb color to hex color.
// Play: https://go.dev/play/p/nzKS2Ro87J1
func ColorRGBToHex(red, green, blue int) string {
r := strconv.FormatInt(int64(red), 16)
g := strconv.FormatInt(int64(green), 16)
@@ -229,3 +285,112 @@ func ColorRGBToHex(red, green, blue int) string {
return "#" + r + g + b
}
// EncodeByte encode data to byte slice.
// Play: https://go.dev/play/p/DVmM1G5JfuP
func EncodeByte(data any) ([]byte, error) {
buffer := bytes.NewBuffer(nil)
encoder := gob.NewEncoder(buffer)
err := encoder.Encode(data)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
// DecodeByte decode byte slice data to target object.
// Play: https://go.dev/play/p/zI6xsmuQRbn
func DecodeByte(data []byte, target any) error {
buffer := bytes.NewBuffer(data)
decoder := gob.NewDecoder(buffer)
return decoder.Decode(target)
}
// DeepClone creates a deep copy of passed item.
// can't clone unexported field of struct
// Play: https://go.dev/play/p/j4DP5dquxnk
func DeepClone[T any](src T) T {
c := cloner{
ptrs: map[reflect.Type]map[uintptr]reflect.Value{},
}
result := c.clone(reflect.ValueOf(src))
if result.Kind() == reflect.Invalid {
var zeroValue T
return zeroValue
}
return result.Interface().(T)
}
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
// Play: https://go.dev/play/p/oZujoB5Sgg5
func CopyProperties[T, U any](dst T, src U) error {
dstType, srcType := reflect.TypeOf(dst), reflect.TypeOf(src)
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
return errors.New("CopyProperties: parameter dst should be struct pointer")
}
if srcType.Kind() == reflect.Ptr {
srcType = srcType.Elem()
}
if srcType.Kind() != reflect.Struct {
return errors.New("CopyProperties: parameter src should be a struct or struct pointer")
}
bytes, err := json.Marshal(src)
if err != nil {
return fmt.Errorf("CopyProperties: unable to marshal src: %s", err)
}
err = json.Unmarshal(bytes, dst)
if err != nil {
return fmt.Errorf("CopyProperties: unable to unmarshal into dst: %s", err)
}
return nil
}
// ToInterface converts reflect value to its interface type.
// Play: https://go.dev/play/p/syqw0-WG7Xd
func ToInterface(v reflect.Value) (value interface{}, ok bool) {
if v.IsValid() && v.CanInterface() {
return v.Interface(), true
}
switch v.Kind() {
case reflect.Bool:
return v.Bool(), true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int(), true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint(), true
case reflect.Float32, reflect.Float64:
return v.Float(), true
case reflect.Complex64, reflect.Complex128:
return v.Complex(), true
case reflect.String:
return v.String(), true
case reflect.Ptr:
return ToInterface(v.Elem())
case reflect.Interface:
return ToInterface(v.Elem())
default:
return nil, false
}
}
// Utf8ToGbk convert utf8 encoding data to GBK encoding data.
// Play: https://go.dev/play/p/9FlIaFLArIL
func Utf8ToGbk(bs []byte) ([]byte, error) {
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewEncoder())
b, err := io.ReadAll(r)
return b, err
}
// GbkToUtf8 convert GBK encoding data to utf8 encoding data.
// Play: https://go.dev/play/p/OphmHCN_9u8
func GbkToUtf8(bs []byte) ([]byte, error) {
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewDecoder())
b, err := io.ReadAll(r)
return b, err
}

View File

@@ -0,0 +1,393 @@
package convertor
import (
"fmt"
"reflect"
"strconv"
"unicode/utf8"
"github.com/duke-git/lancet/v2/validator"
)
func ExampleToBool() {
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
for i := 0; i < len(cases); i++ {
result, _ := ToBool(cases[i])
fmt.Println(result)
}
// Output:
// true
// true
// true
// false
// false
// false
// false
// false
// false
}
func ExampleToBytes() {
result1, _ := ToBytes(1)
result2, _ := ToBytes("abc")
result3, _ := ToBytes(true)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [0 0 0 0 0 0 0 1]
// [97 98 99]
// [116 114 117 101]
}
func ExampleToChar() {
result1 := ToChar("")
result2 := ToChar("abc")
result3 := ToChar("1 2#3")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// []
// [a b c]
// [1 2 # 3]
}
func ExampleToChannel() {
ch := ToChannel([]int{1, 2, 3})
result1 := <-ch
result2 := <-ch
result3 := <-ch
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 3
}
func ExampleToString() {
result1 := ToString("")
result2 := ToString(nil)
result3 := ToString(0)
result4 := ToString(1.23)
result5 := ToString(true)
result6 := ToString(false)
result7 := ToString([]int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
//
//
// 0
// 1.23
// true
// false
// [1,2,3]
}
func ExampleToJson() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result1, err := ToJson(aMap)
if err != nil {
fmt.Printf("%v", err)
}
fmt.Println(result1)
// Output:
// {"a":1,"b":2,"c":3}
}
func ExampleToFloat() {
result1, _ := ToFloat("")
result2, _ := ToFloat("abc")
result3, _ := ToFloat("-1")
result4, _ := ToFloat("-.11")
result5, _ := ToFloat("1.23e3")
result6, _ := ToFloat(true)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// 0
// 0
// -1
// -0.11
// 1230
// 0
}
func ExampleToInt() {
result1, _ := ToInt("123")
result2, _ := ToInt("-123")
result3, _ := ToInt(float64(12.3))
result4, _ := ToInt("abc")
result5, _ := ToInt(true)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 123
// -123
// 12
// 0
// 0
}
func ExampleToPointer() {
result := ToPointer(123)
fmt.Println(*result)
// Output:
// 123
}
func ExampleToMap() {
type Message struct {
name string
code int
}
messages := []Message{
{name: "Hello", code: 100},
{name: "Hi", code: 101},
}
result := ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name
})
fmt.Println(result)
// Output:
// map[100:Hello 101:Hi]
}
func ExampleStructToMap() {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := StructToMap(p)
fmt.Println(pm)
// Output:
// map[name:test]
}
func ExampleMapToSlice() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result := MapToSlice(aMap, func(key string, value int) string {
return key + ":" + strconv.Itoa(value)
})
fmt.Println(result) //[]string{"a:1", "c:3", "b:2"} (random order)
}
func ExampleColorHexToRGB() {
colorHex := "#003366"
r, g, b := ColorHexToRGB(colorHex)
fmt.Println(r, g, b)
// Output:
// 0 51 102
}
func ExampleColorRGBToHex() {
r := 0
g := 51
b := 102
colorHex := ColorRGBToHex(r, g, b)
fmt.Println(colorHex)
// Output:
// #003366
}
func ExampleEncodeByte() {
byteData, _ := EncodeByte("abc")
fmt.Println(byteData)
// Output:
// [6 12 0 3 97 98 99]
}
func ExampleDecodeByte() {
var obj string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
err := DecodeByte(byteData, &obj)
if err != nil {
return
}
fmt.Println(obj)
// Output:
// abc
}
func ExampleDeepClone() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
// unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for _, item := range cases {
cloned := DeepClone(item)
isPointerEqual := &cloned == &item
fmt.Println(cloned, isPointerEqual)
}
// Output:
// true false
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil>} false
}
func ExampleCopyProperties() {
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
CopyProperties(&indicatorVO, indicator)
fmt.Println(indicatorVO.Id)
fmt.Println(indicatorVO.Ip)
fmt.Println(len(indicatorVO.Disk))
// Output:
// 001
// 127.0.0.1
// 3
}
func ExampleToInterface() {
val := reflect.ValueOf("abc")
iVal, ok := ToInterface(val)
fmt.Printf("%T\n", iVal)
fmt.Printf("%v\n", iVal)
fmt.Println(ok)
// Output:
// string
// abc
// true
}
func ExampleUtf8ToGbk() {
utf8Data := []byte("hello")
gbkData, _ := Utf8ToGbk(utf8Data)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(validator.IsGBK(gbkData))
// Output:
// true
// true
}
func ExampleGbkToUtf8() {
gbkData, _ := Utf8ToGbk([]byte("hello"))
utf8Data, _ := GbkToUtf8(gbkData)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(string(utf8Data))
// Output:
// true
// hello
}

View File

@@ -0,0 +1,216 @@
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package convertor implements some functions to convert data.
package convertor
import "reflect"
type cloner struct {
ptrs map[reflect.Type]map[uintptr]reflect.Value
}
// clone return a duplicate of passed item.
func (c *cloner) clone(v reflect.Value) reflect.Value {
switch v.Kind() {
case reflect.Invalid:
return reflect.ValueOf(nil)
// bool
case reflect.Bool:
return reflect.ValueOf(v.Bool())
//int
case reflect.Int:
return reflect.ValueOf(int(v.Int()))
case reflect.Int8:
return reflect.ValueOf(int8(v.Int()))
case reflect.Int16:
return reflect.ValueOf(int16(v.Int()))
case reflect.Int32:
return reflect.ValueOf(int32(v.Int()))
case reflect.Int64:
return reflect.ValueOf(v.Int())
// uint
case reflect.Uint:
return reflect.ValueOf(uint(v.Uint()))
case reflect.Uint8:
return reflect.ValueOf(uint8(v.Uint()))
case reflect.Uint16:
return reflect.ValueOf(uint16(v.Uint()))
case reflect.Uint32:
return reflect.ValueOf(uint32(v.Uint()))
case reflect.Uint64:
return reflect.ValueOf(v.Uint())
// float
case reflect.Float32:
return reflect.ValueOf(float32(v.Float()))
case reflect.Float64:
return reflect.ValueOf(v.Float())
// complex
case reflect.Complex64:
return reflect.ValueOf(complex64(v.Complex()))
case reflect.Complex128:
return reflect.ValueOf(v.Complex())
// string
case reflect.String:
return reflect.ValueOf(v.String())
// array
case reflect.Array, reflect.Slice:
return c.cloneArray(v)
// map
case reflect.Map:
return c.cloneMap(v)
// Ptr
case reflect.Ptr:
return c.clonePtr(v)
// struct
case reflect.Struct:
return c.cloneStruct(v)
// func
case reflect.Func:
return v
// interface
case reflect.Interface:
return c.clone(v.Elem())
}
return reflect.Zero(v.Type())
}
func (c *cloner) cloneArray(v reflect.Value) reflect.Value {
if v.IsNil() {
return reflect.Zero(v.Type())
}
arr := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
for i := 0; i < v.Len(); i++ {
val := c.clone(v.Index(i))
if val.IsValid() {
continue
}
item := arr.Index(i)
if !item.CanSet() {
continue
}
item.Set(val.Convert(item.Type()))
}
return arr
}
func (c *cloner) cloneMap(v reflect.Value) reflect.Value {
if v.IsNil() {
return reflect.Zero(v.Type())
}
clonedMap := reflect.MakeMap(v.Type())
for _, key := range v.MapKeys() {
value := v.MapIndex(key)
clonedKey := c.clone(key)
clonedValue := c.clone(value)
if !isNillable(clonedKey) || !clonedKey.IsNil() {
clonedKey = clonedKey.Convert(key.Type())
}
if (!isNillable(clonedValue) || !clonedValue.IsNil()) && clonedValue.IsValid() {
clonedValue = clonedValue.Convert(value.Type())
}
if !clonedValue.IsValid() {
clonedValue = reflect.Zero(clonedMap.Type().Elem())
}
clonedMap.SetMapIndex(clonedKey, clonedValue)
}
return clonedMap
}
func isNillable(v reflect.Value) bool {
switch v.Kind() {
case reflect.Chan, reflect.Interface, reflect.Ptr, reflect.Func:
return true
}
return false
}
func (c *cloner) clonePtr(v reflect.Value) reflect.Value {
if v.IsNil() {
return reflect.Zero(v.Type())
}
var newVal reflect.Value
if v.Elem().CanAddr() {
ptrs, exists := c.ptrs[v.Type()]
if exists {
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
return newVal
}
}
}
newVal = c.clone(v.Elem())
if v.Elem().CanAddr() {
ptrs, exists := c.ptrs[v.Type()]
if exists {
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
return newVal
}
}
}
clonedPtr := reflect.New(newVal.Type())
clonedPtr.Elem().Set(newVal)
return clonedPtr
}
func (c *cloner) cloneStruct(v reflect.Value) reflect.Value {
clonedStructPtr := reflect.New(v.Type())
clonedStruct := clonedStructPtr.Elem()
if v.CanAddr() {
ptrs := c.ptrs[clonedStructPtr.Type()]
if ptrs == nil {
ptrs = make(map[uintptr]reflect.Value)
c.ptrs[clonedStructPtr.Type()] = ptrs
}
ptrs[v.UnsafeAddr()] = clonedStructPtr
}
for i := 0; i < v.NumField(); i++ {
newStructValue := clonedStruct.Field(i)
if !newStructValue.CanSet() {
continue
}
clonedVal := c.clone(v.Field(i))
if !clonedVal.IsValid() {
continue
}
newStructValue.Set(clonedVal.Convert(newStructValue.Type()))
}
return clonedStruct
}

View File

@@ -2,12 +2,19 @@ package convertor
import (
"fmt"
"reflect"
"strconv"
"testing"
"unicode/utf8"
"github.com/duke-git/lancet/v2/internal"
"github.com/duke-git/lancet/v2/slice"
"github.com/duke-git/lancet/v2/validator"
)
func TestToChar(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToChar")
cases := []string{"", "abc", "1 2#3"}
@@ -21,7 +28,23 @@ func TestToChar(t *testing.T) {
}
}
func TestToChannel(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToChannel")
ch := ToChannel([]int{1, 2, 3})
assert.Equal(1, <-ch)
assert.Equal(2, <-ch)
assert.Equal(3, <-ch)
_, ok := <-ch
assert.Equal(false, ok)
}
func TestToBool(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToBool")
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
@@ -34,6 +57,8 @@ func TestToBool(t *testing.T) {
}
func TestToBytes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToBytes")
cases := []any{
@@ -60,6 +85,8 @@ func TestToBytes(t *testing.T) {
}
func TestToInt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToInt")
cases := []any{"123", "-123", 123,
@@ -76,6 +103,8 @@ func TestToInt(t *testing.T) {
}
func TestToFloat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToFloat")
cases := []any{
@@ -94,6 +123,8 @@ func TestToFloat(t *testing.T) {
}
func TestToString(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToString")
aMap := make(map[string]int)
@@ -118,9 +149,10 @@ func TestToString(t *testing.T) {
"", "",
"0", "1", "-1",
"123", "123", "123", "123", "123", "123", "123",
"12.3", "12.300000190734863",
"12.3", "12.3",
"true", "false",
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello",
}
for i := 0; i < len(cases); i++ {
actual := ToString(cases[i])
@@ -128,6 +160,8 @@ func TestToString(t *testing.T) {
}
}
func TestToJson(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToJson")
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
@@ -142,23 +176,83 @@ func TestToJson(t *testing.T) {
assert.Equal("{\"Name\":\"TestStruct\"}", structJsonStr)
}
func TestToMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToMap")
type Message struct {
name string
code int
}
messages := []Message{
{name: "Hello", code: 100},
{name: "Hi", code: 101},
}
result := ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name
})
expected := map[int]string{100: "Hello", 101: "Hi"}
assert.Equal(expected, result)
}
func TestStructToMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStructToMap")
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := StructToMap(p)
var expected = map[string]any{"name": "test"}
assert.Equal(expected, pm)
t.Run("StructToMap", func(_ *testing.T) {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := StructToMap(p)
var expected = map[string]any{"name": "test"}
assert.Equal(expected, pm)
})
t.Run("StructToMapWithJsonAttr", func(_ *testing.T) {
type People struct {
Name string `json:"name,omitempty"` // json tag with attribute
Phone string `json:"phone"` // json tag without attribute
Sex string `json:"-"` // ignore
age int // no tag
}
p := People{
Phone: "1111",
Sex: "male",
age: 100,
}
pm, _ := StructToMap(p)
var expected = map[string]any{"phone": "1111"}
assert.Equal(expected, pm)
})
}
func TestMapToSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMapToSlice")
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result := MapToSlice(aMap, func(key string, value int) string {
return key + ":" + strconv.Itoa(value)
})
assert.Equal(3, len(result))
assert.Equal(true, slice.Contain(result, "a:1"))
assert.Equal(true, slice.Contain(result, "b:2"))
assert.Equal(true, slice.Contain(result, "c:3"))
}
func TestColorHexToRGB(t *testing.T) {
t.Parallel()
colorHex := "#003366"
r, g, b := ColorHexToRGB(colorHex)
colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b)
@@ -169,6 +263,8 @@ func TestColorHexToRGB(t *testing.T) {
}
func TestColorRGBToHex(t *testing.T) {
t.Parallel()
r := 0
g := 51
b := 102
@@ -178,3 +274,189 @@ func TestColorRGBToHex(t *testing.T) {
assert := internal.NewAssert(t, "TestColorRGBToHex")
assert.Equal(expected, colorHex)
}
func TestToPointer(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToPointer")
result := ToPointer(123)
assert.Equal(*result, 123)
}
func TestEncodeByte(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEncodeByte")
byteData, _ := EncodeByte("abc")
expected := []byte{6, 12, 0, 3, 97, 98, 99}
assert.Equal(expected, byteData)
}
func TestDecodeByte(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDecodeByte")
var obj string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
err := DecodeByte(byteData, &obj)
assert.IsNil(err)
assert.Equal("abc", obj)
}
func TestDeepClone(t *testing.T) {
t.Parallel()
// assert := internal.NewAssert(t, "TestDeepClone")
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
// unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for i, item := range cases {
cloned := DeepClone(item)
if &cloned == &item {
t.Fatalf("[TestDeepClone case #%d failed]: equal pointer", i)
}
if !reflect.DeepEqual(item, cloned) {
t.Fatalf("[TestDeepClone case #%d failed] unequal objects", i)
}
}
}
func TestCopyProperties(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCopyProperties")
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
err := CopyProperties(&indicatorVO, indicator)
assert.IsNil(err)
assert.Equal("001", indicatorVO.Id)
assert.Equal("127.0.0.1", indicatorVO.Ip)
assert.Equal(3, len(indicatorVO.Disk))
}
func TestToInterface(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToInterface")
cases := []reflect.Value{
reflect.ValueOf("abc"),
reflect.ValueOf(int(0)), reflect.ValueOf(int8(1)), reflect.ValueOf(int16(-1)), reflect.ValueOf(int32(123)), reflect.ValueOf(int64(123)),
reflect.ValueOf(uint(123)), reflect.ValueOf(uint8(123)), reflect.ValueOf(uint16(123)), reflect.ValueOf(uint32(123)), reflect.ValueOf(uint64(123)),
reflect.ValueOf(float64(12.3)), reflect.ValueOf(float32(12.3)),
reflect.ValueOf(true), reflect.ValueOf(false),
}
expected := []interface{}{
"abc",
0, int8(1), int16(-1), int32(123), int64(123),
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float64(12.3), float32(12.3),
true, false,
}
for i := 0; i < len(cases); i++ {
actual, _ := ToInterface(cases[i])
assert.Equal(expected[i], actual)
}
nilVal, ok := ToInterface(reflect.ValueOf(nil))
assert.EqualValues(nil, nilVal)
assert.Equal(false, ok)
}
func TestUtf8ToGbk(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUtf8ToGbk")
utf8Data := []byte("hello")
gbkData, err := Utf8ToGbk(utf8Data)
assert.Equal(true, utf8.Valid(utf8Data))
assert.Equal(true, validator.IsGBK(gbkData))
assert.IsNil(err)
}
func TestGbkToUtf8(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGbkToUtf8")
gbkData, err := Utf8ToGbk([]byte("hello"))
utf8Data, err := GbkToUtf8(gbkData)
assert.IsNil(err)
assert.Equal(true, utf8.Valid(utf8Data))
assert.Equal("hello", string(utf8Data))
}

View File

@@ -1,168 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package cryptor implements some util functions to encrypt and decrypt.
// Note:
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
package cryptor
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
)
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32
func AesEcbEncrypt(data, key []byte) []byte {
cipher, _ := aes.NewCipher(generateAesKey(key))
length := (len(data) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, data)
pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32
func AesEcbDecrypt(encrypted, key []byte) []byte {
cipher, _ := aes.NewCipher(generateAesKey(key))
decrypted := make([]byte, len(encrypted))
//
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim]
}
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32
func AesCbcEncrypt(data, key []byte) []byte {
// len(key) should be 16, 24 or 32
block, _ := aes.NewCipher(key)
blockSize := block.BlockSize()
data = pkcs7Padding(data, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
encrypted := make([]byte, len(data))
blockMode.CryptBlocks(encrypted, data)
return encrypted
}
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32
func AesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := aes.NewCipher(key)
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
decrypted := make([]byte, len(encrypted))
blockMode.CryptBlocks(decrypted, encrypted)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}
// AesCtrCrypt encrypt data with key use AES CTR algorithm
// len(key) should be 16, 24 or 32
func AesCtrCrypt(data, key []byte) []byte {
block, _ := aes.NewCipher(key)
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
dst := make([]byte, len(data))
stream.XORKeyStream(dst, data)
return dst
}
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
// len(key) should be 16, 24 or 32
func AesCfbEncrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
func AesCfbDecrypt(encrypted, key []byte) []byte {
block, _ := aes.NewCipher(key)
if len(encrypted) < aes.BlockSize {
panic("encrypted data is too short")
}
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
// len(key) should be 16, 24 or 32
func AesOfbEncrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
data = pkcs7Padding(data, aes.BlockSize)
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
// len(key) should be 16, 24 or 32
func AesOfbDecrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
iv := data[:aes.BlockSize]
data = data[aes.BlockSize:]
if len(data)%aes.BlockSize != 0 {
return nil
}
decrypted := make([]byte, len(data))
mode := cipher.NewOFB(block, iv)
mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}

View File

@@ -1,62 +0,0 @@
package cryptor
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestAesEcbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
assert.Equal(data, string(aesEcbDecrypt))
}
func TestAesCbcEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
assert.Equal(data, string(aesCbcDecrypt))
}
func TestAesCtrCrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCtrCrypt")
assert.Equal(data, string(aesCtrDeCrypt))
}
func TestAesCfbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
assert.Equal(data, string(aesCfbDecrypt))
}
func TestAesOfbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefghijklmnop"
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
assert.Equal(data, string(aesOfbDecrypt))
}

View File

@@ -19,25 +19,52 @@ import (
"os"
)
// Base64StdEncode encode string with base64 encoding
// Base64StdEncode encode string with base64 encoding.
// Play: https://go.dev/play/p/VOaUyQUreoK
func Base64StdEncode(s string) string {
return base64.StdEncoding.EncodeToString([]byte(s))
}
// Base64StdDecode decode a base64 encoded string
// Base64StdDecode decode a base64 encoded string.
// Play: https://go.dev/play/p/RWQylnJVgIe
func Base64StdDecode(s string) string {
b, _ := base64.StdEncoding.DecodeString(s)
return string(b)
}
// Md5String return the md5 value of string
// Md5String return the md5 value of string.
// Play: https://go.dev/play/p/1bLcVetbTOI
func Md5String(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
// Md5File return the md5 value of file
// Md5StringWithBase64 return the md5 value of string with base64.
// Play: https://go.dev/play/p/Lx4gH7Vdr5_y
func Md5StringWithBase64(s string) string {
h := md5.New()
h.Write([]byte(s))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
// Md5Byte return the md5 string of byte slice.
// Play: https://go.dev/play/p/suraalH8lyC
func Md5Byte(data []byte) string {
h := md5.New()
h.Write(data)
return hex.EncodeToString(h.Sum(nil))
}
// Md5ByteWithBase64 return the md5 string of byte slice with base64.
// Play: https://go.dev/play/p/Tcb-Z7LN2ax
func Md5ByteWithBase64(data []byte) string {
h := md5.New()
h.Write(data)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
// Md5File return the md5 value of file.
func Md5File(filename string) (string, error) {
if fileInfo, err := os.Stat(filename); err != nil {
return "", err
@@ -69,51 +96,114 @@ func Md5File(filename string) (string, error) {
return checksum, nil
}
// HmacMd5 return the hmac hash of string use md5
func HmacMd5(data, key string) string {
// HmacMd5 return the hmac hash of string use md5.
// Play: https://go.dev/play/p/uef0q1fz53I
func HmacMd5(str, key string) string {
h := hmac.New(md5.New, []byte(key))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacMd5WithBase64 return the hmac hash of string use md5 with base64.
// https://go.dev/play/p/UY0ng2AefFC
func HmacMd5WithBase64(data, key string) string {
h := hmac.New(md5.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// HmacSha1 return the hmac hash of string use sha1
func HmacSha1(data, key string) string {
// HmacSha1 return the hmac hash of string use sha1.
// Play: https://go.dev/play/p/1UI4oQ4WXKM
func HmacSha1(str, key string) string {
h := hmac.New(sha1.New, []byte(key))
h.Write([]byte(data))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha256 return the hmac hash of string use sha256
func HmacSha256(data, key string) string {
// HmacSha1WithBase64 return the hmac hash of string use sha1 with base64.
// Play: https://go.dev/play/p/47JmmGrnF7B
func HmacSha1WithBase64(str, key string) string {
h := hmac.New(sha1.New, []byte(key))
h.Write([]byte(str))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// HmacSha256 return the hmac hash of string use sha256.
// Play: https://go.dev/play/p/HhpwXxFhhC0
func HmacSha256(str, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(data))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha512 return the hmac hash of string use sha512
func HmacSha512(data, key string) string {
// HmacSha256WithBase64 return the hmac hash of string use sha256 with base64.
// Play: https://go.dev/play/p/EKbkUvPTLwO
func HmacSha256WithBase64(str, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(str))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// HmacSha512 return the hmac hash of string use sha512.
// Play: https://go.dev/play/p/59Od6m4A0Ud
func HmacSha512(str, key string) string {
h := hmac.New(sha512.New, []byte(key))
h.Write([]byte(data))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum([]byte("")))
}
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string
func Sha1(data string) string {
// HmacSha512WithBase64 return the hmac hash of string use sha512 with base64.
// Play: https://go.dev/play/p/c6dSe3E2ydU
func HmacSha512WithBase64(str, key string) string {
h := hmac.New(sha512.New, []byte(key))
h.Write([]byte(str))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string.
// Play: https://go.dev/play/p/_m_uoD1deMT
func Sha1(str string) string {
sha1 := sha1.New()
sha1.Write([]byte(data))
sha1.Write([]byte(str))
return hex.EncodeToString(sha1.Sum([]byte("")))
}
// Sha256 return the sha256 value (SHA256 hash algorithm) of string
func Sha256(data string) string {
// Sha1WithBase64 return the sha1 value (SHA-1 hash algorithm) of base64 string.
// Play: https://go.dev/play/p/fSyx-Gl2l2-
func Sha1WithBase64(str string) string {
sha1 := sha1.New()
sha1.Write([]byte(str))
return base64.StdEncoding.EncodeToString(sha1.Sum([]byte("")))
}
// Sha256 return the sha256 value (SHA256 hash algorithm) of string.
// Play: https://go.dev/play/p/tU9tfBMIAr1
func Sha256(str string) string {
sha256 := sha256.New()
sha256.Write([]byte(data))
sha256.Write([]byte(str))
return hex.EncodeToString(sha256.Sum([]byte("")))
}
// Sha512 return the sha512 value (SHA512 hash algorithm) of string
func Sha512(data string) string {
// Sha256WithBase64 return the sha256 value (SHA256 hash algorithm) of base64 string.
// Play: https://go.dev/play/p/85IXJHIal1k
func Sha256WithBase64(str string) string {
sha256 := sha256.New()
sha256.Write([]byte(str))
return base64.StdEncoding.EncodeToString(sha256.Sum([]byte("")))
}
// Sha512 return the sha512 value (SHA512 hash algorithm) of string.
// Play: https://go.dev/play/p/3WsvLYZxsHa
func Sha512(str string) string {
sha512 := sha512.New()
sha512.Write([]byte(data))
sha512.Write([]byte(str))
return hex.EncodeToString(sha512.Sum([]byte("")))
}
// Sha512WithBase64 return the sha512 value (SHA512 hash algorithm) of base64 string.
// Play: https://go.dev/play/p/q_fY2rA-k5I
func Sha512WithBase64(str string) string {
sha512 := sha512.New()
sha512.Write([]byte(str))
return base64.StdEncoding.EncodeToString(sha512.Sum([]byte("")))
}

View File

@@ -7,21 +7,51 @@ import (
)
func TestBase64StdEncode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBase64StdEncode")
assert.Equal("aGVsbG8gd29ybGQ=", Base64StdEncode("hello world"))
}
func TestBase64StdDecode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBase64StdDecode")
assert.Equal("hello world", Base64StdDecode("aGVsbG8gd29ybGQ="))
}
func TestMd5String(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5String")
assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
}
func TestMd5StringWithBase64(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5StringWithBase64")
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5StringWithBase64("hello"))
}
func TestMd5Byte(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5Byte")
data := []byte{'a'}
assert.Equal("0cc175b9c0f1b6a831c399e269772661", Md5Byte(data))
}
func TestMd5ByteWithBase64(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5ByteWithBase64")
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5ByteWithBase64([]byte("hello")))
}
func TestMd5File(t *testing.T) {
t.Parallel()
fileMd5, err := Md5File("./basic.go")
assert := internal.NewAssert(t, "TestMd5File")
assert.IsNotNil(fileMd5)
@@ -29,11 +59,22 @@ func TestMd5File(t *testing.T) {
}
func TestHmacMd5(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHmacMd5")
assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345"))
}
func TestHmacMd5WithBase64(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHmacMd5WithBase64")
assert.Equal("6DQwbquJLYclJdSRinpjmg==", HmacMd5WithBase64("hello", "12345"))
}
func TestHmacSha1(t *testing.T) {
t.Parallel()
s := "hello world"
key := "12345"
hmacSha1 := HmacSha1(s, key)
@@ -43,17 +84,45 @@ func TestHmacSha1(t *testing.T) {
assert.Equal(expected, hmacSha1)
}
func TestHmacSha256(t *testing.T) {
s := "hello world"
func TestHmacSha1WithBase64(t *testing.T) {
t.Parallel()
s := "hello"
key := "12345"
hmacSha256 := HmacSha256(s, key)
hmacSha1 := HmacSha1WithBase64(s, key)
expected := "XGqdsMzLkuNu0DI/0Jt/k23prOA="
assert := internal.NewAssert(t, "TestHmacSha1")
assert.Equal(expected, hmacSha1)
}
func TestHmacSha256(t *testing.T) {
t.Parallel()
str := "hello world"
key := "12345"
hmacSha256 := HmacSha256(str, key)
expected := "9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8"
assert := internal.NewAssert(t, "TestHmacSha256")
assert.Equal(expected, hmacSha256)
}
func TestHmacSha256WithBase64(t *testing.T) {
t.Parallel()
str := "hello"
key := "12345"
hms := HmacSha256WithBase64(str, key)
expected := "MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU="
assert := internal.NewAssert(t, "TestHmacSha256WithBase64")
assert.Equal(expected, hms)
}
func TestHmacSha512(t *testing.T) {
t.Parallel()
s := "hello world"
key := "12345"
hmacSha512 := HmacSha512(s, key)
@@ -63,7 +132,21 @@ func TestHmacSha512(t *testing.T) {
assert.Equal(expected, hmacSha512)
}
func TestHmacSha512WithBase64(t *testing.T) {
t.Parallel()
str := "hello"
key := "12345"
hms := HmacSha512WithBase64(str, key)
expected := "3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A=="
assert := internal.NewAssert(t, "TestHmacSha512WithBase64")
assert.Equal(expected, hms)
}
func TestSha1(t *testing.T) {
t.Parallel()
s := "hello world"
sha1 := Sha1(s)
expected := "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"
@@ -72,7 +155,19 @@ func TestSha1(t *testing.T) {
assert.Equal(expected, sha1)
}
func TestSha1WithBase64(t *testing.T) {
t.Parallel()
str := Sha1WithBase64("hello")
expected := "qvTGHdzF6KLavt4PO0gs2a6pQ00="
assert := internal.NewAssert(t, "TestSha1WithBase64")
assert.Equal(expected, str)
}
func TestSha256(t *testing.T) {
t.Parallel()
s := "hello world"
sha256 := Sha256(s)
expected := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
@@ -81,7 +176,19 @@ func TestSha256(t *testing.T) {
assert.Equal(expected, sha256)
}
func TestSha256WithBase64(t *testing.T) {
t.Parallel()
str := Sha256WithBase64("hello")
expected := "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="
assert := internal.NewAssert(t, "TestSha256WithBase64")
assert.Equal(expected, str)
}
func TestSha512(t *testing.T) {
t.Parallel()
s := "hello world"
sha512 := Sha512(s)
expected := "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"
@@ -89,3 +196,13 @@ func TestSha512(t *testing.T) {
assert := internal.NewAssert(t, "TestSha512")
assert.Equal(expected, sha512)
}
func TestSha512WithBase64(t *testing.T) {
t.Parallel()
str := Sha512WithBase64("hello")
expected := "m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw=="
assert := internal.NewAssert(t, "TestSha512WithBase64")
assert.Equal(expected, str)
}

507
cryptor/crypto.go Normal file
View File

@@ -0,0 +1,507 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package cryptor implements some util functions to encrypt and decrypt.
// Note:
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
package cryptor
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/des"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"io"
"os"
)
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/jT5irszHx-j
func AesEcbEncrypt(data, key []byte) []byte {
size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
length := (len(data) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, data)
pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
cipher, _ := aes.NewCipher(generateAesKey(key, size))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/jT5irszHx-j
func AesEcbDecrypt(encrypted, key []byte) []byte {
size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
cipher, _ := aes.NewCipher(generateAesKey(key, size))
decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim]
}
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/IOq_g8_lKZD
func AesCbcEncrypt(data, key []byte) []byte {
block, _ := aes.NewCipher(key)
data = pkcs7Padding(data, block.BlockSize())
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/IOq_g8_lKZD
func AesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := aes.NewCipher(key)
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypted, encrypted)
decrypted := pkcs7UnPadding(encrypted)
return decrypted
}
// AesCtrCrypt encrypt data with key use AES CTR algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/SpaZO0-5Nsp
func AesCtrCrypt(data, key []byte) []byte {
block, _ := aes.NewCipher(key)
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
dst := make([]byte, len(data))
stream.XORKeyStream(dst, data)
return dst
}
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/tfkF10B13kH
func AesCfbEncrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/tfkF10B13kH
func AesCfbDecrypt(encrypted, key []byte) []byte {
if len(encrypted) < aes.BlockSize {
panic("encrypted data is too short")
}
block, _ := aes.NewCipher(key)
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/VtHxtkUj-3F
func AesOfbEncrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
data = pkcs7Padding(data, aes.BlockSize)
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
return encrypted
}
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/VtHxtkUj-3F
func AesOfbDecrypt(data, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
iv := data[:aes.BlockSize]
data = data[aes.BlockSize:]
if len(data)%aes.BlockSize != 0 {
return nil
}
decrypted := make([]byte, len(data))
mode := cipher.NewOFB(block, iv)
mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/8qivmPeZy4P
func DesEcbEncrypt(data, key []byte) []byte {
length := (len(data) + des.BlockSize) / des.BlockSize
plain := make([]byte, length*des.BlockSize)
copy(plain, data)
pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
cipher, _ := des.NewCipher(generateDesKey(key))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/8qivmPeZy4P
func DesEcbDecrypt(encrypted, key []byte) []byte {
cipher, _ := des.NewCipher(generateDesKey(key))
decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim]
}
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/4cC4QvWfe3_1
func DesCbcEncrypt(data, key []byte) []byte {
block, _ := des.NewCipher(key)
data = pkcs7Padding(data, block.BlockSize())
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(encrypted[des.BlockSize:], data)
return encrypted
}
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/4cC4QvWfe3_1
func DesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := des.NewCipher(key)
iv := encrypted[:des.BlockSize]
encrypted = encrypted[des.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypted, encrypted)
decrypted := pkcs7UnPadding(encrypted)
return decrypted
}
// DesCtrCrypt encrypt data with key use DES CTR algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/9-T6OjKpcdw
func DesCtrCrypt(data, key []byte) []byte {
block, _ := des.NewCipher(key)
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
dst := make([]byte, len(data))
stream.XORKeyStream(dst, data)
return dst
}
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/y-eNxcFBlxL
func DesCfbEncrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
// len(encrypted) should be great than 16, len(key) should be 8.
// Play: https://go.dev/play/p/y-eNxcFBlxL
func DesCfbDecrypt(encrypted, key []byte) []byte {
block, _ := des.NewCipher(key)
if len(encrypted) < des.BlockSize {
panic("encrypted data is too short")
}
iv := encrypted[:des.BlockSize]
encrypted = encrypted[des.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
// len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/74KmNadjN1J
func DesOfbEncrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
data = pkcs7Padding(data, des.BlockSize)
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
// len(key) should be 8.
// Play: https://go.dev/play/p/74KmNadjN1J
func DesOfbDecrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
iv := data[:des.BlockSize]
data = data[des.BlockSize:]
if len(data)%des.BlockSize != 0 {
return nil
}
decrypted := make([]byte, len(data))
mode := cipher.NewOFB(block, iv)
mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}
// GenerateRsaKey create rsa private and public pemo file.
// Play: https://go.dev/play/p/zutRHrDqs0X
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
// private key
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
if err != nil {
return err
}
derText := x509.MarshalPKCS1PrivateKey(privateKey)
block := pem.Block{
Type: "rsa private key",
Bytes: derText,
}
file, err := os.Create(priKeyFile)
if err != nil {
panic(err)
}
err = pem.Encode(file, &block)
if err != nil {
return err
}
file.Close()
// public key
publicKey := privateKey.PublicKey
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
if err != nil {
return err
}
block = pem.Block{
Type: "rsa public key",
Bytes: derpText,
}
file, err = os.Create(pubKeyFile)
if err != nil {
return err
}
err = pem.Encode(file, &block)
if err != nil {
return err
}
file.Close()
return nil
}
// RsaEncrypt encrypt data with ras algorithm.
// Play: https://go.dev/play/p/rDqTT01SPkZ
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
file, err := os.Open(pubKeyFileName)
if err != nil {
panic(err)
}
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
defer file.Close()
buf := make([]byte, fileInfo.Size())
_, err = file.Read(buf)
if err != nil {
panic(err)
}
block, _ := pem.Decode(buf)
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic(err)
}
pubKey := pubInterface.(*rsa.PublicKey)
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
if err != nil {
panic(err)
}
return cipherText
}
// RsaDecrypt decrypt data with ras algorithm.
// Play: https://go.dev/play/p/rDqTT01SPkZ
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
file, err := os.Open(privateKeyFileName)
if err != nil {
panic(err)
}
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
buf := make([]byte, fileInfo.Size())
defer file.Close()
_, err = file.Read(buf)
if err != nil {
panic(err)
}
block, _ := pem.Decode(buf)
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
panic(err)
}
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
if err != nil {
panic(err)
}
return plainText
}

View File

@@ -0,0 +1,486 @@
package cryptor
import "fmt"
func ExampleAesEcbEncrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesEcbEncrypt([]byte(data), []byte(key))
decrypted := AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesEcbDecrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesEcbEncrypt([]byte(data), []byte(key))
decrypted := AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCbcEncrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCbcEncrypt([]byte(data), []byte(key))
decrypted := AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCbcDecrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCbcEncrypt([]byte(data), []byte(key))
decrypted := AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCtrCrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCtrCrypt([]byte(data), []byte(key))
decrypted := AesCtrCrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCfbEncrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCfbEncrypt([]byte(data), []byte(key))
decrypted := AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesCfbDecrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesCfbEncrypt([]byte(data), []byte(key))
decrypted := AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesOfbEncrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesOfbEncrypt([]byte(data), []byte(key))
decrypted := AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleAesOfbDecrypt() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := AesOfbEncrypt([]byte(data), []byte(key))
decrypted := AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesEcbEncrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesEcbEncrypt([]byte(data), []byte(key))
decrypted := DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesEcbDecrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesEcbEncrypt([]byte(data), []byte(key))
decrypted := DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCbcEncrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCbcEncrypt([]byte(data), []byte(key))
decrypted := DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCbcDecrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCbcEncrypt([]byte(data), []byte(key))
decrypted := DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCtrCrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCtrCrypt([]byte(data), []byte(key))
decrypted := DesCtrCrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCfbEncrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCfbEncrypt([]byte(data), []byte(key))
decrypted := DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesCfbDecrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesCfbEncrypt([]byte(data), []byte(key))
decrypted := DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesOfbEncrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesOfbEncrypt([]byte(data), []byte(key))
decrypted := DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleDesOfbDecrypt() {
data := "hello"
key := "abcdefgh"
encrypted := DesOfbEncrypt([]byte(data), []byte(key))
decrypted := DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleGenerateRsaKey() {
// Create ras private and public pem file
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
return
}
fmt.Println("foo")
// Output:
// foo
}
func ExampleRsaEncrypt() {
// Create ras private and public pem file
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
return
}
data := []byte("hello")
encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleRsaDecrypt() {
// Create ras private and public pem file
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
return
}
data := []byte("hello")
encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted))
// Output:
// hello
}
func ExampleBase64StdEncode() {
base64Str := Base64StdEncode("hello")
fmt.Println(base64Str)
// Output:
// aGVsbG8=
}
func ExampleBase64StdDecode() {
str := Base64StdDecode("aGVsbG8=")
fmt.Println(str)
// Output:
// hello
}
func ExampleHmacMd5() {
str := "hello"
key := "12345"
hms := HmacMd5(str, key)
fmt.Println(hms)
// Output:
// e834306eab892d872525d4918a7a639a
}
func ExampleHmacMd5WithBase64() {
str := "hello"
key := "12345"
hms := HmacMd5WithBase64(str, key)
fmt.Println(hms)
// Output:
// 6DQwbquJLYclJdSRinpjmg==
}
func ExampleHmacSha1() {
str := "hello"
key := "12345"
hms := HmacSha1(str, key)
fmt.Println(hms)
// Output:
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
}
func ExampleHmacSha1WithBase64() {
str := "hello"
key := "12345"
hms := HmacSha1WithBase64(str, key)
fmt.Println(hms)
// Output:
// XGqdsMzLkuNu0DI/0Jt/k23prOA=
}
func ExampleHmacSha256() {
str := "hello"
key := "12345"
hms := HmacSha256(str, key)
fmt.Println(hms)
// Output:
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
}
func ExampleHmacSha256WithBase64() {
str := "hello"
key := "12345"
hms := HmacSha256WithBase64(str, key)
fmt.Println(hms)
// Output:
// MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU=
}
func ExampleHmacSha512() {
str := "hello"
key := "12345"
hms := HmacSha512(str, key)
fmt.Println(hms)
// Output:
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
}
func ExampleHmacSha512WithBase64() {
str := "hello"
key := "12345"
hms := HmacSha512WithBase64(str, key)
fmt.Println(hms)
// Output:
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
}
func ExampleMd5String() {
md5Str := Md5String("hello")
fmt.Println(md5Str)
// Output:
// 5d41402abc4b2a76b9719d911017c592
}
func ExampleMd5StringWithBase64() {
md5Str := Md5StringWithBase64("hello")
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
func ExampleMd5Byte() {
md5Str := Md5Byte([]byte{'a'})
fmt.Println(md5Str)
// Output:
// 0cc175b9c0f1b6a831c399e269772661
}
func ExampleMd5ByteWithBase64() {
md5Str := Md5ByteWithBase64([]byte("hello"))
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
func ExampleSha1() {
result := Sha1("hello")
fmt.Println(result)
// Output:
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
}
func ExampleSha1WithBase64() {
result := Sha1WithBase64("hello")
fmt.Println(result)
// Output:
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
}
func ExampleSha256() {
result := Sha256("hello")
fmt.Println(result)
// Output:
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
}
func ExampleSha256WithBase64() {
result := Sha256WithBase64("hello")
fmt.Println(result)
// Output:
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
}
func ExampleSha512() {
result := Sha512("hello")
fmt.Println(result)
// Output:
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
}
func ExampleSha512WithBase64() {
result := Sha512WithBase64("hello")
fmt.Println(result)
// Output:
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
}

View File

@@ -2,11 +2,11 @@ package cryptor
import "bytes"
func generateAesKey(key []byte) []byte {
genKey := make([]byte, 16)
func generateAesKey(key []byte, size int) []byte {
genKey := make([]byte, size)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
for i := size; i < len(key); {
for j := 0; j < size && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}

152
cryptor/crypto_test.go Normal file
View File

@@ -0,0 +1,152 @@
package cryptor
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestAesEcbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
assert.Equal(data, string(aesEcbDecrypt))
}
func TestAesCbcEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
assert.Equal(data, string(aesCbcDecrypt))
}
func TestAesCtrCrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCtrCrypt")
assert.Equal(data, string(aesCtrDeCrypt))
}
func TestAesCfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
assert.Equal(data, string(aesCfbDecrypt))
}
func TestAesOfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
assert.Equal(data, string(aesOfbDecrypt))
}
func TestDesEcbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
assert.Equal(data, string(desEcbDecrypt))
}
func TestDesCbcEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
assert.Equal(data, string(desCbcDecrypt))
}
func TestDesCtrCrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCtrCrypt")
assert.Equal(data, string(desCtrDeCrypt))
}
func TestDesCfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
assert.Equal(data, string(desCfbDecrypt))
}
func TestDesOfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
assert.Equal(data, string(desOfbDecrypt))
}
func TestRsaEncrypt(t *testing.T) {
t.Parallel()
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
t.FailNow()
}
data := []byte("hello world")
encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
assert := internal.NewAssert(t, "TestRsaEncrypt")
assert.Equal(string(data), string(decrypted))
}

View File

@@ -1,173 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package cryptor implements some util functions to encrypt and decrypt.
package cryptor
import (
"bytes"
"crypto/cipher"
"crypto/des"
"crypto/rand"
"io"
)
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
// len(key) should be 8
func DesEcbEncrypt(data, key []byte) []byte {
cipher, _ := des.NewCipher(generateDesKey(key))
length := (len(data) + des.BlockSize) / des.BlockSize
plain := make([]byte, length*des.BlockSize)
copy(plain, data)
pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
// len(key) should be 8
func DesEcbDecrypt(encrypted, key []byte) []byte {
cipher, _ := des.NewCipher(generateDesKey(key))
decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim]
}
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
// len(key) should be 8
func DesCbcEncrypt(data, key []byte) []byte {
block, _ := des.NewCipher(key)
blockSize := block.BlockSize()
data = pkcs7Padding(data, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
encrypted := make([]byte, len(data))
blockMode.CryptBlocks(encrypted, data)
return encrypted
}
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
// len(key) should be 8
func DesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := des.NewCipher(key)
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
decrypted := make([]byte, len(encrypted))
blockMode.CryptBlocks(decrypted, encrypted)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}
// DesCtrCrypt encrypt data with key use DES CTR algorithm
// len(key) should be 8
func DesCtrCrypt(data, key []byte) []byte {
block, _ := des.NewCipher(key)
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
dst := make([]byte, len(data))
stream.XORKeyStream(dst, data)
return dst
}
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
// len(key) should be 8
func DesCfbEncrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
// len(encrypted) should be great than 16, len(key) should be 8
func DesCfbDecrypt(encrypted, key []byte) []byte {
block, _ := des.NewCipher(key)
if len(encrypted) < des.BlockSize {
panic("encrypted data is too short")
}
iv := encrypted[:des.BlockSize]
encrypted = encrypted[des.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
// len(key) should be 16, 24 or 32
func DesOfbEncrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
data = pkcs7Padding(data, des.BlockSize)
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
// len(key) should be 8
func DesOfbDecrypt(data, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
iv := data[:des.BlockSize]
data = data[des.BlockSize:]
if len(data)%des.BlockSize != 0 {
return nil
}
decrypted := make([]byte, len(data))
mode := cipher.NewOFB(block, iv)
mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}

View File

@@ -1,62 +0,0 @@
package cryptor
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestDesEcbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
assert.Equal(data, string(desEcbDecrypt))
}
func TestDesCbcEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
assert.Equal(data, string(desCbcDecrypt))
}
func TestDesCtrCrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCtrCrypt")
assert.Equal(data, string(desCtrDeCrypt))
}
func TestDesCfbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
assert.Equal(data, string(desCfbDecrypt))
}
func TestDesOfbEncrypt(t *testing.T) {
data := "hello world"
key := "abcdefgh"
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
assert.Equal(data, string(desOfbDecrypt))
}

View File

@@ -1,118 +0,0 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package cryptor implements some util functions to encrypt and decrypt.
package cryptor
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"os"
)
// GenerateRsaKey make a rsa private key, and return key file name
// Generated key file is `rsa_private.pem` and `rsa_public.pem` in current path
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
// private key
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
if err != nil {
return err
}
derText := x509.MarshalPKCS1PrivateKey(privateKey)
block := pem.Block{
Type: "rsa private key",
Bytes: derText,
}
//file,err := os.Create("rsa_private.pem")
file, err := os.Create(priKeyFile)
if err != nil {
panic(err)
}
pem.Encode(file, &block)
file.Close()
// public key
publicKey := privateKey.PublicKey
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
if err != nil {
return err
}
block = pem.Block{
Type: "rsa public key",
Bytes: derpText,
}
//file,err = os.Create("rsa_public.pem")
file, err = os.Create(pubKeyFile)
if err != nil {
return err
}
pem.Encode(file, &block)
file.Close()
return nil
}
// RsaEncrypt encrypt data with ras algorithm
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
file, err := os.Open(pubKeyFileName)
if err != nil {
panic(err)
}
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
defer file.Close()
buf := make([]byte, fileInfo.Size())
file.Read(buf)
block, _ := pem.Decode(buf)
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic(err)
}
pubKey := pubInterface.(*rsa.PublicKey)
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
if err != nil {
panic(err)
}
return cipherText
}
// RsaDecrypt decrypt data with ras algorithm
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
file, err := os.Open(privateKeyFileName)
if err != nil {
panic(err)
}
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
buf := make([]byte, fileInfo.Size())
defer file.Close()
file.Read(buf)
block, _ := pem.Decode(buf)
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
panic(err)
}
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
if err != nil {
panic(err)
}
return plainText
}

View File

@@ -1,20 +0,0 @@
package cryptor
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestRsaEncrypt(t *testing.T) {
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
t.FailNow()
}
data := []byte("hello world")
encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
assert := internal.NewAssert(t, "TestRsaEncrypt")
assert.Equal(string(data), string(decrypted))
}

View File

@@ -0,0 +1,193 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. hashmap structure.
package datastructure
import (
"fmt"
"hash/fnv"
"reflect"
)
var defaultMapCapacity uint64 = 1 << 10
type mapNode struct {
key any
value any
next *mapNode
}
// HashMap implements a hash map
type HashMap struct {
capacity uint64
size uint64
table []*mapNode
}
// NewHashMap return a HashMap instance
func NewHashMap() *HashMap {
return &HashMap{
capacity: defaultMapCapacity,
table: make([]*mapNode, defaultMapCapacity),
}
}
// NewHashMapWithCapacity return a HashMap instance with given size and capacity
func NewHashMapWithCapacity(size, capacity uint64) *HashMap {
return &HashMap{
size: size,
capacity: capacity,
table: make([]*mapNode, capacity),
}
}
// Get return the value of given key in hashmap
func (hm *HashMap) Get(key any) any {
hashValue := hm.hash(key)
node := hm.table[hashValue]
for node != nil {
if reflect.DeepEqual(node.key, key) {
return node.value
}
node = node.next
}
return nil
}
// GetOrDefault return the value of given key in hashmap, if not found return default value
func (hm *HashMap) GetOrDefault(key any, defaultValue any) any {
value := hm.Get(key)
if value == nil {
return defaultValue
}
return value
}
// Put new key value in hashmap
func (hm *HashMap) Put(key any, value any) {
hm.putValue(hm.hash(key), key, value)
}
func (hm *HashMap) putValue(hash uint64, key, value any) {
if hm.capacity == 0 {
hm.capacity = defaultMapCapacity
hm.table = make([]*mapNode, defaultMapCapacity)
}
node := hm.table[hash]
if node == nil {
hm.table[hash] = newMapNode(key, value)
} else if node.key == key {
hm.table[hash] = newMapNodeWithNext(key, value, node)
} else {
hm.resize()
hm.putValue(hash, value, value)
}
hm.size++
}
// Delete item by given key in hashmap
func (hm *HashMap) Delete(key any) {
hash := hm.hash(key)
node := hm.table[hash]
if node == nil {
return
}
hm.table = append(hm.table[:hash], hm.table[hash+1:]...)
hm.size--
}
// Contains checks if given key is in hashmap or not
func (hm *HashMap) Contains(key any) bool {
node := hm.table[hm.hash(key)]
for node != nil {
if reflect.DeepEqual(node.key, key) {
return true
}
node = node.next
}
return false
}
// Iterate executes iteratee funcation for every key and value pair of hashmap (random order)
func (hm *HashMap) Iterate(iteratee func(key, value any)) {
if hm.size > 0 {
for i := 0; i < len(hm.table); i++ {
item := hm.table[i]
if item != nil {
iteratee(item.key, item.value)
}
}
}
}
// Keys returns a slice of the hashmap's keys (random order)
func (hm *HashMap) Keys() []any {
keys := make([]any, int(hm.size))
index := 0
if hm.size > 0 {
hm.Iterate(func(key, value any) {
keys[index] = key
index++
})
}
return keys
}
// Values returns a slice of the hashmap's keys (random order)
func (hm *HashMap) Values() []any {
values := make([]any, int(hm.size))
index := 0
if hm.size > 0 {
hm.Iterate(func(key, value any) {
values[index] = value
index++
})
}
return values
}
func (hm *HashMap) resize() {
hm.capacity <<= 1
tempTable := hm.table
hm.table = make([]*mapNode, hm.capacity)
for i := 0; i < len(tempTable); i++ {
node := tempTable[i]
if node == nil {
continue
}
hm.table[hm.hash(node.key)] = node
}
}
func (hm *HashMap) hash(key any) uint64 {
h := fnv.New64a()
_, _ = h.Write([]byte(fmt.Sprintf("%v", key)))
hashValue := h.Sum64()
return (hm.capacity - 1) & (hashValue ^ (hashValue >> 16))
}
func newMapNode(key, value any) *mapNode {
return &mapNode{
key: key,
value: value,
}
}
func newMapNodeWithNext(key, value any, next *mapNode) *mapNode {
return &mapNode{
key: key,
value: value,
next: next,
}
}

View File

@@ -0,0 +1,107 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestHashMap_PutAndGet(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_PutAndGet")
hm := NewHashMap()
hm.Put("abc", 3)
assert.Equal(3, hm.Get("abc"))
assert.IsNil(hm.Get("abcd"))
hm.Put("abc", 4)
assert.Equal(4, hm.Get("abc"))
}
func TestHashMap_Resize(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_Resize")
hm := NewHashMapWithCapacity(3, 3)
for i := 0; i < 20; i++ {
hm.Put(i, 10)
}
assert.Equal(10, hm.Get(5))
}
func TestHashMap_Delete(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_Delete")
hm := NewHashMap()
hm.Put("abc", 3)
assert.Equal(3, hm.Get("abc"))
hm.Delete("abc")
assert.IsNil(hm.Get("abc"))
}
func TestHashMap_Contains(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_Contains")
hm := NewHashMap()
assert.Equal(false, hm.Contains("abc"))
hm.Put("abc", 3)
assert.Equal(true, hm.Contains("abc"))
}
func TestHashMap_KeysValues(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_KeysValues")
hm := NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
values := hm.Values()
assert.Equal(3, len(values))
assert.Equal(3, len(keys))
}
func TestHashMap_Keys(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_Keys")
hm := NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
assert.Equal(3, len(keys))
}
func TestHashMap_GetOrDefault(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_GetOrDefault")
hm := NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
assert.Equal(1, hm.GetOrDefault("a", 5))
assert.Equal(5, hm.GetOrDefault("d", 5))
}

View File

@@ -0,0 +1,203 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. MaxHeap is a binary max heap.
package datastructure
import (
"fmt"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
// MaxHeap implements a binary max heap
// type T should implements Compare function in lancetconstraints.Comparator interface.
type MaxHeap[T any] struct {
data []T
comparator lancetconstraints.Comparator
}
// NewMaxHeap returns a MaxHeap instance with the given comparator.
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] {
return &MaxHeap[T]{
data: make([]T, 0),
comparator: comparator,
}
}
// BuildMaxHeap builds a MaxHeap instance with data and given comparator.
func BuildMaxHeap[T any](data []T, comparator lancetconstraints.Comparator) *MaxHeap[T] {
heap := &MaxHeap[T]{
data: make([]T, 0, len(data)),
comparator: comparator,
}
for _, v := range data {
heap.Push(v)
}
return heap
}
// Push value into the heap
func (h *MaxHeap[T]) Push(value T) {
h.data = append(h.data, value)
h.heapifyUp(len(h.data) - 1)
}
// heapifyUp heapify the data from bottom to top
func (h *MaxHeap[T]) heapifyUp(i int) {
for h.comparator.Compare(h.data[parentIndex(i)], h.data[i]) < 0 {
h.swap(parentIndex(i), i)
i = parentIndex(i)
}
}
// Pop return the largest value, and remove it from the heap
// if heap is empty, return zero value and fasle
func (h *MaxHeap[T]) Pop() (T, bool) {
var val T
if h.Size() == 0 {
return val, false
}
val = h.data[0]
l := len(h.data) - 1
h.data[0] = h.data[l]
h.data = h.data[:l]
h.heapifyDown(0)
return val, true
}
// heapifyDown heapify the data from top to bottom
func (h *MaxHeap[T]) heapifyDown(i int) {
lastIndex := len(h.data) - 1
l, r := leftChildIndex(i), rightChildIndex(i)
childToCompare := 0
for l <= lastIndex {
if l == lastIndex {
childToCompare = l
} else if h.comparator.Compare(h.data[l], h.data[r]) > 0 {
childToCompare = l
} else {
childToCompare = r
}
if h.comparator.Compare(h.data[i], h.data[childToCompare]) < 0 {
h.swap(i, childToCompare)
i = childToCompare
l, r = leftChildIndex(i), rightChildIndex(i)
} else {
break
}
}
}
// Peek returns the largest element from the heap without removing it.
// if heap is empty, it returns zero value and false.
func (h *MaxHeap[T]) Peek() (T, bool) {
if h.Size() == 0 {
var val T
return val, false
}
return h.data[0], true
}
// Size return the number of elements in the heap
func (h *MaxHeap[T]) Size() int {
return len(h.data)
}
// Data return data of the heap
func (h *MaxHeap[T]) Data() []T {
return h.data
}
// PrintStructure print the structure of the heap
func (h *MaxHeap[T]) PrintStructure() {
level := 1
data := h.data
length := len(h.data)
index := 0
list := [][]string{}
temp := []string{}
for index < length {
start := powerTwo(level-1) - 1
end := start + powerTwo(level-1) - 1
temp = append(temp, fmt.Sprintf("%v", data[index]))
index++
if index > end || index >= length {
list = append(list, temp)
temp = []string{}
if index < length {
level++
}
}
}
lastNum := powerTwo(level - 1)
lastLen := lastNum + (lastNum - 1)
heapTree := make([][]string, level)
for i := 0; i < level; i++ {
heapTree[i] = make([]string, lastLen)
for j := 0; j < lastLen; j++ {
heapTree[i][j] = ""
}
}
for k := 0; k < len(list); k++ {
vals := list[k]
tempLevel := level - k
st := powerTwo(tempLevel-1) - 1
for _, v := range vals {
heapTree[k][st] = v
gap := powerTwo(tempLevel)
st = st + gap
}
}
for m := 0; m < level; m++ {
for n := 0; n < lastLen; n++ {
val := heapTree[m][n]
if val == "" {
fmt.Print(" ")
} else {
fmt.Print(val)
}
}
fmt.Println()
}
}
// parentIndex get parent index of the given index
func parentIndex(i int) int {
return (i - 1) / 2
}
// leftChildIndex get left child index of the given index
func leftChildIndex(i int) int {
return 2*i + 1
}
// rightChildIndex get right child index of the given index
func rightChildIndex(i int) int {
return 2*i + 2
}
// swap two elements in the heap
func (h *MaxHeap[T]) swap(i, j int) {
h.data[i], h.data[j] = h.data[j], h.data[i]
}
func powerTwo(n int) int {
return 1 << n
}

View File

@@ -0,0 +1,98 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func TestMaxHeap_BuildMaxHeap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_BuildMaxHeap")
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
heap := BuildMaxHeap(values, &intComparator{})
expected := []int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
assert.Equal(expected, heap.data)
assert.Equal(12, heap.Size())
}
func TestMaxHeap_Push(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_Push")
heap := NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
heap.Push(v)
}
expected := []int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
assert.Equal(expected, heap.data)
assert.Equal(12, heap.Size())
heap.PrintStructure()
}
func TestMaxHeap_Pop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_Pop")
heap := NewMaxHeap[int](&intComparator{})
_, ok := heap.Pop()
assert.Equal(false, ok)
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
heap.Push(v)
}
val, ok := heap.Pop()
assert.Equal(12, val)
assert.Equal(true, ok)
assert.Equal(11, heap.Size())
}
func TestMaxHeap_Peek(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_Peek")
heap := NewMaxHeap[int](&intComparator{})
_, ok := heap.Peek()
assert.Equal(false, ok)
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
heap.Push(v)
}
val, ok := heap.Peek()
assert.Equal(12, val)
assert.Equal(true, ok)
assert.Equal(12, heap.Size())
}

View File

@@ -1,13 +1,16 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Link structure contains SinglyLink and DoublyLink.
package datastructure
import (
"errors"
"fmt"
"github.com/duke-git/lancet/v2/datastructure"
)
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the link, Next pointer points to a next node of the link.
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the dl, Next pointer points to a next node of the dl.
type DoublyLink[T any] struct {
Head *datastructure.LinkNode[T]
length int
@@ -19,30 +22,30 @@ func NewDoublyLink[T any]() *DoublyLink[T] {
}
// InsertAtHead insert value into doubly linklist at head index
func (link *DoublyLink[T]) InsertAtHead(value T) {
func (dl *DoublyLink[T]) InsertAtHead(value T) {
newNode := datastructure.NewLinkNode(value)
size := link.Size()
size := dl.Size()
if size == 0 {
link.Head = newNode
link.length++
dl.Head = newNode
dl.length++
return
}
newNode.Next = link.Head
newNode.Next = dl.Head
newNode.Pre = nil
link.Head.Pre = newNode
link.Head = newNode
dl.Head.Pre = newNode
dl.Head = newNode
link.length++
dl.length++
}
// InsertAtTail insert value into doubly linklist at tail index
func (link *DoublyLink[T]) InsertAtTail(value T) {
current := link.Head
func (dl *DoublyLink[T]) InsertAtTail(value T) {
current := dl.Head
if current == nil {
link.InsertAtHead(value)
dl.InsertAtHead(value)
return
}
@@ -55,28 +58,29 @@ func (link *DoublyLink[T]) InsertAtTail(value T) {
newNode.Pre = current
current.Next = newNode
link.length++
dl.length++
}
// InsertAt insert value into doubly linklist at index
func (link *DoublyLink[T]) InsertAt(index int, value T) error {
size := link.length
// param `index` should between [0, length], if index do not meet the conditions, do nothing
func (dl *DoublyLink[T]) InsertAt(index int, value T) {
size := dl.length
if index < 0 || index > size {
return errors.New("param index should between 0 and the length of doubly link.")
return
}
if index == 0 {
link.InsertAtHead(value)
return nil
dl.InsertAtHead(value)
return
}
if index == size {
link.InsertAtTail(value)
return nil
dl.InsertAtTail(value)
return
}
i := 0
current := link.Head
current := dl.Head
for current != nil {
if i == index-1 {
@@ -85,38 +89,36 @@ func (link *DoublyLink[T]) InsertAt(index int, value T) error {
newNode.Pre = current
current.Next = newNode
link.length++
dl.length++
return nil
return
}
i++
current = current.Next
}
return errors.New("doubly link list no exist")
}
// DeleteAtHead delete value in doubly linklist at head index
func (link *DoublyLink[T]) DeleteAtHead() error {
if link.Head == nil {
return errors.New("doubly link list no exist")
func (dl *DoublyLink[T]) DeleteAtHead() {
if dl.Head == nil {
return
}
current := link.Head
link.Head = current.Next
link.Head.Pre = nil
link.length--
return nil
current := dl.Head
dl.Head = current.Next
dl.Head.Pre = nil
dl.length--
}
// DeleteAtTail delete value in doubly linklist at tail index
func (link *DoublyLink[T]) DeleteAtTail() error {
if link.Head == nil {
return errors.New("doubly link list no exist")
// DeleteAtTail delete value in doubly linklist at tail
func (dl *DoublyLink[T]) DeleteAtTail() {
if dl.Head == nil {
return
}
current := link.Head
current := dl.Head
if current.Next == nil {
return link.DeleteAtHead()
dl.DeleteAtHead()
}
for current.Next.Next != nil {
@@ -124,45 +126,44 @@ func (link *DoublyLink[T]) DeleteAtTail() error {
}
current.Next = nil
link.length--
return nil
dl.length--
}
// DeleteAt delete value in doubly linklist at index
func (link *DoublyLink[T]) DeleteAt(index int) error {
if link.Head == nil {
return errors.New("doubly link list no exist")
// param `index` should be [0, len(DoublyLink)-1]
func (dl *DoublyLink[T]) DeleteAt(index int) {
if dl.Head == nil {
return
}
current := link.Head
current := dl.Head
if current.Next == nil || index == 0 {
return link.DeleteAtHead()
dl.DeleteAtHead()
}
if index == link.length-1 {
return link.DeleteAtTail()
if index == dl.length-1 {
dl.DeleteAtTail()
}
if index < 0 || index > link.length-1 {
return errors.New("param index should between 0 and link size -1.")
if index < 0 || index > dl.length-1 {
return
}
i := 0
for current != nil {
if i == index-1 {
current.Next = current.Next.Next
link.length--
return nil
dl.length--
return
}
i++
current = current.Next
}
return errors.New("delete error")
}
// Reverse the linked list
func (link *DoublyLink[T]) Reverse() {
current := link.Head
func (dl *DoublyLink[T]) Reverse() {
current := dl.Head
var temp *datastructure.LinkNode[T]
for current != nil {
@@ -173,20 +174,20 @@ func (link *DoublyLink[T]) Reverse() {
}
if temp != nil {
link.Head = temp.Pre
dl.Head = temp.Pre
}
}
// GetMiddleNode return node at middle index of linked list
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if link.Head == nil {
func (dl *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if dl.Head == nil {
return nil
}
if link.Head.Next == nil {
return link.Head
if dl.Head.Next == nil {
return dl.Head
}
fast := link.Head
slow := link.Head
fast := dl.Head
slow := dl.Head
for fast != nil {
fast = fast.Next
@@ -202,24 +203,24 @@ func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
}
// Size return the count of doubly linked list
func (link *DoublyLink[T]) Size() int {
return link.length
func (dl *DoublyLink[T]) Size() int {
return dl.length
}
// Values return slice of all doubly linklist node value
func (link *DoublyLink[T]) Values() []T {
res := []T{}
current := link.Head
func (dl *DoublyLink[T]) Values() []T {
result := []T{}
current := dl.Head
for current != nil {
res = append(res, current.Value)
result = append(result, current.Value)
current = current.Next
}
return res
return result
}
// Print all nodes info of a linked list
func (link *DoublyLink[T]) Print() {
current := link.Head
func (dl *DoublyLink[T]) Print() {
current := dl.Head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
@@ -229,13 +230,13 @@ func (link *DoublyLink[T]) Print() {
fmt.Println(info)
}
// IsEmpty checks if link is empty or not
func (link *DoublyLink[T]) IsEmpty() bool {
return link.length == 0
// IsEmpty checks if dl is empty or not
func (dl *DoublyLink[T]) IsEmpty() bool {
return dl.length == 0
}
// Clear all nodes in doubly linklist
func (link *DoublyLink[T]) Clear() {
link.Head = nil
link.length = 0
func (dl *DoublyLink[T]) Clear() {
dl.Head = nil
dl.length = 0
}

View File

@@ -7,6 +7,8 @@ import (
)
func TestDoublyLink_InsertAtFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtFirst")
link := NewDoublyLink[int]()
@@ -22,6 +24,8 @@ func TestDoublyLink_InsertAtFirst(t *testing.T) {
}
func TestDoublyLink_InsertAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtTail")
link := NewDoublyLink[int]()
@@ -37,33 +41,30 @@ func TestDoublyLink_InsertAtTail(t *testing.T) {
}
func TestDoublyLink_InsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_InsertAt")
link := NewDoublyLink[int]()
err := link.InsertAt(1, 1)
assert.IsNotNil(err)
link.InsertAt(1, 1) //do nothing
link.InsertAt(0, 1)
link.InsertAt(1, 2)
link.InsertAt(2, 4)
link.InsertAt(2, 3)
link.Print()
expected := []int{1, 2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_DeleteAtHead(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
link := NewDoublyLink[int]()
err := link.DeleteAtHead()
assert.IsNotNil(err)
link.DeleteAtHead()
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -71,7 +72,6 @@ func TestDoublyLink_DeleteAtHead(t *testing.T) {
link.InsertAtTail(4)
link.DeleteAtHead()
link.Print()
expected := []int{2, 3, 4}
values := link.Values()
@@ -80,11 +80,12 @@ func TestDoublyLink_DeleteAtHead(t *testing.T) {
}
func TestDoublyLink_DeleteAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
link := NewDoublyLink[int]()
err := link.DeleteAtTail()
assert.IsNotNil(err)
link.DeleteAtTail()
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -92,7 +93,6 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
link.InsertAtTail(4)
link.DeleteAtTail()
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
@@ -101,11 +101,12 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
}
func TestDoublyLink_DeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
link := NewDoublyLink[int]()
err := link.DeleteAt(0)
assert.IsNotNil(err)
link.DeleteAt(0)
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -113,11 +114,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
link.InsertAtTail(4)
link.InsertAtTail(5)
err = link.DeleteAt(5)
assert.IsNotNil(err)
err = link.DeleteAt(0)
assert.IsNil(err)
link.DeleteAt(0)
assert.Equal([]int{2, 3, 4, 5}, link.Values())
link.DeleteAt(3)
@@ -129,6 +126,8 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
}
func TestDoublyLink_Reverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_Reverse")
link := NewDoublyLink[int]()
@@ -143,6 +142,8 @@ func TestDoublyLink_Reverse(t *testing.T) {
}
func TestDoublyLink_GetMiddleNode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_GetMiddleNode")
link := NewDoublyLink[int]()
@@ -162,10 +163,11 @@ func TestDoublyLink_GetMiddleNode(t *testing.T) {
}
func TestDoublyLink_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_Clear")
link := NewDoublyLink[int]()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())

View File

@@ -1,14 +1,17 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Link structure contains SinglyLink and DoublyLink.
package datastructure
import (
"errors"
"fmt"
"reflect"
"github.com/duke-git/lancet/v2/datastructure"
)
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the link.
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the sl.
type SinglyLink[T any] struct {
Head *datastructure.LinkNode[T]
length int
@@ -20,18 +23,18 @@ func NewSinglyLink[T any]() *SinglyLink[T] {
}
// InsertAtHead insert value into singly linklist at head index
func (link *SinglyLink[T]) InsertAtHead(value T) {
func (sl *SinglyLink[T]) InsertAtHead(value T) {
newNode := datastructure.NewLinkNode(value)
newNode.Next = link.Head
link.Head = newNode
link.length++
newNode.Next = sl.Head
sl.Head = newNode
sl.length++
}
// InsertAtTail insert value into singly linklist at tail index
func (link *SinglyLink[T]) InsertAtTail(value T) {
current := link.Head
func (sl *SinglyLink[T]) InsertAtTail(value T) {
current := sl.Head
if current == nil {
link.InsertAtHead(value)
sl.InsertAtHead(value)
return
}
@@ -43,65 +46,63 @@ func (link *SinglyLink[T]) InsertAtTail(value T) {
newNode.Next = nil
current.Next = newNode
link.length++
sl.length++
}
// InsertAt insert value into singly linklist at index
func (link *SinglyLink[T]) InsertAt(index int, value T) error {
size := link.length
// param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing
func (sl *SinglyLink[T]) InsertAt(index int, value T) {
size := sl.length
if index < 0 || index > size {
return errors.New("param index should between 0 and the length of singly link.")
return
}
if index == 0 {
link.InsertAtHead(value)
return nil
sl.InsertAtHead(value)
return
}
if index == size {
link.InsertAtTail(value)
return nil
sl.InsertAtTail(value)
return
}
i := 0
current := link.Head
current := sl.Head
for current != nil {
if i == index-1 {
newNode := datastructure.NewLinkNode(value)
newNode.Next = current.Next
current.Next = newNode
link.length++
return nil
sl.length++
return
}
i++
current = current.Next
}
return errors.New("singly link list no exist")
}
// DeleteAtHead delete value in singly linklist at head index
func (link *SinglyLink[T]) DeleteAtHead() error {
if link.Head == nil {
return errors.New("singly link list no exist")
func (sl *SinglyLink[T]) DeleteAtHead() {
if sl.Head == nil {
return
}
current := link.Head
link.Head = current.Next
link.length--
return nil
current := sl.Head
sl.Head = current.Next
sl.length--
}
// DeleteAtTail delete value in singly linklist at tail index
func (link *SinglyLink[T]) DeleteAtTail() error {
if link.Head == nil {
return errors.New("singly link list no exist")
// DeleteAtTail delete value in singly linklist at tail
func (sl *SinglyLink[T]) DeleteAtTail() {
if sl.Head == nil {
return
}
current := link.Head
current := sl.Head
if current.Next == nil {
return link.DeleteAtHead()
sl.DeleteAtHead()
}
for current.Next.Next != nil {
@@ -109,68 +110,66 @@ func (link *SinglyLink[T]) DeleteAtTail() error {
}
current.Next = nil
link.length--
return nil
sl.length--
}
// DeleteAt delete value in singly linklist at index
func (link *SinglyLink[T]) DeleteAt(index int) error {
if link.Head == nil {
return errors.New("singly link list no exist")
// param `index` should be [0, len(SinglyLink)-1]
func (sl *SinglyLink[T]) DeleteAt(index int) {
if sl.Head == nil {
return
}
current := link.Head
current := sl.Head
if current.Next == nil || index == 0 {
return link.DeleteAtHead()
sl.DeleteAtHead()
}
if index == link.length-1 {
return link.DeleteAtTail()
if index == sl.length-1 {
sl.DeleteAtTail()
}
if index < 0 || index > link.length-1 {
return errors.New("param index should between 0 and link size -1.")
if index < 0 || index > sl.length-1 {
return
}
i := 0
for current != nil {
if i == index-1 {
current.Next = current.Next.Next
link.length--
return nil
sl.length--
return
}
i++
current = current.Next
}
return errors.New("delete error")
}
// DeleteValue delete value in singly linklist
func (link *SinglyLink[T]) DeleteValue(value T) {
if link.Head == nil {
func (sl *SinglyLink[T]) DeleteValue(value T) {
if sl.Head == nil {
return
}
dummyHead := datastructure.NewLinkNode(value)
dummyHead.Next = link.Head
dummyHead.Next = sl.Head
current := dummyHead
for current.Next != nil {
if reflect.DeepEqual(current.Next.Value, value) {
current.Next = current.Next.Next
link.length--
sl.length--
} else {
current = current.Next
}
}
link.Head = dummyHead.Next
sl.Head = dummyHead.Next
}
// Reverse the linked list
func (link *SinglyLink[T]) Reverse() {
func (sl *SinglyLink[T]) Reverse() {
var pre, next *datastructure.LinkNode[T]
current := link.Head
current := sl.Head
for current != nil {
next = current.Next
@@ -179,19 +178,19 @@ func (link *SinglyLink[T]) Reverse() {
current = next
}
link.Head = pre
sl.Head = pre
}
// GetMiddleNode return node at middle index of linked list
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if link.Head == nil {
func (sl *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if sl.Head == nil {
return nil
}
if link.Head.Next == nil {
return link.Head
if sl.Head.Next == nil {
return sl.Head
}
fast := link.Head
slow := link.Head
fast := sl.Head
slow := sl.Head
for fast != nil {
fast = fast.Next
@@ -207,35 +206,35 @@ func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
}
// Size return the count of singly linked list
func (link *SinglyLink[T]) Size() int {
return link.length
func (sl *SinglyLink[T]) Size() int {
return sl.length
}
// Values return slice of all singly linklist node value
func (link *SinglyLink[T]) Values() []T {
res := []T{}
current := link.Head
func (sl *SinglyLink[T]) Values() []T {
result := []T{}
current := sl.Head
for current != nil {
res = append(res, current.Value)
result = append(result, current.Value)
current = current.Next
}
return res
return result
}
// IsEmpty checks if link is empty or not
func (link *SinglyLink[T]) IsEmpty() bool {
return link.length == 0
// IsEmpty checks if sl is empty or not
func (sl *SinglyLink[T]) IsEmpty() bool {
return sl.length == 0
}
// Clear all the node in singly linklist
func (link *SinglyLink[T]) Clear() {
link.Head = nil
link.length = 0
func (sl *SinglyLink[T]) Clear() {
sl.Head = nil
sl.length = 0
}
// Print all nodes info of a linked list
func (link *SinglyLink[T]) Print() {
current := link.Head
func (sl *SinglyLink[T]) Print() {
current := sl.Head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)

View File

@@ -7,6 +7,8 @@ import (
)
func TestSinglyLink_InsertAtFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtFirst")
link := NewSinglyLink[int]()
@@ -22,6 +24,8 @@ func TestSinglyLink_InsertAtFirst(t *testing.T) {
}
func TestSinglyLink_InsertAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtTail")
link := NewSinglyLink[int]()
@@ -37,29 +41,18 @@ func TestSinglyLink_InsertAtTail(t *testing.T) {
}
func TestSinglyLink_InsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_InsertAt")
link := NewSinglyLink[int]()
err := link.InsertAt(1, 1)
assert.IsNotNil(err)
link.InsertAt(1, 1) //do nothing
err = link.InsertAt(0, 1)
if err != nil {
t.FailNow()
}
err = link.InsertAt(1, 2)
if err != nil {
t.FailNow()
}
err = link.InsertAt(2, 4)
if err != nil {
t.FailNow()
}
err = link.InsertAt(2, 3)
if err != nil {
t.FailNow()
}
link.InsertAt(0, 1)
link.InsertAt(1, 2)
link.InsertAt(2, 4)
link.InsertAt(2, 3)
link.Print()
@@ -70,11 +63,13 @@ func TestSinglyLink_InsertAt(t *testing.T) {
}
func TestSinglyLink_DeleteAtHead(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
link := NewSinglyLink[int]()
err := link.DeleteAtHead()
assert.IsNotNil(err)
link.DeleteAtHead()
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -91,19 +86,17 @@ func TestSinglyLink_DeleteAtHead(t *testing.T) {
}
func TestSinglyLink_DeleteAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
link := NewSinglyLink[int]()
err := link.DeleteAtTail()
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteAtTail()
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
@@ -112,10 +105,11 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
}
func TestSinglyLink_DeleteValue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteValue")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(2)
@@ -130,23 +124,18 @@ func TestSinglyLink_DeleteValue(t *testing.T) {
}
func TestSinglyLink_DeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
link := NewSinglyLink[int]()
err := link.DeleteAt(0)
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.InsertAtTail(5)
err = link.DeleteAt(5)
assert.IsNotNil(err)
err = link.DeleteAt(0)
assert.IsNil(err)
link.DeleteAt(0)
assert.Equal([]int{2, 3, 4, 5}, link.Values())
link.DeleteAt(3)
@@ -158,6 +147,8 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
}
func TestSinglyLink_Reverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_Reverse")
link := NewSinglyLink[int]()
@@ -167,11 +158,12 @@ func TestSinglyLink_Reverse(t *testing.T) {
link.InsertAtTail(4)
link.Reverse()
link.Print()
assert.Equal([]int{4, 3, 2, 1}, link.Values())
}
func TestSinglyLink_GetMiddleNode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_GetMiddleNode")
link := NewSinglyLink[int]()
@@ -186,6 +178,7 @@ func TestSinglyLink_GetMiddleNode(t *testing.T) {
link.InsertAtTail(5)
link.InsertAtTail(6)
link.InsertAtTail(7)
middle2 := link.GetMiddleNode()
assert.Equal(4, middle2.Value)
}

View 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
}

View 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)
}

View File

@@ -1,24 +1,26 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
// Package datastructure contains some data structure. list is a linear table, implemented with slice.
package datastructure
import (
"reflect"
"github.com/duke-git/lancet/v2/iterator"
)
// List is a linear table, implemented with slice
// List is a linear table, implemented with slice.
type List[T any] struct {
data []T
}
// NewList return a pointer of List
// NewList return a pointer of List.
func NewList[T any](data []T) *List[T] {
return &List[T]{data: data}
}
// Data return list data
// Data return list data.
func (l *List[T]) Data() []T {
return l.data
}
@@ -31,7 +33,7 @@ func (l *List[T]) ValueOf(index int) (*T, bool) {
return &l.data[index], true
}
// IndexOf reture the index of value. if not found return -1
// IndexOf returns the index of value. if not found return -1.
func (l *List[T]) IndexOf(value T) int {
index := -1
data := l.data
@@ -44,7 +46,49 @@ func (l *List[T]) IndexOf(value T) int {
return index
}
// Contain checks if the value in the list or not
// LastIndexOf returns the index of the last occurrence of the value in this list.
// if not found return -1.
func (l *List[T]) LastIndexOf(value T) int {
index := -1
data := l.data
for i := len(data) - 1; i >= 0; i-- {
if reflect.DeepEqual(data[i], value) {
index = i
break
}
}
return index
}
// IndexOfFunc returns the first index satisfying f(v)
// if not found return -1.
func (l *List[T]) IndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
for i, v := range data {
if f(v) {
index = i
break
}
}
return index
}
// LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i])
// if not found return -1.
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
for i := len(data) - 1; i >= 0; i-- {
if f(data[i]) {
index = i
break
}
}
return index
}
// Contain checks if the value in the list or not.
func (l *List[T]) Contain(value T) bool {
data := l.data
for _, v := range data {
@@ -55,22 +99,22 @@ func (l *List[T]) Contain(value T) bool {
return false
}
// Push append value to the list data
// Push append value to the list data.
func (l *List[T]) Push(value T) {
l.data = append(l.data, value)
}
// InsertAtFirst insert value into list at first index
// InsertAtFirst insert value into list at first index.
func (l *List[T]) InsertAtFirst(value T) {
l.InsertAt(0, value)
}
// InsertAtLast insert value into list at last index
// InsertAtLast insert value into list at last index.
func (l *List[T]) InsertAtLast(value T) {
l.InsertAt(len(l.data), value)
}
// InsertAt insert value into list at index
// InsertAt insert value into list at index.
func (l *List[T]) InsertAt(index int, value T) {
data := l.data
size := len(data)
@@ -81,7 +125,7 @@ func (l *List[T]) InsertAt(index int, value T) {
l.data = append(data[:index], append([]T{value}, data[index:]...)...)
}
// PopFirst delete the first value of list and return it
// PopFirst delete the first value of list and return it.
func (l *List[T]) PopFirst() (*T, bool) {
if len(l.data) == 0 {
return nil, false
@@ -93,7 +137,7 @@ func (l *List[T]) PopFirst() (*T, bool) {
return &v, true
}
// PopLast delete the last value of list and return it
// PopLast delete the last value of list and return it.
func (l *List[T]) PopLast() (*T, bool) {
size := len(l.data)
if size == 0 {
@@ -106,7 +150,7 @@ func (l *List[T]) PopLast() (*T, bool) {
return &v, true
}
// DeleteAt delete the value of list at index
// DeleteAt delete the value of list at index.
func (l *List[T]) DeleteAt(index int) {
data := l.data
size := len(data)
@@ -114,13 +158,38 @@ func (l *List[T]) DeleteAt(index int) {
return
}
if index == size-1 {
data = append(data[:index])
data = data[:index]
} else {
data = append(data[:index], data[index+1:]...)
}
l.data = data
}
// DeleteIf delete all satisfying f(data[i]), returns count of removed elements
func (l *List[T]) DeleteIf(f func(T) bool) int {
data := l.data
size := len(data)
var c int
for index := 0; index < len(data); index++ {
if !f(data[index]) {
continue
}
if index == size-1 {
data = data[:index]
} else {
data = append(data[:index], data[index+1:]...)
index--
}
c++
}
if c > 0 {
l.data = data
}
return c
}
// UpdateAt update value of list at index, index shoud between 0 and list size -1
func (l *List[T]) UpdateAt(index int, value T) {
data := l.data
@@ -132,7 +201,7 @@ func (l *List[T]) UpdateAt(index int, value T) {
l.data = append(data[:index], append([]T{value}, data[index+1:]...)...)
}
// Equal compare list to other list, use reflect.DeepEqual
// Equal compare list to other list, use reflect.DeepEqual.
func (l *List[T]) Equal(other *List[T]) bool {
if len(l.data) != len(other.data) {
return false
@@ -147,17 +216,17 @@ func (l *List[T]) Equal(other *List[T]) bool {
return true
}
// IsEmpty check if the list is empty or not
// IsEmpty check if the list is empty or not.
func (l *List[T]) IsEmpty() bool {
return len(l.data) == 0
}
// Clear the data of list
// Clear the data of list.
func (l *List[T]) Clear() {
l.data = make([]T, 0, 0)
l.data = make([]T, 0)
}
// Clone return a copy of list
// Clone return a copy of list.
func (l *List[T]) Clone() *List[T] {
cl := NewList(make([]T, len(l.data)))
copy(cl.data, l.data)
@@ -165,10 +234,10 @@ func (l *List[T]) Clone() *List[T] {
return cl
}
// Merge two list, return new list, don't change original list
// Merge two list, return new list, don't change original list.
func (l *List[T]) Merge(other *List[T]) *List[T] {
l1, l2 := len(l.data), len(other.data)
ml := NewList(make([]T, l1+l2, l1+l2))
ml := NewList(make([]T, l1+l2))
data := append([]T{}, append(l.data, other.data...)...)
ml.data = data
@@ -176,12 +245,17 @@ func (l *List[T]) Merge(other *List[T]) *List[T] {
return ml
}
// Size return number of list data items
// Size return number of list data items.
func (l *List[T]) Size() int {
return len(l.data)
}
// Swap the value of index i and j in list
// Cap return cap of the inner data.
func (l *List[T]) Cap() int {
return cap(l.data)
}
// Swap the value of index i and j in list.
func (l *List[T]) Swap(i, j int) {
size := len(l.data)
if i < 0 || i >= size || j < 0 || j >= size {
@@ -190,19 +264,19 @@ func (l *List[T]) Swap(i, j int) {
l.data[i], l.data[j] = l.data[j], l.data[i]
}
// Reverse the item order of list
// Reverse the item order of list.
func (l *List[T]) Reverse() {
for i, j := 0, len(l.data)-1; i < j; i, j = i+1, j-1 {
l.data[i], l.data[j] = l.data[j], l.data[i]
}
}
// Unique remove duplicate items in list
// Unique delete duplicate items in list.
func (l *List[T]) Unique() {
data := l.data
size := len(data)
uniqueData := make([]T, 0, 0)
uniqueData := make([]T, 0)
for i := 0; i < size; i++ {
value := data[i]
skip := true
@@ -220,26 +294,125 @@ 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] {
res := NewList([]T{})
result := NewList([]T{})
res.data = append(res.data, l.data...)
res.data = append(res.data, other.data...)
res.Unique()
result.data = append(result.data, l.data...)
result.data = append(result.data, other.data...)
result.Unique()
return res
return result
}
// Intersection creates a new list whose element both be contained in list l and other
// Intersection creates a new list whose element both be contained in list l and other.
func (l *List[T]) Intersection(other *List[T]) *List[T] {
res := NewList(make([]T, 0, 0))
result := NewList(make([]T, 0))
for _, v := range l.data {
if other.Contain(v) {
res.data = append(res.data, v)
result.data = append(result.data, v)
}
}
return res
return result
}
// Difference returns the difference between two collections.
// return a list whose element in the original list, not in the given list.
func (l *List[T]) Difference(other *List[T]) *List[T] {
result := NewList(make([]T, 0))
intersectList := l.Intersection(other)
for _, v := range l.data {
if !intersectList.Contain(v) {
result.data = append(result.data, v)
}
}
return result
}
// SymmetricDifference oppoiste operation of intersection function.
func (l *List[T]) SymmetricDifference(other *List[T]) *List[T] {
result := NewList(make([]T, 0))
intersectList := l.Intersection(other)
for _, v := range l.data {
if !intersectList.Contain(v) {
result.data = append(result.data, v)
}
}
for _, v := range other.data {
if !intersectList.Contain(v) {
result.data = append(result.data, v)
}
}
return result
}
// SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T] {
data := l.data[fromIndex:toIndex]
subList := make([]T, len(data))
copy(subList, data)
return NewList(subList)
}
// ForEach performs the given action for each element of the list.
func (l *List[T]) ForEach(consumer func(T)) {
for _, it := range l.data {
consumer(it)
}
}
// RetainAll retains only the elements in this list that are contained in the given list.
func (l *List[T]) RetainAll(list *List[T]) bool {
return l.batchRemove(list, true)
}
// DeleteAll removes from this list all of its elements that are contained in the given list.
func (l *List[T]) DeleteAll(list *List[T]) bool {
return l.batchRemove(list, false)
}
func (l *List[T]) batchRemove(list *List[T], complement bool) bool {
var (
w = 0
data = l.data
size = len(data)
)
for i := 0; i < size; i++ {
if list.Contain(data[i]) == complement {
data[w] = data[i]
w++
}
}
if w != size {
l.data = data[:w]
return true
}
return false
}
// Iterator returns an iterator over the elements in this list in proper sequence.
func (l *List[T]) Iterator() iterator.Iterator[T] {
return iterator.FromSlice(l.data)
}
// ListToMap convert a list to a map based on iteratee function.
func ListToMap[T any, K comparable, V any](list *List[T], iteratee func(T) (K, V)) map[K]V {
result := make(map[K]V, list.Size())
for _, item := range list.data {
k, v := iteratee(item)
result[k] = v
}
return result
}

View File

@@ -7,6 +7,8 @@ import (
)
func TestListData(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestListData")
list := NewList([]int{1, 2, 3})
@@ -14,6 +16,8 @@ func TestListData(t *testing.T) {
}
func TestValueOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestValueOf")
list := NewList([]int{1, 2, 3})
@@ -26,6 +30,8 @@ func TestValueOf(t *testing.T) {
}
func TestIndexOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3})
@@ -36,7 +42,60 @@ func TestIndexOf(t *testing.T) {
assert.Equal(-1, i)
}
func TestIndexOfFunc(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3})
i := list.IndexOfFunc(func(a int) bool { return a == 1 })
assert.Equal(0, i)
i = list.IndexOfFunc(func(a int) bool { return a == 4 })
assert.Equal(-1, i)
}
func TestLastIndexOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
i := list.LastIndexOf(3)
assert.Equal(5, i)
i = list.LastIndexOf(10)
assert.Equal(-1, i)
i = list.LastIndexOf(4)
assert.Equal(6, i)
i = list.LastIndexOf(1)
assert.Equal(0, i)
}
func TestLastIndexOfFunc(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
i := list.LastIndexOfFunc(func(a int) bool { return a == 3 })
assert.Equal(5, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 10 })
assert.Equal(-1, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 4 })
assert.Equal(6, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 1 })
assert.Equal(0, i)
}
func TestContain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestContain")
list := NewList([]int{1, 2, 3})
@@ -45,6 +104,8 @@ func TestContain(t *testing.T) {
}
func TestPush(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPush")
list := NewList([]int{1, 2, 3})
@@ -54,6 +115,8 @@ func TestPush(t *testing.T) {
}
func TestInsertAtFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAtFirst")
list := NewList([]int{1, 2, 3})
@@ -63,6 +126,8 @@ func TestInsertAtFirst(t *testing.T) {
}
func TestInsertAtLast(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAtLast")
list := NewList([]int{1, 2, 3})
@@ -72,6 +137,8 @@ func TestInsertAtLast(t *testing.T) {
}
func TestInsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAt")
list := NewList([]int{1, 2, 3})
@@ -90,6 +157,8 @@ func TestInsertAt(t *testing.T) {
}
func TestPopFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPopFirst")
list := NewList([]int{1, 2, 3})
@@ -105,6 +174,8 @@ func TestPopFirst(t *testing.T) {
}
func TestPopLast(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPopLast")
list := NewList([]int{1, 2, 3})
@@ -120,6 +191,8 @@ func TestPopLast(t *testing.T) {
}
func TestDeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteAt")
list := NewList([]int{1, 2, 3, 4})
@@ -138,6 +211,8 @@ func TestDeleteAt(t *testing.T) {
}
func TestUpdateAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUpdateAt")
list := NewList([]int{1, 2, 3, 4})
@@ -156,6 +231,8 @@ func TestUpdateAt(t *testing.T) {
}
func TestEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqual")
list1 := NewList([]int{1, 2, 3, 4})
@@ -167,6 +244,8 @@ func TestEqual(t *testing.T) {
}
func TestIsEmpty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsEmpty")
list1 := NewList([]int{1, 2, 3, 4})
@@ -177,6 +256,8 @@ func TestIsEmpty(t *testing.T) {
}
func TestIsClear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsClear")
list1 := NewList([]int{1, 2, 3, 4})
@@ -187,6 +268,8 @@ func TestIsClear(t *testing.T) {
}
func TestClone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestClone")
list1 := NewList([]int{1, 2, 3, 4})
@@ -196,6 +279,8 @@ func TestClone(t *testing.T) {
}
func TestMerge(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMerge")
list1 := NewList([]int{1, 2, 3, 4})
@@ -207,6 +292,8 @@ func TestMerge(t *testing.T) {
}
func TestSize(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSize")
list := NewList([]int{1, 2, 3, 4})
@@ -216,7 +303,23 @@ func TestSize(t *testing.T) {
assert.Equal(0, empty.Size())
}
func TestCap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCap")
data := make([]int, 0, 100)
list := NewList(data)
assert.Equal(100, list.Cap())
data = make([]int, 0)
list = NewList(data)
assert.Equal(0, list.Cap())
}
func TestSwap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSwap")
list := NewList([]int{1, 2, 3, 4})
@@ -228,6 +331,8 @@ func TestSwap(t *testing.T) {
}
func TestReverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReverse")
list := NewList([]int{1, 2, 3, 4})
@@ -239,6 +344,8 @@ func TestReverse(t *testing.T) {
}
func TestUnique(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnique")
list := NewList([]int{1, 2, 2, 3, 4})
@@ -250,6 +357,8 @@ func TestUnique(t *testing.T) {
}
func TestUnion(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnion")
list1 := NewList([]int{1, 2, 3, 4})
@@ -261,6 +370,8 @@ func TestUnion(t *testing.T) {
}
func TestIntersection(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIntersection")
list1 := NewList([]int{1, 2, 3, 4})
@@ -270,3 +381,151 @@ func TestIntersection(t *testing.T) {
list3 := list1.Intersection(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDifference")
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
expected := NewList([]int{3})
list3 := list1.Difference(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSymmetricDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSymmetricDifference")
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
expected := NewList([]int{3, 4})
list3 := list1.SymmetricDifference(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSubSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSubSlice")
list := NewList([]int{1, 2, 3, 4, 5, 8})
subList := list.SubList(2, 5)
assert.Equal([]int{3, 4, 5}, subList.Data())
}
func BenchmarkSubSlice(b *testing.B) {
list := NewList([]int{1, 2, 3, 4, 5, 8})
for n := 0; n < b.N; n++ {
list.SubList(2, 5)
}
}
func TestDeleteIf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteIf")
list := NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
count := list.DeleteIf(func(a int) bool { return a == 1 })
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal(12, count)
count = list.DeleteIf(func(a int) bool { return a == 5 })
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal(0, count)
}
func TestForEach(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestForEach")
list := NewList([]int{1, 2, 3, 4})
rs := make([]int, 0)
list.ForEach(func(i int) {
rs = append(rs, i)
})
assert.Equal([]int{1, 2, 3, 4}, rs)
}
func TestRetainAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRetainAll")
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
retain := NewList([]int{1, 2})
retain1 := NewList([]int{2, 3})
retain2 := NewList([]int{1, 2, 5})
list.RetainAll(retain)
list1.RetainAll(retain1)
list2.RetainAll(retain2)
assert.Equal([]int{1, 2}, list.Data())
assert.Equal([]int{2, 3}, list1.Data())
assert.Equal([]int{1, 2}, list2.Data())
}
func TestDeleteAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteAll")
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
del := NewList([]int{1})
del1 := NewList([]int{2, 3})
del2 := NewList([]int{1, 2, 5})
list.DeleteAll(del)
list1.DeleteAll(del1)
list2.DeleteAll(del2)
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal([]int{1, 4}, list1.Data())
assert.Equal([]int{3, 4}, list2.Data())
}
func TestIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIterator")
list := NewList([]int{1, 2, 3, 4})
iterator := list.Iterator()
rs := make([]int, 0)
for iterator.HasNext() {
item, _ := iterator.Next()
rs = append(rs, item)
}
assert.Equal([]int{1, 2, 3, 4}, rs)
}
func TestListToMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "ListToMap")
list := NewList([]int{1, 2, 3, 4})
result := ListToMap(list, func(n int) (int, bool) {
return n, n > 1
})
expected := map[int]bool{1: false, 2: true, 3: true, 4: true}
assert.Equal(expected, result)
}

View File

@@ -1,7 +1,7 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
// Package datastructure implements some data structure.
package datastructure
// LinkNode is a linkedlist node, which have a Value and Pre points to previous node, Next points to a next node of the link.

View File

@@ -1,3 +1,8 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure.
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
package datastructure
import (
@@ -33,7 +38,7 @@ func (q *ArrayQueue[T]) Data() []T {
return items
}
// Size return length of queue data
// Size return number of elements in queue
func (q *ArrayQueue[T]) Size() int {
return q.size
}

View File

@@ -7,6 +7,8 @@ import (
)
func TestArrayQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Enqueue")
queue := NewArrayQueue[int](5)
@@ -14,17 +16,16 @@ func TestArrayQueue_Enqueue(t *testing.T) {
queue.Enqueue(2)
queue.Enqueue(3)
expected := []int{1, 2, 3}
data := queue.Data()
size := queue.Size()
queue.Print()
assert.Equal(expected, data)
assert.Equal([]int{1, 2, 3}, data)
assert.Equal(3, size)
}
func TestArrayQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Dequeue")
queue := NewArrayQueue[int](4)
@@ -35,12 +36,13 @@ func TestArrayQueue_Dequeue(t *testing.T) {
val, ok := queue.Dequeue()
assert.Equal(true, ok)
queue.Print()
assert.Equal(1, val)
assert.Equal([]int{2, 3}, queue.Data())
}
func TestArrayQueue_Front(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Front")
queue := NewArrayQueue[int](4)
@@ -50,13 +52,13 @@ func TestArrayQueue_Front(t *testing.T) {
val := queue.Front()
queue.Print()
assert.Equal(1, val)
assert.Equal([]int{1, 2, 3}, queue.Data())
}
func TestArrayQueue_Back(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Back")
queue := NewArrayQueue[int](4)
@@ -66,13 +68,13 @@ func TestArrayQueue_Back(t *testing.T) {
val := queue.Back()
queue.Print()
assert.Equal(3, val)
assert.Equal([]int{1, 2, 3}, queue.Data())
}
func TestArrayQueue_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Contain")
queue := NewArrayQueue[int](4)
@@ -85,6 +87,8 @@ func TestArrayQueue_Contain(t *testing.T) {
}
func TestArrayQueue_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Clear")
queue := NewArrayQueue[int](4)
@@ -102,6 +106,8 @@ func TestArrayQueue_Clear(t *testing.T) {
}
func TestArrayQueue_IsFull(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_IsFull")
queue := NewArrayQueue[int](3)

View File

@@ -1,3 +1,8 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure.
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
package datastructure
import (

View File

@@ -7,34 +7,50 @@ import (
)
func TestCircularQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Enqueue")
queue := NewCircularQueue[int](6)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
queue.Print()
err := queue.Enqueue(1)
assert.IsNil(err)
err = queue.Enqueue(2)
assert.IsNil(err)
err = queue.Enqueue(3)
assert.IsNil(err)
err = queue.Enqueue(4)
assert.IsNil(err)
err = queue.Enqueue(5)
assert.IsNil(err)
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
assert.Equal(5, queue.Size())
err := queue.Enqueue(6)
err = queue.Enqueue(6)
assert.IsNotNil(err)
}
func TestCircularQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
queue := NewCircularQueue[int](6)
queue := NewCircularQueue[int](4)
assert.Equal(true, queue.IsEmpty())
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
err := queue.Enqueue(1)
assert.IsNil(err)
err = queue.Enqueue(2)
assert.IsNil(err)
err = queue.Enqueue(3)
assert.IsNil(err)
val, err := queue.Dequeue()
assert.IsNil(err)
@@ -43,79 +59,82 @@ func TestCircularQueue_Dequeue(t *testing.T) {
assert.Equal(false, queue.IsFull())
val, _ = queue.Dequeue()
queue.Print()
assert.Equal(2, *val)
queue.Enqueue(6)
queue.Print()
assert.Equal(false, queue.IsFull())
}
func TestCircularQueue_Front(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Front")
queue := NewCircularQueue[int](6)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
queue.Print()
err := queue.Enqueue(1)
assert.IsNil(err)
queue.Dequeue()
queue.Dequeue()
queue.Enqueue(6)
queue.Enqueue(7)
err = queue.Enqueue(2)
assert.IsNil(err)
queue.Print()
err = queue.Enqueue(3)
assert.IsNil(err)
val := queue.Front()
assert.Equal(3, val)
assert.Equal(5, queue.Size())
assert.IsNil(err)
assert.Equal(1, val)
assert.Equal(3, queue.Size())
}
func TestCircularQueue_Back(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Back")
queue := NewCircularQueue[int](6)
queue := NewCircularQueue[int](3)
assert.Equal(true, queue.IsEmpty())
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
err := queue.Enqueue(1)
assert.IsNil(err)
queue.Print()
assert.Equal(5, queue.Back())
err = queue.Enqueue(2)
assert.IsNil(err)
queue.Dequeue()
queue.Dequeue()
queue.Enqueue(6)
queue.Enqueue(7)
assert.Equal(2, queue.Back())
queue.Print()
assert.Equal(7, queue.Back())
val, _ := queue.Dequeue()
assert.Equal(1, *val)
err = queue.Enqueue(3)
assert.IsNil(err)
assert.Equal(3, queue.Back())
}
func TestCircularQueue_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
queue := NewCircularQueue[int](2)
queue.Enqueue(1)
err := queue.Enqueue(1)
assert.IsNil(err)
assert.Equal(true, queue.Contain(1))
assert.Equal(false, queue.Contain(2))
}
func TestCircularQueue_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Clear")
queue := NewCircularQueue[int](3)
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Size())
queue.Enqueue(1)
err := queue.Enqueue(1)
assert.IsNil(err)
assert.Equal(false, queue.IsEmpty())
assert.Equal(1, queue.Size())
@@ -125,24 +144,16 @@ func TestCircularQueue_Clear(t *testing.T) {
}
func TestCircularQueue_Data(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Data")
queue := NewCircularQueue[int](6)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
queue := NewCircularQueue[int](3)
err := queue.Enqueue(1)
assert.IsNil(err)
queue.Print()
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
queue.Dequeue()
queue.Dequeue()
queue.Enqueue(6)
queue.Enqueue(7)
queue.Print()
assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data())
err = queue.Enqueue(2)
assert.IsNil(err)
assert.Equal([]int{1, 2}, queue.Data())
}

View File

@@ -1,3 +1,8 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure.
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
package datastructure
import (

View File

@@ -7,6 +7,8 @@ import (
)
func TestLinkedQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Enqueue")
queue := NewLinkedQueue[int]()
@@ -14,13 +16,13 @@ func TestLinkedQueue_Enqueue(t *testing.T) {
queue.Enqueue(2)
queue.Enqueue(3)
queue.Print()
assert.Equal([]int{1, 2, 3}, queue.Data())
assert.Equal(3, queue.Size())
}
func TestLinkedQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_DeQueue")
queue := NewLinkedQueue[int]()
@@ -37,6 +39,8 @@ func TestLinkedQueue_Dequeue(t *testing.T) {
}
func TestLinkedQueue_Front(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Front")
queue := NewLinkedQueue[int]()
@@ -53,6 +57,8 @@ func TestLinkedQueue_Front(t *testing.T) {
}
func TestLinkedQueue_Back(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
queue := NewLinkedQueue[int]()
@@ -69,6 +75,8 @@ func TestLinkedQueue_Back(t *testing.T) {
}
func TestLinkedQueue_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
queue := NewLinkedQueue[int]()
@@ -84,10 +92,11 @@ func TestLinkedQueue_Clear(t *testing.T) {
}
func TestLinkedQueue_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Contain")
queue := NewLinkedQueue[int]()
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)

View File

@@ -1,3 +1,8 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure.
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
package datastructure
import (

View File

@@ -20,45 +20,55 @@ func (c *intComparator) Compare(v1, v2 any) int {
return 0
}
func TestPriorityQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
comparator := &intComparator{}
pq := NewPriorityQueue[int](10, comparator)
pq := NewPriorityQueue[int](3, comparator)
assert.Equal(true, pq.IsEmpty())
assert.Equal(false, pq.IsFull())
for i := 1; i < 11; i++ {
pq.Enqueue(i)
}
err := pq.Enqueue(1)
assert.IsNil(err)
err = pq.Enqueue(2)
assert.IsNil(err)
err = pq.Enqueue(3)
assert.IsNil(err)
assert.Equal(true, pq.IsFull())
queueData := pq.Data()
assert.Equal([]int{10, 9, 6, 7, 8, 2, 5, 1, 4, 3}, queueData)
assert.Equal([]int{3, 1, 2}, queueData)
}
func TestPriorityQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
comparator := &intComparator{}
pq := NewPriorityQueue[int](10, comparator)
pq := NewPriorityQueue[int](3, comparator)
_, ok := pq.Dequeue()
assert.Equal(false, ok)
for i := 1; i < 11; i++ {
pq.Enqueue(i)
}
err := pq.Enqueue(1)
assert.IsNil(err)
assert.Equal(10, pq.Size())
err = pq.Enqueue(2)
assert.IsNil(err)
err = pq.Enqueue(3)
assert.IsNil(err)
assert.Equal(3, pq.Size())
val, ok := pq.Dequeue()
assert.Equal(true, ok)
assert.Equal(10, val)
assert.Equal([]int{9, 8, 6, 7, 3, 2, 5, 1, 4}, pq.Data())
assert.Equal(9, pq.Size())
assert.Equal(3, val)
}

View File

@@ -1,25 +1,66 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Set is a data container, like slice, but element of set is not duplicate.
package datastructure
// Set is a data container, like slice, but element of set is not duplicate
type Set[T comparable] map[T]bool
// Set is a data container, like slice, but element of set is not duplicate.
type Set[T comparable] map[T]struct{}
// NewSet return a instance of set
func NewSet[T comparable](values ...T) Set[T] {
func NewSet[T comparable](items ...T) Set[T] {
set := make(Set[T])
set.Add(values...)
set.Add(items...)
return set
}
// Add value to set
func (s Set[T]) Add(values ...T) {
for _, v := range values {
s[v] = true
// NewSetFromSlice create a set from slice
func NewSetFromSlice[T comparable](items []T) Set[T] {
set := make(Set[T])
for _, item := range items {
set.Add(item)
}
return set
}
// Add items to set
func (s Set[T]) Add(items ...T) {
for _, v := range items {
s[v] = struct{}{}
}
}
// Contain checks if set contains value or not
func (s Set[T]) Contain(value T) bool {
_, ok := s[value]
// AddIfNotExist checks if item exists in the set,
// it adds the item to set and returns true if it does not exist in the set,
// or else it does nothing and returns false.
func (s Set[T]) AddIfNotExist(item T) bool {
if !s.Contain(item) {
if _, ok := s[item]; !ok {
s[item] = struct{}{}
return true
}
}
return false
}
// AddIfNotExistBy checks if item exists in the set and pass the `checker` function
// it adds the item to set and returns true if it does not exists in the set and
// function `checker` returns true, or else it does nothing and returns false.
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool {
if !s.Contain(item) {
if checker(item) {
if _, ok := s[item]; !ok {
s[item] = struct{}{}
return true
}
}
}
return false
}
// Contain checks if set contains item or not
func (s Set[T]) Contain(item T) bool {
_, ok := s[item]
return ok
}
@@ -41,9 +82,9 @@ func (s Set[T]) Clone() Set[T] {
return set
}
// Delete value of set
func (s Set[T]) Delete(values ...T) {
for _, v := range values {
// Delete item of set
func (s Set[T]) Delete(items ...T) {
for _, v := range items {
delete(s, v)
}
}
@@ -58,7 +99,7 @@ func (s Set[T]) Equal(other Set[T]) bool {
}
// Iterate call function by every element of set
func (s Set[T]) Iterate(fn func(value T)) {
func (s Set[T]) Iterate(fn func(item T)) {
for v := range s {
fn(v)
}
@@ -76,13 +117,13 @@ func (s Set[T]) Size() int {
// Values return all values of set
func (s Set[T]) Values() []T {
values := make([]T, 0, 0)
result := make([]T, 0, len(s))
s.Iterate(func(value T) {
values = append(values, value)
result = append(result, value)
})
return values
return result
}
// Union creates a new set contain all element of set s and other
@@ -134,3 +175,25 @@ func (s Set[T]) Minus(comparedSet Set[T]) Set[T] {
return set
}
// EachWithBreak iterates over elements of a set and invokes function for each element,
// when iteratee return false, will break the for each loop.
func (s Set[T]) EachWithBreak(iteratee func(item T) bool) {
for _, v := range s.Values() {
if !iteratee(v) {
break
}
}
}
// Pop delete the top element of set then return it, if set is empty, return nil-value of T and false.
func (s Set[T]) Pop() (v T, ok bool) {
if len(s) > 0 {
items := s.Values()
item := items[len(s)-1]
delete(s, item)
return item, true
}
return v, false
}

View File

@@ -6,18 +6,73 @@ import (
"github.com/duke-git/lancet/v2/internal"
)
func TestSet_NewSetFromSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_NewSetFromSlice")
s1 := NewSetFromSlice([]int{1, 2, 2, 3})
assert.Equal(3, s1.Size())
assert.Equal(true, s1.Contain(1))
assert.Equal(true, s1.Contain(2))
assert.Equal(true, s1.Contain(3))
s2 := NewSetFromSlice([]int{})
assert.Equal(0, s2.Size())
}
func TestSet_Add(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Add")
set := NewSet[int]()
set.Add(1, 2, 3)
expected := NewSet(1, 2, 3)
cmpSet := NewSet(1, 2, 3)
assert.Equal(true, set.Equal(expected))
assert.Equal(true, set.Equal(cmpSet))
}
func TestSet_AddIfNotExist(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_AddIfNotExist")
set := NewSet[int]()
set.Add(1, 2, 3)
assert.Equal(false, set.AddIfNotExist(1))
assert.Equal(true, set.AddIfNotExist(4))
assert.Equal(NewSet(1, 2, 3, 4), set)
}
func TestSet_AddIfNotExistBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_AddIfNotExistBy")
set := NewSet[int]()
set.Add(1, 2)
ok := set.AddIfNotExistBy(3, func(val int) bool {
return val%2 != 0
})
notOk := set.AddIfNotExistBy(4, func(val int) bool {
return val%2 != 0
})
assert.Equal(true, ok)
assert.Equal(false, notOk)
assert.Equal(true, set.Contain(3))
assert.Equal(false, set.Contain(4))
}
func TestSet_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Contain")
set := NewSet[int]()
@@ -28,6 +83,8 @@ func TestSet_Contain(t *testing.T) {
}
func TestSet_ContainAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_ContainAll")
set1 := NewSet(1, 2, 3)
@@ -39,6 +96,8 @@ func TestSet_ContainAll(t *testing.T) {
}
func TestSet_Clone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Clone")
set1 := NewSet(1, 2, 3)
@@ -49,18 +108,20 @@ func TestSet_Clone(t *testing.T) {
}
func TestSet_Delete(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Delete")
set := NewSet[int]()
set.Add(1, 2, 3)
set.Delete(3)
expected := NewSet(1, 2)
assert.Equal(true, set.Equal(expected))
assert.Equal(true, set.Equal(NewSet(1, 2)))
}
func TestSet_Equal(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Equal")
set1 := NewSet(1, 2, 3)
@@ -72,6 +133,8 @@ func TestSet_Equal(t *testing.T) {
}
func TestSet_Iterate(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Iterate")
set := NewSet(1, 2, 3)
@@ -84,6 +147,8 @@ func TestSet_Iterate(t *testing.T) {
}
func TestSet_IsEmpty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_IsEmpty")
set := NewSet[int]()
@@ -91,6 +156,8 @@ func TestSet_IsEmpty(t *testing.T) {
}
func TestSet_Size(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Size")
set := NewSet(1, 2, 3)
@@ -98,6 +165,8 @@ func TestSet_Size(t *testing.T) {
}
func TestSet_Values(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Values")
set := NewSet(1, 2, 3)
@@ -107,28 +176,33 @@ func TestSet_Values(t *testing.T) {
}
func TestSet_Union(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Union")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
expected := NewSet(1, 2, 3, 4, 5)
unionSet := set1.Union(set2)
assert.Equal(expected, unionSet)
assert.Equal(NewSet(1, 2, 3, 4, 5), unionSet)
}
func TestSet_Intersection(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Intersection")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
expected := NewSet(2, 3)
intersectionSet := set1.Intersection(set2)
assert.Equal(expected, intersectionSet)
assert.Equal(NewSet(2, 3), intersectionSet)
}
func TestSet_SymmetricDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_SymmetricDifference")
set1 := NewSet(1, 2, 3)
@@ -138,6 +212,8 @@ func TestSet_SymmetricDifference(t *testing.T) {
}
func TestSet_Minus(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Minus")
set1 := NewSet(1, 2, 3)
@@ -147,3 +223,40 @@ func TestSet_Minus(t *testing.T) {
assert.Equal(NewSet(1), set1.Minus(set2))
assert.Equal(NewSet(4, 5), set2.Minus(set3))
}
func TestEachWithBreak(t *testing.T) {
// s := NewSet(1, 2, 3, 4, 5)
// var sum int
// s.EachWithBreak(func(n int) bool {
// if n > 3 {
// return false
// }
// sum += n
// return true
// })
// assert := internal.NewAssert(t, "TestEachWithBreak")
// assert.Equal(6, sum)
}
// func TestPop(t *testing.T) {
// assert := internal.NewAssert(t, "TestPop")
// s := NewSet[int]()
// val, ok := s.Pop()
// assert.Equal(0, val)
// assert.Equal(false, ok)
// s.Add(1)
// s.Add(2)
// s.Add(3)
// // s = NewSet(1, 2, 3, 4, 5)
// val, ok = s.Pop()
// assert.Equal(3, val)
// assert.Equal(true, ok)
// }

View File

@@ -1,3 +1,7 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Stack structure contains ArrayStack and LinkedStack.
package datastructure
import "errors"

View File

@@ -7,6 +7,8 @@ import (
)
func TestArrayStack_Push(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Push")
stack := NewArrayStack[int]()
@@ -14,15 +16,16 @@ func TestArrayStack_Push(t *testing.T) {
stack.Push(2)
stack.Push(3)
expected := []int{3, 2, 1}
values := stack.Data()
length := stack.Size()
assert.Equal(expected, values)
assert.Equal([]int{3, 2, 1}, values)
assert.Equal(3, length)
}
func TestArrayStack_Pop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Pop")
stack := NewArrayStack[int]()
@@ -37,11 +40,12 @@ func TestArrayStack_Pop(t *testing.T) {
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{2, 1}
assert.Equal(expected, stack.Data())
assert.Equal([]int{2, 1}, stack.Data())
}
func TestArrayStack_Peak(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Peak")
stack := NewArrayStack[int]()
@@ -56,11 +60,12 @@ func TestArrayStack_Peak(t *testing.T) {
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{3, 2, 1}
assert.Equal(expected, stack.Data())
assert.Equal([]int{3, 2, 1}, stack.Data())
}
func TestArrayStack_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Clear")
stack := NewArrayStack[int]()

View File

@@ -1,3 +1,7 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. Stack structure contains ArrayStack and LinkedStack.
package datastructure
import (

View File

@@ -7,6 +7,8 @@ import (
)
func TestLinkedStack_Push(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Push")
stack := NewLinkedStack[int]()
@@ -14,17 +16,16 @@ func TestLinkedStack_Push(t *testing.T) {
stack.Push(2)
stack.Push(3)
stack.Print()
expected := []int{3, 2, 1}
values := stack.Data()
size := stack.Size()
assert.Equal(expected, values)
assert.Equal([]int{3, 2, 1}, values)
assert.Equal(3, size)
}
func TestLinkedStack_Pop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Pop")
stack := NewLinkedStack[int]()
@@ -39,12 +40,13 @@ func TestLinkedStack_Pop(t *testing.T) {
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{2, 1}
stack.Print()
assert.Equal(expected, stack.Data())
assert.Equal([]int{2, 1}, stack.Data())
}
func TestLinkedStack_Peak(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Peak")
stack := NewLinkedStack[int]()
@@ -59,11 +61,12 @@ func TestLinkedStack_Peak(t *testing.T) {
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{3, 2, 1}
assert.Equal(expected, stack.Data())
assert.Equal([]int{3, 2, 1}, stack.Data())
}
func TestLinkedStack_Empty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Empty")
stack := NewLinkedStack[int]()

View File

@@ -1,3 +1,7 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure contains some data structure. BSTree is binary search tree.
package datastructure
import (
@@ -84,20 +88,20 @@ func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool {
func hasSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T],
comparator lancetconstraints.Comparator) bool {
res := false
result := false
if superTreeRoot != nil && subTreeRoot != nil {
if comparator.Compare(superTreeRoot.Value, subTreeRoot.Value) == 0 {
res = isSubTree(superTreeRoot, subTreeRoot, comparator)
result = isSubTree(superTreeRoot, subTreeRoot, comparator)
}
if !res {
res = hasSubTree(superTreeRoot.Left, subTreeRoot, comparator)
if !result {
result = hasSubTree(superTreeRoot.Left, subTreeRoot, comparator)
}
if !res {
res = hasSubTree(superTreeRoot.Right, subTreeRoot, comparator)
if !result {
result = hasSubTree(superTreeRoot.Right, subTreeRoot, comparator)
}
}
return res
return result
}
// Print the bstree structure

View File

@@ -20,18 +20,9 @@ func (c *intComparator) Compare(v1, v2 any) int {
return 0
}
func TestBSTree_Insert(t *testing.T) {
bstree := NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
bstree.Print()
}
func TestBSTree_PreOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_PreOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
@@ -42,11 +33,12 @@ func TestBSTree_PreOrderTraverse(t *testing.T) {
bstree.Insert(4)
acturl := bstree.PreOrderTraverse()
t.Log(acturl)
assert.Equal([]int{6, 5, 2, 4, 7}, acturl)
}
func TestBSTree_PostOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_PostOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
@@ -57,11 +49,12 @@ func TestBSTree_PostOrderTraverse(t *testing.T) {
bstree.Insert(4)
acturl := bstree.PostOrderTraverse()
t.Log(acturl)
assert.Equal([]int{5, 2, 4, 7, 6}, acturl)
}
func TestBSTree_InOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_InOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
@@ -72,11 +65,12 @@ func TestBSTree_InOrderTraverse(t *testing.T) {
bstree.Insert(4)
acturl := bstree.InOrderTraverse()
t.Log(acturl)
assert.Equal([]int{2, 4, 5, 6, 7}, acturl)
}
func TestBSTree_LevelOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_LevelOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
@@ -86,14 +80,13 @@ func TestBSTree_LevelOrderTraverse(t *testing.T) {
bstree.Insert(2)
bstree.Insert(4)
bstree.Print()
acturl := bstree.LevelOrderTraverse()
t.Log(acturl)
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
}
func TestBSTree_Delete(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_Delete")
bstree := NewBSTree(6, &intComparator{})
@@ -103,23 +96,21 @@ func TestBSTree_Delete(t *testing.T) {
bstree.Insert(2)
bstree.Insert(4)
bstree.Print()
bstree.Delete(4)
bstree.Print()
acturl1 := bstree.InOrderTraverse()
t.Log(acturl1)
assert.Equal([]int{2, 5, 6, 7}, acturl1)
//todo
// bstree.DeletetNode(6, comparator)
// bstree.Print()
// acturl2 := bstree.InOrderTraverse()
// t.Log(acturl2)
// assert.Equal([]int{2, 5, 7}, acturl2)
}
func TestBSTree_Depth(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_Depth")
bstree := NewBSTree(6, &intComparator{})
@@ -129,12 +120,12 @@ func TestBSTree_Depth(t *testing.T) {
bstree.Insert(2)
bstree.Insert(4)
bstree.Print()
assert.Equal(bstree.Depth(), 4)
}
func TestBSTree_IsSubTree(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_IsSubTree")
superTree := NewBSTree(8, &intComparator{})
@@ -150,8 +141,6 @@ func TestBSTree_IsSubTree(t *testing.T) {
subTree.Insert(4)
subTree.Insert(6)
subTree.Print()
assert.Equal(true, superTree.HasSubTree(subTree))
assert.Equal(false, subTree.HasSubTree(superTree))
}

View File

@@ -38,35 +38,35 @@ func inOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
return data
}
func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
// func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
// if node == nil {
// return
// }
fmt.Printf("%v, ", node.Value)
preOrderPrint(node.Left)
preOrderPrint(node.Right)
}
// fmt.Printf("%v, ", node.Value)
// preOrderPrint(node.Left)
// preOrderPrint(node.Right)
// }
func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
// func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
// if node == nil {
// return
// }
preOrderPrint(node.Left)
preOrderPrint(node.Right)
fmt.Printf("%v, ", node.Value)
}
// postOrderPrint(node.Left)
// postOrderPrint(node.Right)
// fmt.Printf("%v, ", node.Value)
// }
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
// func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
// if node == nil {
// return
// }
inOrderPrint(node.Left)
fmt.Printf("%v, ", node.Value)
inOrderPrint(node.Right)
}
// inOrderPrint(node.Left)
// fmt.Printf("%v, ", node.Value)
// inOrderPrint(node.Right)
// }
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
var q []*datastructure.TreeNode[T] // queue
@@ -226,8 +226,8 @@ func isSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T], com
if comparator.Compare(superTreeRoot.Value, subTreeRoot.Value) != 0 {
return false
}
res := isSubTree(superTreeRoot.Left, subTreeRoot.Left, comparator) && isSubTree(superTreeRoot.Right, subTreeRoot.Right, comparator)
return res
result := isSubTree(superTreeRoot.Left, subTreeRoot.Left, comparator) && isSubTree(superTreeRoot.Right, subTreeRoot.Right, comparator)
return result
}
func max(a, b int) int {

View File

@@ -9,17 +9,20 @@ type theTime struct {
unix int64
}
// NewUnixNow return unix timestamp of current time
// NewUnixNow return unix timestamp of current time.
// Play: https://go.dev/play/p/U4PPx-9D0oz
func NewUnixNow() *theTime {
return &theTime{unix: time.Now().Unix()}
}
// NewUnix return unix timestamp of specified time
// NewUnix return unix timestamp of specified time.
// Play: https://go.dev/play/p/psoSuh_kLRt
func NewUnix(unix int64) *theTime {
return &theTime{unix: unix}
}
// NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss"
// NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss".
// Play: https://go.dev/play/p/VkW08ZOaXPZ
func NewFormat(t string) (*theTime, error) {
timeLayout := "2006-01-02 15:04:05"
loc := time.FixedZone("CST", 8*3600)
@@ -30,7 +33,8 @@ func NewFormat(t string) (*theTime, error) {
return &theTime{unix: tt.Unix()}, nil
}
// NewISO8601 return unix timestamp of specified iso8601 time string
// NewISO8601 return unix timestamp of specified iso8601 time string.
// Play: https://go.dev/play/p/mkhOHQkdeA2
func NewISO8601(iso8601 string) (*theTime, error) {
t, err := time.ParseInLocation(time.RFC3339, iso8601, time.UTC)
if err != nil {
@@ -39,22 +43,26 @@ func NewISO8601(iso8601 string) (*theTime, error) {
return &theTime{unix: t.Unix()}, nil
}
// ToUnix return unix timestamp
// ToUnix return unix timestamp.
// Play: https://go.dev/play/p/_LUiwAdocjy
func (t *theTime) ToUnix() int64 {
return t.unix
}
// ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time
// ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time.
// Play: https://go.dev/play/p/VkW08ZOaXPZ
func (t *theTime) ToFormat() string {
return time.Unix(t.unix, 0).Format("2006-01-02 15:04:05")
}
// ToFormatForTpl return the time string which format is specified tpl
// ToFormatForTpl return the time string which format is specified tpl.
// Play: https://go.dev/play/p/nyXxXcQJ8L5
func (t *theTime) ToFormatForTpl(tpl string) string {
return time.Unix(t.unix, 0).Format(tpl)
}
// ToFormatForTpl return iso8601 time string
// ToFormatForTpl return iso8601 time string.
// Play: https://go.dev/play/p/mkhOHQkdeA2
func (t *theTime) ToIso8601() string {
return time.Unix(t.unix, 0).Format(time.RFC3339)
}

View File

@@ -7,6 +7,8 @@ import (
)
func TestToUnix(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToUnix")
tm1 := NewUnixNow()
@@ -17,37 +19,37 @@ func TestToUnix(t *testing.T) {
}
func TestToFormat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToFormat")
_, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err := NewFormat("2022-03-18 17:04:05")
t.Log("TestToFormat", tm.ToFormat())
assert.IsNil(err)
t.Log("ToFormat -> ", tm.ToFormat())
}
func TestToFormatForTpl(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToFormatForTpl")
_, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err := NewFormat("2022-03-18 17:04:05")
t.Log("TestToFormatForTpl", tm.ToFormatForTpl("2006/01/02 15:04:05"))
assert.IsNil(err)
t.Log("ToFormatForTpl -> ", tm.ToFormatForTpl("2006/01/02 15:04:05"))
}
func TestToIso8601(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToIso8601")
_, err := NewISO8601("2022-03-18 17:04:05")
assert.IsNotNil(err)
tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
t.Log("TestToIso8601", tm.ToIso8601())
assert.IsNil(err)
t.Log("ToIso8601 -> ", tm.ToIso8601())
}

View File

@@ -3,29 +3,34 @@
// Package datetime implements some functions to format date and time.
// Note:
// 1. `format` param in FormatTimeToStr function should be as flow:
//"yyyy-mm-dd hh:mm:ss"
//"yyyy-mm-dd hh:mm"
//"yyyy-mm-dd hh"
//"yyyy-mm-dd"
//"yyyy-mm"
//"mm-dd"
//"dd-mm-yy hh:mm:ss"
//"yyyy/mm/dd hh:mm:ss"
//"yyyy/mm/dd hh:mm"
//"yyyy/mm/dd hh"
//"yyyy/mm/dd"
//"yyyy/mm"
//"mm/dd"
//"dd/mm/yy hh:mm:ss"
//"yyyy"
//"mm"
//"hh:mm:ss"
//"mm:ss"
// 1. `format` param in FormatTimeToStr function should be as flow (case no sensitive):
// "yyyy-mm-dd hh:mm:ss"
// "yyyy-mm-dd hh:mm"
// "yyyy-mm-dd hh"
// "yyyy-mm-dd"
// "yyyy-mm"
// "mm-dd"
// "dd-mm-yy hh:mm:ss"
// "yyyy/mm/dd hh:mm:ss"
// "yyyy/mm/dd hh:mm"
// "yyyy/mm/dd hh"
// "yyyy/mm/dd"
// "yyyy/mm"
// "mm/dd"
// "dd/mm/yy hh:mm:ss"
// "yyyymmdd"
// "mmddyy"
// "yyyy"
// "yy"
// "mm"
// "hh:mm:ss"
// "hh:mm"
// "mm:ss"
package datetime
import (
"fmt"
"strings"
"time"
)
@@ -35,7 +40,7 @@ func init() {
timeFormat = map[string]string{
"yyyy-mm-dd hh:mm:ss": "2006-01-02 15:04:05",
"yyyy-mm-dd hh:mm": "2006-01-02 15:04",
"yyyy-mm-dd hh": "2006-01-02 15:04",
"yyyy-mm-dd hh": "2006-01-02 15",
"yyyy-mm-dd": "2006-01-02",
"yyyy-mm": "2006-01",
"mm-dd": "01-02",
@@ -47,136 +52,332 @@ func init() {
"yyyy/mm": "2006/01",
"mm/dd": "01/02",
"dd/mm/yy hh:mm:ss": "02/01/06 15:04:05",
"yyyymmdd": "20060102",
"mmddyy": "010206",
"yyyy": "2006",
"yy": "06",
"mm": "01",
"hh:mm:ss": "15:04:05",
"hh:mm": "15:04",
"mm:ss": "04:05",
}
}
// AddMinute add or sub minute to the time
// AddMinute add or sub minute to the time.
// Play: https://go.dev/play/p/nT1heB1KUUK
func AddMinute(t time.Time, minute int64) time.Time {
return t.Add(time.Minute * time.Duration(minute))
}
// AddHour add or sub hour to the time
// AddHour add or sub hour to the time.
// Play: https://go.dev/play/p/rcMjd7OCsi5
func AddHour(t time.Time, hour int64) time.Time {
return t.Add(time.Hour * time.Duration(hour))
}
// AddDay add or sub day to the time
// AddDay add or sub day to the time.
// Play: https://go.dev/play/p/dIGbs_uTdFa
func AddDay(t time.Time, day int64) time.Time {
return t.Add(24 * time.Hour * time.Duration(day))
}
// GetNowDate return format yyyy-mm-dd of current date
// AddYear add or sub year to the time.
// Play: https://go.dev/play/p/MqW2ujnBx10
func AddYear(t time.Time, year int64) time.Time {
return t.Add(365 * 24 * time.Hour * time.Duration(year))
}
// GetNowDate return format yyyy-mm-dd of current date.
// Play: https://go.dev/play/p/PvfkPpcpBBf
func GetNowDate() string {
return time.Now().Format("2006-01-02")
}
// GetNowTime return format hh-mm-ss of current time
// GetNowTime return format hh-mm-ss of current time.
// Play: https://go.dev/play/p/l7BNxCkTmJS
func GetNowTime() string {
return time.Now().Format("15:04:05")
}
// GetNowDateTime return format yyyy-mm-dd hh-mm-ss of current datetime
// GetNowDateTime return format yyyy-mm-dd hh-mm-ss of current datetime.
// Play: https://go.dev/play/p/pI4AqngD0al
func GetNowDateTime() string {
return time.Now().Format("2006-01-02 15:04:05")
}
// GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00)
// GetTodayStartTime return the start time of today, format: yyyy-mm-dd 00:00:00.
// Play: https://go.dev/play/p/84siyYF7t99
func GetTodayStartTime() string {
return time.Now().Format("2006-01-02") + " 00:00:00"
}
// GetTodayEndTime return the end time of today, format: yyyy-mm-dd 23:59:59.
// Play: https://go.dev/play/p/jjrLnfoqgn3
func GetTodayEndTime() string {
return time.Now().Format("2006-01-02") + " 23:59:59"
}
// GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00).
// Play: https://go.dev/play/p/QmL2oIaGE3q
func GetZeroHourTimestamp() int64 {
ts := time.Now().Format("2006-01-02")
t, _ := time.Parse("2006-01-02", ts)
return t.UTC().Unix() - 8*3600
}
// GetNightTimestamp return timestamp of zero hour (timestamp of 23:59)
// GetNightTimestamp return timestamp of zero hour (timestamp of 23:59).
// Play: https://go.dev/play/p/UolysR3MYP1
func GetNightTimestamp() int64 {
return GetZeroHourTimestamp() + 86400 - 1
}
// FormatTimeToStr convert time to string
func FormatTimeToStr(t time.Time, format string) string {
return t.Format(timeFormat[format])
}
// FormatStrToTime convert string to time
func FormatStrToTime(str, format string) (time.Time, error) {
v, ok := timeFormat[format]
// FormatTimeToStr convert time to string.
// Play: https://go.dev/play/p/_Ia7M8H_OvE
func FormatTimeToStr(t time.Time, format string, timezone ...string) string {
tf, ok := timeFormat[strings.ToLower(format)]
if !ok {
return time.Time{}, fmt.Errorf("format %s not found", format)
return ""
}
return time.Parse(v, str)
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return ""
}
return t.In(loc).Format(tf)
}
return t.Format(tf)
}
// BeginOfMinute return beginning minute time of day
// FormatStrToTime convert string to time.
// Play: https://go.dev/play/p/1h9FwdU8ql4
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error) {
tf, ok := timeFormat[strings.ToLower(format)]
if !ok {
return time.Time{}, fmt.Errorf("format %s not support", format)
}
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return time.Time{}, err
}
return time.ParseInLocation(tf, str, loc)
}
return time.Parse(tf, str)
}
// BeginOfMinute return beginning minute time of day.
// Play: https://go.dev/play/p/ieOLVJ9CiFT
func BeginOfMinute(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), t.Minute(), 0, 0, t.Location())
}
// EndOfMinute return end minute time of day
// EndOfMinute return end minute time of day.
// Play: https://go.dev/play/p/yrL5wGzPj4z
func EndOfMinute(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), t.Minute(), 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfHour return beginning hour time of day
// BeginOfHour return beginning hour time of day.
// Play: https://go.dev/play/p/GhdGFnDWpYs
func BeginOfHour(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), 0, 0, 0, t.Location())
}
// EndOfHour return end hour time of day
// EndOfHour return end hour time of day.
// Play: https://go.dev/play/p/6ce3j_6cVqN
func EndOfHour(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), 59, 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfDay return beginning hour time of day
// BeginOfDay return beginning hour time of day.
// Play: https://go.dev/play/p/94m_UT6cWs9
func BeginOfDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}
// EndOfDay return end time of day
// EndOfDay return end time of day.
// Play: https://go.dev/play/p/eMBOvmq5Ih1
func EndOfDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfWeek return beginning week, week begin from Sunday
func BeginOfWeek(t time.Time) time.Time {
y, m, d := t.AddDate(0, 0, 0-int(BeginOfDay(t).Weekday())).Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
// BeginOfWeek return beginning week, default week begin from Sunday.
// Play: https://go.dev/play/p/ynjoJPz7VNV
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time {
var beginFromWeekday = time.Sunday
if len(beginFrom) > 0 {
beginFromWeekday = beginFrom[0]
}
y, m, d := t.AddDate(0, 0, int(beginFromWeekday-t.Weekday())).Date()
beginOfWeek := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
if beginOfWeek.After(t) {
return beginOfWeek.AddDate(0, 0, -7)
}
return beginOfWeek
}
// EndOfWeek return end week time, week end with Saturday
func EndOfWeek(t time.Time) time.Time {
y, m, d := BeginOfWeek(t).AddDate(0, 0, 7).Add(-time.Nanosecond).Date()
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
// EndOfWeek return end week time, default week end with Saturday.
// Play: https://go.dev/play/p/i08qKXD9flf
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
var endWithWeekday = time.Saturday
if len(endWith) > 0 {
endWithWeekday = endWith[0]
}
y, m, d := t.AddDate(0, 0, int(endWithWeekday-t.Weekday())).Date()
var endWithWeek = time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
if endWithWeek.Before(t) {
endWithWeek = endWithWeek.AddDate(0, 0, 7)
}
return endWithWeek
}
// BeginOfMonth return beginning of month
// BeginOfMonth return beginning of month.
// Play: https://go.dev/play/p/bWXVFsmmzwL
func BeginOfMonth(t time.Time) time.Time {
y, m, _ := t.Date()
return time.Date(y, m, 1, 0, 0, 0, 0, t.Location())
}
// EndOfMonth return end of month
// EndOfMonth return end of month.
// Play: https://go.dev/play/p/_GWh10B3Nqi
func EndOfMonth(t time.Time) time.Time {
return BeginOfMonth(t).AddDate(0, 1, 0).Add(-time.Nanosecond)
}
// BeginOfYear return beginning of year
// BeginOfYear return the date time at the begin of year.
// Play: https://go.dev/play/p/i326DSwLnV8
func BeginOfYear(t time.Time) time.Time {
y, _, _ := t.Date()
return time.Date(y, time.January, 1, 0, 0, 0, 0, t.Location())
}
// EndOfYear return end of year
// EndOfYear return the date time at the end of year.
// Play: https://go.dev/play/p/G01cKlMCvNm
func EndOfYear(t time.Time) time.Time {
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
}
// IsLeapYear check if param year is leap year or not.
// Play: https://go.dev/play/p/xS1eS2ejGew
func IsLeapYear(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
// BetweenSeconds returns the number of seconds between two times.
// Play: https://go.dev/play/p/n3YDRyfyXJu
func BetweenSeconds(t1 time.Time, t2 time.Time) int64 {
index := t2.Unix() - t1.Unix()
return index
}
// DayOfYear returns which day of the year the parameter date `t` is.
// Play: https://go.dev/play/p/0hjqhTwFNlH
func DayOfYear(t time.Time) int {
y, m, d := t.Date()
firstDay := time.Date(y, 1, 1, 0, 0, 0, 0, t.Location())
nowDate := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
return int(nowDate.Sub(firstDay).Hours() / 24)
}
// IsWeekend checks if passed time is weekend or not.
// Play: https://go.dev/play/p/cupRM5aZOIY
// Deprecated Use '== Weekday' instead
func IsWeekend(t time.Time) bool {
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
}
// NowDateOrTime return current datetime with specific format and timezone.
// Play: https://go.dev/play/p/EZ-begEjtT0
func NowDateOrTime(format string, timezone ...string) string {
tf, ok := timeFormat[strings.ToLower(format)]
if !ok {
return ""
}
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return ""
}
return time.Now().In(loc).Format(tf)
}
return time.Now().Format(tf)
}
// Timestamp return current second timestamp.
// Play: https://go.dev/play/p/iU5b7Vvjx6x
func Timestamp(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return t.Unix()
}
// TimestampMilli return current mill second timestamp.
// Play: https://go.dev/play/p/4gvEusOTu1T
func TimestampMilli(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)
}
// TimestampMicro return current micro second timestamp.
// Play: https://go.dev/play/p/2maANglKHQE
func TimestampMicro(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Microsecond)
}
// TimestampNano return current nano second timestamp.
// Play: https://go.dev/play/p/A9Oq_COrcCF
func TimestampNano(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return t.UnixNano()
}

View File

@@ -0,0 +1,410 @@
package datetime
import (
"fmt"
"reflect"
"time"
)
func ExampleAddDay() {
now := time.Now()
tomorrow := AddDay(now, 1)
diff1 := tomorrow.Sub(now)
yesterday := AddDay(now, -1)
diff2 := yesterday.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 24h0m0s
// -24h0m0s
}
func ExampleAddHour() {
now := time.Now()
after2Hours := AddHour(now, 2)
diff1 := after2Hours.Sub(now)
before2Hours := AddHour(now, -2)
diff2 := before2Hours.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2h0m0s
// -2h0m0s
}
func ExampleAddMinute() {
now := time.Now()
after2Minutes := AddMinute(now, 2)
diff1 := after2Minutes.Sub(now)
before2Minutes := AddMinute(now, -2)
diff2 := before2Minutes.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2m0s
// -2m0s
}
func ExampleAddYear() {
now := time.Now()
after1Year := AddYear(now, 1)
diff1 := after1Year.Sub(now)
before1Year := AddYear(now, -1)
diff2 := before1Year.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 8760h0m0s
// -8760h0m0s
}
func ExampleGetNowDate() {
result := GetNowDate()
expected := time.Now().Format("2006-01-02")
fmt.Println(result == expected)
// Output:
// true
}
func ExampleGetNowTime() {
result := GetNowTime()
expected := time.Now().Format("15:04:05")
fmt.Println(result == expected)
// Output:
// true
}
func ExampleGetNowDateTime() {
result := GetNowDateTime()
expected := time.Now().Format("2006-01-02 15:04:05")
fmt.Println(result == expected)
// Output:
// true
}
// func ExampleGetZeroHourTimestamp() {
// ts := GetZeroHourTimestamp()
// fmt.Println(ts)
// // Output:
// // 1673107200
// }
// func ExampleGetNightTimestamp() {
// ts := GetNightTimestamp()
// fmt.Println(ts)
// // Output:
// // 1673193599
// }
func ExampleFormatTimeToStr() {
datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
result1 := FormatTimeToStr(datetime, "yyyy-mm-dd hh:mm:ss")
result2 := FormatTimeToStr(datetime, "yyyy-mm-dd")
result3 := FormatTimeToStr(datetime, "dd-mm-yy hh:mm:ss")
result4 := FormatTimeToStr(datetime, "yyyy-mm-dd hh")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 2021-01-02 16:04:08
// 2021-01-02
// 02-01-21 16:04:08
// 2021-01-02 16
}
func ExampleFormatStrToTime() {
result1, _ := FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss")
result2, _ := FormatStrToTime("2021-01-02", "yyyy-mm-dd")
result3, _ := FormatStrToTime("02-01-21 16:04:08", "dd-mm-yy hh:mm:ss")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 2021-01-02 16:04:08 +0000 UTC
// 2021-01-02 00:00:00 +0000 UTC
// 2021-01-02 16:04:08 +0000 UTC
}
func ExampleBeginOfMinute() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfMinute(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:50:00 +0000 UTC
}
func ExampleEndOfMinute() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfMinute(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:50:59.999999999 +0000 UTC
}
func ExampleBeginOfHour() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfHour(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:00:00 +0000 UTC
}
func ExampleEndOfHour() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfHour(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:59:59.999999999 +0000 UTC
}
func ExampleBeginOfDay() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfDay(input)
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
}
func ExampleEndOfDay() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfDay(input)
fmt.Println(result)
// Output:
// 2023-01-08 23:59:59.999999999 +0000 UTC
}
func ExampleBeginOfWeek() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfWeek(input)
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
}
func ExampleEndOfWeek() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfWeek(input)
fmt.Println(result)
// Output:
// 2023-01-14 23:59:59.999999999 +0000 UTC
}
func ExampleBeginOfMonth() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfMonth(input)
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
}
func ExampleEndOfMonth() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfMonth(input)
fmt.Println(result)
// Output:
// 2023-01-31 23:59:59.999999999 +0000 UTC
}
func ExampleBeginOfYear() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfYear(input)
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
}
func ExampleEndOfYear() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfYear(input)
fmt.Println(result)
// Output:
// 2023-12-31 23:59:59.999999999 +0000 UTC
}
func ExampleNewUnix() {
result := NewUnix(1647597438)
fmt.Println(result)
// Output:
// &{1647597438}
}
func ExampleNewUnixNow() {
tm1 := NewUnixNow()
unixTimestamp := tm1.ToUnix()
tm2 := NewUnix(unixTimestamp)
fmt.Println(reflect.DeepEqual(tm1, tm2))
// Output:
// true
}
// func ExampleNewFormat() {
// tm, err := NewFormat("2022-03-18 17:04:05")
// if err != nil {
// return
// }
// result := tm.ToFormat()
// fmt.Println(result)
// // Output:
// // 2022-03-18 17:04:05
// }
// func ExampleNewISO8601() {
// tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
// if err != nil {
// return
// }
// result := tm.ToIso8601()
// fmt.Println(result)
// // Output:
// // 2006-01-02T23:04:05+08:00
// }
func ExampleIsLeapYear() {
result1 := IsLeapYear(2000)
result2 := IsLeapYear(2001)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
func ExampleBetweenSeconds() {
today := time.Now()
tomorrow := AddDay(today, 1)
yesterday := AddDay(today, -1)
result1 := BetweenSeconds(today, tomorrow)
result2 := BetweenSeconds(today, yesterday)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 86400
// -86400
}
func ExampleDayOfYear() {
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
result1 := DayOfYear(date1)
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
result2 := DayOfYear(date2)
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
result3 := DayOfYear(date3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 31
// 1
// 0
}
func ExampleIsWeekend() {
date1 := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
date2 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
date3 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
result1 := IsWeekend(date1)
result2 := IsWeekend(date2)
result3 := IsWeekend(date3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}

View File

@@ -7,7 +7,40 @@ import (
"github.com/duke-git/lancet/v2/internal"
)
func TestAddYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
after2Years := AddYear(now, 1)
diff1 := after2Years.Sub(now)
assert.Equal(float64(8760), diff1.Hours())
before2Years := AddYear(now, -1)
diff2 := before2Years.Sub(now)
assert.Equal(float64(-8760), diff2.Hours())
}
func TestBetweenSeconds(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBetweenSeconds")
today := time.Now()
tomorrow := AddDay(today, 1)
yesterday := AddDay(today, -1)
result1 := BetweenSeconds(today, tomorrow)
result2 := BetweenSeconds(today, yesterday)
assert.Equal(int64(86400), result1)
assert.Equal(int64(-86400), result2)
}
func TestAddDay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
@@ -21,6 +54,8 @@ func TestAddDay(t *testing.T) {
}
func TestAddHour(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddHour")
now := time.Now()
@@ -34,6 +69,8 @@ func TestAddHour(t *testing.T) {
}
func TestAddMinute(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddMinute")
now := time.Now()
@@ -47,45 +84,77 @@ func TestAddMinute(t *testing.T) {
}
func TestGetNowDate(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetNowDate")
expected := time.Now().Format("2006-01-02")
assert.Equal(expected, GetNowDate())
}
func TestGetNotTime(t *testing.T) {
assert := internal.NewAssert(t, "TestGetNotTime")
func TestGetNowTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetNowTime")
expected := time.Now().Format("15:04:05")
assert.Equal(expected, GetNowTime())
}
func TestGetNowDateTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetNowDateTime")
expected := time.Now().Format("2006-01-02 15:04:05")
assert.Equal(expected, GetNowDateTime())
}
func TestGetTodayStartTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetTodayStartTime")
expected := time.Now().Format("2006-01-02") + " 00:00:00"
assert.Equal(expected, GetTodayStartTime())
}
func TestGetTodayEndTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetTodayEndTime")
expected := time.Now().Format("2006-01-02") + " 23:59:59"
assert.Equal(expected, GetTodayEndTime())
}
func TestFormatTimeToStr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFormatTimeToStr")
datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
cases := []string{
"yyyy-mm-dd hh:mm:ss", "yyyy-mm-dd",
"dd-mm-yy hh:mm:ss", "yyyy/mm/dd hh:mm:ss",
"hh:mm:ss", "yyyy/mm"}
"hh:mm:ss", "yyyy/mm",
"yyyy-mm-dd hh",
}
expected := []string{
"2021-01-02 16:04:08", "2021-01-02",
"02-01-21 16:04:08", "2021/01/02 16:04:08",
"16:04:08", "2021/01"}
"16:04:08", "2021/01",
"2021-01-02 16",
}
for i := 0; i < len(cases); i++ {
actual := FormatTimeToStr(datetime, cases[i])
assert.Equal(expected[i], actual)
}
ds := FormatTimeToStr(datetime, "yyyy-mm-dd hh:mm:ss", "EST")
t.Log(ds)
}
func TestFormatStrToTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFormatStrToTime")
formats := []string{
@@ -97,22 +166,28 @@ func TestFormatStrToTime(t *testing.T) {
"dd-mm-yy hh:mm:ss", "yyyy/mm/dd hh:mm:ss",
"yyyy/mm"}
datetimeStr := []string{
expected := []string{
"2021-01-02 16:04:08", "2021-01-02",
"02-01-21 16:04:08", "2021/01/02 16:04:08",
"2021/01"}
for i := 0; i < len(cases); i++ {
actual, err := FormatStrToTime(datetimeStr[i], cases[i])
actual, err := FormatStrToTime(expected[i], cases[i])
if err != nil {
t.Fatal(err)
}
expected, _ := time.Parse(formats[i], datetimeStr[i])
expected, _ := time.Parse(formats[i], expected[i])
assert.Equal(expected, actual)
}
estTime, err := FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss", "EST")
t.Log(estTime)
assert.IsNil(err)
}
func TestBeginOfMinute(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfMinute")
expected := time.Date(2022, 2, 15, 15, 48, 0, 0, time.Local)
@@ -123,6 +198,8 @@ func TestBeginOfMinute(t *testing.T) {
}
func TestEndOfMinute(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfMinute")
expected := time.Date(2022, 2, 15, 15, 48, 59, 999999999, time.Local)
@@ -133,6 +210,8 @@ func TestEndOfMinute(t *testing.T) {
}
func TestBeginOfHour(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfHour")
expected := time.Date(2022, 2, 15, 15, 0, 0, 0, time.Local)
@@ -143,6 +222,8 @@ func TestBeginOfHour(t *testing.T) {
}
func TestEndOfHour(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfHour")
expected := time.Date(2022, 2, 15, 15, 59, 59, 999999999, time.Local)
@@ -153,6 +234,8 @@ func TestEndOfHour(t *testing.T) {
}
func TestBeginOfDay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfDay")
expected := time.Date(2022, 2, 15, 0, 0, 0, 0, time.Local)
@@ -163,6 +246,8 @@ func TestBeginOfDay(t *testing.T) {
}
func TestEndOfDay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfDay")
expected := time.Date(2022, 2, 15, 23, 59, 59, 999999999, time.Local)
@@ -173,6 +258,8 @@ func TestEndOfDay(t *testing.T) {
}
func TestBeginOfWeek(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfWeek")
expected := time.Date(2022, 2, 13, 0, 0, 0, 0, time.Local)
@@ -183,6 +270,8 @@ func TestBeginOfWeek(t *testing.T) {
}
func TestEndOfWeek(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfWeek")
expected := time.Date(2022, 2, 19, 23, 59, 59, 999999999, time.Local)
@@ -193,6 +282,8 @@ func TestEndOfWeek(t *testing.T) {
}
func TestBeginOfMonth(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfMonth")
expected := time.Date(2022, 2, 1, 0, 0, 0, 0, time.Local)
@@ -203,6 +294,8 @@ func TestBeginOfMonth(t *testing.T) {
}
func TestEndOfMonth(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfMonth")
expected := time.Date(2022, 2, 28, 23, 59, 59, 999999999, time.Local)
@@ -213,6 +306,8 @@ func TestEndOfMonth(t *testing.T) {
}
func TestBeginOfYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfYear")
expected := time.Date(2022, 1, 1, 0, 0, 0, 0, time.Local)
@@ -223,6 +318,8 @@ func TestBeginOfYear(t *testing.T) {
}
func TestEndOfYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfYear")
expected := time.Date(2022, 12, 31, 23, 59, 59, 999999999, time.Local)
@@ -231,3 +328,85 @@ func TestEndOfYear(t *testing.T) {
assert.Equal(expected, actual)
}
func TestIsLeapYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfYear")
result1 := IsLeapYear(2000)
result2 := IsLeapYear(2001)
assert.Equal(true, result1)
assert.Equal(false, result2)
}
func TestDayOfYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDayOfYear")
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
result1 := DayOfYear(date1)
assert.Equal(31, result1)
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
result2 := DayOfYear(date2)
assert.Equal(1, result2)
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
result3 := DayOfYear(date3)
assert.Equal(0, result3)
}
func TestIsWeekend(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsWeekend")
date := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
result := IsWeekend(date)
assert.Equal(true, result)
date1 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
result1 := IsWeekend(date1)
assert.Equal(true, result1)
date2 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
result2 := IsWeekend(date2)
assert.Equal(false, result2)
}
func TestNowDateOrTime(t *testing.T) {
t.Parallel()
formats := []string{
"yyyy-mm-dd hh:mm:ss",
"yyyy-mm-dd",
"dd-mm-yy hh:mm:ss",
"yyyy/mm/dd hh:mm:ss",
"hh:mm:ss",
"yyyy/mm",
"yyyy-mm-dd hh",
}
for i := 0; i < len(formats); i++ {
result := NowDateOrTime(formats[i], "UTC")
t.Log(result)
}
}
func TestTimestamp(t *testing.T) {
t.Parallel()
ts1 := Timestamp()
t.Log(ts1)
ts2 := TimestampMilli()
t.Log(ts2)
ts3 := TimestampMicro()
t.Log(ts3)
ts4 := TimestampNano()
t.Log(ts4)
}

89
docs/.vitepress/common.ts Normal file
View File

@@ -0,0 +1,89 @@
import { defineConfig, HeadConfig } from 'vitepress'
export const META_IMAGE = '/lancet_logo.png'
export const isProduction = process.env.NETLIFY && process.env.CONTEXT === 'production'
if (process.env.NETLIFY) {
console.log('Netlify build', process.env.CONTEXT)
}
const productionHead: HeadConfig[] = [
[
'script',
{
src: 'https://unpkg.com/thesemetrics@latest',
async: '',
type: 'text/javascript',
},
],
]
const rControl = /[\u0000-\u001f]/g
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g
const rCombining = /[\u0300-\u036F]/g
/**
* Default slugification function
*/
export const slugify = (str: string): string =>
str
.normalize('NFKD')
// Remove accents
.replace(rCombining, '')
// Remove control characters
.replace(rControl, '')
// Replace special characters
.replace(rSpecial, '-')
// ensure it doesn't start with a number
.replace(/^(\d)/, '_$1')
export const commonConfig = defineConfig({
title: 'Lancet',
appearance: 'dark',
markdown: {
theme: {
dark: 'dracula-soft',
light: 'vitesse-light',
},
attrs: {
leftDelimiter: '%{',
rightDelimiter: '}%',
},
anchor: {
slugify,
},
},
head: [
// ['link', { rel: 'icon', type: 'image/svg+xml', href: '/logo.svg' }],
['link', { rel: 'icon', type: 'image/png', href: '/lancet_logo_mini.png' }],
['meta', { name: 'theme-color', content: '#5f67ee' }],
['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:locale', content: 'zh' }],
...(isProduction ? productionHead : []),
],
themeConfig: {
logo: { src: '/lancet_logo_mini.png', width: 24, height: 24 },
outline: [2, 3],
search: {
provider: 'local',
},
socialLinks: [
{
icon: 'github',
link: 'https://github.com/duke-git/lancet',
},
],
footer: {
copyright: 'Copyright © 2023-present Duke Du',
message: 'Released under the MIT License.',
},
},
})

View File

@@ -0,0 +1,14 @@
import { defineConfig } from 'vitepress'
import { commonConfig } from './common'
import { zhConfig } from './zh'
import { enConfig } from './en'
// https://vitepress.dev/reference/site-config
export default defineConfig({
...commonConfig,
locales: {
root: { label: '简体中文', lang: 'zh-CN', link: '/', ...zhConfig },
en: { label: 'English', lang: 'en-US', link: '/en/', ...enConfig },
},
})

91
docs/.vitepress/en.ts Normal file
View File

@@ -0,0 +1,91 @@
import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
export const META_URL = 'https://lancet.go.dev'
export const META_TITLE = 'Lancet'
export const META_DESCRIPTION = 'A powerful util function library of Go'
export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
description: META_DESCRIPTION,
head: [
['meta', { property: 'og:url', content: META_URL }],
['meta', { property: 'og:description', content: META_DESCRIPTION }],
['meta', { property: 'twitter:url', content: META_URL }],
['meta', { property: 'twitter:title', content: META_TITLE }],
['meta', { property: 'twitter:description', content: META_DESCRIPTION }],
],
themeConfig: {
nav: [
{
text: 'Home',
link: '/en/',
activeMatch: '^/en/',
},
{
text: 'Guide',
link: '/en/guide/introduction',
activeMatch: '^/en/guide/',
},
{ text: 'API', link: '/en/api/overview', activeMatch: '^/en/api/' },
{
text: 'Links',
items: [
{
text: 'Releaselog',
link: 'https://github.com/duke-git/lancet/releases',
},
],
},
],
sidebar: {
'/en/': [
{
text: 'Introduction',
items: [
{
text: 'What is Lancet',
link: '/en/guide/introduction',
},
{
text: 'getting started',
link: '/en/guide/getting_started',
},
],
},
],
'/en/api/': [
{
text: 'overview',
items: [{ text: 'overview of API', link: '/en/api/overview' }],
},
{
text: 'packages',
items: [
{ text: 'algorithm', link: '/en/api/packages/algorithm' },
{ text: 'compare', link: '/en/api/packages/compare' },
{ text: 'concurrency', link: '/en/api/packages/concurrency' },
{ text: 'condition', link: '/en/api/packages/condition' },
{ text: 'convertor', link: '/en/api/packages/convertor' },
{ text: 'cryptor', link: '/en/api/packages/cryptor' },
{
text: 'datastructure',
items: [
{ text: 'list', link: '/en/api/packages/datastructure/list' },
{ text: 'safelist', link: '/en/api/packages/datastructure/copyonwritelist' },
{ text: 'link', link: '/en/api/packages/datastructure/link' },
{ text: 'stack', link: '/en/api/packages/datastructure/stack' },
{ text: 'queue', link: '/en/api/packages/datastructure/queue' },
{ text: 'heap', link: '/en/api/packages/datastructure/heap' },
{ text: 'tree', link: '/en/api/packages/datastructure/tree' },
{ text: 'set', link: '/en/api/packages/datastructure/set' },
{ text: 'hashmap', link: '/en/api/packages/datastructure/hashmap' },
]
},
],
},
],
},
},
}

101
docs/.vitepress/zh.ts Normal file
View File

@@ -0,0 +1,101 @@
import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
export const META_URL = 'https://lancet.go.dev'
export const META_TITLE = 'Lancet'
export const META_DESCRIPTION = '一个强大的Go语言工具函数库'
export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
description: META_DESCRIPTION,
head: [
['meta', { property: 'og:url', content: META_URL }],
['meta', { property: 'og:description', content: META_DESCRIPTION }],
['meta', { property: 'twitter:url', content: META_URL }],
['meta', { property: 'twitter:title', content: META_TITLE }],
['meta', { property: 'twitter:description', content: META_DESCRIPTION }],
],
themeConfig: {
outline: {
label: '本页内容',
},
docFooter: {
prev: '上一页',
next: '下一页',
},
nav: [
{
text: '首页',
link: '/',
activeMatch: '^/',
},
{
text: '指南',
link: '/guide/introduction',
activeMatch: '^/guide/',
},
{ text: 'API', link: '/api/overview', activeMatch: '^/api/' },
{
text: '相关链接',
items: [
{
text: '更新日志',
link: 'https://github.com/duke-git/lancet/releases',
},
],
},
],
sidebar: {
'/': [
{
text: '介绍',
items: [
{
text: 'Lancet是什么',
link: '/guide/introduction',
},
{
text: '开始',
link: '/guide/getting_started',
},
],
},
],
'/api/': [
{
text: '概览',
items: [{ text: 'API概述', link: '/api/overview' }],
},
{
text: 'API文档',
items: [
{ text: '算法', link: '/api/packages/algorithm' },
{ text: '比较器', link: '/api/packages/compare' },
{ text: '并发处理', link: '/api/packages/concurrency' },
{ text: '条件判断', link: '/api/packages/condition' },
{ text: '类型转换', link: '/api/packages/convertor' },
{ text: '加密&解密', link: '/api/packages/cryptor' },
{
text: '数据结构',
items: [
{ text: '线性表', link: '/api/packages/datastructure/list' },
{ text: '线性表(线程安全)', link: '/api/packages/datastructure/copyonwritelist' },
{ text: '链表', link: '/api/packages/datastructure/link' },
{ text: '栈', link: '/api/packages/datastructure/stack' },
{ text: '队列', link: '/api/packages/datastructure/queue' },
{ text: '堆', link: '/api/packages/datastructure/heap' },
{ text: '树', link: '/api/packages/datastructure/tree' },
{ text: '集合', link: '/api/packages/datastructure/set' },
{ text: 'HashMap', link: '/api/packages/datastructure/hashmap' },
]
},
],
},
],
},
},
}

View File

@@ -1,595 +0,0 @@
# Algorithm
Package algorithm implements some basic algorithm. eg. sort, search.
<div STYLE="page-break-after: always;"></div>
## Source
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
<div STYLE="page-break-after: always;"></div>
## Usage
```go
import (
"github.com/duke-git/lancet/v2/algorithm"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [BubbleSort](#BubbleSort)
- [InsertionSort](#InsertionSort)
- [SelectionSort](#SelectionSort)
- [ShellSort](#ShellSort)
- [QuickSort](#QuickSort)
- [HeapSort](#HeapSort)
- [MergeSort](#MergeSort)
- [CountSort](#CountSort)
- [BinarySearch](#BinarySearch)
- [BinaryIterativeSearch](#BinaryIterativeSearch)
- [LinearSearch](#LinearSearch)
- [LRUCache](#LRUCache)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="BubbleSort">BubbleSort</span>
<p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.BubbleSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="InsertionSort">InsertionSort</span>
<p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type people struct {
Name string
Age int
}
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
//ascending order
if p1.Age < p2.Age {
return -1
} else if p1.Age > p2.Age {
return 1
}
return 0
//decending order
// if p1.Age > p2.Age {
// return -1
// } else if p1.Age < p2.Age {
// return 1
// }
}
var peoples = []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator)
fmt.Println(peoples) //[{d 8} {b 10} {c 17} {a 20} {e 28}]
}
```
### <span id="SelectionSort">SelectionSort</span>
<p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.SelectionSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="ShellSort">ShellSort</span>
<p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.ShellSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="QuickSort">QuickSort</span>
<p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="HeapSort">HeapSort</span>
<p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.HeapSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="MergeSort">MergeSort</span>
<p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.MergeSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="CountSort">CountSort</span>
<p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
sortedSlice := algorithm.CountSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="BinarySearch">BinarySearch</span>
<p>BinarySearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b>
```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>BinaryIterativeSearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b>
```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="LinearSearch">LinearSearch</span>
<p>LinearSearch Simple linear search algorithm that iterates over all elements of an slice. If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b>
```go
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
fmt.Println(foundIndex) //2
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="LRUCache">LRUCache</span>
<p>LRUCache implements mem cache with lru.</p>
<b>Signature:</b>
```go
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
func (l *LRUCache[K, V]) Get(key K) (V, bool)
func (l *LRUCache[K, V]) Put(key K, value V)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
cache := algorithm.NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
_, ok := cache.Get(0) // ok -> false
v, ok := cache.Get(1) // v->1, ok->true
}
```

View File

@@ -1,596 +0,0 @@
# Algorithm
algorithm算法包实现一些基本算法sortsearchlrucache。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
"github.com/duke-git/lancet/v2/algorithm"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [BubbleSort](#BubbleSort)
- [InsertionSort](#InsertionSort)
- [SelectionSort](#SelectionSort)
- [ShellSort](#ShellSort)
- [QuickSort](#QuickSort)
- [HeapSort](#HeapSort)
- [MergeSort](#MergeSort)
- [CountSort](#CountSort)
- [BinarySearch](#BinarySearch)
- [BinaryIterativeSearch](#BinaryIterativeSearch)
- [LinearSearch](#LinearSearch)
- [LRUCache](#LRUCache)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="BubbleSort">BubbleSort</span>
<p>冒泡排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.BubbleSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="InsertionSort">InsertionSort</span>
<p>插入排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type people struct {
Name string
Age int
}
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
//ascending order
if p1.Age < p2.Age {
return -1
} else if p1.Age > p2.Age {
return 1
}
return 0
//decending order
// if p1.Age > p2.Age {
// return -1
// } else if p1.Age < p2.Age {
// return 1
// }
}
var peoples = []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator)
fmt.Println(intSlice) //[{d 8} {b 10} {c 17} {a 20} {e 28}]
}
```
### <span id="SelectionSort">SelectionSort</span>
<p>选择排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.SelectionSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="ShellSort">ShellSort</span>
<p>希尔排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.ShellSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="QuickSort">QuickSort</span>
<p>快速排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="HeapSort">HeapSort</span>
<p>堆排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.HeapSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="MergeSort">MergeSort</span>
<p>归并排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.MergeSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="CountSort">CountSort</span>
<p>计数排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
sortedSlice := algorithm.CountSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="BinarySearch">BinarySearch</span>
<p>二分递归查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>二分迭代查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="LinearSearch">LinearSearch</span>
<p>线性查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
fmt.Println(foundIndex) //2
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="LRUCache">LRUCache</span>
<p>lru实现缓存</p>
<b>函数签名:</b>
```go
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
func (l *LRUCache[K, V]) Get(key K) (V, bool)
func (l *LRUCache[K, V]) Put(key K, value V)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
cache := algorithm.NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
_, ok := cache.Get(0) // ok -> false
v, ok := cache.Get(1) // v->1, ok->true
}
```

69
docs/api/overview.md Normal file
View File

@@ -0,0 +1,69 @@
---
outline: deep
---
# API概述
<b>lancet柳叶刀是一个强大、全面、高效、可复用的go语言工具函数库。包含25个包超过600个工具函数。功能涵盖字符串处理、切片处理、网络、并发、加解密、文件处理、时间/日期、流处理、迭代器等等。</b>
<style>
.package-title {
color: black;
font-size: 18px;
text-align: center;
font-weight: bold;
}
.package-container {
font-size: 16px;
border: 1px dashed;
padding: 10px;
text-align: center;
}
.package-cell {
height: 40px;
width: 140px;
display: inline-block;
vertical-align: middle;
line-height: 40px;
background: #ecefff;
border: 1px solid;
margin-right: 10px;
margin-bottom: 10px;
border-radius: 6px;
font-weight: bold;
}
</style>
<div>
<p class="package-title">lancet功能模块</p>
<div class="package-container">
<div class="package-cell">algorithm</div>
<div class="package-cell">compare</div>
<div class="package-cell">concurrency</div>
<div class="package-cell">condition</div>
<div class="package-cell">convertor</div>
<div class="package-cell">cryptor</div>
<div class="package-cell">datastructure</div>
<div class="package-cell">datetime</div>
<div class="package-cell">fileutil</div>
<div class="package-cell">formatter</div>
<div class="package-cell">function</div>
<div class="package-cell">iterator</div>
<div class="package-cell">maputil</div>
<div class="package-cell">mathutil</div>
<div class="package-cell">netutil</div>
<div class="package-cell">pointer</div>
<div class="package-cell">random</div>
<div class="package-cell">retry</div>
<div class="package-cell">slice</div>
<div class="package-cell">stream</div>
<div class="package-cell">structs</div>
<div class="package-cell">strutil</div>
<div class="package-cell">system</div>
<div class="package-cell">tuple</div>
<div class="package-cell">validator</div>
<div class="package-cell">xerror</div>
</div>
</div>

View File

@@ -0,0 +1,638 @@
# Algorithm
algorithm 算法包实现一些基本算法sortsearchlrucache。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
"github.com/duke-git/lancet/v2/algorithm"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [BubbleSort](#BubbleSort)
- [InsertionSort](#InsertionSort)
- [SelectionSort](#SelectionSort)
- [ShellSort](#ShellSort)
- [QuickSort](#QuickSort)
- [HeapSort](#HeapSort)
- [MergeSort](#MergeSort)
- [CountSort](#CountSort)
- [BinarySearch](#BinarySearch)
- [BinaryIterativeSearch](#BinaryIterativeSearch)
- [LinearSearch](#LinearSearch)
- [LRUCache](#LRUCache)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
### <span id="BubbleSort">BubbleSort</span>
<p>冒泡排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/GNdv7Jg2Taj)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.BubbleSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="InsertionSort">InsertionSort</span>
<p>插入排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/G5LJiWgJJW6)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type people struct {
Name string
Age int
}
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
//ascending order
if p1.Age < p2.Age {
return -1
} else if p1.Age > p2.Age {
return 1
}
return 0
}
func main() {
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator)
fmt.Println(peoples)
// Output:
// [{d 8} {b 10} {c 17} {a 20} {e 28}]
}
```
### <span id="SelectionSort">SelectionSort</span>
<p>选择排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/oXovbkekayS)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.SelectionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="ShellSort">ShellSort</span>
<p>希尔排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/3ibkszpJEu3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.ShellSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="QuickSort">QuickSort</span>
<p>快速排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/7Y7c1Elk3ax)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="HeapSort">HeapSort</span>
<p>堆排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/u6Iwa1VZS_f)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.HeapSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="MergeSort">MergeSort</span>
<p>归并排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ydinn9YzUJn)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.MergeSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="CountSort">CountSort</span>
<p>计数排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/tB-Umgm0DrP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
sortedNums := algorithm.CountSort(numbers, comparator)
fmt.Println(sortedNums)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="BinarySearch">BinarySearch</span>
<p>二分递归查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/t6MeGiUSN47)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
result1 := algorithm.BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
result2 := algorithm.BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
}
```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>二分迭代查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b>
```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/Anozfr8ZLH3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
result1 := algorithm.BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
result2 := algorithm.BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
}
```
### <span id="LinearSearch">LinearSearch</span>
<p>基于传入的相等函数线性查找元素,返回元素索引,未找到元素返回-1。</p>
<b>函数签名:</b>
```go
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/IsS7rgn5s3x)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
numbers := []int{3, 4, 5, 3, 2, 1}
equalFunc := func(a, b int) bool {
return a == b
}
result1 := algorithm.LinearSearch(numbers, 3, equalFunc)
result2 := algorithm.LinearSearch(numbers, 6, equalFunc)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// -1
}
```
### <span id="LRUCache">LRUCache</span>
<p>lru算法实现缓存。</p>
<b>函数签名:</b>
```go
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
func (l *LRUCache[K, V]) Get(key K) (V, bool)
func (l *LRUCache[K, V]) Put(key K, value V)
func (l *LRUCache[K, V]) Delete(key K) bool
func (l *LRUCache[K, V]) Len() int
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/-EZjgOURufP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
cache := algorithm.NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
fmt.Println(result1, ok1)
fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
fmt.Println(cache.Len())
ok := cache.Delete(2)
fmt.Println(ok)
// Output:
// 1 true
// 2 true
// 0 false
// 2
// true
}
```

View File

@@ -0,0 +1,377 @@
# Compare
compare包提供几个轻量级的类型比较函数。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/compare/compare.go](https://github.com/duke-git/lancet/blob/main/compare/compare.go)
- [https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/condition"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Equal](#Equal)
- [EqualValue](#EqualValue)
- [LessThan](#LessThan)
- [GreaterThan](#GreaterThan)
- [LessOrEqual](#LessOrEqual)
- [GreaterOrEqual](#GreaterOrEqual)
- [InDelta](#InDelta)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="../../styles/api_doc.css">
## 文档
### <span id="Equal">Equal</span>
<p>检查两个值是否相等(检查类型和值)</p>
<b>函数签名:</b>
```go
func Equal(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/wmVxR-to4lz)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := compare.Equal(1, 1)
result2 := compare.Equal("1", "1")
result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3})
result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
result5 := compare.Equal(1, "1")
result6 := compare.Equal(1, int64(1))
result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
```
### <span id="EqualValue">EqualValue</span>
<p>检查两个值是否相等(只检查值)</p>
<b>函数签名:</b>
```go
func EqualValue(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/fxnna_LLD9u)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := compare.EqualValue(1, 1)
result2 := compare.EqualValue(int(1), int64(1))
result3 := compare.EqualValue(1, "1")
result4 := compare.EqualValue(1, "2")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// true
// false
}
```
### <span id="LessThan">LessThan</span>
<p>验证参数`left`的值是否小于参数`right`的值。</p>
<b>函数签名:</b>
```go
func LessThan(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/cYh7FQQj0ne)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := compare.LessThan(1, 2)
result2 := compare.LessThan(1.1, 2.2)
result3 := compare.LessThan("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.LessThan(time1, time2)
result5 := compare.LessThan(2, 1)
result6 := compare.LessThan(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
```
### <span id="GreaterThan">GreaterThan</span>
<p>验证参数`left`的值是否大于参数`right`的值。</p>
<b>函数签名:</b>
```go
func GreaterThan(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/9-NYDFZmIMp)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := compare.GreaterThan(2, 1)
result2 := compare.GreaterThan(2.2, 1.1)
result3 := compare.GreaterThan("b", "a")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.GreaterThan(time2, time1)
result5 := compare.GreaterThan(1, 2)
result6 := compare.GreaterThan(int64(2), 1)
result7 := compare.GreaterThan("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
```
### <span id="LessOrEqual">LessOrEqual</span>
<p>验证参数`left`的值是否小于或等于参数`right`的值。</p>
<b>函数签名:</b>
```go
func LessOrEqual(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/e4T_scwoQzp)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := compare.LessOrEqual(1, 1)
result2 := compare.LessOrEqual(1.1, 2.2)
result3 := compare.LessOrEqual("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.LessOrEqual(time1, time2)
result5 := compare.LessOrEqual(2, 1)
result6 := compare.LessOrEqual(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
```
### <span id="GreaterOrEqual">GreaterOrEqual</span>
<p>验证参数`left`的值是否大于或参数`right`的值。</p>
<b>函数签名:</b>
```go
func GreaterOrEqual(left, right any) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/vx8mP0U8DFk)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := compare.GreaterOrEqual(1, 1)
result2 := compare.GreaterOrEqual(2.2, 1.1)
result3 := compare.GreaterOrEqual("b", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.GreaterOrEqual(time2, time1)
result5 := compare.GreaterOrEqual(1, 2)
result6 := compare.GreaterOrEqual(int64(2), 1)
result7 := compare.GreaterOrEqual("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
```
### <span id="InDelta">InDelta</span>
<p>检查增量内两个值是否相等。</p>
<b>函数签名:</b>
```go
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool
```
<b>示例: <span class="run-container">[运行](https://go.dev/play/p/TuDdcNtMkjo)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := InDelta(1, 1, 0)
result2 := InDelta(1, 2, 0)
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
result4 := InDelta(2.0/3.0, 0.0, 0.001)
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// false
// true
// false
// false
// true
}
```

View File

@@ -0,0 +1,443 @@
# Concurrency
并发包包含一些支持并发编程的功能。例如goroutine, channel等。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/concurrency"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
### Channel
- [NewChannel](#NewChannel)
- [Bridge](#Bridge)
- [FanIn](#FanIn)
- [Generate](#Generate)
- [Or](#Or)
- [OrDone](#OrDone)
- [Repeat](#Repeat)
- [RepeatFn](#RepeatFn)
- [Take](#Take)
- [Tee](#Tee)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
### Channel
### <span id="NewChannel">NewChannel</span>
<p>返回一个Channel指针实例</p>
<b>函数签名:</b>
```go
type Channel[T any] struct
func NewChannel[T any]() *Channel[T]
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
c := concurrency.NewChannel[int]()
}
```
### <span id="Bridge">Bridge</span>
<p>将多个channel链接到一个channel直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/qmWSy1NVF-Y)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
genVals := func() <-chan <-chan int {
out := make(chan (<-chan int))
go func() {
defer close(out)
for i := 1; i <= 5; i++ {
stream := make(chan int, 1)
stream <- i
close(stream)
out <- stream
}
}()
return out
}
for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
```
### <span id="FanIn">FanIn</span>
<p>将多个channel合并为一个channel直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/2VYFMexEvTm)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
channels := make([]<-chan int, 2)
for i := 0; i < 2; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
}
chs := c.FanIn(ctx, channels...)
for v := range chs {
fmt.Println(v) //1 1 0 0 or 0 0 1 1
}
}
```
### <span id="Generate">Generate</span>
<p>根据传入的值生成channel.</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
// Output:
// 1
// 2
// 3
}
```
### <span id="Repeat">Repeat</span>
<p>返回一个channel将参数`values`重复放入channel直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/k5N_ALVmYjE)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 1
// 2
}
```
### <span id="RepeatFn">RepeatFn</span>
<p>返回一个channel重复执行函数fn并将结果放入返回的channel直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/4J1zAWttP85)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() string {
return "hello"
}
c := concurrency.NewChannel[string]()
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// hello
// hello
// hello
}
```
### <span id="Or">Or</span>
<p>将一个或多个channel读取到一个channel中当任何读取channel关闭时将结束读取。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/Wqz9rwioPww)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan any)
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := concurrency.NewChannel[any]()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
)
fmt.Println("done after %v", time.Since(start)) //1.003s
}
```
### <span id="OrDone">OrDone</span>
<p>将一个channel读入另一个channel直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/lm_GoS6aDjo)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for v := range c.OrDone(ctx, intStream) {
fmt.Println(v)
}
// Output:
// 1
// 1
// 1
}
```
### <span id="Take">Take</span>
<p>返回一个channel其值从另一个channel获取直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/9Utt-1pDr2J)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}
```
### <span id="Tee">Tee</span>
<p>将一个channel分成两个channel直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/3TQPKnCirrP)</span></b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
ch1, ch2 := c.Tee(ctx, intStream)
for v := range ch1 {
fmt.Println(v)
fmt.Println(<-ch2)
}
// Output:
// 1
// 1
// 1
// 1
}
```

View File

@@ -0,0 +1,300 @@
# Condition
condition包含一些用于条件判断的函数。这个包的实现参考了carlmjohnson的truthy包的实现更多有用的信息可以在[truthy](https://github.com/carlmjohnson/truthy)中找到感谢carlmjohnson。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/condition/condition.go](https://github.com/duke-git/lancet/blob/main/condition/condition.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/condition"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Bool](#Bool)
- [And](#And)
- [Or](#Or)
- [Xor](#Generate)
- [Nor](#Nor)
- [Xnor](#Xnor)
- [Nand](#Nand)
- [TernaryOperator](#TernaryOperator)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
### <span id="Bool">Bool</span>
<p>返回传入参数的bool值.<br/>
如果出入类型参数含有Bool方法, 会调用该方法并返回<br/>
如果传入类型参数有IsZero方法, 返回IsZero方法返回值的取反<br/>
slices和map的length大于0时返回true否则返回false<br/>
其他类型会判断是否是零值</p>
<b>函数签名:</b>
```go
func Bool[T any](value T) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ETzeDJRSvhm)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
// bool
result1 := condition.Bool(false)
result2 := condition.Bool(true)
fmt.Println(result1) // false
fmt.Println(result2) // true
// integer
result3 := condition.Bool(0)
result4 := condition.Bool(1)
fmt.Println(result3) // false
fmt.Println(result4) // true
// string
result5 := condition.Bool("")
result6 := condition.Bool(" ")
fmt.Println(result5) // false
fmt.Println(result6) // true
// slice
nums := []int{}
result7 := condition.Bool(nums)
nums = append(nums, 1, 2)
result8 := condition.Bool(nums)
fmt.Println(result7) // false
fmt.Println(result8) // true
// struct
result9 = condition.Bool(struct{}{})
fmt.Println(result8) // false
// Output:
// false
// true
// false
// true
// false
// true
// false
// true
// false
}
```
### <span id="And">And</span>
<p>逻辑且操作当切仅当a和b都为true时返回true</p>
<b>函数签名:</b>
```go
func And[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/W1SSUmt6pvr)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.And(0, 1)) // false
fmt.Println(condition.And(0, "")) // false
fmt.Println(condition.And(0, "0")) // false
fmt.Println(condition.And(1, "0")) // true
}
```
### <span id="Or">Or</span>
<p>逻辑或操作当切仅当a和b都为false时返回false</p>
<b>函数签名:</b>
```go
func Or[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/UlQTxHaeEkq)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Or(0, "")) // false
fmt.Println(condition.Or(0, 1)) // true
fmt.Println(condition.Or(0, "0")) // true
fmt.Println(condition.Or(1, "0")) // true
}
```
### <span id="Xor">Xor</span>
<p>逻辑异或操作a和b相同返回falsea和b不相同返回true</p>
<b>函数签名:</b>
```go
func Xor[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/gObZrW7ZbG8)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Xor(0, 0)) // false
fmt.Println(condition.Xor(0, 1)) // true
fmt.Println(condition.Xor(1, 0)) // true
fmt.Println(condition.Xor(1, 1)) // false
}
```
### <span id="Nor">Nor</span>
<p>异或的取反操作</p>
<b>函数签名:</b>
```go
func Nor[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/g2j08F_zZky)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Nor(0, 0)) // true
fmt.Println(condition.Nor(0, 1)) // false
fmt.Println(condition.Nor(1, 0)) // false
fmt.Println(condition.Nor(1, 1)) // false
}
```
### <span id="Xnor">Xnor</span>
<p>如果a和b都是真的或a和b均是假的则返回true。</p>
<b>函数签名:</b>
```go
func Xnor[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/OuDB9g51643)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Xnor(0, 0)) // true
fmt.Println(condition.Xnor(0, 1)) // false
fmt.Println(condition.Xnor(1, 0)) // false
fmt.Println(condition.Xnor(1, 1)) // true
}
```
### <span id="Nand">Nand</span>
<p>如果a和b都为真返回false否则返回true</p>
<b>函数签名:</b>
```go
func Nand[T, U any](a T, b U) bool
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/vSRMLxLIbq8)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Nand(0, 0)) // true
fmt.Println(condition.Nand(0, 1)) // true
fmt.Println(condition.Nand(1, 0)) // true
fmt.Println(condition.Nand(1, 1)) // false
}
```
### <span id="TernaryOperator">TernaryOperator</span>
<p>三元运算符</p>
<b>函数签名:</b>
```go
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
conditionTrue := 2 > 1
result1 := condition.TernaryOperator(conditionTrue, 0, 1)
conditionFalse := 2 > 3
result2 := condition.TernaryOperator(conditionFalse, 0, 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// 1
}
```

View File

@@ -0,0 +1,880 @@
# Convertor
convertor 转换器包支持一些常见的数据类型转换
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/convertor"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToChannel](#ToChannel)
- [ToFloat](#ToFloat)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToMap](#ToMap)
- [ToPointer](#ToPointer)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToSlice](#MapToSlice)
- [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte)
- [DeepClone](#DeepClone)
- [CopyProperties](#CopyProperties)
- [ToInterface](#ToInterface)
- [Utf8ToGbk](#Utf8ToGbk)
- [GbkToUtf8](#GbkToUtf8)
<div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
## 文档
### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>颜色值十六进制转rgb。</p>
<b>函数签名:</b>
```go
func ColorHexToRGB(colorHex string) (red, green, blue int)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/o7_ft-JCJBV)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b)
// Output:
// 0 51 102
}
```
### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>颜色值rgb转十六进制。</p>
<b>函数签名:</b>
```go
func ColorRGBToHex(red, green, blue int) string
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/nzKS2Ro87J1)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
r := 0
g := 51
b := 102
colorHex := ColorRGBToHex(r, g, b)
fmt.Println(colorHex)
// Output:
// #003366
}
```
### <span id="ToBool">ToBool</span>
<p>字符串转布尔类型使用strconv.ParseBool。</p>
<b>函数签名:</b>
```go
func ToBool(s string) (bool, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ARht2WnGdIN)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
for i := 0; i < len(cases); i++ {
result, _ := convertor.ToBool(cases[i])
fmt.Println(result)
}
// Output:
// true
// true
// true
// false
// false
// false
// false
// false
// false
}
```
### <span id="ToBytes">ToBytes</span>
<p>Interface转字节切片。</p>
<b>函数签名:</b>
```go
func ToBytes(data any) ([]byte, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/fAMXYFDvOvr)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
bytesData, err := convertor.ToBytes("abc")
if err != nil {
fmt.Println(err)
}
fmt.Println(bytesData)
// Output:
// [97 98 99]
}
```
### <span id="ToChar">ToChar</span>
<p>字符串转字符切片。</p>
<b>函数签名:</b>
```go
func ToChar(s string) []string
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/JJ1SvbFkVdM)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result1 := convertor.ToChar("")
result2 := convertor.ToChar("abc")
result3 := convertor.ToChar("1 2#3")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// []
// [a b c]
// [1 2 # 3]
}
```
### <span id="ToChannel">ToChannel</span>
<p>将切片转为只读channel。</p>
<b>函数签名:</b>
```go
func ToChannel[T any](array []T) <-chan T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/hOx_oYZbAnL)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
ch := convertor.ToChannel([]int{1, 2, 3})
result1 := <-ch
result2 := <-ch
result3 := <-ch
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 3
}
```
### <span id="ToFloat">ToFloat</span>
<p>将interface转成float64类型如果参数无法转换会返回0和error。</p>
<b>函数签名:</b>
```go
func ToFloat(value any) (float64, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/4YTmPCibqHJ)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result1, _ := convertor.ToFloat("")
result2, err := convertor.ToFloat("abc")
result3, _ := convertor.ToFloat("-1")
result4, _ := convertor.ToFloat("-.11")
result5, _ := convertor.ToFloat("1.23e3")
result6, _ := convertor.ToFloat(true)
fmt.Println(result1)
fmt.Println(result2, err)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// 0
// 0 strconv.ParseFloat: parsing "": invalid syntax
// -1
// -0.11
// 1230
// 0
}
```
### <span id="ToInt">ToInt</span>
<p>将interface转成int64类型如果参数无法转换会返回0和error。</p>
<b>函数签名:</b>
```go
func ToInt(value any) (int64, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/9_h9vIt-QZ_b)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result1, _ := convertor.ToInt("123")
result2, _ := convertor.ToInt("-123")
result3, _ := convertor.ToInt(float64(12.3))
result4, err := convertor.ToInt("abc")
result5, _ := convertor.ToInt(true)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4, err)
fmt.Println(result5)
// Output:
// 123
// -123
// 12
// 0 strconv.ParseInt: parsing "": invalid syntax
// 0
}
```
### <span id="ToJson">ToJson</span>
<p>将interface转成json字符串如果参数无法转换会返回""和error。</p>
<b>函数签名:</b>
```go
func ToJson(value any) (string, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/2rLIkMmXWvR)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result, err := ToJson(aMap)
if err != nil {
fmt.Printf("%v", err)
}
fmt.Println(result)
// Output:
// {"a":1,"b":2,"c":3}
}
```
### <span id="ToMap">ToMap</span>
<p>将切片转为map。</p>
<b>函数签名:</b>
```go
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/tVFy7E-t24l)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Message struct {
name string
code int
}
messages := []Message{
{name: "Hello", code: 100},
{name: "Hi", code: 101},
}
result := convertor.ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name
})
fmt.Println(result)
// Output:
// map[100:Hello 101:Hi]
}
```
### <span id="ToPointer">ToPointer</span>
<p>返回传入值的指针。</p>
<b>函数签名:</b>
```go
func ToPointer[T any](value T) *T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/ASf_etHNlw1)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result := convertor.ToPointer(123)
fmt.Println(*result)
// Output:
// 123
}
```
### <span id="ToString">ToString</span>
<p>将值转换为字符串,对于数字、字符串、[]byte将转换为字符串。 对于其他类型(切片、映射、数组、结构体)将调用 json.Marshal</p>
<b>函数签名:</b>
```go
func ToString(value any) string
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/nF1zOOslpQq)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result1 := convertor.ToString("")
result2 := convertor.ToString(nil)
result3 := convertor.ToString(0)
result4 := convertor.ToString(1.23)
result5 := convertor.ToString(true)
result6 := convertor.ToString(false)
result7 := convertor.ToString([]int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
//
//
// 0
// 1.23
// true
// false
// [1,2,3]
}
```
### <span id="StructToMap">StructToMap</span>
<p>将struct转成map只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记。</p>
<b>函数签名:</b>
```go
func StructToMap(value any) (map[string]any, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/KYGYJqNUBOI)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := convertor.StructToMap(p)
fmt.Println(pm)
// Output:
// map[name:test]
}
```
### <span id="MapToSlice">MapToSlice</span>
<p>map中key和value执行函数iteratee后转为切片。</p>
<b>函数签名:</b>
```go
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/dmX4Ix5V6Wl)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result := MapToSlice(aMap, func(key string, value int) string {
return key + ":" + strconv.Itoa(value)
})
fmt.Println(result) //[]string{"a:1", "b:2", "c:3"}
}
```
### <span id="EncodeByte">EncodeByte</span>
<p>将data编码成字节切片。</p>
<b>函数签名:</b>
```go
func EncodeByte(data any) ([]byte, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/DVmM1G5JfuP)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData)
// Output:
// [6 12 0 3 97 98 99]
}
```
### <span id="DecodeByte">DecodeByte</span>
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例。</p>
<b>函数签名:</b>
```go
func DecodeByte(data []byte, target any) error
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/zI6xsmuQRbn)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
err := convertor.DecodeByte(byteData, &result)
if err != nil {
return
}
fmt.Println(result)
// Output:
// abc
}
```
### <span id="DeepClone">DeepClone</span>
<p>创建一个传入值的深拷贝, 无法克隆结构体的非导出字段。</p>
<b>函数签名:</b>
```go
func DeepClone[T any](src T) T
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/j4DP5dquxnk)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for _, item := range cases {
cloned := convertor.DeepClone(item)
isPointerEqual := &cloned == &item
fmt.Println(cloned, isPointerEqual)
}
// Output:
// true false
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil> } false
}
```
### <span id="CopyProperties">CopyProperties</span>
<p>拷贝不同结构体之间的同名字段。使用json.Marshal序列化需要设置dst和src struct字段的json tag。</p>
<b>函数签名:</b>
```go
func CopyProperties[T, U any](dst T, src U) (err error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/oZujoB5Sgg5)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
err := convertor.CopyProperties(&indicatorVO, indicator)
if err != nil {
return
}
fmt.Println(indicatorVO.Id)
fmt.Println(indicatorVO.Ip)
fmt.Println(len(indicatorVO.Disk))
// Output:
// 001
// 127.0.0.1
// 3
}
```
### <span id="ToInterface">ToInterface</span>
<p>将反射值转换成对应的interface类型。</p>
<b>函数签名:</b>
```go
func ToInterface(v reflect.Value) (value interface{}, ok bool)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/syqw0-WG7Xd)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
val := reflect.ValueOf("abc")
iVal, ok := convertor.ToInterface(val)
fmt.Printf("%T\n", iVal)
fmt.Printf("%v\n", iVal)
fmt.Println(ok)
// Output:
// string
// abc
// true
}
```
### <span id="Utf8ToGbk">Utf8ToGbk</span>
<p>utf8编码转GBK编码。</p>
<b>函数签名:</b>
```go
func Utf8ToGbk(bs []byte) ([]byte, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/9FlIaFLArIL)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
utf8Data := []byte("hello")
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(validator.IsGBK(gbkData))
// Output:
// true
// true
}
```
### <span id="GbkToUtf8">GbkToUtf8</span>
<p>GBK编码转utf8编码。</p>
<b>函数签名:</b>
```go
func GbkToUtf8(bs []byte) ([]byte, error)
```
<b>示例:<span class="run-container">[运行](https://go.dev/play/p/OphmHCN_9u8)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
utf8Data, _ := convertor.GbkToUtf8(gbkData)
fmt.Println(utf8.Valid(utf8Data))
fmt.Println(string(utf8Data))
// Output:
// true
// hello
}
```

1427
docs/api/packages/cryptor.md Normal file

File diff suppressed because it is too large Load Diff

View 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}))
}
```

View File

@@ -0,0 +1,308 @@
# HashMap
HashMap 数据结构实现
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/hashmap/hashmap.go](https://github.com/duke-git/lancet/blob/main/datastructure/hashmap/hashmap.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [NewHashMap](#NewHashMap)
- [NewHashMapWithCapacity](#NewHashMapWithCapacity)
- [Get](#Get)
- [Put](#Put)
- [Delete](#Delete)
- [Contains](#Contains)
- [Iterate](#Iterate)
- [Keys](#Keys)
- [Values](#Values)
<div STYLE="page-break-after: always;"></div>
## API 文档
### <span id="NewHashMap">NewHashMap</span>
<p>新建默认容量1 << 10的HashMap指针实例</p>
<b>函数签名:</b>
```go
func NewHashMap() *HashMap
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
fmt.Println(hm)
}
```
### <span id="NewHashMapWithCapacity">NewHashMapWithCapacity</span>
<p>新建指定容量和长度的HashMap指针实例.</p>
<b>函数签名:</b>
```go
func NewHashMapWithCapacity(size, capacity uint64) *HashMap
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMapWithCapacity(uint64(100), uint64(1000))
fmt.Println(hm)
}
```
### <span id="Get">Get</span>
<p>在hashmap中根据key获取值</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Get(key any) any
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
val := hm.Get("a")
fmt.Println(val) //nil
}
```
### <span id="Put">Put</span>
<p>将key-value放入hashmap中</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Put(key any, value any) any
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
val := hm.Get("a")
fmt.Println(val) //1
}
```
### <span id="Delete">Delete</span>
<p>将指定的key从hashmap中删除</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Delete(key any)
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
val := hm.Get("a")
fmt.Println(val) //1
hm.Delete("a")
val = hm.Get("a")
fmt.Println(val) //nil
}
```
### <span id="Contains">Contains</span>
<p>判断hashmap中是否包含指定的key</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Contains(key any) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
fmt.Println(hm.Contains("a")) //true
fmt.Println(hm.Contains("b")) //false
}
```
### <span id="Iterate">Iterate</span>
<p>迭代hashmap对每个key和value执行iteratee函数</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Iterate(iteratee func(key, value any))
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
hm.Iterate(func(key, value any) {
fmt.Println(key)
fmt.Println(value)
})
}
```
### <span id="Keys">Keys</span>
<p>返回hashmap所有key的切片 (随机顺序)</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Keys() []any
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
fmt.Println(keys) //[]interface{"a", "b", "c"}
}
```
### <span id="Values">Values</span>
<p>返回hashmap所有值的切片 (随机顺序).</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Values() []any
```
<b>示例:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
values := hm.Values()
fmt.Println(values) //[]interface{2, 1, 3}
}
```

View File

@@ -0,0 +1,364 @@
# Heap
堆,切片实现的二叉堆数据结构。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/heap/maxheap.go](https://github.com/duke-git/lancet/blob/main/datastructure/heap/maxheap.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [MaxHeap](#MaxHeap)
- [Push](#Push)
- [Pop](#Pop)
- [Peek](#Peek)
- [Data](#Data)
- [Size](#Size)
<div STYLE="page-break-after: always;"></div>
## API文档
### 1. MaxHeap
MaxHeap是通过slice实现的二叉堆树根节点的key既大于等于左子树的key值且大于等于右子树的key值。
### <span id="NewMaxHeap">NewMaxHeap</span>
<p>返回NewMaxHeap指针实例</p>
<b>函数签名:</b>
```go
type MaxHeap[T any] struct {
data []T
comparator lancetconstraints.Comparator
}
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
fmt.Println(maxHeap)
}
```
### <span id="Push">Push</span>
<p>向堆中插入数据</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Push(value T)
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
fmt.Println(maxHeap.Data()) //[]int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
}
```
### <span id="Pop">Pop</span>
<p>返回堆中最大值并将其从堆中删除如果堆为空返回零值并返回false</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Pop() (T, bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
val, ok := maxHeap.Pop()
fmt.Println(val) //12
fmt.Println(ok) //true
}
```
### <span id="Peek">Peek</span>
<p>返回堆中最大值如果堆为空返回零值并返回false</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Peek() (T, bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
val, ok := maxHeap.Peek()
fmt.Println(val) //12
fmt.Println(maxHeap.Size()) //12
}
```
### <span id="Data">Data</span>
<p>返回堆中全部元素的切片</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Data() []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
fmt.Println(maxHeap.Data()) //[]int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
}
```
### <span id="Size">Size</span>
<p>返回堆中元素的数量</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) Size() int
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2}
for _, v := range values {
maxHeap.Push(v)
}
fmt.Println(maxHeap.Size()) //3
}
```
### <span id="PrintStructure">PrintStructure</span>
<p>打印堆的树形结构</p>
<b>函数签名:</b>
```go
func (h *MaxHeap[T]) PrintStructure()
```
<b>示例:</b>
```go
package main
import (
"fmt"
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func main() {
maxHeap := heap.NewMaxHeap[int](&intComparator{})
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
for _, v := range values {
maxHeap.Push(v)
}
fmt.Println(maxHeap.PrintStructure())
// 12
// 9 11
// 4 8 10 7
// 1 3 5 6 2
}
```

View File

@@ -81,7 +81,7 @@ type SinglyLink[T any] struct {
}
func NewSinglyLink[T any]() *SinglyLink[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -107,7 +107,7 @@ func main() {
```go
func (link *SinglyLink[T]) Values() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -132,14 +132,14 @@ func main() {
### <span id="SinglyLink_InsertAt">InsertAt</span>
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) InsertAt(index int, value T) error
func (link *SinglyLink[T]) InsertAt(index int, value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -152,6 +152,8 @@ import (
func main() {
lk := link.NewSinglyLink[int]()
lk.InsertAt(1, 1) //do nothing
lk.InsertAt(0, 1)
lk.InsertAt(1, 2)
lk.InsertAt(2, 3)
@@ -172,7 +174,7 @@ func main() {
```go
func (link *SinglyLink[T]) InsertAtHead(value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -204,7 +206,7 @@ func main() {
```go
func (link *SinglyLink[T]) InsertAtTail(value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -228,14 +230,14 @@ func main() {
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
<p>删除特定索引处的值索引应大于或等于0且小于或等于链接节点数 - 1</p>
<p>删除特定索引处的值索引应大于或等于0且小于或等于链接节点数-1</p>
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) DeleteAt(index int) error
func (link *SinglyLink[T]) DeleteAt(index int)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -253,9 +255,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAt(3)
lk.DeleteAt(3)
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2, 3}
}
```
@@ -268,9 +269,9 @@ func main() {
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) DeleteAtHead() error
func (link *SinglyLink[T]) DeleteAtHead()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -288,9 +289,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAtHead()
lk.DeleteAtHead()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{2, 3, 4}
}
```
@@ -304,9 +304,9 @@ func main() {
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) DeleteAtTail() error
func (link *SinglyLink[T]) DeleteAtTail()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -323,9 +323,8 @@ func main() {
lk.InsertAtTail(2)
lk.InsertAtTail(3)
err := lk.DeleteAtTail()
lk.DeleteAtTail()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2}
}
```
@@ -340,7 +339,7 @@ func main() {
```go
func (link *SinglyLink[T]) DeleteValue(value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -374,7 +373,7 @@ func main() {
```go
func (link *SinglyLink[T]) Reverse()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -406,7 +405,7 @@ func main() {
```go
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -438,7 +437,7 @@ func main() {
```go
func (link *SinglyLink[T]) Size() int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -469,7 +468,7 @@ func main() {
```go
func (link *SinglyLink[T]) IsEmpty() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -501,7 +500,7 @@ func main() {
```go
func (link *SinglyLink[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -534,7 +533,7 @@ func main() {
```go
func (link *SinglyLink[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -577,7 +576,7 @@ type DoublyLink[T any] struct {
}
func NewDoublyLink[T any]() *DoublyLink[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -603,7 +602,7 @@ func main() {
```go
func (link *DoublyLink[T]) Values() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -628,14 +627,14 @@ func main() {
### <span id="DoublyLink_InsertAt">InsertAt</span>
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) InsertAt(index int, value T) error
func (link *DoublyLink[T]) InsertAt(index int, value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -648,6 +647,8 @@ import (
func main() {
lk := link.NewDoublyLink[int]()
lk.InsertAt(1, 1) //do nothing
lk.InsertAt(0, 1)
lk.InsertAt(1, 2)
lk.InsertAt(2, 3)
@@ -668,7 +669,7 @@ func main() {
```go
func (link *DoublyLink[T]) InsertAtHead(value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -700,7 +701,7 @@ func main() {
```go
func (link *DoublyLink[T]) InsertAtTail(value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -724,14 +725,14 @@ func main() {
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
<p>删除特定索引处的值索引应大于或等于0且小于或等于链接节点数 - 1</p>
<p>删除特定索引处的值索引应大于或等于0且小于或等于链接节点数-1</p>
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) DeleteAt(index int) error
func (link *DoublyLink[T]) DeleteAt(index int)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -749,9 +750,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAt(3)
lk.DeleteAt(3)
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2, 3}
}
```
@@ -764,9 +764,9 @@ func main() {
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) DeleteAtHead() error
func (link *DoublyLink[T]) DeleteAtHead()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -784,9 +784,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAtHead()
lk.DeleteAtHead()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{2, 3, 4}
}
```
@@ -800,9 +799,9 @@ func main() {
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) DeleteAtTail() error
func (link *DoublyLink[T]) DeleteAtTail()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -819,9 +818,8 @@ func main() {
lk.InsertAtTail(2)
lk.InsertAtTail(3)
err := lk.DeleteAtTail()
lk.DeleteAtTail()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2}
}
```
@@ -837,7 +835,7 @@ func main() {
```go
func (link *DoublyLink[T]) Reverse()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -869,7 +867,7 @@ func main() {
```go
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -901,7 +899,7 @@ func main() {
```go
func (link *DoublyLink[T]) Size() int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -932,7 +930,7 @@ func main() {
```go
func (link *DoublyLink[T]) IsEmpty() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -964,7 +962,7 @@ func main() {
```go
func (link *DoublyLink[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -997,7 +995,7 @@ func main() {
```go
func (link *DoublyLink[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main

View File

@@ -26,6 +26,9 @@ import (
- [Data](#Data)
- [ValueOf](#ValueOf)
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [IndexOfFunc](#IndexOfFunc)
- [LastIndexOfFunc](#LastIndexOfFunc)
- [Push](#Push)
- [PopFirst](#PopFirst)
- [PopLast](#PopLast)
@@ -38,11 +41,21 @@ import (
- [Clone](#Clone)
- [Merge](#Merge)
- [Size](#Size)
- [Cap](#Cap)
- [Swap](#Swap)
- [Reverse](#Reverse)
- [Unique](#Unique)
- [Union](#Union)
- [Intersection](#Intersection)
- [Difference](#Difference)
- [SymmetricDifference](#SymmetricDifference)
- [RetainAll](#RetainAll)
- [DeleteAll](#DeleteAll)
- [ForEach](#ForEach)
- [Iterator](#Iterator)
- [ListToMap](#ListToMap)
- [SubList](#SubList)
- [DeleteIf](#DeleteIf)
<div STYLE="page-break-after: always;"></div>
@@ -55,11 +68,11 @@ import (
```go
type List[T any] struct {
data []T
data []T
}
func NewList[T any](data []T) *List[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -85,7 +98,7 @@ func main() {
```go
func (l *List[T]) Contain(value T) bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -114,7 +127,7 @@ func main() {
```go
func (l *List[T]) Data() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -143,7 +156,7 @@ func main() {
```go
func (l *List[T]) ValueOf(index int) (*T, bool)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -173,7 +186,7 @@ func main() {
```go
func (l *List[T]) IndexOf(value T) int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -192,6 +205,85 @@ func main() {
```
### <span id="LastIndexOf">LastIndexOf</span>
<p>返回列表中最后一次出现的值的索引。如果未找到,则返回-1</p>
<b>函数签名:</b>
```go
func (l *List[T]) LastIndexOf(value T) int
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOf(1)) // 3
fmt.Println(li.LastIndexOf(0)) //-1
}
```
### <span id="IndexOfFunc">IndexOfFunc</span>
<p>返回第一个符合函数条件的元素的索引。如果未找到,则返回-1</p>
<b>函数签名:</b>
```go
func (l *List[T]) IndexOfFunc(f func(T) bool) int
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3})
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 1 })) //0
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="LastIndexOfFunc">LastIndexOfFunc</span>
<p>返回最后一个符合函数条件的元素的索引。如果未找到,则返回-1</p>
<b>函数签名:</b>
```go
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 1 })) // 3
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="Push">Push</span>
<p>将值附加到列表末尾</p>
@@ -201,7 +293,7 @@ func main() {
```go
func (l *List[T]) Push(value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -230,7 +322,7 @@ func main() {
```go
func (l *List[T]) PopFirst() (*T, bool)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -262,7 +354,7 @@ func main() {
```go
func (l *List[T]) PopLast() (*T, bool)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -293,7 +385,7 @@ func main() {
```go
func (l *List[T]) DeleteAt(index int)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -331,7 +423,7 @@ func main() {
```go
func (l *List[T]) InsertAt(index int, value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -368,7 +460,7 @@ func main() {
```go
func (l *List[T]) UpdateAt(index int, value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -401,7 +493,7 @@ func main() {
```go
func (l *List[T]) Equal(other *List[T]) bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -431,7 +523,7 @@ func main() {
```go
func (l *List[T]) IsEmpty() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -461,7 +553,7 @@ func main() {
```go
func (l *List[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -489,7 +581,7 @@ func main() {
```go
func (l *List[T]) Clone() *List[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -518,7 +610,7 @@ func main() {
```go
func (l *List[T]) Merge(other *List[T]) *List[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -547,7 +639,7 @@ func main() {
```go
func (l *List[T]) Size() int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -566,6 +658,34 @@ func main() {
### <span id="Cap">Cap</span>
<p>返回列表数据容量</p>
<b>函数签名:</b>
```go
func (l *List[T]) Cap() int
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
data := make([]int, 0, 100)
li := list.NewList(data)
fmt.Println(li.Cap()) // 100
}
```
### <span id="Swap">Swap</span>
<p>交换列表中两个索引位置的值</p>
@@ -575,7 +695,7 @@ func main() {
```go
func (l *List[T]) Swap(i, j int)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -604,7 +724,7 @@ func main() {
```go
func (l *List[T]) Reverse()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -633,7 +753,7 @@ func main() {
```go
func (l *List[T]) Unique()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -662,7 +782,7 @@ func main() {
```go
func (l *List[T]) Union(other *List[T]) *List[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -692,7 +812,7 @@ func main() {
```go
func (l *List[T]) Intersection(other *List[T]) *List[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -709,4 +829,288 @@ func main() {
fmt.Println(li3.Data()) //4
}
```
### <span id="Difference">Difference</span>
<p>差集运算。</p>
<b>函数签名:</b>
```go
func (l *List[T]) Difference(other *List[T]) *List[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
list3 := list1.Intersection(list2)
fmt.Println(list3.Data()) //3
}
```
### <span id="SymmetricDifference">SymmetricDifference</span>
<p>对称差集运算。</p>
<b>函数签名:</b>
```go
func (l *List[T]) SymmetricDifference(other *List[T]) *List[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
list3 := list1.Intersection(list2)
fmt.Println(list3.Data()) //3, 4
}
```
### <span id="RetainAll">RetainAll</span>
<p>仅保留列表中包含在给定列表中的元素。</p>
<b>函数签名:</b>
```go
func (l *List[T]) RetainAll(list *List[T]) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
retain := NewList([]int{1, 2})
retain1 := NewList([]int{2, 3})
retain2 := NewList([]int{1, 2, 5})
list.RetainAll(retain)
list1.RetainAll(retain1)
list2.RetainAll(retain2)
fmt.Println(list.Data()) //1, 2
fmt.Println(list1.Data()) //2, 3
fmt.Println(list2.Data()) //1, 2
}
```
### <span id="DeleteAll">DeleteAll</span>
<p>从列表中删除给定列表中包含的所有元素。</p>
<b>函数签名:</b>
```go
func (l *List[T]) DeleteAll(list *List[T]) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
del := NewList([]int{1})
del1 := NewList([]int{2, 3})
del2 := NewList([]int{1, 2, 5})
list.DeleteAll(del)
list1.DeleteAll(del1)
list2.DeleteAll(del2)
fmt.Println(list.Data()) //2,3,4
fmt.Println(list1.Data()) //1,4
fmt.Println(list2.Data()) //3,4
}
```
### <span id="ForEach">ForEach</span>
<p>对列表的每个元素执行给定的操作。</p>
<b>函数签名:</b>
```go
func (l *List[T]) ForEach(consumer func(T))
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
result := make([]int, 0)
list.ForEach(func(i int) {
result = append(result, i)
})
fmt.Println(result.Data()) //1,2,3,4
}
```
### <span id="Iterator">Iterator</span>
<p>按顺序返回列表中元素的迭代器。</p>
<b>函数签名:</b>
```go
func (l *List[T]) Iterator() iterator.Iterator[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
iterator := list.Iterator()
result := make([]int, 0)
for iterator.HasNext() {
item, _ := iterator.Next()
result = append(result, item)
}
fmt.Println(result.Data()) //1,2,3,4
}
```
### <span id="ListToMap">ListToMap</span>
<p>基于iteratee函数将列表转换为映射map。</p>
<b>函数签名:</b>
```go
func ListToMap[T any, K comparable, V any](list *List[T], iteratee func(T) (K, V)) map[K]V
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
result := ListToMap(list, func(n int) (int, bool) {
return n, n > 1
})
fmt.Println(result) //map[int]bool{1: false, 2: true, 3: true, 4: true}
}
```
### <span id="SubList">SubList</span>
<p>返回指定的fromIndex包含和toIndex不包含之间的原始列表的子列表。</p>
<b>函数签名:</b>
```go
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 2, 3, 4, 5, 6})
fmt.Println(l.SubList(2, 5)) // []int{3, 4, 5}
}
```
### <span id="DeleteIf">DeleteIf</span>
<p>删除列表中所有符合函数调用函数返回true)的元素,返回删除元素的数量</p>
<b>函数签名:</b>
```go
func (l *List[T]) DeleteIf(f func(T) bool) int
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
fmt.Println(l.DeleteIf(func(a int) bool { return a == 1 })) // 12
fmt.Println(l.Data()) // []int{2, 3, 4}
}
```

View File

@@ -99,7 +99,7 @@ type ArrayQueue[T any] struct {
size int
}
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -125,7 +125,7 @@ func main() {
```go
func (q *ArrayQueue[T]) Data() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -152,7 +152,7 @@ func main() {
```go
func (q *ArrayQueue[T]) Enqueue(item T) bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -183,7 +183,7 @@ func main() {
```go
func (q *ArrayQueue[T]) Dequeue() (T, bool)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -215,7 +215,7 @@ func main() {
```go
func (q *ArrayQueue[T]) Front() T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -247,7 +247,7 @@ func main() {
```go
func (q *ArrayQueue[T]) Back() T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -278,7 +278,7 @@ func main() {
```go
func (q *ArrayQueue[T]) Size() int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -308,7 +308,7 @@ func main() {
```go
func (q *ArrayQueue[T]) IsEmpty() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -341,7 +341,7 @@ func main() {
```go
func (q *ArrayQueue[T]) IsFull() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -373,7 +373,7 @@ func main() {
```go
func (q *ArrayQueue[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -404,7 +404,7 @@ func main() {
```go
func (q *ArrayQueue[T]) Contain(value T) bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -448,7 +448,7 @@ type QueueNode[T any] struct {
Next *QueueNode[T]
}
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -474,7 +474,7 @@ func main() {
```go
func (q *LinkedQueue[T]) Data() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -501,7 +501,7 @@ func main() {
```go
func (q *LinkedQueue[T]) Enqueue(value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -532,7 +532,7 @@ func main() {
```go
func (q *LinkedQueue[T]) Dequeue() (T, error)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -564,7 +564,7 @@ func main() {
```go
func (q *LinkedQueue[T]) Front() (*T, error)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -596,7 +596,7 @@ func main() {
```go
func (q *LinkedQueue[T]) Back() (*T, error)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -627,7 +627,7 @@ func main() {
```go
func (q *LinkedQueue[T]) Size() int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -657,7 +657,7 @@ func main() {
```go
func (q *LinkedQueue[T]) IsEmpty() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -690,7 +690,7 @@ func main() {
```go
func (q *LinkedQueue[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -721,7 +721,7 @@ func main() {
```go
func (q *LinkedQueue[T]) Contain(value T) bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -763,7 +763,7 @@ type CircularQueue[T any] struct {
capacity int
}
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -789,7 +789,7 @@ func main() {
```go
func (q *CircularQueue[T]) Data() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -816,7 +816,7 @@ func main() {
```go
func (q *CircularQueue[T]) Enqueue(value T) error
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -847,7 +847,7 @@ func main() {
```go
func (q *CircularQueue[T]) Dequeue() (*T, bool)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -880,7 +880,7 @@ func main() {
```go
func (q *CircularQueue[T]) Front() T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -912,7 +912,7 @@ func main() {
```go
func (q *CircularQueue[T]) Back() T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -943,7 +943,7 @@ func main() {
```go
func (q *CircularQueue[T]) Size() int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -973,7 +973,7 @@ func main() {
```go
func (q *CircularQueue[T]) IsEmpty() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1006,7 +1006,7 @@ func main() {
```go
func (q *CircularQueue[T]) IsFull() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1038,7 +1038,7 @@ func main() {
```go
func (q *CircularQueue[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1069,7 +1069,7 @@ func main() {
```go
func (q *CircularQueue[T]) Contain(value T) bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1108,7 +1108,7 @@ type PriorityQueue[T any] struct {
comparator lancetconstraints.Comparator
}
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1134,7 +1134,7 @@ func main() {
```go
func (q *PriorityQueue[T]) Data() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1161,7 +1161,7 @@ func main() {
```go
func (q *PriorityQueue[T]) Enqueue(item T) bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1207,7 +1207,7 @@ func main() {
```go
func (q *PriorityQueue[T]) Dequeue() (T, bool)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1254,7 +1254,7 @@ func main() {
```go
func (q *PriorityQueue[T]) IsEmpty() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1301,7 +1301,7 @@ func main() {
```go
func (q *PriorityQueue[T]) IsFull() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -1348,7 +1348,7 @@ func main() {
```go
func (q *PriorityQueue[T]) Size() int
```
<b>例:</b>
<b>例:</b>
```go
package main

View File

@@ -1,16 +1,17 @@
# Set
Set集合数据结构类似列表。Set中元素不重复。
Set 集合数据结构类似列表。Set 中元素不重复。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
set "github.com/duke-git/lancet/v2/datastructure/set"
@@ -21,39 +22,41 @@ import (
## 目录
- [NewSet](#NewSet)
- [Values](#Values)
- [Add](#Add)
- [Delete](#Delete)
- [Contain](#Contain)
- [ContainAll](#ContainAll)
- [Clone](#Clone)
- [Size](#Size)
- [Equal](#Equal)
- [Iterate](#Iterate)
- [IsEmpty](#IsEmpty)
- [Union](#Union)
- [Intersection](#Intersection)
- [SymmetricDifference](#SymmetricDifference)
- [Minus](#Minus)
- [NewSet](#NewSet)
- [NewSetFromSlice](#NewSetFromSlice)
- [Values](#Values)
- [Add](#Add)
- [AddIfNotExist](#AddIfNotExist)
- [AddIfNotExistBy](#AddIfNotExistBy)
- [Delete](#Delete)
- [Contain](#Contain)
- [ContainAll](#ContainAll)
- [Clone](#Clone)
- [Size](#Size)
- [Equal](#Equal)
- [Iterate](#Iterate)
- [IsEmpty](#IsEmpty)
- [Union](#Union)
- [Intersection](#Intersection)
- [SymmetricDifference](#SymmetricDifference)
- [Minus](#Minus)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="NewSet">NewSet</span>
<p>返回Set结构体对象</p>
<b>函数签名:</b>
```go
type Set[T comparable] map[T]bool
func NewSet[T comparable](values ...T) Set[T]
func NewSet[T comparable](items ...T) Set[T]
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -69,10 +72,34 @@ func main() {
}
```
### <span id="NewSetFromSlice">NewSetFromSlice</span>
<p>基于切片创建集合</p>
<b>函数签名:</b>
```go
func NewSetFromSlice[T comparable](items []T) Set[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSetFromSlice([]int{1, 2, 2, 3})
fmt.Println(st.Values()) //1,2,3
}
```
### <span id="Values">Values</span>
<p>获取集合中所有元素的切片</p>
<b>函数签名:</b>
@@ -80,7 +107,8 @@ func main() {
```go
func (s Set[T]) Values() []T
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -96,18 +124,17 @@ func main() {
}
```
### <span id="Add">Add</span>
<p>向集合中添加元素</p>
<b>函数签名:</b>
```go
func (s Set[T]) Add(values ...T)
func (s Set[T]) Add(items ...T)
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -125,17 +152,89 @@ func main() {
}
```
### <span id="AddIfNotExist">AddIfNotExist</span>
<p>如果集合中不存在元素则添加该元素返回true, 如果集合中存在元素, 不做任何操作返回false</p>
<b>函数签名:</b>
```go
func (s Set[T]) AddIfNotExist(item T) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSet[int]()
st.Add(1, 2, 3)
r1 := st.AddIfNotExist(1)
r2 := st.AddIfNotExist(4)
fmt.Println(r1) // false
fmt.Println(r2) // true
fmt.Println(st.Values()) // 1,2,3,4
}
```
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
<p>根据checker函数判断元素是否在集合中如果集合中不存在元素且checker返回true则添加该元素返回true, 否则不做任何操作返回false</p>
<b>函数签名:</b>
```go
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
st := set.NewSet[int]()
st.Add(1, 2)
ok := st.AddIfNotExistBy(3, func(val int) bool {
return val%2 != 0
})
fmt.Println(ok) // true
notOk := st.AddIfNotExistBy(4, func(val int) bool {
return val%2 != 0
})
fmt.Println(notOk) // false
fmt.Println(st.Values()) // 1, 2, 3
}
```
### <span id="Delete">Delete</span>
<p>删除集合中元素</p>
<b>函数签名:</b>
```go
func (s Set[T]) Delete(values ...T)
func (s Set[T]) Delete(items ...T)
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -154,17 +253,17 @@ func main() {
}
```
### <span id="Contain">Contain</span>
<p>判断集合是否包含某个值</p>
<b>函数签名:</b>
```go
func (s Set[T]) Contain(value T) bool
func (s Set[T]) Contain(item T) bool
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -183,10 +282,8 @@ func main() {
}
```
### <span id="ContainAll">ContainAll</span>
<p>判断集合是否包含另一个集合</p>
<b>函数签名:</b>
@@ -194,7 +291,8 @@ func main() {
```go
func (s Set[T]) ContainAll(other Set[T]) bool
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -206,17 +304,16 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(1, 2)
set3 := set.NewSet(1, 2, 3, 4)
set2 := set.NewSet(1, 2)
set3 := set.NewSet(1, 2, 3, 4)
fmt.Println(set1.ContainAll(set2)) //true
fmt.Println(set1.ContainAll(set3)) //false
}
```
### <span id="Size">Size</span>
<p>获取集合中元素的个数</p>
<b>函数签名:</b>
@@ -224,7 +321,8 @@ func main() {
```go
func (s Set[T]) Size() int
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -241,9 +339,8 @@ func main() {
}
```
### <span id="Clone">Clone</span>
<p>克隆一个集合</p>
<b>函数签名:</b>
@@ -251,7 +348,8 @@ func main() {
```go
func (s Set[T]) Clone() Set[T]
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -270,10 +368,8 @@ func main() {
}
```
### <span id="Equal">Equal</span>
<p>比较两个集合是否相等,包含相同元素为相等</p>
<b>函数签名:</b>
@@ -281,7 +377,8 @@ func main() {
```go
func (s Set[T]) Equal(other Set[T]) bool
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -301,17 +398,17 @@ func main() {
}
```
### <span id="Iterate">Iterate</span>
<p>迭代结合,在每个元素上调用函数</p>
<b>函数签名:</b>
```go
func (s Set[T]) Iterate(fn func(value T))
func (s Set[T]) Iterate(fn func(item T))
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -324,17 +421,53 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
arr := []int{}
set.Iterate(func(value int) {
arr = append(arr, value)
set.Iterate(func(item int) {
arr = append(arr, item)
})
fmt.Println(arr) //1,2,3
}
```
### <span id="EachWithBreak">EachWithBreak</span>
<p>遍历集合的元素并为每个元素调用iteratee函数当iteratee函数返回false时终止遍历。</p>
<b>函数签名:</b>
```go
func (s Set[T]) EachWithBreak(iteratee func(item T) bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
s := set.NewSet(1, 2, 3, 4, 5)
var sum int
s.EachWithBreak(func(n int) bool {
if n > 3 {
return false
}
sum += n
return true
})
fmt.Println(sum) //6
}
```
### <span id="IsEmpty">IsEmpty</span>
<p>判断集合是否为空</p>
<b>函数签名:</b>
@@ -342,7 +475,8 @@ func main() {
```go
func (s Set[T]) IsEmpty() bool
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -361,9 +495,8 @@ func main() {
}
```
### <span id="Union">Union</span>
<p>求两个集合的并集</p>
<b>函数签名:</b>
@@ -371,7 +504,8 @@ func main() {
```go
func (s Set[T]) Union(other Set[T]) Set[T]
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -390,9 +524,8 @@ func main() {
}
```
### <span id="Intersection">Intersection</span>
<p>求两个集合的交集</p>
<b>函数签名:</b>
@@ -400,7 +533,8 @@ func main() {
```go
func (s Set[T]) Intersection(other Set[T]) Set[T]
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -419,11 +553,8 @@ func main() {
}
```
### <span id="SymmetricDifference">SymmetricDifference</span>
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>
<b>函数签名:</b>
@@ -431,7 +562,8 @@ func main() {
```go
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -443,18 +575,15 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set1.SymmetricDifference(set2)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set1.SymmetricDifference(set2)
fmt.Println(set3.Values()) //1,4,5
}
```
### <span id="Minus">Minus</span>
<p>创建一个集合,其元素在原始集中但不在比较集中</p>
<b>函数签名:</b>
@@ -462,7 +591,8 @@ func main() {
```go
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
```
<b>例子:</b>
<b>示例:</b>
```go
package main
@@ -474,8 +604,8 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set.NewSet(2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set.NewSet(2, 3)
res1 := set1.Minus(set2)
fmt.Println(res1.Values()) //1
@@ -485,5 +615,35 @@ func main() {
}
```
### <span id="Pop">Pop</span>
<p>删除并返回集合中的顶部元素</p>
<b>函数签名:</b>
```go
func (s Set[T]) Pop() (v T, ok bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
s := set.NewSet[int]()
s.Add(1)
s.Add(2)
s.Add(3)
val, ok = s.Pop()
fmt.Println(val) // 3
fmt.Println(ok) // true
}
```

View File

@@ -64,7 +64,7 @@ type ArrayStack[T any] struct {
}
func NewArrayStack[T any]() *ArrayStack[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -91,7 +91,7 @@ func main() {
```go
func (s *ArrayStack[T]) Push(value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -122,7 +122,7 @@ func main() {
```go
func (s *ArrayStack[T]) Pop() (*T, error)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -157,7 +157,7 @@ func main() {
```go
func (s *ArrayStack[T]) Peak() (*T, error)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -192,7 +192,7 @@ func main() {
```go
func (s *ArrayStack[T]) Data() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -223,7 +223,7 @@ func main() {
```go
func (s *ArrayStack[T]) Size() int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -254,7 +254,7 @@ func main() {
```go
func (s *ArrayStack[T]) IsEmpty() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -287,7 +287,7 @@ func main() {
```go
func (s *ArrayStack[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -331,7 +331,7 @@ type LinkedStack[T any] struct {
}
func NewLinkedStack[T any]() *LinkedStack[T]
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -358,7 +358,7 @@ func main() {
```go
func (s *LinkedStack[T]) Push(value T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -389,7 +389,7 @@ func main() {
```go
func (s *LinkedStack[T]) Pop() (*T, error)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -424,7 +424,7 @@ func main() {
```go
func (s *LinkedStack[T]) Peak() (*T, error)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -459,7 +459,7 @@ func main() {
```go
func (s *LinkedStack[T]) Data() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -490,7 +490,7 @@ func main() {
```go
func (s *LinkedStack[T]) Size() int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -521,7 +521,7 @@ func main() {
```go
func (s *LinkedStack[T]) IsEmpty() bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -554,7 +554,7 @@ func main() {
```go
func (s *LinkedStack[T]) Clear()
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -588,7 +588,7 @@ func main() {
```go
func (s *LinkedStack[T]) Print()
```
<b>例:</b>
<b>例:</b>
```go
package main

View File

@@ -29,7 +29,6 @@ import (
- [PreOrderTraverse](#BSTree_PreOrderTraverse)
- [InOrderTraverse](#BSTree_InOrderTraverse)
- [PostOrderTraverse](#BSTree_PostOrderTraverse)
- [LevelOrderTraverse](#BSTree_LevelOrderTraverse)
- [Depth](#BSTree_Depth)
- [HasSubTree](#BSTree_HasSubTree)
@@ -63,7 +62,7 @@ type TreeNode[T any] struct {
Right *TreeNode[T]
}
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -104,7 +103,7 @@ func main() {
```go
func (t *BSTree[T]) Insert(data T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -150,7 +149,7 @@ func main() {
```go
func (t *BSTree[T]) Delete(data T)
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -198,7 +197,7 @@ func main() {
```go
func (t *BSTree[T]) PreOrderTraverse() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -244,7 +243,7 @@ func main() {
```go
func (t *BSTree[T]) InOrderTraverse() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -290,7 +289,7 @@ func main() {
```go
func (t *BSTree[T]) PostOrderTraverse() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -336,7 +335,7 @@ func main() {
```go
func (t *BSTree[T]) LevelOrderTraverse() []T
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -382,7 +381,7 @@ func main() {
```go
func (t *BSTree[T]) Depth() int
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -428,7 +427,7 @@ func main() {
```go
func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool
```
<b>例:</b>
<b>例:</b>
```go
package main
@@ -480,7 +479,7 @@ func main() {
```go
func (t *BSTree[T]) Print()
```
<b>例:</b>
<b>例:</b>
```go
package main

View File

@@ -1,390 +0,0 @@
# Concurrency
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/concurrency"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
### Channel
- [NewChannel](#NewChannel)
- [Bridge](#Bridge)
- [FanIn](#FanIn)
- [Generate](#Generate)
- [Or](#Or)
- [OrDone](#OrDone)
- [Repeat](#Repeat)
- [RepeatFn](#RepeatFn)
- [Take](#Take)
- [Tee](#Tee)
<div STYLE="page-break-after: always;"></div>
## Documentation
## Channel
### <span id="NewChannel">NewChannel</span>
<p>return a Channel pointer instance.</p>
<b>Signature:</b>
```go
type Channel struct {}
func NewChannel() *Channel
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
c := concurrency.NewChannel()
}
```
### <span id="Bridge">Bridge</span>
<p>Link multiple channels into one channel until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
stream <- i
close(stream)
chanStream <- stream
}
}()
return chanStream
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
}
}
```
### <span id="FanIn">FanIn</span>
<p>merge multiple channels into one channel until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
channels := make([]<-chan any, 3)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
}
mergedChannel := c.FanIn(ctx, channels...)
for val := range mergedChannel {
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
}
}
```
### <span id="Repeat">Repeat</span>
<p>Return a chan, put param `values` into the chan repeatly until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
for v := range intStream {
fmt.Println(v) //1, 2, 1, 2, 1
}
}
```
### <span id="RepeatFn">RepeatFn</span>
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
<b>Signature:</b>
```go
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
s := "a"
return s
}
c := concurrency.NewChannel()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range dataStream {
fmt.Println(v) //a, a, a
}
}
```
### <span id="Or">Or</span>
<p>Read one or more channels into one channel, will close when any readin channel is closed.</p>
<b>Signature:</b>
```go
func (c *Channel) Or(channels ...<-chan any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := concurrency.NewChannel()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
sig(4*time.Second),
sig(5*time.Second),
)
fmt.Println("done after %v", time.Since(start)) //1.003s
}
```
### <span id="OrDone">OrDone</span>
<p>Read a channel into another channel, will close until cancel context.</p>
<b>Signature:</b>
```go
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for val := range c.OrDone(ctx, intStream) {
fmt.Println(val) //1
}
}
```
### <span id="Take">Take</span>
<p>Return a chan whose values are tahken from another chan until cancel context.</p>
<b>Signature:</b>
```go
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel()
intStream := c.Take(ctx, numbers, 3)
for val := range intStream {
fmt.Println(val) //1, 2, 3
}
}
```
### <span id="Tee">Tee</span>
<p>Split one chanel into two channels until cancel context.</p>
<b>Signature:</b>
```go
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
fmt.Println(val) //1
fmt.Println(<-out2) //1
}
}
```

View File

@@ -1,390 +0,0 @@
# Concurrency
并发包包含一些支持并发编程的功能。例如goroutine, channel, async等。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/concurrency"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
### Channel
- [NewChannel](#NewChannel)
- [Bridge](#Bridge)
- [FanIn](#FanIn)
- [Generate](#Generate)
- [Or](#Or)
- [OrDone](#OrDone)
- [Repeat](#Repeat)
- [RepeatFn](#RepeatFn)
- [Take](#Take)
- [Tee](#Tee)
<div STYLE="page-break-after: always;"></div>
## 文档
### Channel
### <span id="NewChannel">NewChannel</span>
<p>返回一个 Channel 指针实例</p>
<b>函数签名:</b>
```go
type Channel struct {}
func NewChannel() *Channel
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
c := concurrency.NewChannel()
}
```
### <span id="Bridge">Bridge</span>
<p>将多个通道链接到一个通道,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
stream <- i
close(stream)
chanStream <- stream
}
}()
return chanStream
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
}
}
```
### <span id="FanIn">FanIn</span>
<p>将多个通道合并为一个通道,直到取消上下文</p>
<b>函数签名:</b>
```go
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
channels := make([]<-chan any, 3)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
}
mergedChannel := c.FanIn(ctx, channels...)
for val := range mergedChannel {
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
}
}
```
### <span id="Repeat">Repeat</span>
<p>返回一个chan将参数`values`重复放入chan直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
for v := range intStream {
fmt.Println(v) //1, 2, 1, 2, 1
}
}
```
### <span id="RepeatFn">RepeatFn</span>
<p>返回一个chan重复执行函数fn并将结果放入返回的chan直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
s := "a"
return s
}
c := concurrency.NewChannel()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range dataStream {
fmt.Println(v) //a, a, a
}
}
```
### <span id="Or">Or</span>
<p>将一个或多个通道读取到一个通道中,当任何读取通道关闭时将结束读取。</p>
<b>函数签名:</b>
```go
func (c *Channel) Or(channels ...<-chan any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := concurrency.NewChannel()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
sig(4*time.Second),
sig(5*time.Second),
)
fmt.Println("done after %v", time.Since(start)) //1.003s
}
```
### <span id="OrDone">OrDone</span>
<p>将一个通道读入另一个通道,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for val := range c.OrDone(ctx, intStream) {
fmt.Println(val) //1
}
}
```
### <span id="Take">Take</span>
<p>返回一个chan其值从另一个chan获取直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel()
intStream := c.Take(ctx, numbers, 3)
for val := range intStream {
fmt.Println(val) //1, 2, 3
}
}
```
### <span id="Tee">Tee</span>
<p>将一个通道分成两个通道,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
fmt.Println(val) //1
fmt.Println(<-out2) //1
}
}
```

View File

@@ -1,349 +0,0 @@
# Convertor
Package convertor contains some functions for data type convertion.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/convertor"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>Convert color hex to color rgb.</p>
<b>Signature:</b>
```go
func ColorHexToRGB(colorHex string) (red, green, blue int)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b) //0,51,102
}
```
### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>Convert color rgb to color hex.</p>
<b>Signature:</b>
```go
func ColorRGBToHex(red, green, blue int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
r := 0
g := 51
b := 102
colorHex := convertor.ColorRGBToHex(r, g, b)
fmt.Println(colorHex) //#003366
}
```
### <span id="ToBool">ToBool</span>
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
<b>Signature:</b>
```go
func ToBool(s string) (bool, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v1, _ := convertor.ToBool("1")
fmt.Println(v1) //true
v2, _ := convertor.ToBool("true")
fmt.Println(v2) //true
v3, _ := convertor.ToBool("True")
fmt.Println(v3) //true
v4, _ := convertor.ToBool("123")
fmt.Println(v4) //false
}
```
### <span id="ToBytes">ToBytes</span>
<p>Convert interface to byte slice.</p>
<b>Signature:</b>
```go
func ToBytes(data any) ([]byte, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
bytesData, err := convertor.ToBytes("0")
if err != nil {
fmt.Println(err)
}
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
}
```
### <span id="ToChar">ToChar</span>
<p>Convert string to char slice.</p>
<b>Signature:</b>
```go
func ToChar(s string) []string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
chars := convertor.ToChar("")
fmt.Println(chars) //[]string{""}
chars = convertor.ToChar("abc")
fmt.Println(chars) //[]string{"a", "b", "c"}
chars = convertor.ToChar("1 2#3")
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"}
}
```
### <span id="ToFloat">ToFloat</span>
<p>Convert interface to a float64 value. If param is a invalid floatable, will return 0 and error. </p>
<b>Signature:</b>
```go
func ToFloat(value any) (float64, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v, err := convertor.ToFloat("")
if err != nil {
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax
}
fmt.Println(v) //0
v, _ = convertor.ToFloat("-.11")
fmt.Println(v) //-0.11
}
```
### <span id="ToInt">ToInt</span>
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
<b>Signature:</b>
```go
func ToInt(value any) (int64, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v, err := convertor.ToInt("")
if err != nil {
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax
}
fmt.Println(v) //0
v, _ = convertor.ToFloat(1.12)
fmt.Println(v) //1
}
```
### <span id="ToJson">ToJson</span>
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
<b>Signature:</b>
```go
func ToJson(value any) (string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
jsonStr, _ := convertor.ToJson(aMap)
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
}
```
### <span id="ToString">ToString</span>
<p>Convert interface to string. </p>
<b>Signature:</b>
```go
func ToString(value any) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
fmt.Printf("%q", convertor.ToString(1)) //"1"
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1"
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]"
}
```
### <span id="StructToMap">StructToMap</span>
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
<b>Signature:</b>
```go
func StructToMap(value any) (map[string]any, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := convertor.StructToMap(p)
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
}
```

View File

@@ -1,351 +0,0 @@
# Convertor
convertor转换器包支持一些常见的数据类型转换
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/convertor"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>颜色值十六进制转rgb</p>
<b>函数签名:</b>
```go
func ColorHexToRGB(colorHex string) (red, green, blue int)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b) //0,51,102
}
```
### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>颜色值rgb转十六进制</p>
<b>函数签名:</b>
```go
func ColorRGBToHex(red, green, blue int) string
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
r := 0
g := 51
b := 102
colorHex := convertor.ColorRGBToHex(r, g, b)
fmt.Println(colorHex) //#003366
}
```
### <span id="ToBool">ToBool</span>
<p>字符串转布尔类型使用strconv.ParseBool</p>
<b>函数签名:</b>
```go
func ToBool(s string) (bool, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v1, _ := convertor.ToBool("1")
fmt.Println(v1) //true
v2, _ := convertor.ToBool("true")
fmt.Println(v2) //true
v3, _ := convertor.ToBool("True")
fmt.Println(v3) //true
v4, _ := convertor.ToBool("123")
fmt.Println(v4) //false
}
```
### <span id="ToBytes">ToBytes</span>
<p>interface转字节切片.</p>
<b>函数签名:</b>
```go
func ToBytes(data any) ([]byte, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
bytesData, err := convertor.ToBytes("0")
if err != nil {
fmt.Println(err)
}
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
}
```
### <span id="ToChar">ToChar</span>
<p>字符串转字符切片</p>
<b>函数签名:</b>
```go
func ToChar(s string) []string
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
chars := convertor.ToChar("")
fmt.Println(chars) //[]string{""}
chars = convertor.ToChar("abc")
fmt.Println(chars) //[]string{"a", "b", "c"}
chars = convertor.ToChar("1 2#3")
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"}
}
```
### <span id="ToFloat">ToFloat</span>
<p>将interface转成float64类型如果参数无法转换会返回0和error</p>
<b>函数签名:</b>
```go
func ToFloat(value any) (float64, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v, err := convertor.ToFloat("")
if err != nil {
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax
}
fmt.Println(v) //0
v, _ = convertor.ToFloat("-.11")
fmt.Println(v) //-0.11
}
```
### <span id="ToInt">ToInt</span>
<p>将interface转成intt64类型如果参数无法转换会返回0和error</p>
<b>函数签名:</b>
```go
func ToInt(value any) (int64, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v, err := convertor.ToInt("")
if err != nil {
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax
}
fmt.Println(v) //0
v, _ = convertor.ToFloat(1.12)
fmt.Println(v) //1
}
```
### <span id="ToJson">ToJson</span>
<p>将interface转成json字符串如果参数无法转换会返回""和error</p>
<b>函数签名:</b>
```go
func ToJson(value any) (string, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
jsonStr, _ := convertor.ToJson(aMap)
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
}
```
### <span id="ToString">ToString</span>
<p>将interface转成字符串</p>
<b>函数签名:</b>
```go
func ToString(value any) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
fmt.Printf("%q", convertor.ToString(1)) //"1"
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1"
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]"
}
```
### <span id="StructToMap">StructToMap</span>
<p>将struct转成map只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p>
<b>函数签名:</b>
```go
func StructToMap(value any) (map[string]any, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := convertor.StructToMap(p)
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
}
```

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