buffer.go 9.4 KB

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