1 /* 2 PADRING -- a padring generator for ASICs. 3 4 Copyright (c) 2019, Niels Moseley <niels@symbioticeda.com> 5 6 Permission to use, copy, modify, and/or distribute this software for any 7 purpose with or without fee is hereby granted, provided that the above 8 copyright notice and this permission notice appear in all copies. 9 10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 18 */ 19 20 #ifndef linereader_h 21 #define linereader_h 22 23 #include <iterator> 24 #include <iostream> 25 #include <list> 26 #include <string> 27 #include <string_view> 28 29 /** Takes a line and produces a list of std::string_view objects, 30 * one for each whitespace-separated chunk. 31 **/ 32 class TextChunkifier 33 { 34 public: TextChunkifier(const std::string & separators)35 TextChunkifier(const std::string &separators) : m_separators(separators) {} 36 37 /** Submit a string and generate a list of std::string_view objects/chunks. 38 * Use iterators to access the chunks **/ submitString(const std::string & line)39 void submitString(const std::string &line) 40 { 41 uint32_t state = 0; 42 int32_t idx = 0; 43 int32_t startIdx = -1; // -1 signals no start found 44 45 m_chunks.clear(); 46 47 while(idx < line.size()) 48 { 49 char c = line[idx]; 50 switch(state) 51 { 52 case 0: // idle state 53 if (m_separators.find(c) != std::string::npos) 54 { 55 startIdx = -1; // no start found 56 continue; 57 } 58 else 59 { 60 // non whitespace char -> 61 // the start of a new chunk 62 startIdx = idx; 63 state = 1; 64 } 65 break; 66 case 1: // inside a chunk 67 if (m_separators.find(c) != std::string::npos) 68 { 69 // chunk ended, so we emit it! 70 std::string_view chunk{line.c_str() + startIdx, static_cast<uint32_t>(idx - startIdx)}; 71 m_chunks.push_back(chunk); 72 startIdx = -1; // no start found 73 state = 0; 74 } 75 break; 76 default: 77 state = 0; 78 } 79 idx++; 80 } 81 82 // check if there was a chunk at the end of the line. 83 // if there is one, emit it! 84 if (startIdx != -1) 85 { 86 std::string_view chunk{line.c_str() + startIdx, static_cast<uint32_t>(idx - startIdx)}; 87 m_chunks.push_back(chunk); 88 } 89 } 90 91 /** get the first chunk as a std::string_view object */ getFirstChunk()92 std::string_view getFirstChunk() const 93 { 94 if (m_chunks.size() < 1) 95 { 96 return std::string_view(); 97 } 98 else 99 { 100 return m_chunks.front(); 101 } 102 } 103 104 typedef std::list<std::string_view> itertype; 105 begin()106 inline itertype::iterator begin() noexcept { return m_chunks.begin(); } cbegin()107 inline itertype::const_iterator cbegin() const noexcept { return m_chunks.cbegin(); } end()108 inline itertype::iterator end() noexcept { return m_chunks.end(); } cend()109 inline itertype::const_iterator cend() const noexcept { return m_chunks.cend(); } 110 111 protected: 112 std::string m_separators; 113 std::list<std::string_view > m_chunks; 114 }; 115 116 117 /** a stream based line reader with accept function to allow 118 lexing/parsing. */ 119 class LineReader 120 { 121 public: LineReader(std::istream & is)122 LineReader(std::istream &is) 123 : m_is(is) 124 { 125 m_lineNum = 0; 126 nextLine(); 127 } 128 129 /** accept the current line and advance to 130 the next */ accept()131 void accept() 132 { 133 nextLine(); 134 } 135 136 /** true if the end of file/stream is encountered */ eof()137 bool eof() const 138 { 139 return m_eof; 140 } 141 142 /** return the current line number */ getLineNumber()143 uint32_t getLineNumber() const 144 { 145 return m_lineNum; 146 } 147 148 /** return the current line as string_view */ getLine()149 const std::string& getLine() const 150 { 151 return m_line; 152 } 153 154 protected: 155 156 /** read the next line and update the line number 157 and eof boolean. 158 */ nextLine()159 void nextLine() 160 { 161 if (!std::getline(m_is, m_line)) 162 { 163 m_eof = true; 164 } 165 else 166 { 167 m_lineNum++; 168 m_eof = false; 169 } 170 } 171 172 std::string m_line; 173 std::istream &m_is; 174 175 bool m_eof; 176 uint32_t m_lineNum; 177 }; 178 179 180 /** a stream based line reader with accept function to allow 181 lexing/parsing. It will split the string into chunks based 182 on a set of separators 183 */ 184 class ChunkyLineReader 185 { 186 public: 187 ChunkyLineReader(std::istream &is, const std::string separators = " \t") m_is(is)188 : m_is(is), m_chunkifier(separators) 189 { 190 m_lineNum = 0; 191 nextLine(); 192 } 193 194 /** accept the current line and advance to 195 the next */ accept()196 void accept() 197 { 198 nextLine(); 199 } 200 201 /** true if the end of file/stream is encountered */ eof()202 bool eof() const 203 { 204 return m_eof; 205 } 206 207 /** return the current line number */ getLineNumber()208 uint32_t getLineNumber() const 209 { 210 return m_lineNum; 211 } 212 213 /** get this first chunk in the list */ getFirstChunk()214 std::string_view getFirstChunk() const 215 { 216 return m_chunkifier.getFirstChunk(); 217 } 218 219 typedef std::list<std::string_view> itertype; 220 221 /** iterator to access the string_view chunks */ begin()222 inline itertype::iterator begin() noexcept { return m_chunkifier.begin(); } 223 224 /** iterator to access the string_view chunks */ cbegin()225 inline itertype::const_iterator cbegin() const noexcept { return m_chunkifier.cbegin(); } 226 227 /** iterator to access the string_view chunks */ end()228 inline itertype::iterator end() noexcept { return m_chunkifier.end(); } 229 230 /** iterator to access the string_view chunks */ cend()231 inline itertype::const_iterator cend() const noexcept { return m_chunkifier.cend(); } 232 233 protected: 234 235 /** read the next line and update the line number 236 and eof boolean. 237 */ nextLine()238 void nextLine() 239 { 240 if (!std::getline(m_is, m_line)) 241 { 242 m_eof = true; 243 } 244 else 245 { 246 m_lineNum++; 247 m_eof = false; 248 m_chunkifier.submitString(m_line); 249 } 250 } 251 252 TextChunkifier m_chunkifier; 253 std::string m_line; 254 255 std::istream &m_is; 256 257 bool m_eof; 258 uint32_t m_lineNum; 259 }; 260 261 #endif