gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

input.go (4154B)


      1 package parse
      2 
      3 import (
      4 	"io"
      5 	"io/ioutil"
      6 )
      7 
      8 var nullBuffer = []byte{0}
      9 
     10 // Input is a buffered reader that allows peeking forward and shifting, taking an io.Input.
     11 // It keeps data in-memory until Free, taking a byte length, is called to move beyond the data.
     12 type Input struct {
     13 	buf   []byte
     14 	pos   int // index in buf
     15 	start int // index in buf
     16 	err   error
     17 
     18 	restore func()
     19 }
     20 
     21 // NewInput returns a new Input for a given io.Input and uses ioutil.ReadAll to read it into a byte slice.
     22 // If the io.Input implements Bytes, that is used instead. It will append a NULL at the end of the buffer.
     23 func NewInput(r io.Reader) *Input {
     24 	var b []byte
     25 	if r != nil {
     26 		if buffer, ok := r.(interface {
     27 			Bytes() []byte
     28 		}); ok {
     29 			b = buffer.Bytes()
     30 		} else {
     31 			var err error
     32 			b, err = ioutil.ReadAll(r)
     33 			if err != nil {
     34 				return &Input{
     35 					buf: nullBuffer,
     36 					err: err,
     37 				}
     38 			}
     39 		}
     40 	}
     41 	return NewInputBytes(b)
     42 }
     43 
     44 // NewInputString returns a new Input for a given string and appends NULL at the end.
     45 func NewInputString(s string) *Input {
     46 	return NewInputBytes([]byte(s))
     47 }
     48 
     49 // NewInputBytes returns a new Input for a given byte slice and appends NULL at the end.
     50 // To avoid reallocation, make sure the capacity has room for one more byte.
     51 func NewInputBytes(b []byte) *Input {
     52 	z := &Input{
     53 		buf: b,
     54 	}
     55 
     56 	n := len(b)
     57 	if n == 0 {
     58 		z.buf = nullBuffer
     59 	} else {
     60 		// Append NULL to buffer, but try to avoid reallocation
     61 		if cap(b) > n {
     62 			// Overwrite next byte but restore when done
     63 			b = b[:n+1]
     64 			c := b[n]
     65 			b[n] = 0
     66 
     67 			z.buf = b
     68 			z.restore = func() {
     69 				b[n] = c
     70 			}
     71 		} else {
     72 			z.buf = append(b, 0)
     73 		}
     74 	}
     75 	return z
     76 }
     77 
     78 // Restore restores the replaced byte past the end of the buffer by NULL.
     79 func (z *Input) Restore() {
     80 	if z.restore != nil {
     81 		z.restore()
     82 		z.restore = nil
     83 	}
     84 }
     85 
     86 // Err returns the error returned from io.Input or io.EOF when the end has been reached.
     87 func (z *Input) Err() error {
     88 	return z.PeekErr(0)
     89 }
     90 
     91 // PeekErr returns the error at position pos. When pos is zero, this is the same as calling Err().
     92 func (z *Input) PeekErr(pos int) error {
     93 	if z.err != nil {
     94 		return z.err
     95 	} else if z.pos+pos >= len(z.buf)-1 {
     96 		return io.EOF
     97 	}
     98 	return nil
     99 }
    100 
    101 // Peek returns the ith byte relative to the end position.
    102 // Peek returns 0 when an error has occurred, Err returns the erroz.
    103 func (z *Input) Peek(pos int) byte {
    104 	pos += z.pos
    105 	return z.buf[pos]
    106 }
    107 
    108 // PeekRune returns the rune and rune length of the ith byte relative to the end position.
    109 func (z *Input) PeekRune(pos int) (rune, int) {
    110 	// from unicode/utf8
    111 	c := z.Peek(pos)
    112 	if c < 0xC0 || z.Peek(pos+1) == 0 {
    113 		return rune(c), 1
    114 	} else if c < 0xE0 || z.Peek(pos+2) == 0 {
    115 		return rune(c&0x1F)<<6 | rune(z.Peek(pos+1)&0x3F), 2
    116 	} else if c < 0xF0 || z.Peek(pos+3) == 0 {
    117 		return rune(c&0x0F)<<12 | rune(z.Peek(pos+1)&0x3F)<<6 | rune(z.Peek(pos+2)&0x3F), 3
    118 	}
    119 	return rune(c&0x07)<<18 | rune(z.Peek(pos+1)&0x3F)<<12 | rune(z.Peek(pos+2)&0x3F)<<6 | rune(z.Peek(pos+3)&0x3F), 4
    120 }
    121 
    122 // Move advances the position.
    123 func (z *Input) Move(n int) {
    124 	z.pos += n
    125 }
    126 
    127 // Pos returns a mark to which can be rewinded.
    128 func (z *Input) Pos() int {
    129 	return z.pos - z.start
    130 }
    131 
    132 // Rewind rewinds the position to the given position.
    133 func (z *Input) Rewind(pos int) {
    134 	z.pos = z.start + pos
    135 }
    136 
    137 // Lexeme returns the bytes of the current selection.
    138 func (z *Input) Lexeme() []byte {
    139 	return z.buf[z.start:z.pos:z.pos]
    140 }
    141 
    142 // Skip collapses the position to the end of the selection.
    143 func (z *Input) Skip() {
    144 	z.start = z.pos
    145 }
    146 
    147 // Shift returns the bytes of the current selection and collapses the position to the end of the selection.
    148 func (z *Input) Shift() []byte {
    149 	b := z.buf[z.start:z.pos:z.pos]
    150 	z.start = z.pos
    151 	return b
    152 }
    153 
    154 // Offset returns the character position in the buffez.
    155 func (z *Input) Offset() int {
    156 	return z.pos
    157 }
    158 
    159 // Bytes returns the underlying buffez.
    160 func (z *Input) Bytes() []byte {
    161 	return z.buf[: len(z.buf)-1 : len(z.buf)-1]
    162 }
    163 
    164 // Len returns the length of the underlying buffez.
    165 func (z *Input) Len() int {
    166 	return len(z.buf) - 1
    167 }
    168 
    169 // Reset resets position to the underlying buffez.
    170 func (z *Input) Reset() {
    171 	z.start = 0
    172 	z.pos = 0
    173 }