diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/compiler-core/slang-json-value.cpp | 261 | ||||
| -rw-r--r-- | source/compiler-core/slang-json-value.h | 77 | ||||
| -rw-r--r-- | source/core/slang-string.cpp | 60 | ||||
| -rw-r--r-- | source/core/slang-string.h | 8 |
4 files changed, 386 insertions, 20 deletions
diff --git a/source/compiler-core/slang-json-value.cpp b/source/compiler-core/slang-json-value.cpp index ba4ccad09..9edb81b67 100644 --- a/source/compiler-core/slang-json-value.cpp +++ b/source/compiler-core/slang-json-value.cpp @@ -22,6 +22,8 @@ namespace Slang { JSONValue::Kind::Float, // FloatValue, JSONValue::Kind::String, // StringValue, + JSONValue::Kind::String, // StringRepresentation + JSONValue::Kind::Array, // Array, JSONValue::Kind::Object, // Object, }; @@ -143,6 +145,221 @@ double JSONValue::asFloat() const /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + PersistentJSONValue + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +PersistentJSONValue::PersistentJSONValue(const ThisType& rhs) +{ + *(JSONValue*)this = rhs; + + if (type == Type::StringRepresentation && stringRep) + { + stringRep->addReference(); + } +} + +void PersistentJSONValue::operator=(const ThisType& rhs) +{ + if (this != &rhs) + { + if (rhs.type == Type::StringRepresentation && rhs.stringRep) + { + rhs.stringRep->addReference(); + } + if (type == Type::StringRepresentation && stringRep) + { + stringRep->releaseReference(); + } + *(JSONValue*)this = rhs; + } +} + +String PersistentJSONValue::getString() const +{ + if (type == Type::StringRepresentation) + { + return String(stringRep); + } + SLANG_ASSERT(!"Not a string type"); + return String(); +} + +UnownedStringSlice PersistentJSONValue::getSlice() const +{ + if (type == Type::StringRepresentation) + { + return StringRepresentation::asSlice(stringRep); + } + SLANG_ASSERT(!"Not a string type"); + return UnownedStringSlice(); +} + +void PersistentJSONValue::set(const UnownedStringSlice& slice, SourceLoc inLoc) +{ + StringRepresentation* oldRep = (type == JSONValue::Type::StringRepresentation) ? stringRep : nullptr; + + type = Type::StringRepresentation; + loc = inLoc; + + StringRepresentation* newRep = nullptr; + + const auto sliceLength = slice.getLength(); + + // If we have an oldRep that is unique and large enough reuse it + if (sliceLength) + { + if (oldRep && + oldRep->isUniquelyReferenced() && + sliceLength <= oldRep->capacity) + { + oldRep->setContents(slice); + newRep = oldRep; + // We are reusing so make null so not freed + oldRep = nullptr; + } + else + { + newRep = StringRepresentation::createWithReference(slice); + } + + SLANG_ASSERT(newRep->debugGetReferenceCount() >= 1); + } + + stringRep = newRep; + + if (oldRep) + { + oldRep->releaseReference(); + } +} + +void PersistentJSONValue::_init(const UnownedStringSlice& slice, SourceLoc inLoc) +{ + loc = inLoc; + type = Type::StringRepresentation; + stringRep = StringRepresentation::createWithReference(slice); +} + +bool PersistentJSONValue::operator==(const ThisType& rhs) const +{ + if (this == &rhs) + { + return true; + } + + if (type != rhs.type || + loc != rhs.loc) + { + return false; + } + + switch (type) + { + case Type::Invalid: + case Type::True: + case Type::False: + case Type::Null: + { + // The type is all that needs to be checked + return true; + } + case Type::IntegerValue: return intValue == rhs.intValue; + case Type::FloatValue: return floatValue == rhs.floatValue; + case Type::StringRepresentation: + { + if (stringRep == rhs.stringRep) + { + return true; + } + auto thisSlice = StringRepresentation::asSlice(stringRep); + auto rhsSlice = StringRepresentation::asSlice(rhs.stringRep); + return thisSlice == rhsSlice; + } + default: break; + } + + SLANG_ASSERT(!"Not valid Persistent type"); + return false; +} + +void PersistentJSONValue::_init(const JSONValue& in, JSONContainer* container) +{ + // We are assuming this is invalid, so it can't be the same as in + SLANG_ASSERT(&in != this); + + switch (in.type) + { + case Type::StringValue: + case Type::StringLexeme: + { + if (!container) + { + SLANG_ASSERT(!"Requires container"); + return; + } + _init(container->getTransientString(in), in.loc); + break; + } + case Type::StringRepresentation: + { + *(JSONValue*)this = in; + if (stringRep) + { + stringRep->addReference(); + } + break; + } + case Type::IntegerLexeme: + { + type = JSONValue::Type::IntegerValue; + intValue = container->asInteger(in); + loc = in.loc; + break; + } + case Type::FloatLexeme: + { + type = JSONValue::Type::FloatValue; + floatValue = container->asFloat(in); + loc = in.loc; + break; + } + case Type::Array: + case Type::Object: + { + SLANG_ASSERT(!"Not a simple JSON type"); + break; + } + default: + { + *(JSONValue*)this = in; + break; + } + } +} + +void PersistentJSONValue::set(const JSONValue& in, JSONContainer* container) +{ + if (&in != this) + { + if (type == Type::StringRepresentation) + { + StringRepresentation* oldStringRep = stringRep; + _init(in, container); + if (oldStringRep) + { + oldStringRep->releaseReference(); + } + } + else + { + _init(in, container); + } + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + JSONContainer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -279,8 +496,8 @@ ConstArrayView<JSONValue> JSONContainer::getArray(const JSONValue& in) const ConstArrayView<JSONKeyValue> JSONContainer::getObject(const JSONValue& in) const { - SLANG_ASSERT(in.type == JSONValue::Type::Array); - if (in.type != JSONValue::Type::Array || in.rangeIndex == 0) + SLANG_ASSERT(in.type == JSONValue::Type::Object); + if (in.type != JSONValue::Type::Object || in.rangeIndex == 0) { return ConstArrayView<JSONKeyValue>((const JSONKeyValue*)nullptr, 0); } @@ -339,17 +556,25 @@ UnownedStringSlice JSONContainer::getLexeme(const JSONValue& in) UnownedStringSlice JSONContainer::getString(const JSONValue& in) { - if (in.type == JSONValue::Type::StringValue) - { - return getStringFromKey(in.stringKey); - } - else if (in.type == JSONValue::Type::StringLexeme) + switch (in.type) { - auto slice = getTransientString(in); - auto handle = m_slicePool.add(slice); - return m_slicePool.getSlice(handle); + case JSONValue::Type::StringValue: + { + return getStringFromKey(in.stringKey); + } + case JSONValue::Type::StringLexeme: + { + auto slice = getTransientString(in); + auto handle = m_slicePool.add(slice); + return m_slicePool.getSlice(handle); + } + case JSONValue::Type::StringRepresentation: + { + return StringRepresentation::asSlice(in.stringRep); + } + default: break; } - + SLANG_ASSERT(!"Not a string type"); return UnownedStringSlice(); } @@ -358,6 +583,10 @@ UnownedStringSlice JSONContainer::getTransientString(const JSONValue& in) { switch (in.type) { + case JSONValue::Type::StringRepresentation: + { + return StringRepresentation::asSlice(in.stringRep); + } case JSONValue::Type::StringValue: { return getStringFromKey(in.stringKey); @@ -917,7 +1146,11 @@ bool JSONContainer::areEqual(const JSONValue& a, const JSONValue& b) case JSONValue::Type::IntegerValue: return a.intValue == b.intValue; case JSONValue::Type::FloatValue: return a.floatValue == b.floatValue; case JSONValue::Type::StringValue: return a.stringKey == b.stringKey; - + case JSONValue::Type::StringRepresentation: + { + return a.stringRep == b.stringRep || + StringRepresentation::asSlice(a.stringRep) == StringRepresentation::asSlice(b.stringRep); + } case JSONValue::Type::Array: { if (a.rangeIndex == b.rangeIndex) @@ -982,6 +1215,10 @@ void JSONContainer::traverseRecursively(const JSONValue& value, JSONListener* li const auto slice = getStringFromKey(value.stringKey); return listener->addStringValue(slice, value.loc); } + case Type::StringRepresentation: + { + return listener->addStringValue(getTransientString(value), value.loc); + } case Type::Array: { listener->startArray(value.loc); diff --git a/source/compiler-core/slang-json-value.h b/source/compiler-core/slang-json-value.h index 2e8707a87..25e74cb36 100644 --- a/source/compiler-core/slang-json-value.h +++ b/source/compiler-core/slang-json-value.h @@ -50,6 +50,8 @@ struct JSONValue FloatValue, StringValue, + StringRepresentation, + Array, Object, @@ -105,14 +107,14 @@ struct JSONValue union { - Index rangeIndex; ///< Used for Array/Object - Index length; ///< Length in bytes if it is a 'Lexeme' - double floatValue; ///< Float value - int64_t intValue; ///< Integer value - JSONKey stringKey; ///< The pool key if it's a string + Index rangeIndex; ///< Used for Array/Object + Index length; ///< Length in bytes if it is a 'Lexeme' + double floatValue; ///< Float value + int64_t intValue; ///< Integer value + JSONKey stringKey; ///< The pool key if it's a string + StringRepresentation* stringRep; ///< Only ever used on a 'PersistentJSONValue' }; - static const Kind g_typeToKind[Index(Type::CountOf)]; static const OtherRttiInfo g_rttiInfo; @@ -145,6 +147,65 @@ struct JSONKeyValue static JSONKeyValue g_invalid; }; +class JSONContainer; + +/* Is similar to JSONValue, but is designed to + +* Only be able to hold 'Simple' types (ie not array/object) +* Does not reference/require JSONContainer. + +Not requiring JSONContainer means it's useful to hold state when JSONContainer goes out of scope. +Care may need to be taken if sourceManager goes out of scope, sourceLocs may become invalid. This +is true of a regular JSONValue. + +Care must also be taken because it is derived from JSONValue. It *can* be sliced and work correctly, +but *requires* that the PersistentJSONValue with same value to stay in scope in general. In practice +this is only an issue with StringRepresention type. +*/ +class PersistentJSONValue : public JSONValue +{ +public: + typedef JSONValue Super; + typedef PersistentJSONValue ThisType; + + /// If it's a string type this will always work + String getString() const; + UnownedStringSlice getSlice() const; + + /// Set to the value + void set(const JSONValue& in, JSONContainer* container); + /// Set directly to a string + void set(const UnownedStringSlice& slice, SourceLoc loc); + + /// True if identical + bool operator==(const ThisType& rhs) const; + bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + + /// Assignable + void operator=(const ThisType& rhs); + + PersistentJSONValue(const JSONValue& in, JSONContainer* container) { _init(in, container); } + PersistentJSONValue(const JSONValue& in, JSONContainer* container, SourceLoc inLoc) { _init(in, container); loc = inLoc; } + + /// Copy Ctor + PersistentJSONValue(const ThisType& rhs); + /// Default Ctor (will be set to invalid) + PersistentJSONValue() {} + + + ~PersistentJSONValue() + { + if (type == Type::StringRepresentation && stringRep) + { + stringRep->releaseReference(); + } + } +protected: + /// Assumes this has no valid data + void _init(const JSONValue& in, JSONContainer* container); + void _init(const UnownedStringSlice& slice, SourceLoc loc); +}; + class JSONContainer : public RefObject { public: @@ -170,7 +231,7 @@ public: /// Returns the index of key in obj, or -1 if not found Index findObjectIndex(const JSONValue& obj, JSONKey key) const; - /// Get the value in the object at key. REturns invalid if not found. + /// Get the value in the object at key. Returns invalid if not found. JSONValue findObjectValue(const JSONValue& obj, JSONKey key) const; /// Returns the index @@ -201,7 +262,7 @@ public: /// Get as a string. The contents will stay in scope as long as the container UnownedStringSlice getString(const JSONValue& in); - /// Gets the lexeme + /// Gets the lexeme UnownedStringSlice getLexeme(const JSONValue& in); /// Get a key for a name diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp index e21333809..1a6221cc8 100644 --- a/source/core/slang-string.cpp +++ b/source/core/slang-string.cpp @@ -11,6 +11,66 @@ namespace Slang // for anything that uses core static const auto s_charUtilLink = CharUtil::_ensureLink(); + + // StringRepresentation + + void StringRepresentation::setContents(const UnownedStringSlice& slice) + { + const auto sliceLength = slice.getLength(); + SLANG_ASSERT(sliceLength <= capacity); + + char* chars = getData(); + + // Use move (rather than memcpy), because the slice *could* be contained in the StringRepresentation + ::memmove(chars, slice.begin(), sliceLength * sizeof(char)); + // Zero terminate. + chars[sliceLength] = 0; + // Set the length + length = sliceLength; + } + + + /* static */StringRepresentation* StringRepresentation::create(const UnownedStringSlice& slice) + { + const auto sliceLength = slice.getLength(); + + if (sliceLength) + { + StringRepresentation* rep = StringRepresentation::createWithLength(sliceLength); + + char* chars = rep->getData(); + ::memcpy(chars, slice.begin(), sizeof(char) * sliceLength); + chars[sliceLength] = 0; + + return rep; + } + else + { + return nullptr; + } + } + + /* static */StringRepresentation* StringRepresentation::createWithReference(const UnownedStringSlice& slice) + { + const auto sliceLength = slice.getLength(); + + if (sliceLength) + { + StringRepresentation* rep = StringRepresentation::createWithLength(sliceLength); + rep->addReference(); + + char* chars = rep->getData(); + ::memcpy(chars, slice.begin(), sizeof(char) * sliceLength); + chars[sliceLength] = 0; + + return rep; + } + else + { + return nullptr; + } + } + // OSString OSString::OSString() diff --git a/source/core/slang-string.h b/source/core/slang-string.h index 85f7b894f..cb13ec415 100644 --- a/source/core/slang-string.h +++ b/source/core/slang-string.h @@ -210,6 +210,9 @@ namespace Slang return (const char*)(this + 1); } + /// Set the contents to be the slice. Must be enough capacity to hold the slice. + void setContents(const UnownedStringSlice& slice); + static const char* getData(const StringRepresentation* stringRep) { return stringRep ? stringRep->getData() : ""; @@ -246,6 +249,11 @@ namespace Slang return createWithCapacityAndLength(length, length); } + /// Create a representation from the slice. If slice is empty will return nullptr. + static StringRepresentation* create(const UnownedStringSlice& slice); + /// Same as create, but representation will have refcount of 1 (if not nullptr) + static StringRepresentation* createWithReference(const UnownedStringSlice& slice); + StringRepresentation* cloneWithCapacity(Index newCapacity) { StringRepresentation* newObj = createWithCapacityAndLength(newCapacity, length); |
