From 5315153059529f03b06c8f25487ffcc21ae3163f Mon Sep 17 00:00:00 2001
From: KN4CK3R <admin@oldschoolhack.me>
Date: Wed, 30 Aug 2023 08:55:25 +0200
Subject: [PATCH] Use `Set[Type]` instead of `map[Type]bool/struct{}`. (#26804)

---
 build/backport-locales.go                |  7 ++++---
 build/generate-go-licenses.go            | 14 +++++---------
 models/unit/unit.go                      |  6 +++---
 modules/assetfs/layered.go               | 19 +++++++------------
 modules/templates/util_dict.go           | 10 +++++-----
 routers/api/actions/runner/utils.go      |  8 +++-----
 routers/web/user/home.go                 |  7 ++-----
 services/auth/source/ldap/source_sync.go |  7 ++++---
 services/migrations/gitlab.go            |  6 +++---
 9 files changed, 36 insertions(+), 48 deletions(-)

diff --git a/build/backport-locales.go b/build/backport-locales.go
index 0346215348..d112dd72bd 100644
--- a/build/backport-locales.go
+++ b/build/backport-locales.go
@@ -12,6 +12,7 @@ import (
 	"path/filepath"
 	"strings"
 
+	"code.gitea.io/gitea/modules/container"
 	"code.gitea.io/gitea/modules/setting"
 )
 
@@ -58,7 +59,7 @@ func main() {
 
 	// use old en-US as the base, and copy the new translations to the old locales
 	enUsOld := inisOld["options/locale/locale_en-US.ini"]
-	brokenWarned := map[string]bool{}
+	brokenWarned := make(container.Set[string])
 	for path, iniOld := range inisOld {
 		if iniOld == enUsOld {
 			continue
@@ -77,7 +78,7 @@ func main() {
 					broken := oldStr != "" && strings.Count(oldStr, "%") != strings.Count(newStr, "%")
 					broken = broken || strings.Contains(oldStr, "\n") || strings.Contains(oldStr, "\n")
 					if broken {
-						brokenWarned[secOld.Name()+"."+keyEnUs.Name()] = true
+						brokenWarned.Add(secOld.Name() + "." + keyEnUs.Name())
 						fmt.Println("----")
 						fmt.Printf("WARNING: skip broken locale: %s , [%s] %s\n", path, secEnUS.Name(), keyEnUs.Name())
 						fmt.Printf("\told: %s\n", strings.ReplaceAll(oldStr, "\n", "\\n"))
@@ -103,7 +104,7 @@ func main() {
 				broken = broken || strings.HasPrefix(str, "`\"")
 				broken = broken || strings.Count(str, `"`)%2 == 1
 				broken = broken || strings.Count(str, "`")%2 == 1
-				if broken && !brokenWarned[sec.Name()+"."+key.Name()] {
+				if broken && !brokenWarned.Contains(sec.Name()+"."+key.Name()) {
 					fmt.Printf("WARNING: found broken locale: %s , [%s] %s\n", path, sec.Name(), key.Name())
 					fmt.Printf("\tstr: %s\n", strings.ReplaceAll(str, "\n", "\\n"))
 					fmt.Println("----")
diff --git a/build/generate-go-licenses.go b/build/generate-go-licenses.go
index c3b40c226f..84ba39025c 100644
--- a/build/generate-go-licenses.go
+++ b/build/generate-go-licenses.go
@@ -15,6 +15,8 @@ import (
 	"regexp"
 	"sort"
 	"strings"
+
+	"code.gitea.io/gitea/modules/container"
 )
 
 // regexp is based on go-license, excluding README and NOTICE
@@ -55,20 +57,14 @@ func main() {
 	//    yml
 	//
 	// It could be removed once we have a better regex.
-	excludedExt := map[string]bool{
-		".gitignore": true,
-		".go":        true,
-		".mod":       true,
-		".sum":       true,
-		".toml":      true,
-		".yml":       true,
-	}
+	excludedExt := container.SetOf(".gitignore", ".go", ".mod", ".sum", ".toml", ".yml")
+
 	var paths []string
 	err := filepath.WalkDir(base, func(path string, entry fs.DirEntry, err error) error {
 		if err != nil {
 			return err
 		}
-		if entry.IsDir() || !licenseRe.MatchString(entry.Name()) || excludedExt[filepath.Ext(entry.Name())] {
+		if entry.IsDir() || !licenseRe.MatchString(entry.Name()) || excludedExt.Contains(filepath.Ext(entry.Name())) {
 			return nil
 		}
 		paths = append(paths, path)
diff --git a/models/unit/unit.go b/models/unit/unit.go
index 5f5e20de1e..ca3e7f999d 100644
--- a/models/unit/unit.go
+++ b/models/unit/unit.go
@@ -9,6 +9,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models/perm"
+	"code.gitea.io/gitea/modules/container"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 )
@@ -318,14 +319,13 @@ var (
 
 // FindUnitTypes give the unit key names and return valid unique units and invalid keys
 func FindUnitTypes(nameKeys ...string) (res []Type, invalidKeys []string) {
-	m := map[Type]struct{}{}
+	m := make(container.Set[Type])
 	for _, key := range nameKeys {
 		t := TypeFromKey(key)
 		if t == TypeInvalid {
 			invalidKeys = append(invalidKeys, key)
-		} else if _, ok := m[t]; !ok {
+		} else if m.Add(t) {
 			res = append(res, t)
-			m[t] = struct{}{}
 		}
 	}
 	return res, invalidKeys
diff --git a/modules/assetfs/layered.go b/modules/assetfs/layered.go
index d69732f81b..9678d23ad6 100644
--- a/modules/assetfs/layered.go
+++ b/modules/assetfs/layered.go
@@ -14,6 +14,7 @@ import (
 	"sort"
 	"time"
 
+	"code.gitea.io/gitea/modules/container"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/process"
 	"code.gitea.io/gitea/modules/util"
@@ -130,7 +131,7 @@ func readDir(layer *Layer, name string) ([]fs.FileInfo, error) {
 // * false: only directories will be returned.
 // The returned files are sorted by name.
 func (l *LayeredFS) ListFiles(name string, fileMode ...bool) ([]string, error) {
-	fileMap := map[string]bool{}
+	fileSet := make(container.Set[string])
 	for _, layer := range l.layers {
 		infos, err := readDir(layer, name)
 		if err != nil {
@@ -138,14 +139,11 @@ func (l *LayeredFS) ListFiles(name string, fileMode ...bool) ([]string, error) {
 		}
 		for _, info := range infos {
 			if shouldInclude(info, fileMode...) {
-				fileMap[info.Name()] = true
+				fileSet.Add(info.Name())
 			}
 		}
 	}
-	files := make([]string, 0, len(fileMap))
-	for file := range fileMap {
-		files = append(files, file)
-	}
+	files := fileSet.Values()
 	sort.Strings(files)
 	return files, nil
 }
@@ -161,7 +159,7 @@ func (l *LayeredFS) ListAllFiles(name string, fileMode ...bool) ([]string, error
 }
 
 func listAllFiles(layers []*Layer, name string, fileMode ...bool) ([]string, error) {
-	fileMap := map[string]bool{}
+	fileSet := make(container.Set[string])
 	var list func(dir string) error
 	list = func(dir string) error {
 		for _, layer := range layers {
@@ -172,7 +170,7 @@ func listAllFiles(layers []*Layer, name string, fileMode ...bool) ([]string, err
 			for _, info := range infos {
 				path := util.PathJoinRelX(dir, info.Name())
 				if shouldInclude(info, fileMode...) {
-					fileMap[path] = true
+					fileSet.Add(path)
 				}
 				if info.IsDir() {
 					if err = list(path); err != nil {
@@ -186,10 +184,7 @@ func listAllFiles(layers []*Layer, name string, fileMode ...bool) ([]string, err
 	if err := list(name); err != nil {
 		return nil, err
 	}
-	var files []string
-	for file := range fileMap {
-		files = append(files, file)
-	}
+	files := fileSet.Values()
 	sort.Strings(files)
 	return files, nil
 }
diff --git a/modules/templates/util_dict.go b/modules/templates/util_dict.go
index 79c307b68d..8d6376b522 100644
--- a/modules/templates/util_dict.go
+++ b/modules/templates/util_dict.go
@@ -9,6 +9,7 @@ import (
 	"html/template"
 	"reflect"
 
+	"code.gitea.io/gitea/modules/container"
 	"code.gitea.io/gitea/modules/json"
 	"code.gitea.io/gitea/modules/setting"
 )
@@ -51,7 +52,7 @@ func dict(args ...any) (map[string]any, error) {
 	return m, nil
 }
 
-func dumpVarMarshalable(v any, dumped map[uintptr]bool) (ret any, ok bool) {
+func dumpVarMarshalable(v any, dumped container.Set[uintptr]) (ret any, ok bool) {
 	if v == nil {
 		return nil, true
 	}
@@ -61,11 +62,10 @@ func dumpVarMarshalable(v any, dumped map[uintptr]bool) (ret any, ok bool) {
 	}
 	if e.CanAddr() {
 		addr := e.UnsafeAddr()
-		if dumped[addr] {
+		if !dumped.Add(addr) {
 			return "[dumped]", false
 		}
-		dumped[addr] = true
-		defer delete(dumped, addr)
+		defer dumped.Remove(addr)
 	}
 	switch e.Kind() {
 	case reflect.Bool, reflect.String,
@@ -107,7 +107,7 @@ func dumpVar(v any) template.HTML {
 	if setting.IsProd {
 		return "<pre>dumpVar: only available in dev mode</pre>"
 	}
-	m, ok := dumpVarMarshalable(v, map[uintptr]bool{})
+	m, ok := dumpVarMarshalable(v, make(container.Set[uintptr]))
 	var dumpStr string
 	jsonBytes, err := json.MarshalIndent(m, "", "  ")
 	if err != nil {
diff --git a/routers/api/actions/runner/utils.go b/routers/api/actions/runner/utils.go
index b8c7ca842a..24432ab6b2 100644
--- a/routers/api/actions/runner/utils.go
+++ b/routers/api/actions/runner/utils.go
@@ -10,6 +10,7 @@ import (
 	actions_model "code.gitea.io/gitea/models/actions"
 	secret_model "code.gitea.io/gitea/models/secret"
 	actions_module "code.gitea.io/gitea/modules/actions"
+	"code.gitea.io/gitea/modules/container"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/json"
 	"code.gitea.io/gitea/modules/log"
@@ -197,10 +198,7 @@ func findTaskNeeds(ctx context.Context, task *actions_model.ActionTask) (map[str
 	if len(task.Job.Needs) == 0 {
 		return nil, nil
 	}
-	needs := map[string]struct{}{}
-	for _, v := range task.Job.Needs {
-		needs[v] = struct{}{}
-	}
+	needs := container.SetOf(task.Job.Needs...)
 
 	jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: task.Job.RunID})
 	if err != nil {
@@ -209,7 +207,7 @@ func findTaskNeeds(ctx context.Context, task *actions_model.ActionTask) (map[str
 
 	ret := make(map[string]*runnerv1.TaskNeed, len(needs))
 	for _, job := range jobs {
-		if _, ok := needs[job.JobID]; !ok {
+		if !needs.Contains(job.JobID) {
 			continue
 		}
 		if job.TaskID == 0 || !job.Status.IsDone() {
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index c44e5a50af..a7f6a52f1b 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -567,12 +567,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
 
 	// Remove repositories that should not be shown,
 	// which are repositories that have no issues and are not selected by the user.
-	selectedReposMap := make(map[int64]struct{}, len(selectedRepoIDs))
-	for _, repoID := range selectedRepoIDs {
-		selectedReposMap[repoID] = struct{}{}
-	}
+	selectedRepos := container.SetOf(selectedRepoIDs...)
 	for k, v := range issueCountByRepo {
-		if _, ok := selectedReposMap[k]; !ok && v == 0 {
+		if v == 0 && !selectedRepos.Contains(k) {
 			delete(issueCountByRepo, k)
 		}
 	}
diff --git a/services/auth/source/ldap/source_sync.go b/services/auth/source/ldap/source_sync.go
index 43ee32c84b..df5eb60393 100644
--- a/services/auth/source/ldap/source_sync.go
+++ b/services/auth/source/ldap/source_sync.go
@@ -13,6 +13,7 @@ import (
 	"code.gitea.io/gitea/models/organization"
 	user_model "code.gitea.io/gitea/models/user"
 	auth_module "code.gitea.io/gitea/modules/auth"
+	"code.gitea.io/gitea/modules/container"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/util"
 	source_service "code.gitea.io/gitea/services/auth/source"
@@ -41,7 +42,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
 
 	usernameUsers := make(map[string]*user_model.User, len(users))
 	mailUsers := make(map[string]*user_model.User, len(users))
-	keepActiveUsers := make(map[int64]struct{})
+	keepActiveUsers := make(container.Set[int64])
 
 	for _, u := range users {
 		usernameUsers[u.LowerName] = u
@@ -97,7 +98,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
 		}
 
 		if usr != nil {
-			keepActiveUsers[usr.ID] = struct{}{}
+			keepActiveUsers.Add(usr.ID)
 		} else if len(su.Username) == 0 {
 			// we cannot create the user if su.Username is empty
 			continue
@@ -208,7 +209,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
 	// Deactivate users not present in LDAP
 	if updateExisting {
 		for _, usr := range users {
-			if _, ok := keepActiveUsers[usr.ID]; ok {
+			if keepActiveUsers.Contains(usr.ID) {
 				continue
 			}
 
diff --git a/services/migrations/gitlab.go b/services/migrations/gitlab.go
index 76180a5159..f626036254 100644
--- a/services/migrations/gitlab.go
+++ b/services/migrations/gitlab.go
@@ -14,6 +14,7 @@ import (
 	"strings"
 	"time"
 
+	"code.gitea.io/gitea/modules/container"
 	"code.gitea.io/gitea/modules/log"
 	base "code.gitea.io/gitea/modules/migration"
 	"code.gitea.io/gitea/modules/structs"
@@ -673,16 +674,15 @@ func (g *GitlabDownloader) GetReviews(reviewable base.Reviewable) ([]*base.Revie
 
 func (g *GitlabDownloader) awardsToReactions(awards []*gitlab.AwardEmoji) []*base.Reaction {
 	result := make([]*base.Reaction, 0, len(awards))
-	uniqCheck := make(map[string]struct{})
+	uniqCheck := make(container.Set[string])
 	for _, award := range awards {
 		uid := fmt.Sprintf("%s%d", award.Name, award.User.ID)
-		if _, ok := uniqCheck[uid]; !ok {
+		if uniqCheck.Add(uid) {
 			result = append(result, &base.Reaction{
 				UserID:   int64(award.User.ID),
 				UserName: award.User.Username,
 				Content:  award.Name,
 			})
-			uniqCheck[uid] = struct{}{}
 		}
 	}
 	return result