• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 COMMON_INTERFACES_OBJECTS_STRING_BASE_STRING_INL2_H
17 #define COMMON_INTERFACES_OBJECTS_STRING_BASE_STRING_INL2_H
18 
19 #include "securec.h"
20 
21 #include "common_components/base/config.h"
22 #include "common_interfaces/base/mem.h"
23 #include "common_interfaces/objects/string/base_string_declare.h"
24 #include "common_interfaces/objects/string/line_string.h"
25 #include "common_interfaces/objects/string/sliced_string.h"
26 #include "common_interfaces/objects/string/tree_string.h"
27 #include "common_interfaces/objects/utils/utf_utils.h"
28 
29 namespace common {
30 template <typename Allocator, objects_traits::enable_if_is_allocate<Allocator, BaseObject *>>
CreateFromUtf8(Allocator && allocator,const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress)31 BaseString *BaseString::CreateFromUtf8(Allocator &&allocator, const uint8_t *utf8Data, uint32_t utf8Len,
32                                        bool canBeCompress)
33 {
34     BaseString *string = nullptr;
35     if (canBeCompress) {
36         string = CreateLineString(allocator, utf8Len, true);
37         DCHECK_CC(string != nullptr);
38         std::copy(utf8Data, utf8Data + utf8Len, string->GetDataUtf8Writable());
39     } else {
40         ASSERT(UtfUtils::Utf8ToUtf16Size(utf8Data, utf8Len) <= utf8Len);
41         string = CreateLineString(allocator, utf8Len, false);
42         ASSERT(string != nullptr);
43         auto utf16Len = UtfUtils::ConvertRegionUtf8ToUtf16(utf8Data, string->GetDataUtf16Writable(),
44                                                            utf8Len, utf8Len);
45     #if !defined(NDEBUG)
46         auto calculatedLen = UtfUtils::Utf8ToUtf16Size(utf8Data, utf8Len);
47         ASSERT_PRINT(utf16Len == calculatedLen,
48                      "Bad utf8 to utf16 conversion!, utf16 length: " << utf16Len
49                      << ", calculated length: " << calculatedLen);
50     #endif
51         reinterpret_cast<LineString *>(string)->LineString::Trim(utf16Len);
52     }
53 
54     ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!");
55     return string;
56 }
57 
58 template <typename Allocator, objects_traits::enable_if_is_allocate<Allocator, BaseObject *>>
CreateFromUtf8CompressedSubString(Allocator && allocator,const ReadOnlyHandle<BaseString> string,uint32_t offset,uint32_t utf8Len)59 BaseString *BaseString::CreateFromUtf8CompressedSubString(Allocator &&allocator,
60                                                           const ReadOnlyHandle<BaseString> string,
61                                                           uint32_t offset, uint32_t utf8Len)
62 {
63     BaseString *subString = CreateLineString(allocator, utf8Len, true);
64     DCHECK_CC(subString != nullptr);
65 
66     auto *utf8Data = string->GetDataUtf8() + offset;
67     std::copy(utf8Data, utf8Data + utf8Len, subString->GetDataUtf8Writable());
68     ASSERT_PRINT(CanBeCompressed(subString), "String cannot be compressed!");
69     return subString;
70 }
71 
72 template <typename Allocator, objects_traits::enable_if_is_allocate<Allocator, BaseObject *>>
CreateFromUtf16(Allocator && allocator,const uint16_t * utf16Data,uint32_t utf16Len,bool canBeCompress)73 BaseString *BaseString::CreateFromUtf16(Allocator &&allocator, const uint16_t *utf16Data, uint32_t utf16Len,
74                                         bool canBeCompress)
75 {
76     auto string = CreateLineString(allocator, utf16Len, canBeCompress);
77     DCHECK_CC(string != nullptr);
78 
79     if (canBeCompress) {
80         CopyChars(string->GetDataUtf8Writable(), utf16Data, utf16Len);
81     } else {
82         uint32_t len = utf16Len * (sizeof(uint16_t) / sizeof(uint8_t));
83         if (memcpy_s(string->GetDataUtf16Writable(), len, utf16Data, len) != EOK) {
84             UNREACHABLE();
85         }
86     }
87 
88     ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!");
89     return string;
90 }
91 
92 template <typename Allocator, objects_traits::enable_if_is_allocate<Allocator, BaseObject *>>
CreateLineString(Allocator && allocator,size_t length,bool compressed)93 LineString *BaseString::CreateLineString(Allocator &&allocator, size_t length, bool compressed)
94 {
95     size_t size = compressed ? LineString::ComputeSizeUtf8(length) : LineString::ComputeSizeUtf16(length);
96     BaseObject *obj = std::invoke(allocator, size, CommonType::LINE_STRING);
97     LineString *string = LineString::Cast(obj);
98     string->InitLengthAndFlags(length, compressed);
99     string->SetMixHashcode(0);
100     return string;
101 }
102 
103 template <typename Allocator, typename WriteBarrier,
104           objects_traits::enable_if_is_allocate<Allocator, BaseObject *>,
105           objects_traits::enable_if_is_write_barrier<WriteBarrier>>
CreateSlicedString(Allocator && allocate,WriteBarrier && writeBarrier,ReadOnlyHandle<BaseString> parent)106 SlicedString *BaseString::CreateSlicedString(Allocator &&allocate, WriteBarrier &&writeBarrier,
107                                              ReadOnlyHandle<BaseString> parent)
108 {
109     SlicedString *slicedString = SlicedString::Cast(
110         std::invoke(allocate, SlicedString::SIZE, CommonType::SLICED_STRING));
111     slicedString->SetMixHashcode(0);
112     slicedString->SetParent(std::forward<WriteBarrier>(writeBarrier), parent.GetBaseObject());
113     return slicedString;
114 }
115 
116 
117 template <typename Allocator, typename WriteBarrier,
118           objects_traits::enable_if_is_allocate<Allocator, BaseObject *>,
119           objects_traits::enable_if_is_write_barrier<WriteBarrier>>
CreateTreeString(Allocator && allocator,WriteBarrier && writeBarrier,ReadOnlyHandle<BaseString> left,ReadOnlyHandle<BaseString> right,uint32_t length,bool compressed)120 TreeString *BaseString::CreateTreeString(Allocator &&allocator, WriteBarrier &&writeBarrier,
121                                          ReadOnlyHandle<BaseString> left, ReadOnlyHandle<BaseString> right,
122                                          uint32_t length, bool compressed)
123 {
124     auto string = TreeString::Cast(
125         std::invoke(allocator, TreeString::SIZE, CommonType::TREE_STRING));
126     string->InitLengthAndFlags(length, compressed);
127     string->SetMixHashcode(0);
128     string->SetFirst(writeBarrier, left.GetBaseObject());
129     string->SetSecond(writeBarrier, right.GetBaseObject());
130     return string;
131 }
132 
133 template <typename ReadBarrier>
GetUtf8Length(ReadBarrier && readBarrier,bool modify,bool isGetBufferSize)134 size_t BaseString::GetUtf8Length(ReadBarrier &&readBarrier, bool modify, bool isGetBufferSize) const
135 {
136     if (!IsUtf16()) {
137         return GetLength() + 1; // add place for zero in the end
138     }
139     std::vector<uint16_t> tmpBuf;
140     const uint16_t *data = GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
141     return UtfUtils::Utf16ToUtf8Size(data, GetLength(), modify, isGetBufferSize);
142 }
143 
144 template <typename ReadBarrier, typename Vec,
145           std::enable_if_t<objects_traits::is_std_vector_of_v<std::decay_t<Vec>, uint16_t>, int>>
GetUtf16DataFlat(ReadBarrier && readBarrier,const BaseString * src,Vec & buf)146 const uint16_t *BaseString::GetUtf16DataFlat(ReadBarrier &&readBarrier, const BaseString *src, Vec &buf)
147 {
148     DCHECK_CC(src->IsUtf16());
149     uint32_t length = src->GetLength();
150     BaseString *string = const_cast<BaseString *>(src);
151     if (string->IsTreeString()) {
152         if (string->IsFlat(std::forward<ReadBarrier>(readBarrier))) {
153             string = BaseString::Cast(
154                 TreeString::Cast(string)->GetFirst<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
155         } else {
156             buf.reserve(length);
157             WriteToFlat(std::forward<ReadBarrier>(readBarrier), string, buf.data(), length);
158             return buf.data();
159         }
160     } else if (string->IsSlicedString()) {
161         SlicedString *str = SlicedString::Cast(string);
162         return BaseString::Cast(str->GetParent<BaseObject *>(std::forward<ReadBarrier>(readBarrier)))->GetDataUtf16() +
163                str->GetStartIndex();
164     }
165     return string->GetDataUtf16();
166 }
167 
GetStringType()168 inline CommonType BaseString::GetStringType() const
169 {
170     CommonType type = GetBaseClass()->GetObjectType();
171     ASSERT_PRINT(type >= CommonType::STRING_FIRST && type <= CommonType::STRING_LAST,
172                  "Invalid CommonType: " + std::to_string(static_cast<uint8_t>(type)));
173     return type;
174 }
175 
176 template <bool verify, typename ReadBarrier>
At(ReadBarrier && readBarrier,int32_t index)177 uint16_t BaseString::At(ReadBarrier &&readBarrier, int32_t index) const
178 {
179     int32_t length = static_cast<int32_t>(GetLength());
180     if constexpr (verify) {
181         if ((index < 0) || (index >= length)) {
182             return 0;
183         }
184     }
185     switch (GetStringType()) {
186         case CommonType::LINE_STRING:
187             return LineString::ConstCast(this)->Get<verify>(index);
188         case CommonType::SLICED_STRING:
189             return SlicedString::ConstCast(this)->Get<verify>(std::forward<ReadBarrier>(readBarrier), index);
190         case CommonType::TREE_STRING:
191             return TreeString::ConstCast(this)->Get<verify>(std::forward<ReadBarrier>(readBarrier), index);
192         default:
193             UNREACHABLE();
194     }
195 }
196 
GetData()197 inline uint16_t *BaseString::GetData() const
198 {
199     ASSERT_PRINT(IsLineString(), "BaseString: Read data from not LineString");
200     return LineString::ConstCast(this)->GetData();
201 }
202 
GetData()203 inline uint16_t *LineString::GetData() const
204 {
205     return reinterpret_cast<uint16_t *>(ToUintPtr(this) + DATA_OFFSET);
206 }
207 
GetDataUtf8()208 inline const uint8_t *BaseString::GetDataUtf8() const
209 {
210     ASSERT_PRINT(IsUtf8(), "BaseString: Read data as utf8 for utf16 string");
211     return reinterpret_cast<uint8_t *>(GetData());
212 }
213 
GetDataUtf16()214 inline const uint16_t *BaseString::GetDataUtf16() const
215 {
216     ASSERT_PRINT(IsUtf16(), "BaseString: Read data as utf16 for utf8 string");
217     return GetData();
218 }
219 
GetDataUtf8Writable()220 inline uint8_t *BaseString::GetDataUtf8Writable()
221 {
222     ASSERT_PRINT(IsUtf8(), "BaseString: Read data as utf8 for utf16 string");
223     return reinterpret_cast<uint8_t *>(GetData());
224 }
225 
GetDataUtf16Writable()226 inline uint16_t *BaseString::GetDataUtf16Writable()
227 {
228     ASSERT_PRINT(IsUtf16(), "BaseString: Read data as utf16 for utf8 string");
229     return GetData();
230 }
231 
232 
WriteData(uint32_t index,uint16_t src)233 inline void BaseString::WriteData(uint32_t index, uint16_t src)
234 {
235     DCHECK_CC(index < GetLength());
236     DCHECK_CC(IsLineString());
237     LineString::Cast(this)->Set(index, src);
238 }
239 
240 
241 template <typename ReadBarrier>
IsFlat(ReadBarrier && readBarrier)242 bool BaseString::IsFlat(ReadBarrier &&readBarrier) const
243 {
244     if (!this->IsTreeString()) {
245         return true;
246     }
247     return TreeString::ConstCast(this)->IsFlat(std::forward<ReadBarrier>(readBarrier));
248 }
249 
250 template <typename Char, typename ReadBarrier>
251 // CC-OFFNXT(huge_depth, huge_method, G.FUN.01-CPP) solid logic
WriteToFlat(ReadBarrier && readBarrier,BaseString * src,Char * buf,uint32_t maxLength)252 void BaseString::WriteToFlat(ReadBarrier &&readBarrier, BaseString *src, Char *buf, uint32_t maxLength)
253 {
254     // DISALLOW_GARBAGE_COLLECTION;
255     uint32_t length = src->GetLength();
256     if (length == 0) {
257         return;
258     }
259     while (true) {
260         DCHECK_CC(length <= maxLength && length > 0);
261         DCHECK_CC(length <= src->GetLength());
262         switch (src->GetStringType()) {
263             case CommonType::LINE_STRING: {
264                 if (src->IsUtf8()) {
265                     CopyChars(buf, src->GetDataUtf8(), length);
266                 } else {
267                     CopyChars(buf, src->GetDataUtf16(), length);
268                 }
269                 return;
270             }
271             case CommonType::TREE_STRING: {
272                 TreeString *treeSrc = TreeString::Cast(src);
273                 BaseString *first = BaseString::Cast(
274                     treeSrc->GetFirst<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
275                 BaseString *second = BaseString::Cast(
276                     treeSrc->GetSecond<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
277                 uint32_t firstLength = first->GetLength();
278                 uint32_t secondLength = second->GetLength();
279                 // NOLINTNEXTLINE(C_RULE_ID_FUNCTION_NESTING_LEVEL)
280                 if (secondLength >= firstLength) {
281                     // second string is longer. So recurse over first.
282                     WriteToFlat(std::forward<ReadBarrier>(readBarrier), first, buf, maxLength);
283                     // CC-OFFNXT(G.FUN.01-CPP) solid logic
284                     if (first == second) {
285                         CopyChars(buf + firstLength, buf, firstLength);
286                         return;
287                     }
288                     buf += firstLength;
289                     maxLength -= firstLength;
290                     src = second;
291                     length -= firstLength;
292                 } else {
293                     // first string is longer.  So recurse over second.
294                     // if src{first:A,second:B} is half flat to {first:A+B,second:empty} by another thread
295                     // but the other thread didn't end, and this thread get  {first:A+B,second:B}
296                     // it may cause write buffer overflower in line 424, buf + firstLength is overflower.
297                     // so use 'length > firstLength' instead of 'secondLength > 0'
298                     // CC-OFFNXT(G.FUN.01-CPP) solid logic
299                     if (length > firstLength) {
300                         if (secondLength == 1) {
301                             buf[firstLength] = static_cast<Char>(second->At<false>(
302                                 std::forward<ReadBarrier>(readBarrier), 0));
303                         } else if ((second->IsLineString()) && second->IsUtf8()) {
304                             CopyChars(buf + firstLength, second->GetDataUtf8(), secondLength);
305                         } else {
306                             WriteToFlat(std::forward<ReadBarrier>(readBarrier), second, buf + firstLength,
307                                         maxLength - firstLength);
308                         }
309                         length -= secondLength;
310                     }
311                     maxLength = firstLength;
312                     src = first;
313                 }
314                 continue;
315             }
316             case CommonType::SLICED_STRING: {
317                 BaseString *parent = BaseString::Cast(
318                     SlicedString::Cast(src)->GetParent<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
319                 if (src->IsUtf8()) {
320                     CopyChars(buf, parent->GetDataUtf8() + SlicedString::Cast(src)->GetStartIndex(), length);
321                 } else {
322                     CopyChars(buf, parent->GetDataUtf16() + SlicedString::Cast(src)->GetStartIndex(), length);
323                 }
324                 return;
325             }
326             default:
327                 UNREACHABLE();
328         }
329     }
330 }
331 
332 
333 template <typename Char, typename ReadBarrier>
WriteToFlatWithPos(ReadBarrier && readBarrier,BaseString * src,Char * buf,uint32_t length,uint32_t pos)334 void BaseString::WriteToFlatWithPos(ReadBarrier &&readBarrier, BaseString *src, Char *buf, uint32_t length,
335                                     uint32_t pos)
336 {
337     // DISALLOW_GARBAGE_COLLECTION;
338     [[ maybe_unused ]] uint32_t maxLength = src->GetLength();
339     if (length == 0) {
340         return;
341     }
342     while (true) {
343         DCHECK_CC(length + pos <= maxLength && length > 0);
344         DCHECK_CC(length <= src->GetLength());
345         DCHECK_CC(pos >= 0);
346         switch (src->GetStringType()) {
347             case CommonType::LINE_STRING: {
348                 if (src->IsUtf8()) {
349                     CopyChars(buf, src->GetDataUtf8() + pos, length);
350                 } else {
351                     CopyChars(buf, src->GetDataUtf16() + pos, length);
352                 }
353                 return;
354             }
355             case CommonType::TREE_STRING: {
356                 TreeString *treeSrc = TreeString::Cast(src);
357                 BaseString *first = BaseString::Cast(
358                     treeSrc->GetFirst<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
359                 DCHECK_CC(first->IsLineString());
360                 src = first;
361                 continue;
362             }
363             case CommonType::SLICED_STRING: {
364                 BaseString *parent = BaseString::Cast(
365                     SlicedString::Cast(src)->GetParent<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
366                 if (src->IsUtf8()) {
367                     CopyChars(buf, parent->GetDataUtf8() + SlicedString::Cast(src)->GetStartIndex() + pos, length);
368                 } else {
369                     CopyChars(buf, parent->GetDataUtf16() + SlicedString::Cast(src)->GetStartIndex() + pos, length);
370                 }
371                 return;
372             }
373             default:
374                 UNREACHABLE();
375         }
376     }
377 }
378 
379 // It allows user to copy into buffer even if maxLength < length
380 template <typename ReadBarrier>
WriteUtf8(ReadBarrier && readBarrier,uint8_t * buf,size_t maxLength,bool isWriteBuffer)381 size_t BaseString::WriteUtf8(ReadBarrier &&readBarrier, uint8_t *buf, size_t maxLength, bool isWriteBuffer) const
382 {
383     if (maxLength == 0) {
384         return 1; // maxLength was -1 at napi
385     }
386     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
387     buf[maxLength - 1] = '\0';
388     return CopyDataRegionUtf8(std::forward<ReadBarrier>(readBarrier), buf, 0, GetLength(), maxLength, true,
389                               isWriteBuffer) + 1;
390 }
391 
392 // It allows user to copy into buffer even if maxLength < length
393 template <typename ReadBarrier>
WriteUtf16(ReadBarrier && readBarrier,uint16_t * buf,uint32_t targetLength,uint32_t bufLength)394 size_t BaseString::WriteUtf16(ReadBarrier &&readBarrier, uint16_t *buf, uint32_t targetLength,
395                               uint32_t bufLength) const
396 {
397     if (bufLength == 0) {
398         return 0;
399     }
400     // Returns a number representing a valid backrest length.
401     return CopyDataToUtf16(std::forward<ReadBarrier>(readBarrier), buf, targetLength, bufLength);
402 }
403 
404 
405 template <typename ReadBarrier>
WriteOneByte(ReadBarrier && readBarrier,uint8_t * buf,size_t maxLength)406 size_t BaseString::WriteOneByte(ReadBarrier &&readBarrier, uint8_t *buf, size_t maxLength) const
407 {
408     if (maxLength == 0) {
409         return 0;
410     }
411     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
412     buf[maxLength - 1] = '\0';
413     uint32_t length = GetLength();
414     if (!IsUtf16()) {
415         std::vector<uint8_t> tmpBuf;
416         const uint8_t *data = GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
417         if (length > maxLength) {
418             length = maxLength;
419         }
420         if (memcpy_s(buf, maxLength, data, length) != EOK) {
421             UNREACHABLE();
422         }
423         return length;
424     }
425 
426     std::vector<uint16_t> tmpBuf;
427     const uint16_t *data = GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
428     if (length > maxLength) {
429         return UtfUtils::ConvertRegionUtf16ToLatin1(data, buf, maxLength, maxLength);
430     }
431     return UtfUtils::ConvertRegionUtf16ToLatin1(data, buf, length, maxLength);
432 }
433 
434 
435 template <typename ReadBarrier>
CopyDataUtf16(ReadBarrier && readBarrier,uint16_t * buf,uint32_t maxLength)436 uint32_t BaseString::CopyDataUtf16(ReadBarrier &&readBarrier, uint16_t *buf, uint32_t maxLength) const
437 {
438     uint32_t length = GetLength();
439     if (length > maxLength) {
440         return 0;
441     }
442     if (IsUtf16()) {
443         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
444         std::vector<uint16_t> tmpBuf;
445         const uint16_t *data = GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
446         if (memcpy_s(buf, maxLength * sizeof(uint16_t), data, length * sizeof(uint16_t)) != EOK) {
447             UNREACHABLE();
448         }
449         return length;
450     }
451     std::vector<uint8_t> tmpBuf;
452     const uint8_t *data = GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
453     return UtfUtils::ConvertRegionUtf8ToUtf16(data, buf, length, maxLength);
454 }
455 
456 
457 template <typename ReadBarrier, typename Vec,
458           std::enable_if_t<objects_traits::is_std_vector_of_v<std::decay_t<Vec>, uint8_t>, int>>
ToUtf8Span(ReadBarrier && readBarrier,Vec & buf,bool modify,bool cesu8)459 Span<const uint8_t> BaseString::ToUtf8Span(ReadBarrier &&readBarrier, Vec &buf, bool modify, bool cesu8)
460 {
461     Span<const uint8_t> str;
462     uint32_t strLen = GetLength();
463     if (UNLIKELY(IsUtf16())) {
464         using U16Vec = objects_traits::vector_with_same_alloc_t<Vec, uint16_t>;
465         U16Vec tmpBuf;
466         const uint16_t *data = BaseString::GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
467         DCHECK_CC(UtfUtils::Utf16ToUtf8Size(data, strLen, modify, false, cesu8) > 0);
468         size_t len = UtfUtils::Utf16ToUtf8Size(data, strLen, modify, false, cesu8) - 1;
469         buf.reserve(len);
470         len = UtfUtils::ConvertRegionUtf16ToUtf8(data, buf.data(), strLen, len, 0, modify, false, cesu8);
471         str = Span<const uint8_t>(buf.data(), len);
472     } else {
473         const uint8_t *data = BaseString::GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, buf);
474         str = Span<const uint8_t>(data, strLen);
475     }
476     return str;
477 }
478 
479 
480 template <typename ReadBarrier, typename Vec,
481           std::enable_if_t<objects_traits::is_std_vector_of_v<std::decay_t<Vec>, uint8_t>, int>>
DebuggerToUtf8Span(ReadBarrier && readBarrier,Vec & buf,bool modify)482 Span<const uint8_t> BaseString::DebuggerToUtf8Span(ReadBarrier &&readBarrier, Vec &buf, bool modify)
483 {
484     Span<const uint8_t> str;
485     uint32_t strLen = GetLength();
486     if (UNLIKELY(IsUtf16())) {
487         using U16Vec = objects_traits::vector_with_same_alloc_t<Vec, uint16_t>;
488         U16Vec tmpBuf;
489         const uint16_t *data = BaseString::GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
490         size_t len = UtfUtils::Utf16ToUtf8Size(data, strLen, modify) - 1;
491         buf.reserve(len);
492         len = UtfUtils::DebuggerConvertRegionUtf16ToUtf8(data, buf.data(), strLen, len, 0, modify);
493         str = Span<const uint8_t>(buf.data(), len);
494     } else {
495         const uint8_t *data = BaseString::GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, buf);
496         str = Span<const uint8_t>(data, strLen);
497     }
498     return str;
499 }
500 
501 // single char copy for loop
502 template <typename DstType, typename SrcType>
CopyChars(DstType * dst,SrcType * src,uint32_t count)503 void BaseString::CopyChars(DstType *dst, SrcType *src, uint32_t count)
504 {
505     Span<SrcType> srcSp(src, count);
506     Span<DstType> dstSp(dst, count);
507     for (uint32_t i = 0; i < count; i++) {
508         dstSp[i] = srcSp[i];
509     }
510 }
511 
512 template <typename ReadBarrier, typename Vec,
513           std::enable_if_t<objects_traits::is_std_vector_of_v<std::decay_t<Vec>, uint8_t>, int>>
GetUtf8DataFlat(ReadBarrier && readBarrier,const BaseString * src,Vec & buf)514 const uint8_t *BaseString::GetUtf8DataFlat(ReadBarrier &&readBarrier, const BaseString *src, Vec &buf)
515 {
516     DCHECK_CC(src->IsUtf8());
517     uint32_t length = src->GetLength();
518     BaseString *string = const_cast<BaseString *>(src);
519     if (string->IsTreeString()) {
520         if (string->IsFlat(std::forward<ReadBarrier>(readBarrier))) {
521             string = BaseString::Cast(
522                 TreeString::Cast(string)->GetFirst<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
523         } else {
524             buf.reserve(length);
525             WriteToFlat(std::forward<ReadBarrier>(readBarrier), string, buf.data(), length);
526             return buf.data();
527         }
528     } else if (string->IsSlicedString()) {
529         SlicedString *str = SlicedString::Cast(string);
530         return BaseString::Cast(str->GetParent<BaseObject *>(std::forward<ReadBarrier>(readBarrier)))->GetDataUtf8() +
531                str->GetStartIndex();
532     }
533     return string->GetDataUtf8();
534 }
535 
536 
537 template <typename ReadBarrier>
CopyDataRegionUtf8(ReadBarrier && readBarrier,uint8_t * buf,size_t start,size_t length,size_t maxLength,bool modify,bool isWriteBuffer)538 size_t BaseString::CopyDataRegionUtf8(ReadBarrier &&readBarrier, uint8_t *buf, size_t start, size_t length,
539                                       size_t maxLength, bool modify, bool isWriteBuffer) const
540 {
541     uint32_t len = GetLength();
542     if (start + length > len) {
543         return 0;
544     }
545     constexpr size_t TWO_TIMES = 2;
546     if (!IsUtf16()) {
547         if (length > (std::numeric_limits<size_t>::max() / TWO_TIMES - 1)) {
548             // 2: half
549             UNREACHABLE();
550         }
551         std::vector<uint8_t> tmpBuf;
552         const uint8_t *data = GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf) + start;
553         // Only copy maxLength number of chars into buffer if length > maxLength
554         auto dataLen = std::min(length, maxLength);
555         std::copy(data, data + dataLen, buf);
556         return dataLen;
557     }
558     std::vector<uint16_t> tmpBuf;
559     const uint16_t *data = GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
560     if (length > maxLength) {
561         return UtfUtils::ConvertRegionUtf16ToUtf8(data, buf, maxLength, maxLength, start,
562                                                   modify, isWriteBuffer);
563     }
564     return UtfUtils::ConvertRegionUtf16ToUtf8(data, buf, length, maxLength, start,
565                                               modify, isWriteBuffer);
566 }
567 
568 template <typename ReadBarrier>
CopyDataToUtf16(ReadBarrier && readBarrier,uint16_t * buf,uint32_t length,uint32_t bufLength)569 size_t BaseString::CopyDataToUtf16(ReadBarrier &&readBarrier, uint16_t *buf, uint32_t length,
570                                    uint32_t bufLength) const
571 {
572     if (IsUtf16()) {
573         std::vector<uint16_t> tmpBuf;
574         const uint16_t *data = BaseString::GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
575         if (length > bufLength) {
576             if (memcpy_s(buf, bufLength * sizeof(uint16_t), data, bufLength * sizeof(uint16_t)) != EOK) {
577                 UNREACHABLE();
578             }
579             return bufLength;
580         }
581         if (memcpy_s(buf, bufLength * sizeof(uint16_t), data, length * sizeof(uint16_t)) != EOK) {
582             UNREACHABLE();
583         }
584         return length;
585     }
586     std::vector<uint8_t> tmpBuf;
587     const uint8_t *data = BaseString::GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
588     if (length > bufLength) {
589         return UtfUtils::ConvertRegionUtf8ToUtf16(data, buf, bufLength, bufLength);
590     }
591     return UtfUtils::ConvertRegionUtf8ToUtf16(data, buf, length, bufLength);
592 }
593 } // namespace common
594 
595 #endif //COMMON_INTERFACES_OBJECTS_STRING_BASE_STRING_INL2_H