1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-04 21:02:27 +08:00

Compare commits

..

288 Commits

Author SHA1 Message Date
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
dudaodong
0b05a6dd6f release: v2.0.9 2022-06-15 15:27:01 +08:00
dudaodong
d21c101caf refactor: change function name EqualWithFunc to EqualWith 2022-06-15 15:25:44 +08:00
dudaodong
bf49db60d9 docs: change function name EqualWithFunc to EqualWith 2022-06-15 15:24:58 +08:00
dudaodong
d57fa3b603 docs: update readme file add new functions 2022-06-15 15:23:30 +08:00
dudaodong
b3a29ce82d docs: add doc for function Equal and EqualWithFunc 2022-06-13 15:14:37 +08:00
dudaodong
1d8a37d6e8 docs: add doc for function CreateDir 2022-06-13 15:00:12 +08:00
dudaodong
ef2d8e14b0 feat: add EqualWithFunc function for slice 2022-06-13 14:15:32 +08:00
dudaodong
0cbb3dd97e feat: add Equal function for slice 2022-06-13 14:06:20 +08:00
dudaodong
38a7f9423f fmt: gofmt package datastructure/queue 2022-06-08 14:40:37 +08:00
dudaodong
2c0ab9e922 feat: add CreateDir function in file.go 2022-06-08 14:38:35 +08:00
168 changed files with 18169 additions and 3549 deletions

1
.gitignore vendored
View File

