History

TimeSeriesPlatformLibrary: Converter function pointer to standard function templates to support more versatile function registration, e.g, lambda expressions.

J. Ritchie Carroll committed 7 years ago

Commit 70535871 parent 0c9b55217 files · +346 −307Browse files

Showing the changes to Source/Libraries/TimeSeriesPlatformLibrary/Common/Convert.cpp (1 of 17 files). Show all

Unified · Split

Source/Libraries/TimeSeriesPlatformLibrary/Common/Convert.cpp+181−2
@@ -25,11 +25,12 @@ · 24 unmodified lines
2525 #include <sstream>
2626 #include <locale>
2727 #include <codecvt>
28−#include <boost/uuid/string_generator.hpp>
2928 #include <boost/uuid/uuid_io.hpp>
29+#include <boost/uuid/string_generator.hpp>
3030 #include <boost/date_time/posix_time/posix_time.hpp>
3131 #include <boost/date_time/gregorian/gregorian.hpp>
3232 #include <boost/date_time/c_local_time_adjustor.hpp>
33+#include <boost/algorithm/string.hpp>
3334 #include "Convert.h"
3435
3536 using namespace std;
@@ -232,7 +233,7 @@ uint32_t GSF::TicksToString(char* ptr, uint32_t maxsize, string format, int64_t · 196 unmodified lines
232233
233234 DateTime GSF::LocalFromUtc(const DateTime& timestamp)
234235 {
235− return DateTime(boost::date_time::c_local_adjustor<DateTime>::utc_to_local(timestamp));
236+ return boost::date_time::c_local_adjustor<DateTime>::utc_to_local(timestamp);
236237 }
237238
238239 std::string GSF::ToString(const Guid& value)
@@ -273,6 +274,48 @@ string GSF::ToUTF8(const wstring& value) · 34 unmodified lines
273274 return converter.to_bytes(value);
274275 }
275276
277+bool GSF::ParseBoolean(const string& value)
278+{
279+ if (value.empty())
280+ return false;
281+
282+ const string result = Trim(value);
283+
284+ if (result.empty())
285+ {
286+ if (IsEqual(result, "true"))
287+ return true;
288+
289+ if (IsEqual(result, "false"))
290+ return false;
291+
292+ try
293+ {
294+ return stoi(result) != 0;
295+ }
296+ catch (...)
297+ {
298+ const char first = toupper(result[0]);
299+ return first == 'T' || first == 'Y';
300+ }
301+ }
302+
303+ return false;
304+}
305+
306+bool GSF::TryParseDouble(const string& value, float64_t& result)
307+{
308+ try
309+ {
310+ result = stod(value);
311+ return true;
312+ }
313+ catch (...)
314+ {
315+ return false;
316+ }
317+}
318+
276319 std::string GSF::RegExEncode(const char value)
277320 {
278321 std::stringstream stream;
@@ -380,3 +423,139 @@ DateTime GSF::ParseTimestamp(const char* time, bool parseAsUTC) · 101 unmodified lines
380423
381424 throw runtime_error("Failed to parse timestamp \"" + string(time) + "\"");
382425 }
426+
427+StringMap<string> GSF::ParseKeyValuePairs(const string& value, const char parameterDelimiter, const char keyValueDelimiter, const char startValueDelimiter, const char endValueDelimiter)
428+{
429+ if (parameterDelimiter == keyValueDelimiter ||
430+ parameterDelimiter == startValueDelimiter ||
431+ parameterDelimiter == endValueDelimiter ||
432+ keyValueDelimiter == startValueDelimiter ||
433+ keyValueDelimiter == endValueDelimiter ||
434+ startValueDelimiter == endValueDelimiter)
435+ throw invalid_argument("All delimiters must be unique");
436+
437+ const string& escapedParameterDelimiter = RegExEncode(parameterDelimiter);
438+ const string& escapedKeyValueDelimiter = RegExEncode(keyValueDelimiter);
439+ const string& escapedStartValueDelimiter = RegExEncode(startValueDelimiter);
440+ const string& escapedEndValueDelimiter = RegExEncode(endValueDelimiter);
441+ const string& escapedBackslashDelimiter = RegExEncode('\\');
442+ const string& parameterDelimiterStr = string(1, parameterDelimiter);
443+ const string& keyValueDelimiterStr = string(1, keyValueDelimiter);
444+ const string& startValueDelimiterStr = string(1, startValueDelimiter);
445+ const string& endValueDelimiterStr = string(1, endValueDelimiter);
446+ const string& backslashDelimiterStr = "\\";
447+
448+ StringMap<string> keyValuePairs;
449+ vector<string> escapedValue;
450+ bool valueEscaped = false;
451+ uint32_t delimiterDepth = 0;
452+
453+ // Escape any parameter or key/value delimiters within tagged value sequences
454+ // For example, the following string:
455+ // "normalKVP=-1; nestedKVP={p1=true; p2=false}")
456+ // would be encoded as:
457+ // "normalKVP=-1; nestedKVP=p1\\u003dtrue\\u003b p2\\u003dfalse")
458+ for (uint32_t i = 0; i < value.size(); i++)
459+ {
460+ const char character = value[i];
461+
462+ if (character == startValueDelimiter)
463+ {
464+ if (!valueEscaped)
465+ {
466+ valueEscaped = true;
467+ continue; // Don't add tag start delimiter to final value
468+ }
469+
470+ // Handle nested delimiters
471+ delimiterDepth++;
472+ }
473+
474+ if (character == endValueDelimiter)
475+ {
476+ if (valueEscaped)
477+ {
478+ if (delimiterDepth > 0)
479+ {
480+ // Handle nested delimiters
481+ delimiterDepth--;
482+ }
483+ else
484+ {
485+ valueEscaped = false;
486+ continue; // Don't add tag stop delimiter to final value
487+ }
488+ }
489+ else
490+ {
491+ throw runtime_error("Failed to parse key/value pairs: invalid delimiter mismatch. Encountered end value delimiter '" + endValueDelimiterStr + "' before start value delimiter '" + startValueDelimiterStr + "'."); // NOLINT
492+ }
493+ }
494+
495+ if (valueEscaped)
496+ {
497+ // Escape any delimiter characters inside nested key/value pair
498+ if (character == parameterDelimiter)
499+ escapedValue.push_back(escapedParameterDelimiter);
500+ else if (character == keyValueDelimiter)
501+ escapedValue.push_back(escapedKeyValueDelimiter);
502+ else if (character == startValueDelimiter)
503+ escapedValue.push_back(escapedStartValueDelimiter);
504+ else if (character == endValueDelimiter)
505+ escapedValue.push_back(escapedEndValueDelimiter);
506+ else if (character == '\\')
507+ escapedValue.push_back(escapedBackslashDelimiter);
508+ else
509+ escapedValue.emplace_back(1, character);
510+ }
511+ else
512+ {
513+ if (character == '\\')
514+ escapedValue.push_back(escapedBackslashDelimiter);
515+ else
516+ escapedValue.emplace_back(1, character);
517+ }
518+ }
519+
520+ if (delimiterDepth != 0 || valueEscaped)
521+ {
522+ // If value is still escaped, tagged expression was not terminated
523+ if (valueEscaped)
524+ delimiterDepth = 1;
525+
526+ const bool moreStartDelimiters = delimiterDepth > 0;
527+
528+ throw runtime_error(
529+ "Failed to parse key/value pairs: invalid delimiter mismatch. Encountered more " +
530+ (moreStartDelimiters ? "start value delimiters '" + startValueDelimiterStr + "'" : "end value delimiters '" + endValueDelimiterStr + "'") + " than " +
531+ (moreStartDelimiters ? "end value delimiters '" + endValueDelimiterStr + "'" : "start value delimiters '" + startValueDelimiterStr + "'") + ".");
532+ }
533+
534+ // Parse key/value pairs from escaped value
535+ vector<string> pairs = Split(boost::algorithm::join(escapedValue, ""), parameterDelimiterStr, false);
536+
537+ for (uint32_t i = 0; i < pairs.size(); i++)
538+ {
539+ // Separate key from value
540+ vector<string> elements = Split(pairs[i], keyValueDelimiterStr, false);
541+
542+ if (elements.size() == 2)
543+ {
544+ // Get key
545+ const string key = Trim(elements[0]);
546+
547+ // Get unescaped value
548+ const string unescapedValue = Replace(Replace(Replace(Replace(Replace(Trim(elements[1]),
549+ escapedParameterDelimiter, parameterDelimiterStr, false),
550+ escapedKeyValueDelimiter, keyValueDelimiterStr, false),
551+ escapedStartValueDelimiter, startValueDelimiterStr, false),
552+ escapedEndValueDelimiter, endValueDelimiterStr, false),
553+ escapedBackslashDelimiter, backslashDelimiterStr, false);
554+
555+ // Add or replace key elements with unescaped value
556+ keyValuePairs[key] = unescapedValue;
557+ }
558+ }
559+
560+ return keyValuePairs;
561+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t