github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/common/sink/zero_copy_sink.go (about)

     1  /*
     2   * Copyright (C) 2018 The ontology Authors
     3   * This file is part of The ontology library.
     4   *
     5   * The ontology is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU Lesser General Public License as published by
     7   * the Free Software Foundation, either version 3 of the License, or
     8   * (at your option) any later version.
     9   *
    10   * The ontology is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU Lesser General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU Lesser General Public License
    16   * along with The ontology.  If not, see <http://www.gnu.org/licenses/>.
    17   */
    18  package sink
    19  
    20  import (
    21  	"bytes"
    22  	"encoding/binary"
    23  	"errors"
    24  
    25  	"github.com/sixexorg/magnetic-ring/common"
    26  )
    27  
    28  type ZeroCopySink struct {
    29  	buf []byte
    30  }
    31  
    32  // tryGrowByReslice is a inlineable version of grow for the fast-case where the
    33  // internal buffer only needs to be resliced.
    34  // It returns the index where bytes should be written and whether it succeeded.
    35  func (self *ZeroCopySink) tryGrowByReslice(n int) (int, bool) {
    36  	if l := len(self.buf); n <= cap(self.buf)-l {
    37  		self.buf = self.buf[:l+n]
    38  		return l, true
    39  	}
    40  	return 0, false
    41  }
    42  
    43  const maxInt = int(^uint(0) >> 1)
    44  
    45  // grow grows the buffer to guarantee space for n more bytes.
    46  // It returns the index where bytes should be written.
    47  // If the buffer can't grow it will panic with ErrTooLarge.
    48  func (self *ZeroCopySink) grow(n int) int {
    49  	// Try to grow by means of a reslice.
    50  	if i, ok := self.tryGrowByReslice(n); ok {
    51  		return i
    52  	}
    53  
    54  	l := len(self.buf)
    55  	c := cap(self.buf)
    56  	if c > maxInt-c-n {
    57  		panic(ErrTooLarge)
    58  	}
    59  	// Not enough space anywhere, we need to allocate.
    60  	buf := makeSlice(2*c + n)
    61  	copy(buf, self.buf)
    62  	self.buf = buf[:l+n]
    63  	return l
    64  }
    65  
    66  func (self *ZeroCopySink) WriteBytes(p []byte) {
    67  	data := self.NextBytes(uint64(len(p)))
    68  	copy(data, p)
    69  }
    70  
    71  func (self *ZeroCopySink) Size() uint64 { return uint64(len(self.buf)) }
    72  
    73  func (self *ZeroCopySink) NextBytes(n uint64) (data []byte) {
    74  	m, ok := self.tryGrowByReslice(int(n))
    75  	if !ok {
    76  		m = self.grow(int(n))
    77  	}
    78  	data = self.buf[m:]
    79  	return
    80  }
    81  
    82  // Backs up a number of bytes, so that the next call to NextXXX() returns data again
    83  // that was already returned by the last call to NextXXX().
    84  func (self *ZeroCopySink) BackUp(n uint64) {
    85  	l := len(self.buf) - int(n)
    86  	self.buf = self.buf[:l]
    87  }
    88  
    89  func (self *ZeroCopySink) WriteUint8(data uint8) {
    90  	buf := self.NextBytes(1)
    91  	buf[0] = data
    92  }
    93  
    94  func (self *ZeroCopySink) WriteByte(c byte) {
    95  	self.WriteUint8(c)
    96  }
    97  
    98  func (self *ZeroCopySink) WriteBool(data bool) {
    99  	if data {
   100  		self.WriteByte(1)
   101  	} else {
   102  		self.WriteByte(0)
   103  	}
   104  }
   105  
   106  func (self *ZeroCopySink) WriteUint16(data uint16) {
   107  	buf := self.NextBytes(2)
   108  	binary.LittleEndian.PutUint16(buf, data)
   109  }
   110  
   111  func (self *ZeroCopySink) WriteUint32(data uint32) {
   112  	buf := self.NextBytes(4)
   113  	binary.LittleEndian.PutUint32(buf, data)
   114  }
   115  
   116  func (self *ZeroCopySink) WriteUint64(data uint64) {
   117  	buf := self.NextBytes(8)
   118  	binary.LittleEndian.PutUint64(buf, data)
   119  }
   120  
   121  func (self *ZeroCopySink) WriteInt64(data int64) {
   122  	self.WriteUint64(uint64(data))
   123  }
   124  
   125  func (self *ZeroCopySink) WriteInt32(data int32) {
   126  	self.WriteUint32(uint32(data))
   127  }
   128  
   129  func (self *ZeroCopySink) WriteInt16(data int16) {
   130  	self.WriteUint16(uint16(data))
   131  }
   132  
   133  func (self *ZeroCopySink) WriteVarBytes(data []byte) (size uint64) {
   134  	l := uint64(len(data))
   135  	size = self.WriteVarUint(l) + l
   136  
   137  	self.WriteBytes(data)
   138  	return
   139  }
   140  
   141  func (self *ZeroCopySink) WriteString(data string) (size uint64) {
   142  	return self.WriteVarBytes([]byte(data))
   143  }
   144  
   145  func (self *ZeroCopySink) WriteAddress(addr common.Address) {
   146  	self.WriteBytes(addr[:])
   147  }
   148  func (self *ZeroCopySink) WriteSymbol(symbol common.Symbol) {
   149  	self.WriteBytes(symbol[:])
   150  }
   151  
   152  func (self *ZeroCopySink) WriteHash(hash common.Hash) {
   153  	self.WriteBytes(hash[:])
   154  }
   155  
   156  func (self *ZeroCopySink) WriteVarUint(data uint64) (size uint64) {
   157  	buf := self.NextBytes(9)
   158  	if data < 0xFD {
   159  		buf[0] = uint8(data)
   160  		size = 1
   161  	} else if data <= 0xFFFF {
   162  		buf[0] = 0xFD
   163  		binary.LittleEndian.PutUint16(buf[1:], uint16(data))
   164  		size = 3
   165  	} else if data <= 0xFFFFFFFF {
   166  		buf[0] = 0xFE
   167  		binary.LittleEndian.PutUint32(buf[1:], uint32(data))
   168  		size = 5
   169  	} else {
   170  		buf[0] = 0xFF
   171  		binary.LittleEndian.PutUint64(buf[1:], uint64(data))
   172  		size = 9
   173  	}
   174  
   175  	self.BackUp(9 - size)
   176  	return
   177  }
   178  
   179  func (self *ZeroCopySink) WriteComplex(data *ComplexType) {
   180  	self.WriteBytes(data.Size[:])
   181  	self.WriteByte(data.MType)
   182  	self.WriteBytes(data.Data)
   183  }
   184  
   185  // NewReader returns a new ZeroCopySink reading from b.
   186  func NewZeroCopySink(b []byte) *ZeroCopySink {
   187  	if b == nil {
   188  		b = make([]byte, 0, 512)
   189  	}
   190  	return &ZeroCopySink{b}
   191  }
   192  
   193  func (self *ZeroCopySink) Bytes() []byte { return self.buf }
   194  
   195  func (self *ZeroCopySink) Reset() { self.buf = self.buf[:0] }
   196  
   197  var ErrTooLarge = errors.New("bytes.Buffer: too large")
   198  
   199  // makeSlice allocates a slice of size n. If the allocation fails, it panics
   200  // with ErrTooLarge.
   201  func makeSlice(n int) []byte {
   202  	// If the make fails, give a known error.
   203  	defer func() {
   204  		if recover() != nil {
   205  			panic(bytes.ErrTooLarge)
   206  		}
   207  	}()
   208  	return make([]byte, n)
   209  }