123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- #ifndef _SIMPLE_FILE_HPP
- #define _SIMPLE_FILE_HPP
- #include <iosfwd>
- #include <type_traits>
- #include <fstream>
- #include <vector>
- #include <string>
- #include <algorithm>
- #include <memory>
- namespace simple
- { namespace file
- {
- using namespace std::literals;
- using std::string;
- using stream = std::fstream;
- using dfltAlloc = std::allocator<char>;
- using size_type = std::streamoff;
- template<typename Alloc = dfltAlloc>
- using buffer = std::vector<char, Alloc>;
- static const string path_delimeters = R"(/\)"s;
- 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 Alloc = dfltAlloc>
- inline void dump(stream& from, buffer<Alloc>& to);
- template<typename Alloc = dfltAlloc>
- inline auto dump(stream& from) -> buffer<Alloc>;
- 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 Alloc = dfltAlloc>
- inline void dump(const buffer<Alloc>& from, stream& to);
- namespace operators
- {
- template<typename Alloc = dfltAlloc>
- inline void operator <<= (buffer<Alloc>& to, stream& from);
- template<typename Alloc = dfltAlloc>
- inline stream& operator <<= (stream& to, const buffer<Alloc>& 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);
- namespace string_stack
- {
- template<typename String = string>
- inline auto top(const String& stack, const String& delimeters = path_delimeters)
- -> typename String::size_type;
- template<typename String = string>
- inline String pop(String& stack, const String& delimeters = path_delimeters);
- template<typename String = string>
- inline void drop(String& stack, const String& delimeters = path_delimeters);
- template<typename String = string>
- inline void push(String& stack, const String& content, const String& delimeters = path_delimeters);
- template <typename String = string>
- class manipulator
- {
- public:
- manipulator(String& on, String delimeters = path_delimeters);
- manipulator(manipulator&& other);
- manipulator&& operator=(manipulator&& other);
- ~manipulator();
- void release();
- String pop();
- void drop();
- manipulator& push(const String& value) &;
- template <typename ...Args>
- manipulator& push(const String& value, Args... args) &;
- manipulator&& push(const String& value) &&;
- template <typename ...Args>
- manipulator&& push(const String& value, Args... args) &&;
- private:
- String* stack;
- unsigned size = 0;
- const String delimeters;
- unsigned dec(unsigned amount = 1);
- manipulator(const manipulator& other) = default;
- manipulator& operator=(const manipulator& other) = default;
- };
- } // namespace string_stack
- /************************ 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)
- {
- file.seekg(0, file.end);
- auto ret = file.tellg();
- return ret;
- }
- 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 Alloc>
- inline void dump(stream& from, buffer<Alloc>& to)
- {
- auto _size = size(from);
- if(-1 == _size)
- return;
- to.resize(_size);
- from.read(to.data(), to.size());
- }
- template<typename Alloc>
- inline auto dump(stream& from) -> buffer<Alloc>
- {
- buffer<Alloc> 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 Alloc>
- inline void dump(const buffer<Alloc>& from, stream& to)
- {
- dump(from.data(), from.size(), to);
- }
- template<typename Alloc>
- inline void operators::operator <<= (buffer<Alloc>& to, stream& from)
- {
- dump(from, to);
- }
- template<typename Alloc>
- inline stream& operators::operator <<= (stream& to, const buffer<Alloc>& from)
- {
- dump(from, to);
- return to;
- }
- inline stream& operators::operator <<= (stream& to, stream& from)
- {
- return to <<= dump(from);
- }
- flags& flags::throws(stream::iostate these)
- {
- exceptions |= these;
- return *this;
- }
- flags& flags::reads()
- {
- io |= stream::in;
- return *this;
- }
- flags& flags::writes()
- {
- io |= stream::out;
- return *this;
- }
- flags& flags::binary()
- {
- io |= stream::binary;
- return *this;
- }
- flags& flags::no_buffer()
- {
- buffering = false;
- return *this;
- }
- 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());
- }
- namespace string_stack
- {
- template<typename String>
- inline auto top(const String& stack, const String& delimeters)
- -> typename String::size_type
- {
- auto end = stack.find_last_not_of(delimeters);
- auto top = stack.find_last_of(delimeters, end);
- // this edge case turns out to be handled rather nicely by the usual case, but leaving the code commented here to indicate the intent
- // if(string::npos == top)
- // top = 0;
- // else
- ++top;
- return top;
- }
- template<typename String>
- inline String pop(String& stack, const String& delimeters)
- {
- auto _top = top(stack, delimeters);
- auto name = stack.substr(_top);
- stack.resize(_top);
- return name;
- }
- template<typename String>
- inline void drop(String& stack, const String& delimeters)
- {
- stack.resize(top(stack, delimeters));
- }
- template<typename String>
- inline void push(String& stack, const String& content, const String& delimeters)
- {
- if(!stack.empty() && delimeters.find(stack.back()) == string::npos)
- stack += delimeters.front();
- stack += content;
- }
- template <typename String>
- unsigned manipulator<String>::dec(unsigned amount)
- {
- return size -= std::min(size, amount);
- }
- template <typename String>
- manipulator<String>::manipulator(String& on, String delimeters)
- : stack(&on), delimeters(delimeters)
- {}
- template <typename String>
- manipulator<String>::manipulator(manipulator&& other) : manipulator(other)
- {
- other.release();
- }
- template <typename String>
- manipulator<String>&& manipulator<String>::operator=(manipulator&& other)
- {
- *this = other;
- other.release();
- return *this;
- }
- template <typename String>
- manipulator<String>::~manipulator()
- {
- while(size)
- drop();
- }
- template <typename String>
- void manipulator<String>::release()
- {
- size = 0;
- }
- template <typename String>
- String manipulator<String>::pop()
- {
- dec();
- return string_stack::pop(*stack, delimeters);
- };
- template <typename String>
- void manipulator<String>::drop()
- {
- string_stack::drop(*stack, delimeters);
- dec();
- };
- template <typename String>
- auto manipulator<String>::push(const String& value) &
- -> manipulator<String>&
- {
- if(!value.empty())
- {
- string_stack::push(*stack, value, delimeters);
- ++size;
- }
- return *this;
- }
- template <typename String>
- template <typename ...Args>
- auto manipulator<String>::push(const String& value, Args... args) &
- -> manipulator<String>&
- {
- push(value);
- return push(args...);
- }
- template <typename String>
- auto manipulator<String>::push(const String& value) &&
- -> manipulator<String>&&
- {
- push(value);
- return std::move(*this);
- }
- template <typename String>
- template <typename ...Args>
- auto manipulator<String>::push(const String& value, Args... args) &&
- -> manipulator<String>&&
- {
- std::move(*this).push(value);
- return std::move(*this).push(args...);
- }
- } // namespace string_stack
- // rvalue variants
- inline void dump(stream&& from, char* to, size_type this_much)
- { dump(from, to, this_much); }
- template<typename Alloc = dfltAlloc>
- inline void dump(stream&& from, buffer<Alloc>& to)
- { dump(from, to); }
- template<typename Alloc = dfltAlloc>
- inline auto dump(stream&& from) -> buffer<Alloc>
- { return dump(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 Alloc = dfltAlloc>
- inline void dump(const buffer<Alloc>& from, stream&& to)
- { dump(from, to); }
- namespace operators
- {
- inline stream& operator <<= (stream& to, stream&& from)
- { return to <<= from; }
- template<typename Alloc = dfltAlloc>
- inline void operator <<= (buffer<Alloc>& to, stream&& from)
- { to <<= from; }
- template<typename Alloc = dfltAlloc>
- inline stream&& operator <<= (stream&& to, const buffer<Alloc>& 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 */
|