staticlib_io  1.2.11
 All Classes Namespaces Files Functions Variables
unbuffered_streambuf.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: unbuffered_streambuf.hpp
19  * Author: alex
20  *
21  * Created on October 9, 2015, 12:10 PM
22  */
23 
24 #ifndef STATICLIB_IO_UNBUFFERED_STREAMBUF_HPP
25 #define STATICLIB_IO_UNBUFFERED_STREAMBUF_HPP
26 
27 #include <ios>
28 #include <memory>
29 #include <streambuf>
30 #include <utility>
31 
32 #include "staticlib/config.hpp"
33 
36 #include "staticlib/io/span.hpp"
37 
38 namespace staticlib {
39 namespace io {
40 
41 namespace detail {
42 
47 class unbuffered_streambuf_base : public std::streambuf {
48 public:
52  virtual int underflow() override {
53  throw std::ios_base::failure("'underflow' operation is not supported by unbuffered streambuf");
54  }
55 
59  virtual int uflow() override {
60  throw std::ios_base::failure("'uflow' operation is not supported by unbuffered streambuf");
61  }
62 
66  virtual int overflow(int) override {
67  throw std::ios_base::failure("'overflow' operation is not supported by unbuffered streambuf");
68  }
69 
70 protected:
71 
79  virtual std::streamsize xsgetn(char*, std::streamsize) override {
80  throw std::ios_base::failure("'xsgetn' operation is not supported by unbuffered streambuf");
81  }
82 
90  virtual std::streamsize xsputn(const char*, std::streamsize) override {
91  throw std::ios_base::failure("'xsputn' operation is not supported by unbuffered streambuf");
92  }
93 
97  virtual unbuffered_streambuf_base* setbuf(char*, std::streamsize) override {
98  throw std::ios_base::failure("'setbuf' operation is not supported by unbuffered streambuf");
99  }
100 
104  virtual std::streampos seekoff(std::streamoff, std::ios_base::seekdir, std::ios_base::openmode) override {
105  throw std::ios_base::failure("'seekoff' operation is not supported by unbuffered streambuf");
106  }
107 
111  virtual std::streampos seekpos(std::streampos, std::ios_base::openmode) override {
112  throw std::ios_base::failure("'seekpos' operation is not supported by unbuffered streambuf");
113  }
114 
115 };
116 
117 } // namespace
118 
123 // use -1 as std::char_traits<char>::eof() won't work in msvc
124 template <typename Source, std::streamsize source_eof = -1>
126  Source source;
127  bool exhausted = false;
128 
129 public:
136  explicit unbuffered_istreambuf(Source&& source) :
137  source(std::move(source)) { }
138 
143 
148 
152  unbuffered_istreambuf(unbuffered_istreambuf&& other) STATICLIB_NOEXCEPT :
153  source(std::move(other.source)),
154  exhausted(other.exhausted) {
155  other.exhausted = true;
156  }
157 
162  source = std::move(other.source);
163  exhausted = other.exhausted;
164  other.exhausted = true;
165  return *this;
166  }
167 
173  virtual int uflow() override {
174  if (exhausted) {
175  return std::char_traits<char>::eof();
176  } else {
177  throw std::ios_base::failure("'uflow' operation is not supported by unbuffered streambuf");
178  }
179  }
180 
186  Source& get_source() {
187  return source;
188  }
189 
190 protected:
198  virtual std::streamsize xsgetn(char* s, std::streamsize count) override {
199  if (!exhausted) {
200  auto res = source.read({s, count});
201  if (source_eof != res) {
202  return res;
203  } else {
204  exhausted = true;
205  return 0;
206  }
207  } else {
208  return 0;
209  }
210  }
211 };
212 
220 template <typename Source,
221  class = typename std::enable_if<!std::is_lvalue_reference<Source>::value>::type>
223  return unbuffered_istreambuf<Source>(std::move(source));
224 }
225 
233 template <typename Source,
234 class = typename std::enable_if<!std::is_lvalue_reference<Source>::value>::type>
235 std::unique_ptr<unbuffered_istreambuf<Source>> make_unbuffered_istreambuf_ptr(Source&& source) {
236  return std::unique_ptr<unbuffered_istreambuf<Source>>(
237  new unbuffered_istreambuf<Source>(std::move(source)));
238 }
239 
247 template <typename Source>
250 }
251 
259 template <typename Source>
260 std::unique_ptr<unbuffered_istreambuf<reference_source<Source>>> make_unbuffered_istreambuf_ptr(Source& source) {
261  return std::unique_ptr<unbuffered_istreambuf<reference_source<Source>>>(
263 }
264 
269 template <typename Sink>
271  Sink sink;
272 
273 public:
280  explicit unbuffered_ostreambuf(Sink&& sink) :
281  sink(std::move(sink)) { }
282 
287 
292 
296  unbuffered_ostreambuf(unbuffered_ostreambuf&& other) STATICLIB_NOEXCEPT :
297  sink(std::move(other.sink)) { }
298 
303  sink = std::move(other.sink);
304  return *this;
305  }
306 
312  Sink& get_sink() {
313  return sink;
314  }
315 
316 protected:
317 
324  virtual std::streamsize xsputn(const char* s, std::streamsize count) override {
325  return sink.write({s, count});
326  }
327 };
328 
336 template <typename Sink,
337  class = typename std::enable_if<!std::is_lvalue_reference<Sink>::value>::type>
339  return unbuffered_ostreambuf<Sink>(std::move(sink));
340 }
341 
349 template <typename Sink,
350 class = typename std::enable_if<!std::is_lvalue_reference<Sink>::value>::type>
351 std::unique_ptr<unbuffered_ostreambuf<Sink>> make_unbuffered_ostreambuf_ptr(Sink&& sink) {
352  return std::unique_ptr<unbuffered_ostreambuf<Sink>>(
353  new unbuffered_ostreambuf<Sink>(std::move(sink)));
354 }
355 
363 template <typename Sink>
366 }
367 
375 template <typename Sink>
376 std::unique_ptr<unbuffered_ostreambuf<reference_sink<Sink>>> make_unbuffered_ostreambuf_ptr(Sink& sink) {
377  return std::unique_ptr<unbuffered_ostreambuf<reference_sink<Sink>>>(
379 }
380 
381 } // namespace
382 }
383 
384 #endif /* STATICLIB_IO_UNBUFFERED_STREAMBUF_HPP */
385