[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);