libostd/ostd/stream.hh

241 lines
5.0 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>
#include <locale>
#include <optional>
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/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
2017-02-16 20:39:05 +01:00
using stream_off_t = off_t;
#else
2017-02-16 20:39:05 +01:00
using stream_off_t = __int64;
#endif
2015-06-26 03:30:48 +02:00
2017-02-16 20:39:05 +01:00
enum class stream_seek {
CUR = SEEK_CUR,
END = SEEK_END,
SET = SEEK_SET
2015-06-26 03:30:48 +02:00
};
2017-02-09 20:56:15 +01:00
template<typename T = char, bool = std::is_pod_v<T>>
struct stream_range;
2015-06-26 22:14:54 +02:00
2017-02-16 20:39:05 +01:00
struct stream {
using offset_type = stream_off_t;
2015-06-26 03:30:48 +02:00
2017-02-16 20:39:05 +01:00
virtual ~stream() {}
2015-06-26 21:18:40 +02:00
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
2017-02-16 20:39:05 +01:00
virtual offset_type size() {
offset_type p = tell();
seek(0, stream_seek::END);
2017-02-16 20:39:05 +01:00
offset_type e = tell();
if (p == e) {
return e;
}
seek(p, stream_seek::SET);
return e;
2015-06-26 03:30:48 +02:00
}
virtual void seek(offset_type, stream_seek = stream_seek::SET) {}
2015-06-26 03:30:48 +02:00
2017-02-16 20:39:05 +01:00
virtual offset_type tell() const { return -1; }
2015-06-26 03:30:48 +02:00
virtual void flush() {}
2015-06-26 21:18:40 +02:00
virtual void read_bytes(void *, size_t) {}
virtual void write_bytes(void const *, size_t) {}
2015-06-26 21:18:40 +02:00
virtual int getchar() {
byte c;
read_bytes(&c, 1);
return c;
}
virtual void putchar(int c) {
byte wc = byte(c);
write_bytes(&wc, 1);
}
template<typename T>
2017-02-11 01:28:14 +01:00
void write(T const &v);
template<typename T, typename ...A>
2017-02-11 01:28:14 +01:00
void write(T const &v, A const &...args) {
write(v);
write(args...);
}
template<typename T>
2017-02-11 01:28:14 +01:00
void writeln(T const &v) {
write(v);
putchar('\n');
}
template<typename T, typename ...A>
2017-02-12 22:51:43 +01:00
void writeln(T const &v, A const &...args) {
2017-02-11 01:28:14 +01:00
write(v);
write(args...);
putchar('\n');
}
template<typename ...A>
2017-02-16 18:48:14 +01:00
void writef(string_range fmt, A const &...args);
template<typename ...A>
2017-02-16 18:48:14 +01:00
void writefln(string_range fmt, A const &...args) {
2017-02-11 01:28:14 +01:00
writef(fmt, args...);
putchar('\n');
}
template<typename T = char>
stream_range<T> iter();
template<typename T>
void put(T const *v, size_t count) {
write_bytes(v, count * sizeof(T));
}
template<typename T>
void put(T v) {
write_bytes(&v, sizeof(T));
}
template<typename T>
void get(T *v, size_t count) {
read_bytes(v, count * sizeof(T));
}
template<typename T>
void get(T &v) {
read_bytes(&v, sizeof(T));
}
template<typename T>
T get() {
T r;
get(r);
return r;
}
std::locale imbue(std::locale const &loc) {
std::locale ret{p_loc};
p_loc = loc;
return ret;
}
std::locale getloc() const {
return p_loc;
}
private:
std::locale p_loc;
2015-06-26 22:14:54 +02:00
};
template<typename T>
struct stream_range<T, true>: input_range<stream_range<T>> {
using range_category = input_range_tag;
using value_type = T;
using reference = T;
using size_type = size_t;
2017-02-16 20:39:05 +01:00
using difference_type = stream_off_t;
stream_range() = delete;
stream_range(stream &s): p_stream(&s) {}
2017-02-27 17:55:05 +01:00
stream_range(stream_range const &r):
p_stream(r.p_stream), p_item(r.p_item)
{}
2015-06-26 21:18:40 +02:00
2015-06-27 04:19:00 +02:00
bool empty() const {
if (!p_item.has_value()) {
try {
p_item = p_stream->get<T>();
} catch (...) {
return true;
}
}
return false;
2015-06-27 04:19:00 +02:00
}
2015-06-26 21:18:40 +02:00
void pop_front() {
if (p_item.has_value()) {
p_item = std::nullopt;
} else {
p_stream->get<T>();
}
2015-06-26 21:18:40 +02:00
}
T front() const {
if (p_item.has_value()) {
return p_item.value();
} else {
return (p_item = p_stream->get<T>()).value();
}
2015-06-26 21:18:40 +02:00
}
bool equals_front(stream_range const &s) const {
return p_stream == s.p_stream;
2015-06-26 21:18:40 +02:00
}
void put(T val) {
p_stream->put(val);
}
2015-06-26 22:14:54 +02:00
private:
2017-02-16 20:39:05 +01:00
stream *p_stream;
mutable std::optional<T> p_item;
2015-06-26 21:18:40 +02:00
};
template<typename T>
2017-02-16 20:39:05 +01:00
inline stream_range<T> stream::iter() {
return stream_range<T>(*this);
2015-06-26 22:14:54 +02:00
}
namespace detail {
/* lightweight output range for write/writef on streams */
struct fmt_stream_range: output_range<fmt_stream_range> {
using value_type = char;
using reference = char &;
using size_type = size_t;
using difference_type = ptrdiff_t;
fmt_stream_range(stream *s): p_s(s) {}
void put(char c) {
p_s->write_bytes(&c, 1);
}
stream *p_s;
};
}
template<typename T>
2017-02-16 20:39:05 +01:00
inline void stream::write(T const &v) {
format_spec{'s', p_loc}.format_value(detail::fmt_stream_range{this}, v);
}
template<typename ...A>
2017-02-16 20:39:05 +01:00
inline void stream::writef(string_range fmt, A const &...args) {
format_spec sp{fmt, p_loc};
sp.format(detail::fmt_stream_range{this}, args...);
}
}
2016-02-07 22:17:15 +01:00
#endif