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 <stdio.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
2015-06-28 14:39:04 +00:00
|
|
|
#include "octa/types.hh"
|
|
|
|
#include "octa/range.hh"
|
|
|
|
#include "octa/string.hh"
|
|
|
|
#include "octa/type_traits.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
|
|
|
|
|
|
|
/* off_t is POSIX - will also work on windows with mingw/clang, but FIXME */
|
|
|
|
using StreamOffset = off_t;
|
|
|
|
|
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-06-27 00:02:28 +00:00
|
|
|
template<typename T = char, bool = octa::IsPod<T>::value>
|
2015-06-26 20:14:54 +00:00
|
|
|
struct StreamRange;
|
|
|
|
|
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-06-27 01:59:10 +00:00
|
|
|
virtual octa::Size read(void *, octa::Size) { return 0; }
|
|
|
|
virtual octa::Size write(const void *, octa::Size) { return 0; }
|
2015-06-26 19:18:40 +00:00
|
|
|
|
2015-06-27 00:02:28 +00:00
|
|
|
template<typename T = char>
|
|
|
|
StreamRange<T> iter();
|
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-06-27 02:02:00 +00:00
|
|
|
StreamRange<T>, octa::InputRangeTag, T, T, octa::Size, StreamOffset
|
2015-06-26 20:14:54 +00:00
|
|
|
> {
|
2015-06-27 02:19:00 +00:00
|
|
|
StreamRange(): p_stream(), p_size(0) {}
|
|
|
|
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;
|
|
|
|
return !!p_stream->read(&val, sizeof(T));
|
2015-06-26 19:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-27 00:02:28 +00:00
|
|
|
T front() const {
|
|
|
|
T val;
|
|
|
|
p_stream->seek(-p_stream->read(&val, sizeof(T)), StreamSeek::cur);
|
2015-06-26 19:18:40 +00:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2015-06-26 20:14:54 +00:00
|
|
|
virtual bool equals_front(const StreamRange &s) const {
|
|
|
|
return p_stream->tell() == s.p_stream->tell();
|
2015-06-26 19:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-27 00:02:28 +00:00
|
|
|
void put(T val) {
|
2015-06-27 02:19:00 +00:00
|
|
|
p_size += p_stream->write(&val, sizeof(T));
|
2015-06-26 19:18:40 +00:00
|
|
|
}
|
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-06-26 19:18:40 +00:00
|
|
|
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 19:41:11 +00:00
|
|
|
struct FileStream: Stream {
|
2015-06-26 20:14:54 +00:00
|
|
|
FileStream(): p_f() {}
|
2015-06-26 20:20:05 +00:00
|
|
|
FileStream(const FileStream &s) = delete;
|
2015-06-26 19:18:40 +00:00
|
|
|
|
2015-06-26 20:14:54 +00:00
|
|
|
FileStream(const octa::String &path, StreamMode mode): p_f() {
|
2015-06-26 19:18:40 +00:00
|
|
|
open(path, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
~FileStream() { close(); }
|
|
|
|
|
|
|
|
bool open(const octa::String &path, StreamMode mode) {
|
2015-06-26 20:14:54 +00:00
|
|
|
if (p_f) return false;
|
2015-06-26 19:18:40 +00:00
|
|
|
p_f = fopen(path.data(), octa::detail::filemodes[octa::Size(mode)]);
|
|
|
|
return p_f != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void close() {
|
2015-06-26 20:14:54 +00:00
|
|
|
if (p_f) fclose(p_f);
|
2015-06-26 19:18:40 +00:00
|
|
|
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-27 01:59:10 +00:00
|
|
|
octa::Size read(void *buf, octa::Size count) {
|
2015-06-26 19:41:11 +00:00
|
|
|
return fread(buf, 1, count, p_f);
|
2015-06-26 19:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-27 01:59:10 +00:00
|
|
|
octa::Size write(const void *buf, octa::Size count) {
|
2015-06-26 19:41:11 +00:00
|
|
|
return fwrite(buf, 1, count, p_f);
|
2015-06-26 19:18:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
FILE *p_f;
|
2015-06-26 01:30:48 +00:00
|
|
|
};
|
|
|
|
|
2015-05-12 20:27:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|