Skip to content

Commit 3c9b633

Browse files
authored
chore: refactor set in collection package (#5016)
1 parent bf6ef5f commit 3c9b633

File tree

5 files changed

+74
-441
lines changed

5 files changed

+74
-441
lines changed

core/collection/set.go

Lines changed: 21 additions & 317 deletions
Original file line numberDiff line numberDiff line change
@@ -1,349 +1,53 @@
11
package collection
22

3-
import (
4-
"github.com/zeromicro/go-zero/core/lang"
5-
"github.com/zeromicro/go-zero/core/logx"
6-
)
3+
import "github.com/zeromicro/go-zero/core/lang"
74

8-
const (
9-
unmanaged = iota
10-
untyped
11-
intType
12-
int64Type
13-
uintType
14-
uint64Type
15-
stringType
16-
)
17-
18-
// TypedSet is a type-safe generic set collection. It's not thread-safe,
19-
// use with synchronization for concurrent access.
20-
//
21-
// Advantages over the legacy Set:
22-
// - Compile-time type safety (no runtime type validation needed)
23-
// - Better performance (no type assertions or reflection overhead)
24-
// - Cleaner API (single Add method instead of multiple type-specific methods)
25-
// - No need for type-specific Keys methods (KeysInt, KeysStr, etc.)
26-
// - Zero-allocation for empty checks and direct type access
27-
type TypedSet[T comparable] struct {
5+
// Set is a type-safe generic set collection.
6+
// It's not thread-safe, use with synchronization for concurrent access.
7+
type Set[T comparable] struct {
288
data map[T]lang.PlaceholderType
299
}
3010

31-
// NewTypedSet returns a new type-safe set.
32-
func NewTypedSet[T comparable]() *TypedSet[T] {
33-
return &TypedSet[T]{
11+
// NewSet returns a new type-safe set.
12+
func NewSet[T comparable]() *Set[T] {
13+
return &Set[T]{
3414
data: make(map[T]lang.PlaceholderType),
3515
}
3616
}
3717

38-
// NewIntSet returns a new int-typed set.
39-
func NewIntSet() *TypedSet[int] {
40-
return NewTypedSet[int]()
41-
}
42-
43-
// NewInt64Set returns a new int64-typed set.
44-
func NewInt64Set() *TypedSet[int64] {
45-
return NewTypedSet[int64]()
46-
}
47-
48-
// NewUintSet returns a new uint-typed set.
49-
func NewUintSet() *TypedSet[uint] {
50-
return NewTypedSet[uint]()
51-
}
52-
53-
// NewUint64Set returns a new uint64-typed set.
54-
func NewUint64Set() *TypedSet[uint64] {
55-
return NewTypedSet[uint64]()
56-
}
57-
58-
// NewStringSet returns a new string-typed set.
59-
func NewStringSet() *TypedSet[string] {
60-
return NewTypedSet[string]()
61-
}
62-
6318
// Add adds items to the set. Duplicates are automatically ignored.
64-
func (s *TypedSet[T]) Add(items ...T) {
19+
func (s *Set[T]) Add(items ...T) {
6520
for _, item := range items {
6621
s.data[item] = lang.Placeholder
6722
}
6823
}
6924

25+
// Clear removes all items from the set.
26+
func (s *Set[T]) Clear() {
27+
clear(s.data)
28+
}
29+
7030
// Contains checks if an item exists in the set.
71-
func (s *TypedSet[T]) Contains(item T) bool {
31+
func (s *Set[T]) Contains(item T) bool {
7232
_, ok := s.data[item]
7333
return ok
7434
}
7535

76-
// Remove removes an item from the set.
77-
func (s *TypedSet[T]) Remove(item T) {
78-
delete(s.data, item)
79-
}
80-
81-
// Keys returns all elements in the set as a slice.
82-
func (s *TypedSet[T]) Keys() []T {
83-
keys := make([]T, 0, len(s.data))
84-
for key := range s.data {
85-
keys = append(keys, key)
86-
}
87-
return keys
88-
}
89-
9036
// Count returns the number of items in the set.
91-
func (s *TypedSet[T]) Count() int {
37+
func (s *Set[T]) Count() int {
9238
return len(s.data)
9339
}
9440

95-
// Clear removes all items from the set.
96-
func (s *TypedSet[T]) Clear() {
97-
s.data = make(map[T]lang.PlaceholderType)
98-
}
99-
100-
// Set is not thread-safe, for concurrent use, make sure to use it with synchronization.
101-
// Deprecated: Use TypedSet[T] instead for better type safety and performance.
102-
// TypedSet provides compile-time type checking and eliminates the need for type-specific methods.
103-
type Set struct {
104-
data map[any]lang.PlaceholderType
105-
tp int
106-
}
107-
108-
// NewSet returns a managed Set, can only put the values with the same type.
109-
// Deprecated: Use NewTypedSet[T]() instead for better type safety and performance.
110-
// Example: NewIntSet() instead of NewSet() with AddInt()
111-
func NewSet() *Set {
112-
return &Set{
113-
data: make(map[any]lang.PlaceholderType),
114-
tp: untyped,
115-
}
116-
}
117-
118-
// NewUnmanagedSet returns an unmanaged Set, which can put values with different types.
119-
// Deprecated: Use TypedSet[any] or multiple TypedSet instances for different types instead.
120-
// If you really need mixed types, consider using map[any]struct{} directly.
121-
func NewUnmanagedSet() *Set {
122-
return &Set{
123-
data: make(map[any]lang.PlaceholderType),
124-
tp: unmanaged,
125-
}
126-
}
127-
128-
// Add adds i into s.
129-
// Deprecated: Use TypedSet[T].Add() instead for better type safety and performance.
130-
func (s *Set) Add(i ...any) {
131-
for _, each := range i {
132-
s.add(each)
133-
}
134-
}
135-
136-
// AddInt adds int values ii into s.
137-
// Deprecated: Use NewIntSet().Add() instead for better type safety and performance.
138-
// Example: intSet := NewIntSet(); intSet.Add(1, 2, 3)
139-
func (s *Set) AddInt(ii ...int) {
140-
for _, each := range ii {
141-
s.add(each)
142-
}
143-
}
144-
145-
// AddInt64 adds int64 values ii into s.
146-
// Deprecated: Use NewInt64Set().Add() instead for better type safety and performance.
147-
// Example: int64Set := NewInt64Set(); int64Set.Add(1, 2, 3)
148-
func (s *Set) AddInt64(ii ...int64) {
149-
for _, each := range ii {
150-
s.add(each)
151-
}
152-
}
153-
154-
// AddUint adds uint values ii into s.
155-
// Deprecated: Use NewUintSet().Add() instead for better type safety and performance.
156-
// Example: uintSet := NewUintSet(); uintSet.Add(1, 2, 3)
157-
func (s *Set) AddUint(ii ...uint) {
158-
for _, each := range ii {
159-
s.add(each)
160-
}
161-
}
162-
163-
// AddUint64 adds uint64 values ii into s.
164-
// Deprecated: Use NewUint64Set().Add() instead for better type safety and performance.
165-
// Example: uint64Set := NewUint64Set(); uint64Set.Add(1, 2, 3)
166-
func (s *Set) AddUint64(ii ...uint64) {
167-
for _, each := range ii {
168-
s.add(each)
169-
}
170-
}
171-
172-
// AddStr adds string values ss into s.
173-
// Deprecated: Use NewStringSet().Add() instead for better type safety and performance.
174-
// Example: stringSet := NewStringSet(); stringSet.Add("a", "b", "c")
175-
func (s *Set) AddStr(ss ...string) {
176-
for _, each := range ss {
177-
s.add(each)
178-
}
179-
}
180-
181-
// Contains checks if i is in s.
182-
// Deprecated: Use TypedSet[T].Contains() instead for better type safety and performance.
183-
func (s *Set) Contains(i any) bool {
184-
if len(s.data) == 0 {
185-
return false
186-
}
187-
188-
s.validate(i)
189-
_, ok := s.data[i]
190-
return ok
191-
}
192-
193-
// Keys returns the keys in s.
194-
// Deprecated: Use TypedSet[T].Keys() instead for better type safety and performance.
195-
func (s *Set) Keys() []any {
196-
var keys []any
197-
41+
// Keys returns all elements in the set as a slice.
42+
func (s *Set[T]) Keys() []T {
43+
keys := make([]T, 0, len(s.data))
19844
for key := range s.data {
19945
keys = append(keys, key)
20046
}
201-
20247
return keys
20348
}
20449

205-
// KeysInt returns the int keys in s.
206-
// Deprecated: Use NewIntSet().Keys() instead for better type safety and performance.
207-
// The TypedSet version returns []int directly without type casting.
208-
func (s *Set) KeysInt() []int {
209-
var keys []int
210-
211-
for key := range s.data {
212-
if intKey, ok := key.(int); ok {
213-
keys = append(keys, intKey)
214-
}
215-
}
216-
217-
return keys
218-
}
219-
220-
// KeysInt64 returns int64 keys in s.
221-
// Deprecated: Use NewInt64Set().Keys() instead for better type safety and performance.
222-
// The TypedSet version returns []int64 directly without type casting.
223-
func (s *Set) KeysInt64() []int64 {
224-
var keys []int64
225-
226-
for key := range s.data {
227-
if intKey, ok := key.(int64); ok {
228-
keys = append(keys, intKey)
229-
}
230-
}
231-
232-
return keys
233-
}
234-
235-
// KeysUint returns uint keys in s.
236-
// Deprecated: Use NewUintSet().Keys() instead for better type safety and performance.
237-
// The TypedSet version returns []uint directly without type casting.
238-
func (s *Set) KeysUint() []uint {
239-
var keys []uint
240-
241-
for key := range s.data {
242-
if intKey, ok := key.(uint); ok {
243-
keys = append(keys, intKey)
244-
}
245-
}
246-
247-
return keys
248-
}
249-
250-
// KeysUint64 returns uint64 keys in s.
251-
//
252-
// Deprecated: Use NewUint64Set().Keys() instead for better type safety and performance.
253-
// The TypedSet version returns []uint64 directly without type casting.
254-
func (s *Set) KeysUint64() []uint64 {
255-
var keys []uint64
256-
257-
for key := range s.data {
258-
if intKey, ok := key.(uint64); ok {
259-
keys = append(keys, intKey)
260-
}
261-
}
262-
263-
return keys
264-
}
265-
266-
// KeysStr returns string keys in s.
267-
// Deprecated: Use NewStringSet().Keys() instead for better type safety and performance.
268-
// The TypedSet version returns []string directly without type casting.
269-
func (s *Set) KeysStr() []string {
270-
var keys []string
271-
272-
for key := range s.data {
273-
if strKey, ok := key.(string); ok {
274-
keys = append(keys, strKey)
275-
}
276-
}
277-
278-
return keys
279-
}
280-
281-
// Remove removes i from s.
282-
// Deprecated: Use TypedSet[T].Remove() instead for better type safety and performance.
283-
func (s *Set) Remove(i any) {
284-
s.validate(i)
285-
delete(s.data, i)
286-
}
287-
288-
// Count returns the number of items in s.
289-
// Deprecated: Use TypedSet[T].Count() instead for better type safety and performance.
290-
func (s *Set) Count() int {
291-
return len(s.data)
292-
}
293-
294-
func (s *Set) add(i any) {
295-
switch s.tp {
296-
case unmanaged:
297-
// do nothing
298-
case untyped:
299-
s.setType(i)
300-
default:
301-
s.validate(i)
302-
}
303-
s.data[i] = lang.Placeholder
304-
}
305-
306-
func (s *Set) setType(i any) {
307-
// s.tp can only be untyped here
308-
switch i.(type) {
309-
case int:
310-
s.tp = intType
311-
case int64:
312-
s.tp = int64Type
313-
case uint:
314-
s.tp = uintType
315-
case uint64:
316-
s.tp = uint64Type
317-
case string:
318-
s.tp = stringType
319-
}
320-
}
321-
322-
func (s *Set) validate(i any) {
323-
if s.tp == unmanaged {
324-
return
325-
}
326-
327-
switch i.(type) {
328-
case int:
329-
if s.tp != intType {
330-
logx.Errorf("element is int, but set contains elements with type %d", s.tp)
331-
}
332-
case int64:
333-
if s.tp != int64Type {
334-
logx.Errorf("element is int64, but set contains elements with type %d", s.tp)
335-
}
336-
case uint:
337-
if s.tp != uintType {
338-
logx.Errorf("element is uint, but set contains elements with type %d", s.tp)
339-
}
340-
case uint64:
341-
if s.tp != uint64Type {
342-
logx.Errorf("element is uint64, but set contains elements with type %d", s.tp)
343-
}
344-
case string:
345-
if s.tp != stringType {
346-
logx.Errorf("element is string, but set contains elements with type %d", s.tp)
347-
}
348-
}
50+
// Remove removes an item from the set.
51+
func (s *Set[T]) Remove(item T) {
52+
delete(s.data, item)
34953
}

0 commit comments

Comments
 (0)