Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/buffers
8 : //
9 :
10 : #ifndef BOOST_BUFFERS_ANY_READ_SOURCE_HPP
11 : #define BOOST_BUFFERS_ANY_READ_SOURCE_HPP
12 :
13 : #include <boost/buffers/detail/config.hpp>
14 : #include <boost/buffers/error.hpp>
15 : #include <boost/buffers/read_source.hpp>
16 : #include <boost/core/span.hpp>
17 : #include <boost/assert.hpp>
18 :
19 : namespace boost {
20 : namespace buffers {
21 :
22 : /** Type-erased interface to a read source
23 : */
24 : class BOOST_SYMBOL_VISIBLE
25 : any_read_source
26 : {
27 : public:
28 2 : virtual ~any_read_source() = default;
29 :
30 : virtual bool has_size() const noexcept = 0;
31 :
32 : virtual bool has_rewind() const noexcept = 0;
33 :
34 : virtual std::uint64_t size() const = 0;
35 :
36 : virtual void rewind() = 0;
37 :
38 : template<class MutableBufferSequence>
39 : std::size_t read(
40 : MutableBufferSequence const& dest,
41 : system::error_code& ec);
42 :
43 : private:
44 : virtual std::size_t do_read(
45 : mutable_buffer const* p,
46 : std::size_t n,
47 : system::error_code& ec) = 0;
48 : };
49 :
50 : //-----------------------------------------------
51 :
52 : template<class MutableBufferSequence>
53 : std::size_t
54 54 : any_read_source::
55 : read(
56 : MutableBufferSequence const& dest,
57 : system::error_code& ec)
58 : {
59 54 : std::size_t result = 0;
60 54 : constexpr std::size_t N = 16;
61 54 : std::size_t n = 0;
62 54 : mutable_buffer mb[N];
63 54 : auto it = buffers::begin(dest);
64 54 : auto const end_ = buffers::end(dest);
65 407 : while(it != end_)
66 : {
67 354 : mb[n++] = *it++;
68 354 : if(n < N)
69 338 : continue;
70 16 : auto const nread = do_read(mb, n, ec);
71 16 : BOOST_ASSERT(
72 : ec.failed() ||
73 : nread == buffers::size(
74 : span<mutable_buffer const>(mb, n)));
75 16 : result += nread;
76 16 : if(ec.failed())
77 1 : return result;
78 15 : n = 0;
79 : }
80 53 : if(n > 0)
81 : {
82 53 : auto const nread = do_read(mb, n, ec);
83 53 : BOOST_ASSERT(
84 : ec.failed() ||
85 : nread == buffers::size(
86 : span<mutable_buffer const>(mb, n)));
87 53 : result += nread;
88 53 : if(ec.failed())
89 1 : return result;
90 : }
91 52 : return result;
92 : }
93 :
94 : //-----------------------------------------------
95 :
96 : namespace detail {
97 :
98 : template<class Source>
99 : class read_source_impl : public any_read_source
100 : {
101 : public:
102 : template<class Source_>
103 2 : explicit read_source_impl(
104 : Source_&& source) noexcept
105 2 : : source_(std::forward<Source_>(source))
106 : {
107 2 : }
108 :
109 : private:
110 0 : bool has_size() const noexcept override
111 : {
112 0 : return buffers::has_size<Source>::value;
113 : }
114 :
115 0 : bool has_rewind() const noexcept override
116 : {
117 0 : return buffers::has_rewind<Source>::value;
118 : }
119 :
120 0 : std::uint64_t size() const override
121 : {
122 0 : return size(buffers::has_size<Source>{});
123 : }
124 :
125 : std::uint64_t size(std::true_type) const
126 : {
127 : return source_.size();
128 : }
129 :
130 0 : std::uint64_t size(std::false_type) const
131 : {
132 0 : detail::throw_invalid_argument();
133 : }
134 :
135 0 : void rewind() override
136 : {
137 0 : rewind(buffers::has_rewind<Source>{});
138 0 : }
139 :
140 : void rewind(std::true_type)
141 : {
142 : ec_ = {};
143 : source_.rewind();
144 : }
145 :
146 0 : void rewind(std::false_type) const
147 : {
148 0 : detail::throw_invalid_argument();
149 : }
150 :
151 69 : std::size_t do_read(
152 : mutable_buffer const* p,
153 : std::size_t n,
154 : system::error_code& ec) override
155 : {
156 69 : if(ec_.failed())
157 : {
158 0 : ec = ec_;
159 0 : return 0;
160 : }
161 69 : auto const nread = source_.read(
162 69 : span<mutable_buffer const>(p, n), ec);
163 69 : ec_ = ec;
164 69 : return nread;
165 : }
166 :
167 : Source source_;
168 : system::error_code ec_;
169 : };
170 :
171 : } // detail
172 :
173 : //-----------------------------------------------
174 :
175 : template<class ReadSource>
176 : auto
177 2 : make_any_read_source(
178 : ReadSource&& source) ->
179 : detail::read_source_impl<typename
180 : std::decay<ReadSource>::type>
181 : {
182 : return detail::read_source_impl<typename
183 : std::decay<ReadSource>::type>(
184 2 : std::forward<ReadSource>(source));
185 : }
186 :
187 : } // buffers
188 : } // boost
189 :
190 : #endif
|