byte_writer.h 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #pragma once
  2. #include "macros.h"
  3. #include <library/cpp/yson_pull/output.h>
  4. #include <util/system/types.h>
  5. #include <cstddef>
  6. #include <cstring>
  7. namespace NYsonPull {
  8. namespace NDetail {
  9. template <class StreamCounter>
  10. class byte_writer {
  11. NYsonPull::NOutput::IStream& stream_;
  12. StreamCounter stream_counter_;
  13. public:
  14. byte_writer(NYsonPull::NOutput::IStream& stream)
  15. : stream_(stream)
  16. {
  17. }
  18. // const-ness added to prevent direct stream mutation
  19. const NYsonPull::NOutput::IStream& stream() {
  20. return stream_;
  21. }
  22. const StreamCounter& counter() {
  23. return stream_counter_;
  24. }
  25. void flush_buffer() {
  26. stream_.flush_buffer();
  27. }
  28. void advance(size_t bytes) {
  29. auto& buf = stream_.buffer();
  30. stream_counter_.update(
  31. buf.pos(),
  32. buf.pos() + bytes);
  33. buf.advance(bytes);
  34. }
  35. void write(ui8 c) {
  36. auto& buf = stream_.buffer();
  37. if (Y_LIKELY(!buf.is_full())) {
  38. *buf.pos() = c;
  39. advance(1);
  40. } else {
  41. auto ptr = reinterpret_cast<char*>(&c);
  42. stream_counter_.update(&c, &c + 1);
  43. stream_.flush_buffer({ptr, 1});
  44. }
  45. }
  46. void write(const ui8* data, size_t size) {
  47. auto& buf = stream_.buffer();
  48. auto free_buf = buf.available();
  49. if (Y_LIKELY(size < free_buf)) {
  50. ::memcpy(buf.pos(), data, size);
  51. advance(size);
  52. } else {
  53. if (!buf.is_full()) {
  54. ::memcpy(buf.pos(), data, free_buf);
  55. advance(free_buf);
  56. data += free_buf;
  57. size -= free_buf;
  58. }
  59. stream_counter_.update(data, data + size);
  60. stream_.flush_buffer({reinterpret_cast<const char*>(data),
  61. size});
  62. }
  63. }
  64. };
  65. }
  66. }