iter_wasm.mx raw

   1  // Copyright 2024 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package bytes
   6  
   7  import (
   8  	"iter"
   9  	"unicode"
  10  	"unicode/utf8"
  11  )
  12  
  13  // Lines returns an iterator over the newline-terminated lines in the byte slice s.
  14  // The lines yielded by the iterator include their terminating newlines.
  15  // If s is empty, the iterator yields no lines at all.
  16  // If s does not end in a newline, the final yielded line will not end in a newline.
  17  // It returns a single-use iterator.
  18  func Lines(s []byte) iter.Seq[[]byte] {
  19  	return func(yield func([]byte) bool) {
  20  		for len(s) > 0 {
  21  			var line []byte
  22  			if i := IndexByte(s, '\n'); i >= 0 {
  23  				line, s = s[:i+1], s[i+1:]
  24  			} else {
  25  				line, s = s, nil
  26  			}
  27  			if !yield(line[:len(line):len(line)]) {
  28  				return
  29  			}
  30  		}
  31  	}
  32  }
  33  
  34  // splitSeq is SplitSeq or SplitAfterSeq, configured by how many
  35  // bytes of sep to include in the results (none or all).
  36  func splitSeq(s, sep []byte, sepSave int32) iter.Seq[[]byte] {
  37  	return func(yield func([]byte) bool) {
  38  		if len(sep) == 0 {
  39  			for len(s) > 0 {
  40  				_, size := utf8.DecodeRune(s)
  41  				if !yield(s[:size:size]) {
  42  					return
  43  				}
  44  				s = s[size:]
  45  			}
  46  			return
  47  		}
  48  		for {
  49  			i := Index(s, sep)
  50  			if i < 0 {
  51  				break
  52  			}
  53  			frag := s[:i+sepSave]
  54  			if !yield(frag[:len(frag):len(frag)]) {
  55  				return
  56  			}
  57  			s = s[i+len(sep):]
  58  		}
  59  		yield(s[:len(s):len(s)])
  60  	}
  61  }
  62  
  63  // SplitSeq returns an iterator over all subslices of s separated by sep.
  64  // The iterator yields the same subslices that would be returned by [Split](s, sep),
  65  // but without constructing a new slice containing the subslices.
  66  // It returns a single-use iterator.
  67  func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
  68  	return splitSeq(s, sep, 0)
  69  }
  70  
  71  // SplitAfterSeq returns an iterator over subslices of s split after each instance of sep.
  72  // The iterator yields the same subslices that would be returned by [SplitAfter](s, sep),
  73  // but without constructing a new slice containing the subslices.
  74  // It returns a single-use iterator.
  75  func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
  76  	return splitSeq(s, sep, len(sep))
  77  }
  78  
  79  // FieldsSeq returns an iterator over subslices of s split around runs of
  80  // whitespace characters, as defined by [unicode.IsSpace].
  81  // The iterator yields the same subslices that would be returned by [Fields](s),
  82  // but without constructing a new slice containing the subslices.
  83  func FieldsSeq(s []byte) iter.Seq[[]byte] {
  84  	return func(yield func([]byte) bool) {
  85  		asciiSpace := _asciiSpace()
  86  		t := unicode.NewTables()
  87  		start := -1
  88  		for i := 0; i < len(s); {
  89  			size := 1
  90  			r := rune(s[i])
  91  			isSpace := asciiSpace[s[i]] != 0
  92  			if r >= utf8.RuneSelf {
  93  				r, size = utf8.DecodeRune(s[i:])
  94  				isSpace = t.IsSpace(r)
  95  			}
  96  			if isSpace {
  97  				if start >= 0 {
  98  					if !yield(s[start:i:i]) {
  99  						return
 100  					}
 101  					start = -1
 102  				}
 103  			} else if start < 0 {
 104  				start = i
 105  			}
 106  			i += size
 107  		}
 108  		if start >= 0 {
 109  			yield(s[start:len(s):len(s)])
 110  		}
 111  	}
 112  }
 113  
 114  // FieldsFuncSeq returns an iterator over subslices of s split around runs of
 115  // Unicode code points satisfying f(c).
 116  // The iterator yields the same subslices that would be returned by [FieldsFunc](s),
 117  // but without constructing a new slice containing the subslices.
 118  func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
 119  	return func(yield func([]byte) bool) {
 120  		start := -1
 121  		for i := 0; i < len(s); {
 122  			size := 1
 123  			r := rune(s[i])
 124  			if r >= utf8.RuneSelf {
 125  				r, size = utf8.DecodeRune(s[i:])
 126  			}
 127  			if f(r) {
 128  				if start >= 0 {
 129  					if !yield(s[start:i:i]) {
 130  						return
 131  					}
 132  					start = -1
 133  				}
 134  			} else if start < 0 {
 135  				start = i
 136  			}
 137  			i += size
 138  		}
 139  		if start >= 0 {
 140  			yield(s[start:len(s):len(s)])
 141  		}
 142  	}
 143  }
 144