diff --git a/src/imemfile.cpp b/src/imemfile.cpp new file mode 100644 index 0000000..196d3e3 --- /dev/null +++ b/src/imemfile.cpp @@ -0,0 +1,14 @@ +#include "libscio.hpp" + +sc::io::imemfile::imemfile(const std::string& path) : std::istream {&_buf}, + _file {path}, + _buf {_file.mapping(), _file.size()} {} + +sc::io::imemfile::imemfile(imemfile&& other) : std::istream {&_buf}, + _file {std::move(other._file)}, + _buf {std::move(other._buf)} {} + +void sc::io::imemfile::open(const std::string& path, std::ios_base::openmode /* mode */) { + _file.open(path); + _buf.init(_file.mapping(), _file.size()); +} diff --git a/src/libscio.hpp b/src/libscio.hpp index 36f49cd..3b4c582 100644 --- a/src/libscio.hpp +++ b/src/libscio.hpp @@ -284,7 +284,7 @@ namespace sc { class mapped_file { public: - mapped_file(); + mapped_file() = default; mapped_file(const std::string& path); // no copying @@ -301,6 +301,7 @@ namespace sc { // it's an error to open an already opened mapped_file // open() is meant to be used after default constructor void open(const std::string& path); + bool is_open() const { return _fd != -1; } // direct (read-only) access to mapped memory char* mapping() const { return _mapping; } @@ -312,6 +313,67 @@ namespace sc { size_t _length {0}; }; + class memstreambuf : public std::streambuf { + public: + memstreambuf() = default; + void init(char* mem, size_t size); + + memstreambuf(char* mem, size_t size); + + void mem(char* m) { _mem = m; } + char* mem() const { return _mem; } + void size(size_t sz) { _size = sz; } + size_t size() const { return _size; } + + protected: + // input + int_type uflow() override; + std::streamsize xsgetn(char* s, std::streamsize n) override; + + // output + int_type overflow(int_type c) override; + std::streamsize xsputn(const char* s, std::streamsize num) override; + + // stream offset positioning + pos_type seekoff(off_type off, + std::ios_base::seekdir dir, + std::ios_base::openmode which + = std::ios_base::in | std::ios_base::out) override; + pos_type seekpos(pos_type pos, std::ios_base::openmode which + = std::ios_base::in | std::ios_base::out) override; + int_type pbackfail(int_type c = EOF) override; + + private: + char* _mem {nullptr}; + size_t _size {0}; + }; + + class imemfile : public std::istream { + public: + imemfile() : std::istream(&_buf) {} + imemfile(const std::string& path); + + // no copying + imemfile(const imemfile&) = delete; + imemfile& operator=(const imemfile&) = delete; + + // move is allowed + imemfile(imemfile&& other); + imemfile& operator=(imemfile&&) = default; + + ~imemfile() = default; + + bool is_open() const { return _file.is_open(); } + void open(const std::string& path, std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::binary); + + char* data() const { return _file.mapping(); } + size_t size() const { return _file.size(); } + + private: + mapped_file _file; + memstreambuf _buf; + }; } } diff --git a/src/memstreambuf.cpp b/src/memstreambuf.cpp new file mode 100644 index 0000000..eb29e35 --- /dev/null +++ b/src/memstreambuf.cpp @@ -0,0 +1,79 @@ +#include "libscio.hpp" +#include +#include + +sc::io::memstreambuf::memstreambuf(char* mem, size_t size) { + init(mem, size); +} + +void sc::io::memstreambuf::init(char* mem, size_t size) { + _mem = mem; + _size = size; + setg(_mem, _mem, _mem + _size); +} + +std::streambuf::int_type sc::io::memstreambuf::uflow() { + if (gptr() == _mem + _size) return EOF; + char c = *gptr(); + setg(_mem, gptr() + 1, _mem + _size); + return c; +} + +std::streamsize sc::io::memstreambuf::xsgetn(char* s, std::streamsize n) { + std::streamsize left = _mem + _size - gptr(); + std::streamsize tot_read = std::min(left, n); + if (tot_read == 0) return EOF; + std::memcpy(s, gptr(), tot_read); + return tot_read; +} + +std::streambuf::int_type sc::io::memstreambuf::overflow(std::streambuf::int_type c) { + // TODO + // if (c != EOF) { + // int res; + // if ((res = write(_fd, &c, 1)) != 1) { + // return EOF; + // } + // else { + // std::cerr << "write result = " << res << ", errno = " << errno << '\n'; + // } + // } + // _ch = c; + // setp(&_ch, &_ch + 1); + return c; +} + +std::streamsize sc::io::memstreambuf::xsputn(const char* s, std::streamsize num) { + // TODO +// int res = write(_fd, s, num); +// if (res != num) { +// std::cerr << "write result = " << res << ", errno = " << errno << '\n'; +// return EOF; +// } + // return res; + return num; +} + +std::streambuf::pos_type sc::io::memstreambuf::seekoff(std::streambuf::off_type off, + std::ios_base::seekdir dir, + std::ios_base::openmode /*which*/) { + switch (dir) { + case std::ios_base::beg: setg(_mem, _mem + off, _mem + _size); break; + case std::ios_base::end: setg(_mem, _mem + _size - off, _mem + _size); break; + case std::ios_base::cur: setg(_mem, gptr() + off, _mem + _size); break; + default: throw std::runtime_error("invalid seekdir"); + } + return gptr() - _mem; +} + +std::streambuf::pos_type sc::io::memstreambuf::seekpos(std::streambuf::pos_type pos, + std::ios_base::openmode /*which*/) { + setg(_mem, _mem + pos, _mem + _size); + return gptr() - _mem; +} + +std::streambuf::int_type sc::io::memstreambuf::pbackfail(std::streambuf::int_type /*c*/) { + setg(_mem, gptr() - 1, _mem + _size); + if (gptr() < _mem) return EOF; + return 0; +}