fields.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /*
  2. Copyright 2020 The Go4 AUTHORS
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package mem
  14. import (
  15. "unicode"
  16. "unicode/utf8"
  17. )
  18. var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
  19. // AppendFields is like strings.Fields, but is append-like and uses a mem.RO instead of a string.
  20. func AppendFields(dst []RO, m RO) []RO {
  21. s := m.m
  22. // Copied from the Go standard library (BSD license).
  23. // First count the fields.
  24. // This is an exact count if s is ASCII, otherwise it is an approximation.
  25. n := 0
  26. wasSpace := 1
  27. // setBits is used to track which bits are set in the bytes of s.
  28. setBits := uint8(0)
  29. for i := 0; i < len(s); i++ {
  30. r := s[i]
  31. setBits |= r
  32. isSpace := int(asciiSpace[r])
  33. n += wasSpace & ^isSpace
  34. wasSpace = isSpace
  35. }
  36. if setBits >= utf8.RuneSelf {
  37. // Some runes in the input string are not ASCII.
  38. return AppendFieldsFunc(dst, m, unicode.IsSpace)
  39. }
  40. // ASCII fast path
  41. fieldStart := 0
  42. i := 0
  43. // Skip spaces in the front of the input.
  44. for i < len(s) && asciiSpace[s[i]] != 0 {
  45. i++
  46. }
  47. fieldStart = i
  48. for i < len(s) {
  49. if asciiSpace[s[i]] == 0 {
  50. i++
  51. continue
  52. }
  53. dst = append(dst, RO{m: s[fieldStart:i]})
  54. i++
  55. // Skip spaces in between fields.
  56. for i < len(s) && asciiSpace[s[i]] != 0 {
  57. i++
  58. }
  59. fieldStart = i
  60. }
  61. if fieldStart < len(s) { // Last field might end at EOF.
  62. dst = append(dst, RO{m: s[fieldStart:]})
  63. }
  64. return dst
  65. }
  66. // AppendFieldsFunc is like strings.FieldsFunc, but is append-like and uses a mem.RO instead of a string.
  67. func AppendFieldsFunc(dst []RO, m RO, f func(rune) bool) []RO {
  68. s := string(m.m)
  69. // Find the field start and end indices.
  70. wasField := false
  71. fromIndex := 0
  72. for i, rune := range s {
  73. if f(rune) {
  74. if wasField {
  75. dst = append(dst, RO{m: unsafeString(s[fromIndex:i])})
  76. wasField = false
  77. }
  78. } else {
  79. if !wasField {
  80. fromIndex = i
  81. wasField = true
  82. }
  83. }
  84. }
  85. // Last field might end at EOF.
  86. if wasField {
  87. dst = append(dst, RO{m: unsafeString(s[fromIndex:len(s)])})
  88. }
  89. return dst
  90. }