| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- /*
- Copyright 2020 The Go4 AUTHORS
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package mem
- import (
- "unicode"
- "unicode/utf8"
- )
- var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
- // AppendFields is like strings.Fields, but is append-like and uses a mem.RO instead of a string.
- func AppendFields(dst []RO, m RO) []RO {
- s := m.m
- // Copied from the Go standard library (BSD license).
- // First count the fields.
- // This is an exact count if s is ASCII, otherwise it is an approximation.
- n := 0
- wasSpace := 1
- // setBits is used to track which bits are set in the bytes of s.
- setBits := uint8(0)
- for i := 0; i < len(s); i++ {
- r := s[i]
- setBits |= r
- isSpace := int(asciiSpace[r])
- n += wasSpace & ^isSpace
- wasSpace = isSpace
- }
- if setBits >= utf8.RuneSelf {
- // Some runes in the input string are not ASCII.
- return AppendFieldsFunc(dst, m, unicode.IsSpace)
- }
- // ASCII fast path
- fieldStart := 0
- i := 0
- // Skip spaces in the front of the input.
- for i < len(s) && asciiSpace[s[i]] != 0 {
- i++
- }
- fieldStart = i
- for i < len(s) {
- if asciiSpace[s[i]] == 0 {
- i++
- continue
- }
- dst = append(dst, RO{m: s[fieldStart:i]})
- i++
- // Skip spaces in between fields.
- for i < len(s) && asciiSpace[s[i]] != 0 {
- i++
- }
- fieldStart = i
- }
- if fieldStart < len(s) { // Last field might end at EOF.
- dst = append(dst, RO{m: s[fieldStart:]})
- }
- return dst
- }
- // AppendFieldsFunc is like strings.FieldsFunc, but is append-like and uses a mem.RO instead of a string.
- func AppendFieldsFunc(dst []RO, m RO, f func(rune) bool) []RO {
- s := string(m.m)
- // Find the field start and end indices.
- wasField := false
- fromIndex := 0
- for i, rune := range s {
- if f(rune) {
- if wasField {
- dst = append(dst, RO{m: unsafeString(s[fromIndex:i])})
- wasField = false
- }
- } else {
- if !wasField {
- fromIndex = i
- wasField = true
- }
- }
- }
- // Last field might end at EOF.
- if wasField {
- dst = append(dst, RO{m: unsafeString(s[fromIndex:len(s)])})
- }
- return dst
- }
|