staticlib_io  1.2.11
 All Classes Namespaces Files Functions Variables
buffered_sink.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2015, alex at staticlibs.net
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * File: buffered_sink.hpp
19  * Author: alex
20  *
21  * Created on October 9, 2015, 12:15 PM
22  */
23 
24 #ifndef STATICLIB_IO_BUFFERED_SINK_HPP
25 #define STATICLIB_IO_BUFFERED_SINK_HPP
26 
27 #include <cstring>
28 #include <array>
29 #include <ios>
30 #include <utility>
31 
32 #include "staticlib/config.hpp"
33 
36 #include "staticlib/io/span.hpp"
37 
38 namespace staticlib {
39 namespace io {
40 
44 template <typename Sink, std::size_t buf_size = 4096>
49  Sink sink;
50 
54  std::array<char, buf_size> buffer;
58  size_t pos = 0;
62  size_t avail = 0;
63 
64 public:
71  explicit buffered_sink(Sink&& sink) :
72  sink(std::move(sink)) { }
73 
77  ~buffered_sink() STATICLIB_NOEXCEPT {
78  try {
79  flush();
80  } catch(...) {
81  // ignore
82  }
83  }
84 
90  buffered_sink(const buffered_sink&) = delete;
91 
98  buffered_sink& operator=(const buffered_sink&) = delete;
99 
105  buffered_sink(buffered_sink&& other) STATICLIB_NOEXCEPT :
106  sink(std::move(other.sink)),
107  buffer(std::move(other.buffer)),
108  pos(other.pos),
109  avail(other.avail) {
110  other.pos = 0;
111  other.avail = 0;
112  }
113 
120  buffered_sink& operator=(buffered_sink&& other) STATICLIB_NOEXCEPT {
121  sink = std::move(other.sink);
122  buffer = std::move(other.buffer);
123  pos = other.pos;
124  other.pos = 0;
125  avail = other.avail;
126  other.avail = 0;
127  return *this;
128  }
129 
136  std::streamsize write(span<const char> span) {
137  size_t ulen = span.size();
138  if (ulen >= buffer.size()) {
139  write_to_sink(buffer.data(), pos);
140  pos = 0;
141  avail = buffer.size();
142  write_to_sink(span.data(), ulen);
143  } else if (ulen <= avail) {
144  std::memcpy(buffer.data() + pos, span.data(), ulen);
145  pos += ulen;
146  if (avail > ulen) {
147  avail -= ulen;
148  return span.size_signed();
149  } else {
150  write_to_sink(buffer.data(), buffer.size());
151  pos = 0;
152  avail = buffer.size();
153  }
154  } else {
155  write_to_sink(buffer.data(), pos);
156  std::memcpy(buffer.data(), span.data(), ulen);
157  pos = ulen;
158  avail = buffer.size() - ulen;
159  }
160  return span.size_signed();
161  }
162 
168  std::streamsize flush() {
169  std::streamsize flushed = 0;
170  if (pos > 0) {
171  write_to_sink(buffer.data(), pos);
172  flushed += pos;
173  pos = 0;
174  avail = buffer.size();
175  }
176  flushed += sink.flush();
177  return flushed;
178  }
179 
185  Sink& get_sink() {
186  return sink;
187  }
188 
194  std::array<char, buf_size>& get_buffer() {
195  return buffer;
196  }
197 
198 private:
199  void write_to_sink(const char* buf, size_t length) {
200  size_t result = 0;
201  while (result < length) {
202  size_t ulen = length - result;
203  if (!sl::support::is_streamsize(ulen)) {
204  ulen = static_cast<size_t> (std::numeric_limits<std::streamsize>::max());
205  }
206  std::streamsize amt = sink.write({buf + result, static_cast<std::streamsize>(ulen)});
207  if (!sl::support::is_sizet(amt)) throw io_exception(TRACEMSG(
208  "Invalid result returned by underlying 'write' operation: [" + sl::support::to_string(amt) + "]"));
209  result += static_cast<size_t> (amt);
210  }
211  }
212 
213 };
214 
222 template <typename Sink,
223  class = typename std::enable_if<!std::is_lvalue_reference<Sink>::value>::type>
225  return buffered_sink<Sink>(std::move(sink));
226 }
227 
235 template <typename Sink>
238 }
239 
240 } // namespace
241 }
242 
243 #endif /* STATICLIB_IO_BUFFERED_SINK_HPP */
244