Line data Source code
1 : /* Copyright (C) 2025 Robert Schiwon 2 : * 3 : * This file is part of libjdx. 4 : * 5 : * libjdx is free software: you can redistribute it and/or modify it under the 6 : * terms of the GNU Lesser General Public License as published by the Free 7 : * Software Foundation, either version 3 of the License, or (at your option) any 8 : * later version. 9 : * 10 : * libjdx is distributed in the hope that it will be useful, but WITHOUT ANY 11 : * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 12 : * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 : * details. 14 : * 15 : * You should have received a copy of the GNU Lesser General Public License 16 : * along with libjdx. If not, see <https://www.gnu.org/licenses/>. 17 : */ 18 : #include "util/PeakTableParser.hpp" 19 : #include "jdx/ParseException.hpp" 20 : #include "jdx/Peak.hpp" 21 : #include "util/LdrUtils.hpp" 22 : #include "util/StringUtils.hpp" 23 : 24 : #include <algorithm> 25 : #include <regex> 26 : 27 15 : libjdx::jdx::util::PeakTableParser::PeakTableParser( 28 15 : io::TextReader& reader, std::string variableList) 29 15 : : TuplesParser(std::move(variableList), "peak table") 30 30 : , m_reader{reader} 31 : { 32 15 : } 33 : 34 52 : std::optional<libjdx::jdx::Peak> libjdx::jdx::util::PeakTableParser::next() 35 : { 36 52 : return TuplesParser::next<Peak>([this]() { return nextTuple(); }, 37 97 : [this](const std::string& tuple) { return createPeak(tuple); }); 38 : // alternative without lambdas: 39 : // return TuplesParser::next<Peak>( 40 : // std::bind(&PeakTableParser::nextTuple, this), 41 : // std::bind(&PeakTableParser::createPeak, this, std::placeholders::_1)); 42 : } 43 : 44 79 : std::optional<std::string> libjdx::jdx::util::PeakTableParser::nextTuple() 45 : { 46 79 : while (m_tuples.empty()) 47 : { 48 38 : if (m_reader.eof()) 49 : { 50 11 : return std::nullopt; 51 : } 52 : 53 38 : auto pos = m_reader.tellg(); 54 38 : auto nextLine = m_reader.readLine(); 55 38 : if (util::isLdrStart(nextLine)) 56 : { 57 : // next LDR => end of PEAK TABLE 58 11 : m_reader.seekg(pos); 59 11 : return std::nullopt; 60 : } 61 : 62 27 : auto value = util::stripLineComment(nextLine, true).first; 63 27 : if (value.empty()) 64 : { 65 : // skip pure comments 66 0 : continue; 67 : } 68 : auto tuples 69 81 : = util::split(value, R"([^,\s](\s*(?:\s|;)\s*)[^,\s])", true, 1); 70 27 : if (tuples.empty()) 71 : { 72 : throw ParseException( 73 : "Unexpected content found while parsing PEAK TABLE: " 74 0 : + nextLine); 75 : } 76 : // add to queue 77 68 : for (auto& tuple : tuples) 78 : { 79 41 : m_tuples.push(tuple); 80 : } 81 : } 82 : 83 82 : auto tuple = m_tuples.front(); 84 41 : m_tuples.pop(); 85 41 : return tuple; 86 : } 87 : 88 41 : libjdx::jdx::Peak libjdx::jdx::util::PeakTableParser::createPeak( 89 : const std::string& tuple) const 90 : { 91 : // tokenize 92 : // token[0] is the full match so extract 1 + 3 tokens for 3 groups 93 80 : const auto tokens = extractTokens(tuple, m_regex, 1 + 3); 94 39 : const auto& varList = getVariableList(); 95 : 96 : // error conditions {varList, {error condition, error message}} 97 : const std::multimap<std::string, std::tuple<bool, std::string>> errorMap{ 98 39 : {s_varLists.at(0), 99 117 : {tokens.at(3).has_value(), std::string{"Illegal "} + s_ldrName 100 117 : + " entry for " + s_varLists.at(0) 101 78 : + ": " + tuple}}, 102 39 : {s_varLists.at(1), 103 117 : {!tokens.at(3), std::string{"Illegal "} + s_ldrName + " entry for " 104 117 : + s_varLists.at(1) + ": " + tuple}}, 105 39 : {s_varLists.at(2), 106 117 : {!tokens.at(3), std::string{"Illegal "} + s_ldrName + " entry for " 107 117 : + s_varLists.at(2) + ": " + tuple}}, 108 429 : }; 109 : 110 43 : checkForErrors(varList, errorMap, s_ldrName); 111 : 112 : // map 113 37 : Peak peak{}; 114 37 : peak.x = parseDoubleToken(tokens.at(1)); 115 37 : peak.y = parseDoubleToken(tokens.at(2)); 116 : // nothing to do for varLists[0] 117 37 : if (s_varLists.at(1) == varList) 118 : { 119 7 : peak.w = parseDoubleToken(tokens.at(3)); 120 : } 121 30 : else if (s_varLists.at(2) == varList) 122 : { 123 1 : peak.m = tokens.at(3); 124 : } 125 : 126 74 : return peak; 127 : }