buffer.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. package util
  2. import (
  3. "bufio"
  4. "bytes"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "math"
  9. "os"
  10. "unsafe"
  11. "github.com/opencost/opencost/core/pkg/util/stringutil"
  12. )
  13. var bytePool *bufferPool = newBufferPool()
  14. // NonPrimitiveTypeError represents an error where the user provided a non-primitive data type for reading/writing
  15. var NonPrimitiveTypeError error = errors.New("Type provided to read/write does not fit inside 8 bytes.")
  16. // Buffer is a utility type which implements a very basic binary protocol for
  17. // writing core go types.
  18. type Buffer struct {
  19. b *bufio.Reader
  20. bw *bytes.Buffer
  21. }
  22. // NewBuffer creates a new Buffer instance using LittleEndian ByteOrder.
  23. func NewBuffer() *Buffer {
  24. var b bytes.Buffer
  25. return &Buffer{
  26. b: nil,
  27. bw: &b,
  28. }
  29. }
  30. // NewBufferFromBytes creates a new Buffer instance using the provided byte slice.
  31. // The new buffer assumes ownership of the byte slice.
  32. func NewBufferFromBytes(b []byte) *Buffer {
  33. return &Buffer{
  34. bw: bytes.NewBuffer(b),
  35. }
  36. }
  37. // NewBufferFrom creates a new Buffer instance using the remaining unread data from the
  38. // provided Buffer instance. The new buffer assumes ownership of the underlying data.
  39. func NewBufferFrom(b *Buffer) *Buffer {
  40. bb := b.Bytes()
  41. return &Buffer{
  42. bw: bytes.NewBuffer(bb),
  43. }
  44. }
  45. // NewBufferFromReader creates a new Buffer instance using the provided io.Reader. This
  46. // buffer is set to read-only.
  47. func NewBufferFromReader(reader io.Reader) *Buffer {
  48. return &Buffer{
  49. b: bufio.NewReader(reader),
  50. bw: nil,
  51. }
  52. }
  53. // WriteBool writes a bool value to the buffer
  54. func (b *Buffer) WriteBool(i bool) {
  55. b.checkRO()
  56. writeBool(b.bw, i)
  57. }
  58. // WriteInt writes an int value to the buffer.
  59. func (b *Buffer) WriteInt(i int) {
  60. b.checkRO()
  61. writeInt(b.bw, i)
  62. }
  63. // WriteInt8 writes an int8 value to the buffer.
  64. func (b *Buffer) WriteInt8(i int8) {
  65. b.checkRO()
  66. writeInt8(b.bw, i)
  67. }
  68. // WriteInt16 writes an int16 value to the buffer.
  69. func (b *Buffer) WriteInt16(i int16) {
  70. b.checkRO()
  71. writeInt16(b.bw, i)
  72. }
  73. // WriteInt32 writes an int32 value to the buffer.
  74. func (b *Buffer) WriteInt32(i int32) {
  75. b.checkRO()
  76. writeInt32(b.bw, i)
  77. }
  78. // WriteInt64 writes an int64 value to the buffer.
  79. func (b *Buffer) WriteInt64(i int64) {
  80. b.checkRO()
  81. writeInt64(b.bw, i)
  82. }
  83. // WriteUInt writes a uint value to the buffer.
  84. func (b *Buffer) WriteUInt(i uint) {
  85. b.checkRO()
  86. writeUint(b.bw, i)
  87. }
  88. // WriteUInt8 writes a uint8 value to the buffer.
  89. func (b *Buffer) WriteUInt8(i uint8) {
  90. b.checkRO()
  91. writeUint8(b.bw, i)
  92. }
  93. // WriteUInt16 writes a uint16 value to the buffer.
  94. func (b *Buffer) WriteUInt16(i uint16) {
  95. b.checkRO()
  96. writeUint16(b.bw, i)
  97. }
  98. // WriteUInt32 writes a uint32 value to the buffer.
  99. func (b *Buffer) WriteUInt32(i uint32) {
  100. b.checkRO()
  101. writeUint32(b.bw, i)
  102. }
  103. // WriteUInt64 writes a uint64 value to the buffer.
  104. func (b *Buffer) WriteUInt64(i uint64) {
  105. b.checkRO()
  106. writeUint64(b.bw, i)
  107. }
  108. // WriteFloat32 writes a float32 value to the buffer.
  109. func (b *Buffer) WriteFloat32(i float32) {
  110. b.checkRO()
  111. writeFloat32(b.bw, i)
  112. }
  113. // WriteFloat64 writes a float64 value to the buffer.
  114. func (b *Buffer) WriteFloat64(i float64) {
  115. b.checkRO()
  116. writeFloat64(b.bw, i)
  117. }
  118. // WriteString writes the string's length as a uint16 followed by the string contents.
  119. func (b *Buffer) WriteString(i string) {
  120. b.checkRO()
  121. s := stringToBytes(i)
  122. // string lengths are limited to uint16 - See ReadString()
  123. if len(s) > math.MaxUint16 {
  124. s = s[:math.MaxUint16]
  125. }
  126. writeUint16(b.bw, uint16(len(s)))
  127. b.bw.Write(s)
  128. }
  129. // WriteBytes writes the contents of the byte slice to the buffer.
  130. func (b *Buffer) WriteBytes(bytes []byte) {
  131. b.checkRO()
  132. b.bw.Write(bytes)
  133. }
  134. // Bytes returns the unread portion of the underlying buffer storage.
  135. func (b *Buffer) Bytes() []byte {
  136. if b.bw != nil {
  137. return b.bw.Bytes()
  138. }
  139. bytes, err := io.ReadAll(b.b)
  140. if err != nil {
  141. fmt.Fprintf(os.Stderr, "failed to read remaining bytes from Buffer: %s\n", err)
  142. }
  143. return bytes
  144. }
  145. func (b *Buffer) Peek(length int) ([]byte, error) {
  146. if b.bw != nil {
  147. return nil, fmt.Errorf("unsupported Peek() operation on read/write buffer.")
  148. }
  149. return b.b.Peek(length)
  150. }
  151. // this should be inlined
  152. func (b *Buffer) checkRO() {
  153. if b.bw == nil {
  154. panic("Buffer is set to read-only")
  155. }
  156. }
  157. // ReadBool reads a bool value from the buffer.
  158. func (b *Buffer) ReadBool() bool {
  159. var i bool
  160. if b.bw != nil {
  161. readBool(b.bw, &i)
  162. return i
  163. }
  164. readBuffBool(b.b, &i)
  165. return i
  166. }
  167. // ReadInt reads an int value from the buffer.
  168. func (b *Buffer) ReadInt() int {
  169. var i int
  170. if b.bw != nil {
  171. readInt(b.bw, &i)
  172. return i
  173. }
  174. readBuffInt(b.b, &i)
  175. return i
  176. }
  177. // ReadInt8 reads an int8 value from the buffer.
  178. func (b *Buffer) ReadInt8() int8 {
  179. var i int8
  180. if b.bw != nil {
  181. readInt8(b.bw, &i)
  182. return i
  183. }
  184. readBuffInt8(b.b, &i)
  185. return i
  186. }
  187. // ReadInt16 reads an int16 value from the buffer.
  188. func (b *Buffer) ReadInt16() int16 {
  189. var i int16
  190. if b.bw != nil {
  191. readInt16(b.bw, &i)
  192. return i
  193. }
  194. readBuffInt16(b.b, &i)
  195. return i
  196. }
  197. // ReadInt32 reads an int32 value from the buffer.
  198. func (b *Buffer) ReadInt32() int32 {
  199. var i int32
  200. if b.bw != nil {
  201. readInt32(b.bw, &i)
  202. return i
  203. }
  204. readBuffInt32(b.b, &i)
  205. return i
  206. }
  207. // ReadInt64 reads an int64 value from the buffer.
  208. func (b *Buffer) ReadInt64() int64 {
  209. var i int64
  210. if b.bw != nil {
  211. readInt64(b.bw, &i)
  212. return i
  213. }
  214. readBuffInt64(b.b, &i)
  215. return i
  216. }
  217. // ReadUInt reads a uint value from the buffer.
  218. func (b *Buffer) ReadUInt() uint {
  219. var i uint
  220. if b.bw != nil {
  221. readUint(b.bw, &i)
  222. return i
  223. }
  224. readBuffUint(b.b, &i)
  225. return i
  226. }
  227. // ReadUInt8 reads a uint8 value from the buffer.
  228. func (b *Buffer) ReadUInt8() uint8 {
  229. var i uint8
  230. if b.bw != nil {
  231. readUint8(b.bw, &i)
  232. return i
  233. }
  234. readBuffUint8(b.b, &i)
  235. return i
  236. }
  237. // ReadUInt16 reads a uint16 value from the buffer.
  238. func (b *Buffer) ReadUInt16() uint16 {
  239. var i uint16
  240. if b.bw != nil {
  241. readUint16(b.bw, &i)
  242. return i
  243. }
  244. readBuffUint16(b.b, &i)
  245. return i
  246. }
  247. // ReadUInt32 reads a uint32 value from the buffer.
  248. func (b *Buffer) ReadUInt32() uint32 {
  249. var i uint32
  250. if b.bw != nil {
  251. readUint32(b.bw, &i)
  252. return i
  253. }
  254. readBuffUint32(b.b, &i)
  255. return i
  256. }
  257. // ReadUInt64 reads a uint64 value from the buffer.
  258. func (b *Buffer) ReadUInt64() uint64 {
  259. var i uint64
  260. if b.bw != nil {
  261. readUint64(b.bw, &i)
  262. return i
  263. }
  264. readBuffUint64(b.b, &i)
  265. return i
  266. }
  267. // ReadFloat32 reads a float32 value from the buffer.
  268. func (b *Buffer) ReadFloat32() float32 {
  269. var i float32
  270. if b.bw != nil {
  271. readFloat32(b.bw, &i)
  272. return i
  273. }
  274. readBuffFloat32(b.b, &i)
  275. return i
  276. }
  277. // ReadFloat64 reads a float64 value from the buffer.
  278. func (b *Buffer) ReadFloat64() float64 {
  279. var i float64
  280. if b.bw != nil {
  281. readFloat64(b.bw, &i)
  282. return i
  283. }
  284. readBuffFloat64(b.b, &i)
  285. return i
  286. }
  287. // ReadString reads a uint16 value from the buffer representing the string's length,
  288. // then uses the length to extract the exact length []byte representing the string.
  289. func (b *Buffer) ReadString() string {
  290. var l uint16
  291. if b.bw != nil {
  292. readUint16(b.bw, &l)
  293. return bytesToString(b.bw.Next(int(l)))
  294. }
  295. readBuffUint16(b.b, &l)
  296. bytes := bytePool.Get(int(l))
  297. defer bytePool.Put(bytes)
  298. _, err := readBuffFull(b.b, bytes)
  299. if err != nil {
  300. return ""
  301. }
  302. return bytesToString(bytes)
  303. }
  304. // ReadStringBytes reads a uint16 length prefix and that many bytes as a new slice.
  305. // Unlike ReadString, this does not route through the global string bank.
  306. func (b *Buffer) ReadStringBytes() ([]byte, error) {
  307. var l uint16
  308. if b.bw != nil {
  309. if err := readUint16(b.bw, &l); err != nil {
  310. return nil, err
  311. }
  312. if l == 0 {
  313. return []byte{}, nil
  314. }
  315. out := make([]byte, int(l))
  316. if _, err := readFull(b.bw, out); err != nil {
  317. return nil, err
  318. }
  319. return out, nil
  320. }
  321. if b.b == nil {
  322. return nil, fmt.Errorf("buffer: ReadStringBytes on invalid buffer")
  323. }
  324. if err := readBuffUint16(b.b, &l); err != nil {
  325. return nil, err
  326. }
  327. if l == 0 {
  328. return []byte{}, nil
  329. }
  330. out := make([]byte, int(l))
  331. if _, err := readBuffFull(b.b, out); err != nil {
  332. return nil, err
  333. }
  334. return out, nil
  335. }
  336. // ReadBytes reads the specified length from the buffer and returns the byte slice.
  337. func (b *Buffer) ReadBytes(length int) []byte {
  338. if b.bw != nil {
  339. return b.bw.Next(length)
  340. }
  341. bytes := bytePool.Get(length)
  342. defer bytePool.Put(bytes)
  343. _, err := readBuffFull(b.b, bytes)
  344. if err != nil {
  345. return bytes
  346. }
  347. return bytes
  348. }
  349. // Conversion from byte slice to string
  350. func bytesToString(b []byte) string {
  351. // This code will take the passed byte slice and cast it in-place into a string. By doing
  352. // this, we are pinning the byte slice's underlying array in memory, preventing it from
  353. // being garbage collected while the string is still in use. If we are using the Bank()
  354. // functionality to cache new strings, we risk keeping the pinned array alive. To avoid this,
  355. // we will use the BankFunc() call which uses the casted string to check for existence of a
  356. // cached string. If it exists, then we drop the pinned reference immediately and use the
  357. // cached string. If it does _not_ exist, then we use the passed func() string to allocate a new
  358. // string and cache it. This will prevent us from allocating throw-away strings just to
  359. // check our cache.
  360. pinned := unsafe.String(unsafe.SliceData(b), len(b))
  361. return stringutil.BankFunc(pinned, func() string {
  362. return string(b)
  363. })
  364. }
  365. // Direct string to byte conversion that doesn't allocate.
  366. func stringToBytes(s string) []byte {
  367. return unsafe.Slice(unsafe.StringData(s), len(s))
  368. }