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  }