fast pQCD calculations for hadron-induced processes
zstr.hpp
1 // Code taken from https://github.com/mateidavid/zstr
2 //
3 // The MIT License (MIT)
4 //
5 // Copyright (c) 2015 Matei David, Ontario Institute for Cancer Research
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 //
25 //---------------------------------------------------------
26 // Copyright 2015 Ontario Institute for Cancer Research
27 // Written by Matei David (matei@cs.toronto.edu)
28 //---------------------------------------------------------
29 
30 // Reference:
31 // http://stackoverflow.com/questions/14086417/how-to-write-custom-input-stream-in-c
32 
33 #ifndef __ZSTR_HPP
34 #define __ZSTR_HPP
35 
36 #include <cassert>
37 #include <fstream>
38 #include <sstream>
39 #include <zlib.h>
40 #include <cstring>
41 #include <string>
42 
52 #ifdef HAVE_LIBZ
53 namespace strict_fstream
54 {
55 
57 class Exception
58  : public std::exception
59 {
60 public:
61  Exception(const std::string& msg) : _msg(msg) {}
62  const char * what() const noexcept { return _msg.c_str(); }
63 private:
64  std::string _msg;
65 }; // class Exception
66 
67 namespace detail
68 {
69 
70 struct static_method_holder
71 {
72  static std::string mode_to_string(std::ios_base::openmode mode)
73  {
74  static const int n_modes = 6;
75  static const std::ios_base::openmode mode_val_v[n_modes] =
76  {
77  std::ios_base::in,
78  std::ios_base::out,
79  std::ios_base::app,
80  std::ios_base::ate,
81  std::ios_base::trunc,
82  std::ios_base::binary
83  };
84 
85  static const char * mode_name_v[n_modes] =
86  {
87  "in",
88  "out",
89  "app",
90  "ate",
91  "trunc",
92  "binary"
93  };
94  std::string res;
95  for (size_t i = 0; i < n_modes; ++i)
96  {
97  if (mode & mode_val_v[i])
98  {
99  res += (not res.empty()? "|" : "");
100  res += mode_name_v[i];
101  }
102  }
103  if (res.empty()) res = "none";
104  return res;
105  }
106  static void check_mode(const std::string& filename, std::ios_base::openmode mode)
107  {
108  if ((mode & std::ios_base::trunc) and not (mode & std::ios_base::out))
109  {
110  throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: trunc and not out");
111  }
112  else if ((mode & std::ios_base::app) and not (mode & std::ios_base::out))
113  {
114  throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: app and not out");
115  }
116  else if ((mode & std::ios_base::trunc) and (mode & std::ios_base::app))
117  {
118  throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: trunc and app");
119  }
120  }
121  static void check_open(std::ios * s_p, const std::string& filename, std::ios_base::openmode mode)
122  {
123  if (s_p->fail())
124  {
125  throw Exception(std::string("strict_fstream: open('")
126  + filename + "'," + mode_to_string(mode) + "): open failed: "
127  + std::strerror(errno));
128  }
129  }
130  static void check_peek(std::istream * is_p, const std::string& filename, std::ios_base::openmode mode)
131  {
132  bool peek_failed = true;
133  try
134  {
135  is_p->peek();
136  peek_failed = is_p->fail();
137  }
138  catch (std::ios_base::failure e) {}
139  if (peek_failed)
140  {
141  throw Exception(std::string("strict_fstream: open('")
142  + filename + "'," + mode_to_string(mode) + "): peek failed: "
143  + std::strerror(errno));
144  }
145  is_p->clear();
146  }
147 }; // struct static_method_holder
148 
149 } // namespace detail
150 
151 class ifstream
152  : public std::ifstream
153 {
154 public:
155  ifstream() = default;
156  ifstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
157  {
158  open(filename, mode);
159  }
160  void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
161  {
162  mode |= std::ios_base::in;
163  exceptions(std::ios_base::badbit);
164  detail::static_method_holder::check_mode(filename, mode);
165  std::ifstream::open(filename, mode);
166  detail::static_method_holder::check_open(this, filename, mode);
167  detail::static_method_holder::check_peek(this, filename, mode);
168  }
169 }; // class ifstream
170 
171 class ofstream
172  : public std::ofstream
173 {
174 public:
175  ofstream() = default;
176  ofstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
177  {
178  open(filename, mode);
179  }
180  void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
181  {
182  mode |= std::ios_base::out;
183  exceptions(std::ios_base::badbit);
184  detail::static_method_holder::check_mode(filename, mode);
185  std::ofstream::open(filename, mode);
186  detail::static_method_holder::check_open(this, filename, mode);
187  }
188 }; // class ofstream
189 
190 class fstream
191  : public std::fstream
192 {
193 public:
194  fstream() = default;
195  fstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
196  {
197  open(filename, mode);
198  }
199  void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
200  {
201  if (not (mode & std::ios_base::out)) mode |= std::ios_base::in;
202  exceptions(std::ios_base::badbit);
203  detail::static_method_holder::check_mode(filename, mode);
204  std::fstream::open(filename, mode);
205  detail::static_method_holder::check_open(this, filename, mode);
206  detail::static_method_holder::check_peek(this, filename, mode);
207  }
208 }; // class fstream
209 
210 } // namespace strict_fstream
211 
212 
213 
214 
215 namespace zstr
216 {
217 
219 class Exception
220  : public std::exception
221 {
222 public:
223  Exception(z_stream * zstrm_p, int ret)
224  : _msg("zlib: ")
225  {
226  switch (ret)
227  {
228  case Z_STREAM_ERROR:
229  _msg += "Z_STREAM_ERROR: ";
230  break;
231  case Z_DATA_ERROR:
232  _msg += "Z_DATA_ERROR: ";
233  break;
234  case Z_MEM_ERROR:
235  _msg += "Z_MEM_ERROR: ";
236  break;
237  case Z_VERSION_ERROR:
238  _msg += "Z_VERSION_ERROR: ";
239  break;
240  case Z_BUF_ERROR:
241  _msg += "Z_BUF_ERROR: ";
242  break;
243  default:
244  std::ostringstream oss;
245  oss << ret;
246  _msg += "[" + oss.str() + "]: ";
247  break;
248  }
249  _msg += zstrm_p->msg;
250  }
251  Exception(const std::string msg) : _msg(msg) {}
252  const char * what() const noexcept { return _msg.c_str(); }
253 private:
254  std::string _msg;
255 }; // class Exception
256 
257 namespace detail
258 {
259 
260 class z_stream_wrapper
261  : public z_stream
262 {
263 public:
264  z_stream_wrapper(bool _is_input = true, int _level = Z_DEFAULT_COMPRESSION)
265  : is_input(_is_input)
266  {
267  this->zalloc = Z_NULL;
268  this->zfree = Z_NULL;
269  this->opaque = Z_NULL;
270  int ret;
271  if (is_input)
272  {
273  this->avail_in = 0;
274  this->next_in = Z_NULL;
275  ret = inflateInit2(this, 15+32);
276  }
277  else
278  {
279  ret = deflateInit2(this, _level, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY);
280  }
281  if (ret != Z_OK) throw Exception(this, ret);
282  }
283  ~z_stream_wrapper()
284  {
285  if (is_input)
286  {
287  inflateEnd(this);
288  }
289  else
290  {
291  deflateEnd(this);
292  }
293  }
294 private:
295  bool is_input;
296 }; // class z_stream_wrapper
297 
298 } // namespace detail
299 
300 class istreambuf
301  : public std::streambuf
302 {
303 public:
304  istreambuf(std::streambuf * _sbuf_p,
305  std::streamsize _buff_size = default_buff_size, bool _auto_detect = true)
306  : sbuf_p(_sbuf_p),
307  zstrm_p(nullptr),
308  buff_size(_buff_size),
309  auto_detect(_auto_detect),
310  auto_detect_run(false),
311  is_text(false)
312  {
313  assert(sbuf_p);
314  in_buff = new char [buff_size];
315  in_buff_start = in_buff;
316  in_buff_end = in_buff;
317  out_buff = new char [buff_size];
318  setg(out_buff, out_buff, out_buff);
319  }
320 
321  istreambuf(const istreambuf &) = delete;
322  istreambuf(istreambuf &&) = default;
323  istreambuf & operator = (const istreambuf &) = delete;
324  istreambuf & operator = (istreambuf &&) = default;
325 
326  virtual ~istreambuf()
327  {
328  delete [] in_buff;
329  delete [] out_buff;
330  if (zstrm_p) delete zstrm_p;
331  }
332 
333  virtual std::streambuf::int_type underflow()
334  {
335  if (this->gptr() == this->egptr())
336  {
337  // pointers for free region in output buffer
338  char * out_buff_free_start = out_buff;
339  do
340  {
341  // read more input if none available
342  if (in_buff_start == in_buff_end)
343  {
344  // empty input buffer: refill from the start
345  in_buff_start = in_buff;
346  std::streamsize sz = sbuf_p->sgetn(in_buff, buff_size);
347  in_buff_end = in_buff + sz;
348  if (in_buff_end == in_buff_start) break; // end of input
349  }
350  // auto detect if the stream contains text or deflate data
351  if (auto_detect and not auto_detect_run)
352  {
353  auto_detect_run = true;
354  unsigned char b0 = *reinterpret_cast< unsigned char * >(in_buff_start);
355  unsigned char b1 = *reinterpret_cast< unsigned char * >(in_buff_start + 1);
356  // Ref:
357  // http://en.wikipedia.org/wiki/Gzip
358  // http://stackoverflow.com/questions/9050260/what-does-a-zlib-header-look-like
359  is_text = not (in_buff_start + 2 <= in_buff_end
360  and ((b0 == 0x1F and b1 == 0x8B) // gzip header
361  or (b0 == 0x78 and (b1 == 0x01 // zlib header
362  or b1 == 0x9C
363  or b1 == 0xDA))));
364  }
365  if (is_text)
366  {
367  // simply swap in_buff and out_buff, and adjust pointers
368  assert(in_buff_start == in_buff);
369  std::swap(in_buff, out_buff);
370  out_buff_free_start = in_buff_end;
371  in_buff_start = in_buff;
372  in_buff_end = in_buff;
373  }
374  else
375  {
376  // run inflate() on input
377  if (not zstrm_p) zstrm_p = new detail::z_stream_wrapper(true);
378  zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(in_buff_start);
379  zstrm_p->avail_in = in_buff_end - in_buff_start;
380  zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff_free_start);
381  zstrm_p->avail_out = (out_buff + buff_size) - out_buff_free_start;
382  int ret = inflate(zstrm_p, Z_NO_FLUSH);
383  // process return code
384  if (ret != Z_OK and ret != Z_STREAM_END) throw Exception(zstrm_p, ret);
385  // update in&out pointers following inflate()
386  in_buff_start = reinterpret_cast< decltype(in_buff_start) >(zstrm_p->next_in);
387  in_buff_end = in_buff_start + zstrm_p->avail_in;
388  out_buff_free_start = reinterpret_cast< decltype(out_buff_free_start) >(zstrm_p->next_out);
389  assert(out_buff_free_start + zstrm_p->avail_out == out_buff + buff_size);
390  // if stream ended, deallocate inflator
391  if (ret == Z_STREAM_END)
392  {
393  delete zstrm_p;
394  zstrm_p = nullptr;
395  }
396  }
397  } while (out_buff_free_start == out_buff);
398  // 2 exit conditions:
399  // - end of input: there might or might not be output available
400  // - out_buff_free_start != out_buff: output available
401  this->setg(out_buff, out_buff, out_buff_free_start);
402  }
403  return this->gptr() == this->egptr()
404  ? traits_type::eof()
405  : traits_type::to_int_type(*this->gptr());
406  }
407 private:
408  std::streambuf * sbuf_p;
409  char * in_buff;
410  char * in_buff_start;
411  char * in_buff_end;
412  char * out_buff;
413  detail::z_stream_wrapper * zstrm_p;
414  std::streamsize buff_size;
415  bool auto_detect;
416  bool auto_detect_run;
417  bool is_text;
418 
419  static const std::streamsize default_buff_size = 1 << 20;
420 }; // class istreambuf
421 
422 class ostreambuf
423  : public std::streambuf
424 {
425 public:
426  ostreambuf(std::streambuf * _sbuf_p,
427  std::streamsize _buff_size = default_buff_size, int _level = Z_DEFAULT_COMPRESSION)
428  : sbuf_p(_sbuf_p),
429  zstrm_p(new detail::z_stream_wrapper(false, _level)),
430  buff_size(_buff_size)
431  {
432  assert(sbuf_p);
433  in_buff = new char [buff_size];
434  out_buff = new char [buff_size];
435  setp(in_buff, in_buff + buff_size);
436  }
437 
438  ostreambuf(const ostreambuf &) = delete;
439  ostreambuf(ostreambuf &&) = default;
440  ostreambuf & operator = (const ostreambuf &) = delete;
441  ostreambuf & operator = (ostreambuf &&) = default;
442 
443  int deflate_loop(int flush)
444  {
445  while (true)
446  {
447  zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff);
448  zstrm_p->avail_out = buff_size;
449  int ret = deflate(zstrm_p, flush);
450  if (ret != Z_OK and ret != Z_STREAM_END and ret != Z_BUF_ERROR) throw Exception(zstrm_p, ret);
451  std::streamsize sz = sbuf_p->sputn(out_buff, reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff);
452  if (sz != reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff)
453  {
454  // there was an error in the sink stream
455  return -1;
456  }
457  if (ret == Z_STREAM_END or ret == Z_BUF_ERROR or sz == 0)
458  {
459  break;
460  }
461  }
462  return 0;
463  }
464 
465  virtual ~ostreambuf()
466  {
467  // flush the zlib stream
468  sync();
469  delete [] in_buff;
470  delete [] out_buff;
471  delete zstrm_p;
472  }
473  virtual std::streambuf::int_type overflow(std::streambuf::int_type c = traits_type::eof())
474  {
475  zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(pbase());
476  zstrm_p->avail_in = pptr() - pbase();
477  while (zstrm_p->avail_in > 0)
478  {
479  int r = deflate_loop(Z_NO_FLUSH);
480  if (r != 0)
481  {
482  setp(nullptr, nullptr);
483  return traits_type::eof();
484  }
485  }
486  setp(in_buff, in_buff + buff_size);
487  return traits_type::eq_int_type(c, traits_type::eof()) ? traits_type::eof() : sputc(c);
488  }
489  virtual int sync()
490  {
491  // first, call overflow to clear in_buff
492  overflow();
493  if (not pptr()) return -1;
494  // then, call deflate asking to finish the zlib stream
495  zstrm_p->next_in = nullptr;
496  zstrm_p->avail_in = 0;
497  if (deflate_loop(Z_FINISH) != 0) return -1;
498  deflateReset(zstrm_p);
499  return 0;
500  }
501 private:
502  std::streambuf * sbuf_p;
503  char * in_buff;
504  char * out_buff;
505  detail::z_stream_wrapper * zstrm_p;
506  std::streamsize buff_size;
507 
508  static const std::streamsize default_buff_size = 1 << 20;
509 }; // class ostreambuf
510 
511 class istream
512  : public std::istream
513 {
514 public:
515  istream(std::istream & is)
516  : std::istream(new istreambuf(is.rdbuf()))
517  {
518  exceptions(std::ios_base::badbit);
519  }
520  explicit istream(std::streambuf * sbuf_p)
521  : std::istream(new istreambuf(sbuf_p))
522  {
523  exceptions(std::ios_base::badbit);
524  }
525  virtual ~istream()
526  {
527  delete rdbuf();
528  }
529 }; // class istream
530 
531 class ostream
532  : public std::ostream
533 {
534 public:
535  ostream(std::ostream & os)
536  : std::ostream(new ostreambuf(os.rdbuf()))
537  {
538  exceptions(std::ios_base::badbit);
539  }
540  explicit ostream(std::streambuf * sbuf_p)
541  : std::ostream(new ostreambuf(sbuf_p))
542  {
543  exceptions(std::ios_base::badbit);
544  }
545  virtual ~ostream()
546  {
547  delete rdbuf();
548  }
549 }; // class ostream
550 
551 namespace detail
552 {
553 
554 template < typename FStream_Type >
555 struct strict_fstream_holder
556 {
557  strict_fstream_holder(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
558  : _fs(filename, mode)
559  {}
560  FStream_Type _fs;
561 }; // class strict_fstream_holder
562 
563 } // namespace detail
564 
565 class ifstream
566  : private detail::strict_fstream_holder< strict_fstream::ifstream >,
567  public std::istream
568 {
569 public:
570  explicit ifstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
571  : detail::strict_fstream_holder< strict_fstream::ifstream >(filename, mode),
572  std::istream(new istreambuf(_fs.rdbuf()))
573  {
574  exceptions(std::ios_base::badbit);
575  }
576  virtual ~ifstream()
577  {
578  if (rdbuf()) delete rdbuf();
579  }
580 }; // class ifstream
581 
582 class ofstream
583  : private detail::strict_fstream_holder< strict_fstream::ofstream >,
584  public std::ostream
585 {
586 public:
587  explicit ofstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
588  : detail::strict_fstream_holder< strict_fstream::ofstream >(filename, mode | std::ios_base::binary),
589  std::ostream(new ostreambuf(_fs.rdbuf()))
590  {
591  exceptions(std::ios_base::badbit);
592  }
593  virtual ~ofstream()
594  {
595  if (rdbuf()) delete rdbuf();
596  }
597 }; // class ofstream
598 
599 } // namespace zstr
600 #else
601 namespace zstr
602 {
603 typedef std::ifstream ifstream;
604 typedef std::ofstream ofstream;
605 }
606 #endif
607 
608 
609 #endif
Definition: zstr.hpp:601