File indexing completed on 2024-04-28 05:41:19

0001 /*
0002     SPDX-FileCopyrightText: 2014-2017 Milian Wolff <mail@milianw.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #ifndef LINEREADER_H
0008 #define LINEREADER_H
0009 
0010 #include <cstdint>
0011 #include <istream>
0012 #include <string>
0013 
0014 /**
0015  * Optimized class to speed up reading of the potentially big data files.
0016  *
0017  * sscanf or istream are just slow when reading plain hex numbers. The
0018  * below does all we need and thus far less than what the generic functions
0019  * are capable of. We are not locale aware e.g.
0020  */
0021 class LineReader
0022 {
0023 public:
0024     LineReader()
0025     {
0026         m_line.reserve(1024);
0027     }
0028 
0029     bool getLine(std::istream& in)
0030     {
0031         if (!in.good()) {
0032             return false;
0033         }
0034         std::getline(in, m_line);
0035         m_it = m_line.cbegin();
0036         if (m_line.length() > 2) {
0037             m_it += 2;
0038         } else {
0039             m_it = m_line.cend();
0040         }
0041         return true;
0042     }
0043 
0044     char mode() const
0045     {
0046         return m_line.empty() ? '#' : m_line[0];
0047     }
0048 
0049     const std::string& line() const
0050     {
0051         return m_line;
0052     }
0053 
0054     template <typename T>
0055     bool readHex(T& in)
0056     {
0057         auto it = m_it;
0058         const auto end = m_line.cend();
0059         if (it == end) {
0060             return false;
0061         }
0062 
0063         T hex = 0;
0064         do {
0065             const char c = *it;
0066             if ('0' <= c && c <= '9') {
0067                 hex *= 16;
0068                 hex += c - '0';
0069             } else if ('a' <= c && c <= 'f') {
0070                 hex *= 16;
0071                 hex += c - 'a' + 10;
0072             } else if (c == ' ') {
0073                 ++it;
0074                 break;
0075             } else {
0076                 fprintf(stderr, "unexpected non-hex char: %d %zx\n", c, std::distance(m_line.cbegin(), it));
0077                 return false;
0078             }
0079             ++it;
0080         } while (it != end);
0081 
0082         in = hex;
0083         m_it = it;
0084         return true;
0085     }
0086 
0087     bool operator>>(int64_t& hex)
0088     {
0089         return readHex(hex);
0090     }
0091 
0092     bool operator>>(uint64_t& hex)
0093     {
0094         return readHex(hex);
0095     }
0096 
0097     bool operator>>(uint32_t& hex)
0098     {
0099         return readHex(hex);
0100     }
0101 
0102     bool operator>>(int& hex)
0103     {
0104         return readHex(hex);
0105     }
0106 
0107     void setExpectedSizedStrings(bool expectSizedStrings)
0108     {
0109         m_expectSizedStrings = expectSizedStrings;
0110     }
0111 
0112     bool operator>>(std::string& str)
0113     {
0114         if (m_expectSizedStrings) {
0115             uint64_t size = 0;
0116             if (!(*this >> size) || size > static_cast<uint64_t>(std::distance(m_it, m_line.cend()))) {
0117                 return false;
0118             }
0119             auto start = m_it;
0120             m_it += size;
0121             str.assign(start, m_it);
0122             if (m_it != m_line.cend()) {
0123                 // eat trailing whitespace
0124                 ++m_it;
0125             }
0126             return true;
0127         }
0128 
0129         auto it = m_it;
0130         const auto end = m_line.cend();
0131         while (it != end && *it != ' ') {
0132             ++it;
0133         }
0134         if (it != m_it) {
0135             str = std::string(m_it, it);
0136             if (*it == ' ') {
0137                 ++it;
0138             }
0139             m_it = it;
0140             return true;
0141         } else {
0142             return false;
0143         }
0144     }
0145 
0146     bool operator>>(bool& flag)
0147     {
0148         if (m_it != m_line.cend()) {
0149             flag = *m_it;
0150             m_it++;
0151             if (*m_it == ' ') {
0152                 ++m_it;
0153             }
0154             return true;
0155         } else {
0156             return false;
0157         }
0158     }
0159 
0160 private:
0161     bool m_expectSizedStrings = false;
0162     std::string m_line;
0163     std::string::const_iterator m_it;
0164 };
0165 
0166 #endif // LINEREADER_H