{"id":28715208,"url":"https://github.com/bytedance/gg","last_synced_at":"2025-06-15T02:03:04.009Z","repository":{"id":294415856,"uuid":"982115336","full_name":"bytedance/gg","owner":"bytedance","description":"🔥gg is a basic library of generics for Go language developed by ByteDance. It is based on the Go 1.18+ generic features and provides efficient, type-safe and rich generic data structures and tool functions.","archived":false,"fork":false,"pushed_at":"2025-05-29T19:32:44.000Z","size":292,"stargazers_count":94,"open_issues_count":0,"forks_count":8,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-29T19:42:29.911Z","etag":null,"topics":["generics","go","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bytedance.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-12T11:54:46.000Z","updated_at":"2025-05-29T18:34:32.000Z","dependencies_parsed_at":"2025-05-29T19:24:08.708Z","dependency_job_id":null,"html_url":"https://github.com/bytedance/gg","commit_stats":null,"previous_names":["bytedance/gg"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bytedance/gg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fgg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fgg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fgg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fgg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bytedance","download_url":"https://codeload.github.com/bytedance/gg/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytedance%2Fgg/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259910673,"owners_count":22930702,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["generics","go","golang"],"created_at":"2025-06-15T02:01:13.857Z","updated_at":"2025-06-15T02:03:04.003Z","avatar_url":"https://github.com/bytedance.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# gg: Go Generics\n\n[![GoDoc](https://godoc.org/github.com/bytedance/gg?status.svg)](https://godoc.org/github.com/bytedance/gg)\n[![Go Report Card](https://goreportcard.com/badge/github.com/bytedance/gg)](https://goreportcard.com/report/github.com/bytedance/gg)\n[![Go Coverage](https://codecov.io/gh/bytedance/gg/branch/main/graph/badge.svg)](https://codecov.io/gh/bytedance/gg)\n[![License](https://img.shields.io/github/license/bytedance/gg)](https://github.com/bytedance/gg/blob/main/LICENSE)\n\nEnglish | [简体中文](README.zh-CN.md)\n\n🔥`bytedance/gg` is a basic library of generics for Go language developed by ByteDance. It is based on the Go 1.18+ generic features and provides efficient, type-safe and rich generic data structures and tool functions.\n\n❓**Why this name?**\n\nTake the first letter of **G**o **G**enerics, short and simple.\n\n❓**Why choose gg?**\n\n- Stable and reliable: It is a necessary tool library for ByteDance R\u0026D team, and it has 1w+ repository references inside.\n- Easy to use: With the design principle of simplicity and self-consistent, subcontracted according to functions, modular, semantic intuitive and unified, and low learning cost.\n- High Performance: Provides high-performance concurrent data structures, with performance 10+ times faster than standard library.\n- No three-party dependencies: Generic libraries will not introduce any three-party dependencies.\n- Version control: Follow the SemVer, guaranteeing backward compatibility.\n\n## 🚀 Install\n\n```sh\ngo get github.com/bytedance/gg\n```\n\n## 🔎 Table of contents\n\n- [Generic Functional Programming](#-generic-functional-programming)\n  - [goption](#goption)：Option type, simplifying the processing of `(T, bool)`\n  - [gresult](#gresult)：Result type, simplifying the processing of `(T, error)`\n- [Generic Data Processing](#-generic-data-processing)\n  - [gcond](#gcond)：Conditional operation\n  - [gvalue](#gvalue)：Processing value `T`\n  - [gptr](#gptr)：Processing pointer `*T`\n  - [gslice](#gslice)：Processing slice `[]T`\n  - [gmap](#gmap)：Processing map `map[K]V`\n  - [gfunc](#gfunc)：Processing function `func`\n  - [gconv](#gconv)：Data type conversion\n  - [gson](#gson)：Processing JSON\n- [Generic Standard Wrapper](#-generic-standard-wrapper)\n  - [gsync](#gsync)：Wrap `sync`\n- [Generic Data Structures](#-generic-data-structures)\n  - [tuple](#tuple)：Implementation of tuple provides definition of generic n-ary tuples\n  - [set](#set)：Implementation of set based on `map[T]struct{}`\n  - [skipset](#skipset)：High-performance, scalable, concurrent-safe set based on skip-list, up to 15x faster than the built-in `sync.Map` below Go 1.24\n  - [skipmap](#skipmap)：High-performance, scalable, concurrent-safe map based on skip-list, up to 10x faster than the built-in `sync.Map` below Go 1.24\n\n## ✨ Generic Functional Programming\n\n### goption\n\nOption type, simplifying the processing of `(T, bool)`\n\nUsage：\n\n```go\nimport (\n    \"github.com/bytedance/gg/goption\"\n)\n```\n\nExample:\n\n```go\ngoption.Of(1, true).Value()\n// 1\ngoption.Nil[int]().IsNil()\n// true\ngoption.Nil[int]().ValueOr(10)\n// 10\ngoption.OK(1).IsOK()\n// true\ngoption.OK(1).ValueOrZero()\n// 1\ngoption.OfPtr((*int)(nil)).Ptr()\n// nil\ngoption.Map(goption.OK(1), strconv.Itoa).Get()\n// \"1\" true\n```\n\n### gresult\n\nResult type, simplifying the processing of `(T, error)`\n\nUsage：\n\n```go\nimport (\n    \"github.com/bytedance/gg/gresult\"\n)\n```\n\nExample:\n\n```go\ngresult.Of(strconv.Atoi(\"1\")).Value()\n// 1\ngresult.Err[int](io.EOF).IsErr()\n// true\ngresult.Err[int](io.EOF).ValueOr(10)\n// 10\ngresult.OK(1).IsOK()\n// true\ngresult.OK(1).ValueOrZero()\n// 1\ngresult.Of(strconv.Atoi(\"x\")).Option().Get()\n// 0 false\ngresult.Map(gresult.OK(1), strconv.Itoa).Get()\n// \"1\" nil\n```\n\n## ✨ Generic Data Processing\n\n### gcond：\n\nConditional operation\n\nUsage：\n\n```go\nimport (\n    \"github.com/bytedance/gg/gcond\"\n)\n```\n\nExample：\n\n```go\ngcond.If(true, 1, 2)\n// 1\nvar a *struct{ A int }\ngetA := func() int { return a.A }\nget1 := func() int { return 1 }\ngcond.IfLazy(a != nil, getA, get1)\n// 1\ngcond.IfLazyL(a != nil, getA, 1)\n// 1\ngcond.IfLazyR(a == nil, 1, getA)\n// 1\n\ngcond.Switch[string](3).\n    Case(1, \"1\").\n    CaseLazy(2, func() string { return \"3\" }).\n    When(3, 4).Then(\"3/4\").\n    When(5, 6).ThenLazy(func() string { return \"5/6\" }).\n    Default(\"other\")\n// 3/4\n```\n\n### gvalue\n\nProcessing value `T`\n\nUsage：\n```go\nimport (\n    \"github.com/bytedance/gg/gvalue\"\n)\n```\n\nExample1：Zero Value\n\n```go\na := gvalue.Zero[int]()\n// 0\ngvalue.IsZero(a)\n// true\nb := gvalue.Zero[*int]()\n// nil\ngvalue.IsNil(b)\n// true\ngvalue.Or(0, 1, 2)\n// 1\n```\n\nExample2：Math Operation\n\n```go\ngvalue.Max(1, 2, 3)\n// 3\ngvalue.Min(1, 2, 3)\n// 1\ngvalue.MinMax(1, 2, 3)\n// 1 3\ngvalue.Clamp(5, 1, 10)\n// 5\ngvalue.Add(1, 2)\n// 3\n```\n\nExample3：Comparison\n\n```go\ngvalue.Equal(1, 1)\n// true\ngvalue.Between(2, 1, 3)\n// true\n```\n\nExample4：Type Assertion\n\n```go\ngvalue.TypeAssert[int](any(1))\n// 1\ngvalue.TryAssert[int](any(1))\n// 1 true\n```\n\n### gptr\n\nProcessing pointer `*T`\n\nUsage：\n\n```go\nimport (\n    \"github.com/bytedance/gg/gptr\"\n)\n```\n\nExample：\n\n```go\na := Of(1)\ngptr.Indirect(a)\n// 1\n\nb := OfNotZero(1)\ngptr.IsNotNil(b)\n// true\ngptr.IndirectOr(b, 2)\n// 1\ngptr.Indirect(gptr.Map(b, strconv.Itoa))\n// \"1\"\n\nc := OfNotZero(0)\n// nil\ngptr.IsNil(c)\n// true\ngptr.IndirectOr(c, 2)\n// 2\n```\n\n### gslice\n\nProcessing slice `[]T`\n\nUsage：\n\n```go\nimport (\n    \"github.com/bytedance/gg/gslice\"\n)\n```\n\nExample1：High-order Function\n\n```go\ngslice.Map([]int{1, 2, 3, 4, 5}, strconv.Itoa)\n// [\"1\", \"2\", \"3\", \"4\", \"5\"]\nisEven := func(i int) bool { return i%2 == 0 }\ngslice.Filter([]int{1, 2, 3, 4, 5}, isEven)\n// [2, 4]\ngslice.Reduce([]int{1, 2, 3, 4, 5}, gvalue.Add[int].Value())\n// 15\ngslice.Any([]int{1, 2, 3, 4, 5}, isEven)\n// true\ngslice.All([]int{1, 2, 3, 4, 5}, isEven)\n// false\n```\n\nExample2：CURD Operation\n\n```go\ngslice.Contains([]int{1, 2, 3, 4, 5}, 2)\n// true\ngslice.ContainsAny([]int{1, 2, 3, 4, 5}, 2, 6)\n// true\ngslice.ContainsAll([]int{1, 2, 3, 4, 5}, 2, 6)\n// false\ngslice.Index([]int{1, 2, 3, 4, 5}, 3.Value())\n// 2\ngslice.Find([]int{1, 2, 3, 4, 5}, isEven).Value()\n// 2\ngslice.First([]int{1, 2, 3, 4, 5}).Value()\n// 1\ngslice.Get([]int{1, 2, 3, 4, 5}, 1).Value()\n// 2\ngslice.Get([]int{1, 2, 3, 4, 5}, -1).Value() // Access element with negative index\n// 5\n```\n\nExample3：Partion Operation\n\n```go\ngslice.Range(1, 5)\n// [1, 2, 3, 4]\ngslice.RangeWithStep(5, 1, -2)\n// [5, 3]\ngslice.Take([]int{1, 2, 3, 4, 5}, 2)\n// [1, 2]\ngslice.Take([]int{1, 2, 3, 4, 5}, -2)\n// [4, 5]\ngslice.Slice([]int{1, 2, 3, 4, 5}, 1, 3)\n// [2, 3]\ngslice.Chunk([]int{1, 2, 3, 4, 5}, 2)\n// [[1, 2], [3, 4], [5]]\ngslice.Divide([]int{1, 2, 3, 4, 5}, 2)\n// [[1, 2, 3], [4, 5]]\ngslice.Concat([]int{1, 2}, []int{3, 4, 5})\n// [1, 2, 3, 4, 5]\ngslice.Flatten([][]int{{1, 2}, {3, 4, 5}})\n// [1, 2, 3, 4, 5]\ngslice.Partition([]int{1, 2, 3, 4, 5}, isEven)\n// [2, 4], [1, 3, 5]\n```\n\nExample4：Math Operation\n\n```go\ngslice.Max([]int{1, 2, 3, 4, 5}).Value()\n// 5\ngslice.Min([]int{1, 2, 3, 4, 5}).Value()\n// 1\ngslice.MinMax([]int{1, 2, 3, 4, 5}).Value().Values()\n// 1 5\ngslice.Sum([]int{1, 2, 3, 4, 5})\n// 15\n```\n\nExample5：Convert to map\n\n```go\nToMap([]int{1, 2, 3, 4, 5}, func(i int) (string, int) { return strconv.Itoa(i), i })\n// {\"1\":1, \"2\":2, \"3\":3, \"4\":4, \"5\":5}\nToMapValues([]int{1, 2, 3, 4, 5}, strconv.Itoa)\n// {\"1\":1, \"2\":2, \"3\":3, \"4\":4, \"5\":5}\nGroupBy([]int{1, 2, 3, 4, 5}, func(i int) string {\n  if i%2 == 0 {\n    return \"even\"\n  } else {\n    return \"odd\"\n  }\n})\n// {\"even\":[2,4], \"odd\":[1,3,5]}\n```\n\nExample6：Set Operation\n\n```go\ngslice.Union([]int{1, 2, 3}, []int{3, 4, 5})\n// [1, 2, 3, 4, 5]\ngslice.Intersect([]int{1, 2, 3}, []int{3, 4, 5})\n// [3]\ngslice.Diff([]int{1, 2, 3}, []int{3, 4, 5})\n// [1, 2]\ngslice.Uniq([]int{1, 1, 2, 2, 3})\n// [1, 2, 3]\ngslice.Dup([]int{1, 1, 2, 2, 3})\n// [1, 2]\n```\n\nExample7：Re-order Operation\n\n```go\ns1 := []int{5, 1, 2, 3, 4}\ns2, s3, s4 := Clone(s1), Clone(s1), Clone(s1)\nSort(s1)\n// [1, 2, 3, 4, 5]\nSortBy(s2, func(i, j int) bool { return i \u003e j })\n// [5, 4, 3, 2, 1]\nStableSortBy(s3, func(i, j int) bool { return i \u003e j })\n// [5, 4, 3, 2, 1]\nReverse(s4)\n// [4, 3, 2, 1, 5]\n```\n\n### gmap\n\nProcessing map `map[K]V`\n\nUsage：\n```go\nimport (\n    \"github.com/bytedance/gg/gmap\"\n)\n```\n\nExample1：Keys / Values Getter\n\n```go\ngmap.Keys(map[int]int{1: 2})\n// [1]\ngmap.Values(map[int]int{1: 2})\n// [2]\ngmap.Items(map[int]int{1: 2}).Unzip()\n// [1] [2]\ngmap.OrderedKeys(map[int]int{1: 2, 2: 3, 3: 4})\n// [1, 2, 3]\ngmap.OrderedValues(map[int]int{1: 2, 2: 3, 3: 4})\n// [2, 3, 4]\ngmap.OrderedItems(map[int]int{1: 2, 2: 3, 3: 4}).Unzip()\n// [1, 2, 3] [2, 3, 4]\nf := func(k, v int) string { return strconv.Itoa(k) + \":\" + strconv.Itoa(v) }\ngmap.ToSlice(map[int]int{1: 2}, f)\n// [\"1:2\"]\ngmap.ToOrderedSlice(map[int]int{1: 2, 2: 3, 3: 4}, f)\n// [\"1:2\", \"2:3\", \"3:4\"]\n```\n\nExample2：High-order Function\n\n```go\ngmap.Map(map[int]int{1: 2, 2: 3, 3: 4}, func(k int, v int) (string, string) {\n    return strconv.Itoa(k), strconv.Itoa(k + 1)\n})\n// {\"1\":\"2\", \"2\":\"3\", \"3\":\"4\"}\ngmap.Filter(map[int]int{1: 2, 2: 3, 3: 4}, func(k int, v int) bool {\n    return k+v \u003e 3\n})\n// {\"2\":2, \"3\":3}\n```\n\nExample3：CURD Operation\n\n```go\ngmap.Contains(map[int]int{1: 2, 2: 3, 3: 4}, 1)\n// true\ngmap.ContainsAny(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4)\n// true\ngmap.ContainsAll(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4)\n// false\ngmap.Load(map[int]int{1: 2, 2: 3, 3: 4}, 1).Value()\n// 2\ngmap.LoadAny(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4).Value()\n// 2\ngmap.LoadAll(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4)\n// []\ngmap.LoadSome(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4)\n// [2]\n```\n\nExample4：Partion Operation\n\n```go\nChunk(map[int]int{1: 2, 2: 3, 3: 4, 4: 5, 5: 6}, 2)\n// possible result: [{1:2, 2:3}, {3:4, 4:5}, {5:6}]\nDivide(map[int]int{1: 2, 2: 3, 3: 4, 4: 5, 5: 6}, 2)\n// possible result: [{1:2, 2:3, 3:4}, {4:5, 5:6}]\n```\n\nExample5：Math Operation\n\n```go\ngmap.Max(map[int]int{1: 2, 2: 3, 3: 4}).Value()\n// 4\ngmap.Min(map[int]int{1: 2, 2: 3, 3: 4}).Value()\n// 2\ngmap.MinMax(map[int]int{1: 2, 2: 3, 3: 4}).Value().Values()\n// 2 4\ngmap.Sum(map[int]int{1: 2, 2: 3, 3: 4})\n// 9\n```\n\nExample6：Set Operation\n\n```go\ngmap.Union(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16})\n// {1:2, 2:3, 3:14, 4:15, 5:16}\ngmap.Intersect(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16})\n// {3:14}\ngmap.Diff(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16})\n// {1:2, 2:3}\ngmap.UnionBy(gslice.Of(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16}), DiscardNew[int, int]())\n// {1:2, 2:3, 3:4, 4:15, 5:16}\ngmap.IntersectBy(gslice.Of(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16}), DiscardNew[int, int]())\n// {3:4}\n```\n\n### gfunc\n\nProcessing function `func`\n\nUsage：\n\n```go\nimport (\n    \"github.com/bytedance/gg/gfunc\"\n)\n```\n\nExample1：Partial Application\n\n```go\nadd := Partial2(gvalue.Add[int]) // convert the Add function into a partial function\nadd1 := add.Partial(1)           // Bind (i.e., \"freeze\") the first argument to 1\nadd1(0)                          // 0 + 1 = 1\n// 1\nadd1(1)                          // Reuse the partially applied function: 1 + 1 = 2\n// 2\nadd1n2 := add1.PartialR(2)       // Bind the remaining (rightmost) argument to 2; all arguments are now fixed\nadd1n2()                         // 1 + 2 = 3\n```\n\n### gconv\n\nData type conversion\n\nUsage：\n\n```go\nimport (\n    \"github.com/bytedance/gg/gconv\"\n)\n```\n\nExample：\n\n```go\ngconv.To[string](1)\n// \"1\"\ngconv.To[int](\"1\")\n// 1\ngconv.To[int](\"x\")\n// 0\ngconv.To[bool](\"true\")\n// true\ngconv.To[bool](\"x\")\n// false\ngconv.To[int](gptr.Of(gptr.Of(gptr.Of(\"1\"))))\n// 1\ntype myInt int\ntype myString string\ngconv.To[myInt](myString(\"1\"))\n// 1\ngconv.To[myString](myInt(1))\n// \"1\"\n\ngconv.ToE[int](\"x\")\n// 0 strconv.ParseInt: parsing \"x\": invalid syntax\n```\n\n### gson\n\nProcessing JSON\n\nUsage：\n\n```go\nimport (\n    \"github.com/bytedance/gg/gson\"\n)\n```\n\nExample：\n\n```go\ntype testStruct struct {\n    Name string `json:\"name\"`\n    Age  int    `json:\"age\"`\n}\ntestcase := testStruct{Name: \"test\", Age: 10}\n\ngson.Marshal(testcase)\n// []byte(`{\"name\":\"test\",\"age\":10}`) nil\ngson.MarshalString(testcase)\n// `{\"name\":\"test\",\"age\":10}` nil\ngson.ToString(testcase)\n// `{\"name\":\"test\",\"age\":10}`\ngson.MarshalIndent(testcase, \"\", \"  \")\n// \"{\\n  \\\"name\\\": \\\"test\\\",\\n  \\\"age\\\": 10\\n}\" nil\ngson.ToStringIndent(testcase, \"\", \"  \")\n// \"{\\n  \\\"name\\\": \\\"test\\\",\\n  \\\"age\\\": 10\\n}\"\ngson.Valid(`{\"name\":\"test\",\"age\":10}`)\n// true\ngson.Unmarshal[testStruct](`{\"name\":\"test\",\"age\":10}`)\n// {test 10} nil\n\n// Use high-performance JSON codecs such as Sonic or json-iterator, instead of the standard library's encoding/json.\nimport \"github.com/bytedance/sonic\"\n\ngson.MarshalBy(sonic.ConfigDefault, testcase)\n// []byte(`{\"name\":\"test\",\"age\":10}`) nil\ngson.MarshalString(sonic.ConfigDefault, testcase)\n// {\"name\":\"test\",\"age\":10}`, nil\ngson.UnmarshalBy[testStruct](sonic.ConfigDefault, `{\"name\":\"test\",\"age\":10}`)\n// testStruct{Name: \"test\", Age: 10}, nil\n\n// Example using Json-Iterator:\nimport jsoniter \"github.com/json-iterator/go\"\n\ngson.MarshalBy(jsoniter.ConfigDefault, testcase)\n// []byte(`{\"name\":\"test\",\"age\":10}`) nil\ngson.MarshalString(jsoniter.ConfigDefault, testcase)   \n// {\"name\":\"test\",\"age\":10}`, nil\ngson.UnmarshalBy[testStruct](jsoniter.ConfigDefault, `{\"name\":\"test\",\"age\":10}`)\n// testStruct{Name: \"test\", Age: 10}, nil\n```\n\n## ✨ Generic Standard Wrapper\n\n### gsync\n\nWrap `sync`\n\nUsage：\n\n```go\nimport (\n    \"github.com/bytedance/gg/gstd/gsync\"\n)\n```\n\nExample1：`gsync.Map` wraps `sync.Map`\n\n```go\nsm := gsync.Map[string, int]{}\nsm.Store(\"k\", 1)\nsm.Load(\"k\")\n// 1 true\nsm.LoadO(\"k\").Value()\n// 1\nsm.Store(\"k\", 2)\nsm.Load(\"k\")\n// 2 true\nsm.LoadAndDelete(\"k\")\n// 2 true\nsm.Load(\"k\")\n// 0 false\nsm.LoadOrStore(\"k\", 3)\n// 3 false\nsm.Load(\"k\")\n// 3 true\nsm.ToMap()\n// {\"k\":3}\n```\n\nExample2：`gsync.Pool` wraps `sync.Pool`\n\n```go\npool := Pool[*int]{\n    New: func() *int {\n        i := 1\n        return \u0026i\n    },\n}\na := pool.Get()\n*a\n// 1\n*a = 2\npool.Put(a)\n*pool.Get()\n// possible result: 1 or 2\n```\n\nExample3：`gsync.OnceXXX` wraps `sync.Once`\n\n\n```go\nonceFunc := gsync.OnceFunc(func() { fmt.Println(\"OnceFunc\") })\nonceFunc()\n// \"OnceFunc\"\nonceFunc()\n// (no output)\nonceFunc()\n// (no output)\n\ni := 1\nonceValue := gsync.OnceValue(func() int { i++; return i })\nonceValue()\n// 2\nonceValue()\n// 2\n\nonceValues := gsync.OnceValues(func() (int, error) { i++; return i, nil })\nonceValues()\n// 3 nil\nonceValues()\n// 3 nil\n```\n\n## ✨ Generic Data Structures\n\n### tuple\n\nImplementation of tuple provides definition of generic n-ary tuples\n\nUsage\n\n```go\nimport (\n    \"github.com/bytedance/gg/collection/tuple\"\n)\n```\n\nExample：\n\n```go\naddr := Make2(\"localhost\", 8080)\nfmt.Printf(\"%s:%d\\n\", addr.First, addr.Second)\n// localhost:8080\n\ns := Zip2([]string{\"red\", \"green\", \"blue\"}, []int{14, 15, 16})\nfor _, v := range s {\n    fmt.Printf(\"%s:%d\\n\", v.First, v.Second)\n}\n// red:14\n// green:15\n// blue:16\n\ns.Unzip()\n// [\"red\", \"green\", \"blue\"] [14, 15, 16]\n```\n\n### set\n\nImplementation of set based on `map[T]struct{}`\n\nUsage\n\n```go\nimport (\n    \"github.com/bytedance/gg/collection/set\"\n)\n```\n\nExample：\n\n```go\ns := New(10, 10, 12, 15)\ns.Len()\n// 3\ns.Add(10)\n// false\ns.Add(11)\n// true\ns.Remove(11) \u0026\u0026 s.Remove(12)\n// true\n\ns.ContainsAny(10, 15)\n// true\ns.ContainsAny(11, 12)\n// false\ns.ContainsAny()\n// false\ns.ContainsAll(10, 15)\n// true\ns.ContainsAll(10, 11)\n// false\ns.ContainsAll()\n// true\n\nlen(s.ToSlice())\n// 2\n```\n\n### skipset\n\nHigh-performance, scalable, concurrent-safe set based on skip-list, up to 15x faster than the built-in `sync.Map` below Go 1.24\n\n⚠️ NOTICE: Go 1.24 or later, please consider using the std `sync.Map`, which has better performance compared to `skipset` in about 90% of use cases.\n\nUsage\n\n```go\nimport (\n    \"github.com/bytedance/gg/collection/skipset\"\n)\n```\n\nExample：\n\n```go\ns := skipset.New[int]()\ns.Add(10)\n// true\ns.Add(10)\n// false\ns.Add(11)\n// true\ns.Add(12)\n// true\ns.Len()\n// 3\n\ns.Contains(10)\n// true\ns.Remove(10)\n// true\ns.Contains(10)\n// false\n\ns.ToSlice()\n// [11, 12]\n\nvar wg sync.WaitGroup\nwg.Add(1000)\nfor i := 0; i \u003c 1000; i++ {\n    i := i\n    go func() {\n        defer wg.Done()\n        s.Add(i)\n    }()\n}\nwg.Wait()\ns.Len()\n// 1000\n```\n\n### skipmap\n\nHigh-performance, scalable, concurrent-safe map based on skip-list, up to 10x faster than the built-in `sync.Map` below Go 1.24\n\n⚠️ Go 1.24 or later, please consider using the std `sync.Map`, which has better performance compared to `skipmap` in about 90% of use cases.\n\nUsage\n\n```go\nimport (\n    \"github.com/bytedance/gg/collection/skipmap\"\n)\n```\n\nExample：\n\n```go\ns := New[string, int]()\ns.Store(\"a\", 0)\ns.Store(\"a\", 1)\ns.Store(\"b\", 2)\ns.Store(\"c\", 3)\ns.Len()\n// 3\n\ns.Load(\"a\")\n// 1 true\ns.LoadAndDelete(\"a\")\n// 1 true\ns.LoadOrStore(\"a\", 11)\n// 11 false\n\ngson.ToString(s.ToMap())\n// {\"a\":11, \"b\":2, \"c\": 3}\n\ns.Delete(\"a\")\ns.Delete(\"b\")\ns.Delete(\"c\")\nvar wg sync.WaitGroup\nwg.Add(1000)\nfor i := 0; i \u003c 1000; i++ {\n    i := i\n    go func() {\n        defer wg.Done()\n        s.Store(strconv.Itoa(i), i)\n    }()\n}\nwg.Wait()\ns.Len()\n// 1000\n```\n\n## License\n\n`gg` is licensed under the Apache-2.0 license. See [LICENSE](LICENSE) for details.\n\n2025 © Bytedance\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytedance%2Fgg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbytedance%2Fgg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytedance%2Fgg/lists"}