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)