file.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. #ifndef SIMPLE_FILE_HPP
  2. #define SIMPLE_FILE_HPP
  3. #include <iosfwd>
  4. #include <type_traits>
  5. #include <fstream>
  6. #include <vector>
  7. #include <string>
  8. #include <algorithm>
  9. #include <memory>
  10. #include <limits>
  11. namespace simple
  12. { namespace file
  13. {
  14. //TODO: wow, turns out there are actual file descriptors in POSIX, so need those here too, as an option
  15. // TODO:
  16. // class c_stream_deleter
  17. // {
  18. // public:
  19. // void operator ()(FILE* file) const noexcept;
  20. // };
  21. // using c_stream = std::unique_ptr<FILE, c_stream_deleter>;
  22. using namespace std::literals;
  23. using std::string;
  24. using stream = std::fstream;
  25. using buffer_type = std::vector<char>;
  26. using size_type = std::streamoff;
  27. template<typename Alloc = std::allocator<char>>
  28. using buffer [[deprecated]] = std::vector<char, Alloc>;
  29. inline size_type size(stream& file);
  30. inline size_type size(stream&& file);
  31. inline void dump(stream& from, char* to, size_type this_much);
  32. template<typename Buffer = buffer_type>
  33. inline void dump(stream& from, Buffer& to);
  34. template<typename Buffer = buffer_type>
  35. inline auto dump(stream& from) -> Buffer;
  36. inline void dump(const char* from, size_t this_much, stream& to);
  37. template<int N>
  38. inline void dump(const char from[N], stream& to);
  39. template<typename Buffer = buffer_type>
  40. inline void dump(const Buffer& from, stream& to);
  41. namespace operators
  42. {
  43. template<typename Buffer = buffer_type>
  44. inline void operator <<= (Buffer& to, stream& from);
  45. template<typename Buffer = buffer_type>
  46. inline stream& operator <<= (stream& to, const Buffer& from);
  47. inline stream& operator <<= (stream& to, stream& from);
  48. } // namespace operators
  49. struct flags
  50. {
  51. stream::openmode io;
  52. stream::iostate exceptions = stream::goodbit;
  53. bool buffering = true;
  54. flags& throws(stream::iostate these = stream::badbit | stream::failbit);
  55. flags& reads();
  56. flags& writes();
  57. flags& binary();
  58. flags& no_buffer();
  59. };
  60. inline stream open(const string& name, flags options = {stream::in | stream::out});
  61. inline stream ropen(const string& name);
  62. inline stream wopen(const string& name);
  63. inline stream bopen(const string& name, flags options = {stream::in | stream::out});
  64. inline stream bropen(const string& name);
  65. inline stream bwopen(const string& name);
  66. inline stream opex(const string& name, flags options = {stream::in | stream::out});
  67. inline stream ropex(const string& name);
  68. inline stream wopex(const string& name);
  69. inline stream bopex(const string& name, flags options = {stream::in | stream::out});
  70. inline stream bropex(const string& name);
  71. inline stream bwopex(const string& name);
  72. /************************ implementation ************************/
  73. inline size_type size(stream& file)
  74. {
  75. auto current = file.tellg();
  76. auto ret = size(std::move(file));
  77. file.seekg(current);
  78. return ret;
  79. }
  80. inline size_type size(stream&& file)
  81. {
  82. // TODO FIXME: does not work on text steams and generally is undefined behavior apparently -_-
  83. file.seekg(0, file.end);
  84. auto ret = file.tellg();
  85. return ret;
  86. }
  87. // supa slow way
  88. inline std::streamsize defined_size(stream& file)
  89. {
  90. file.ignore( std::numeric_limits<std::streamsize>::max() );
  91. std::streamsize size = file.gcount();
  92. file.clear();
  93. file.seekg( 0, file.beg );
  94. return size;
  95. }
  96. // just read it (trollface)
  97. inline void dump(stream& from, char* to, size_type this_much)
  98. {
  99. auto _size = size(from);
  100. if(-1 != _size)
  101. from.read(to, std::min(_size, this_much));
  102. }
  103. template<typename Buffer>
  104. inline void dump(stream& from, Buffer& to)
  105. {
  106. auto _size = size(from);
  107. if(-1 == _size)
  108. return;
  109. to.resize(_size);
  110. from.read(reinterpret_cast<char*>(to.data()), sizeof(*to.data())*to.size());
  111. }
  112. template<typename Buffer>
  113. inline auto dump(stream& from) -> Buffer
  114. {
  115. Buffer to;
  116. dump(from, to);
  117. return to;
  118. }
  119. inline void dump(const char* from, size_t this_much, stream& to)
  120. {
  121. to.write(from, this_much);
  122. }
  123. template<int N>
  124. inline void dump(const char from[N], stream& to)
  125. {
  126. to.write(from, N);
  127. }
  128. template<typename Buffer>
  129. inline void dump(const Buffer& from, stream& to)
  130. {
  131. dump(reinterpret_cast<const char*>(from.data()), sizeof(*from.data())*from.size(), to);
  132. }
  133. template<typename Buffer>
  134. inline void operators::operator <<= (Buffer& to, stream& from)
  135. {
  136. dump(from, to);
  137. }
  138. template<typename Buffer>
  139. inline stream& operators::operator <<= (stream& to, const Buffer& from)
  140. {
  141. dump(from, to);
  142. return to;
  143. }
  144. inline stream& operators::operator <<= (stream& to, stream& from)
  145. {
  146. return to <<= dump(from);
  147. }
  148. inline flags& flags::throws(stream::iostate these)
  149. {
  150. exceptions |= these;
  151. return *this;
  152. }
  153. inline flags& flags::reads()
  154. {
  155. io |= stream::in;
  156. return *this;
  157. }
  158. inline flags& flags::writes()
  159. {
  160. io |= stream::out;
  161. return *this;
  162. }
  163. inline flags& flags::binary()
  164. {
  165. io |= stream::binary;
  166. return *this;
  167. }
  168. inline flags& flags::no_buffer()
  169. {
  170. buffering = false;
  171. return *this;
  172. }
  173. // accept anything fstream::open accepts
  174. // also why does fstream::open not accept the same things constructor does? hmm std??
  175. inline stream open (const string& name, flags options)
  176. {
  177. stream file;
  178. file.exceptions(options.exceptions);
  179. if(!options.buffering)
  180. file.rdbuf()->pubsetbuf(0, 0);
  181. file.open(name, options.io);
  182. return file;
  183. }
  184. inline stream ropen(const string& name)
  185. {
  186. return open(name, flags{}.reads());
  187. }
  188. inline stream wopen(const string& name)
  189. {
  190. return open(name, flags{}.writes());
  191. }
  192. inline stream bopen(const string& name, flags options)
  193. {
  194. return open(name, options.binary());
  195. }
  196. inline stream bropen(const string& name)
  197. {
  198. return open(name, flags{}.reads().binary());
  199. }
  200. inline stream bwopen(const string& name)
  201. {
  202. return open(name, flags{}.writes().binary());
  203. }
  204. inline stream opex(const string& name, flags options)
  205. {
  206. return open(name, options.throws());
  207. }
  208. inline stream ropex(const string& name)
  209. {
  210. return open(name, flags{}.reads().throws());
  211. }
  212. inline stream wopex(const string& name)
  213. {
  214. return open(name, flags{}.writes().throws());
  215. }
  216. inline stream bopex(const string& name, flags options)
  217. {
  218. return open(name, options.binary().throws());
  219. }
  220. inline stream bropex(const string& name)
  221. {
  222. return open(name, flags{}.reads().binary().throws());
  223. }
  224. inline stream bwopex(const string& name)
  225. {
  226. return open(name, flags{}.writes().binary().throws());
  227. }
  228. // rvalue variants
  229. inline void dump(stream&& from, char* to, size_type this_much)
  230. { dump(from, to, this_much); }
  231. template<typename Buffer = buffer_type>
  232. inline void dump(stream&& from, Buffer& to)
  233. { dump(from, to); }
  234. template<typename Buffer = buffer_type>
  235. inline auto dump(stream&& from) -> Buffer
  236. { return dump<Buffer>(from); }
  237. inline void dump(const char* from, size_t this_much, stream&& to)
  238. { dump(from, this_much, to); }
  239. template<int N>
  240. inline void dump(const char from[N], stream&& to)
  241. { dump<N>(from, to); }
  242. template<typename Buffer = buffer_type>
  243. inline void dump(const Buffer& from, stream&& to)
  244. { dump(from, to); }
  245. namespace operators
  246. {
  247. inline stream& operator <<= (stream& to, stream&& from)
  248. { return to <<= from; }
  249. template<typename Buffer = buffer_type>
  250. inline void operator <<= (Buffer& to, stream&& from)
  251. { to <<= from; }
  252. template<typename Buffer = buffer_type>
  253. inline stream&& operator <<= (stream&& to, const Buffer& from)
  254. { return std::move(to <<= from); }
  255. inline stream&& operator <<= (stream&& to, stream&& from)
  256. { return std::move(to <<= from); }
  257. }
  258. }} // namespace simple::file
  259. #endif /* end of include guard */