github.com/patricebensoussan/go/codec@v1.2.99/writer.go (about) 1 // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved. 2 // Use of this source code is governed by a MIT license found in the LICENSE file. 3 4 package codec 5 6 import "io" 7 8 // encWriter abstracts writing to a byte array or to an io.Writer. 9 type encWriter interface { 10 writeb([]byte) 11 writestr(string) 12 writeqstr(string) // write string wrapped in quotes ie "..." 13 writen1(byte) 14 15 // add convenience functions for writing 2,4 16 writen2(byte, byte) 17 writen4([4]byte) 18 writen8([8]byte) 19 20 end() 21 } 22 23 // --------------------------------------------- 24 25 type bufioEncWriter struct { 26 w io.Writer 27 28 buf []byte 29 30 n int 31 32 b [16]byte // scratch buffer and padding (cache-aligned) 33 } 34 35 func (z *bufioEncWriter) reset(w io.Writer, bufsize int, blist *bytesFreelist) { 36 z.w = w 37 z.n = 0 38 if bufsize <= 0 { 39 bufsize = defEncByteBufSize 40 } 41 // bufsize must be >= 8, to accomodate writen methods (where n <= 8) 42 if bufsize <= 8 { 43 bufsize = 8 44 } 45 if cap(z.buf) < bufsize { 46 if len(z.buf) > 0 && &z.buf[0] != &z.b[0] { 47 blist.put(z.buf) 48 } 49 if len(z.b) > bufsize { 50 z.buf = z.b[:] 51 } else { 52 z.buf = blist.get(bufsize) 53 } 54 } 55 z.buf = z.buf[:cap(z.buf)] 56 } 57 58 func (z *bufioEncWriter) flushErr() (err error) { 59 n, err := z.w.Write(z.buf[:z.n]) 60 z.n -= n 61 if z.n > 0 { 62 if err == nil { 63 err = io.ErrShortWrite 64 } 65 if n > 0 { 66 copy(z.buf, z.buf[n:z.n+n]) 67 } 68 } 69 return err 70 } 71 72 func (z *bufioEncWriter) flush() { 73 halt.onerror(z.flushErr()) 74 } 75 76 func (z *bufioEncWriter) writeb(s []byte) { 77 LOOP: 78 a := len(z.buf) - z.n 79 if len(s) > a { 80 z.n += copy(z.buf[z.n:], s[:a]) 81 s = s[a:] 82 z.flush() 83 goto LOOP 84 } 85 z.n += copy(z.buf[z.n:], s) 86 } 87 88 func (z *bufioEncWriter) writestr(s string) { 89 // z.writeb(bytesView(s)) // inlined below 90 LOOP: 91 a := len(z.buf) - z.n 92 if len(s) > a { 93 z.n += copy(z.buf[z.n:], s[:a]) 94 s = s[a:] 95 z.flush() 96 goto LOOP 97 } 98 z.n += copy(z.buf[z.n:], s) 99 } 100 101 func (z *bufioEncWriter) writeqstr(s string) { 102 // z.writen1('"') 103 // z.writestr(s) 104 // z.writen1('"') 105 106 if z.n+len(s)+2 > len(z.buf) { 107 z.flush() 108 } 109 z.buf[z.n] = '"' 110 z.n++ 111 LOOP: 112 a := len(z.buf) - z.n 113 if len(s)+1 > a { 114 z.n += copy(z.buf[z.n:], s[:a]) 115 s = s[a:] 116 z.flush() 117 goto LOOP 118 } 119 z.n += copy(z.buf[z.n:], s) 120 z.buf[z.n] = '"' 121 z.n++ 122 } 123 124 func (z *bufioEncWriter) writen1(b1 byte) { 125 if 1 > len(z.buf)-z.n { 126 z.flush() 127 } 128 z.buf[z.n] = b1 129 z.n++ 130 } 131 func (z *bufioEncWriter) writen2(b1, b2 byte) { 132 if 2 > len(z.buf)-z.n { 133 z.flush() 134 } 135 z.buf[z.n+1] = b2 136 z.buf[z.n] = b1 137 z.n += 2 138 } 139 func (z *bufioEncWriter) writen4(b [4]byte) { 140 if 4 > len(z.buf)-z.n { 141 z.flush() 142 } 143 copy(z.buf[z.n:], b[:]) 144 z.n += 4 145 } 146 147 func (z *bufioEncWriter) writen8(b [8]byte) { 148 if 8 > len(z.buf)-z.n { 149 z.flush() 150 } 151 copy(z.buf[z.n:], b[:]) 152 z.n += 8 153 } 154 155 func (z *bufioEncWriter) endErr() (err error) { 156 if z.n > 0 { 157 err = z.flushErr() 158 } 159 return 160 } 161 162 // --------------------------------------------- 163 164 // bytesEncAppender implements encWriter and can write to an byte slice. 165 type bytesEncAppender struct { 166 b []byte 167 out *[]byte 168 } 169 170 func (z *bytesEncAppender) writeb(s []byte) { 171 z.b = append(z.b, s...) 172 } 173 func (z *bytesEncAppender) writestr(s string) { 174 z.b = append(z.b, s...) 175 } 176 func (z *bytesEncAppender) writeqstr(s string) { 177 z.b = append(append(append(z.b, '"'), s...), '"') 178 // z.b = append(z.b, '"') 179 // z.b = append(z.b, s...) 180 // z.b = append(z.b, '"') 181 } 182 func (z *bytesEncAppender) writen1(b1 byte) { 183 z.b = append(z.b, b1) 184 } 185 func (z *bytesEncAppender) writen2(b1, b2 byte) { 186 z.b = append(z.b, b1, b2) 187 } 188 func (z *bytesEncAppender) writen4(b [4]byte) { 189 z.b = append(z.b, b[:]...) 190 // z.b = append(z.b, b[0], b[1], b[2], b[3]) // prevents inlining encWr.writen4 191 } 192 func (z *bytesEncAppender) writen8(b [8]byte) { 193 z.b = append(z.b, b[:]...) 194 // z.b = append(z.b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]) // prevents inlining encWr.writen4 195 } 196 func (z *bytesEncAppender) endErr() error { 197 *(z.out) = z.b 198 return nil 199 } 200 func (z *bytesEncAppender) reset(in []byte, out *[]byte) { 201 z.b = in[:0] 202 z.out = out 203 } 204 205 // -------------------------------------------------- 206 207 type encWr struct { 208 bytes bool // encoding to []byte 209 js bool // is json encoder? 210 be bool // is binary encoder? 211 212 c containerState 213 214 calls uint16 215 seq uint16 // sequencer (e.g. used by binc for symbols, etc) 216 wb bytesEncAppender 217 wf *bufioEncWriter 218 } 219 220 // MARKER: manually inline bytesEncAppender.writenx/writeqstr methods, 221 // as calling them causes encWr.writenx/writeqstr methods to not be inlined (cost > 80). 222 // 223 // i.e. e.g. instead of writing z.wb.writen2(b1, b2), use z.wb.b = append(z.wb.b, b1, b2) 224 225 func (z *encWr) writeb(s []byte) { 226 if z.bytes { 227 z.wb.writeb(s) 228 } else { 229 z.wf.writeb(s) 230 } 231 } 232 func (z *encWr) writeqstr(s string) { 233 if z.bytes { 234 // MARKER: z.wb.writeqstr(s) 235 z.wb.b = append(append(append(z.wb.b, '"'), s...), '"') 236 } else { 237 z.wf.writeqstr(s) 238 } 239 } 240 func (z *encWr) writestr(s string) { 241 if z.bytes { 242 z.wb.writestr(s) 243 } else { 244 z.wf.writestr(s) 245 } 246 } 247 func (z *encWr) writen1(b1 byte) { 248 if z.bytes { 249 z.wb.writen1(b1) 250 } else { 251 z.wf.writen1(b1) 252 } 253 } 254 255 func (z *encWr) writen2(b1, b2 byte) { 256 if z.bytes { 257 // MARKER: z.wb.writen2(b1, b2) 258 z.wb.b = append(z.wb.b, b1, b2) 259 } else { 260 z.wf.writen2(b1, b2) 261 } 262 } 263 func (z *encWr) writen4(b [4]byte) { 264 if z.bytes { 265 z.wb.writen4(b) 266 } else { 267 z.wf.writen4(b) 268 } 269 } 270 func (z *encWr) writen8(b [8]byte) { 271 if z.bytes { 272 z.wb.writen8(b) 273 } else { 274 z.wf.writen8(b) 275 } 276 } 277 278 func (z *encWr) endErr() error { 279 if z.bytes { 280 return z.wb.endErr() 281 } 282 return z.wf.endErr() 283 } 284 285 func (z *encWr) end() { 286 halt.onerror(z.endErr()) 287 } 288 289 var _ encWriter = (*encWr)(nil)