Skip to content

Commit

Permalink
chore: matchSet.addX - add length check and option for "update-in-place"
Browse files Browse the repository at this point in the history
- addX: adding length check to avoid copying the map if nothing was
  changed.
- Introducing addXSingleThreaded which allows update-in-place in
  single-threaded usages.

```
name \ time/op                          benchs/1_baseline  benchs/2_len_check  benchs/3_thread_safe_add  benchs/4_thread_safe_len_check
_Quamina-10                                   48.0µs ± 0%         33.9µs ± 0%                6.6µs ± 0%                      6.8µs ± 0%

name \ alloc/op                         benchs/1_baseline  benchs/2_len_check  benchs/3_thread_safe_add  benchs/4_thread_safe_len_check
_Quamina-10                                   41.0kB ± 0%         30.4kB ± 0%                8.9kB ± 0%                      8.9kB ± 0%

name \ allocs/op                        benchs/1_baseline  benchs/2_len_check  benchs/3_thread_safe_add  benchs/4_thread_safe_len_check
_Quamina-10                                      161 ± 0%            129 ± 0%                   28 ± 0%                         28 ± 0%
```

* `benchs/1_baseline` - baseline
* `benchs/2_len_check` - adding early returrn with length check to `addX` (still being used in matching)
* `benchs/3_thread_safe_add` - using `addXSingleThreaded` in matching
* `benchs/4_thread_safe_len_check` - adding early return with length check to `addXSingleThreaded` .. didn't improved the situation, which makes sense in this case.
  • Loading branch information
yosiat committed Sep 27, 2022
1 parent 6b85ff9 commit 8f3267c
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 3 deletions.
6 changes: 3 additions & 3 deletions core_matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,11 @@ func (m *coreMatcher) matchesForSortedFields(fields []Field) *matchSet {
for _, nextState := range nextStates {

// if arriving at this state means we've matched one or more patterns, record that fact
matches = matches.addX(nextState.fields().matches...)
matches = matches.addXSingleThreaded(nextState.fields().matches...)

// have we invalidated a presumed exists:false pattern?
for existsMatch := range nextState.fields().existsFalseFailures.set {
failedExistsFalseMatches = failedExistsFalseMatches.addX(existsMatch)
failedExistsFalseMatches = failedExistsFalseMatches.addXSingleThreaded(existsMatch)
}

// for each state we've transitioned to, give each subsequent field a chance to
Expand All @@ -197,7 +197,7 @@ func (m *coreMatcher) matchesForSortedFields(fields []Field) *matchSet {
}
for presumedExistsFalseMatch := range m.start().presumedExistFalseMatches.set {
if !failedExistsFalseMatches.contains(presumedExistsFalseMatch) {
matches = matches.addX(presumedExistsFalseMatch)
matches = matches.addXSingleThreaded(presumedExistsFalseMatch)
}
}
return matches
Expand Down
12 changes: 12 additions & 0 deletions match_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ func newMatchSet() *matchSet {
}

func (m *matchSet) addX(exes ...X) *matchSet {
if len(exes) == 0 {
return m
}

// for concurrency, can't update in place
newSet := make(map[X]bool, len(m.set)+1)
for k := range m.set {
Expand All @@ -22,6 +26,14 @@ func (m *matchSet) addX(exes ...X) *matchSet {
return &matchSet{set: newSet}
}

func (m *matchSet) addXSingleThreaded(exes ...X) *matchSet {
for _, x := range exes {
m.set[x] = true
}

return m
}

func (m *matchSet) contains(x X) bool {
_, ok := m.set[x]
return ok
Expand Down
70 changes: 70 additions & 0 deletions match_set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package quamina

import "testing"

func TestAddX(t *testing.T) {
set := newMatchSet()

// empty exes
set = set.addX()
if !isSameMatches(set) {
t.Errorf("Expected matches to be empty: %+v", set.matches())
}

newSet := set.addX(1)
// existing set should be empty.
if len(set.matches()) > 0 {
t.Errorf("Expected matches to be empty: %+v", set.matches())
}
if !isSameMatches(newSet, 1) {
t.Errorf("Expected matches to be [1]: %+v", set.matches())
}

// add another two values
newSet = newSet.addX(2)
newSet = newSet.addX(3)
if !isSameMatches(newSet, 1, 2, 3) {
t.Errorf("Expected matches to be [1, 2, 3]: %+v", set.matches())
}
}

func TestAddXSingleThreaded(t *testing.T) {
set := newMatchSet()

// empty exes
set.addXSingleThreaded()
if !isSameMatches(set) {
t.Errorf("Expected matches to be empty: %+v", set.matches())
}

set.addXSingleThreaded(1)
// existing set should be empty.
if !isSameMatches(set, 1) {
t.Errorf("Expected matches to be [1]: %+v", set.matches())
}

// add another two values
set.addXSingleThreaded(2)
set.addXSingleThreaded(3)
if !isSameMatches(set, 1, 2, 3) {
t.Errorf("Expected matches to be [1, 2, 3]: %+v", set.matches())
}
}

func isSameMatches(matchSet *matchSet, exes ...X) bool {
if len(exes) == 0 && len(matchSet.matches()) == 0 {
return true
}

if len(exes) != len(matchSet.matches()) {
return false
}

for _, x := range exes {
if !matchSet.contains(x) {
return false
}
}

return true
}

0 comments on commit 8f3267c

Please sign in to comment.