file.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  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. namespace simple
  11. { namespace file
  12. {
  13. using namespace std::literals;
  14. using std::string;
  15. using stream = std::fstream;
  16. using dfltAlloc = std::allocator<char>;
  17. using size_type = std::streamoff;
  18. template<typename Alloc = dfltAlloc>
  19. using buffer = std::vector<char, Alloc>;
  20. static const string path_delimeters = R"(/\)"s;
  21. inline size_type size(stream& file);
  22. inline size_type size(stream&& file);
  23. inline void dump(stream& from, char* to, size_type this_much);
  24. template<typename Alloc = dfltAlloc>
  25. inline void dump(stream& from, buffer<Alloc>& to);
  26. template<typename Alloc = dfltAlloc>
  27. inline auto dump(stream& from) -> buffer<Alloc>;
  28. inline void dump(const char* from, size_t this_much, stream& to);
  29. template<int N>
  30. inline void dump(const char from[N], stream& to);
  31. template<typename Alloc = dfltAlloc>
  32. inline void dump(const buffer<Alloc>& from, stream& to);
  33. namespace operators
  34. {
  35. template<typename Alloc = dfltAlloc>
  36. inline void operator <<= (buffer<Alloc>& to, stream& from);
  37. template<typename Alloc = dfltAlloc>
  38. inline stream& operator <<= (stream& to, const buffer<Alloc>& from);
  39. inline stream& operator <<= (stream& to, stream& from);
  40. } // namespace operators
  41. struct flags
  42. {
  43. stream::openmode io;
  44. stream::iostate exceptions = stream::goodbit;
  45. bool buffering = true;
  46. flags& throws(stream::iostate these = stream::badbit | stream::failbit);
  47. flags& reads();
  48. flags& writes();
  49. flags& binary();
  50. flags& no_buffer();
  51. };
  52. inline stream open(const string& name, flags options = {stream::in | stream::out});
  53. inline stream ropen(const string& name);
  54. inline stream wopen(const string& name);
  55. inline stream bopen(const string& name, flags options = {stream::in | stream::out});
  56. inline stream bropen(const string& name);
  57. inline stream bwopen(const string& name);
  58. inline stream opex(const string& name, flags options = {stream::in | stream::out});
  59. inline stream ropex(const string& name);
  60. inline stream wopex(const string& name);
  61. inline stream bopex(const string& name, flags options = {stream::in | stream::out});
  62. inline stream bropex(const string& name);
  63. inline stream bwopex(const string& name);
  64. namespace string_stack
  65. {
  66. template<typename String = string>
  67. inline auto top(const String& stack, const String& delimeters = path_delimeters)
  68. -> typename String::size_type;
  69. template<typename String = string>
  70. inline String pop(String& stack, const String& delimeters = path_delimeters);
  71. template<typename String = string>
  72. inline void drop(String& stack, const String& delimeters = path_delimeters);
  73. template<typename String = string>
  74. inline void push(String& stack, const String& content, const String& delimeters = path_delimeters);
  75. template <typename String = string>
  76. class manipulator
  77. {
  78. public:
  79. manipulator(String& on, String delimeters = path_delimeters);
  80. manipulator(manipulator&& other);
  81. manipulator&& operator=(manipulator&& other);
  82. ~manipulator();
  83. void release();
  84. String pop();
  85. void drop();
  86. manipulator& push(const String& value) &;
  87. template <typename ...Args>
  88. manipulator& push(const String& value, Args... args) &;
  89. manipulator&& push(const String& value) &&;
  90. template <typename ...Args>
  91. manipulator&& push(const String& value, Args... args) &&;
  92. private:
  93. String* stack;
  94. unsigned size = 0;
  95. const String delimeters;
  96. unsigned dec(unsigned amount = 1);
  97. manipulator(const manipulator& other) = default;
  98. manipulator& operator=(const manipulator& other) = default;
  99. };
  100. } // namespace string_stack
  101. /************************ implementation ************************/
  102. inline size_type size(stream& file)
  103. {
  104. auto current = file.tellg();
  105. auto ret = size(std::move(file));
  106. file.seekg(current);
  107. return ret;
  108. }
  109. inline size_type size(stream&& file)
  110. {
  111. file.seekg(0, file.end);
  112. auto ret = file.tellg();
  113. return ret;
  114. }
  115. inline void dump(stream& from, char* to, size_type this_much)
  116. {
  117. auto _size = size(from);
  118. if(-1 != _size)
  119. from.read(to, std::min(_size, this_much));
  120. }
  121. template<typename Alloc>
  122. inline void dump(stream& from, buffer<Alloc>& to)
  123. {
  124. auto _size = size(from);
  125. if(-1 == _size)
  126. return;
  127. to.resize(_size);
  128. from.read(to.data(), to.size());
  129. }
  130. template<typename Alloc>
  131. inline auto dump(stream& from) -> buffer<Alloc>
  132. {
  133. buffer<Alloc> to;
  134. dump(from, to);
  135. return to;
  136. }
  137. inline void dump(const char* from, size_t this_much, stream& to)
  138. {
  139. to.write(from, this_much);
  140. }
  141. template<int N>
  142. inline void dump(const char from[N], stream& to)
  143. {
  144. to.write(from, N);
  145. }
  146. template<typename Alloc>
  147. inline void dump(const buffer<Alloc>& from, stream& to)
  148. {
  149. dump(from.data(), from.size(), to);
  150. }
  151. template<typename Alloc>
  152. inline void operators::operator <<= (buffer<Alloc>& to, stream& from)
  153. {
  154. dump(from, to);
  155. }
  156. template<typename Alloc>
  157. inline stream& operators::operator <<= (stream& to, const buffer<Alloc>& from)
  158. {
  159. dump(from, to);
  160. return to;
  161. }
  162. inline stream& operators::operator <<= (stream& to, stream& from)
  163. {
  164. return to <<= dump(from);
  165. }
  166. flags& flags::throws(stream::iostate these)
  167. {
  168. exceptions |= these;
  169. return *this;
  170. }
  171. flags& flags::reads()
  172. {
  173. io |= stream::in;
  174. return *this;
  175. }
  176. flags& flags::writes()
  177. {
  178. io |= stream::out;
  179. return *this;
  180. }
  181. flags& flags::binary()
  182. {
  183. io |= stream::binary;
  184. return *this;
  185. }
  186. flags& flags::no_buffer()
  187. {
  188. buffering = false;
  189. return *this;
  190. }
  191. inline stream open (const string& name, flags options)
  192. {
  193. stream file;
  194. file.exceptions(options.exceptions);
  195. if(!options.buffering)
  196. file.rdbuf()->pubsetbuf(0, 0);
  197. file.open(name, options.io);
  198. return file;
  199. }
  200. inline stream ropen(const string& name)
  201. {
  202. return open(name, flags{}.reads());
  203. }
  204. inline stream wopen(const string& name)
  205. {
  206. return open(name, flags{}.writes());
  207. }
  208. inline stream bopen(const string& name, flags options)
  209. {
  210. return open(name, options.binary());
  211. }
  212. inline stream bropen(const string& name)
  213. {
  214. return open(name, flags{}.reads().binary());
  215. }
  216. inline stream bwopen(const string& name)
  217. {
  218. return open(name, flags{}.writes().binary());
  219. }
  220. inline stream opex(const string& name, flags options)
  221. {
  222. return open(name, options.throws());
  223. }
  224. inline stream ropex(const string& name)
  225. {
  226. return open(name, flags{}.reads().throws());
  227. }
  228. inline stream wopex(const string& name)
  229. {
  230. return open(name, flags{}.writes().throws());
  231. }
  232. inline stream bopex(const string& name, flags options)
  233. {
  234. return open(name, options.binary().throws());
  235. }
  236. inline stream bropex(const string& name)
  237. {
  238. return open(name, flags{}.reads().binary().throws());
  239. }
  240. inline stream bwopex(const string& name)
  241. {
  242. return open(name, flags{}.writes().binary().throws());
  243. }
  244. namespace string_stack
  245. {
  246. template<typename String>
  247. inline auto top(const String& stack, const String& delimeters)
  248. -> typename String::size_type
  249. {
  250. auto end = stack.find_last_not_of(delimeters);
  251. auto top = stack.find_last_of(delimeters, end);
  252. // this edge case turns out to be handled rather nicely by the usual case, but leaving the code commented here to indicate the intent
  253. // if(string::npos == top)
  254. // top = 0;
  255. // else
  256. ++top;
  257. return top;
  258. }
  259. template<typename String>
  260. inline String pop(String& stack, const String& delimeters)
  261. {
  262. auto _top = top(stack, delimeters);
  263. auto name = stack.substr(_top);
  264. stack.resize(_top);
  265. return name;
  266. }
  267. template<typename String>
  268. inline void drop(String& stack, const String& delimeters)
  269. {
  270. stack.resize(top(stack, delimeters));
  271. }
  272. template<typename String>
  273. inline void push(String& stack, const String& content, const String& delimeters)
  274. {
  275. if(!stack.empty() && delimeters.find(stack.back()) == string::npos)
  276. stack += delimeters.front();
  277. stack += content;
  278. }
  279. template <typename String>
  280. unsigned manipulator<String>::dec(unsigned amount)
  281. {
  282. return size -= std::min(size, amount);
  283. }
  284. template <typename String>
  285. manipulator<String>::manipulator(String& on, String delimeters)
  286. : stack(&on), delimeters(delimeters)
  287. {}
  288. template <typename String>
  289. manipulator<String>::manipulator(manipulator&& other) : manipulator(other)
  290. {
  291. other.release();
  292. }
  293. template <typename String>
  294. manipulator<String>&& manipulator<String>::operator=(manipulator&& other)
  295. {
  296. *this = other;
  297. other.release();
  298. return *this;
  299. }
  300. template <typename String>
  301. manipulator<String>::~manipulator()
  302. {
  303. while(size)
  304. drop();
  305. }
  306. template <typename String>
  307. void manipulator<String>::release()
  308. {
  309. size = 0;
  310. }
  311. template <typename String>
  312. String manipulator<String>::pop()
  313. {
  314. dec();
  315. return string_stack::pop(*stack, delimeters);
  316. };
  317. template <typename String>
  318. void manipulator<String>::drop()
  319. {
  320. string_stack::drop(*stack, delimeters);
  321. dec();
  322. };
  323. template <typename String>
  324. auto manipulator<String>::push(const String& value) &
  325. -> manipulator<String>&
  326. {
  327. if(!value.empty())
  328. {
  329. string_stack::push(*stack, value, delimeters);
  330. ++size;
  331. }
  332. return *this;
  333. }
  334. template <typename String>
  335. template <typename ...Args>
  336. auto manipulator<String>::push(const String& value, Args... args) &
  337. -> manipulator<String>&
  338. {
  339. push(value);
  340. return push(args...);
  341. }
  342. template <typename String>
  343. auto manipulator<String>::push(const String& value) &&
  344. -> manipulator<String>&&
  345. {
  346. push(value);
  347. return std::move(*this);
  348. }
  349. template <typename String>
  350. template <typename ...Args>
  351. auto manipulator<String>::push(const String& value, Args... args) &&
  352. -> manipulator<String>&&
  353. {
  354. std::move(*this).push(value);
  355. return std::move(*this).push(args...);
  356. }
  357. } // namespace string_stack
  358. // rvalue variants
  359. inline void dump(stream&& from, char* to, size_type this_much)
  360. { dump(from, to, this_much); }
  361. template<typename Alloc = dfltAlloc>
  362. inline void dump(stream&& from, buffer<Alloc>& to)
  363. { dump(from, to); }
  364. template<typename Alloc = dfltAlloc>
  365. inline auto dump(stream&& from) -> buffer<Alloc>
  366. { return dump(from); }
  367. inline void dump(const char* from, size_t this_much, stream&& to)
  368. { dump(from, this_much, to); }
  369. template<int N>
  370. inline void dump(const char from[N], stream&& to)
  371. { dump<N>(from, to); }
  372. template<typename Alloc = dfltAlloc>
  373. inline void dump(const buffer<Alloc>& from, stream&& to)
  374. { dump(from, to); }
  375. namespace operators
  376. {
  377. inline stream& operator <<= (stream& to, stream&& from)
  378. { return to <<= from; }
  379. template<typename Alloc = dfltAlloc>
  380. inline void operator <<= (buffer<Alloc>& to, stream&& from)
  381. { to <<= from; }
  382. template<typename Alloc = dfltAlloc>
  383. inline stream&& operator <<= (stream&& to, const buffer<Alloc>& from)
  384. { return std::move(to <<= from); }
  385. inline stream&& operator <<= (stream&& to, stream&& from)
  386. { return std::move(to <<= from); }
  387. }
  388. }} // namespace simple::file
  389. #endif /* end of include guard */