123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- #ifndef SIMPLE_FILE_HPP
- #define SIMPLE_FILE_HPP
- #include <iosfwd>
- #include <type_traits>
- #include <fstream>
- #include <vector>
- #include <string>
- #include <algorithm>
- #include <memory>
- #include <limits>
- namespace simple
- { namespace file
- {
- //TODO: wow, turns out there are actual file descriptors in POSIX, so need those here too, as an option
- // TODO:
- // class c_stream_deleter
- // {
- // public:
- // void operator ()(FILE* file) const noexcept;
- // };
- // using c_stream = std::unique_ptr<FILE, c_stream_deleter>;
- using namespace std::literals;
- using std::string;
- using stream = std::fstream;
- using buffer_type = std::vector<char>;
- using size_type = std::streamoff;
- template<typename Alloc = std::allocator<char>>
- using buffer [[deprecated]] = std::vector<char, Alloc>;
- inline size_type size(stream& file);
- inline size_type size(stream&& file);
- inline void dump(stream& from, char* to, size_type this_much);
- template<typename Buffer = buffer_type>
- inline void dump(stream& from, Buffer& to);
- template<typename Buffer = buffer_type>
- inline auto dump(stream& from) -> Buffer;
- inline void dump(const char* from, size_t this_much, stream& to);
- template<int N>
- inline void dump(const char from[N], stream& to);
- template<typename Buffer = buffer_type>
- inline void dump(const Buffer& from, stream& to);
- namespace operators
- {
- template<typename Buffer = buffer_type>
- inline void operator <<= (Buffer& to, stream& from);
- template<typename Buffer = buffer_type>
- inline stream& operator <<= (stream& to, const Buffer& from);
- inline stream& operator <<= (stream& to, stream& from);
- } // namespace operators
- struct flags
- {
- stream::openmode io;
- stream::iostate exceptions = stream::goodbit;
- bool buffering = true;
- flags& throws(stream::iostate these = stream::badbit | stream::failbit);
- flags& reads();
- flags& writes();
- flags& binary();
- flags& no_buffer();
- };
- inline stream open(const string& name, flags options = {stream::in | stream::out});
- inline stream ropen(const string& name);
- inline stream wopen(const string& name);
- inline stream bopen(const string& name, flags options = {stream::in | stream::out});
- inline stream bropen(const string& name);
- inline stream bwopen(const string& name);
- inline stream opex(const string& name, flags options = {stream::in | stream::out});
- inline stream ropex(const string& name);
- inline stream wopex(const string& name);
- inline stream bopex(const string& name, flags options = {stream::in | stream::out});
- inline stream bropex(const string& name);
- inline stream bwopex(const string& name);
- /************************ implementation ************************/
- inline size_type size(stream& file)
- {
- auto current = file.tellg();
- auto ret = size(std::move(file));
- file.seekg(current);
- return ret;
- }
- inline size_type size(stream&& file)
- {
- // TODO FIXME: does not work on text steams and generally is undefined behavior apparently -_-
- file.seekg(0, file.end);
- auto ret = file.tellg();
- return ret;
- }
- // supa slow way
- inline std::streamsize defined_size(stream& file)
- {
- file.ignore( std::numeric_limits<std::streamsize>::max() );
- std::streamsize size = file.gcount();
- file.clear();
- file.seekg( 0, file.beg );
- return size;
- }
- // just read it (trollface)
- inline void dump(stream& from, char* to, size_type this_much)
- {
- auto _size = size(from);
- if(-1 != _size)
- from.read(to, std::min(_size, this_much));
- }
- template<typename Buffer>
- inline void dump(stream& from, Buffer& to)
- {
- auto _size = size(from);
- if(-1 == _size)
- return;
- to.resize(_size);
- from.read(reinterpret_cast<char*>(to.data()), sizeof(*to.data())*to.size());
- }
- template<typename Buffer>
- inline auto dump(stream& from) -> Buffer
- {
- Buffer to;
- dump(from, to);
- return to;
- }
- inline void dump(const char* from, size_t this_much, stream& to)
- {
- to.write(from, this_much);
- }
- template<int N>
- inline void dump(const char from[N], stream& to)
- {
- to.write(from, N);
- }
- template<typename Buffer>
- inline void dump(const Buffer& from, stream& to)
- {
- dump(reinterpret_cast<const char*>(from.data()), sizeof(*from.data())*from.size(), to);
- }
- template<typename Buffer>
- inline void operators::operator <<= (Buffer& to, stream& from)
- {
- dump(from, to);
- }
- template<typename Buffer>
- inline stream& operators::operator <<= (stream& to, const Buffer& from)
- {
- dump(from, to);
- return to;
- }
- inline stream& operators::operator <<= (stream& to, stream& from)
- {
- return to <<= dump(from);
- }
- inline flags& flags::throws(stream::iostate these)
- {
- exceptions |= these;
- return *this;
- }
- inline flags& flags::reads()
- {
- io |= stream::in;
- return *this;
- }
- inline flags& flags::writes()
- {
- io |= stream::out;
- return *this;
- }
- inline flags& flags::binary()
- {
- io |= stream::binary;
- return *this;
- }
- inline flags& flags::no_buffer()
- {
- buffering = false;
- return *this;
- }
- // accept anything fstream::open accepts
- // also why does fstream::open not accept the same things constructor does? hmm std??
- inline stream open (const string& name, flags options)
- {
- stream file;
- file.exceptions(options.exceptions);
- if(!options.buffering)
- file.rdbuf()->pubsetbuf(0, 0);
- file.open(name, options.io);
- return file;
- }
- inline stream ropen(const string& name)
- {
- return open(name, flags{}.reads());
- }
- inline stream wopen(const string& name)
- {
- return open(name, flags{}.writes());
- }
- inline stream bopen(const string& name, flags options)
- {
- return open(name, options.binary());
- }
- inline stream bropen(const string& name)
- {
- return open(name, flags{}.reads().binary());
- }
- inline stream bwopen(const string& name)
- {
- return open(name, flags{}.writes().binary());
- }
- inline stream opex(const string& name, flags options)
- {
- return open(name, options.throws());
- }
- inline stream ropex(const string& name)
- {
- return open(name, flags{}.reads().throws());
- }
- inline stream wopex(const string& name)
- {
- return open(name, flags{}.writes().throws());
- }
- inline stream bopex(const string& name, flags options)
- {
- return open(name, options.binary().throws());
- }
- inline stream bropex(const string& name)
- {
- return open(name, flags{}.reads().binary().throws());
- }
- inline stream bwopex(const string& name)
- {
- return open(name, flags{}.writes().binary().throws());
- }
- // rvalue variants
- inline void dump(stream&& from, char* to, size_type this_much)
- { dump(from, to, this_much); }
- template<typename Buffer = buffer_type>
- inline void dump(stream&& from, Buffer& to)
- { dump(from, to); }
- template<typename Buffer = buffer_type>
- inline auto dump(stream&& from) -> Buffer
- { return dump<Buffer>(from); }
- inline void dump(const char* from, size_t this_much, stream&& to)
- { dump(from, this_much, to); }
- template<int N>
- inline void dump(const char from[N], stream&& to)
- { dump<N>(from, to); }
- template<typename Buffer = buffer_type>
- inline void dump(const Buffer& from, stream&& to)
- { dump(from, to); }
- namespace operators
- {
- inline stream& operator <<= (stream& to, stream&& from)
- { return to <<= from; }
- template<typename Buffer = buffer_type>
- inline void operator <<= (Buffer& to, stream&& from)
- { to <<= from; }
- template<typename Buffer = buffer_type>
- inline stream&& operator <<= (stream&& to, const Buffer& from)
- { return std::move(to <<= from); }
- inline stream&& operator <<= (stream&& to, stream&& from)
- { return std::move(to <<= from); }
- }
- }} // namespace simple::file
- #endif /* end of include guard */
|