Source file src/bytes/iter.go

     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  

View as plain text