2015-05-12 20:27:46 +00:00
|
|
|
/* Generic stream implementation for OctaSTD.
|
|
|
|
*
|
|
|
|
* This file is part of OctaSTD. See COPYING.md for futher information.
|
|
|
|
*/
|
|
|
|
|
2015-06-28 15:04:49 +00:00
|
|
|
#ifndef OCTA_STREAM_HH
|
|
|
|
#define OCTA_STREAM_HH
|
2015-05-12 20:27:46 +00:00
|
|
|
|
2015-06-26 01:30:48 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
2015-07-01 19:59:05 +00:00
|
|
|
#include "octa/platform.hh"
|
2015-06-28 14:39:04 +00:00
|
|
|
#include "octa/types.hh"
|
|
|
|
#include "octa/range.hh"
|
|
|
|
#include "octa/type_traits.hh"
|
2015-06-30 18:25:40 +00:00
|
|
|
#include "octa/string.hh"
|
|
|
|
#include "octa/utility.hh"
|
2015-07-01 17:51:39 +00:00
|
|
|
#include "octa/format.hh"
|
2015-06-26 01:30:48 +00:00
|
|
|
|
2015-05-12 20:27:46 +00:00
|
|
|
namespace octa {
|
2015-06-26 01:30:48 +00:00
|
|
|
|
2015-07-01 19:59:05 +00:00
|
|
|
#ifndef OCTA_PLATFORM_WIN32
|
2015-06-26 01:30:48 +00:00
|
|
|
using StreamOffset = off_t;
|
2015-07-01 19:59:05 +00:00
|
|
|
#else
|
|
|
|
using StreamOffset = __int64;
|
|
|
|
#endif
|
2015-06-26 01:30:48 +00:00
|
|
|
|
2015-06-26 19:18:40 +00:00
|
|
|
enum class StreamSeek {
|
2015-06-26 01:30:48 +00:00
|
|
|
cur = SEEK_CUR,
|
|
|
|
end = SEEK_END,
|
|
|
|
set = SEEK_SET
|
|
|
|
};
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename T = char, bool = IsPod<T>::value>
|
2015-06-26 20:14:54 +00:00
|
|
|
struct StreamRange;
|
|
|
|
|
2015-07-01 17:51:39 +00:00
|
|
|
namespace detail {
|
2015-07-05 22:59:36 +00:00
|
|
|
template<Size N>
|
|
|
|
struct FormatOutRange: OutputRange<FormatOutRange<N>, char> {
|
2015-07-01 17:51:39 +00:00
|
|
|
FormatOutRange(char *buf): buf(buf), idx(0) {}
|
|
|
|
FormatOutRange(const FormatOutRange &r): buf(r.buf), idx(r.idx) {}
|
|
|
|
char *buf;
|
2015-07-05 22:59:36 +00:00
|
|
|
Size idx;
|
2015-07-01 20:12:45 +00:00
|
|
|
bool put(char v) {
|
|
|
|
if (idx < N) {
|
|
|
|
buf[idx++] = v;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2015-07-01 17:51:39 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-06-26 23:59:16 +00:00
|
|
|
struct Stream {
|
2015-06-26 01:30:48 +00:00
|
|
|
using Offset = StreamOffset;
|
|
|
|
|
2015-06-26 19:18:40 +00:00
|
|
|
virtual ~Stream() {}
|
|
|
|
|
2015-06-26 01:30:48 +00:00
|
|
|
virtual void close() = 0;
|
|
|
|
|
2015-06-26 19:18:40 +00:00
|
|
|
virtual bool end() const = 0;
|
2015-06-26 01:30:48 +00:00
|
|
|
|
|
|
|
virtual Offset size() {
|
|
|
|
Offset p = tell();
|
2015-06-26 19:18:40 +00:00
|
|
|
if ((p < 0) || !seek(0, StreamSeek::end)) return -1;
|
2015-06-26 01:30:48 +00:00
|
|
|
Offset e = tell();
|
2015-06-27 02:19:00 +00:00
|
|
|
return ((p == e) || seek(p, StreamSeek::set)) ? e : -1;
|
2015-06-26 01:30:48 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 19:18:40 +00:00
|
|
|
virtual bool seek(Offset, StreamSeek = StreamSeek::set) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-06-26 01:30:48 +00:00
|
|
|
|
2015-06-26 19:18:40 +00:00
|
|
|
virtual Offset tell() const { return -1; }
|
2015-06-26 01:30:48 +00:00
|
|
|
|
|
|
|
virtual bool flush() { return true; }
|
2015-06-26 19:18:40 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
virtual Size read_bytes(void *, Size) { return 0; }
|
|
|
|
virtual Size write_bytes(const void *, Size) { return 0; }
|
2015-06-26 19:18:40 +00:00
|
|
|
|
2015-06-30 22:07:28 +00:00
|
|
|
virtual int getchar() {
|
2015-07-05 22:59:36 +00:00
|
|
|
byte c;
|
2015-06-30 22:07:28 +00:00
|
|
|
return (read_bytes(&c, 1) == 1) ? c : -1;
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-30 22:07:28 +00:00
|
|
|
virtual bool putchar(int c) {
|
2015-07-05 22:59:36 +00:00
|
|
|
byte wc = byte(c);
|
2015-06-30 22:07:28 +00:00
|
|
|
return write_bytes(&wc, 1) == 1;
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool write(const char *s) {
|
2015-07-05 22:59:36 +00:00
|
|
|
Size len = strlen(s);
|
2015-06-30 22:07:28 +00:00
|
|
|
return write_bytes(s, len) == len;
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
virtual bool write(const String &s) {
|
2015-06-30 22:07:28 +00:00
|
|
|
return write_bytes(s.data(), s.size()) == s.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> bool write(const T &v) {
|
2015-07-05 22:59:36 +00:00
|
|
|
return write(to_string(v));
|
2015-06-30 22:07:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename ...A>
|
|
|
|
bool write(const T &v, const A &...args) {
|
|
|
|
return write(v) && write(args...);
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
virtual bool writeln(const String &s) {
|
2015-07-01 17:51:39 +00:00
|
|
|
return write(s) && putchar('\n');
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool writeln(const char *s) {
|
2015-07-01 17:51:39 +00:00
|
|
|
return write(s) && putchar('\n');
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-30 22:07:28 +00:00
|
|
|
template<typename T> bool writeln(const T &v) {
|
2015-07-01 17:51:39 +00:00
|
|
|
return write(v) && putchar('\n');
|
2015-06-30 22:07:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename ...A>
|
|
|
|
bool writeln(const T &v, const A &...args) {
|
2015-07-01 17:51:39 +00:00
|
|
|
return write(v) && write(args...) && putchar('\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
|
|
|
bool writef(const char *fmt, const A &...args) {
|
|
|
|
char buf[512];
|
2015-07-05 22:59:36 +00:00
|
|
|
Size need = format(detail::FormatOutRange<sizeof(buf)>(buf),
|
|
|
|
fmt, args...);
|
2015-07-01 17:51:39 +00:00
|
|
|
if (need < sizeof(buf))
|
|
|
|
return write_bytes(buf, need) == need;
|
2015-07-05 22:59:36 +00:00
|
|
|
String s;
|
2015-07-01 17:51:39 +00:00
|
|
|
s.reserve(need);
|
|
|
|
s[need] = '\0';
|
2015-07-05 22:59:36 +00:00
|
|
|
format(s.iter(), fmt, args...);
|
2015-07-01 17:51:39 +00:00
|
|
|
return write_bytes(s.data(), need) == need;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
2015-07-05 22:59:36 +00:00
|
|
|
bool writef(const String &fmt, const A &...args) {
|
2015-07-01 17:51:39 +00:00
|
|
|
return writef(fmt.data(), args...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
|
|
|
bool writefln(const char *fmt, const A &...args) {
|
|
|
|
return writef(fmt, args...) && putchar('\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
2015-07-05 22:59:36 +00:00
|
|
|
bool writefln(const String &fmt, const A &...args) {
|
2015-07-01 17:51:39 +00:00
|
|
|
return writefln(fmt.data(), args...);
|
2015-06-30 22:07:28 +00:00
|
|
|
}
|
|
|
|
|
2015-06-27 00:02:28 +00:00
|
|
|
template<typename T = char>
|
|
|
|
StreamRange<T> iter();
|
2015-06-30 18:25:40 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename T> Size put(const T *v, Size count) {
|
2015-06-30 22:07:28 +00:00
|
|
|
return write_bytes(v, count * sizeof(T)) / sizeof(T);
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> bool put(T v) {
|
2015-06-30 22:07:28 +00:00
|
|
|
return write_bytes(&v, sizeof(T)) == sizeof(T);
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename T> Size get(T *v, Size count) {
|
2015-06-30 22:07:28 +00:00
|
|
|
return read_bytes(v, count * sizeof(T)) / sizeof(T);
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> bool get(T &v) {
|
2015-06-30 22:07:28 +00:00
|
|
|
return read_bytes(&v, sizeof(T)) == sizeof(T);
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> T get() {
|
|
|
|
T r;
|
|
|
|
return get(r) ? r : T();
|
|
|
|
}
|
2015-06-26 20:14:54 +00:00
|
|
|
};
|
|
|
|
|
2015-06-27 00:02:28 +00:00
|
|
|
template<typename T>
|
|
|
|
struct StreamRange<T, true>: InputRange<
|
2015-07-05 22:59:36 +00:00
|
|
|
StreamRange<T>, InputRangeTag, T, T, Size, StreamOffset
|
2015-06-26 20:14:54 +00:00
|
|
|
> {
|
2015-06-29 22:33:20 +00:00
|
|
|
StreamRange() = delete;
|
2015-06-27 02:19:00 +00:00
|
|
|
StreamRange(Stream &s): p_stream(&s), p_size(s.size()) {}
|
|
|
|
StreamRange(const StreamRange &r): p_stream(r.p_stream), p_size(r.p_size) {}
|
2015-06-26 19:18:40 +00:00
|
|
|
|
2015-06-27 02:19:00 +00:00
|
|
|
bool empty() const {
|
2015-06-29 17:54:25 +00:00
|
|
|
return (p_size - p_stream->tell()) < StreamOffset(sizeof(T));
|
2015-06-27 02:19:00 +00:00
|
|
|
}
|
2015-06-26 19:18:40 +00:00
|
|
|
|
|
|
|
bool pop_front() {
|
|
|
|
if (empty()) return false;
|
2015-06-27 00:02:28 +00:00
|
|
|
T val;
|
2015-06-30 22:07:28 +00:00
|
|
|
return !!p_stream->read_bytes(&val, sizeof(T));
|
2015-06-26 19:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-27 00:02:28 +00:00
|
|
|
T front() const {
|
|
|
|
T val;
|
2015-06-30 22:07:28 +00:00
|
|
|
p_stream->seek(-p_stream->read_bytes(&val, sizeof(T)), StreamSeek::cur);
|
2015-06-26 19:18:40 +00:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2015-06-30 18:25:40 +00:00
|
|
|
bool equals_front(const StreamRange &s) const {
|
2015-06-26 20:14:54 +00:00
|
|
|
return p_stream->tell() == s.p_stream->tell();
|
2015-06-26 19:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-07-01 20:12:45 +00:00
|
|
|
bool put(T val) {
|
2015-07-05 22:59:36 +00:00
|
|
|
Size v = p_stream->write_bytes(&val, sizeof(T));
|
2015-07-01 20:12:45 +00:00
|
|
|
p_size += v;
|
|
|
|
return (v == sizeof(T));
|
2015-06-26 19:18:40 +00:00
|
|
|
}
|
2015-06-26 20:14:54 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size put_n(const T *p, Size n) {
|
2015-07-01 20:46:58 +00:00
|
|
|
return p_stream->put(p, n);
|
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size copy(RemoveCv<T> *p, Size n = -1) {
|
|
|
|
if (n == Size(-1)) {
|
2015-07-01 21:21:29 +00:00
|
|
|
n = p_stream->size() / sizeof(T);
|
|
|
|
}
|
2015-07-01 20:46:58 +00:00
|
|
|
return p_stream->get(p, n);
|
|
|
|
}
|
|
|
|
|
2015-06-26 20:14:54 +00:00
|
|
|
private:
|
|
|
|
Stream *p_stream;
|
2015-06-27 02:19:00 +00:00
|
|
|
StreamOffset p_size;
|
2015-06-26 19:18:40 +00:00
|
|
|
};
|
|
|
|
|
2015-06-27 00:02:28 +00:00
|
|
|
template<typename T>
|
|
|
|
inline StreamRange<T> Stream::iter() {
|
|
|
|
return StreamRange<T>(*this);
|
2015-06-26 20:14:54 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 20:27:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|