bool StringCell::operator==(const StringCell &other) const { if (byteLength() != other.byteLength()) { return false; } if (dataIsInline()) { auto thisInlineString = static_cast<const InlineStringCell*>(this); auto otherInlineString = static_cast<const InlineStringCell*>(&other); return memcmp( thisInlineString->inlineData(), otherInlineString->inlineData(), thisInlineString->inlineByteLength()) == 0; } else { auto thisHeapString = static_cast<const HeapStringCell*>(this); auto thisByteArray = thisHeapString->heapByteArray(); auto otherByteArray = static_cast<const HeapStringCell*>(&other)->heapByteArray(); return thisByteArray->isEqual(otherByteArray, thisHeapString->heapByteLength()); } }
StringCell* StringCell::fromSymbol(World &world, SymbolCell *symbol) { alloc::SymbolRef symbolRef(world, symbol); void *cellPlacement = alloc::allocateCells(world); if (symbolRef->dataIsInline()) { auto inlineSymbol = static_cast<InlineSymbolCell*>(symbolRef.data()); auto inlineString = new (cellPlacement) InlineStringCell( inlineSymbol->inlineByteLength(), inlineSymbol->inlineCharLength() ); // Copy the inline data over const void *srcData = inlineSymbol->inlineData(); memcpy(inlineString->inlineData(), srcData, inlineSymbol->inlineByteLength()); return inlineString; } else { auto heapSymbol = static_cast<HeapSymbolCell*>(symbolRef.data()); // Share the heap symbols's byte array return new (cellPlacement) HeapStringCell( heapSymbol->heapByteArray()->ref(), heapSymbol->heapByteLength(), heapSymbol->heapCharLength() ); } }
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()); } }
StringCell* StringCell::createUninitialized(World &world, ByteLengthType byteLength, CharLengthType charLength) { void *cellPlacement = alloc::allocateCells(world); if (byteLength <= inlineDataSize()) { // We can fit this string inline auto newString = new (cellPlacement) InlineStringCell(byteLength, charLength); #ifndef NDEBUG if (byteLength < inlineDataSize()) { // Explicitly terminate with non-NULL to catch users that assume we're NULL terminated internally newString->inlineData()[byteLength] = 0xff; } #endif return newString; } else { // Allocate a new shared byte array SharedByteArray *newByteArray = SharedByteArray::createInstance(byteLength); #ifndef NDEBUG if (newByteArray->capacity(byteLength) > byteLength) { newByteArray->data()[byteLength] = 0xff; } #endif return new (cellPlacement) HeapStringCell(newByteArray, byteLength, charLength); } }
SymbolCell* SymbolCell::fromUtf8Data(World &world, const std::uint8_t *data, ByteLengthType byteLength) { const std::uint8_t *scanPtr = data; const std::uint8_t *endPtr = data + byteLength; // Validate the UTF-8 data const std::size_t charLength = utf8::validateData(scanPtr, endPtr); void *cellPlacement = alloc::allocateCells(world); if (byteLength <= inlineDataSize()) { auto inlineSymbol = new (cellPlacement) InlineSymbolCell(byteLength, charLength); memcpy(inlineSymbol->inlineData(), data, byteLength); return inlineSymbol; } else { SharedByteArray *newByteArray = SharedByteArray::createUninitialised(byteLength); memcpy(newByteArray->data(), data, byteLength); return new (cellPlacement) HeapSymbolCell(newByteArray, byteLength, charLength); } }
SymbolCell* SymbolCell::fromString(World &world, StringCell *string) { void *cellPlacement = alloc::allocateCells(world); // Symbols must have the same inlining threshold as strings for the below logic to work static_assert( sizeof(InlineSymbolCell::m_inlineData) == sizeof(InlineStringCell::m_inlineData), "Symbols and strings must have the same inlining threshold" ); if (string->dataIsInline()) { auto inlineString = static_cast<InlineStringCell*>(string); auto inlineSymbol = new (cellPlacement) InlineSymbolCell( inlineString->inlineByteLength(), inlineString->inlineCharLength() ); // Copy the inline data over const void *srcData = inlineString->inlineData(); memcpy(inlineSymbol->inlineData(), srcData, inlineString->inlineByteLength()); return inlineSymbol; } else { auto heapString = static_cast<HeapStringCell*>(string); // Share the heap strings's byte array return new (cellPlacement) HeapSymbolCell( heapString->heapByteArray()->ref(), heapString->heapByteLength(), heapString->heapCharLength() ); } }
SharedByteHash::ResultType StringCell::sharedByteHash() const { if (dataIsInline()) { auto inlineString = static_cast<const InlineStringCell*>(this); SharedByteHash byteHasher; return byteHasher(inlineString->inlineData(), inlineString->inlineByteLength()); } else { auto heapString = static_cast<const HeapStringCell*>(this); return heapString->heapByteArray()->hashValue(heapString->heapByteLength()); } }