diff --git a/octa/io.hh b/octa/io.hh new file mode 100644 index 0000000..ac00ac5 --- /dev/null +++ b/octa/io.hh @@ -0,0 +1,136 @@ +/* Standard I/O implementation for OctaSTD. + * + * This file is part of OctaSTD. See COPYING.md for futher information. + */ + +#ifndef OCTA_IO_HH +#define OCTA_IO_HH + +#include + +#include "octa/string.hh" +#include "octa/stream.hh" + +namespace octa { + +enum class StreamMode { + read, write, append, + update = 1 << 2 +}; + +namespace detail { + static const char *filemodes[] = { + "rb", "wb", "ab", nullptr, "rb+", "wb+", "ab+" + }; +} + +struct FileStream: Stream { + FileStream(): p_f(), p_owned(false) {} + FileStream(const FileStream &) = delete; + FileStream(FileStream &&s): p_f(s.p_f), p_owned(s.p_owned) { + s.p_f = nullptr; + s.p_owned = false; + } + + FileStream(const octa::String &path, StreamMode mode): p_f() { + open(path, mode); + } + + FileStream(FILE *f): p_f(f), p_owned(false) {} + + ~FileStream() { close(); } + + FileStream &operator=(const FileStream &) = delete; + FileStream &operator=(FileStream &&s) { + close(); + swap(s); + return *this; + } + + bool open(const octa::String &path, StreamMode mode) { + if (p_f) return false; + p_f = fopen(path.data(), octa::detail::filemodes[octa::Size(mode)]); + p_owned = true; + return is_open(); + } + + bool open(FILE *f) { + if (p_f) return false; + p_f = f; + p_owned = false; + return is_open(); + } + + bool is_open() const { return p_f != nullptr; } + bool is_owned() const { return p_owned; } + + void close() { + if (p_f && p_owned) fclose(p_f); + p_f = nullptr; + p_owned = false; + } + + bool end() const { + return feof(p_f) != 0; + } + + bool seek(StreamOffset pos, StreamSeek whence = StreamSeek::set) { + return fseeko(p_f, pos, int(whence)) >= 0; + } + + StreamOffset tell() const { + return ftello(p_f); + } + + bool flush() { return !fflush(p_f); } + + using Stream::read; + using Stream::write; + + octa::Size read(void *buf, octa::Size count) { + return fread(buf, 1, count, p_f); + } + + octa::Size write(const void *buf, octa::Size count) { + return fwrite(buf, 1, count, p_f); + } + + void swap(FileStream &s) { + octa::swap(p_f, s.p_f); + octa::swap(p_owned, s.p_owned); + } + + FILE *get_file() { return p_f; } + +private: + FILE *p_f; + bool p_owned; +}; + +static FileStream in(::stdin); +static FileStream out(::stdout); +static FileStream err(::stderr); + +/* no need to call anything from FileStream, prefer simple calls... */ + +static inline void write(const char *s) { + fputs(s, ::stdout); +} + +static inline void write(const octa::String &s) { + fwrite(s.data(), 1, s.size(), ::stdout); +} + +static inline void writeln(const char *s) { + octa::write(s); + putc('\n', ::stdout); +} + +static inline void writeln(const octa::String &s) { + octa::write(s); + putc('\n', ::stdout); +} + +} + +#endif \ No newline at end of file diff --git a/octa/stream.hh b/octa/stream.hh index 20bcadf..5601197 100644 --- a/octa/stream.hh +++ b/octa/stream.hh @@ -6,13 +6,13 @@ #ifndef OCTA_STREAM_HH #define OCTA_STREAM_HH -#include #include #include "octa/types.hh" #include "octa/range.hh" -#include "octa/string.hh" #include "octa/type_traits.hh" +#include "octa/string.hh" +#include "octa/utility.hh" namespace octa { @@ -55,8 +55,56 @@ struct Stream { virtual octa::Size read(void *, octa::Size) { return 0; } virtual octa::Size write(const void *, octa::Size) { return 0; } + virtual int read() { + octa::uchar c; + return (read(&c, 1) == 1) ? c : -1; + } + + virtual bool write(int c) { + octa::uchar wc = octa::uchar(c); + return write(&wc, 1) == 1; + } + + virtual bool write(const char *s) { + octa::Size len = strlen(s); + return write(s, len) == len; + } + + virtual bool write(const octa::String &s) { + return write(s.data(), s.size()) == s.size(); + } + + virtual bool writeln(const octa::String &s) { + return write(s) && write('\n'); + } + + virtual bool writeln(const char *s) { + return write(s) && write('\n'); + } + template StreamRange iter(); + + template octa::Size put(const T *v, octa::Size count) { + return write(v, count * sizeof(T)) / sizeof(T); + } + + template bool put(T v) { + return write(&v, sizeof(T)) == sizeof(T); + } + + template octa::Size get(T *v, octa::Size count) { + return read(v, count * sizeof(T)) / sizeof(T); + } + + template bool get(T &v) { + return read(&v, sizeof(T)) == sizeof(T); + } + + template T get() { + T r; + return get(r) ? r : T(); + } }; template @@ -83,7 +131,7 @@ struct StreamRange: InputRange< return val; } - virtual bool equals_front(const StreamRange &s) const { + bool equals_front(const StreamRange &s) const { return p_stream->tell() == s.p_stream->tell(); } @@ -101,64 +149,6 @@ inline StreamRange Stream::iter() { return StreamRange(*this); } -enum class StreamMode { - read, write, append, - update = 1 << 2 -}; - -namespace detail { - static const char *filemodes[] = { - "rb", "wb", "ab", nullptr, "rb+", "wb+", "ab+" - }; -} - -struct FileStream: Stream { - FileStream(): p_f() {} - FileStream(const FileStream &s) = delete; - - FileStream(const octa::String &path, StreamMode mode): p_f() { - open(path, mode); - } - - ~FileStream() { close(); } - - bool open(const octa::String &path, StreamMode mode) { - if (p_f) return false; - p_f = fopen(path.data(), octa::detail::filemodes[octa::Size(mode)]); - return p_f != nullptr; - } - - void close() { - if (p_f) fclose(p_f); - p_f = nullptr; - } - - bool end() const { - return feof(p_f) != 0; - } - - bool seek(StreamOffset pos, StreamSeek whence = StreamSeek::set) { - return fseeko(p_f, pos, int(whence)) >= 0; - } - - StreamOffset tell() const { - return ftello(p_f); - } - - bool flush() { return !fflush(p_f); } - - octa::Size read(void *buf, octa::Size count) { - return fread(buf, 1, count, p_f); - } - - octa::Size write(const void *buf, octa::Size count) { - return fwrite(buf, 1, count, p_f); - } - -private: - FILE *p_f; -}; - } #endif \ No newline at end of file