NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
stringvarfactory.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2019 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19#include "stringvarfactory.hpp"
20#include "../../kernel.hpp"
21
22using namespace std;
23
24namespace NumeRe
25{
35 bool StringVarFactory::isNumericCandidate(const string& sComponent)
36 {
37 if (sComponent.front() != '"' && sComponent.find_first_of("+-*/^!&|<>=% ?:,") != string::npos)
38 {
39 if ((sComponent.front() == '(' || sComponent.front() == '{') && getMatchingParenthesis(sComponent) == sComponent.length()-1)
40 return false;
41
42 return true;
43 }
44
45 return false;
46 }
47
48
57 string StringVarFactory::createStringVectorVar(const vector<string>& vStringVector)
58 {
59 // Return, if empty (something else went wrong)
60 if (!vStringVector.size())
61 return "";
62
63 string strVectName = "_~STRVECT[" + toString((int)m_mStringVectorVars.size()) + "]";
64
65 // Does it already exist?
66 if (m_mStringVectorVars.find(strVectName) != m_mStringVectorVars.end())
68
69 if (vStringVector.size() == 1 && vStringVector.front().find(strVectName) != std::string::npos)
71
72 // save the vector
73 m_mStringVectorVars[strVectName] = vStringVector;
74
75 return strVectName;
76 }
77
78
87 bool StringVarFactory::isStringVectorVar(const std::string& sVarName) const
88 {
89 return m_mStringVectorVars.find(sVarName) != m_mStringVectorVars.end()
90 || m_mTempStringVectorVars.find(sVarName) != m_mTempStringVectorVars.end();
91 }
92
93
103 const StringVector& StringVarFactory::getStringVectorVar(const std::string& sVarName) const
104 {
105 auto iter = m_mStringVectorVars.find(sVarName);
106
107 if (iter != m_mStringVectorVars.end())
108 return iter->second;
109
110 iter = m_mTempStringVectorVars.find(sVarName);
111
112 if (iter != m_mTempStringVectorVars.end())
113 return iter->second;
114
115 throw std::out_of_range("Could not find " + sVarName + " in the string vectors.");
116 }
117
118
129 {
130 // If the command line or the string vector vars are empty return false
131 if (!sLine.length() || (!m_mStringVectorVars.size() && !m_mTempStringVectorVars.size()))
132 return false;
133
134 // Try to find at least one of the known string vector vars
135 for (auto iter = m_mTempStringVectorVars.begin(); iter != m_mTempStringVectorVars.end(); ++iter)
136 {
137 // There's one: return true
138 if (sLine.find(iter->first) != string::npos)
139 return true;
140 }
141
142 // Try to find at least one of the known string vector vars
143 for (auto iter = m_mStringVectorVars.begin(); iter != m_mStringVectorVars.end(); ++iter)
144 {
145 // There's one: return true
146 if (sLine.find(iter->first) != string::npos)
147 return true;
148 }
149
150 // Nothing found
151 return false;
152 }
153
154
168 {
169 StringVector vRes;
170 const map<string, vector<mu::value_type> >& mNumVectorVars = NumeReKernel::getInstance()->getParser().GetVectors();
171 g_logger.info("Evaluating string vector for '" + sLine + "'");
172 g_logger.info("Contains vars: " + toString(containsStringVectorVars(sLine)));
173 g_logger.info("Contains parser vars: " + toString(NumeReKernel::getInstance()->getParser().ContainsVectorVars(sLine, false)));
174
175 // As long as the current vector is not empty
176 while (sLine.length())
177 {
178 // Get-cut the next argument
179 string sCurrentComponent = getNextArgument(sLine, true);
180
181 // If the current component does not contain any further
182 // vectors, push it back.
183 // Otherwise expand the contained vectors
184 //if (!containsStringVectorVars(sCurrentComponent))
185 // vRes.push_back(sCurrentComponent);
186 //else
187 {
188 // Expand the contained vectors
189 size_t nCurrentComponent = 0;
190
191 // This while loop is terminated with a break command
192 while (true)
193 {
194 string currentline = sCurrentComponent;
195 bool bHasComponents = false;
196
197 // Replace all found numerical vectors with their nCurrentComponent-th component
198 for (auto iter = mNumVectorVars.begin(); iter != mNumVectorVars.end(); ++iter)
199 {
200 size_t nMatch = 0;
201
202 // Vector found: replace its occurence with its nCurrentComponent-th value
203 while ((nMatch = currentline.find(iter->first, nMatch)) != string::npos)
204 {
205 // Do not replace vector variables, which are part
206 // of a string
207 if (isInQuotes(currentline, nMatch)
208 || (nMatch && !isDelimiter(currentline[nMatch-1]))
209 || (nMatch + iter->first.length() < currentline.length() && !isDelimiter(currentline[nMatch+iter->first.length()])))
210 {
211 nMatch++;
212 continue;
213 }
214
215 // Handle the size of the current vector correspondingly
216 if ((iter->second).size() > nCurrentComponent)
217 {
218 bHasComponents = true;
219 currentline.replace(nMatch, (iter->first).length(), toCmdString((iter->second)[nCurrentComponent]));
220 }
221 else if ((iter->second).size() == 1)
222 currentline.replace(nMatch, (iter->first).length(), toCmdString((iter->second)[0]));
223 else
224 currentline.replace(nMatch, (iter->first).length(), "nan");
225 }
226 }
227
228 // Replace all internal vectors
229 replaceStringVectorVars(m_mStringVectorVars, currentline, nCurrentComponent, bHasComponents);
230
231 // Replace all temporary vectors
232 replaceStringVectorVars(m_mTempStringVectorVars, currentline, nCurrentComponent, bHasComponents);
233
234 // Break the loop, if there are no further vector components
235 if (!bHasComponents)
236 break;
237
238 // Push back the current line and increment the component
239 vRes.push_generic(currentline);
240 nCurrentComponent++;
241 }
242 }
243 }
244
245 return vRes;
246 }
247
248
264 StringVector StringVarFactory::expandStringVectorComponents(std::vector<StringVector>& vStringVector)
265 {
266 // If the vector contains only one element,
267 // then return it directly
268 if (vStringVector.size() == 1)
269 return vStringVector.front();
270
271 // Concatenate all embedded vectors to a single component
272 StringVector vRet = vStringVector.front();
273
274 for (size_t i = 1; i < vStringVector.size(); i++)
275 {
276 vRet.insert(vRet.end(), vStringVector[i].begin(), vStringVector[i].end());
277 }
278
279 // Return the concatenated result
280 return vRet;
281 }
282
283
294 {
295 if (m_mStringVectorVars.size())
296 m_mStringVectorVars.clear();
297 }
298
299
311 string StringVarFactory::createTempStringVectorVar(const vector<string>& vStringVector)
312 {
313 // Return, if empty (something else went wrong)
314 if (!vStringVector.size())
315 return "";
316
317 // Does it already exist?
318 string strVectName = findVectorInMap(m_mTempStringVectorVars, vStringVector);
319
320 if (strVectName.length())
321 return strVectName;
322
323 strVectName = "_~TEMPSTRVECT[" + toString((int)m_mTempStringVectorVars.size()) + "]";
324
325 // save the vector
326 m_mTempStringVectorVars[strVectName] = vStringVector;
327
328 return strVectName;
329 }
330
331
343 {
344 if (m_mTempStringVectorVars.size())
346 }
347
348
359 bool StringVarFactory::checkStringvarDelimiter(const string& sToken) const
360 {
361 static const string sDELIMITER = "+-*/ ()={}^&|!<>,\\%#[]?:\";";
362
363 // The opening parenthesis at the end indicates a function.
364 // This is obviously not a string variable
365 if (sToken.back() == '(')
366 return false;
367
368 // If the first and the last character are part of the
369 // delimiter list (or the last character is a dot), then
370 // we indicate the current token as delimited.
371 return sDELIMITER.find(sToken.front()) != string::npos && (sDELIMITER.find(sToken.back()) != string::npos || sToken.back() == '.');
372 }
373
374
387 void StringVarFactory::replaceStringVectorVars(map<string,StringVector>& mVectorVarMap, string& currentline, size_t nCurrentComponent, bool& bHasComponents)
388 {
389 // Replace all found vectors with their nCurrentComponent-th component
390 for (auto iter = mVectorVarMap.begin(); iter != mVectorVarMap.end(); ++iter)
391 {
392 size_t nMatch = 0;
393
394 // Vector found: replace its occurence with its nCurrentComponent-th value
395 while ((nMatch = currentline.find(iter->first)) != string::npos)
396 {
397 // Handle the size of the current vector correspondingly
398 if ((iter->second).size() > nCurrentComponent)
399 {
400 bHasComponents = true;
401
402 if (!iter->second.is_string(nCurrentComponent))
403 currentline.replace(nMatch, (iter->first).length(), "(" + (iter->second).getMasked(nCurrentComponent) + ")");
404 else
405 currentline.replace(nMatch, (iter->first).length(), (iter->second).getMasked(nCurrentComponent));
406 }
407 else if ((iter->second).size() == 1)
408 {
409 if (!iter->second.is_string(0))
410 currentline.replace(nMatch, (iter->first).length(), "(" + (iter->second).getMasked(0) + ")");
411 else
412 currentline.replace(nMatch, (iter->first).length(), (iter->second).getMasked(0));
413 }
414 else
415 currentline.replace(nMatch, (iter->first).length(), "\"\"");
416 }
417 }
418 }
419
420
432 string StringVarFactory::findVectorInMap(const map<string,StringVector>& mVectorVarMap, const vector<string>& vStringVector)
433 {
434 // Go through the map
435 for (auto iter = mVectorVarMap.begin(); iter != mVectorVarMap.end(); ++iter)
436 {
437 // Compare first size and the first component
438 if (iter->second.size() == vStringVector.size() && iter->second[0] == vStringVector[0])
439 {
440 // If both appear similar, compare every
441 // component
442 for (size_t i = 1; i < vStringVector.size(); i++)
443 {
444 // Break if a component is not equal
445 if (vStringVector[i] != iter->second.at(i))
446 break;
447
448 // Return the vector name, if all components
449 // appear equal
450 if (i == vStringVector.size()-1)
451 return iter->first;
452 }
453 }
454 }
455
456 // Return an empty string, if nothing was found
457 return "";
458 }
459
460
470 bool StringVarFactory::containsStringVars(const string& _sLine) const
471 {
472 // Do nothing, if no string variables were declared
473 if (!m_mStringVars.size())
474 return false;
475
476 // Add whitespaces for safety
477 string sLine = " " + _sLine + " ";
478
479 // Search for the first match of all declared string variables
480 for (auto iter = m_mStringVars.begin(); iter != m_mStringVars.end(); ++iter)
481 {
482 size_t pos = 0;
483
484 // Examine all possible candidates for string variables,
485 // because the first one might be a false-positive
486 while ((pos = sLine.find(iter->first, pos)) != std::string::npos)
487 {
488 // Compare the located match to the delimiters and return
489 // true, if the match is delimited on both sides
490 if (sLine[pos+(iter->first).length()] != '('
491 && checkStringvarDelimiter(sLine.substr(pos-1, (iter->first).length()+2))
492 )
493 return true;
494
495 pos++;
496 }
497 }
498
499 // No match found
500 return false;
501 }
502
503
512 bool StringVarFactory::isStringVar(const std::string& sVarName) const
513 {
514 return m_mStringVars.find(sVarName) != m_mStringVars.end();
515 }
516
517
531 void StringVarFactory::getStringValuesAsInternalVar(std::string& sLine, unsigned int nPos)
532 {
533 // Do nothing, if no string variables were declared
534 if (!m_mStringVars.size())
535 return;
536
537 unsigned int __nPos;
538 sLine += " ";
539
540 // Try to find every string variable into the passed string and
541 // replace it correspondingly
542 for (auto iter = m_mStringVars.begin(); iter != m_mStringVars.end(); ++iter)
543 {
544 __nPos = nPos;
545 std::string sVectVar;
546
547 // Examine all occurences of the current variable in the
548 // string
549 while ((__nPos = sLine.find(iter->first, __nPos)) != string::npos)
550 {
551 __nPos++;
552
553 // Appended opening parenthesis indicates a function
554 if (sLine[__nPos+(iter->first).length()-1] == '('
555 || sLine[__nPos+(iter->first).length()-1] == '{')
556 continue;
557
558 // Only create the variable, if it is actually needed
559 if (!sVectVar.length())
560 sVectVar = createStringVectorVar(std::vector<std::string>(1, "\""+iter->second+"\""));
561 //sVectVar = "\""+iter->second+"\"";
562
563 // Check, whether the found occurence is correctly
564 // delimited and replace it. If the match is at the
565 // beginning of the command line, it serves a special
566 // treatment
567 if (__nPos == 1)
568 {
569 // Check with delimiter
570 if (checkStringvarDelimiter(" " + sLine.substr(0, (iter->first).length()+1))
571 && !isInQuotes(sLine, 0, true))
572 {
573 // Replace it with standard function signature or its value
574 if (sLine[(iter->first).length()] == '.')
575 replaceStringMethod(sLine, 0, (iter->first).length(), sVectVar);
576 else
577 sLine.replace(0, (iter->first).length(), sVectVar);
578 }
579
580 continue;
581 }
582
583 // Check with delimiter
584 if (checkStringvarDelimiter(sLine.substr(__nPos-2, (iter->first).length()+2))
585 && !isInQuotes(sLine, __nPos-1, true))
586 {
587 // Replace it with standard function signature or its value
588 if (sLine[__nPos+(iter->first).length()-1] == '.')
589 replaceStringMethod(sLine, __nPos-1, (iter->first).length(), sVectVar);
590 else
591 sLine.replace(__nPos-1, (iter->first).length(), sVectVar);
592 }
593 }
594 }
595 }
596
597
609 void StringVarFactory::getStringValues(std::string& sLine)
610 {
611 // Do nothing, if no string variables were declared
612 if (!m_mStringVars.size())
613 return;
614
615 unsigned int __nPos;
616 sLine += " ";
617
618 // Try to find every string variable into the passed string and
619 // replace it correspondingly
620 for (auto iter = m_mStringVars.begin(); iter != m_mStringVars.end(); ++iter)
621 {
622 __nPos = 0;
623 std::string sVectVar;
624
625 // Examine all occurences of the current variable in the
626 // string
627 while ((__nPos = sLine.find(iter->first, __nPos)) != string::npos)
628 {
629 __nPos++;
630
631 // Appended opening parenthesis indicates a function
632 if (sLine[__nPos+(iter->first).length()-1] == '('
633 || sLine[__nPos+(iter->first).length()-1] == '{')
634 continue;
635
636 // Only create the variable, if it is actually needed
637 if (!sVectVar.length())
638 sVectVar = "\""+iter->second+"\"";
639
640 // Check, whether the found occurence is correctly
641 // delimited and replace it. If the match is at the
642 // beginning of the command line, it serves a special
643 // treatment
644 if (__nPos == 1)
645 {
646 // Check with delimiter
647 if (checkStringvarDelimiter(" " + sLine.substr(0, (iter->first).length()+1))
648 && !isInQuotes(sLine, 0, true))
649 {
650 // Replace it with standard function signature or its value
651 if (sLine[(iter->first).length()] == '.')
652 replaceStringMethod(sLine, 0, (iter->first).length(), sVectVar);
653 else
654 sLine.replace(0, (iter->first).length(), sVectVar);
655 }
656
657 continue;
658 }
659
660 // Check with delimiter
661 if (checkStringvarDelimiter(sLine.substr(__nPos-2, (iter->first).length()+2))
662 && !isInQuotes(sLine, __nPos-1, true))
663 {
664 // Replace it with standard function signature or its value
665 if (sLine[__nPos+(iter->first).length()-1] == '.')
666 replaceStringMethod(sLine, __nPos-1, (iter->first).length(), sVectVar);
667 else
668 sLine.replace(__nPos-1, (iter->first).length(), sVectVar);
669 }
670 }
671 }
672 }
673
674
683 std::string StringVarFactory::getStringValue(const std::string& sVar) const
684 {
685 auto iter = m_mStringVars.find(sVar);
686
687 if (iter == m_mStringVars.end())
688 return "";
689
690 return iter->second;
691 }
692
693
704 void StringVarFactory::setStringValue(const string& sVar, const string& sValue)
705 {
706 static const string sVALIDCHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_1234567890~";
707
708 // Variable names cannot start with a number
709 if (sVar[0] >= '0' && sVar[0] <= '9')
711
712 // Compare every character to the list of valid characters,
713 // to ensure that the name is absolutly valid
714 for (unsigned int i = 0; i < sVar.length(); i++)
715 {
716 if (sVALIDCHARACTERS.find(sVar[i]) == string::npos)
718 }
719
720 // Create or update the variable name with the passed value.
721 // Omit the surrounding quotation marks
722 if (sValue[0] == '"' && sValue[sValue.length()-1] == '"')
723 m_mStringVars[sVar] = sValue.substr(1,sValue.length()-2);
724 else
725 m_mStringVars[sVar] = sValue;
726 }
727
728
737 void StringVarFactory::removeStringVar(const string& sVar)
738 {
739 // Do nothing, if no string variables were declared
740 if (!m_mStringVars.size())
741 return;
742
743 // Delete the string variable, if it exists
744 auto iter = m_mStringVars.find(sVar);
745 if (iter != m_mStringVars.end())
746 m_mStringVars.erase(iter);
747 }
748
749}
750
void info(const std::string &sMessage)
Convenience member function.
Definition: logger.hpp:106
std::map< std::string, StringVector > m_mTempStringVectorVars
StringVector evaluateStringVectors(std::string sLine)
This member function evaluates the passed string vector and returns it's evaluated components in sepa...
const StringVector & getStringVectorVar(const std::string &sVarName) const
Return a reference to the identified string vector variable or throw if it does not exist.
bool containsStringVars(const std::string &sLine) const
This public member function determines, whether the passed string line contains string variables as p...
void removeStringVectorVars()
This member function removes all internal string vector variables.
std::map< std::string, StringVector > m_mStringVectorVars
bool isStringVectorVar(const std::string &sVarName) const
Check, whether the passed string identifies a string vector variable.
bool isStringVar(const std::string &sVarName) const
Determine, whether the passed string is the identifier of a string variable.
bool checkStringvarDelimiter(const std::string &sToken) const
This private member function examines the first and the last character of the passed string and deter...
std::map< std::string, std::string > m_mStringVars
StringVector expandStringVectorComponents(std::vector< StringVector > &vStringVector)
This member function expands the internal multi-expressions in the veector into separate components b...
bool containsStringVectorVars(const std::string &sLine)
This member function determines, whether there are string vector variables in the passed command line...
void setStringValue(const std::string &sVar, const std::string &sValue)
This public member function creates or updates a string variable and fills it with the passed value.
void replaceStringVectorVars(std::map< std::string, StringVector > &mVectorVarMap, std::string &currentline, size_t nCurrentComponent, bool &bHasComponents)
Replaces all found vectors of the passed map with their nCurrentComponent component.
std::string findVectorInMap(const std::map< std::string, StringVector > &mVectorVarMap, const std::vector< std::string > &vStringVector)
Searches for the passed string in the passed map and returns the key string from the map,...
void getStringValues(std::string &sLine)
This public member function resolves all string variable occurences and replaces them with their valu...
std::string createStringVectorVar(const std::vector< std::string > &vStringVector)
This member function is used to create a string vector variable.
void removeTempStringVectorVars()
This member function removes all temporary string vector variables.
std::string createTempStringVectorVar(const std::vector< std::string > &vStringVector)
This member function is used to create a temporary string vector variable.
bool isNumericCandidate(const std::string &sComponent)
This member function is used to determine, whether a string vector component is numerical parsable.
std::string getStringValue(const std::string &sVar) const
Returns the value of the selected string variable.
void removeStringVar(const std::string &sVar)
This public member function removes the selected string variable from memory.
void getStringValuesAsInternalVar(std::string &sLine, unsigned int nPos=0)
This public member function resolves all string variable occurences and replaces them with an interna...
static NumeReKernel * getInstance()
This static member function returns a a pointer to the singleton instance of the kernel.
Definition: kernel.hpp:221
mu::Parser & getParser()
Definition: kernel.hpp:281
This class is an extension to the std::vector<std::string> to provide the vector-like functionalities...
void push_generic(const std::string &sStr)
Append a generic string value to the end of this vector. Depending on the existence of surrounding qu...
Common exception class for all exceptions thrown in NumeRe.
Definition: error.hpp:32
@ STRINGVARS_MUSTNT_CONTAIN
Definition: error.hpp:208
@ STRINGVARS_MUSTNT_BEGIN_WITH_A_NUMBER
Definition: error.hpp:207
@ STRING_ERROR
Definition: error.hpp:209
static size_t invalid_position
Definition: error.hpp:235
const std::map< std::string, std::vector< mu::value_type > > & GetVectors() const
DetachedLogger g_logger
Definition: logger.cpp:23
unsigned int getMatchingParenthesis(const StringView &)
Returns the position of the closing parenthesis.
Definition: tools.cpp:414
std::string toCmdString(double dNumber)
Converts a numerical value into a "full" precision string.
std::string getNextArgument(std::string &sArgList, bool bCut)
Definition: tools.cpp:2294
std::string toString(int)
Converts an integer to a string without the Settings bloat.
void replaceStringMethod(string &sLine, size_t nPos, size_t nLength, const string &sReplacement)
This function searches the indicated string variable occurence for possible string methods and replac...
Definition: tools.cpp:3875
bool isInQuotes(StringView sExpr, unsigned int nPos, bool bIgnoreVarParser)
Checks, whether the position in the passed expression is part of a string literal.
Definition: tools.cpp:1672
bool isDelimiter(char c)
This function determines, if the passed character is a delimiter character.
Definition: tools.cpp:1852