bool SymbolCell::operator==(const SymbolCell &other) const { if (isGlobalConstant() && other.isGlobalConstant()) { // Constant folding guarantees this works return this == &other; } if (byteLength() != other.byteLength()) { return false; } if (dataIsInline()) { auto thisInlineSymbol = static_cast<const InlineSymbolCell*>(this); auto otherInlineSymbol = static_cast<const InlineSymbolCell*>(&other); return memcmp( thisInlineSymbol->inlineData(), otherInlineSymbol->inlineData(), thisInlineSymbol->inlineByteLength()) == 0; } else { auto thisHeapSymbol = static_cast<const HeapSymbolCell*>(this); auto thisByteArray = thisHeapSymbol->heapByteArray(); auto otherByteArray = static_cast<const HeapSymbolCell*>(&other)->heapByteArray(); return thisByteArray->isEqual(otherByteArray, thisHeapSymbol->heapByteLength()); } }
bool StringCell::replaceBytes(const CharRange &range, const std::uint8_t *pattern, unsigned int patternBytes, unsigned int count) { assert(!isGlobalConstant()); const unsigned int requiredBytes = patternBytes * count; const unsigned int replacedBytes = range.byteCount(); // If we have exclusive access to our data and we're not resizing the string we can use the fast path if ((dataIsInline() || static_cast<HeapStringCell*>(this)->heapByteArray()->isExclusive()) && (requiredBytes == replacedBytes)) { std::uint8_t *copyDest = const_cast<std::uint8_t*>(range.startPointer); while(count--) { memmove(copyDest, pattern, patternBytes); copyDest += patternBytes; } } else { // Create a new string from pieces of the old string const std::uint64_t newByteLength = byteLength() + requiredBytes - replacedBytes; const auto newCharLength = charLength(); if (newByteLength > maximumByteLength()) { return false; } const ByteLengthType initialBytes = range.startPointer - utf8Data(); const ByteLengthType finalBytes = newByteLength - initialBytes - requiredBytes; const bool wasInline = dataIsInline(); const bool nowInline = newByteLength <= inlineDataSize(); SharedByteArray *oldByteArray = nullptr; SharedByteArray *newByteArray = nullptr; // Does this require a COW due to sharing our byte array? const bool needsCow = (!wasInline && !nowInline) && !static_cast<HeapStringCell*>(this)->heapByteArray()->isExclusive(); // Determine if we exceeded our current capacity or if we're using less than half of our allocated space // This will trigger a reallocation of our heap space const auto currentCapacity = byteCapacity(); const bool needHeapRealloc = (newByteLength > currentCapacity) || ((newByteLength < (currentCapacity / 2)) && !nowInline) || needsCow; std::uint8_t* destString; const std::uint8_t* copySource; if (!wasInline && nowInline) { // We're converting to an inline string destString = static_cast<InlineStringCell*>(this)->inlineData(); copySource = pattern; // Store our old byte array so we can unref it later // The code below will overwrite it with our new inline string oldByteArray = static_cast<HeapStringCell*>(this)->heapByteArray(); // Fill the initial chunk of the string memcpy(destString, utf8Data(), initialBytes); } else if (needHeapRealloc) { size_t byteArraySize = newByteLength; newByteArray = SharedByteArray::createInstance(byteArraySize); destString = newByteArray->data(); copySource = pattern; // Fill the initial chunk of the string memcpy(destString, utf8Data(), initialBytes); if (!wasInline) { // Store our old byte array so we can unref it later oldByteArray = static_cast<HeapStringCell*>(this)->heapByteArray(); } } else { destString = utf8Data(); // The initial chunk is already correct // Are our pattern bytes in the range we're about to overwrite? // We only need to check the end of the pattern because the pattern should only be completely inside our // completely outside our string if (((pattern + patternBytes) > (utf8Data() + initialBytes)) && ((pattern + patternBytes) <= (utf8Data() + byteLength()))) { // Create a temporary copy to work with copySource = new std::uint8_t[patternBytes]; memcpy(const_cast<std::uint8_t*>(copySource), pattern, patternBytes); } else { copySource = pattern; } } // Move the unchanged chunk at the end // We need to do this now because if the pattern bytes are longer than the byte we're replacing then we might // overwrite the beginning of the unchanged chunk memmove(destString + initialBytes + requiredBytes, range.startPointer + replacedBytes, finalBytes); std::uint8_t* copyDest = destString + initialBytes; while(count--) { memcpy(copyDest, copySource, patternBytes); copyDest += patternBytes; } if (copySource != pattern) { delete[] copySource; } // Update ourselves with our new string setLengths(newByteLength, newCharLength); if (newByteArray) { static_cast<HeapStringCell*>(this)->setHeapByteArray(newByteArray); } if (oldByteArray != nullptr) { // We can unref this now oldByteArray->unref(); } } return true; }