libostd/octa/stream.h

145 lines
3.1 KiB
C
Raw Normal View History

/* Generic stream implementation for OctaSTD.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
#ifndef OCTA_STREAM_H
#define OCTA_STREAM_H
2015-06-26 03:30:48 +02:00
#include <stdio.h>
#include <sys/types.h>
#include "octa/types.h"
#include "octa/range.h"
2015-06-26 21:18:40 +02:00
#include "octa/string.h"
#include "octa/type_traits.h"
2015-06-26 03:30:48 +02:00
namespace octa {
2015-06-26 03:30:48 +02:00
/* off_t is POSIX - will also work on windows with mingw/clang, but FIXME */
using StreamOffset = off_t;
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
};
2015-06-26 21:41:11 +02:00
struct Stream: InputRange<
Stream, octa::InputRangeTag, char, char, octa::Size, StreamOffset
2015-06-26 21:18:40 +02:00
> {
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();
2015-06-26 21:18:40 +02:00
if ((p < 0) || !seek(0, StreamSeek::end)) return -1;
2015-06-26 03:30:48 +02:00
Offset e = tell();
2015-06-26 21:18:40 +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
2015-06-26 21:41:11 +02:00
virtual octa::Size read(char *, octa::Size) { return 0; }
virtual octa::Size write(const char *, octa::Size) { return 0; }
2015-06-26 21:18:40 +02:00
/* range interface */
bool empty() const { return end(); }
bool pop_front() {
if (empty()) return false;
2015-06-26 21:41:11 +02:00
char val;
return !!read(&val, 1);
2015-06-26 21:18:40 +02:00
}
2015-06-26 21:41:11 +02:00
char front() const {
2015-06-26 21:18:40 +02:00
Stream *f = (Stream *)this;
2015-06-26 21:41:11 +02:00
char val;
2015-06-26 21:18:40 +02:00
f->seek(-f->read(&val, 1), StreamSeek::cur);
return val;
}
virtual bool equals_front(const Stream &s) const {
return s.tell() == tell();
}
2015-06-26 21:41:11 +02:00
void put(const char &val) {
2015-06-26 21:18:40 +02:00
write(&val, 1);
}
};
enum class StreamMode {
read, write, append,
update = 1 << 2
};
namespace detail {
static const char *filemodes[] = {
"rb", "wb", "ab", nullptr, "rb+", "wb+", "ab+"
};
}
2015-06-26 21:41:11 +02:00
struct FileStream: Stream {
2015-06-26 21:18:40 +02:00
FileStream(): p_f(), p_owned(false) {}
FileStream(const FileStream &s): p_f(s.p_f), p_owned(false) {}
FileStream(const octa::String &path, StreamMode mode): p_f(), p_owned(false) {
open(path, mode);
}
~FileStream() { close(); }
bool open(const octa::String &path, StreamMode mode) {
if (p_f && !p_owned) return false;
p_f = fopen(path.data(), octa::detail::filemodes[octa::Size(mode)]);
p_owned = true;
return p_f != nullptr;
}
void close() {
if (p_owned && 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); }
2015-06-26 21:41:11 +02:00
octa::Size read(char *buf, octa::Size count) {
return fread(buf, 1, count, p_f);
2015-06-26 21:18:40 +02:00
}
2015-06-26 21:41:11 +02:00
octa::Size write(const char *buf, octa::Size count) {
return fwrite(buf, 1, count, p_f);
2015-06-26 21:18:40 +02:00
}
private:
FILE *p_f;
bool p_owned;
2015-06-26 03:30:48 +02:00
};
}
#endif