stream.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include "../sys/platform.h"
  5. #include "../sys/ref.h"
  6. #include "../sys/filename.h"
  7. #include "../sys/estring.h"
  8. #include <vector>
  9. #include <iostream>
  10. #include <cstdio>
  11. #include <string.h>
  12. namespace embree
  13. {
  14. /*! stores the location of a stream element in the source */
  15. class ParseLocation
  16. {
  17. public:
  18. ParseLocation () : lineNumber(-1), colNumber(-1) {}
  19. ParseLocation (std::shared_ptr<std::string> fileName, ssize_t lineNumber, ssize_t colNumber, ssize_t /*charNumber*/)
  20. : fileName(fileName), lineNumber(lineNumber), colNumber(colNumber) {}
  21. std::string str() const
  22. {
  23. std::string str = "unknown";
  24. if (fileName) str = *fileName;
  25. if (lineNumber >= 0) str += " line " + toString(lineNumber);
  26. if (lineNumber >= 0 && colNumber >= 0) str += " character " + toString(colNumber);
  27. return str;
  28. }
  29. private:
  30. std::shared_ptr<std::string> fileName; /// name of the file (or stream) the token is from
  31. ssize_t lineNumber; /// the line number the token is from
  32. ssize_t colNumber; /// the character number in the current line
  33. };
  34. /*! a stream class templated over the stream elements */
  35. template<typename T> class Stream : public RefCount
  36. {
  37. enum { BUF_SIZE = 1024 };
  38. private:
  39. virtual T next() = 0;
  40. virtual ParseLocation location() = 0;
  41. __forceinline std::pair<T,ParseLocation> nextHelper() {
  42. ParseLocation l = location();
  43. T v = next();
  44. return std::pair<T,ParseLocation>(v,l);
  45. }
  46. __forceinline void push_back(const std::pair<T,ParseLocation>& v) {
  47. if (past+future == BUF_SIZE) pop_front();
  48. size_t end = (start+past+future++)%BUF_SIZE;
  49. buffer[end] = v;
  50. }
  51. __forceinline void pop_front() {
  52. if (past == 0) THROW_RUNTIME_ERROR("stream buffer empty");
  53. start = (start+1)%BUF_SIZE; past--;
  54. }
  55. public:
  56. Stream () : start(0), past(0), future(0), buffer(BUF_SIZE) {}
  57. virtual ~Stream() {}
  58. public:
  59. const ParseLocation& loc() {
  60. if (future == 0) push_back(nextHelper());
  61. return buffer[(start+past)%BUF_SIZE].second;
  62. }
  63. T get() {
  64. if (future == 0) push_back(nextHelper());
  65. T t = buffer[(start+past)%BUF_SIZE].first;
  66. past++; future--;
  67. return t;
  68. }
  69. const T& peek() {
  70. if (future == 0) push_back(nextHelper());
  71. return buffer[(start+past)%BUF_SIZE].first;
  72. }
  73. const T& unget(size_t n = 1) {
  74. if (past < n) THROW_RUNTIME_ERROR ("cannot unget that many items");
  75. past -= n; future += n;
  76. return peek();
  77. }
  78. void drop() {
  79. if (future == 0) push_back(nextHelper());
  80. past++; future--;
  81. }
  82. private:
  83. size_t start,past,future;
  84. std::vector<std::pair<T,ParseLocation> > buffer;
  85. };
  86. /*! warps an iostream stream */
  87. class StdStream : public Stream<int>
  88. {
  89. public:
  90. StdStream (std::istream& cin, const std::string& name = "std::stream")
  91. : cin(cin), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {}
  92. ~StdStream() {}
  93. ParseLocation location() {
  94. return ParseLocation(name,lineNumber,colNumber,charNumber);
  95. }
  96. int next() {
  97. int c = cin.get();
  98. if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
  99. charNumber++;
  100. return c;
  101. }
  102. private:
  103. std::istream& cin;
  104. ssize_t lineNumber; /// the line number the token is from
  105. ssize_t colNumber; /// the character number in the current line
  106. ssize_t charNumber; /// the character in the file
  107. std::shared_ptr<std::string> name; /// name of buffer
  108. };
  109. /*! creates a stream from a file */
  110. class FileStream : public Stream<int>
  111. {
  112. public:
  113. FileStream (const FileName& fileName)
  114. : lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(fileName.str())))
  115. {
  116. if (ifs) ifs.close();
  117. ifs.open(fileName.str());
  118. if (!ifs.is_open()) THROW_RUNTIME_ERROR("cannot open file " + fileName.str());
  119. }
  120. ~FileStream() {
  121. if (ifs) ifs.close();
  122. }
  123. public:
  124. ParseLocation location() {
  125. return ParseLocation(name,lineNumber,colNumber,charNumber);
  126. }
  127. int next() {
  128. int c = ifs.get();
  129. if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
  130. charNumber++;
  131. return c;
  132. }
  133. private:
  134. std::ifstream ifs;
  135. ssize_t lineNumber; /// the line number the token is from
  136. ssize_t colNumber; /// the character number in the current line
  137. ssize_t charNumber; /// the character in the file
  138. std::shared_ptr<std::string> name; /// name of buffer
  139. };
  140. /*! creates a stream from a string */
  141. class StrStream : public Stream<int>
  142. {
  143. public:
  144. StrStream (const char* str)
  145. : str(str), lineNumber(1), colNumber(0), charNumber(0) {}
  146. public:
  147. ParseLocation location() {
  148. return ParseLocation(std::shared_ptr<std::string>(),lineNumber,colNumber,charNumber);
  149. }
  150. int next() {
  151. int c = str[charNumber];
  152. if (c == 0) return EOF;
  153. if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
  154. charNumber++;
  155. return c;
  156. }
  157. private:
  158. const char* str;
  159. ssize_t lineNumber; /// the line number the token is from
  160. ssize_t colNumber; /// the character number in the current line
  161. ssize_t charNumber; /// the character in the file
  162. };
  163. /*! creates a character stream from a command line */
  164. class CommandLineStream : public Stream<int>
  165. {
  166. public:
  167. CommandLineStream (int argc, char** argv, const std::string& name = "command line")
  168. : i(0), j(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name)))
  169. {
  170. if (argc > 0) {
  171. for (size_t i=0; argv[0][i] && i<1024; i++) charNumber++;
  172. charNumber++;
  173. }
  174. for (ssize_t k=1; k<argc; k++) args.push_back(argv[k]);
  175. }
  176. ~CommandLineStream() {}
  177. public:
  178. ParseLocation location() {
  179. return ParseLocation(name,0,charNumber,charNumber);
  180. }
  181. int next() {
  182. if (i == args.size()) return EOF;
  183. if (j == args[i].size()) { i++; j=0; charNumber++; return ' '; }
  184. charNumber++;
  185. return args[i][j++];
  186. }
  187. private:
  188. size_t i,j;
  189. std::vector<std::string> args;
  190. ssize_t charNumber; /// the character in the file
  191. std::shared_ptr<std::string> name; /// name of buffer
  192. };
  193. }