buffer.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
  2. //
  3. // Copyright 2013 Julien Schmidt. All rights reserved.
  4. // http://www.julienschmidt.com
  5. //
  6. // This Source Code Form is subject to the terms of the Mozilla Public
  7. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  8. // You can obtain one at http://mozilla.org/MPL/2.0/.
  9. package mysql
  10. import "io"
  11. const defaultBufSize = 4096
  12. // A read buffer similar to bufio.Reader but zero-copy-ish
  13. // Also highly optimized for this particular use case.
  14. type buffer struct {
  15. buf []byte
  16. rd io.Reader
  17. idx int
  18. length int
  19. }
  20. func newBuffer(rd io.Reader) *buffer {
  21. return &buffer{
  22. buf: make([]byte, defaultBufSize),
  23. rd: rd,
  24. }
  25. }
  26. // fill reads into the buffer until at least _need_ bytes are in it
  27. func (b *buffer) fill(need int) (err error) {
  28. // move existing data to the beginning
  29. if b.length > 0 && b.idx > 0 {
  30. copy(b.buf[0:b.length], b.buf[b.idx:])
  31. }
  32. // grow buffer if necessary
  33. if need > len(b.buf) {
  34. for {
  35. b.buf = append(b.buf, 0)
  36. b.buf = b.buf[:cap(b.buf)]
  37. if cap(b.buf) >= need {
  38. break
  39. }
  40. }
  41. }
  42. b.idx = 0
  43. var n int
  44. for {
  45. n, err = b.rd.Read(b.buf[b.length:])
  46. b.length += n
  47. if b.length < need && err == nil {
  48. continue
  49. }
  50. return // err
  51. }
  52. return
  53. }
  54. // returns next N bytes from buffer.
  55. // The returned slice is only guaranteed to be valid until the next read
  56. func (b *buffer) readNext(need int) (p []byte, err error) {
  57. if b.length < need {
  58. // refill
  59. err = b.fill(need) // err deferred
  60. }
  61. p = b.buf[b.idx : b.idx+need]
  62. b.idx += need
  63. b.length -= need
  64. return
  65. }