diff options
| author | Cuong Manh Le <cuong.manhle.vn@gmail.com> | 2024-09-26 01:37:07 +0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2024-09-28 00:51:17 +0000 |
| commit | 677b6cc17544e5e667d4bb67d063f5d775c69e32 (patch) | |
| tree | c186ad859d66e4bf69185f69e8e4f408d9949917 /test/fixedbugs | |
| parent | 676d427f77ea255fa6e4cdebf0fb348a27575855 (diff) | |
| download | go-677b6cc17544e5e667d4bb67d063f5d775c69e32.tar.xz | |
test: simplify issue 69434 test
Updates #69434
Change-Id: I780c5ed63561eb8fa998bb0e6cdc77a904ff29c8
Reviewed-on: https://go-review.googlesource.com/c/go/+/615915
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'test/fixedbugs')
| -rw-r--r-- | test/fixedbugs/issue69434.go | 164 |
1 files changed, 22 insertions, 142 deletions
diff --git a/test/fixedbugs/issue69434.go b/test/fixedbugs/issue69434.go index 6820466019..6443bde50f 100644 --- a/test/fixedbugs/issue69434.go +++ b/test/fixedbugs/issue69434.go @@ -1,4 +1,4 @@ -// run +// run -gcflags=-d=maymorestack=runtime.mayMoreStackMove // Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -7,167 +7,47 @@ package main import ( - "bufio" - "fmt" - "io" "iter" - "math/rand" - "os" - "strings" - "unicode" ) -// WordReader is the struct that implements io.Reader -type WordReader struct { - scanner *bufio.Scanner -} - -// NewWordReader creates a new WordReader from an io.Reader -func NewWordReader(r io.Reader) *WordReader { - scanner := bufio.NewScanner(r) - scanner.Split(bufio.ScanWords) - return &WordReader{ - scanner: scanner, - } -} - -// Read reads data from the input stream and returns a single lowercase word at a time -func (wr *WordReader) Read(p []byte) (n int, err error) { - if !wr.scanner.Scan() { - if err := wr.scanner.Err(); err != nil { - return 0, err - } - return 0, io.EOF - } - word := wr.scanner.Text() - cleanedWord := removeNonAlphabetic(word) - if len(cleanedWord) == 0 { - return wr.Read(p) - } - n = copy(p, []byte(cleanedWord)) - return n, nil -} - -// All returns an iterator allowing the caller to iterate over the WordReader using for/range. -func (wr *WordReader) All() iter.Seq[string] { - word := make([]byte, 1024) - return func(yield func(string) bool) { - var err error - var n int - for n, err = wr.Read(word); err == nil; n, err = wr.Read(word) { - if !yield(string(word[:n])) { +func All() iter.Seq[int] { + return func(yield func(int) bool) { + for i := 0; i < 10; i++ { + if !yield(i) { return } } - if err != io.EOF { - fmt.Fprintf(os.Stderr, "error reading word: %v\n", err) - } } } -// removeNonAlphabetic removes non-alphabetic characters from a word using strings.Map -func removeNonAlphabetic(word string) string { - return strings.Map(func(r rune) rune { - if unicode.IsLetter(r) { - return unicode.ToLower(r) - } - return -1 - }, word) -} - -// ProbabilisticSkipper determines if an item should be retained with probability 1/(1<<n) -type ProbabilisticSkipper struct { - n int - counter uint64 - bitmask uint64 +type S struct { + round int } -// NewProbabilisticSkipper initializes the ProbabilisticSkipper -func NewProbabilisticSkipper(n int) *ProbabilisticSkipper { - pr := &ProbabilisticSkipper{n: n} - pr.refreshCounter() - return pr +func NewS(round int) *S { + s := &S{round: round} + return s } -// check panics if pr.n is not the expected value -func (pr *ProbabilisticSkipper) check(n int) { - if pr.n != n { - panic(fmt.Sprintf("check: pr.n != n %d != %d", pr.n, n)) +func (s *S) check(round int) { + if s.round != round { + panic("bad round") } } -// refreshCounter refreshes the counter with a new random value -func (pr *ProbabilisticSkipper) refreshCounter() { - if pr.n == 0 { - pr.bitmask = ^uint64(0) // All bits set to 1 - } else { - pr.bitmask = rand.Uint64() - for i := 0; i < pr.n-1; i++ { - pr.bitmask &= rand.Uint64() - } - } - pr.counter = 64 -} - -// ShouldSkip returns true with probability 1/(1<<n) -func (pr *ProbabilisticSkipper) ShouldSkip() bool { - remove := pr.bitmask&1 == 0 - pr.bitmask >>= 1 - pr.counter-- - if pr.counter == 0 { - pr.refreshCounter() - } - return remove -} - -// EstimateUniqueWordsIter estimates the number of unique words using a probabilistic counting method -func EstimateUniqueWordsIter(reader io.Reader, memorySize int) int { - wordReader := NewWordReader(reader) - words := make(map[string]struct{}, memorySize) - +func f() { rounds := 0 - roundRemover := NewProbabilisticSkipper(1) - wordSkipper := NewProbabilisticSkipper(rounds) - wordSkipper.check(rounds) - - for word := range wordReader.All() { - wordSkipper.check(rounds) - if wordSkipper.ShouldSkip() { - delete(words, word) - } else { - words[word] = struct{}{} - - if len(words) >= memorySize { - rounds++ + s := NewS(rounds) + s.check(rounds) - wordSkipper = NewProbabilisticSkipper(rounds) - for w := range words { - if roundRemover.ShouldSkip() { - delete(words, w) - } - } - } - } - wordSkipper.check(rounds) - } - - if len(words) == 0 { - return 0 + for range All() { + s.check(rounds) + rounds++ + s = NewS(rounds) + s.check(rounds) } - - invProbability := 1 << rounds - estimatedUniqueWords := len(words) * invProbability - return estimatedUniqueWords } func main() { - input := "Hello, world! This is a test. Hello, world, hello!" - expectedUniqueWords := 6 // "hello", "world", "this", "is", "a", "test" (but "hello" and "world" are repeated) - memorySize := 6 - - reader := strings.NewReader(input) - estimatedUniqueWords := EstimateUniqueWordsIter(reader, memorySize) - if estimatedUniqueWords != expectedUniqueWords { - // ... - } + f() } |
