summaryrefslogtreecommitdiffstats
path: root/source/core
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2021-06-01 16:58:07 -0400
committerGitHub <noreply@github.com>2021-06-01 16:58:07 -0400
commit7a3c87b58de2683c077bd5341052c2e3cebeb048 (patch)
tree8641667ebcfecd728bfe8b572822751fae1c55bd /source/core
parent67486ee516ddc33806003727682cbfc68ab1f726 (diff)
JSONValue / Container (#1864)
* #include an absolute path didn't work - because paths were taken to always be relative. * WIP JSONWriter/JSONParser. * Checking different Layout styles for JSON. * Add slang-json-parser.h/.cpp * WIP JSONValue. * Added JSONValue::destroy/Recursive. * Improvement to JSONValue. * Improve text double conversion precision. Testing. * Simplify double parsing (just use atof). JSON comparison More testing of conversions and start of JSONValue. * Add <math.h> for isnan, isinf etc. * Small improvement with object comparison. * Fix typo in getArgsByName. * Removed use of isnan and isinf as includes don't work on linux. * Improve JSON unit test. * Added asInteger/asFloat/asBool to JSONValue. * Change comment to trigger CI build.
Diffstat (limited to 'source/core')
-rw-r--r--source/core/slang-list.h2
-rw-r--r--source/core/slang-string-escape-util.cpp43
-rw-r--r--source/core/slang-string-escape-util.h16
-rw-r--r--source/core/slang-string-util.cpp100
-rw-r--r--source/core/slang-string-util.h6
5 files changed, 162 insertions, 5 deletions
diff --git a/source/core/slang-list.h b/source/core/slang-list.h
index 08d9aa773..4420cc084 100644
--- a/source/core/slang-list.h
+++ b/source/core/slang-list.h
@@ -351,7 +351,7 @@ namespace Slang
void growToCount(Index count)
{
- Index newBufferCount = Index(1) << Math::Log2Ceil(count);
+ Index newBufferCount = Index(1) << Math::Log2Ceil((unsigned int)count);
if (m_capacity < newBufferCount)
{
reserve(newBufferCount);
diff --git a/source/core/slang-string-escape-util.cpp b/source/core/slang-string-escape-util.cpp
index a91d88e05..ffc43a7cb 100644
--- a/source/core/slang-string-escape-util.cpp
+++ b/source/core/slang-string-escape-util.cpp
@@ -18,6 +18,8 @@ public:
virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE { return isEscapingNeeded(slice); }
virtual bool isEscapingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE;
+ virtual bool isUnescapingNeeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE;
+
virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) SLANG_OVERRIDE;
@@ -30,6 +32,13 @@ bool SpaceStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice)
return slice.indexOf(' ') >= 0;
}
+bool SpaceStringEscapeHandler::isUnescapingNeeeded(const UnownedStringSlice& slice)
+{
+ SLANG_UNUSED(slice);
+ // As it stands we never have to unescape
+ return false;
+}
+
SlangResult SpaceStringEscapeHandler::appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out)
{
if (slice.indexOf('"') >= 0)
@@ -98,6 +107,7 @@ public:
virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE { SLANG_UNUSED(slice); return true; }
virtual bool isEscapingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE;
+ virtual bool isUnescapingNeeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE;
virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) SLANG_OVERRIDE;
@@ -167,6 +177,12 @@ static char _getCppUnescapedChar(char c)
}
}
+
+bool CppStringEscapeHandler::isUnescapingNeeeded(const UnownedStringSlice& slice)
+{
+ return slice.indexOf('\\') >= 0;
+}
+
/* static */bool CppStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice)
{
const char* cur = slice.begin();
@@ -456,6 +472,7 @@ public:
virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE { SLANG_UNUSED(slice); return true; }
virtual bool isEscapingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE;
+ virtual bool isUnescapingNeeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE;
virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) SLANG_OVERRIDE;
@@ -463,6 +480,11 @@ public:
JSONStringEscapeHandler() : Super('"') {}
};
+bool JSONStringEscapeHandler::isUnescapingNeeeded(const UnownedStringSlice& slice)
+{
+ return slice.indexOf('\\') >= 0;
+}
+
bool JSONStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice)
{
const char* cur = slice.begin();
@@ -868,6 +890,23 @@ StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style)
}
}
+/* static */bool StringEscapeUtil::isQuoted(char quoteChar, UnownedStringSlice& slice)
+{
+ const Index len = slice.getLength();
+ return len >= 2 && slice[0] == quoteChar && slice[len - 1] == quoteChar;
+}
+
+/* static */UnownedStringSlice StringEscapeUtil::unquote(char quoteChar, const UnownedStringSlice& slice)
+{
+ const Index len = slice.getLength();
+ if (len >= 2 && slice[0] == quoteChar && slice[len - 1] == quoteChar)
+ {
+ return UnownedStringSlice(slice.begin() + 1, len - 2);
+ }
+ SLANG_ASSERT(!"Not quoted!");
+ return UnownedStringSlice();
+}
+
/* static */SlangResult StringEscapeUtil::appendMaybeUnquoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out)
{
const char quoteChar = handler->getQuoteChar();
@@ -885,6 +924,10 @@ StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style)
}
}
+/* static */SlangResult StringEscapeUtil::isUnescapeShellLikeNeeded(Handler* handler, const UnownedStringSlice& slice)
+{
+ return slice.indexOf(handler->getQuoteChar()) >= 0;
+}
/* static */SlangResult StringEscapeUtil::unescapeShellLike(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out)
{
diff --git a/source/core/slang-string-escape-util.h b/source/core/slang-string-escape-util.h
index c3039eb47..5f749c423 100644
--- a/source/core/slang-string-escape-util.h
+++ b/source/core/slang-string-escape-util.h
@@ -14,6 +14,9 @@ public:
virtual bool isQuotingNeeded(const UnownedStringSlice& slice) = 0;
/// True if any escaping is needed. If not slice can be used (assuming appropriate quoting) as is
virtual bool isEscapingNeeded(const UnownedStringSlice& slice) = 0;
+ /// True if we need to unescape
+ virtual bool isUnescapingNeeeded(const UnownedStringSlice& slice) = 0;
+
/// Takes slice and adds any appropriate escaping (for example C++/C type escaping for special characters like '\', '"' and if not ascii will write out as hex sequence)
/// Does not append quotes
virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) = 0;
@@ -57,6 +60,14 @@ struct StringEscapeUtil
/// Given a style returns a handler
static Handler* getHandler(Style style);
+ /// Get without quotes. Will assert if not correctly quoted
+ static UnownedStringSlice unquote(char quoteChar, const UnownedStringSlice& slice);
+ static UnownedStringSlice unquote(Handler* handler, const UnownedStringSlice& slice) { return unquote(handler->getQuoteChar(), slice); }
+
+ /// True is slice is quoted
+ static bool isQuoted(char quoteChar, UnownedStringSlice& slice);
+ static bool isQuoted(Handler* handler, UnownedStringSlice& slice) { return isQuoted(handler->getQuoteChar(), slice); }
+
/// If quoting is needed appends to out quoted
static SlangResult appendMaybeQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out);
@@ -69,6 +80,11 @@ struct StringEscapeUtil
/// Append with quotes (even if not needed)
static SlangResult appendQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out);
+
+ /// True if requires 'shell-like' unescape. With shell-like, quoting does *not* have to start at the start of the slice.
+ /// and there may be multiple quoted section
+ static SlangResult isUnescapeShellLikeNeeded(Handler* handler, const UnownedStringSlice& slice);
+
/// Shells can have multiple quoted sections. This function makes a string with out quoting
static SlangResult unescapeShellLike(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out);
};
diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp
index 7a142f643..b2886c413 100644
--- a/source/core/slang-string-util.cpp
+++ b/source/core/slang-string-util.cpp
@@ -458,9 +458,31 @@ ComPtr<ISlangBlob> StringUtil::createStringBlob(const String& string)
}
}
-SLANG_FORCE_INLINE static bool _isDigit(char c)
+/* static */SlangResult StringUtil::parseDouble(const UnownedStringSlice& text, double& out)
{
- return (c >= '0' && c <= '9');
+ const Index bufSize = 32;
+
+ const auto len = text.getLength();
+
+ if (len > bufSize - 1)
+ {
+ List<char> work;
+ work.setCount(len + 1);
+ char* dst = work.getBuffer();
+
+ ::memcpy(dst, text.begin(), len * sizeof(char));
+ dst[len] = 0;
+
+ out = atof(dst);
+ }
+ else
+ {
+ char buf[bufSize];
+ ::memcpy(buf, text.begin(), len * sizeof(char));
+ buf[len] = 0;
+ out = atof(buf);
+ }
+ return SLANG_OK;
}
/* static */SlangResult StringUtil::parseInt(const UnownedStringSlice& in, Int& outValue)
@@ -476,7 +498,7 @@ SLANG_FORCE_INLINE static bool _isDigit(char c)
}
// We need at least one digit
- if (cur >= end || !_isDigit(*cur))
+ if (cur >= end || !CharUtil::isDigit(*cur))
{
return SLANG_FAIL;
}
@@ -486,7 +508,7 @@ SLANG_FORCE_INLINE static bool _isDigit(char c)
for (; cur < end; ++cur)
{
const char c = *cur;
- if (!_isDigit(c))
+ if (!CharUtil::isDigit(c))
{
return SLANG_FAIL;
}
@@ -499,4 +521,74 @@ SLANG_FORCE_INLINE static bool _isDigit(char c)
return SLANG_OK;
}
+/* static */SlangResult StringUtil::parseInt64(const UnownedStringSlice& text, int64_t& out)
+{
+ bool negate = false;
+
+ const char* cur = text.begin();
+ const char* end = text.end();
+
+ if (cur < end)
+ {
+ if (*cur == '-')
+ {
+ negate = true;
+ cur++;
+ }
+ else if (*cur == '+')
+ {
+ cur++;
+ }
+ }
+
+ // Must have at least one digit
+ if (cur >= end || !CharUtil::isDigit(*cur))
+ {
+ return SLANG_FAIL;
+ }
+
+ uint64_t value = 0;
+ // We can have 20 digits, but the last digit can cause overflow.
+ // Lets do the easy first digits first
+ Index numSimple = 19;
+ for (; cur < end && CharUtil::isDigit(*cur) && numSimple > 0; ++cur, --numSimple)
+ {
+ value = value * 10 + (*cur - '0');
+ }
+
+ if (cur < end && CharUtil::isDigit(*cur))
+ {
+ const auto prevValue = value;
+ value = value * 10 + (*cur - '0');
+ cur++;
+
+ if (value < prevValue)
+ {
+ // We have overflow
+ return SLANG_FAIL;
+ }
+ }
+
+ if (negate)
+ {
+ if (value > ~((~uint64_t(0)) >> 1))
+ {
+ // Overflow
+ return SLANG_FAIL;
+ }
+ out = -int64_t(value);
+ }
+ else
+ {
+ if (value > ((~uint64_t(0)) >> 1))
+ {
+ // Overflow
+ return SLANG_FAIL;
+ }
+ out = value;
+ }
+
+ return (cur == end) ? SLANG_OK : SLANG_FAIL;
+}
+
} // namespace Slang
diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h
index 2b30120b7..6a0794082 100644
--- a/source/core/slang-string-util.h
+++ b/source/core/slang-string-util.h
@@ -100,6 +100,12 @@ struct StringUtil
/// Convert in to int. Returns SLANG_FAIL on error
static SlangResult parseInt(const UnownedStringSlice& in, Int& outValue);
+
+ /// Convert ioText into double. Returns SLANG_OK on success.
+ static SlangResult parseDouble(const UnownedStringSlice& text, double& out);
+
+ /// Convert into int64_t. Returns SLANG_OK on success.
+ static SlangResult parseInt64(const UnownedStringSlice& text, int64_t& out);
};
/* A helper class that allows parsing of lines from text with iteration. Uses StringUtil::extractLine for the actual underlying implementation. */