buffer.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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. // Mode is used to represent the 3 possible states of the buffer. note there is
  17. // no overlapping between states, as each Mode is handled exclusively.
  18. type Mode uint8
  19. const (
  20. ReadWrite Mode = iota
  21. ReadOnly
  22. WriteOnly
  23. )
  24. // Buffer is a utility type which implements a very basic binary protocol for
  25. // writing core go types. It can run as read-only, write-only, or read-write.
  26. type Buffer struct {
  27. r *bufio.Reader
  28. w *bufio.Writer
  29. rw *bytes.Buffer
  30. m Mode
  31. }
  32. // NewBuffer creates a new Buffer instance using LittleEndian ByteOrder.
  33. func NewBuffer() *Buffer {
  34. return &Buffer{
  35. r: nil,
  36. w: nil,
  37. rw: new(bytes.Buffer),
  38. m: ReadWrite,
  39. }
  40. }
  41. // NewBufferFromBytes creates a new read/write Buffer instance using the provided byte slice.
  42. // The new buffer assumes ownership of the byte slice.
  43. func NewBufferFromBytes(b []byte) *Buffer {
  44. return &Buffer{
  45. r: nil,
  46. w: nil,
  47. rw: bytes.NewBuffer(b),
  48. m: ReadWrite,
  49. }
  50. }
  51. // NewBufferFrom creates a new Buffer instance using the remaining unread data from the
  52. // provided Buffer instance. The new buffer assumes ownership of the underlying data.
  53. func NewBufferFrom(b *Buffer) *Buffer {
  54. bb := b.Bytes()
  55. return &Buffer{
  56. r: nil,
  57. w: nil,
  58. rw: bytes.NewBuffer(bb),
  59. m: ReadWrite,
  60. }
  61. }
  62. // NewBufferFromReader creates a new Buffer instance using the provided io.Reader. This
  63. // buffer is set to read-only.
  64. func NewBufferFromReader(reader io.Reader) *Buffer {
  65. return &Buffer{
  66. r: bufio.NewReader(reader),
  67. w: nil,
  68. rw: nil,
  69. m: ReadOnly,
  70. }
  71. }
  72. // NewBufferFromWriter creates a new Buffer instance using the provided io.Writer. This
  73. // buffer is set to write-only.
  74. func NewBufferFromWriter(writer io.Writer) *Buffer {
  75. return &Buffer{
  76. r: nil,
  77. w: bufio.NewWriter(writer),
  78. rw: nil,
  79. m: WriteOnly,
  80. }
  81. }
  82. // WriteBool writes a bool value to the buffer
  83. func (b *Buffer) WriteBool(i bool) {
  84. b.checkRO()
  85. if b.rw != nil {
  86. writeBool(b.rw, i)
  87. return
  88. }
  89. writeBuffBool(b.w, i)
  90. }
  91. // WriteInt writes an int value to the buffer.
  92. func (b *Buffer) WriteInt(i int) {
  93. b.checkRO()
  94. if b.rw != nil {
  95. writeInt(b.rw, i)
  96. return
  97. }
  98. writeBuffInt(b.w, i)
  99. }
  100. // WriteInt8 writes an int8 value to the buffer.
  101. func (b *Buffer) WriteInt8(i int8) {
  102. b.checkRO()
  103. if b.rw != nil {
  104. writeInt8(b.rw, i)
  105. return
  106. }
  107. writeBuffInt8(b.w, i)
  108. }
  109. // WriteInt16 writes an int16 value to the buffer.
  110. func (b *Buffer) WriteInt16(i int16) {
  111. b.checkRO()
  112. if b.rw != nil {
  113. writeInt16(b.rw, i)
  114. return
  115. }
  116. writeBuffInt16(b.w, i)
  117. }
  118. // WriteInt32 writes an int32 value to the buffer.
  119. func (b *Buffer) WriteInt32(i int32) {
  120. b.checkRO()
  121. if b.rw != nil {
  122. writeInt32(b.rw, i)
  123. return
  124. }
  125. writeBuffInt32(b.w, i)
  126. }
  127. // WriteInt64 writes an int64 value to the buffer.
  128. func (b *Buffer) WriteInt64(i int64) {
  129. b.checkRO()
  130. if b.rw != nil {
  131. writeInt64(b.rw, i)
  132. return
  133. }
  134. writeBuffInt64(b.w, i)
  135. }
  136. // WriteUInt writes a uint value to the buffer.
  137. func (b *Buffer) WriteUInt(i uint) {
  138. b.checkRO()
  139. if b.rw != nil {
  140. writeUint(b.rw, i)
  141. return
  142. }
  143. writeBuffUint(b.w, i)
  144. }
  145. // WriteUInt8 writes a uint8 value to the buffer.
  146. func (b *Buffer) WriteUInt8(i uint8) {
  147. b.checkRO()
  148. if b.rw != nil {
  149. writeUint8(b.rw, i)
  150. return
  151. }
  152. writeBuffUint8(b.w, i)
  153. }
  154. // WriteUInt16 writes a uint16 value to the buffer.
  155. func (b *Buffer) WriteUInt16(i uint16) {
  156. b.checkRO()
  157. if b.rw != nil {
  158. writeUint16(b.rw, i)
  159. return
  160. }
  161. writeBuffUint16(b.w, i)
  162. }
  163. // WriteUInt32 writes a uint32 value to the buffer.
  164. func (b *Buffer) WriteUInt32(i uint32) {
  165. b.checkRO()
  166. if b.rw != nil {
  167. writeUint32(b.rw, i)
  168. return
  169. }
  170. writeBuffUint32(b.w, i)
  171. }
  172. // WriteUInt64 writes a uint64 value to the buffer.
  173. func (b *Buffer) WriteUInt64(i uint64) {
  174. b.checkRO()
  175. if b.rw != nil {
  176. writeUint64(b.rw, i)
  177. return
  178. }
  179. writeBuffUint64(b.w, i)
  180. }
  181. // WriteFloat32 writes a float32 value to the buffer.
  182. func (b *Buffer) WriteFloat32(i float32) {
  183. b.checkRO()
  184. if b.rw != nil {
  185. writeFloat32(b.rw, i)
  186. return
  187. }
  188. writeBuffFloat32(b.w, i)
  189. }
  190. // WriteFloat64 writes a float64 value to the buffer.
  191. func (b *Buffer) WriteFloat64(i float64) {
  192. b.checkRO()
  193. if b.rw != nil {
  194. writeFloat64(b.rw, i)
  195. return
  196. }
  197. writeBuffFloat64(b.w, i)
  198. }
  199. // WriteString writes the string's length as a uint16 followed by the string contents.
  200. func (b *Buffer) WriteString(i string) {
  201. b.checkRO()
  202. s := stringToBytes(i)
  203. // string lengths are limited to uint16 - See ReadString()
  204. if len(s) > math.MaxUint16 {
  205. s = s[:math.MaxUint16]
  206. }
  207. l := uint16(len(s))
  208. if b.rw != nil {
  209. writeUint16(b.rw, l)
  210. b.rw.Write(s)
  211. return
  212. }
  213. writeBuffUint16(b.w, l)
  214. b.w.Write(s)
  215. }
  216. // WriteBytes writes the contents of the byte slice to the buffer.
  217. func (b *Buffer) WriteBytes(bytes []byte) {
  218. b.checkRO()
  219. if b.rw != nil {
  220. b.rw.Write(bytes)
  221. return
  222. }
  223. b.w.Write(bytes)
  224. }
  225. // Bytes returns the unread portion of the underlying buffer storage. If the buffer was
  226. // created with an `io.Reader`, then the remaining unread bytes are drained into a byte
  227. // slice and returned.
  228. func (b *Buffer) Bytes() []byte {
  229. b.checkWO()
  230. if b.rw != nil {
  231. return b.rw.Bytes()
  232. }
  233. bytes, err := io.ReadAll(b.r)
  234. if err != nil {
  235. fmt.Fprintf(os.Stderr, "failed to read remaining bytes from Buffer: %s\n", err)
  236. }
  237. return bytes
  238. }
  239. // Peek will attempt to peek ahead if the buffer is in read-only mode.
  240. func (b *Buffer) Peek(length int) ([]byte, error) {
  241. b.checkWO()
  242. if b.rw != nil {
  243. return nil, fmt.Errorf("unsupported Peek() operation on read/write buffer.")
  244. }
  245. return b.r.Peek(length)
  246. }
  247. // Flush will attempt to flush any pending writes if the buffer is in write-only mode.
  248. func (b *Buffer) Flush() {
  249. if b.IsWriteOnly() {
  250. if err := b.w.Flush(); err != nil {
  251. fmt.Fprintf(os.Stderr, "Flushing io.Writer failed: %s\n", err)
  252. }
  253. }
  254. }
  255. // this should be inlined
  256. func (b *Buffer) checkRO() {
  257. if b.IsReadOnly() {
  258. panic("Tried to write to a Buffer that is set to read-only")
  259. }
  260. }
  261. func (b *Buffer) checkWO() {
  262. if b.IsWriteOnly() {
  263. panic("Tried to read from a Buffer that is set to write-only")
  264. }
  265. }
  266. // IsReadOnly returns true if the buffer is set to only read mode.
  267. func (b *Buffer) IsReadOnly() bool {
  268. return b.m == ReadOnly
  269. }
  270. // IsWriteOnly returns true if the buffer is set to only write mode.
  271. func (b *Buffer) IsWriteOnly() bool {
  272. return b.m == WriteOnly
  273. }
  274. // IsReadWrite returns true if the buffer can be written to and read from.
  275. func (b *Buffer) IsReadWrite() bool {
  276. return b.m == ReadWrite
  277. }
  278. // ReadBool reads a bool value from the buffer.
  279. func (b *Buffer) ReadBool() bool {
  280. b.checkWO()
  281. var i bool
  282. if b.rw != nil {
  283. readBool(b.rw, &i)
  284. return i
  285. }
  286. readBuffBool(b.r, &i)
  287. return i
  288. }
  289. // ReadInt reads an int value from the buffer.
  290. func (b *Buffer) ReadInt() int {
  291. b.checkWO()
  292. var i int
  293. if b.rw != nil {
  294. readInt(b.rw, &i)
  295. return i
  296. }
  297. readBuffInt(b.r, &i)
  298. return i
  299. }
  300. // ReadInt8 reads an int8 value from the buffer.
  301. func (b *Buffer) ReadInt8() int8 {
  302. b.checkWO()
  303. var i int8
  304. if b.rw != nil {
  305. readInt8(b.rw, &i)
  306. return i
  307. }
  308. readBuffInt8(b.r, &i)
  309. return i
  310. }
  311. // ReadInt16 reads an int16 value from the buffer.
  312. func (b *Buffer) ReadInt16() int16 {
  313. b.checkWO()
  314. var i int16
  315. if b.rw != nil {
  316. readInt16(b.rw, &i)
  317. return i
  318. }
  319. readBuffInt16(b.r, &i)
  320. return i
  321. }
  322. // ReadInt32 reads an int32 value from the buffer.
  323. func (b *Buffer) ReadInt32() int32 {
  324. b.checkWO()
  325. var i int32
  326. if b.rw != nil {
  327. readInt32(b.rw, &i)
  328. return i
  329. }
  330. readBuffInt32(b.r, &i)
  331. return i
  332. }
  333. // ReadInt64 reads an int64 value from the buffer.
  334. func (b *Buffer) ReadInt64() int64 {
  335. b.checkWO()
  336. var i int64
  337. if b.rw != nil {
  338. readInt64(b.rw, &i)
  339. return i
  340. }
  341. readBuffInt64(b.r, &i)
  342. return i
  343. }
  344. // ReadUInt reads a uint value from the buffer.
  345. func (b *Buffer) ReadUInt() uint {
  346. b.checkWO()
  347. var i uint
  348. if b.rw != nil {
  349. readUint(b.rw, &i)
  350. return i
  351. }
  352. readBuffUint(b.r, &i)
  353. return i
  354. }
  355. // ReadUInt8 reads a uint8 value from the buffer.
  356. func (b *Buffer) ReadUInt8() uint8 {
  357. b.checkWO()
  358. var i uint8
  359. if b.rw != nil {
  360. readUint8(b.rw, &i)
  361. return i
  362. }
  363. readBuffUint8(b.r, &i)
  364. return i
  365. }
  366. // ReadUInt16 reads a uint16 value from the buffer.
  367. func (b *Buffer) ReadUInt16() uint16 {
  368. b.checkWO()
  369. var i uint16
  370. if b.rw != nil {
  371. readUint16(b.rw, &i)
  372. return i
  373. }
  374. readBuffUint16(b.r, &i)
  375. return i
  376. }
  377. // ReadUInt32 reads a uint32 value from the buffer.
  378. func (b *Buffer) ReadUInt32() uint32 {
  379. b.checkWO()
  380. var i uint32
  381. if b.rw != nil {
  382. readUint32(b.rw, &i)
  383. return i
  384. }
  385. readBuffUint32(b.r, &i)
  386. return i
  387. }
  388. // ReadUInt64 reads a uint64 value from the buffer.
  389. func (b *Buffer) ReadUInt64() uint64 {
  390. b.checkWO()
  391. var i uint64
  392. if b.rw != nil {
  393. readUint64(b.rw, &i)
  394. return i
  395. }
  396. readBuffUint64(b.r, &i)
  397. return i
  398. }
  399. // ReadFloat32 reads a float32 value from the buffer.
  400. func (b *Buffer) ReadFloat32() float32 {
  401. b.checkWO()
  402. var i float32
  403. if b.rw != nil {
  404. readFloat32(b.rw, &i)
  405. return i
  406. }
  407. readBuffFloat32(b.r, &i)
  408. return i
  409. }
  410. // ReadFloat64 reads a float64 value from the buffer.
  411. func (b *Buffer) ReadFloat64() float64 {
  412. b.checkWO()
  413. var i float64
  414. if b.rw != nil {
  415. readFloat64(b.rw, &i)
  416. return i
  417. }
  418. readBuffFloat64(b.r, &i)
  419. return i
  420. }
  421. // ReadString reads a uint16 value from the buffer representing the string's length,
  422. // then uses the length to extract the exact length []byte representing the string.
  423. func (b *Buffer) ReadString() string {
  424. b.checkWO()
  425. var l uint16
  426. if b.rw != nil {
  427. readUint16(b.rw, &l)
  428. return bytesToString(b.rw.Next(int(l)))
  429. }
  430. readBuffUint16(b.r, &l)
  431. bytes := bytePool.Get(int(l))
  432. defer bytePool.Put(bytes)
  433. _, err := readBuffFull(b.r, bytes)
  434. if err != nil {
  435. return ""
  436. }
  437. return bytesToString(bytes)
  438. }
  439. // ReadBytes reads the specified length from the buffer and returns the byte slice.
  440. func (b *Buffer) ReadBytes(length int) []byte {
  441. b.checkWO()
  442. if b.rw != nil {
  443. return b.rw.Next(length)
  444. }
  445. bytes := make([]byte, length)
  446. _, err := readBuffFull(b.r, bytes)
  447. if err != nil {
  448. return bytes
  449. }
  450. return bytes
  451. }
  452. // bytesAsString converts a []byte into a string in place. Note that you should use this helper
  453. // when the []byte slice contains _only_ the string data and isn't part of a larger underlying array.
  454. // For example, a case where you should *not* use this helper:
  455. //
  456. // func parseString(buffer *bytes.Buffer, length int) string {
  457. // bytes := buffer.Next(length) // this extracts a sub-slice of the underlying byte array from pos->pos+length
  458. //
  459. // return bytesAsString(bytes)
  460. // }
  461. //
  462. // Now both the []byte AND the value string are linked and neither can be GC'd until the other one is GC'd.
  463. // This is especially problematic if you drop the references to the byte array, as you're effectively requiring
  464. // 1024 bytes for an 11-byte string.
  465. //
  466. // An example where it _is_ ok, and recommended to drop the underlying []byte reference is the following:
  467. //
  468. // func parseString(reader io.Reader, length int) string {
  469. // bytes := make([]byte, length)
  470. // io.ReadFull(reader, bytes)
  471. //
  472. // return bytesAsString(bytes)
  473. // }
  474. //
  475. // In this case, we've created a byte array just big enough for the string, we extract the string data from the reader
  476. // and then cast the byte array in place to the string, and finally drop the byte array reference. This omits an additional
  477. // allocation if you were to use string(bytes)
  478. func bytesAsString(b []byte) string {
  479. return unsafe.String(unsafe.SliceData(b), len(b))
  480. }
  481. // Conversion from byte slice to string
  482. func bytesToString(b []byte) string {
  483. // This code will take the passed byte slice and cast it in-place into a string. By doing
  484. // this, we are pinning the byte slice's underlying array in memory, preventing it from
  485. // being garbage collected while the string is still in use. If we are using the Bank()
  486. // functionality to cache new strings, we risk keeping the pinned array alive. To avoid this,
  487. // we will use the BankFunc() call which uses the casted string to check for existence of a
  488. // cached string. If it exists, then we drop the pinned reference immediately and use the
  489. // cached string. If it does _not_ exist, then we use the passed func() string to allocate a new
  490. // string and cache it. This will prevent us from allocating throw-away strings just to
  491. // check our cache.
  492. pinned := bytesAsString(b)
  493. return stringutil.BankFunc(pinned, func() string {
  494. return string(b)
  495. })
  496. }
  497. // Direct string to byte conversion that doesn't allocate.
  498. func stringToBytes(s string) []byte {
  499. return unsafe.Slice(unsafe.StringData(s), len(s))
  500. }