iter.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 int) 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  		start := -1
  86  		for i := 0; i < len(s); {
  87  			size := 1
  88  			r := rune(s[i])
  89  			isSpace := asciiSpace[s[i]] != 0
  90  			if r >= utf8.RuneSelf {
  91  				r, size = utf8.DecodeRune(s[i:])
  92  				isSpace = unicode.IsSpace(r)
  93  			}
  94  			if isSpace {
  95  				if start >= 0 {
  96  					if !yield(s[start:i:i]) {
  97  						return
  98  					}
  99  					start = -1
 100  				}
 101  			} else if start < 0 {
 102  				start = i
 103  			}
 104  			i += size
 105  		}
 106  		if start >= 0 {
 107  			yield(s[start:len(s):len(s)])
 108  		}
 109  	}
 110  }
 111  
 112  // FieldsFuncSeq returns an iterator over subslices of s split around runs of
 113  // Unicode code points satisfying f(c).
 114  // The iterator yields the same subslices that would be returned by [FieldsFunc](s),
 115  // but without constructing a new slice containing the subslices.
 116  func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
 117  	return func(yield func([]byte) bool) {
 118  		start := -1
 119  		for i := 0; i < len(s); {
 120  			size := 1
 121  			r := rune(s[i])
 122  			if r >= utf8.RuneSelf {
 123  				r, size = utf8.DecodeRune(s[i:])
 124  			}
 125  			if f(r) {
 126  				if start >= 0 {
 127  					if !yield(s[start:i:i]) {
 128  						return
 129  					}
 130  					start = -1
 131  				}
 132  			} else if start < 0 {
 133  				start = i
 134  			}
 135  			i += size
 136  		}
 137  		if start >= 0 {
 138  			yield(s[start:len(s):len(s)])
 139  		}
 140  	}
 141  }
 142