libostd/ostd/stream.hh

216 lines
4.9 KiB
C++
Raw Normal View History

/* Generic stream implementation for OctaSTD.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
2015-07-13 21:08:55 +02:00
#ifndef OSTD_STREAM_HH
#define OSTD_STREAM_HH
2015-06-26 03:30:48 +02:00
#include <sys/types.h>
2017-02-09 20:56:15 +01:00
#include <type_traits>
2017-01-25 01:44:22 +01:00
2015-07-13 21:08:55 +02:00
#include "ostd/platform.hh"
#include "ostd/types.hh"
#include "ostd/range.hh"
#include "ostd/string.hh"
#include "ostd/utility.hh"
#include "ostd/format.hh"
2015-06-26 03:30:48 +02:00
2015-07-13 21:07:14 +02:00
namespace ostd {
2015-06-26 03:30:48 +02:00
2015-07-13 21:08:55 +02:00
#ifndef OSTD_PLATFORM_WIN32
2015-06-26 03:30:48 +02:00
using StreamOffset = off_t;
#else
using StreamOffset = __int64;
#endif
2015-06-26 03:30:48 +02:00
2015-06-26 21:18:40 +02:00
enum class StreamSeek {
2015-06-26 03:30:48 +02:00
cur = SEEK_CUR,
end = SEEK_END,
set = SEEK_SET
};
2017-02-09 20:56:15 +01:00
template<typename T = char, bool = std::is_pod_v<T>>
2015-06-26 22:14:54 +02:00
struct StreamRange;
2015-06-27 01:59:16 +02:00
struct Stream {
2015-06-26 03:30:48 +02:00
using Offset = StreamOffset;
2015-06-26 21:18:40 +02:00
virtual ~Stream() {}
2015-06-26 03:30:48 +02:00
virtual void close() = 0;
2015-06-26 21:18:40 +02:00
virtual bool end() const = 0;
2015-06-26 03:30:48 +02:00
virtual Offset size() {
Offset p = tell();
if ((p < 0) || !seek(0, StreamSeek::end)) {
return -1;
}
2015-06-26 03:30:48 +02:00
Offset e = tell();
2015-06-27 04:19:00 +02:00
return ((p == e) || seek(p, StreamSeek::set)) ? e : -1;
2015-06-26 03:30:48 +02:00
}
2015-06-26 21:18:40 +02:00
virtual bool seek(Offset, StreamSeek = StreamSeek::set) {
return false;
}
2015-06-26 03:30:48 +02:00
2015-06-26 21:18:40 +02:00
virtual Offset tell() const { return -1; }
2015-06-26 03:30:48 +02:00
virtual bool flush() { return true; }
2015-06-26 21:18:40 +02:00
2017-01-30 19:11:39 +01:00
virtual size_t read_bytes(void *, size_t) { return 0; }
virtual size_t write_bytes(void const *, size_t) { return 0; }
2015-06-26 21:18:40 +02:00
virtual int getchar() {
byte c;
return (read_bytes(&c, 1) == 1) ? c : -1;
}
virtual bool putchar(int c) {
byte wc = byte(c);
return write_bytes(&wc, 1) == 1;
}
template<typename T>
bool write(T const &v);
template<typename T, typename ...A>
2016-06-23 20:18:35 +02:00
bool write(T const &v, A const &...args) {
return write(v) && write(args...);
}
template<typename T>
2016-06-23 20:18:35 +02:00
bool writeln(T const &v) {
return write(v) && putchar('\n');
}
template<typename T, typename ...A>
2016-06-23 20:18:35 +02:00
bool writeln(T const &v, A const &...args) {
return write(v) && write(args...) && putchar('\n');
}
template<typename ...A>
bool writef(ConstCharRange fmt, A const &...args);
template<typename ...A>
2016-06-23 20:18:35 +02:00
bool writefln(ConstCharRange fmt, A const &...args) {
return writef(fmt, args...) && putchar('\n');
}
template<typename T = char>
StreamRange<T> iter();
template<typename T>
2017-01-30 19:11:39 +01:00
size_t put(T const *v, size_t count) {
return write_bytes(v, count * sizeof(T)) / sizeof(T);
}
template<typename T>
bool put(T v) {
return write_bytes(&v, sizeof(T)) == sizeof(T);
}
template<typename T>
2017-01-30 19:11:39 +01:00
size_t get(T *v, size_t count) {
return read_bytes(v, count * sizeof(T)) / sizeof(T);
}
template<typename T>
bool get(T &v) {
return read_bytes(&v, sizeof(T)) == sizeof(T);
}
template<typename T>
T get() {
T r;
return get(r) ? r : T();
}
2015-06-26 22:14:54 +02:00
};
template<typename T>
struct StreamRange<T, true>: InputRange<
2017-01-30 19:11:39 +01:00
StreamRange<T>, InputRangeTag, T, T, size_t, StreamOffset
2015-06-26 22:14:54 +02:00
> {
StreamRange() = delete;
2015-06-27 04:19:00 +02:00
StreamRange(Stream &s): p_stream(&s), p_size(s.size()) {}
2016-06-23 20:18:35 +02:00
StreamRange(StreamRange const &r): p_stream(r.p_stream), p_size(r.p_size) {}
2015-06-26 21:18:40 +02:00
2015-06-27 04:19:00 +02:00
bool empty() const {
return (p_size - p_stream->tell()) < StreamOffset(sizeof(T));
2015-06-27 04:19:00 +02:00
}
2015-06-26 21:18:40 +02:00
bool pop_front() {
if (empty()) {
return false;
}
T val;
return !!p_stream->read_bytes(&val, sizeof(T));
2015-06-26 21:18:40 +02:00
}
T front() const {
T val;
p_stream->seek(-p_stream->read_bytes(&val, sizeof(T)), StreamSeek::cur);
2015-06-26 21:18:40 +02:00
return val;
}
2016-06-23 20:18:35 +02:00
bool equals_front(StreamRange const &s) const {
2015-06-26 22:14:54 +02:00
return p_stream->tell() == s.p_stream->tell();
2015-06-26 21:18:40 +02:00
}
2015-07-01 22:12:45 +02:00
bool put(T val) {
2017-01-30 19:11:39 +01:00
size_t v = p_stream->write_bytes(&val, sizeof(T));
2015-07-01 22:12:45 +02:00
p_size += v;
return (v == sizeof(T));
2015-06-26 21:18:40 +02:00
}
2015-06-26 22:14:54 +02:00
2017-01-30 19:11:39 +01:00
size_t put_n(T const *p, size_t n) {
return p_stream->put(p, n);
}
2017-02-09 20:56:15 +01:00
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
2017-01-30 19:11:39 +01:00
if (n == size_t(-1)) {
n = p_stream->size() / sizeof(T);
}
return p_stream->get(p, n);
}
2015-06-26 22:14:54 +02:00
private:
Stream *p_stream;
2015-06-27 04:19:00 +02:00
StreamOffset p_size;
2015-06-26 21:18:40 +02:00
};
template<typename T>
inline StreamRange<T> Stream::iter() {
return StreamRange<T>(*this);
2015-06-26 22:14:54 +02:00
}
namespace detail {
/* lightweight output range for write/writef on streams */
struct FmtStreamRange: OutputRange<FmtStreamRange, char> {
FmtStreamRange(Stream &s): p_s(s) {}
bool put(char c) {
return p_s.putchar(c);
}
size_t put_n(char const *p, size_t n) {
return p_s.put(p, n);
}
Stream &p_s;
};
}
template<typename T>
inline bool Stream::write(T const &v) {
// TODO: switch to direct FormatSpec later
return format(detail::FmtStreamRange{*this}, "%s", v) >= 0;
}
template<typename ...A>
inline bool Stream::writef(ConstCharRange fmt, A const &...args) {
return format(detail::FmtStreamRange{*this}, fmt, args...) >= 0;
}
}
2016-02-07 22:17:15 +01:00
#endif