[Native] Add non-owning strings
diff --git a/kotlin-native/runtime/src/main/cpp/KString.cpp b/kotlin-native/runtime/src/main/cpp/KString.cpp index f593cc4..e59d5c7 100644 --- a/kotlin-native/runtime/src/main/cpp/KString.cpp +++ b/kotlin-native/runtime/src/main/cpp/KString.cpp
@@ -205,6 +205,21 @@ }); } +extern "C" OBJ_GETTER(CreateBorrowedString, StringEncoding encoding, const char* data, uint32_t length) { + if (length == 0) RETURN_RESULT_OF0(TheEmptyString); + if (encoding == StringEncoding::kUTF8 && utf8StringIsASCII(data, length)) { + encoding = StringEncoding::kLatin1; + } + auto flags = (static_cast<uint32_t>(encoding) << StringHeader::ENCODING_OFFSET) | StringHeader::BORROWED; + auto result = AllocArrayInstance(theStringTypeInfo, StringHeader::extraLength(flags) / sizeof(KChar), OBJ_RESULT); + auto header = StringHeader::of(result); + header->flags_ = flags; + auto desc = reinterpret_cast<StringHeader::BorrowedData*>(header->data_); + desc->size_ = length; + desc->data_ = const_cast<char*>(data); + return result; +} + extern "C" char* CreateCStringFromString(KConstRef kref) { if (kref == nullptr) return nullptr; std::string utf8 = kotlin::to_string<KStringConversionMode::UNCHECKED>(kref);
diff --git a/kotlin-native/runtime/src/main/cpp/KString.h b/kotlin-native/runtime/src/main/cpp/KString.h index 8cba01e..a8018aa 100644 --- a/kotlin-native/runtime/src/main/cpp/KString.h +++ b/kotlin-native/runtime/src/main/cpp/KString.h
@@ -36,23 +36,30 @@ uint16_t flags_; alignas(KChar) char data_[]; + struct __attribute__((packed)) BorrowedData { + uint16_t padding_; + uint32_t size_; + char *data_; + }; + enum { HASHCODE_COMPUTED = 1 << 0, IGNORE_LAST_BYTE = 1 << 1, + BORROWED = 1 << 2, ENCODING_OFFSET = 12, }; ALWAYS_INLINE StringEncoding encoding() const { return static_cast<StringEncoding>(flags_ >> ENCODING_OFFSET); } - ALWAYS_INLINE char *data() { return data_; } - ALWAYS_INLINE const char *data() const { return data_; } - ALWAYS_INLINE size_t size() const { return count_ * sizeof(KChar) - extraLength(flags_); } + ALWAYS_INLINE char *data() { return flags_ & BORROWED ? reinterpret_cast<BorrowedData*>(data_)->data_ : data_; } + ALWAYS_INLINE const char *data() const { return flags_ & BORROWED ? reinterpret_cast<const BorrowedData*>(data_)->data_ : data_; } + ALWAYS_INLINE size_t size() const { return flags_ & BORROWED ? reinterpret_cast<const BorrowedData*>(data_)->size_ : count_ * sizeof(KChar) - extraLength(flags_); } ALWAYS_INLINE static StringHeader* of(KRef string) { return reinterpret_cast<StringHeader*>(string); } ALWAYS_INLINE static const StringHeader* of(KConstRef string) { return reinterpret_cast<const StringHeader*>(string); } ALWAYS_INLINE constexpr static size_t extraLength(int flags) { - return (offsetof(StringHeader, data_) - sizeof(ArrayHeader)) + !!(flags & IGNORE_LAST_BYTE); + return (offsetof(StringHeader, data_) - sizeof(ArrayHeader)) + (flags & BORROWED ? sizeof(BorrowedData) : 0) + (flags & IGNORE_LAST_BYTE ? 1 : 0); } }; @@ -121,6 +128,7 @@ OBJ_GETTER(CreateStringFromUtf8OrThrow, const char* utf8, uint32_t length); OBJ_GETTER(CreateStringFromUtf16, const KChar* utf16, uint32_t length); OBJ_GETTER(CreateUninitializedString, StringEncoding encoding, uint32_t length); +OBJ_GETTER(CreateBorrowedString, StringEncoding encoding, const char* data, uint32_t length); char* CreateCStringFromString(KConstRef kstring); void DisposeCString(char* cstring);
diff --git a/kotlin-native/runtime/src/main/cpp/ObjCInteropUtils.mm b/kotlin-native/runtime/src/main/cpp/ObjCInteropUtils.mm index ea1e14d..e883ffd 100644 --- a/kotlin-native/runtime/src/main/cpp/ObjCInteropUtils.mm +++ b/kotlin-native/runtime/src/main/cpp/ObjCInteropUtils.mm
@@ -64,15 +64,23 @@ NSStringEncoding encoding = [immutableCopyOrSameStr fastestEncoding]; switch (encoding) { case NSUTF8StringEncoding: - result = CreateStringFromUtf8( - [immutableCopyOrSameStr UTF8String], - [immutableCopyOrSameStr lengthOfBytesUsingEncoding: encoding], OBJ_RESULT); + if (auto borrowed = CFStringGetCStringPtr((CFStringRef)immutableCopyOrSameStr, encoding)) { + result = CreateBorrowedString(StringEncoding::kUTF8, borrowed, strlen(borrowed), OBJ_RESULT); + } else { + result = CreateStringFromUtf8( + [immutableCopyOrSameStr UTF8String], + [immutableCopyOrSameStr lengthOfBytesUsingEncoding: encoding], OBJ_RESULT); + } break; case NSASCIIStringEncoding: case NSISOLatin1StringEncoding: - result = CreateUninitializedString(StringEncoding::kLatin1, length, OBJ_RESULT); - [immutableCopyOrSameStr getBytes: StringHeader::of(result)->data() maxLength: length usedLength: nullptr - encoding: encoding options: 0 range: NSMakeRange(0, length) remainingRange: nullptr]; + if (auto borrowed = CFStringGetCStringPtr((CFStringRef)immutableCopyOrSameStr, encoding)) { + result = CreateBorrowedString(StringEncoding::kLatin1, borrowed, strlen(borrowed), OBJ_RESULT); + } else { + result = CreateUninitializedString(StringEncoding::kLatin1, length, OBJ_RESULT); + [immutableCopyOrSameStr getBytes: StringHeader::of(result)->data() maxLength: length usedLength: nullptr + encoding: encoding options: 0 range: NSMakeRange(0, length) remainingRange: nullptr]; + } break; default: result = CreateUninitializedString(StringEncoding::kUTF16, length, OBJ_RESULT);