stream.h 7.6 KB

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