1 /** 2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H_ 17 #define PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H_ 18 19 #include "runtime/include/runtime.h" 20 #include "runtime/include/coretypes/string-inl.h" 21 #include "plugins/ets/runtime/types/ets_array.h" 22 #include "plugins/ets/runtime/types/ets_box_primitive.h" 23 #include "plugins/ets/runtime/types/ets_object.h" 24 #include "plugins/ets/runtime/napi/ets_napi.h" 25 #include <cmath> 26 27 namespace ark::ets { 28 29 // Private inheritance, because need to disallow implicit conversion to core type 30 class EtsString : private coretypes::String { 31 public: CreateFromMUtf8(const char * mutf8)32 static EtsString *CreateFromMUtf8(const char *mutf8) 33 { 34 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 35 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 36 if (mutf8 == nullptr) { 37 ThrowNullPointerException(ctx, ManagedThread::GetCurrent()); 38 return nullptr; 39 } 40 const auto *data = reinterpret_cast<const uint8_t *>(mutf8); 41 coretypes::String *s = coretypes::String::CreateFromMUtf8(data, ctx, Runtime::GetCurrent()->GetPandaVM()); 42 return reinterpret_cast<EtsString *>(s); 43 } 44 CreateFromMUtf8(const char * mutf8,uint32_t utf16Length)45 static EtsString *CreateFromMUtf8(const char *mutf8, uint32_t utf16Length) 46 { 47 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 48 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 49 if (utf16Length == 0) { 50 return reinterpret_cast<EtsString *>( 51 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 52 } 53 if (mutf8 == nullptr) { 54 ThrowNullPointerException(ctx, ManagedThread::GetCurrent()); 55 return nullptr; 56 } 57 const auto *data = reinterpret_cast<const uint8_t *>(mutf8); 58 coretypes::String *s = 59 coretypes::String::CreateFromMUtf8(data, utf16Length, ctx, Runtime::GetCurrent()->GetPandaVM()); 60 return reinterpret_cast<EtsString *>(s); 61 } 62 CreateFromUtf8(const char * utf8,uint32_t length)63 static EtsString *CreateFromUtf8(const char *utf8, uint32_t length) 64 { 65 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 66 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 67 if (length == 0) { 68 return reinterpret_cast<EtsString *>( 69 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 70 } 71 if (utf8 == nullptr) { 72 ThrowNullPointerException(ctx, ManagedThread::GetCurrent()); 73 return nullptr; 74 } 75 const auto *data = reinterpret_cast<const uint8_t *>(utf8); 76 return reinterpret_cast<EtsString *>( 77 coretypes::String::CreateFromUtf8(data, length, ctx, Runtime::GetCurrent()->GetPandaVM())); 78 } 79 CreateFromAscii(const char * str,uint32_t length)80 static EtsString *CreateFromAscii(const char *str, uint32_t length) 81 { 82 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 83 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 84 const auto *data = reinterpret_cast<const uint8_t *>(str); 85 return reinterpret_cast<EtsString *>( 86 coretypes::String::CreateFromMUtf8(data, length, length, true, ctx, Runtime::GetCurrent()->GetPandaVM())); 87 } 88 CreateFromUtf16(const ets_char * utf16,ets_int length)89 static EtsString *CreateFromUtf16(const ets_char *utf16, ets_int length) 90 { 91 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 92 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 93 if (length == 0) { 94 return reinterpret_cast<EtsString *>( 95 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 96 } 97 if (utf16 == nullptr) { 98 ThrowNullPointerException(ctx, ManagedThread::GetCurrent()); 99 return nullptr; 100 } 101 coretypes::String *s = 102 coretypes::String::CreateFromUtf16(utf16, length, ctx, Runtime::GetCurrent()->GetPandaVM()); 103 return reinterpret_cast<EtsString *>(s); 104 } 105 106 using CharCodeArray = EtsTypedObjectArray<EtsBoxPrimitive<EtsDouble>>; 107 CreateNewStringFromCharCode(CharCodeArray * charCodes)108 static EtsString *CreateNewStringFromCharCode(CharCodeArray *charCodes) 109 { 110 const size_t length = charCodes->GetLength(); 111 if (length == 0) { 112 return CreateNewEmptyString(); 113 } 114 115 // allocator may trig gc and move the 'charCodes' array, need to hold it 116 EtsCoroutine *coroutine = EtsCoroutine::GetCurrent(); 117 [[maybe_unused]] EtsHandleScope scope(coroutine); 118 EtsHandle arrayHandle(coroutine, charCodes); 119 120 auto isCompressed = [](CharCodeArray *codes) -> bool { 121 if (!Runtime::GetOptions().IsRuntimeCompressedStringsEnabled()) { 122 return false; 123 } 124 125 for (size_t i = 0; i < codes->GetLength(); ++i) { 126 if (!IsASCIICharacter(CodeToChar(codes->Get(i)->GetValue()))) { 127 return false; 128 } 129 } 130 return true; 131 }; 132 133 auto copyCharsIntoString = [](CharCodeArray *codes, auto *dstData) { 134 Span<std::remove_pointer_t<decltype(dstData)>> to(dstData, codes->GetLength()); 135 for (size_t i = 0; i < codes->GetLength(); ++i) { 136 to[i] = CodeToChar(codes->Get(i)->GetValue()); 137 } 138 }; 139 140 bool compress = isCompressed(arrayHandle.GetPtr()); 141 EtsString *s = AllocateNonInitializedString(length, compress); 142 if (compress) { 143 copyCharsIntoString(arrayHandle.GetPtr(), s->GetDataMUtf8()); 144 } else { 145 copyCharsIntoString(arrayHandle.GetPtr(), s->GetDataUtf16()); 146 } 147 return s; 148 } 149 CreateNewStringFromCharCode(EtsDouble charCode)150 static EtsString *CreateNewStringFromCharCode(EtsDouble charCode) 151 { 152 constexpr size_t SINGLE_CHAR_LENGTH = 1U; 153 uint16_t character = CodeToChar(charCode); 154 bool compress = Runtime::GetOptions().IsRuntimeCompressedStringsEnabled() && IsASCIICharacter(character); 155 EtsString *s = AllocateNonInitializedString(SINGLE_CHAR_LENGTH, compress); 156 ASSERT(s != nullptr); 157 auto putCharacterIntoString = [character](auto *dstData) { 158 Span<std::remove_pointer_t<decltype(dstData)>> to(dstData, SINGLE_CHAR_LENGTH); 159 to[0] = character; 160 }; 161 if (compress) { 162 putCharacterIntoString(s->GetDataMUtf8()); 163 } else { 164 putCharacterIntoString(s->GetDataUtf16()); 165 } 166 return s; 167 } 168 CreateNewStringFromChars(uint32_t offset,uint32_t length,EtsArray * chararray)169 static EtsString *CreateNewStringFromChars(uint32_t offset, uint32_t length, EtsArray *chararray) 170 { 171 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 172 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 173 return reinterpret_cast<EtsString *>(coretypes::String::CreateNewStringFromChars( 174 offset, length, reinterpret_cast<coretypes::Array *>(chararray), ctx, Runtime::GetCurrent()->GetPandaVM())); 175 } 176 CreateNewStringFromBytes(EtsArray * bytearray,ets_int high,ets_int offset,ets_int length)177 static EtsString *CreateNewStringFromBytes(EtsArray *bytearray, ets_int high, ets_int offset, ets_int length) 178 { 179 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 180 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 181 if (length == 0) { 182 return reinterpret_cast<EtsString *>( 183 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 184 } 185 if (bytearray == nullptr) { 186 ThrowNullPointerException(ctx, ManagedThread::GetCurrent()); 187 return nullptr; 188 } 189 if (offset < 0 || length < 0 || bytearray->GetLength() < static_cast<uint32_t>(offset + length)) { 190 ThrowArrayIndexOutOfBoundsException(static_cast<uint32_t>(offset + length), bytearray->GetLength(), ctx, 191 ManagedThread::GetCurrent()); 192 return nullptr; 193 } 194 return reinterpret_cast<EtsString *>(coretypes::String::CreateNewStringFromBytes( 195 offset, length, static_cast<uint32_t>(high), reinterpret_cast<coretypes::Array *>(bytearray), ctx, 196 Runtime::GetCurrent()->GetPandaVM())); 197 } 198 CreateNewStringFromString(EtsString * etsString)199 static EtsString *CreateNewStringFromString(EtsString *etsString) 200 { 201 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 202 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 203 if (etsString == nullptr) { 204 ThrowNullPointerException(ctx, ManagedThread::GetCurrent()); 205 return nullptr; 206 } 207 coretypes::String *string = etsString->GetCoreType(); 208 return reinterpret_cast<EtsString *>( 209 coretypes::String::CreateFromString(string, ctx, Runtime::GetCurrent()->GetPandaVM())); 210 } 211 CreateNewEmptyString()212 static EtsString *CreateNewEmptyString() 213 { 214 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 215 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 216 return reinterpret_cast<EtsString *>( 217 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 218 } 219 Resolve(const uint8_t * mutf8,uint32_t length)220 static EtsString *Resolve(const uint8_t *mutf8, uint32_t length) 221 { 222 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 223 return reinterpret_cast<EtsString *>( 224 Runtime::GetCurrent()->ResolveString(Runtime::GetCurrent()->GetPandaVM(), mutf8, length, ctx)); 225 } 226 Concat(EtsString * etsString1,EtsString * etsString2)227 static EtsString *Concat(EtsString *etsString1, EtsString *etsString2) 228 { 229 ASSERT(etsString1 != nullptr); 230 ASSERT(etsString2 != nullptr); 231 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 232 ASSERT(etsString1 != nullptr); 233 ASSERT(etsString2 != nullptr); 234 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 235 coretypes::String *string3 = coretypes::String::Concat(etsString1->GetCoreType(), etsString2->GetCoreType(), 236 ctx, Runtime::GetCurrent()->GetPandaVM()); 237 return reinterpret_cast<EtsString *>(string3); 238 } 239 TrimLeft()240 EtsString *TrimLeft() 241 { 242 if (IsEmpty() || !utf::IsWhiteSpaceChar(At(0))) { 243 return this; 244 } 245 const auto numChars = GetLength(); 246 auto notWhiteSpaceIndex = numChars; 247 for (int i = 1; i < numChars; ++i) { 248 if (!utf::IsWhiteSpaceChar(At(i))) { 249 notWhiteSpaceIndex = i; 250 break; 251 } 252 } 253 auto len = numChars - notWhiteSpaceIndex; 254 return FastSubString(this, static_cast<uint32_t>(notWhiteSpaceIndex), static_cast<uint32_t>(len)); 255 } 256 TrimRight()257 EtsString *TrimRight() 258 { 259 if (IsEmpty()) { 260 return this; 261 } 262 auto last = GetLength() - 1; 263 if (!utf::IsWhiteSpaceChar(At(last))) { 264 return this; 265 } 266 int notWhiteSpaceIndex = -1; 267 for (int i = last - 1; i >= 0; --i) { 268 if (!utf::IsWhiteSpaceChar(At(i))) { 269 notWhiteSpaceIndex = i; 270 break; 271 } 272 } 273 auto len = notWhiteSpaceIndex + 1; 274 return EtsString::FastSubString(this, 0, static_cast<uint32_t>(len)); 275 } 276 Trim()277 EtsString *Trim() 278 { 279 if (IsEmpty()) { 280 return this; 281 } 282 int left = 0; 283 int right = GetLength() - 1; 284 while (utf::IsWhiteSpaceChar(At(right))) { 285 if (right == left) { 286 return EtsString::CreateNewEmptyString(); 287 } 288 --right; 289 } 290 while (left < right && utf::IsWhiteSpaceChar(At(left))) { 291 ++left; 292 } 293 return EtsString::FastSubString(this, left, static_cast<uint32_t>(right - left + 1)); 294 } 295 StartsWith(EtsString * prefix,EtsInt fromIndex)296 EtsBoolean StartsWith(EtsString *prefix, EtsInt fromIndex) 297 { 298 ASSERT(prefix != nullptr); 299 if (fromIndex < 0) { 300 fromIndex = 0; 301 } 302 auto prefixLen = prefix->GetLength(); 303 ASSERT(prefixLen >= 0); 304 if (fromIndex > GetLength() - prefixLen) { 305 return ToEtsBoolean(prefix->IsEmpty()); 306 } 307 auto *thisCoreType = GetCoreType(); 308 auto *prefCoreType = prefix->GetCoreType(); 309 for (EtsInt i = 0; i < prefixLen; ++i) { 310 if (thisCoreType->At<false>(fromIndex + i) != prefCoreType->At<false>(i)) { 311 return ToEtsBoolean(false); 312 } 313 } 314 return ToEtsBoolean(true); 315 } 316 EndsWith(EtsString * suffix,EtsInt endIndex)317 EtsBoolean EndsWith(EtsString *suffix, EtsInt endIndex) 318 { 319 ASSERT(suffix != nullptr); 320 if (suffix->IsEmpty()) { 321 return ToEtsBoolean(true); 322 } 323 auto strLen = GetLength(); 324 if (strLen == 0) { 325 return ToEtsBoolean(false); 326 } 327 if (endIndex <= 0) { 328 return ToEtsBoolean(false); 329 } 330 if (endIndex > strLen) { 331 endIndex = strLen; 332 } 333 ASSERT(endIndex > 0); 334 auto suffixLen = suffix->GetLength(); 335 auto fromIndex = endIndex - suffixLen; 336 if (fromIndex < 0) { 337 return ToEtsBoolean(false); 338 } 339 auto *thisCoreType = GetCoreType(); 340 auto *suffCoreType = suffix->GetCoreType(); 341 for (EtsInt i = 0; i < suffixLen; ++i) { 342 if (thisCoreType->At<false>(fromIndex + i) != suffCoreType->At<false>(i)) { 343 return ToEtsBoolean(false); 344 } 345 } 346 return ToEtsBoolean(true); 347 } 348 Compare(EtsString * rhs)349 int32_t Compare(EtsString *rhs) 350 { 351 return GetCoreType()->Compare(rhs->GetCoreType()); 352 } 353 At(int32_t index)354 uint16_t At(int32_t index) 355 { 356 return GetCoreType()->At(index); 357 } 358 DoReplace(EtsString * src,ets_char oldC,ets_char newC)359 static EtsString *DoReplace(EtsString *src, ets_char oldC, ets_char newC) 360 { 361 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 362 if (src->GetLength() == 0) { 363 return reinterpret_cast<EtsString *>( 364 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 365 } 366 coretypes::String *result = coretypes::String::DoReplace(reinterpret_cast<coretypes::String *>(src), oldC, newC, 367 ctx, Runtime::GetCurrent()->GetPandaVM()); 368 return reinterpret_cast<EtsString *>(result); 369 } 370 FastSubString(EtsString * src,uint32_t start,uint32_t length)371 static EtsString *FastSubString(EtsString *src, uint32_t start, uint32_t length) 372 { 373 ASSERT(src != nullptr); 374 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 375 coretypes::String *string1 = src->GetCoreType(); 376 coretypes::String *string2 = 377 coretypes::String::FastSubString(string1, start, length, ctx, Runtime::GetCurrent()->GetPandaVM()); 378 return reinterpret_cast<EtsString *>(string2); 379 } 380 ToCharArray()381 EtsArray *ToCharArray() 382 { 383 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 384 auto *ret = GetCoreType()->ToCharArray(ctx); 385 if (UNLIKELY(ret == nullptr)) { 386 return nullptr; 387 } 388 return reinterpret_cast<EtsArray *>(ret); 389 } 390 IsUtf16()391 bool IsUtf16() 392 { 393 return GetCoreType()->IsUtf16(); 394 } 395 GetLength()396 ets_int GetLength() 397 { 398 return GetCoreType()->GetLength(); 399 } 400 CopyDataMUtf8(void * buf,size_t maxLength,bool isCString)401 size_t CopyDataMUtf8(void *buf, size_t maxLength, bool isCString) 402 { 403 return GetCoreType()->CopyDataMUtf8(reinterpret_cast<uint8_t *>(buf), maxLength, isCString); 404 } 405 CopyDataRegionUtf8(void * buf,size_t start,size_t length,size_t maxLength)406 size_t CopyDataRegionUtf8(void *buf, size_t start, size_t length, size_t maxLength) 407 { 408 return GetCoreType()->CopyDataRegionUtf8(reinterpret_cast<uint8_t *>(buf), start, length, maxLength); 409 } 410 CopyDataRegionMUtf8(void * buf,size_t start,size_t length,size_t maxLength)411 size_t CopyDataRegionMUtf8(void *buf, size_t start, size_t length, size_t maxLength) 412 { 413 return GetCoreType()->CopyDataRegionMUtf8(reinterpret_cast<uint8_t *>(buf), start, length, maxLength); 414 } 415 CopyDataUtf16(void * buf,uint32_t maxLength)416 uint32_t CopyDataUtf16(void *buf, uint32_t maxLength) 417 { 418 return GetCoreType()->CopyDataUtf16(reinterpret_cast<uint16_t *>(buf), maxLength); 419 } 420 CopyDataRegionUtf16(void * buf,uint32_t start,uint32_t length,uint32_t maxLength)421 uint32_t CopyDataRegionUtf16(void *buf, uint32_t start, uint32_t length, uint32_t maxLength) 422 { 423 return GetCoreType()->CopyDataRegionUtf16(reinterpret_cast<uint16_t *>(buf), start, length, maxLength); 424 } 425 ConvertToStringView(PandaVector<uint8_t> * buf)426 std::string_view ConvertToStringView(PandaVector<uint8_t> *buf) 427 { 428 if (IsUtf16()) { 429 size_t len = utf::Utf16ToUtf8Size(GetDataUtf16(), GetUtf16Length(), false) - 1; 430 buf->reserve(len); 431 utf::ConvertRegionUtf16ToUtf8(GetDataUtf16(), buf->data(), GetUtf16Length(), len, 0, false); 432 return {utf::Mutf8AsCString(buf->data()), len}; 433 } 434 return {utf::Mutf8AsCString(GetDataMUtf8()), static_cast<size_t>(GetLength())}; 435 } 436 GetMUtf8Length()437 uint32_t GetMUtf8Length() 438 { 439 return GetCoreType()->GetMUtf8Length(); 440 } 441 GetUtf16Length()442 uint32_t GetUtf16Length() 443 { 444 return GetCoreType()->GetUtf16Length(); 445 } 446 GetUtf8Length()447 uint32_t GetUtf8Length() 448 { 449 return GetCoreType()->GetUtf8Length(); 450 } 451 IsEqual(const char * str)452 bool IsEqual(const char *str) 453 { 454 auto *mutf8Str = utf::CStringAsMutf8(str); 455 return coretypes::String::StringsAreEqualMUtf8(GetCoreType(), mutf8Str, utf::MUtf8ToUtf16Size(mutf8Str)); 456 } 457 GetMutf8()458 PandaString GetMutf8() 459 { 460 size_t len = GetMUtf8Length(); 461 PandaString out; 462 out.resize(len - 1); 463 if (!IsUtf16()) { 464 // CopyData expects one byte preserved for zero at the end. For utf16 it will preserve itself 465 --len; 466 } 467 CopyDataMUtf8(out.data(), len, false); 468 return out; 469 } 470 GetUtf8()471 PandaString GetUtf8() 472 { 473 size_t len = GetUtf8Length(); 474 PandaString out; 475 out.resize(len); 476 CopyDataRegionUtf8(out.data(), 0, GetCoreType()->GetLength(), len); 477 return out; 478 } 479 GetDataUtf8()480 uint8_t *GetDataUtf8() 481 { 482 return GetCoreType()->GetDataUtf8(); 483 } 484 GetDataMUtf8()485 uint8_t *GetDataMUtf8() 486 { 487 return GetCoreType()->GetDataMUtf8(); 488 } 489 GetDataUtf16()490 uint16_t *GetDataUtf16() 491 { 492 return GetCoreType()->GetDataUtf16(); 493 } 494 IsEmpty()495 bool IsEmpty() 496 { 497 return GetCoreType()->IsEmpty(); 498 } 499 StringsAreEqual(EtsObject * obj)500 bool StringsAreEqual(EtsObject *obj) 501 { 502 return coretypes::String::StringsAreEqual(GetCoreType(), FromEtsObject(obj)->GetCoreType()); 503 } 504 GetCoreType()505 coretypes::String *GetCoreType() 506 { 507 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 508 return reinterpret_cast<coretypes::String *>(this); 509 } 510 AsObjectHeader()511 ObjectHeader *AsObjectHeader() 512 { 513 return reinterpret_cast<ObjectHeader *>(this); 514 } 515 AsObject()516 EtsObject *AsObject() 517 { 518 return reinterpret_cast<EtsObject *>(this); 519 } 520 AsObject()521 const EtsObject *AsObject() const 522 { 523 return reinterpret_cast<const EtsObject *>(this); 524 } 525 FromCoreType(coretypes::String * str)526 static EtsString *FromCoreType(coretypes::String *str) 527 { 528 return reinterpret_cast<EtsString *>(str); 529 } 530 FromEtsObject(EtsObject * obj)531 static EtsString *FromEtsObject(EtsObject *obj) 532 { 533 ASSERT(obj->GetClass()->GetRuntimeClass() == Runtime::GetCurrent() 534 ->GetClassLinker() 535 ->GetExtension(panda_file::SourceLang::ETS) 536 ->GetClassRoot(ClassRoot::STRING)); 537 return reinterpret_cast<EtsString *>(obj); 538 } 539 540 EtsString() = delete; 541 ~EtsString() = delete; 542 543 NO_COPY_SEMANTIC(EtsString); 544 NO_MOVE_SEMANTIC(EtsString); 545 546 private: 547 friend EtsString *StringBuilderToString(ObjectHeader *sb); 548 AllocateNonInitializedString(uint32_t length,bool compressed)549 static EtsString *AllocateNonInitializedString(uint32_t length, bool compressed) 550 { 551 ASSERT(length != 0); 552 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 553 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 554 return reinterpret_cast<EtsString *>( 555 coretypes::String::AllocStringObject(length, compressed, ctx, Runtime::GetCurrent()->GetPandaVM())); 556 } 557 CodeToChar(double code)558 static uint16_t CodeToChar(double code) 559 { 560 constexpr double UTF16_CHAR_DIVIDER = 0x10000; 561 return static_cast<uint16_t>(static_cast<int64_t>(std::fmod(code, UTF16_CHAR_DIVIDER))); 562 } 563 }; 564 565 } // namespace ark::ets 566 567 #endif // PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H_ 568