buffer.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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. If the buffer was
  135. // created with an `io.Reader`, then the remaining unread bytes are drained into a byte
  136. // slice and returned.
  137. func (b *Buffer) Bytes() []byte {
  138. if b.bw != nil {
  139. return b.bw.Bytes()
  140. }
  141. bytes, err := io.ReadAll(b.b)
  142. if err != nil {
  143. fmt.Fprintf(os.Stderr, "failed to read remaining bytes from Buffer: %s\n", err)
  144. }
  145. return bytes
  146. }
  147. func (b *Buffer) Peek(length int) ([]byte, error) {
  148. if b.bw != nil {
  149. return nil, fmt.Errorf("unsupported Peek() operation on read/write buffer.")
  150. }
  151. return b.b.Peek(length)
  152. }
  153. // this should be inlined
  154. func (b *Buffer) checkRO() {
  155. if b.bw == nil {
  156. panic("Buffer is set to read-only")
  157. }
  158. }
  159. // ReadBool reads a bool value from the buffer.
  160. func (b *Buffer) ReadBool() bool {
  161. var i bool
  162. if b.bw != nil {
  163. readBool(b.bw, &i)
  164. return i
  165. }
  166. readBuffBool(b.b, &i)
  167. return i
  168. }
  169. // ReadInt reads an int value from the buffer.
  170. func (b *Buffer) ReadInt() int {
  171. var i int
  172. if b.bw != nil {
  173. readInt(b.bw, &i)
  174. return i
  175. }
  176. readBuffInt(b.b, &i)
  177. return i
  178. }
  179. // ReadInt8 reads an int8 value from the buffer.
  180. func (b *Buffer) ReadInt8() int8 {
  181. var i int8
  182. if b.bw != nil {
  183. readInt8(b.bw, &i)
  184. return i
  185. }
  186. readBuffInt8(b.b, &i)
  187. return i
  188. }
  189. // ReadInt16 reads an int16 value from the buffer.
  190. func (b *Buffer) ReadInt16() int16 {
  191. var i int16
  192. if b.bw != nil {
  193. readInt16(b.bw, &i)
  194. return i
  195. }
  196. readBuffInt16(b.b, &i)
  197. return i
  198. }
  199. // ReadInt32 reads an int32 value from the buffer.
  200. func (b *Buffer) ReadInt32() int32 {
  201. var i int32
  202. if b.bw != nil {
  203. readInt32(b.bw, &i)
  204. return i
  205. }
  206. readBuffInt32(b.b, &i)
  207. return i
  208. }
  209. // ReadInt64 reads an int64 value from the buffer.
  210. func (b *Buffer) ReadInt64() int64 {
  211. var i int64
  212. if b.bw != nil {
  213. readInt64(b.bw, &i)
  214. return i
  215. }
  216. readBuffInt64(b.b, &i)
  217. return i
  218. }
  219. // ReadUInt reads a uint value from the buffer.
  220. func (b *Buffer) ReadUInt() uint {
  221. var i uint
  222. if b.bw != nil {
  223. readUint(b.bw, &i)
  224. return i
  225. }
  226. readBuffUint(b.b, &i)
  227. return i
  228. }
  229. // ReadUInt8 reads a uint8 value from the buffer.
  230. func (b *Buffer) ReadUInt8() uint8 {
  231. var i uint8
  232. if b.bw != nil {
  233. readUint8(b.bw, &i)
  234. return i
  235. }
  236. readBuffUint8(b.b, &i)
  237. return i
  238. }
  239. // ReadUInt16 reads a uint16 value from the buffer.
  240. func (b *Buffer) ReadUInt16() uint16 {
  241. var i uint16
  242. if b.bw != nil {
  243. readUint16(b.bw, &i)
  244. return i
  245. }
  246. readBuffUint16(b.b, &i)
  247. return i
  248. }
  249. // ReadUInt32 reads a uint32 value from the buffer.
  250. func (b *Buffer) ReadUInt32() uint32 {
  251. var i uint32
  252. if b.bw != nil {
  253. readUint32(b.bw, &i)
  254. return i
  255. }
  256. readBuffUint32(b.b, &i)
  257. return i
  258. }
  259. // ReadUInt64 reads a uint64 value from the buffer.
  260. func (b *Buffer) ReadUInt64() uint64 {
  261. var i uint64
  262. if b.bw != nil {
  263. readUint64(b.bw, &i)
  264. return i
  265. }
  266. readBuffUint64(b.b, &i)
  267. return i
  268. }
  269. // ReadFloat32 reads a float32 value from the buffer.
  270. func (b *Buffer) ReadFloat32() float32 {
  271. var i float32
  272. if b.bw != nil {
  273. readFloat32(b.bw, &i)
  274. return i
  275. }
  276. readBuffFloat32(b.b, &i)
  277. return i
  278. }
  279. // ReadFloat64 reads a float64 value from the buffer.
  280. func (b *Buffer) ReadFloat64() float64 {
  281. var i float64
  282. if b.bw != nil {
  283. readFloat64(b.bw, &i)
  284. return i
  285. }
  286. readBuffFloat64(b.b, &i)
  287. return i
  288. }
  289. // ReadString reads a uint16 value from the buffer representing the string's length,
  290. // then uses the length to extract the exact length []byte representing the string.
  291. func (b *Buffer) ReadString() string {
  292. var l uint16
  293. if b.bw != nil {
  294. readUint16(b.bw, &l)
  295. return bytesToString(b.bw.Next(int(l)))
  296. }
  297. readBuffUint16(b.b, &l)
  298. bytes := bytePool.Get(int(l))
  299. defer bytePool.Put(bytes)
  300. _, err := readBuffFull(b.b, bytes)
  301. if err != nil {
  302. return ""
  303. }
  304. return bytesToString(bytes)
  305. }
  306. // ReadBytes reads the specified length from the buffer and returns the byte slice.
  307. func (b *Buffer) ReadBytes(length int) []byte {
  308. if b.bw != nil {
  309. return b.bw.Next(length)
  310. }
  311. bytes := make([]byte, length)
  312. _, err := readBuffFull(b.b, bytes)
  313. if err != nil {
  314. return bytes
  315. }
  316. return bytes
  317. }
  318. // bytesAsString converts a []byte into a string in place. Note that you should use this helper
  319. // when the []byte slice contains _only_ the string data and isn't part of a larger underlying array.
  320. // For example, a case where you should *not* use this helper:
  321. //
  322. // func parseString(buffer *bytes.Buffer, length int) string {
  323. // bytes := buffer.Next(length) // this extracts a sub-slice of the underlying byte array from pos->pos+length
  324. //
  325. // return bytesAsString(bytes)
  326. // }
  327. //
  328. // Now both the []byte AND the value string are linked and neither can be GC'd until the other one is GC'd.
  329. // This is especially problematic if you drop the references to the byte array, as you're effectively requiring
  330. // 1024 bytes for an 11-byte string.
  331. //
  332. // An example where it _is_ ok, and recommended to drop the underlying []byte reference is the following:
  333. //
  334. // func parseString(reader io.Reader, length int) string {
  335. // bytes := make([]byte, length)
  336. // io.ReadFull(reader, bytes)
  337. //
  338. // return bytesAsString(bytes)
  339. // }
  340. //
  341. // In this case, we've create a byte array just big enough for the string, we extract the string data from the reader
  342. // and then cast the byte array in place to the string, and finally drop the byte array reference. This omits an additional
  343. // allocation if you were to use string(bytes)
  344. func bytesAsString(b []byte) string {
  345. return unsafe.String(unsafe.SliceData(b), len(b))
  346. }
  347. // Conversion from byte slice to string
  348. func bytesToString(b []byte) string {
  349. // This code will take the passed byte slice and cast it in-place into a string. By doing
  350. // this, we are pinning the byte slice's underlying array in memory, preventing it from
  351. // being garbage collected while the string is still in use. If we are using the Bank()
  352. // functionality to cache new strings, we risk keeping the pinned array alive. To avoid this,
  353. // we will use the BankFunc() call which uses the casted string to check for existence of a
  354. // cached string. If it exists, then we drop the pinned reference immediately and use the
  355. // cached string. If it does _not_ exist, then we use the passed func() string to allocate a new
  356. // string and cache it. This will prevent us from allocating throw-away strings just to
  357. // check our cache.
  358. pinned := bytesAsString(b)
  359. return stringutil.BankFunc(pinned, func() string {
  360. return string(b)
  361. })
  362. }
  363. // Direct string to byte conversion that doesn't allocate.
  364. func stringToBytes(s string) []byte {
  365. return unsafe.Slice(unsafe.StringData(s), len(s))
  366. }