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 }