filebuf.h
Upload User: ijipin
Upload Date: 2019-09-11
Package Size: 10044k
Code Size: 9k
Development Platform:

C/C++

  1. /*
  2.  * filebuf.h
  3.  *
  4.  *      Author: Ben Langmead
  5.  */
  6. #ifndef FILEBUF_H_
  7. #define FILEBUF_H_
  8. #include <iostream>
  9. #include <fstream>
  10. #include <string>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <stdint.h>
  14. #include <stdexcept>
  15. #include "assert_helpers.h"
  16. /**
  17.  * Simple wrapper for a FILE*, istream or ifstream that reads it in
  18.  * chunks (with fread) and keeps those chunks in a buffer.  It also
  19.  * services calls to get(), peek() and gets() from the buffer, reading
  20.  * in additional chunks when necessary.
  21.  */
  22. class FileBuf {
  23. public:
  24. FileBuf() {
  25. init();
  26. }
  27. FileBuf(FILE *in) {
  28. init();
  29. _in = in;
  30. assert(_in != NULL);
  31. }
  32. FileBuf(std::ifstream *inf) {
  33. init();
  34. _inf = inf;
  35. assert(_inf != NULL);
  36. }
  37. FileBuf(std::istream *ins) {
  38. init();
  39. _ins = ins;
  40. assert(_ins != NULL);
  41. }
  42. bool isOpen() {
  43. return _in != NULL || _inf != NULL || _ins != NULL;
  44. }
  45. /**
  46.  * Close the input stream (if that's possible)
  47.  */
  48. void close() {
  49. if(_in != NULL && _in != stdin) {
  50. fclose(_in);
  51. } else if(_inf != NULL) {
  52. _inf->close();
  53. } else {
  54. // can't close _ins
  55. }
  56. }
  57. /**
  58.  * Get the next character of input and advance.
  59.  */
  60. int get() {
  61. assert(_in != NULL || _inf != NULL || _ins != NULL);
  62. int c = peek();
  63. if(c != -1) {
  64. _cur++;
  65. if(_lastn_cur < LASTN_BUF_SZ) _lastn_buf[_lastn_cur++] = c;
  66. }
  67. return c;
  68. }
  69. /**
  70.  * Return true iff all input is exhausted.
  71.  */
  72. bool eof() {
  73. return (_cur == _buf_sz) && _done;
  74. }
  75. /**
  76.  * Initialize the buffer with a new C-style file.
  77.  */
  78. void newFile(FILE *in) {
  79. _in = in;
  80. _inf = NULL;
  81. _ins = NULL;
  82. _cur = BUF_SZ;
  83. _buf_sz = BUF_SZ;
  84. _done = false;
  85. }
  86. /**
  87.  * Initialize the buffer with a new ifstream.
  88.  */
  89. void newFile(std::ifstream *__inf) {
  90. _in = NULL;
  91. _inf = __inf;
  92. _ins = NULL;
  93. _cur = BUF_SZ;
  94. _buf_sz = BUF_SZ;
  95. _done = false;
  96. }
  97. /**
  98.  * Initialize the buffer with a new istream.
  99.  */
  100. void newFile(std::istream *__ins) {
  101. _in = NULL;
  102. _inf = NULL;
  103. _ins = __ins;
  104. _cur = BUF_SZ;
  105. _buf_sz = BUF_SZ;
  106. _done = false;
  107. }
  108. /**
  109.  * Restore state as though we just started reading the input
  110.  * stream.
  111.  */
  112. void reset() {
  113. if(_inf != NULL) {
  114. _inf->clear();
  115. _inf->seekg(0, std::ios::beg);
  116. } else if(_ins != NULL) {
  117. _ins->clear();
  118. _ins->seekg(0, std::ios::beg);
  119. } else {
  120. rewind(_in);
  121. }
  122. _cur = BUF_SZ;
  123. _buf_sz = BUF_SZ;
  124. _done = false;
  125. }
  126. /**
  127.  * Peek at the next character of the input stream without
  128.  * advancing.  Typically we can simple read it from the buffer.
  129.  * Occasionally we'll need to read in a new buffer's worth of data.
  130.  */
  131. int peek() {
  132. assert(_in != NULL || _inf != NULL || _ins != NULL);
  133. assert_leq(_cur, _buf_sz);
  134. if(_cur == _buf_sz) {
  135. if(_done) {
  136. // We already exhausted the input stream
  137. return -1;
  138. }
  139. // Read a new buffer's worth of data
  140. else {
  141. // Get the next chunk
  142. if(_inf != NULL) {
  143. _inf->read((char*)_buf, BUF_SZ);
  144. _buf_sz = _inf->gcount();
  145. } else if(_ins != NULL) {
  146. _ins->read((char*)_buf, BUF_SZ);
  147. _buf_sz = _ins->gcount();
  148. } else {
  149. assert(_in != NULL);
  150. _buf_sz = fread(_buf, 1, BUF_SZ, _in);
  151. }
  152. _cur = 0;
  153. if(_buf_sz == 0) {
  154. // Exhausted, and we have nothing to return to the
  155. // caller
  156. _done = true;
  157. return -1;
  158. } else if(_buf_sz < BUF_SZ) {
  159. // Exhausted
  160. _done = true;
  161. }
  162. }
  163. }
  164. return (int)_buf[_cur];
  165. }
  166. /**
  167.  * Store a string of characters from the input file into 'buf',
  168.  * until we see a newline, EOF, or until 'len' characters have been
  169.  * read.
  170.  */
  171. size_t gets(char *buf, size_t len) {
  172. size_t stored = 0;
  173. while(true) {
  174. int c = get();
  175. if(c == -1) {
  176. // End-of-file
  177. buf[stored] = '';
  178. return stored;
  179. }
  180. if(stored == len-1 || c == 'n' || c == 'r') {
  181. // End of string
  182. buf[stored] = '';
  183. // Skip over all end-of-line characters
  184. int pc = peek();
  185. while(pc == 'n' || pc == 'r') {
  186. get(); // discard
  187. pc = peek();
  188. }
  189. // Next get() will be after all newline characters
  190. return stored;
  191. }
  192. buf[stored++] = (char)c;
  193. }
  194. }
  195. /**
  196.  * Store a string of characters from the input file into 'buf',
  197.  * until we see a newline, EOF, or until 'len' characters have been
  198.  * read.
  199.  */
  200. size_t get(char *buf, size_t len) {
  201. size_t stored = 0;
  202. for(size_t i = 0; i < len; i++) {
  203. int c = get();
  204. if(c == -1) return i;
  205. buf[stored++] = (char)c;
  206. }
  207. return len;
  208. }
  209. static const size_t LASTN_BUF_SZ = 8 * 1024;
  210. /**
  211.  * Reset to the beginning of the last-N-chars buffer.
  212.  */
  213. void resetLastN() {
  214. _lastn_cur = 0;
  215. }
  216. /**
  217.  * Copy the last several characters in the last-N-chars buffer
  218.  * (since the last reset) into the provided buffer.
  219.  */
  220. size_t copyLastN(char *buf) {
  221. memcpy(buf, _lastn_buf, _lastn_cur);
  222. return _lastn_cur;
  223. }
  224. private:
  225. void init() {
  226. _in = NULL;
  227. _inf = NULL;
  228. _ins = NULL;
  229. _cur = _buf_sz = BUF_SZ;
  230. _done = false;
  231. _lastn_cur = 0;
  232. // no need to clear _buf[]
  233. }
  234. static const size_t BUF_SZ = 256 * 1024;
  235. FILE     *_in;
  236. std::ifstream *_inf;
  237. std::istream  *_ins;
  238. size_t    _cur;
  239. size_t    _buf_sz;
  240. bool      _done;
  241. uint8_t   _buf[BUF_SZ]; // (large) input buffer
  242. size_t    _lastn_cur;
  243. char      _lastn_buf[LASTN_BUF_SZ]; // buffer of the last N chars dispensed
  244. };
  245. /**
  246.  * Wrapper for a buffered output stream that writes bitpairs.
  247.  */
  248. class BitpairOutFileBuf {
  249. public:
  250. /**
  251.  * Open a new output stream to a file with given name.
  252.  */
  253. BitpairOutFileBuf(const char *in) : bpPtr_(0), cur_(0) {
  254. assert(in != NULL);
  255. out_ = fopen(in, "wb");
  256. if(out_ == NULL) {
  257. std::cerr << "Error: Could not open bitpair-output file " << in << std::endl;
  258. throw 1;
  259. }
  260. memset(buf_, 0, BUF_SZ);
  261. }
  262. /**
  263.  * Write a single bitpair into the buf.  Flush the buffer if it's
  264.  * full.
  265.  */
  266. void write(int bp) {
  267. assert_lt(bp, 4);
  268. assert_geq(bp, 0);
  269. buf_[cur_] |= (bp << bpPtr_);
  270. if(bpPtr_ == 6) {
  271. bpPtr_ = 0;
  272. cur_++;
  273. if(cur_ == BUF_SZ) {
  274. // Flush the buffer
  275. if(!fwrite((const void *)buf_, BUF_SZ, 1, out_)) {
  276. std::cerr << "Error writing to the reference index file (.4.ebwt)" << std::endl;
  277. throw 1;
  278. }
  279. // Reset to beginning of the buffer
  280. cur_ = 0;
  281. }
  282. // Initialize next octet to 0
  283. buf_[cur_] = 0;
  284. } else {
  285. bpPtr_ += 2;
  286. }
  287. }
  288. /**
  289.  * Write any remaining bitpairs and then close the input
  290.  */
  291. void close() {
  292. if(cur_ > 0 || bpPtr_ > 0) {
  293. if(bpPtr_ == 0) cur_--;
  294. if(!fwrite((const void *)buf_, cur_ + 1, 1, out_)) {
  295. std::cerr << "Error writing to the reference index file (.4.ebwt)" << std::endl;
  296. throw 1;
  297. }
  298. }
  299. fclose(out_);
  300. }
  301. private:
  302. static const size_t BUF_SZ = 128 * 1024;
  303. FILE    *out_;
  304. int      bpPtr_;
  305. uint32_t cur_;
  306. char     buf_[BUF_SZ]; // (large) input buffer
  307. };
  308. /**
  309.  * Wrapper for a buffered output stream that writes characters and
  310.  * other data types.  This class is *not* synchronized; the caller is
  311.  * responsible for synchronization.
  312.  */
  313. class OutFileBuf {
  314. public:
  315. /**
  316.  * Open a new output stream to a file with given name.
  317.  */
  318. OutFileBuf(const char *out, bool binary = false) :
  319. name_(out), cur_(0), closed_(false)
  320. {
  321. assert(out != NULL);
  322. out_ = fopen(out, binary ? "wb" : "w");
  323. if(out_ == NULL) {
  324. std::cerr << "Error: Could not open alignment output file " << out << std::endl;
  325. throw 1;
  326. }
  327. }
  328. /**
  329.  * Open a new output stream to a file with given name.
  330.  */
  331. OutFileBuf() : name_("cout"), cur_(0), closed_(false) {
  332. out_ = stdout;
  333. }
  334. /**
  335.  * Write a single character into the write buffer and, if
  336.  * necessary, flush.
  337.  */
  338. void write(char c) {
  339. assert(!closed_);
  340. if(cur_ == BUF_SZ) flush();
  341. buf_[cur_++] = c;
  342. }
  343. /**
  344.  * Write a c++ string to the write buffer and, if necessary, flush.
  345.  */
  346. void writeString(const std::string& s) {
  347. assert(!closed_);
  348. size_t slen = s.length();
  349. if(cur_ + slen > BUF_SZ) {
  350. if(cur_ > 0) flush();
  351. if(slen >= BUF_SZ) {
  352. fwrite(s.c_str(), slen, 1, out_);
  353. } else {
  354. memcpy(&buf_[cur_], s.data(), slen);
  355. assert_eq(0, cur_);
  356. cur_ = slen;
  357. }
  358. } else {
  359. memcpy(&buf_[cur_], s.data(), slen);
  360. cur_ += slen;
  361. }
  362. assert_leq(cur_, BUF_SZ);
  363. }
  364. /**
  365.  * Write a c++ string to the write buffer and, if necessary, flush.
  366.  */
  367. void writeChars(const char * s, size_t len) {
  368. assert(!closed_);
  369. if(cur_ + len > BUF_SZ) {
  370. if(cur_ > 0) flush();
  371. if(len >= BUF_SZ) {
  372. fwrite(s, len, 1, out_);
  373. } else {
  374. memcpy(&buf_[cur_], s, len);
  375. assert_eq(0, cur_);
  376. cur_ = len;
  377. }
  378. } else {
  379. memcpy(&buf_[cur_], s, len);
  380. cur_ += len;
  381. }
  382. assert_leq(cur_, BUF_SZ);
  383. }
  384. /**
  385.  * Write any remaining bitpairs and then close the input
  386.  */
  387. void close() {
  388. if(closed_) return;
  389. if(cur_ > 0) flush();
  390. closed_ = true;
  391. if(out_ != stdout) {
  392. fclose(out_);
  393. }
  394. }
  395. void flush() {
  396. if(!fwrite((const void *)buf_, cur_, 1, out_)) {
  397. std::cerr << "Error while flushing and closing output" << std::endl;
  398. throw 1;
  399. }
  400. cur_ = 0;
  401. }
  402. /**
  403.  * Return true iff this stream is closed.
  404.  */
  405. bool closed() const {
  406. return closed_;
  407. }
  408. /**
  409.  * Return the filename.
  410.  */
  411. const char *name() {
  412. return name_;
  413. }
  414. private:
  415. static const size_t BUF_SZ = 16 * 1024;
  416. const char *name_;
  417. FILE       *out_;
  418. uint32_t    cur_;
  419. char        buf_[BUF_SZ]; // (large) input buffer
  420. bool        closed_;
  421. };
  422. #endif /*ndef FILEBUF_H_*/