Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcb6a472

Browse files
authored
chore: implement generalized symmetric difference for set comparison (#14407)
* chore: implement generalized symmetric difference for set comparisonGoing to be used in Organization Sync + maybe group sync. Feltbetter to reuse, rather than copy
1 parent4bd7fe8 commitcb6a472

File tree

4 files changed

+156
-23
lines changed

4 files changed

+156
-23
lines changed

‎coderd/rbac/roles.go

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -764,29 +764,9 @@ func SiteRoles() []Role {
764764
// RBAC checks can be applied using "ActionCreate" and "ActionDelete" for
765765
// "added" and "removed" roles respectively.
766766
funcChangeRoleSet(from []RoleIdentifier,to []RoleIdentifier) (added []RoleIdentifier,removed []RoleIdentifier) {
767-
has:=make(map[RoleIdentifier]struct{})
768-
for_,exists:=rangefrom {
769-
has[exists]=struct{}{}
770-
}
771-
772-
for_,roleName:=rangeto {
773-
// If the user already has the role assigned, we don't need to check the permission
774-
// to reassign it. Only run permission checks on the difference in the set of
775-
// roles.
776-
if_,ok:=has[roleName];ok {
777-
delete(has,roleName)
778-
continue
779-
}
780-
781-
added=append(added,roleName)
782-
}
783-
784-
// Remaining roles are the ones removed/deleted.
785-
forroleName:=rangehas {
786-
removed=append(removed,roleName)
787-
}
788-
789-
returnadded,removed
767+
returnslice.SymmetricDifferenceFunc(from,to,func(a,bRoleIdentifier)bool {
768+
returna.Name==b.Name&&a.OrganizationID==b.OrganizationID
769+
})
790770
}
791771

792772
// Permissions is just a helper function to make building roles that list out resources

‎coderd/util/slice/example_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package slice_test
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/coder/coder/v2/coderd/util/slice"
7+
)
8+
9+
//nolint:revive // They want me to error check my Printlns
10+
funcExampleSymmetricDifference() {
11+
// The goal of this function is to find the elements to add & remove from
12+
// set 'a' to make it equal to set 'b'.
13+
a:= []int{1,2,5,6}
14+
b:= []int{2,3,4,5}
15+
add,remove:=slice.SymmetricDifference(a,b)
16+
fmt.Println("Elements to add:",add)
17+
fmt.Println("Elements to remove:",remove)
18+
// Output:
19+
// Elements to add: [3 4]
20+
// Elements to remove: [1 6]
21+
}

‎coderd/util/slice/slice.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,35 @@ func Ascending[T constraints.Ordered](a, b T) int {
107107
funcDescending[T constraints.Ordered](a,bT)int {
108108
return-Ascending[T](a,b)
109109
}
110+
111+
// SymmetricDifference returns the elements that need to be added and removed
112+
// to get from set 'a' to set 'b'.
113+
// In classical set theory notation, SymmetricDifference returns
114+
// all elements of {add} and {remove} together. It is more useful to
115+
// return them as their own slices.
116+
// Notation: A Δ B = (A\B) ∪ (B\A)
117+
// Example:
118+
//
119+
//a := []int{1, 3, 4}
120+
//b := []int{1, 2}
121+
//add, remove := SymmetricDifference(a, b)
122+
//fmt.Println(add) // [2]
123+
//fmt.Println(remove) // [3, 4]
124+
funcSymmetricDifference[Tcomparable](a,b []T) (add []T,remove []T) {
125+
f:=func(a,bT)bool {returna==b }
126+
returnSymmetricDifferenceFunc(a,b,f)
127+
}
128+
129+
funcSymmetricDifferenceFunc[Tany](a,b []T,equalfunc(a,bT)bool) (add []T,remove []T) {
130+
returnDifferenceFunc(b,a,equal),DifferenceFunc(a,b,equal)
131+
}
132+
133+
funcDifferenceFunc[Tany](a []T,b []T,equalfunc(a,bT)bool) []T {
134+
tmp:=make([]T,0,len(a))
135+
for_,v:=rangea {
136+
if!ContainsCompare(b,v,equal) {
137+
tmp=append(tmp,v)
138+
}
139+
}
140+
returntmp
141+
}

‎coderd/util/slice/slice_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,103 @@ func TestOmit(t *testing.T) {
131131
slice.Omit([]string{"a","b","c","d","e","f"},"c","d","e"),
132132
)
133133
}
134+
135+
funcTestSymmetricDifference(t*testing.T) {
136+
t.Parallel()
137+
138+
t.Run("Simple",func(t*testing.T) {
139+
t.Parallel()
140+
141+
add,remove:=slice.SymmetricDifference([]int{1,3,4}, []int{1,2})
142+
require.ElementsMatch(t, []int{2},add)
143+
require.ElementsMatch(t, []int{3,4},remove)
144+
})
145+
146+
t.Run("Large",func(t*testing.T) {
147+
t.Parallel()
148+
149+
add,remove:=slice.SymmetricDifference(
150+
[]int{1,2,3,4,5,10,11,12,13,14,15},
151+
[]int{1,3,7,9,11,13,17},
152+
)
153+
require.ElementsMatch(t, []int{7,9,17},add)
154+
require.ElementsMatch(t, []int{2,4,5,10,12,14,15},remove)
155+
})
156+
157+
t.Run("AddOnly",func(t*testing.T) {
158+
t.Parallel()
159+
160+
add,remove:=slice.SymmetricDifference(
161+
[]int{1,2},
162+
[]int{1,2,3,4,5,6,7,8,9},
163+
)
164+
require.ElementsMatch(t, []int{3,4,5,6,7,8,9},add)
165+
require.ElementsMatch(t, []int{},remove)
166+
})
167+
168+
t.Run("RemoveOnly",func(t*testing.T) {
169+
t.Parallel()
170+
171+
add,remove:=slice.SymmetricDifference(
172+
[]int{1,2,3,4,5,6,7,8,9},
173+
[]int{1,2},
174+
)
175+
require.ElementsMatch(t, []int{},add)
176+
require.ElementsMatch(t, []int{3,4,5,6,7,8,9},remove)
177+
})
178+
179+
t.Run("Equal",func(t*testing.T) {
180+
t.Parallel()
181+
182+
add,remove:=slice.SymmetricDifference(
183+
[]int{1,2,3,4,5,6,7,8,9},
184+
[]int{1,2,3,4,5,6,7,8,9},
185+
)
186+
require.ElementsMatch(t, []int{},add)
187+
require.ElementsMatch(t, []int{},remove)
188+
})
189+
190+
t.Run("ToEmpty",func(t*testing.T) {
191+
t.Parallel()
192+
193+
add,remove:=slice.SymmetricDifference(
194+
[]int{1,2,3},
195+
[]int{},
196+
)
197+
require.ElementsMatch(t, []int{},add)
198+
require.ElementsMatch(t, []int{1,2,3},remove)
199+
})
200+
201+
t.Run("ToNil",func(t*testing.T) {
202+
t.Parallel()
203+
204+
add,remove:=slice.SymmetricDifference(
205+
[]int{1,2,3},
206+
nil,
207+
)
208+
require.ElementsMatch(t, []int{},add)
209+
require.ElementsMatch(t, []int{1,2,3},remove)
210+
})
211+
212+
t.Run("FromEmpty",func(t*testing.T) {
213+
t.Parallel()
214+
215+
add,remove:=slice.SymmetricDifference(
216+
[]int{},
217+
[]int{1,2,3},
218+
)
219+
require.ElementsMatch(t, []int{1,2,3},add)
220+
require.ElementsMatch(t, []int{},remove)
221+
})
222+
223+
t.Run("FromNil",func(t*testing.T) {
224+
t.Parallel()
225+
226+
add,remove:=slice.SymmetricDifference(
227+
nil,
228+
[]int{1,2,3},
229+
)
230+
require.ElementsMatch(t, []int{1,2,3},add)
231+
require.ElementsMatch(t, []int{},remove)
232+
})
233+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp