aboutsummaryrefslogtreecommitdiff
path: root/include/openvic-dataloader/detail/CallbackOStream.hpp
blob: f7cfc4a6485cee6c9814b58c53126b42fff5e6dd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#pragma once

#include <cstring>
#include <functional>
#include <ostream>
#include <type_traits>

namespace ovdl::detail {
   template<typename Callback, class CharT, class traits = std::char_traits<CharT>>
   class BasicCallbackStreamBuffer : public std::basic_streambuf<CharT, traits> {
   public:
      using base_type = std::basic_streambuf<CharT, traits>;
      using callback_type = Callback;
      using char_type = typename base_type::char_type;
      using int_type = typename base_type::int_type;

      BasicCallbackStreamBuffer(Callback cb, void* user_data = nullptr)
         : _callback(cb),
           _user_data(user_data) {}

   protected:
      std::streamsize xsputn(const char_type* s, std::streamsize n) override {
         if constexpr (std::is_same_v<void, typename decltype(std::function { _callback })::result_type>) {
            _callback(s, n, _user_data);
            return n;
         } else {
            return _callback(s, n, _user_data); // returns the number of characters successfully written.
         }
      };

      int_type overflow(int_type ch) override {
         auto c = static_cast<char_type>(ch);
         if constexpr (std::is_same_v<void, typename decltype(std::function { _callback })::result_type>) {
            _callback(&c, 1, _user_data);
            return 1;
         } else {
            return _callback(&c, 1, _user_data); // returns the number of characters successfully written.
         }
      }

   private:
      Callback _callback;
      void* _user_data;
   };

   template<typename Callback>
   class CallbackStreamBuffer : public BasicCallbackStreamBuffer<Callback, char> {
   public:
      using base_type = BasicCallbackStreamBuffer<Callback, char>;
      using callback_type = Callback;
      using char_type = typename base_type::char_type;
      using int_type = typename base_type::int_type;

      CallbackStreamBuffer(Callback cb, void* user_data = nullptr) : base_type(cb, user_data) {}
   };

   template<typename Callback>
   class CallbackWStreamBuffer : public BasicCallbackStreamBuffer<Callback, wchar_t> {
   public:
      using base_type = BasicCallbackStreamBuffer<Callback, wchar_t>;
      using callback_type = Callback;
      using char_type = typename base_type::char_type;
      using int_type = typename base_type::int_type;

      CallbackWStreamBuffer(Callback cb, void* user_data = nullptr) : base_type(cb, user_data) {}
   };

   template<class CharT, typename Callback, class traits = std::char_traits<CharT>>
   class BasicCallbackStream : public std::basic_ostream<CharT, traits> {
   public:
      using base_type = std::basic_ostream<CharT, traits>;

      BasicCallbackStream(Callback cb, void* user_data = nullptr)
         : m_sbuf(cb, user_data),
           std::basic_ios<CharT, traits>(&m_sbuf),
           std::basic_ostream<CharT, traits>(&m_sbuf) {
         std::basic_ios<CharT, traits>::init(&m_sbuf);
      }

   private:
      BasicCallbackStreamBuffer<Callback, CharT, traits> m_sbuf;
   };

   template<typename CharT>
   auto make_callback_stream(auto&& cb, void* user_data = nullptr) {
      using Callback = std::decay_t<decltype(cb)>;
      return BasicCallbackStream<CharT, Callback> { std::forward<Callback>(cb), user_data };
   }

   template<typename Callback>
   class CallbackStream : public BasicCallbackStream<Callback, char> {
   public:
      using base_type = BasicCallbackStream<Callback, char>;

      CallbackStream(Callback cb, void* user_data = nullptr) : base_type(cb, user_data) {
      }
   };

   template<typename Callback>
   class CallbackWStream : public BasicCallbackStream<Callback, wchar_t> {
   public:
      using base_type = BasicCallbackStream<Callback, wchar_t>;

      CallbackWStream(Callback cb, void* user_data = nullptr) : base_type(cb, user_data) {
      }
   };
}