github.com/influx6/npkg@v0.8.8/nbytes/builder.go (about) 1 package nbytes 2 3 import ( 4 "io" 5 "unicode/utf8" 6 "unsafe" 7 ) 8 9 // BuildReader implements a Bytes Builder with a wrapped reader to allow 10 // reading off content from a provided Builder. 11 type BuildReader struct { 12 builder *Builder 13 i int 14 } 15 16 // NewBuildReader returns a new instance of BuildReader. 17 func NewBuildReader() *BuildReader { 18 var br Builder 19 br.copyCheck() 20 return &BuildReader{ 21 builder: &br, 22 i: -1, 23 } 24 } 25 26 // BuildReaderWith returns a new instance of BuildReader using the Builder. 27 func BuildReaderWith(bm *Builder) *BuildReader { 28 return &BuildReader{ 29 builder: bm, 30 i: -1, 31 } 32 } 33 34 // BuildReaderFor returns a new instance of BuildReader using the byte slice. 35 func BuildReaderFor(bm []byte) *BuildReader { 36 var br Builder 37 br.buf = bm 38 br.copyCheck() 39 40 return &BuildReader{ 41 builder: &br, 42 i: -1, 43 } 44 } 45 46 // Builder returns the underline builder for reader. 47 func (r *BuildReader) Builder() *Builder { 48 return r.builder 49 } 50 51 // Reset resets underline builder. 52 // It reuses underline buffer unless argument is true, 53 // which allows for efficient reading and managing of reader. 54 func (r *BuildReader) Reset(dontReuse bool) { 55 var lastBuf = r.builder.buf 56 r.builder.Reset() 57 r.i = -1 58 59 if !dontReuse { 60 r.builder.buf = lastBuf[:0] 61 } 62 } 63 64 // Read provides a Read method wrapper around a provided Builder. 65 func (r *BuildReader) Read(b []byte) (n int, err error) { 66 if r.i >= r.builder.Len() { 67 return 0, io.EOF 68 } 69 70 if r.i <= 0 { 71 r.i++ 72 n = 0 73 return 74 } 75 76 n = copy(b, r.builder.buf[r.i:]) 77 r.i += n 78 return 79 } 80 81 // Len returns the current length of reader. 82 func (r *BuildReader) Len() int { 83 if r.i >= r.builder.Len() { 84 return 0 85 } 86 87 return r.builder.Len() - r.i 88 } 89 90 // ReadByte returns a single byte from the underline byte slice. 91 func (r *BuildReader) ReadByte() (byte, error) { 92 if r.i >= r.builder.Len() { 93 return 0, io.EOF 94 } 95 96 if r.i >= r.builder.Len() { 97 return 0, io.EOF 98 } 99 100 nextByte := r.builder.buf[r.i] 101 r.i++ 102 return nextByte, nil 103 } 104 105 // Write writes new data into reader. 106 func (r *BuildReader) Write(b []byte) (int, error) { 107 if r.i <= -1 { 108 r.i = 0 109 } 110 return r.builder.Write(b) 111 } 112 113 // WriteByte writes new data into reader. 114 func (r *BuildReader) WriteByte(b byte) error { 115 if r.i <= -1 { 116 r.i = 0 117 } 118 return r.builder.WriteByte(b) 119 } 120 121 // WriteString writes new data into reader. 122 func (r *BuildReader) WriteString(b string) (int, error) { 123 return r.builder.WriteString(b) 124 } 125 126 func (r *BuildReader) String() string { 127 return r.builder.String() 128 } 129 130 // A Builder is used to efficiently build a string using Write methods. 131 // It minimizes memory copying. The zero value is ready to use. 132 // Do not copy a non-zero Builder. 133 type Builder struct { 134 addr *Builder // of receiver, to detect copies by value 135 buf []byte 136 } 137 138 // NewBuilder returns new reader. 139 func NewBuilder() *Builder { 140 var bm Builder 141 bm.copyCheck() 142 return &bm 143 } 144 145 // BuilderWith returns new reader. 146 func BuilderWith(m []byte) *Builder { 147 var bm Builder 148 bm.copyCheck() 149 bm.buf = m 150 return &bm 151 } 152 153 // noescape hides a pointer from escape analysis. noescape is 154 // the identity function but escape analysis doesn't think the 155 // output depends on the input. noescape is inlined and currently 156 // compiles down to zero instructions. 157 // USE CAREFULLY! 158 // This was copied from the runtime; see issues 23382 and 7921. 159 //go:nosplit 160 func noescape(p unsafe.Pointer) unsafe.Pointer { 161 x := uintptr(p) 162 return unsafe.Pointer(x ^ 0) 163 } 164 165 func (b *Builder) copyCheck() { 166 if b.addr == nil { 167 // This hack works around a failing of Go's escape analysis 168 // that was causing b to escape and be heap allocated. 169 // See issue 23382. 170 // TODO: once issue 7921 is fixed, this should be reverted to 171 // just "b.addr = b". 172 b.addr = (*Builder)(noescape(unsafe.Pointer(b))) 173 } else if b.addr != b { 174 panic("strings: illegal use of non-zero Builder copied by value") 175 } 176 } 177 178 // Bytes returns the accumulated byte slice. 179 func (b *Builder) Bytes() []byte { 180 return b.buf 181 } 182 183 // Copy returns the accumulated byte slice. 184 func (b *Builder) Copy() []byte { 185 var buf = make([]byte, len(b.buf)) 186 copy(buf, b.buf) 187 return buf 188 } 189 190 // String returns the accumulated string. 191 func (b *Builder) String() string { 192 return *(*string)(unsafe.Pointer(&b.buf)) 193 } 194 195 // Len returns the number of accumulated bytes; b.Len() == len(b.String()). 196 func (b *Builder) Len() int { return len(b.buf) } 197 198 // Cap returns the capacity of the builder's underlying byte slice. It is the 199 // total space allocated for the string being built and includes any bytes 200 // already written. 201 func (b *Builder) Cap() int { return cap(b.buf) } 202 203 // Reset resets the Builder to be empty. 204 func (b *Builder) Reset() { 205 b.addr = nil 206 b.buf = nil 207 } 208 209 // grow copies the buffer to a new, larger buffer so that there are at least n 210 // bytes of capacity beyond len(b.buf). 211 func (b *Builder) grow(n int) { 212 buf := make([]byte, len(b.buf), 2*cap(b.buf)+n) 213 copy(buf, b.buf) 214 b.buf = buf 215 } 216 217 // Grow grows b's capacity, if necessary, to guarantee space for 218 // another n bytes. After Grow(n), at least n bytes can be written to b 219 // without another allocation. If n is negative, Grow panics. 220 func (b *Builder) Grow(n int) { 221 b.copyCheck() 222 if n < 0 { 223 panic("strings.Builder.Grow: negative count") 224 } 225 226 if cap(b.buf)-len(b.buf) < n { 227 b.grow(n) 228 } 229 } 230 231 // Write appends the contents of p to b's buffer. 232 // Write always returns len(p), nil. 233 func (b *Builder) Write(p []byte) (int, error) { 234 b.copyCheck() 235 b.buf = append(b.buf, p...) 236 return len(p), nil 237 } 238 239 // WriteByte appends the byte c to b's buffer. 240 // The returned error is always nil. 241 func (b *Builder) WriteByte(c byte) error { 242 b.copyCheck() 243 b.buf = append(b.buf, c) 244 return nil 245 } 246 247 // WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer. 248 // It returns the length of r and a nil error. 249 func (b *Builder) WriteRune(r rune) (int, error) { 250 b.copyCheck() 251 if r < utf8.RuneSelf { 252 b.buf = append(b.buf, byte(r)) 253 return 1, nil 254 } 255 256 l := len(b.buf) 257 if cap(b.buf)-l < utf8.UTFMax { 258 b.grow(utf8.UTFMax) 259 } 260 261 n := utf8.EncodeRune(b.buf[l:l+utf8.UTFMax], r) 262 b.buf = b.buf[:l+n] 263 return n, nil 264 } 265 266 // WriteString appends the contents of s to b's buffer. 267 // It returns the length of s and a nil error. 268 func (b *Builder) WriteString(s string) (int, error) { 269 b.copyCheck() 270 b.buf = append(b.buf, s...) 271 return len(s), nil 272 }