buffer.go 9.5 KB

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