@@ -6,4 +6,5 @@ fileutil/*.txt
fileutil/*.zip
fileutil/*.link
fileutil/unzip/*
slice/testdata/*
cryptor/*.pem

1245
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

@@ -9,13 +9,13 @@ import (
func TestLRUCache(t *testing.T) {
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 +25,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: Todo
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,24 @@ import (
"github.com/duke-git/lancet/v2/internal"
)
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
func TestLinearSearch(t *testing.T) {
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) {
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 +31,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,8 +45,6 @@ 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) {
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
@@ -76,6 +66,7 @@ func TestBubbleSortForStructSlice(t *testing.T) {
func TestBubbleSortForIntSlice(t *testing.T) {
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
BubbleSort(numbers, comparator)
@@ -151,7 +142,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)

View File

@@ -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: Todo
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: Todo
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: Todo
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: Todo
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: Todo
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: Todo
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: Todo
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: Todo
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: Todo
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

@@ -14,12 +14,9 @@ func TestGenerate(t *testing.T) {
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)
@@ -31,12 +28,9 @@ func TestRepeat(t *testing.T) {
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)
@@ -50,17 +44,13 @@ func TestRepeatFn(t *testing.T) {
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)
@@ -72,7 +62,7 @@ func TestTake(t *testing.T) {
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 +70,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)
@@ -94,8 +84,8 @@ func TestFanIn(t *testing.T) {
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)
@@ -124,7 +114,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,9 +123,7 @@ 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) {
@@ -144,16 +132,12 @@ func TestOrDone(t *testing.T) {
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) {
@@ -162,15 +146,13 @@ func TestTee(t *testing.T) {
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)
}
@@ -182,13 +164,13 @@ func TestBridge(t *testing.T) {
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

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
}

119
condition/condition_test.go Normal file
View File

@@ -0,0 +1,119 @@
package condition
import (
"errors"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
type TestStruct struct{}
func TestBool(t *testing.T) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
assert := internal.NewAssert(t, "TernaryOperator")
trueValue := "1"
falseValue := "0"
assert.Equal(trueValue, TernaryOperator(true, trueValue, falseValue))
}

View File

@@ -7,6 +7,7 @@ package convertor
import (
"bytes"
"encoding/binary"
"encoding/gob"
"encoding/json"
"fmt"
"math"
@@ -16,12 +17,14 @@ import (
"strings"
)
// 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 +65,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,104 +78,161 @@ 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)
@@ -183,7 +244,7 @@ func StructToMap(value any) (map[string]any, error) {
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
}
res := make(map[string]any)
result := make(map[string]any)
fieldNum := t.NumField()
pattern := `^[A-Z]`
@@ -192,15 +253,28 @@ func StructToMap(value any) (map[string]any, error) {
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()
//result[name] = v.Field(i).Interface()
result[tag] = v.Field(i).Interface()
}
}
return res, nil
return result, nil
}
// 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 +285,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 +304,23 @@ 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)
}

View File

@@ -0,0 +1,254 @@
package convertor
import (
"fmt"
"strconv"
)
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
}

View File

@@ -2,9 +2,11 @@ package convertor
import (
"fmt"
"strconv"
"testing"
"github.com/duke-git/lancet/v2/internal"
"github.com/duke-git/lancet/v2/slice"
)
func TestToChar(t *testing.T) {
@@ -21,6 +23,18 @@ func TestToChar(t *testing.T) {
}
}
func TestToChannel(t *testing.T) {
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) {
assert := internal.NewAssert(t, "TestToBool")
@@ -118,9 +132,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])
@@ -142,6 +157,25 @@ func TestToJson(t *testing.T) {
assert.Equal("{\"Name\":\"TestStruct\"}", structJsonStr)
}
func TestToMap(t *testing.T) {
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) {
assert := internal.NewAssert(t, "TestStructToMap")
@@ -154,10 +188,25 @@ func TestStructToMap(t *testing.T) {
100,
}
pm, _ := StructToMap(p)
var expected = map[string]any{"name": "test"}
expected := map[string]any{"name": "test"}
assert.Equal(expected, pm)
}
func TestMapToSlice(t *testing.T) {
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) {
colorHex := "#003366"
r, g, b := ColorHexToRGB(colorHex)
@@ -178,3 +227,29 @@ func TestColorRGBToHex(t *testing.T) {
assert := internal.NewAssert(t, "TestColorRGBToHex")
assert.Equal(expected, colorHex)
}
func TestToPointer(t *testing.T) {
assert := internal.NewAssert(t, "TestToPointer")
result := ToPointer(123)
assert.Equal(*result, 123)
}
func TestEncodeByte(t *testing.T) {
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) {
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)
}

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,28 @@ 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
// Md5File return the md5 value of file.
func Md5File(filename string) (string, error) {
if fileInfo, err := os.Stat(filename); err != nil {
return "", err
@@ -69,49 +72,56 @@ func Md5File(filename string) (string, error) {
return checksum, nil
}
// HmacMd5 return the hmac hash of string use md5
// HmacMd5 return the hmac hash of string use md5.
// Play: https://go.dev/play/p/uef0q1fz53I
func HmacMd5(data, key string) string {
h := hmac.New(md5.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha1 return the hmac hash of string use sha1
// HmacSha1 return the hmac hash of string use sha1.
// Play: https://go.dev/play/p/1UI4oQ4WXKM
func HmacSha1(data, key string) string {
h := hmac.New(sha1.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha256 return the hmac hash of string use sha256
// HmacSha256 return the hmac hash of string use sha256.
// Play: https://go.dev/play/p/HhpwXxFhhC0
func HmacSha256(data, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha512 return the hmac hash of string use sha512
// HmacSha512 return the hmac hash of string use sha512.
// Play: https://go.dev/play/p/59Od6m4A0Ud
func HmacSha512(data, key string) string {
h := hmac.New(sha512.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string.
// Play: https://go.dev/play/p/_m_uoD1deMT
func Sha1(data string) string {
sha1 := sha1.New()
sha1.Write([]byte(data))
return hex.EncodeToString(sha1.Sum([]byte("")))
}
// Sha256 return the sha256 value (SHA256 hash algorithm) of string
// Sha256 return the sha256 value (SHA256 hash algorithm) of string.
// Play: https://go.dev/play/p/tU9tfBMIAr1
func Sha256(data string) string {
sha256 := sha256.New()
sha256.Write([]byte(data))
return hex.EncodeToString(sha256.Sum([]byte("")))
}
// Sha512 return the sha512 value (SHA512 hash algorithm) of string
// Sha512 return the sha512 value (SHA512 hash algorithm) of string.
// Play: https://go.dev/play/p/3WsvLYZxsHa
func Sha512(data string) string {
sha512 := sha512.New()
sha512.Write([]byte(data))

View File

@@ -0,0 +1,410 @@
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 ExampleHmacSha1() {
str := "hello"
key := "12345"
hms := HmacSha1(str, key)
fmt.Println(hms)
// Output:
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
}
func ExampleHmacSha256() {
str := "hello"
key := "12345"
hms := HmacSha256(str, key)
fmt.Println(hms)
// Output:
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
}
func ExampleHmacSha512() {
str := "hello"
key := "12345"
hms := HmacSha512(str, key)
fmt.Println(hms)
// Output:
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
}
func ExampleMd5String() {
str := "hello"
md5Str := Md5String(str)
fmt.Println(md5Str)
// Output:
// 5d41402abc4b2a76b9719d911017c592
}
func ExampleSha1() {
str := "hello"
result := Sha1(str)
fmt.Println(result)
// Output:
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
}
func ExampleSha256() {
str := "hello"
result := Sha256(str)
fmt.Println(result)
// Output:
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
}
func ExampleSha512() {
str := "hello"
result := Sha512(str)
fmt.Println(result)
// Output:
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
}

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

498
cryptor/encrypt.go Normal file
View File

@@ -0,0 +1,498 @@
// 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 {
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))
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 {
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.
// 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
}

130
cryptor/encrypt_test.go Normal file
View File

@@ -0,0 +1,130 @@
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))
}
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))
}
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

@@ -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,175 @@
// 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
import (
"fmt"
"hash/fnv"
)
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]
if node != nil {
return node.value
}
return nil
}
// 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)]
return node != nil
}
// 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,71 @@
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) {
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) {
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) {
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()
t.Log(keys, values)
assert.Equal(3, len(values))
assert.Equal(3, len(keys))
}

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. eg. list, linklist, stack, queue, tree, graph.
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,90 @@
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) {
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) {
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) {
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) {
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,12 @@
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 +18,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 +54,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 +85,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 +122,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 +170,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 +199,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 +226,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

@@ -41,29 +41,24 @@ func TestDoublyLink_InsertAt(t *testing.T) {
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) {
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 +66,6 @@ func TestDoublyLink_DeleteAtHead(t *testing.T) {
link.InsertAtTail(4)
link.DeleteAtHead()
link.Print()
expected := []int{2, 3, 4}
values := link.Values()
@@ -83,8 +77,7 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
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 +85,6 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
link.InsertAtTail(4)
link.DeleteAtTail()
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
@@ -104,8 +96,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
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 +104,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)

View File

@@ -1,14 +1,13 @@
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 +19,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 +42,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 +106,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 +174,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 +202,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

@@ -41,25 +41,12 @@ func TestSinglyLink_InsertAt(t *testing.T) {
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()
@@ -73,8 +60,8 @@ func TestSinglyLink_DeleteAtHead(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
link := NewSinglyLink[int]()
err := link.DeleteAtHead()
assert.IsNotNil(err)
link.DeleteAtHead()
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -94,8 +81,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
link := NewSinglyLink[int]()
err := link.DeleteAtTail()
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -103,7 +88,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
link.InsertAtTail(4)
link.DeleteAtTail()
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
@@ -133,8 +117,6 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
link := NewSinglyLink[int]()
err := link.DeleteAt(0)
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -142,11 +124,7 @@ func TestSinglyLink_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)
@@ -167,7 +145,6 @@ func TestSinglyLink_Reverse(t *testing.T) {
link.InsertAtTail(4)
link.Reverse()
link.Print()
assert.Equal([]int{4, 3, 2, 1}, link.Values())
}

View File

@@ -8,17 +8,17 @@ import (
"reflect"
)
// 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 +31,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 +44,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 +97,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 +123,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 +135,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 +148,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 +156,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 +199,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 +214,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 +232,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 +243,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 +262,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 remove 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
@@ -222,24 +294,32 @@ func (l *List[T]) Unique() {
// Union creates a new list contain all element in list l and other, remove 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
}
// 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)
}

View File

@@ -36,6 +36,51 @@ func TestIndexOf(t *testing.T) {
assert.Equal(-1, i)
}
func TestIndexOfFunc(t *testing.T) {
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) {
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) {
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) {
assert := internal.NewAssert(t, "TestContain")
@@ -216,6 +261,18 @@ func TestSize(t *testing.T) {
assert.Equal(0, empty.Size())
}
func TestCap(t *testing.T) {
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) {
assert := internal.NewAssert(t, "TestSwap")
@@ -270,3 +327,33 @@ func TestIntersection(t *testing.T) {
list3 := list1.Intersection(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSubSlice(t *testing.T) {
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) {
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)
}

View File

@@ -33,7 +33,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

@@ -18,8 +18,6 @@ func TestArrayQueue_Enqueue(t *testing.T) {
data := queue.Data()
size := queue.Size()
queue.Print()
assert.Equal(expected, data)
assert.Equal(3, size)
}
@@ -35,7 +33,6 @@ 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())
}
@@ -50,8 +47,6 @@ func TestArrayQueue_Front(t *testing.T) {
val := queue.Front()
queue.Print()
assert.Equal(1, val)
assert.Equal([]int{1, 2, 3}, queue.Data())
}
@@ -66,8 +61,6 @@ func TestArrayQueue_Back(t *testing.T) {
val := queue.Back()
queue.Print()
assert.Equal(3, val)
assert.Equal([]int{1, 2, 3}, queue.Data())
}

View File

@@ -9,10 +9,10 @@ import (
// CircularQueue implements circular queue with slice,
// last index of CircularQueue don't contain value, so acturl capacity is capacity - 1
type CircularQueue[T any] struct {
data []T
front int
rear int
capacity int
data []T
front int
rear int
capacity int
}
// NewCircularQueue return a empty CircularQueue pointer

View File

@@ -10,31 +10,43 @@ func TestCircularQueue_Enqueue(t *testing.T) {
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) {
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,11 +55,7 @@ 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())
}
@@ -55,55 +63,52 @@ func TestCircularQueue_Front(t *testing.T) {
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) {
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) {
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))
}
@@ -115,7 +120,9 @@ func TestCircularQueue_Clear(t *testing.T) {
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())
@@ -127,22 +134,12 @@ func TestCircularQueue_Clear(t *testing.T) {
func TestCircularQueue_Data(t *testing.T) {
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

@@ -42,7 +42,6 @@ func (q *LinkedQueue[T]) IsEmpty() bool {
return q.length == 0
}
// Enqueue put element into queue
func (q *LinkedQueue[T]) Enqueue(value T) {
newNode := datastructure.NewQueueNode(value)

View File

@@ -14,8 +14,6 @@ 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())
}

View File

@@ -23,19 +23,24 @@ func TestPriorityQueue_Enqueue(t *testing.T) {
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)
}
@@ -43,22 +48,23 @@ func TestPriorityQueue_Dequeue(t *testing.T) {
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,62 @@
package datastructure
// Set is a data container, like slice, but element of set is not duplicate
type Set[T comparable] map[T]bool
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 +78,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 +95,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 +113,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

View File

@@ -6,6 +6,19 @@ import (
"github.com/duke-git/lancet/v2/internal"
)
func TestSet_NewSetFromSlice(t *testing.T) {
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) {
assert := internal.NewAssert(t, "TestSet_Add")
@@ -17,6 +30,38 @@ func TestSet_Add(t *testing.T) {
assert.Equal(true, set.Equal(expected))
}
func TestSet_AddIfNotExist(t *testing.T) {
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) {
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) {
assert := internal.NewAssert(t, "TestSet_Contain")

View File

@@ -14,8 +14,6 @@ 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()

View File

@@ -84,20 +84,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

@@ -27,8 +27,6 @@ func TestBSTree_Insert(t *testing.T) {
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
bstree.Print()
}
func TestBSTree_PreOrderTraverse(t *testing.T) {
@@ -86,8 +84,6 @@ 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)
@@ -103,10 +99,8 @@ 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)
@@ -129,8 +123,6 @@ func TestBSTree_Depth(t *testing.T) {
bstree.Insert(2)
bstree.Insert(4)
bstree.Print()
assert.Equal(bstree.Depth(), 4)
}
@@ -150,8 +142,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

@@ -19,9 +19,6 @@ func TestToUnix(t *testing.T) {
func TestToFormat(t *testing.T) {
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")
assert.IsNil(err)

View File

@@ -4,24 +4,24 @@
// 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"
// "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"
package datetime
import (
@@ -54,54 +54,64 @@ func init() {
}
}
// 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
// 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)
// 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
// FormatTimeToStr convert time to string.
// Play: https://go.dev/play/p/_Ia7M8H_OvE
func FormatTimeToStr(t time.Time, format string) string {
return t.Format(timeFormat[format])
}
// FormatStrToTime convert string to time
// FormatStrToTime convert string to time.
// Play: https://go.dev/play/p/1h9FwdU8ql4
func FormatStrToTime(str, format string) (time.Time, error) {
v, ok := timeFormat[format]
if !ok {
@@ -111,72 +121,100 @@ func FormatStrToTime(str, format string) (time.Time, error) {
return time.Parse(v, str)
}
// BeginOfMinute return beginning minute time of day
// 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)
}

View File

@@ -0,0 +1,323 @@
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 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")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 2021-01-02 16:04:08
// 2021-01-02
// 02-01-21 16:04:08
}
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
// }

View File

@@ -52,8 +52,8 @@ func TestGetNowDate(t *testing.T) {
assert.Equal(expected, GetNowDate())
}
func TestGetNotTime(t *testing.T) {
assert := internal.NewAssert(t, "TestGetNotTime")
func TestGetNowTime(t *testing.T) {
assert := internal.NewAssert(t, "TestGetNowTime")
expected := time.Now().Format("15:04:05")
assert.Equal(expected, GetNowTime())
}
@@ -81,7 +81,6 @@ func TestFormatTimeToStr(t *testing.T) {
for i := 0; i < len(cases); i++ {
actual := FormatTimeToStr(datetime, cases[i])
assert.Equal(expected[i], actual)
}
}

View File

@@ -5,7 +5,7 @@ Package algorithm implements some basic algorithm. eg. sort, search.
## 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/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)
@@ -21,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div>
## Index
- [BubbleSort](#BubbleSort)
- [InsertionSort](#InsertionSort)
- [SelectionSort](#SelectionSort)
@@ -31,7 +32,6 @@ import (
- [CountSort](#CountSort)
- [BinarySearch](#BinarySearch)
- [BinaryIterativeSearch](#BinaryIterativeSearch)
- [LinearSearch](#LinearSearch)
- [LRUCache](#LRUCache)
@@ -248,7 +248,7 @@ func main() {
<b>Signature:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator)
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
```
<b>Example:</b>
@@ -278,7 +278,7 @@ func main() {
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
@@ -570,6 +570,8 @@ func main() {
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>Example:</b>
@@ -584,12 +586,16 @@ import (
func main() {
cache := algorithm.NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
cache.Put(1, 1)
cache.Put(2, 2)
cache.Put(3, 3)
_, ok := cache.Get(0) // ok -> false
fmt.Println(cache.Len()) // 3
v, ok := cache.Get(1) // v->1, ok->true
v, ok := cache.Get(1)
fmt.Println(v, ok) // 1 true
ok = cache.Delete(1)
fmt.Println(ok) // true
}
```

View File

@@ -5,7 +5,7 @@ algorithm算法包实现一些基本算法sortsearchlrucache。
## 源码
- [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/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)
@@ -29,7 +29,6 @@ import (
- [QuickSort](#QuickSort)
- [HeapSort](#HeapSort)
- [MergeSort](#MergeSort)
- [CountSort](#CountSort)
- [BinarySearch](#BinarySearch)
- [BinaryIterativeSearch](#BinaryIterativeSearch)
@@ -249,7 +248,7 @@ func main() {
<b>函数签名:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) []T
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
@@ -279,7 +278,7 @@ func main() {
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
@@ -571,6 +570,8 @@ func main() {
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>Example:</b>
@@ -585,12 +586,16 @@ import (
func main() {
cache := algorithm.NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
cache.Put(1, 1)
cache.Put(2, 2)
cache.Put(3, 3)
_, ok := cache.Get(0) // ok -> false
fmt.Println(cache.Len()) // 3
v, ok := cache.Get(1) // v->1, ok->true
v, ok := cache.Get(1)
fmt.Println(v, ok) // 1 true
ok = cache.Delete(1)
fmt.Println(ok) // true
}
```

View File

@@ -38,13 +38,13 @@ import (
## Channel
### <span id="NewChannel">NewChannel</span>
<p>return a Channel pointer instance.</p>
<p>Create a Channel pointer instance.</p>
<b>Signature:</b>
```go
type Channel struct {}
func NewChannel() *Channel
type Channel[T any] struct
func NewChannel[T any]() *Channel[T]
```
<b>Example:</b>
@@ -57,7 +57,7 @@ import (
)
func main() {
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
}
```
@@ -70,7 +70,7 @@ func main() {
<b>Signature:</b>
```go
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
```
<b>Example:</b>
@@ -84,28 +84,33 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
c := concurrency.NewChannel[int]()
genVals := func() <-chan <-chan int {
out := make(chan (<-chan int))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
defer close(out)
for i := 1; i <= 5; i++ {
stream := make(chan int, 1)
stream <- i
close(stream)
chanStream <- stream
out <- stream
}
}()
return chanStream
return out
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
```
@@ -114,12 +119,12 @@ func main() {
### <span id="FanIn">FanIn</span>
<p>merge multiple channels into one channel until cancel the context.</p>
<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
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
```
<b>Example:</b>
@@ -133,20 +138,20 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
channels := make([]<-chan any, 3)
c := concurrency.NewChannel[int]()
channels := make([]<-chan int, 2)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
for i := 0; i < 2; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
}
mergedChannel := c.FanIn(ctx, channels...)
chs := 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)
for v := range chs {
fmt.Println(v) //1 1 0 0 or 0 0 1 1
}
}
```
@@ -154,12 +159,12 @@ func main() {
### <span id="Repeat">Repeat</span>
<p>Return a chan, put param `values` into the chan repeatly until cancel the context.</p>
<p>Create channel, put values into the channel repeatly until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
```
<b>Example:</b>
@@ -173,29 +178,33 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
for v := range intStream {
fmt.Println(v) //1, 2, 1, 2, 1
fmt.Println(v)
}
// Output:
// 1
// 2
// 1
// 2
}
```
### <span id="Generate">Generate</span>
### <span id="RepeatFn">RepeatFn</span>
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
<p>Creates a channel, then put values into the channel.</p>
<b>Signature:</b>
```go
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
```
<b>Example:</b>
@@ -209,19 +218,61 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
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)
c := concurrency.NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
for v := range dataStream {
fmt.Println(v) //a, a, a
fmt.Println(<-intStream)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
// Output:
// 1
// 2
// 3
}
```
### <span id="RepeatFn">RepeatFn</span>
<p>Create a channel, excutes fn repeatly, and put the result into the channel, until close context.</p>
<b>Signature:</b>
```go
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
```
<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() 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
}
```
@@ -234,7 +285,7 @@ func main() {
<b>Signature:</b>
```go
func (c *Channel) Or(channels ...<-chan any) <-chan any
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
```
<b>Example:</b>
@@ -248,8 +299,8 @@ import (
)
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
sig := func(after time.Duration) <-chan any {
c := make(chan any)
go func() {
defer close(c)
time.Sleep(after)
@@ -259,13 +310,11 @@ func main() {
start := time.Now()
c := concurrency.NewChannel()
c := concurrency.NewChannel[any]()
<-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
@@ -282,7 +331,7 @@ func main() {
<b>Signature:</b>
```go
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
```
<b>Example:</b>
@@ -296,15 +345,19 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for val := range c.OrDone(ctx, intStream) {
fmt.Println(val) //1
for v := range c.OrDone(ctx, intStream) {
fmt.Println(v)
}
// Output:
// 1
// 1
// 1
}
```
@@ -313,12 +366,12 @@ func main() {
### <span id="Take">Take</span>
<p>Return a chan whose values are tahken from another chan until cancel context.</p>
<p>Create a channel whose values are taken from another channel with limit number.</p>
<b>Signature:</b>
```go
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
```
<b>Example:</b>
@@ -332,10 +385,10 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
@@ -343,12 +396,16 @@ func main() {
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
for val := range intStream {
fmt.Println(val) //1, 2, 3
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}
```
@@ -356,12 +413,12 @@ func main() {
### <span id="Tee">Tee</span>
<p>Split one chanel into two channels until cancel context.</p>
<p>Split one chanel into two channels, until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
```
<b>Example:</b>
@@ -375,16 +432,22 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
fmt.Println(val) //1
fmt.Println(<-out2) //1
ch1, ch2 := c.Tee(ctx, intStream)
for v := range ch1 {
fmt.Println(v)
fmt.Println(<-ch2)
}
// Output:
// 1
// 1
// 1
// 1
}
```

View File

@@ -38,13 +38,13 @@ import (
### Channel
### <span id="NewChannel">NewChannel</span>
<p>返回一个 Channel 指针实例</p>
<p>返回一个Channel指针实例</p>
<b>函数签名:</b>
```go
type Channel struct {}
func NewChannel() *Channel
type Channel[T any] struct
func NewChannel[T any]() *Channel[T]
```
<b>例子:</b>
@@ -57,7 +57,7 @@ import (
)
func main() {
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
}
```
@@ -65,12 +65,12 @@ func main() {
### <span id="Bridge">Bridge</span>
<p>将多个通道链接到一个通道,直到取消上下文。</p>
<p>将多个channel链接到一个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
```
<b>例子:</b>
@@ -84,28 +84,33 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
c := concurrency.NewChannel[int]()
genVals := func() <-chan <-chan int {
out := make(chan (<-chan int))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
defer close(out)
for i := 1; i <= 5; i++ {
stream := make(chan int, 1)
stream <- i
close(stream)
chanStream <- stream
out <- stream
}
}()
return chanStream
return out
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
```
@@ -114,12 +119,12 @@ func main() {
### <span id="FanIn">FanIn</span>
<p>将多个通道合并为一个通道,直到取消上下文</p>
<p>将多个channel合并为一个channel,直到取消上下文</p>
<b>函数签名:</b>
```go
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
```
<b>例子:</b>
@@ -133,33 +138,33 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
channels := make([]<-chan any, 3)
c := concurrency.NewChannel[int]()
channels := make([]<-chan int, 2)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
for i := 0; i < 2; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
}
mergedChannel := c.FanIn(ctx, channels...)
chs := 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)
for v := range chs {
fmt.Println(v) //1 1 0 0 or 0 0 1 1
}
}
```
### <span id="Repeat">Repeat</span>
### <span id="Generate">Generate</span>
<p>返回一个chan将参数`values`重复放入chan直到取消上下文。</p>
<p>根据传入的值生成channel.</p>
<b>函数签名:</b>
```go
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
```
<b>例子:</b>
@@ -173,15 +178,58 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
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>例子:</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) //1, 2, 1, 2, 1
fmt.Println(v)
}
// Output:
// 1
// 2
// 1
// 2
}
```
@@ -190,12 +238,12 @@ func main() {
### <span id="RepeatFn">RepeatFn</span>
<p>返回一个chan重复执行函数fn并将结果放入返回的chan直到取消上下文。</p>
<p>返回一个channel重复执行函数fn并将结果放入返回的channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
```
<b>例子:</b>
@@ -209,19 +257,23 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
s := "a"
return s
fn := func() string {
return "hello"
}
c := concurrency.NewChannel()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range dataStream {
fmt.Println(v) //a, a, a
c := concurrency.NewChannel[string]()
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// hello
// hello
// hello
}
```
@@ -229,12 +281,12 @@ func main() {
### <span id="Or">Or</span>
<p>将一个或多个通道读取到一个通道中,当任何读取通道关闭时将结束读取。</p>
<p>将一个或多个channel读取到一个channel中当任何读取channel关闭时将结束读取。</p>
<b>函数签名:</b>
```go
func (c *Channel) Or(channels ...<-chan any) <-chan any
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
```
<b>例子:</b>
@@ -248,8 +300,8 @@ import (
)
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
sig := func(after time.Duration) <-chan any {
c := make(chan any)
go func() {
defer close(c)
time.Sleep(after)
@@ -259,13 +311,11 @@ func main() {
start := time.Now()
c := concurrency.NewChannel()
c := concurrency.NewChannel[any]()
<-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
@@ -277,12 +327,12 @@ func main() {
### <span id="OrDone">OrDone</span>
<p>将一个通道读入另一个通道,直到取消上下文。</p>
<p>将一个channel读入另一个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
```
<b>例子:</b>
@@ -296,15 +346,19 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for val := range c.OrDone(ctx, intStream) {
fmt.Println(val) //1
for v := range c.OrDone(ctx, intStream) {
fmt.Println(v)
}
// Output:
// 1
// 1
// 1
}
```
@@ -313,12 +367,12 @@ func main() {
### <span id="Take">Take</span>
<p>返回一个chan其值从另一个chan获取直到取消上下文。</p>
<p>返回一个channel其值从另一个channel获取,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
```
<b>例子:</b>
@@ -332,10 +386,10 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
@@ -343,12 +397,16 @@ func main() {
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
for val := range intStream {
fmt.Println(val) //1, 2, 3
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}
```
@@ -356,12 +414,12 @@ func main() {
### <span id="Tee">Tee</span>
<p>将一个通道分成两个通道,直到取消上下文。</p>
<p>将一个channel分成两个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
```
<b>例子:</b>
@@ -375,16 +433,22 @@ import (
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
fmt.Println(val) //1
fmt.Println(<-out2) //1
ch1, ch2 := c.Tee(ctx, intStream)
for v := range ch1 {
fmt.Println(v)
fmt.Println(<-ch2)
}
// Output:
// 1
// 1
// 1
// 1
}
```

291
docs/condition.md Normal file
View File

@@ -0,0 +1,291 @@
# Condition
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.
<div STYLE="page-break-after: always;"></div>
## Source:
- [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>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/condition"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Bool](#Bool)
- [And](#And)
- [Or](#Or)
- [Xor](#Generate)
- [Nor](#Nor)
- [Xnor](#Xnor)
- [Nand](#Nand)
- [TernaryOperator](#TernaryOperator)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Bool">Bool</span>
<p>Returns the truthy value of anything.<br/>
If the value's type has a Bool() bool method, the method is called and returned.<br/>
If the type has an IsZero() bool method, the opposite value is returned.<br/>
Slices and maps are truthy if they have a length greater than zero.<br/>
All other types are truthy if they are not their zero value.</p>
<b>Signature:</b>
```go
func Bool[T any](value T) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
// bool
fmt.Println(condition.Bool(false)) // false
fmt.Println(condition.Bool(true)) // true
// integer
fmt.Println(condition.Bool(0)) // false
fmt.Println(condition.Bool(1)) // true
// float
fmt.Println(condition.Bool(0.0)) // false
fmt.Println(condition.Bool(0.1)) // true
// string
fmt.Println(condition.Bool("")) // false
fmt.Println(condition.Bool(" ")) // true
fmt.Println(condition.Bool("0")) // true
// slice
var nums [2]int
fmt.Println(condition.Bool(nums)) // false
nums = [2]int{0, 1}
fmt.Println(condition.Bool(nums)) // true
// map
fmt.Println(condition.Bool(map[string]string{})) // false
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true
// struct
fmt.Println(condition.Bool(struct{}{})) // false
fmt.Println(condition.Bool(time.Now())) // true
}
```
### <span id="And">And</span>
<p>Returns true if both a and b are truthy.</p>
<b>Signature:</b>
```go
func And[T, U any](a T, b U) bool
```
<b>Example:</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>Returns false if neither a nor b is truthy.</p>
<b>Signature:</b>
```go
func Or[T, U any](a T, b U) bool
```
<b>Example:</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>Returns true if a or b but not both is truthy.</p>
<b>Signature:</b>
```go
func Xor[T, U any](a T, b U) bool
```
<b>Example:</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>Returns true if neither a nor b is truthy.</p>
<b>Signature:</b>
```go
func Nor[T, U any](a T, b U) bool
```
<b>Example:</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>Returns true if both a and b or neither a nor b are truthy.</p>
<b>Signature:</b>
```go
func Xnor[T, U any](a T, b U) bool
```
<b>Example:</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>Returns false if both a and b are truthy</p>
<b>Signature:</b>
```go
func Nand[T, U any](a T, b U) bool
```
<b>Example:</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>Checks the value of param `isTrue`, if true return ifValue else return elseValue</p>
<b>Signature:</b>
```go
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
trueValue := "1"
falseValue := "0"
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1"
}
```

290
docs/condition_zh-CN.md Normal file
View File

@@ -0,0 +1,290 @@
# 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>
## Index
- [Bool](#Bool)
- [And](#And)
- [Or](#Or)
- [Xor](#Generate)
- [Nor](#Nor)
- [Xnor](#Xnor)
- [Nand](#Nand)
- [TernaryOperator](#TernaryOperator)
<div STYLE="page-break-after: always;"></div>
## 目录
### <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>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
// bool
fmt.Println(condition.Bool(false)) // false
fmt.Println(condition.Bool(true)) // true
// integer
fmt.Println(condition.Bool(0)) // false
fmt.Println(condition.Bool(1)) // true
// float
fmt.Println(condition.Bool(0.0)) // false
fmt.Println(condition.Bool(0.1)) // true
// string
fmt.Println(condition.Bool("")) // false
fmt.Println(condition.Bool(" ")) // true
fmt.Println(condition.Bool("0")) // true
// slice
var nums [2]int
fmt.Println(condition.Bool(nums)) // false
nums = [2]int{0, 1}
fmt.Println(condition.Bool(nums)) // true
// map
fmt.Println(condition.Bool(map[string]string{})) // false
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true
// struct
fmt.Println(condition.Bool(struct{}{})) // false
fmt.Println(condition.Bool(time.Now())) // true
}
```
### <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>例子:</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>例子:</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>例子:</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>例子:</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>例子:</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>例子:</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>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
trueValue := "1"
falseValue := "0"
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1"
}
```

View File

@@ -24,10 +24,17 @@ import (
- [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)
<div STYLE="page-break-after: always;"></div>
@@ -95,7 +102,7 @@ func main() {
### <span id="ToBool">ToBool</span>
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
<p>Convert string to bool. Use strconv.ParseBool.</p>
<b>Signature:</b>
@@ -131,7 +138,7 @@ func main() {
### <span id="ToBytes">ToBytes</span>
<p>Convert interface to byte slice.</p>
<p>Convert value to byte slice.</p>
<b>Signature:</b>
@@ -191,10 +198,47 @@ func main() {
```
### <span id="ToChannel">ToChannel</span>
<p>Convert a collection of elements to a read-only channel.</p>
<b>Signature:</b>
```go
func ToChannel[T any](array []T) <-chan T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
ch := convertor.ToChannel([]int{1, 2, 3})
val1, _ := <-ch
fmt.Println(val1) //1
val2, _ := <-ch
fmt.Println(val2) //2
val3, _ := <-ch
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
}
```
### <span id="ToFloat">ToFloat</span>
<p>Convert interface to a float64 value. If param is a invalid floatable, will return 0 and error. </p>
<p>Convert value to a float64 value. If param is a invalid floatable, will return 0.0 and error. </p>
<b>Signature:</b>
@@ -227,7 +271,7 @@ func main() {
### <span id="ToInt">ToInt</span>
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
<p>Convert value to a int64 value. If param is a invalid intable, will return 0 and error. </p>
<b>Signature:</b>
@@ -286,9 +330,73 @@ func main() {
### <span id="ToMap">ToMap</span>
<p>Convert a slice of structs to a map based on iteratee function. </p>
<b>Signature:</b>
```go
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V
```
<b>Example:</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) //{100: "Hello", 101: "Hi"}
}
```
### <span id="ToPointer">ToPointer</span>
<p>Returns a pointer to passed value. </p>
<b>Signature:</b>
```go
func ToPointer[T any](value T) *T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result := convertor.ToPointer(123)
fmt.Println(*result) //123
}
```
### <span id="ToString">ToString</span>
<p>Convert interface to string. </p>
<p>ToString convert value to string, for number, string, []byte, will convert to string. For other type (slice, map, array, struct) will call json.Marshal</p>
<b>Signature:</b>
@@ -313,7 +421,6 @@ func main() {
```
### <span id="StructToMap">StructToMap</span>
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
@@ -346,4 +453,90 @@ func main() {
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
}
```
### <span id="MapToSlice">MapToSlice</span>
<p>Convert a map to a slice based on iteratee function.</p>
<b>Signature:</b>
```go
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T
```
<b>Example:</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>Encode data to byte slice.</p>
<b>Signature:</b>
```go
func EncodeByte(data any) ([]byte, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
}
```
### <span id="DecodeByte">DecodeByte</span>
<p>Decode byte data to target object. target should be a pointer instance.</p>
<b>Signature:</b>
```go
func DecodeByte(data []byte, target any) error
```
<b>Example:</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}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc"
}
```

View File

@@ -26,10 +26,17 @@ import (
- [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)
<div STYLE="page-break-after: always;"></div>
@@ -194,6 +201,44 @@ func main() {
### <span id="ToChannel">ToChannel</span>
<p>将切片转为只读channel</p>
<b>函数签名:</b>
```go
func ToChannel[T any](array []T) <-chan T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
ch := convertor.ToChannel([]int{1, 2, 3})
val1, _ := <-ch
fmt.Println(val1) //1
val2, _ := <-ch
fmt.Println(val2) //2
val3, _ := <-ch
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
}
```
### <span id="ToFloat">ToFloat</span>
<p>将interface转成float64类型如果参数无法转换会返回0和error</p>
@@ -229,7 +274,7 @@ func main() {
### <span id="ToInt">ToInt</span>
<p>将interface转成intt64类型如果参数无法转换会返回0和error</p>
<p>将interface转成int64类型如果参数无法转换会返回0和error</p>
<b>函数签名:</b>
@@ -288,9 +333,74 @@ func main() {
### <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>例子:</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) //{100: "Hello", 101: "Hi"}
}
```
### <span id="ToPointer">ToPointer</span>
<p>返回传入值的指针</p>
<b>函数签名:</b>
```go
func ToPointer[T any](value T) *T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
result := convertor.ToPointer(123)
fmt.Println(*result) //123
}
```
### <span id="ToString">ToString</span>
<p>将interface转成字符串</p>
<p>将值转换为字符串,对于数字、字符串、[]byte将转换为字符串。 对于其他类型(切片、映射、数组、结构)将调用 json.Marshal</p>
<b>函数签名:</b>
@@ -348,4 +458,91 @@ func main() {
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: 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>例子:</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>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{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>例子:</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}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc"
}
```

View File

@@ -5,10 +5,10 @@ Package cryptor contains some functions for data encryption and decryption. Supp
## Source:
- [https://github.com/duke-git/lancet/blob/main/cryptor/aes.go](https://github.com/duke-git/lancet/blob/main/cryptor/aes.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/des.go](https://github.com/duke-git/lancet/blob/main/cryptor/des.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/basic.go](https://github.com/duke-git/lancet/blob/main/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go](https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go)
<div STYLE="page-break-after: always;"></div>
@@ -47,7 +47,6 @@ import (
- [HmacSha1](#HmacSha1)
- [HmacSha256](#HmacSha256)
- [HmacSha512](#HmacSha512)
- [Md5String](#Md5String)
- [Md5File](#Md5File)
- [Sha1](#Sha1)
@@ -85,7 +84,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
@@ -115,9 +114,9 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
@@ -145,7 +144,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
@@ -176,9 +175,9 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
@@ -207,7 +206,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrCrypt(encrypted, []byte(key))
@@ -239,7 +238,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
@@ -271,7 +270,7 @@ func main() {
data := "hello world"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
@@ -300,7 +299,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
@@ -330,9 +329,9 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
@@ -360,7 +359,7 @@ import (
)
func main() {
base64Str := cryptor.Base64StdEncode("hello world")
base64Str := cryptor.Base64StdEncode("hello world")
fmt.Println(base64Str) //aGVsbG8gd29ybGQ=
}
```
@@ -417,7 +416,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
@@ -448,9 +447,9 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byt(key)
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
@@ -480,7 +479,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
fmt.Println(string(encrypted))
@@ -511,7 +510,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
@@ -543,7 +542,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrCrypt(encrypted, []byte(key))
@@ -575,7 +574,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
fmt.Println(string(encrypted))
}
@@ -605,9 +604,9 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
@@ -636,7 +635,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
@@ -666,9 +665,9 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
@@ -725,8 +724,8 @@ import (
)
func main() {
s := cryptor.HmacSha1("hello world", "12345"))
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd
s := cryptor.HmacSha1("hello world", "12345"))
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd
}
```
@@ -753,8 +752,8 @@ import (
)
func main() {
s := cryptor.HmacSha256("hello world", "12345"))
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
s := cryptor.HmacSha256("hello world", "12345"))
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
}
```
@@ -781,8 +780,8 @@ import (
)
func main() {
s := cryptor.HmacSha512("hello world", "12345"))
fmt.Println(s)
s := cryptor.HmacSha512("hello world", "12345"))
fmt.Println(s)
//5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
}
```
@@ -810,8 +809,8 @@ import (
)
func main() {
s := cryptor.Md5String("hello"))
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
s := cryptor.Md5String("hello"))
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
}
```
@@ -838,8 +837,8 @@ import (
)
func main() {
s := cryptor.Md5File("./main.go"))
fmt.Println(s)
s := cryptor.Md5File("./main.go"))
fmt.Println(s)
}
```
@@ -866,8 +865,8 @@ import (
)
func main() {
s := cryptor.Sha1("hello world"))
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
s := cryptor.Sha1("hello world"))
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
}
```
@@ -894,8 +893,8 @@ import (
)
func main() {
s := cryptor.Sha256("hello world"))
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
s := cryptor.Sha256("hello world"))
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
}
```
@@ -922,7 +921,7 @@ import (
)
func main() {
s := cryptor.Sha512("hello world"))
s := cryptor.Sha512("hello world"))
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
}
```
@@ -950,10 +949,10 @@ import (
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
}
}
```
@@ -980,14 +979,14 @@ import (
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world
}
@@ -1016,14 +1015,14 @@ import (
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
}
data := []byte("hello world")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world
}

View File

@@ -5,10 +5,8 @@ cryptor加密包支持数据加密和解密获取md5hash值。支持base64
## 源码:
- [https://github.com/duke-git/lancet/blob/main/cryptor/aes.go](https://github.com/duke-git/lancet/blob/main/cryptor/aes.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/des.go](https://github.com/duke-git/lancet/blob/main/cryptor/des.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/basic.go](https://github.com/duke-git/lancet/blob/main/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go](https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go)
<div STYLE="page-break-after: always;"></div>
@@ -33,7 +31,6 @@ import (
- [AesOfbDecrypt](#AesOfbDecrypt)
- [Base64StdEncode](#Base64StdEncode)
- [Base64StdDecode](#Base64StdDecode)
- [DesEcbEncrypt](#DesEcbEncrypt)
- [DesEcbDecrypt](#DesEcbDecrypt)
- [DesCbcEncrypt](#DesCbcEncrypt)
@@ -43,7 +40,6 @@ import (
- [DesCfbDecrypt](#DesCfbDecrypt)
- [DesOfbEncrypt](#DesOfbEncrypt)
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacSha1](#HmacSha1)
- [HmacSha256](#HmacSha256)
@@ -85,7 +81,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
@@ -115,9 +111,9 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
@@ -145,7 +141,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
@@ -176,9 +172,9 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
@@ -188,7 +184,7 @@ func main() {
### <span id="AesCtrCrypt">AesCtrCrypt</span>
<p>使用AES CTR算法模式加密/解密数据. 参数`key`的长度是16, 24 or 32。</p>
<p>使用AES CTR算法模式加密/解密数据参数`key`的长度是16, 24 or 32。</p>
<b>函数签名:</b>
@@ -208,7 +204,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrCrypt(encrypted, []byte(key))
@@ -240,7 +236,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
@@ -270,9 +266,9 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
@@ -301,7 +297,7 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
@@ -331,9 +327,9 @@ import (
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
@@ -360,7 +356,7 @@ import (
)
func main() {
base64Str := cryptor.Base64StdEncode("hello world")
base64Str := cryptor.Base64StdEncode("hello world")
fmt.Println(base64Str) //aGVsbG8gd29ybGQ=
}
```
@@ -388,7 +384,7 @@ import (
)
func main() {
str := cryptor.Base64StdDecode("aGVsbG8gd29ybGQ=")
str := cryptor.Base64StdDecode("aGVsbG8gd29ybGQ=")
fmt.Println(str) //hello world
}
```
@@ -417,7 +413,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
@@ -448,7 +444,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
@@ -480,7 +476,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
@@ -511,7 +507,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
@@ -543,7 +539,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrCrypt(encrypted, []byte(key))
@@ -575,7 +571,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
@@ -605,7 +601,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
@@ -636,7 +632,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
@@ -666,7 +662,7 @@ import (
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
@@ -696,8 +692,8 @@ import (
)
func main() {
s := cryptor.HmacMd5("hello world", "12345"))
fmt.Println(s) //5f4c9faaff0a1ad3007d9ddc06abe36d
s := cryptor.HmacMd5("hello world", "12345"))
fmt.Println(s) //5f4c9faaff0a1ad3007d9ddc06abe36d
}
```
@@ -724,8 +720,8 @@ import (
)
func main() {
s := cryptor.HmacSha1("hello world", "12345"))
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd
s := cryptor.HmacSha1("hello world", "12345"))
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd
}
```
@@ -752,8 +748,8 @@ import (
)
func main() {
s := cryptor.HmacSha256("hello world", "12345"))
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
s := cryptor.HmacSha256("hello world", "12345"))
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
}
```
@@ -780,8 +776,8 @@ import (
)
func main() {
s := cryptor.HmacSha512("hello world", "12345"))
fmt.Println(s)
s := cryptor.HmacSha512("hello world", "12345"))
fmt.Println(s)
//5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
}
```
@@ -809,8 +805,8 @@ import (
)
func main() {
s := cryptor.Md5String("hello"))
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
s := cryptor.Md5String("hello"))
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
}
```
@@ -837,8 +833,8 @@ import (
)
func main() {
s := cryptor.Md5File("./main.go"))
fmt.Println(s)
s := cryptor.Md5File("./main.go"))
fmt.Println(s)
}
```
@@ -865,8 +861,8 @@ import (
)
func main() {
s := cryptor.Sha1("hello world"))
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
s := cryptor.Sha1("hello world"))
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
}
```
@@ -893,8 +889,8 @@ import (
)
func main() {
s := cryptor.Sha256("hello world"))
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
s := cryptor.Sha256("hello world"))
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
}
```
@@ -921,8 +917,8 @@ import (
)
func main() {
s := cryptor.Sha512("hello world"))
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
s := cryptor.Sha512("hello world"))
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
}
```
@@ -949,10 +945,10 @@ import (
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
}
```
@@ -979,11 +975,11 @@ import (
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world
@@ -1013,11 +1009,11 @@ import (
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world

View File

@@ -0,0 +1,314 @@
# HashMap
HashMap is a key value map data structure.
<div STYLE="page-break-after: always;"></div>
## Source
- [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>
## Usage
```go
import (
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [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>
## Documentation
### <span id="NewHashMap">NewHashMap</span>
<p>Make a HashMap instance with default capacity is 1 << 10.</p>
<b>Signature:</b>
```go
func NewHashMap() *HashMap
```
<b>Example:</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="NewHashMap">NewHashMap</span>
<p>Make a HashMap instance with given size and capacity.</p>
<b>Signature:</b>
```go
func NewHashMapWithCapacity(size, capacity uint64) *HashMap
```
<b>Example:</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>Get the value of given key in hashmap</p>
<b>Signature:</b>
```go
func (hm *HashMap) Get(key any) any
```
<b>Example:</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>Put new key value in hashmap, then return value</p>
<b>Signature:</b>
```go
func (hm *HashMap) Put(key any, value any) any
```
<b>Example:</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>Delete key-value item by given key in hashmap.</p>
<b>Signature:</b>
```go
func (hm *HashMap) Delete(key any)
```
<b>Example:</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>Checks if given key is in hashmap or not.</p>
<b>Signature:</b>
```go
func (hm *HashMap) Contains(key any) bool
```
<b>Example:</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>Executes iteratee funcation for every key and value pair of hashmap.</p>
<b>Signature:</b>
```go
func (hm *HashMap) Iterate(iteratee func(key, value any))
```
<b>Example:</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>Return a slice of the hashmap's keys (random order).</p>
<b>Signature:</b>
```go
func (hm *HashMap) Keys() []any
```
<b>Example:</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>Return a slice of the hashmap's values (random order).</p>
<b>Signature:</b>
```go
func (hm *HashMap) Values() []any
```
<b>Example:</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,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}
}
```

364
docs/datastructure/heap.md Normal file
View File

@@ -0,0 +1,364 @@
# Heap
Heap is a binary heap tree implemented by slice.
<div STYLE="page-break-after: always;"></div>
## Source
- [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>
## Usage
```go
import (
heap "github.com/duke-git/lancet/v2/datastructure/heap"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [MaxHeap](#MaxHeap)
- [Push](#Push)
- [Pop](#Pop)
- [Peek](#Peek)
- [Data](#Data)
- [Size](#Size)
<div STYLE="page-break-after: always;"></div>
## Documentation
### 1. MaxHeap
MaxHeap is a binary heap tree implemented by slice, The key of the root node is both greater than or equal to the key value of the left subtree and greater than or equal to the key value of the right subtree.
### <span id="NewMaxHeap">NewMaxHeap</span>
<p>Return a NewMaxHeap pointer instance.</p>
<b>Signature:</b>
```go
type MaxHeap[T any] struct {
data []T
comparator lancetconstraints.Comparator
}
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T]
```
<b>Example:</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>Push value into the heap</p>
<b>Signature:</b>
```go
func (h *MaxHeap[T]) Push(value T)
```
<b>Example:</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>Pop return the largest value, and remove it from the heap if heap is empty, return zero value and fasle</p>
<b>Signature:</b>
```go
func (h *MaxHeap[T]) Pop() (T, bool)
```
<b>Example:</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>Return the largest element from the heap without removing it, if heap is empty, it returns zero value and false.</p>
<b>Signature:</b>
```go
func (h *MaxHeap[T]) Peek() (T, bool)
```
<b>Example:</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>Return all element of the heap</p>
<b>Signature:</b>
```go
func (h *MaxHeap[T]) Data() []T
```
<b>Example:</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>Return the number of elements in the heap</p>
<b>Signature:</b>
```go
func (h *MaxHeap[T]) Size() int
```
<b>Example:</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>Print the tree structure of the heap</p>
<b>Signature:</b>
```go
func (h *MaxHeap[T]) PrintStructure()
```
<b>Example:</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

@@ -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

@@ -132,12 +132,12 @@ func main() {
### <span id="SinglyLink_InsertAt">InsertAt</span>
<p>Insert value into singly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
<p>Insert value into singly linklist at index, param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing</p>
<b>Signature:</b>
```go
func (link *SinglyLink[T]) InsertAt(index int, value T) error
func (link *SinglyLink[T]) InsertAt(index int, value T)
```
<b>Example:</b>
@@ -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)
@@ -228,12 +230,12 @@ func main() {
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
<p>Delete value at specific index, param `index` should be [0, len(SinglyLink)-1]</p>
<b>Signature:</b>
```go
func (link *SinglyLink[T]) DeleteAt(index int) error
func (link *SinglyLink[T]) DeleteAt(index int)
```
<b>Example:</b>
@@ -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,7 +269,7 @@ func main() {
<b>Signature:</b>
```go
func (link *SinglyLink[T]) DeleteAtHead() error
func (link *SinglyLink[T]) DeleteAtHead()
```
<b>Example:</b>
@@ -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,7 +304,7 @@ func main() {
<b>Signature:</b>
```go
func (link *SinglyLink[T]) DeleteAtTail() error
func (link *SinglyLink[T]) DeleteAtTail()
```
<b>Example:</b>
@@ -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}
}
```
@@ -628,12 +627,12 @@ func main() {
### <span id="DoublyLink_InsertAt">InsertAt</span>
<p>Insert value into doubly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
<p>Insert value into doubly linklist at index, param `index` should between [0, len(DoublyLink)], if index do not meet the conditions, do nothing</p>
<b>Signature:</b>
```go
func (link *DoublyLink[T]) InsertAt(index int, value T) error
func (link *DoublyLink[T]) InsertAt(index int, value T)
```
<b>Example:</b>
@@ -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)
@@ -724,12 +725,12 @@ func main() {
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
<p>Delete value at specific index, param `index` should be [0, len(DoublyLink)-1]</p>
<b>Signature:</b>
```go
func (link *DoublyLink[T]) DeleteAt(index int) error
func (link *DoublyLink[T]) DeleteAt(index int)
```
<b>Example:</b>
@@ -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,7 +764,7 @@ func main() {
<b>Signature:</b>
```go
func (link *DoublyLink[T]) DeleteAtHead() error
func (link *DoublyLink[T]) DeleteAtHead()
```
<b>Example:</b>
@@ -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}
}
```

View File

@@ -132,12 +132,12 @@ 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>
@@ -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)
@@ -228,12 +230,12 @@ 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>
@@ -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,7 +269,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) DeleteAtHead() error
func (link *SinglyLink[T]) DeleteAtHead()
```
<b>例子:</b>
@@ -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,7 +304,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) DeleteAtTail() error
func (link *SinglyLink[T]) DeleteAtTail()
```
<b>例子:</b>
@@ -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}
}
```
@@ -628,12 +627,12 @@ 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>
@@ -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)
@@ -724,12 +725,12 @@ 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>
@@ -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,7 +764,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) DeleteAtHead() error
func (link *DoublyLink[T]) DeleteAtHead()
```
<b>例子:</b>
@@ -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,7 +799,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) DeleteAtTail() error
func (link *DoublyLink[T]) DeleteAtTail()
```
<b>例子:</b>
@@ -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}
}
```

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,14 @@ import (
- [Clone](#Clone)
- [Merge](#Merge)
- [Size](#Size)
- [Cap](#Cap)
- [Swap](#Swap)
- [Reverse](#Reverse)
- [Unique](#Unique)
- [Union](#Union)
- [Intersection](#Intersection)
- [SubList](#SubList)
- [DeleteIf](#DeleteIf)
<div STYLE="page-break-after: always;"></div>
@@ -167,7 +173,7 @@ func main() {
### <span id="IndexOf">IndexOf</span>
<p>Reture the index of value in the list. if not found return -1</p>
<p>Returns the index of value in the list. if not found return -1</p>
<b>Signature:</b>
@@ -192,6 +198,84 @@ func main() {
}
```
### <span id="LastIndexOf">LastIndexOf</span>
<p> Returns the index of the last occurrence of the value in this list if not found return -1</p>
<b>Signature:</b>
```go
func (l *List[T]) LastIndexOf(value T) int
```
<b>Example:</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> IndexOfFunc returns the first index satisfying f(v). if not found return -1</p>
<b>Signature:</b>
```go
func (l *List[T]) IndexOfFunc(f func(T) bool) int
```
<b>Example:</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>LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i]). if not found return -1</p>
<b>Signature:</b>
```go
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int
```
<b>Example:</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>
@@ -568,6 +652,36 @@ func main() {
### <span id="Cap">Cap</span>
<p>Cap return cap of the inner data</p>
<b>Signature:</b>
```go
func (l *List[T]) Cap() int
```
<b>Example:</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>Swap the value at two index in list</p>
@@ -710,4 +824,61 @@ func main() {
fmt.Println(li3.Data()) //4
}
```
```
### <span id="SubList">SubList</span>
<p>SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.</p>
<b>Signature:</b>
```go
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T]
```
<b>Example:</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>DeleteIf delete all satisfying f(data[i]), returns count of removed elements</p>
<b>Signature:</b>
```go
func (l *List[T]) DeleteIf(f func(T) bool) int
```
<b>Example:</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

@@ -26,11 +26,15 @@ import (
- [Data](#Data)
- [ValueOf](#ValueOf)
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [IndexOfFunc](#IndexOfFunc)
- [LastIndexOfFunc](#LastIndexOfFunc)
- [Push](#Push)
- [PopFirst](#PopFirst)
- [PopLast](#PopLast)
- [DeleteAt](#DeleteAt)
- [InsertAt](#InsertAt)
- [UpdateAt](#UpdateAt)
- [Equal](#Equal)
- [IsEmpty](#IsEmpty)
@@ -38,11 +42,14 @@ import (
- [Clone](#Clone)
- [Merge](#Merge)
- [Size](#Size)
- [Cap](#Cap)
- [Swap](#Swap)
- [Reverse](#Reverse)
- [Unique](#Unique)
- [Union](#Union)
- [Intersection](#Intersection)
- [SubList](#SubList)
- [DeleteIf](#DeleteIf)
<div STYLE="page-break-after: always;"></div>
@@ -192,6 +199,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>
@@ -566,6 +652,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>
@@ -709,4 +823,60 @@ func main() {
fmt.Println(li3.Data()) //4
}
```
### <span id="SubList">SubList</span>
<p>SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.</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

@@ -22,8 +22,11 @@ import (
## Index
- [NewSet](#NewSet)
- [NewSetFromSlice](#NewSetFromSlice)
- [Values](#Values)
- [Add](#Add)
- [AddIfNotExist](#AddIfNotExist)
- [AddIfNotExistBy](#AddIfNotExistBy)
- [Delete](#Delete)
- [Contain](#Contain)
- [ContainAll](#ContainAll)
@@ -34,7 +37,6 @@ import (
- [IsEmpty](#IsEmpty)
- [Union](#Union)
- [Intersection](#Intersection)
- [SymmetricDifference](#SymmetricDifference)
- [Minus](#Minus)
@@ -45,13 +47,13 @@ import (
## Documentation
### <span id="NewSet">NewSet</span>
<p>Make a Set instance</p>
<p>Create a set instance</p>
<b>Signature:</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>Example:</b>
@@ -70,6 +72,30 @@ func main() {
```
### <span id="NewSetFromSlice">NewSetFromSlice</span>
<p>Create a set from slice</p>
<b>Signature:</b>
```go
func NewSetFromSlice[T comparable](items []T) Set[T]
```
<b>Example:</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>
@@ -100,12 +126,12 @@ func main() {
### <span id="Add">Add</span>
<p>Add value to set</p>
<p>Add items to set</p>
<b>Signature:</b>
```go
func (s Set[T]) Add(values ...T)
func (s Set[T]) Add(items ...T)
```
<b>Example:</b>
@@ -126,14 +152,83 @@ func main() {
```
### <span id="Delete">Delete</span>
<p>Delete value in set</p>
### <span id="AddIfNotExist">AddIfNotExist</span>
<p>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.</p>
<b>Signature:</b>
```go
func (s Set[T]) Delete(values ...T)
func (s Set[T]) AddIfNotExist(item T) bool
```
<b>Example:</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>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.</p>
<b>Signature:</b>
```go
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
```
<b>Example:</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>Delete item in set</p>
<b>Signature:</b>
```go
func (s Set[T]) Delete(items ...T)
```
<b>Example:</b>
@@ -157,12 +252,12 @@ func main() {
### <span id="Contain">Contain</span>
<p>Check if value is in set or not</p>
<p>Check if item is in set or not</p>
<b>Signature:</b>
```go
func (s Set[T]) Contain(value T) bool
func (s Set[T]) Contain(item T) bool
```
<b>Example:</b>
@@ -309,7 +404,7 @@ func main() {
<b>Signature:</b>
```go
func (s Set[T]) Iterate(fn func(value T))
func (s Set[T]) Iterate(fn func(item T))
```
<b>Example:</b>
@@ -324,8 +419,8 @@ 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

View File

@@ -22,8 +22,11 @@ import (
## 目录
- [NewSet](#NewSet)
- [NewSetFromSlice](#NewSetFromSlice)
- [Values](#Values)
- [Add](#Add)
- [AddIfNotExist](#AddIfNotExist)
- [AddIfNotExistBy](#AddIfNotExistBy)
- [Delete](#Delete)
- [Contain](#Contain)
- [ContainAll](#ContainAll)
@@ -34,7 +37,6 @@ import (
- [IsEmpty](#IsEmpty)
- [Union](#Union)
- [Intersection](#Intersection)
- [SymmetricDifference](#SymmetricDifference)
- [Minus](#Minus)
@@ -51,7 +53,7 @@ import (
```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>
@@ -71,6 +73,31 @@ 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>
@@ -105,7 +132,7 @@ func main() {
<b>函数签名:</b>
```go
func (s Set[T]) Add(values ...T)
func (s Set[T]) Add(items ...T)
```
<b>例子:</b>
@@ -126,6 +153,76 @@ 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>
@@ -133,7 +230,7 @@ func main() {
<b>函数签名:</b>
```go
func (s Set[T]) Delete(values ...T)
func (s Set[T]) Delete(items ...T)
```
<b>例子:</b>
@@ -162,7 +259,7 @@ func main() {
<b>函数签名:</b>
```go
func (s Set[T]) Contain(value T) bool
func (s Set[T]) Contain(item T) bool
```
<b>例子:</b>
@@ -309,7 +406,7 @@ func main() {
<b>函数签名:</b>
```go
func (s Set[T]) Iterate(fn func(value T))
func (s Set[T]) Iterate(fn func(item T))
```
<b>例子:</b>
@@ -324,8 +421,8 @@ 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
@@ -420,9 +517,6 @@ func main() {
```
### <span id="SymmetricDifference">SymmetricDifference</span>
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>

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)

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)

View File

@@ -42,7 +42,6 @@ import (
- [GetNightTimestamp](#GetNightTimestamp)
- [FormatTimeToStr](#FormatTimeToStr)
- [FormatStrToTime](#FormatStrToTime)
- [NewUnixNow](#NewUnixNow)
- [NewUnix](#NewUnix)
- [NewFormat](#NewFormat)
@@ -251,7 +250,7 @@ func main() {
<b>Signature:</b>
```go
func BeginOfWeek(t time.Time) time.Time
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time
```
<b>Example:</b>
@@ -414,7 +413,7 @@ func main() {
<b>Signature:</b>
```go
func EndOfWeek(t time.Time) time.Time
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time
```
<b>Example:</b>
@@ -712,7 +711,7 @@ func main() {
```go
type theTime struct {
unix int64
unix int64
}
func NewUnix(unix int64) *theTime
```
@@ -741,7 +740,7 @@ func main() {
```go
type theTime struct {
unix int64
unix int64
}
func NewFormat(t string) (*theTime, error)
```
@@ -771,7 +770,7 @@ func main() {
```go
type theTime struct {
unix int64
unix int64
}
func NewISO8601(iso8601 string) (*theTime, error)
```

View File

@@ -41,7 +41,6 @@ import (
- [GetNightTimestamp](#GetNightTimestamp)
- [FormatTimeToStr](#FormatTimeToStr)
- [FormatStrToTime](#FormatStrToTime)
- [NewUnixNow](#NewUnixNow)
- [NewUnix](#NewUnix)
- [NewFormat](#NewFormat)
@@ -243,12 +242,12 @@ func main() {
### <span id="BeginOfWeek">BeginOfWeek</span>
<p>返回指定时间的星期开始时间</p>
<p>返回指定时间的每周开始时间,默认开始时间星期日</p>
<b>函数签名:</b>
```go
func BeginOfWeek(t time.Time) time.Time
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time
```
<b>例子:</b>
@@ -378,7 +377,7 @@ func main() {
```
### <span id="EndOfDay">EndOfDay</span>
<p>返回指定时间的当天结束时间.</p>
<p>返回指定时间的当天结束时间</p>
<b>函数签名:</b>
@@ -406,12 +405,12 @@ func main() {
### <span id="EndOfWeek">EndOfWeek</span>
<p>返回指定时间的星期结束时间</p>
<p>返回指定时间的星期结束时间,默认结束时间星期六</p>
<b>函数签名:</b>
```go
func EndOfWeek(t time.Time) time.Time
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time
```
<b>例子:</b>
@@ -542,7 +541,7 @@ func main() {
### <span id="GetNowDateTime">GetNowDateTime</span>
<p>获取当时日期和时间返回格式yyyy-mm-dd hh:mm:ss.</p>
<p>获取当时日期和时间返回格式yyyy-mm-dd hh:mm:ss</p>
<b>函数签名:</b>
@@ -569,7 +568,7 @@ func main() {
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
<p>获取零时时间戳(timestamp of 00:00).</p>
<p>获取零时时间戳(timestamp of 00:00)</p>
<b>函数签名:</b>
@@ -596,7 +595,7 @@ func main() {
### <span id="GetNightTimestamp">GetNightTimestamp</span>
<p>获取午夜时间戳(timestamp of 23:59).</p>
<p>获取午夜时间戳(timestamp of 23:59)</p>
<b>函数签名:</b>
@@ -680,7 +679,7 @@ func main() {
```go
type theTime struct {
unix int64
unix int64
}
func NewUnixNow() *theTime
```
@@ -708,7 +707,7 @@ func main() {
```go
type theTime struct {
unix int64
unix int64
}
func NewUnix(unix int64) *theTime
```
@@ -737,7 +736,7 @@ func main() {
```go
type theTime struct {
unix int64
unix int64
}
func NewFormat(t string) (*theTime, error)
```
@@ -767,7 +766,7 @@ func main() {
```go
type theTime struct {
unix int64
unix int64
}
func NewISO8601(iso8601 string) (*theTime, error)
```

View File

@@ -21,6 +21,7 @@ import (
## Index
- [ClearFile](#ClearFile)
- [CreateFile](#CreateFile)
- [CreateDir](#CreateDir)
- [CopyFile](#CopyFile)
- [FileMode](#FileMode)
- [MiMeType](#MiMeType)
@@ -32,7 +33,7 @@ import (
- [ReadFileToString](#ReadFileToString)
- [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip)
- [UnZip](#UnZip)
- [UnZip](#UnZip)
<div STYLE="page-break-after: always;"></div>
@@ -92,6 +93,32 @@ func main() {
```
### <span id="CreateDir">CreateDir</span>
<p>Create directory in absolute path. param `absPath` like /a/, /a/b/.</p>
<b>Signature:</b>
```go
func CreateDir(absPath string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.CreateDir("/a/")
fmt.Println(err)
}
```
### <span id="CopyFile">CopyFile</span>
<p>Copy src file to dest file. If dest file exist will overwrite it.</p>
@@ -112,9 +139,9 @@ import (
func main() {
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
if err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
}
```
@@ -140,9 +167,9 @@ import (
func main() {
mode, err := fileutil.FileMode("./test.txt")
if err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
fmt.Println(mode)
}
```
@@ -310,8 +337,8 @@ import (
func main() {
err := fileutil.RemoveFile("./test.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(err)
}
}
```
@@ -337,12 +364,12 @@ import (
func main() {
path := "./test.txt"
fileutil.CreateFile(path)
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
content, _ := fileutil.ReadFileToString(path)
content, _ := fileutil.ReadFileToString(path)
fmt.Println(content) //hello world
}
```
@@ -370,13 +397,13 @@ import (
func main() {
path := "./text.txt"
fileutil.CreateFile(path)
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
contents, _ := fileutil.ReadFileByLine(path)
contents, _ := fileutil.ReadFileByLine(path)
fmt.Println(contents) //[]string{"hello", "world"}
}
```
@@ -402,7 +429,7 @@ import (
)
func main() {
err := fileutil.Zip("./test.txt", "./test.zip")
err := fileutil.Zip("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
@@ -431,7 +458,7 @@ import (
)
func main() {
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
if err != nil {
fmt.Println(err)
}

View File

@@ -21,13 +21,13 @@ import (
## 目录
- [ClearFile](#ClearFile)
- [CreateFile](#CreateFile)
- [CreateDir](#CreateDir)
- [CopyFile](#CopyFile)
- [FileMode](#FileMode)
- [MiMeType](#MiMeType)
- [IsExist](#IsExist)
- [IsLink](#IsLink)
- [IsDir](#IsDir)
- [ListFileNames](#ListFileNames)
- [RemoveFile](#RemoveFile)
- [ReadFileToString](#ReadFileToString)
@@ -92,8 +92,34 @@ func main() {
```
### <span id="CreateDir">CreateDir</span>
<p>使用绝对路径创建嵌套目录,例如/a/, /a/b/</p>
<b>函数签名:</b>
```go
func CreateDir(absPath string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.CreateDir("/a/")
fmt.Println(err)
}
```
### <span id="CopyFile">CopyFile</span>
<p>拷贝文件,会覆盖原有的拷贝文件</p>
<p>拷贝文件,会覆盖原有的文件</p>
<b>函数签名:</b>
@@ -112,9 +138,9 @@ import (
func main() {
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
if err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
}
```
@@ -140,9 +166,9 @@ import (
func main() {
mode, err := fileutil.FileMode("./test.txt")
if err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
fmt.Println(mode)
}
```
@@ -235,7 +261,7 @@ func main() {
### <span id="IsDir">IsDir</span>
<p>判断目录是否存在</p>
<p>判断参数是否是目录</p>
<b>函数签名:</b>
@@ -310,8 +336,8 @@ import (
func main() {
err := fileutil.RemoveFile("./test.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(err)
}
}
```
@@ -337,12 +363,12 @@ import (
func main() {
path := "./test.txt"
fileutil.CreateFile(path)
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
content, _ := fileutil.ReadFileToString(path)
content, _ := fileutil.ReadFileToString(path)
fmt.Println(content) //hello world
}
```
@@ -370,13 +396,13 @@ import (
func main() {
path := "./text.txt"
fileutil.CreateFile(path)
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
contents, _ := fileutil.ReadFileByLine(path)
contents, _ := fileutil.ReadFileByLine(path)
fmt.Println(contents) //[]string{"hello", "world"}
}
```
@@ -402,7 +428,7 @@ import (
)
func main() {
err := fileutil.Zip("./test.txt", "./test.zip")
err := fileutil.Zip("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
@@ -431,7 +457,7 @@ import (
)
func main() {
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
if err != nil {
fmt.Println(err)
}

View File

@@ -28,13 +28,12 @@ import (
### <span id="Comma">Comma</span>
<p>Add comma to number by every 3 numbers from right. ahead by symbol char.
Param should be number or numberic string.</p>
<p>Add comma to a number value by every 3 numbers from right to left. ahead by symbol char. if value is a invalid number string like "aa", return empty string.</p>
<b>Signature:</b>
```go
func Comma(v any, symbol string) string
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
```
<b>Example:</b>

View File

@@ -28,12 +28,12 @@ import (
### <span id="Comma">Comma</span>
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
<p>用逗号每隔3位分割数字/字符串,支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
<b>函数签名:</b>
```go
func Comma(v any, symbol string) string
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
```
<b>例子:</b>

View File

@@ -22,10 +22,11 @@ import (
## Index
- [After](#After)
- [Before](#Before)
- [Curry](#Curry)
- [CurryFn](#CurryFn)
- [Compose](#Compose)
- [Debounced](#Debounced)
- [Delay](#Delay)
- [Pipeline](#Pipeline)
- [Watcher](#Watcher)
<div STYLE="page-break-after: always;"></div>
@@ -101,8 +102,6 @@ import (
)
func main() {
assert := internal.NewAssert(t, "TestBefore")
arr := []string{"a", "b", "c", "d", "e"}
f := function.Before(3, func(i int) int {
return i
@@ -120,21 +119,21 @@ func main() {
}
expected := []int64{0, 1, 2, 2, 2}
assert.Equal(expected, res)
fmt.Println(res) // 0, 1, 2, 2, 2
}
```
### <span id="Curry">Curry</span>
### <span id="CurryFn">CurryFn</span>
<p>Make a curry function.</p>
<p>Make curry function.</p>
<b>Signature:</b>
```go
type Fn func(...any) any
func (f Fn) Curry(i any) func(...any) any
type CurryFn[T any] func(...T) T
func (cf CurryFn[T]) New(val T) func(...T) T
```
<b>Example:</b>
@@ -150,12 +149,15 @@ func main() {
add := func(a, b int) int {
return a + b
}
var addCurry function.Fn = func(values ...any) any {
return add(values[0].(int), values[1].(int))
var addCurry CurryFn[int] = func(values ...int) int {
return add(values[0], values[1])
}
add1 := addCurry.Curry(1)
add1 := addCurry.New(1)
result := add1(2)
fmt.Println(result) //3
fmt.Println(result) //3
}
```
@@ -168,7 +170,7 @@ func main() {
<b>Signature:</b>
```go
func Compose(fnList ...func(...any) any) func(...any) any
func Compose[T any](fnList ...func(...T) T) func(...T) T
```
<b>Example:</b>
@@ -181,17 +183,17 @@ import (
)
func main() {
add1 := func(v ...any) any {
return v[0].(int) + 1
toUpper := func(strs ...string) string {
return strings.ToUpper(strs[0])
}
add2 := func(v ...any) any {
return v[0].(int) + 2
toLower := func(strs ...string) string {
return strings.ToLower(strs[0])
}
transform := Compose(toUpper, toLower)
add3 := function.Compose(add1, add2)
result := add3(1)
result := transform("aBCde")
fmt.Println(result) //4
fmt.Println(result) //ABCDE
}
```
@@ -260,9 +262,9 @@ import (
func main() {
var print = func(s string) {
fmt.Println(count) //test delay
fmt.Println(count) //delay 2 seconds
}
function.Delay(2*time.Second, print, "test delay")
function.Delay(2*time.Second, print, "delay 2 seconds")
}
```
@@ -302,6 +304,43 @@ func main() {
```
### <span id="Pipeline">Pipeline</span>
<p>Pipeline takes a list of functions and returns a function whose param will be passed into
the functions one by one.</p>
<b>Signature:</b>
```go
func Pipeline[T any](funcs ...func(T) T) func(T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
addOne := func(x int) int {
return x + 1
}
double := func(x int) int {
return 2 * x
}
square := func(x int) int {
return x * x
}
fn := Pipeline(addOne, double, square)
fmt.Println(fn(2)) //36
}
```
### <span id="Watcher">Watcher</span>
@@ -315,6 +354,7 @@ type Watcher struct {
stopTime int64
excuting bool
}
func NewWatcher() *Watcher
func (w *Watcher) Start() //start the watcher
func (w *Watcher) Stop() //stop the watcher
func (w *Watcher) Reset() //reset the watcher
@@ -331,7 +371,8 @@ import (
)
func main() {
w := &function.Watcher{}
w := function.NewWatcher()
w.Start()
longRunningTask()
@@ -341,14 +382,10 @@ func main() {
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
w.Reset()
fmt.Println(w.excuting) //false
fmt.Println(w.startTime) //0
fmt.Println(w.stopTime) //0
}
func longRunningTask() {

View File

@@ -22,10 +22,11 @@ import (
## 目录
- [After](#After)
- [Before](#Before)
- [Curry](#Curry)
- [CurryFn](#CurryFn)
- [Compose](#Compose)
- [Debounced](#Debounced)
- [Delay](#Delay)
- [Pipeline](#Pipeline)
- [Watcher](#Watcher)
<div STYLE="page-break-after: always;"></div>
@@ -101,8 +102,6 @@ import (
)
func main() {
assert := internal.NewAssert(t, "TestBefore")
arr := []string{"a", "b", "c", "d", "e"}
f := function.Before(3, func(i int) int {
return i
@@ -119,22 +118,21 @@ func main() {
appendStr(i, arr[i], f)
}
expected := []int64{0, 1, 2, 2, 2}
assert.Equal(expected, res)
fmt.Println(res) // 0, 1, 2, 2, 2
}
```
### <span id="Curry">Curry</span>
### <span id="CurryFn">CurryFn</span>
<p>创建一个柯里化函数</p>
<p>创建柯里化函数</p>
<b>函数签名:</b>
```go
type Fn func(...any) any
func (f Fn) Curry(i any) func(...any) any
type CurryFn[T any] func(...T) T
func (cf CurryFn[T]) New(val T) func(...T) T
```
<b>例子:</b>
@@ -150,11 +148,14 @@ func main() {
add := func(a, b int) int {
return a + b
}
var addCurry function.Fn = func(values ...any) any {
return add(values[0].(int), values[1].(int))
var addCurry CurryFn[int] = func(values ...int) int {
return add(values[0], values[1])
}
add1 := addCurry.Curry(1)
add1 := addCurry.New(1)
result := add1(2)
fmt.Println(result) //3
}
```
@@ -163,12 +164,12 @@ func main() {
### <span id="Compose">Compose</span>
<p>从右至左组合函数列表fnList 返回组合后的函数</p>
<p>从右至左组合函数列表fnList返回组合后的函数</p>
<b>函数签名:</b>
```go
func Compose(fnList ...func(...any) any) func(...any) any
func Compose[T any](fnList ...func(...T) T) func(...T) T
```
<b>例子:</b>
@@ -181,17 +182,17 @@ import (
)
func main() {
add1 := func(v ...any) any {
return v[0].(int) + 1
toUpper := func(strs ...string) string {
return strings.ToUpper(strs[0])
}
add2 := func(v ...any) any {
return v[0].(int) + 2
toLower := func(strs ...string) string {
return strings.ToLower(strs[0])
}
transform := Compose(toUpper, toLower)
add3 := function.Compose(add1, add2)
result := add3(1)
result := transform("aBCde")
fmt.Println(result) //4
fmt.Println(result) //ABCDE
}
```
@@ -199,7 +200,7 @@ func main() {
### <span id="Debounced">Debounced</span>
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
<p>创建一个debounced函数该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。</p>
<b>函数签名:</b>
@@ -297,7 +298,45 @@ func main() {
time.Sleep(5 * time.Second)
close(stop)
fmt.Println(res) //[* * * * *]
fmt.Println(res) //[* * * * *]
}
```
### <span id="Pipeline">Pipeline</span>
<p>执行函数pipeline.</p>
<b>函数签名:</b>
```go
func Pipeline[T any](funcs ...func(T) T) func(T) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
addOne := func(x int) int {
return x + 1
}
double := func(x int) int {
return 2 * x
}
square := func(x int) int {
return x * x
}
f := Pipeline(addOne, double, square)
fmt.Println(fn(2)) //36
}
```
@@ -305,7 +344,7 @@ func main() {
### <span id="Watcher">Watcher</span>
<p>Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。 </p>
<p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p>
<b>函数签名:</b>
@@ -315,6 +354,7 @@ type Watcher struct {
stopTime int64
excuting bool
}
func NewWatcher() *Watcher
func (w *Watcher) Start() //start the watcher
func (w *Watcher) Stop() //stop the watcher
func (w *Watcher) Reset() //reset the watcher
@@ -331,7 +371,8 @@ import (
)
func main() {
w := &function.Watcher{}
w := function.NewWatcher()
w.Start()
longRunningTask()
@@ -341,14 +382,11 @@ func main() {
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
w.Reset()
fmt.Println(w.excuting) //false
fmt.Println(w.startTime) //0
fmt.Println(w.stopTime) //0
}
func longRunningTask() {

View File

@@ -5,7 +5,7 @@ Package maputil includes some functions to manipulate map.
## Source:
- [https://github.com/duke-git/lancet/blob/main/maputil/maputil.go](https://github.com/duke-git/lancet/blob/main/maputil/maputil.go)
- [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go)
<div STYLE="page-break-after: always;"></div>
@@ -27,6 +27,7 @@ import (
- [Merge](#Merge)
- [Minus](#Minus)
- [Values](#Values)
- [IsDisjoint](#IsDisjoint)
<div STYLE="page-break-after: always;"></div>
@@ -301,4 +302,51 @@ func main() {
fmt.Println(values) // []string{"a", "a", "b", "c", "d"}
}
```
### <span id="IsDisjoint">IsDisjoint</span>
<p>Checks two maps are disjoint if they have no keys in common</p>
<b>Signature:</b>
```go
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
m2 := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
m3 := map[int]string{
6: "a",
}
ok := maputil.IsDisjoint(m2, m1)
fmt.Println(ok) // false
ok = maputil.IsDisjoint(m2, m3)
fmt.Println(ok) // true
}
```

View File

@@ -5,7 +5,7 @@ maputil包包括一些操作map的函数。
## 源码:
- [https://github.com/duke-git/lancet/blob/main/maputil/maputil.go](https://github.com/duke-git/lancet/blob/main/maputil/maputil.go)
- [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go)
<div STYLE="page-break-after: always;"></div>
@@ -27,6 +27,7 @@ import (
- [Merge](#Merge)
- [Minus](#Minus)
- [Values](#Values)
- [IsDisjoint](#IsDisjoint)
<div STYLE="page-break-after: always;"></div>
@@ -231,7 +232,6 @@ func main() {
### <span id="Minus">Minus</span>
<p>返回一个map其中的key存在于mapA不存在于mapB.</p>
@@ -301,4 +301,52 @@ func main() {
fmt.Println(values) // []string{"a", "a", "b", "c", "d"}
}
```
### <span id="IsDisjoint">IsDisjoint</span>
<p>验证两个map是否具有不同的key</p>
<b>函数签名:</b>
```go
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
m2 := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
m3 := map[int]string{
6: "a",
}
ok := maputil.IsDisjoint(m2, m1)
fmt.Println(ok) // false
ok = maputil.IsDisjoint(m2, m3)
fmt.Println(ok) // true
}
```

View File

@@ -28,7 +28,6 @@ import (
- [MaxBy](#MaxBy)
- [Min](#Min)
- [MinBy](#MaxBy)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
@@ -46,7 +45,7 @@ import (
<b>Signature:</b>
```go
func Average[T lancetconstraints.Number](numbers ...T) T
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>Example:</b>
@@ -158,7 +157,7 @@ func main() {
<b>Signature:</b>
```go
func Max[T lancetconstraints.Number](numbers ...T) T
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>Example:</b>
@@ -219,12 +218,12 @@ func main() {
### <span id="Min">Min</span>
<p>Return min value of numbers.</p>
<p>Return the minimum value of numbers.</p>
<b>Signature:</b>
```go
func Min[T lancetconstraints.Number](numbers ...T) T
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>Example:</b>
@@ -303,8 +302,8 @@ import (
)
func main() {
fmt.Println(mathutil.Percent(1, 2, 2)) //1
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
}
```

View File

@@ -28,7 +28,6 @@ import (
- [MaxBy](#MaxBy)
- [Min](#Min)
- [MinBy](#MaxBy)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
@@ -45,7 +44,7 @@ import (
<b>函数签名:</b>
```go
func Average[T lancetconstraints.Number](numbers ...T) T
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>例子:</b>
@@ -155,7 +154,7 @@ func main() {
<b>函数签名:</b>
```go
func Max[T lancetconstraints.Number](numbers ...T) T
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>例子:</b>
@@ -221,7 +220,7 @@ func main() {
<b>函数签名:</b>
```go
func Min[T lancetconstraints.Number](numbers ...T) T
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>例子:</b>
@@ -300,8 +299,8 @@ import (
)
func main() {
fmt.Println(mathutil.Percent(1, 2, 2)) //1
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
}
```

View File

@@ -7,6 +7,8 @@ Package netutil contains functions to get net information and send http request.
- [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http_client.go](https://github.com/duke-git/lancet/blob/main/netutil/http_client.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go)
<div STYLE="page-break-after: always;"></div>
@@ -22,17 +24,24 @@ import (
## Index
- [ConvertMapToQueryString](#ConvertMapToQueryString)
- [EncodeUrl](#EncodeUrl)
- [GetInternalIp](#GetInternalIp)
- [GetIps](#GetIps)
- [GetMacAddrs](#GetMacAddrs)
- [GetPublicIpInfo](#GetPublicIpInfo)
- [GetRequestPublicIp](#GetRequestPublicIp)
- [IsPublicIP](#IsPublicIP)
- [HttpGet](#HttpGet)
- [HttpDelete](#HttpDelete)
- [HttpPost](#HttpPost)
- [HttpPut](#HttpPut)
- [HttpPatch](#HttpPatch)
- [IsInternalIP](#IsInternalIP)
- [HttpRequest](#HttpRequest)
- [HttpClient](#HttpClient)
- [SendRequest](#SendRequest)
- [DecodeResponse](#DecodeResponse)
- [StructToUrlValues](#StructToUrlValues)
- [HttpGet<sup>Deprecated</sup>](#HttpGet)
- [HttpDelete<sup>Deprecated</sup>](#HttpDelete)
- [HttpPost<sup>Deprecated</sup>](#HttpPost)
- [HttpPut<sup>Deprecated</sup>](#HttpPut)
- [HttpPatch<sup>Deprecated</sup>](#HttpPatch)
- [ParseHttpResponse](#ParseHttpResponse)
<div STYLE="page-break-after: always;"></div>
@@ -72,6 +81,36 @@ func main() {
### <span id="EncodeUrl">EncodeUrl</span>
<p>Encode url query string values.</p>
<b>Signature:</b>
```go
func EncodeUrl(urlStr string) (string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
urlAddr := "http://www.lancet.com?a=1&b=[2]"
encodedUrl, err := netutil.EncodeUrl(urlAddr)
if err != nil {
fmt.Println(err)
}
fmt.Println(encodedUrl) //http://www.lancet.com?a=1&b=%5B2%5D
}
```
### <span id="GetInternalIp">GetInternalIp</span>
<p>Get internal ip information.</p>
@@ -199,8 +238,51 @@ func main() {
### <span id="GetRequestPublicIp">GetRequestPublicIp</span>
<p>Get http request public ip.</p>
<b>Signature:</b>
```go
func GetRequestPublicIp(req *http.Request) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip := "36.112.24.10"
request1 := http.Request{
Method: "GET",
Header: http.Header{
"X-Forwarded-For": {ip},
},
}
publicIp1 := netutil.GetRequestPublicIp(&request1)
fmt.Println(publicIp1) //36.112.24.10
request2 := http.Request{
Method: "GET",
Header: http.Header{
"X-Real-Ip": {ip},
},
}
publicIp2 := netutil.GetRequestPublicIp(&request2)
fmt.Println(publicIp2) //36.112.24.10
}
```
### <span id="IsPublicIP">IsPublicIP</span>
<p>Checks if a ip is public or not.</p>
<p>Checks if an ip is public or not.</p>
<b>Signature:</b>
@@ -230,14 +312,268 @@ func main() {
### <span id="HttpGet">HttpGet</span>
### <span id="IsInternalIP">IsInternalIP</span>
<p>Checks if an ip is intranet or not.</p>
<b>Signature:</b>
```go
func IsInternalIP(IP net.IP) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip1 := net.ParseIP("127.0.0.1")
ip2 := net.ParseIP("36.112.24.10")
fmt.Println(netutil.IsInternalIP(ip1)) //true
fmt.Println(netutil.IsInternalIP(ip2)) //false
}
```
### <span id="HttpRequest">HttpRequest</span>
<p>HttpRequest is a struct used to abstract HTTP request entity.</p>
<b>Signature:</b>
```go
type HttpRequest struct {
RawURL string
Method string
Headers http.Header
QueryParams url.Values
FormData url.Values
Body []byte
}
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
header := http.Header{}
header.Add("Content-Type", "multipart/form-data")
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "testItem")
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "POST",
Headers: header,
FormData: postData,
}
}
```
### <span id="HttpClient">HttpClient</span>
<p>HttpClient is a struct used to send HTTP request. It can be instanced with some configurations or none config.</p>
<b>Signature:</b>
```go
type HttpClient struct {
*http.Client
TLS *tls.Config
Request *http.Request
Config HttpClientConfig
}
type HttpClientConfig struct {
SSLEnabled bool
TLSConfig *tls.Config
Compressed bool
HandshakeTimeout time.Duration
ResponseTimeout time.Duration
Verbose bool
}
func NewHttpClient() *HttpClient
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
httpClientCfg := netutil.HttpClientConfig{
SSLEnabled: true,
HandshakeTimeout:10 * time.Second
}
httpClient := netutil.NewHttpClientWithConfig(&httpClientCfg)
}
```
### <span id="SendRequest">SendRequest</span>
<p>Use HttpClient to send HTTP request.</p>
<b>Signature:</b>
```go
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
fmt.Println(todo.Id) //1
}
```
### <span id="DecodeResponse">DecodeResponse</span>
<p>Decode http response into target object.</p>
<b>Signature:</b>
```go
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
fmt.Println(todo.Id) //1
}
```
### <span id="StructToUrlValues">StructToUrlValues</span>
<p>Convert struct to url values, only convert the field which is exported and has `json` tag.</p>
<b>Signature:</b>
```go
func StructToUrlValues(targetStruct any) url.Values
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
type TodoQuery struct {
Id int `json:"id"`
UserId int `json:"userId"`
}
todoQuery := TodoQuery{
Id: 1,
UserId: 2,
}
todoValues := netutil.StructToUrlValues(todoQuery)
fmt.Println(todoValues.Get("id")) //1
fmt.Println(todoValues.Get("userId")) //2
}
```
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
<p>Send http get request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpGet(url string, params ...any) (*http.Response, error)
@@ -272,14 +608,14 @@ func main() {
### <span id="HttpPost">HttpPost</span>
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
<p>Send http post request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpPost(url string, params ...any) (*http.Response, error)
@@ -321,14 +657,14 @@ func main() {
### <span id="HttpPut">HttpPut</span>
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
<p>Send http put request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpPut(url string, params ...any) (*http.Response, error)
@@ -371,14 +707,14 @@ func main() {
### <span id="HttpDelete">HttpDelete</span>
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
<p>Send http delete request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpDelete(url string, params ...any) (*http.Response, error)
@@ -410,14 +746,14 @@ func main() {
### <span id="HttpPatch">HttpPatch</span>
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
<p>Send http patch request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpPatch(url string, params ...any) (*http.Response, error)

View File

@@ -6,6 +6,9 @@ netutil网络包支持获取ip地址发送http请求。
## 源码:
- [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http_client.go](https://github.com/duke-git/lancet/blob/main/netutil/http_client.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go)
<div STYLE="page-break-after: always;"></div>
@@ -21,17 +24,24 @@ import (
## 目录
- [ConvertMapToQueryString](#ConvertMapToQueryString)
- [EncodeUrl](#EncodeUrl)
- [GetInternalIp](#GetInternalIp)
- [GetIps](#GetIps)
- [GetMacAddrs](#GetMacAddrs)
- [GetPublicIpInfo](#GetPublicIpInfo)
- [GetRequestPublicIp](#GetRequestPublicIp)
- [IsPublicIP](#IsPublicIP)
- [HttpGet](#HttpGet)
- [HttpDelete](#HttpDelete)
- [HttpPost](#HttpPost)
- [HttpPut](#HttpPut)
- [HttpPatch](#HttpPatch)
- [IsInternalIP](#IsInternalIP)
- [HttpRequest](#HttpRequest)
- [HttpClient](#HttpClient)
- [SendRequest](#SendRequest)
- [DecodeResponse](#DecodeResponse)
- [StructToUrlValues](#StructToUrlValues)
- [HttpGet<sup>Deprecated</sup>](#HttpGet)
- [HttpDelete<sup>Deprecated</sup>](#HttpDelete)
- [HttpPost<sup>Deprecated</sup>](#HttpPost)
- [HttpPut<sup>Deprecated</sup>](#HttpPut)
- [HttpPatch<sup>Deprecated</sup>](#HttpPatch)
- [ParseHttpResponse](#ParseHttpResponse)
<div STYLE="page-break-after: always;"></div>
@@ -71,6 +81,37 @@ func main() {
### <span id="EncodeUrl">EncodeUrl</span>
<p>编码url query string的值</p>
<b>函数签名:</b>
```go
func EncodeUrl(urlStr string) (string, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
urlAddr := "http://www.lancet.com?a=1&b=[2]"
encodedUrl, err := netutil.EncodeUrl(urlAddr)
if err != nil {
fmt.Println(err)
}
fmt.Println(encodedUrl) //http://www.lancet.com?a=1&b=%5B2%5D
}
```
### <span id="GetInternalIp">GetInternalIp</span>
<p>获取内部ip</p>
@@ -197,6 +238,50 @@ func main() {
### <span id="GetRequestPublicIp">GetRequestPublicIp</span>
<p>获取http请求ip</p>
<b>函数签名:</b>
```go
func GetRequestPublicIp(req *http.Request) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip := "36.112.24.10"
request1 := http.Request{
Method: "GET",
Header: http.Header{
"X-Forwarded-For": {ip},
},
}
publicIp1 := netutil.GetRequestPublicIp(&request1)
fmt.Println(publicIp1) //36.112.24.10
request2 := http.Request{
Method: "GET",
Header: http.Header{
"X-Real-Ip": {ip},
},
}
publicIp2 := netutil.GetRequestPublicIp(&request2)
fmt.Println(publicIp2) //36.112.24.10
}
```
### <span id="IsPublicIP">IsPublicIP</span>
<p>判断ip是否是公共ip</p>
@@ -227,15 +312,268 @@ func main() {
### <span id="IsInternalIP">IsInternalIP</span>
<p>判断ip是否是局域网ip.</p>
### <span id="HttpGet">HttpGet</span>
<b>函数签名:</b>
```go
func IsInternalIP(IP net.IP) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip1 := net.ParseIP("127.0.0.1")
ip2 := net.ParseIP("36.112.24.10")
fmt.Println(netutil.IsInternalIP(ip1)) //true
fmt.Println(netutil.IsInternalIP(ip2)) //false
}
```
### <span id="HttpRequest">HttpRequest</span>
<p>HttpRequest用于抽象HTTP请求实体的结构</p>
<b>函数签名:</b>
```go
type HttpRequest struct {
RawURL string
Method string
Headers http.Header
QueryParams url.Values
FormData url.Values
Body []byte
}
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
header := http.Header{}
header.Add("Content-Type", "multipart/form-data")
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "testItem")
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "POST",
Headers: header,
FormData: postData,
}
}
```
### <span id="HttpClient">HttpClient</span>
<p>HttpClient是用于发送HTTP请求的结构体。它可以用一些配置参数或无配置实例化.</p>
<b>函数签名:</b>
```go
type HttpClient struct {
*http.Client
TLS *tls.Config
Request *http.Request
Config HttpClientConfig
}
type HttpClientConfig struct {
SSLEnabled bool
TLSConfig *tls.Config
Compressed bool
HandshakeTimeout time.Duration
ResponseTimeout time.Duration
Verbose bool
}
func NewHttpClient() *HttpClient
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
httpClientCfg := netutil.HttpClientConfig{
SSLEnabled: true,
HandshakeTimeout:10 * time.Second
}
httpClient := netutil.NewHttpClientWithConfig(&httpClientCfg)
}
```
### <span id="SendRequest">SendRequest</span>
<p>HttpClient发送http请求</p>
<b>函数签名:</b>
```go
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
fmt.Println(todo.Id) //1
}
```
### <span id="DecodeResponse">DecodeResponse</span>
<p>解析http响应体到目标结构体</p>
<b>函数签名:</b>
```go
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
fmt.Println(todo.Id) //1
}
```
### <span id="StructToUrlValues">StructToUrlValues</span>
<p>将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag</p>
<b>函数签名:</b>
```go
func StructToUrlValues(targetStruct any) url.Values
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
type TodoQuery struct {
Id int `json:"id"`
UserId int `json:"userId"`
}
todoQuery := TodoQuery{
Id: 1,
UserId: 2,
}
todoValues := netutil.StructToUrlValues(todoQuery)
fmt.Println(todoValues.Get("id")) //1
fmt.Println(todoValues.Get("userId")) //2
}
```
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
<p>发送http get请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpGet(url string, params ...any) (*http.Response, error)
@@ -270,14 +608,14 @@ func main() {
### <span id="HttpPost">HttpPost</span>
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
<p>发送http post请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpPost(url string, params ...any) (*http.Response, error)
@@ -319,19 +657,19 @@ func main() {
### <span id="HttpPut">HttpPut</span>
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
<p>发送http put请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpPut(url string, params ...any) (*http.Response, error)
```
<b>Example:</b>
<b>例子:</b>
```go
package main
@@ -369,14 +707,14 @@ func main() {
### <span id="HttpDelete">HttpDelete</span>
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
<p>发送http delete请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpDelete(url string, params ...any) (*http.Response, error)
@@ -408,14 +746,14 @@ func main() {
### <span id="HttpPatch">HttpPatch</span>
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
<p>发送http patch请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpPatch(url string, params ...any) (*http.Response, error)

View File

@@ -1,16 +1,17 @@
# Random
Package random implements some basic functions to generate random int and string.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
- [https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/random"
@@ -20,17 +21,22 @@ import (
<div STYLE="page-break-after: always;"></div>
## Index
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [UUIdV4](#UUIdV4)
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [RandUpper](#RandUpper)
- [RandLower](#RandLower)
- [RandNumeral](#RandNumeral)
- [RandNumeralOrLetter](#RandNumeralOrLetter)
- [UUIdV4](#UUIdV4)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="RandBytes">RandBytes</span>
<p>Generate random byte slice.</p>
<b>Signature:</b>
@@ -38,6 +44,7 @@ import (
```go
func RandBytes(length int) []byte
```
<b>Example:</b>
```go
@@ -54,8 +61,8 @@ func main() {
}
```
### <span id="RandInt">RandInt</span>
<p>Generate random int between min and max, may contain min, not max.</p>
<b>Signature:</b>
@@ -63,6 +70,7 @@ func main() {
```go
func RandInt(min, max int) int
```
<b>Example:</b>
```go
@@ -79,16 +87,16 @@ func main() {
}
```
### <span id="RandString">RandString</span>
### <span id="RandString">RandInt</span>
<p>Generate random given length string.</p>
<p>Generate random given length string. only contains letter (a-zA-Z)</p>
<b>Signature:</b>
```go
func RandString(length int) string
```
<b>Example:</b>
```go
@@ -101,14 +109,116 @@ import (
func main() {
randStr := random.RandString(6)
fmt.Println(randStr)
fmt.Println(randStr) //pGWsze
}
```
### <span id="RandUpper">RandUpper</span>
<p>Generate a random upper case string</p>
<b>Signature:</b>
```go
func RandUpper(length int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr) //PACWGF
}
```
### <span id="RandLower">RandLower</span>
<p>Generate a random lower case string</p>
<b>Signature:</b>
```go
func RandLower(length int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandLower(6)
fmt.Println(randStr) //siqbew
}
```
### <span id="RandNumeral">RandNumeral</span>
<p>Generate a random numeral string</p>
<b>Signature:</b>
```go
func RandNumeral(length int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandNumeral(6)
fmt.Println(randStr) //035172
}
```
### <span id="RandNumeralOrLetter">RandNumeralOrLetter</span>
<p>generate a random numeral or letter string</p>
<b>Signature:</b>
```go
func RandNumeralOrLetter(length int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandNumeralOrLetter(6)
fmt.Println(randStr) //0aW7cQ
}
```
### <span id="UUIdV4">UUIdV4</span>
<p>Generate a random UUID of version 4 according to RFC 4122.</p>
<b>Signature:</b>
@@ -116,6 +226,7 @@ func main() {
```go
func UUIdV4() (string, error)
```
<b>Example:</b>
```go
@@ -134,5 +245,3 @@ func main() {
fmt.Println(uuid)
}
```

View File

@@ -1,16 +1,17 @@
# Random
random随机数生成器包可以生成随机[]bytes, int, string。
random 随机数生成器包,可以生成随机[]bytes, int, string。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
- [https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/random"
@@ -20,18 +21,22 @@ import (
<div STYLE="page-break-after: always;"></div>
## 目录
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [UUIdV4](#UUIdV4)
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [RandUpper](#RandUpper)
- [RandLower](#RandLower)
- [RandNumeral](#RandNumeral)
- [RandNumeralOrLetter](#RandNumeralOrLetter)
- [UUIdV4](#UUIdV4)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="RandBytes">RandBytes</span>
<p>生成随机字节切片</p>
<b>函数签名:</b>
@@ -39,6 +44,7 @@ import (
```go
func RandBytes(length int) []byte
```
<b>例子:</b>
```go
@@ -55,8 +61,8 @@ func main() {
}
```
### <span id="RandInt">RandInt</span>
<p>生成随机int, 范围[min, max)</p>
<b>函数签名:</b>
@@ -64,6 +70,7 @@ func main() {
```go
func RandInt(min, max int) int
```
<b>例子:</b>
```go
@@ -80,16 +87,16 @@ func main() {
}
```
### <span id="RandString">RandString</span>
### <span id="RandString">RandInt</span>
<p>生成随机给定长度的随机字符串</p>
<p>生成给定长度的随机字符串,只包含字母(a-zA-Z)</p>
<b>函数签名:</b>
```go
func RandString(length int) string
```
<b>例子:</b>
```go
@@ -102,13 +109,116 @@ import (
func main() {
randStr := random.RandString(6)
fmt.Println(randStr)
fmt.Println(randStr) //pGWsze
}
```
### <span id="RandUpper">RandUpper</span>
<p>生成给定长度的随机大写字母字符串</p>
<b>函数签名:</b>
```go
func RandUpper(length int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr) //PACWGF
}
```
### <span id="RandLower">RandLower</span>
<p>生成给定长度的随机小写字母字符串</p>
<b>函数签名:</b>
```go
func RandLower(length int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandLower(6)
fmt.Println(randStr) //siqbew
}
```
### <span id="RandNumeral">RandNumeral</span>
<p>生成给定长度的随机数字字符串</p>
<b>函数签名:</b>
```go
func RandNumeral(length int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandNumeral(6)
fmt.Println(randStr) //035172
}
```
### <span id="RandNumeralOrLetter">RandNumeralOrLetter</span>
<p>生成给定长度的随机字符串(数字+字母)</p>
<b>函数签名:</b>
```go
func RandNumeralOrLetter(length int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandNumeralOrLetter(6)
fmt.Println(randStr) //0aW7cQ
}
```
### <span id="UUIdV4">UUIdV4</span>
<p>生成UUID v4字符串</p>
<b>函数签名:</b>
@@ -116,6 +226,7 @@ func main() {
```go
func UUIdV4() (string, error)
```
<b>例子:</b>
```go
@@ -134,5 +245,3 @@ func main() {
fmt.Println(uuid)
}
```

View File

@@ -97,8 +97,8 @@ import (
func main() {
var number int
var increaseNumber retry.RetryFunc
increaseNumber = func() error {
increaseNumber := func() error {
number++
if number == 3 {
return nil
@@ -139,6 +139,7 @@ import (
func main() {
var number int
increaseNumber := func() error {
number++
if number == 3 {

View File

@@ -99,8 +99,7 @@ import (
func main() {
var number int
var increaseNumber retry.RetryFunc
increaseNumber = func() error {
increaseNumber := func() error {
number++
if number == 3 {
return nil

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