helpers: Make UniqueStringsReuse allocation free
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 16 Nov 2021 18:20:33 +0000 (19:20 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 17 Nov 2021 09:44:03 +0000 (10:44 +0100)
This should be faster for all of our use cases (small string slices), but more important, it makes UniqueStringsReuse allocation free.

```bash
name                                 old time/op    new time/op    delta
UniqueStrings/Safe-16                   776ns ± 0%     305ns ± 0%   -60.68%  (p=0.029 n=4+4)
UniqueStrings/Reuse_slice-16            621ns ± 3%     174ns ± 0%   -72.01%  (p=0.029 n=4+4)
UniqueStrings/Reuse_slice_sorted-16     319ns ± 4%     313ns ± 0%    -2.01%  (p=0.029 n=4+4)

name                                 old alloc/op   new alloc/op   delta
UniqueStrings/Safe-16                    224B ± 0%      128B ± 0%   -42.86%  (p=0.029 n=4+4)
UniqueStrings/Reuse_slice-16            96.0B ± 0%      0.0B       -100.00%  (p=0.029 n=4+4)
UniqueStrings/Reuse_slice_sorted-16     24.0B ± 0%     24.0B ± 0%      ~     (all equal)

name                                 old allocs/op  new allocs/op  delta
UniqueStrings/Safe-16                    7.00 ± 0%      1.00 ± 0%   -85.71%  (p=0.029 n=4+4)
UniqueStrings/Reuse_slice-16             6.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
UniqueStrings/Reuse_slice_sorted-16      1.00 ± 0%      1.00 ± 0%      ~     (all equal)
```

helpers/general.go

index 25decbbc12d169f6a6d7bf955e1821bb435f46dc..74053123fa3d6bb48568fd00239d23b68ae205bd 100644 (file)
@@ -85,11 +85,16 @@ func FirstUpper(s string) string {
 // UniqueStrings returns a new slice with any duplicates removed.
 func UniqueStrings(s []string) []string {
        unique := make([]string, 0, len(s))
-       set := map[string]interface{}{}
-       for _, val := range s {
-               if _, ok := set[val]; !ok {
+       for i, val := range s {
+               var seen bool
+               for j := 0; j < i; j++ {
+                       if s[j] == val {
+                               seen = true
+                               break
+                       }
+               }
+               if !seen {
                        unique = append(unique, val)
-                       set[val] = val
                }
        }
        return unique
@@ -98,12 +103,19 @@ func UniqueStrings(s []string) []string {
 // UniqueStringsReuse returns a slice with any duplicates removed.
 // It will modify the input slice.
 func UniqueStringsReuse(s []string) []string {
-       set := map[string]interface{}{}
        result := s[:0]
-       for _, val := range s {
-               if _, ok := set[val]; !ok {
+       for i, val := range s {
+               var seen bool
+
+               for j := 0; j < i; j++ {
+                       if s[j] == val {
+                               seen = true
+                               break
+                       }
+               }
+
+               if !seen {
                        result = append(result, val)
-                       set[val] = val
                }
        }
        return result