• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MtFmT-Lib / mtfmt / 5777411721

pending completion
5777411721

push

github

web-flow
Merge pull request #92 from MtFmT-Lib/str_replace

ADD: 字符串的retain

150 of 150 new or added lines in 4 files covered. (100.0%)

3261 of 3533 relevant lines covered (92.3%)

42.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.86
/src/mm_string.c
1
// SPDX-License-Identifier: LGPL-3.0
2
/**
3
 * @file    mm_string.c
4
 * @author  向阳 (hinata.hoshino@foxmail.com)
5
 * @brief   字符串
6
 * @version 1.0
7
 * @date    2023-04-22
8
 *
9
 * @copyright Copyright (c) 向阳, all rights reserved.
10
 *
11
 */
12

13
#define MSTR_IMP_SOURCES 1
14

15
#include "mm_string.h"
16
#include "mm_heap.h"
17
#include <stddef.h>
18
#include <string.h>
19

20
/**
21
 * @brief 进行扩展的阈值
22
 *
23
 */
24
#define MSTR_SIZE_EXPAND_MAX          1024
25

26
/**
27
 * @brief 超过X2阈值的情况下每次增大的大小
28
 *
29
 */
30
#define MSTR_SIZE_LARGE_CAP_SIZE_STEP 512
31

32
//
33
// private:
34
//
35

36
static mstr_bool_t mstr_compare_helper(
37
    const char*, const char*, usize_t
38
);
39
static void
40
    mstr_reverse_unicode_helper(mstr_char_t*, const mstr_char_t*);
41
static void* mstr_string_realloc(void*, mstr_bool_t, usize_t, usize_t);
42
static usize_t mstr_resize_tactic(usize_t, usize_t);
43
static mstr_result_t
44
    mstr_strlen(usize_t*, usize_t*, const mstr_char_t*, const mstr_char_t*);
45
//
46
// public:
47
//
48

49
MSTR_EXPORT_API(mstr_result_t)
50
mstr_create(MString* str, const char* content)
448✔
51
{
52
    if (content == NULL || content[0] == '\0') {
448✔
53
        mstr_init(str);
334✔
54
        return MStr_Ok;
334✔
55
    }
56
    else {
57
        usize_t content_len, content_cnt;
58
        mstr_strlen(&content_len, &content_cnt, content, NULL);
114✔
59
        str->count = content_cnt;
114✔
60
        str->length = content_len;
114✔
61
        if (content_cnt == 0) {
114✔
62
            // str->buff =...;
63
            // str->cap_size = ...;
64
            return MStr_Ok;
×
65
        }
66
        else if (content_cnt < MSTR_STACK_REGION_SIZE) {
114✔
67
            str->buff = str->stack_region;
99✔
68
            str->cap_size = MSTR_STACK_REGION_SIZE;
99✔
69
            strcpy(str->buff, content);
99✔
70
            return MStr_Ok;
99✔
71
        }
72
        else {
73
            str->cap_size = content_cnt + MSTR_STACK_REGION_SIZE;
15✔
74
            str->buff = (char*)mstr_heap_alloc(str->cap_size);
15✔
75
            if (str->buff == NULL) {
15✔
76
                // 内存分配失败
77
                return MStr_Err_HeapTooSmall;
×
78
            }
79
            memcpy(str->buff, content, content_cnt);
15✔
80
            return MStr_Ok;
15✔
81
        }
82
    }
83
}
84

85
MSTR_EXPORT_API(void)
86
mstr_move_from(MString* str, MString* other)
2✔
87
{
88
    if (str->buff != NULL) {
2✔
89
        mstr_free(str);
2✔
90
    }
91
    str->count = other->count;
2✔
92
    str->length = other->length;
2✔
93
    if (other->buff == other->stack_region) {
2✔
94
        str->buff = str->stack_region;
1✔
95
        str->cap_size = MSTR_STACK_REGION_SIZE;
1✔
96
        // 复制stack上的内容
97
        memcpy(str->buff, other->buff, other->count);
1✔
98
    }
99
    else {
100
        str->buff = other->buff;
1✔
101
        str->cap_size = other->cap_size;
1✔
102
    }
103
    other->buff = NULL;
2✔
104
    other->count = 0;
2✔
105
    other->length = 0;
2✔
106
    other->cap_size = 0;
2✔
107
}
2✔
108

109
MSTR_EXPORT_API(mstr_result_t)
110
mstr_copy_from(MString* str, const MString* other)
25✔
111
{
112
    mstr_result_t result = MStr_Ok;
25✔
113
    if (str->buff != NULL) {
25✔
114
        mstr_free(str);
25✔
115
    }
116
    MSTR_AND_THEN(result, mstr_create(str, ""));
25✔
117
    MSTR_AND_THEN(result, mstr_concat(str, other));
25✔
118
    return result;
25✔
119
}
120
MSTR_EXPORT_API(mstr_result_t)
121
mstr_reserve(MString* str, usize_t new_size)
21✔
122
{
123
    if (new_size > str->cap_size) {
21✔
124
        char* new_ptr = (char*)mstr_string_realloc(
20✔
125
            str->buff,
20✔
126
            str->buff == str->stack_region,
20✔
127
            str->count,
128
            new_size
129
        );
130
        if (new_ptr == NULL) {
20✔
131
            // 分配失败
132
            return MStr_Err_HeapTooSmall;
×
133
        }
134
        str->buff = new_ptr;
20✔
135
        str->cap_size = new_size;
20✔
136
        return MStr_Ok;
20✔
137
    }
138
    else {
139
        return MStr_Ok;
1✔
140
    }
141
}
142

143
MSTR_EXPORT_API(mstr_result_t)
144
mstr_append(MString* str, mstr_codepoint_t ch)
734✔
145
{
146
    return mstr_repeat_append(str, ch, 1);
734✔
147
}
148

149
MSTR_EXPORT_API(mstr_result_t)
150
mstr_repeat_append(MString* str, mstr_codepoint_t ch, usize_t cnt)
744✔
151
{
152
    if (cnt == 0) {
744✔
153
        return MStr_Ok;
×
154
    }
155
    else {
156
        usize_t code_len;
157
        usize_t need_len;
158
        mstr_char_t buff[8];
159
        mstr_result_t result = MStr_Ok;
744✔
160
#if _MSTR_USE_UTF_8
161
        result = mstr_as_utf8(ch, buff, &code_len);
744✔
162
#else
163
        code_len = 1;
164
        buff[0] = (mstr_char_t)(ch & 0x7f);
165
#endif // _MSTR_USE_UTF_8
166
        need_len = code_len * cnt;
744✔
167
        if (str->count + need_len + 1 >= str->cap_size) {
744✔
168
            // 保证length < cap_size + 1
169
            // 且有足够的空间存放下一个字符
170
            MSTR_AND_THEN(
8✔
171
                result,
172
                mstr_reserve(
173
                    str, mstr_resize_tactic(str->cap_size, need_len)
174
                )
175
            );
176
        }
177
        if (MSTR_SUCC(result)) {
744✔
178
            usize_t i_cnt = 0;
744✔
179
            mstr_char_t* it = str->buff + str->count;
744✔
180
            while (i_cnt < cnt) {
1,514✔
181
                for (usize_t j = 0; j < code_len; j += 1) {
1,575✔
182
                    *it = buff[j];
805✔
183
                    it += 1;
805✔
184
                }
185
                i_cnt += 1;
770✔
186
            }
187
            str->count += code_len * cnt;
744✔
188
            str->length += cnt;
744✔
189
        }
190
        return result;
744✔
191
    }
192
}
193

194
MSTR_EXPORT_API(mstr_result_t)
195
mstr_concat(MString* str, const MString* other)
305✔
196
{
197
    mstr_result_t result = MStr_Ok;
305✔
198
    if (str->count + other->count >= str->cap_size) {
305✔
199
        // 且有足够的空间存放
200
        MSTR_AND_THEN(
10✔
201
            result,
202
            mstr_reserve(
203
                str, mstr_resize_tactic(str->cap_size, other->count)
204
            )
205
        );
206
    }
207
    if (MSTR_SUCC(result)) {
305✔
208
        char* dst = str->buff + str->count;
305✔
209
        usize_t cnt = other->count;
305✔
210
        const char* src = other->buff;
305✔
211
        // 复制内容
212
        memcpy(dst, src, cnt);
305✔
213
        str->count += cnt;
305✔
214
        str->length += other->length;
305✔
215
    }
216
    return result;
305✔
217
}
218

219
MSTR_EXPORT_API(mstr_result_t)
220
mstr_concat_cstr(MString* str, const char* other)
15✔
221
{
222
    MString lit;
223
    usize_t content_len, content_cnt;
224
    mstr_result_t res;
225
    res = mstr_strlen(&content_len, &content_cnt, other, NULL);
15✔
226
    if (MSTR_SUCC(res)) {
15✔
227
        // const MString不会被修改, 所以可强转一下
228
        lit.buff = (char*)(iptr_t)other;
15✔
229
        lit.count = content_cnt;
15✔
230
        lit.length = content_len;
15✔
231
        lit.cap_size = 0;
15✔
232
        res = mstr_concat(str, &lit);
15✔
233
    }
234
    return res;
15✔
235
}
236

237
MSTR_EXPORT_API(mstr_result_t)
238
mstr_concat_cstr_slice(MString* str, const char* start, const char* end)
36✔
239
{
240
    if (start == end) {
36✔
241
        return MStr_Ok;
×
242
    }
243
    else {
244
        MString lit;
245
        usize_t content_len, content_cnt;
246
        mstr_result_t res;
247
        res = mstr_strlen(&content_len, &content_cnt, start, end);
36✔
248
        if (MSTR_SUCC(res)) {
36✔
249
            // const MString不会被修改, 所以可强转一下
250
            lit.buff = (char*)(iptr_t)start;
35✔
251
            lit.count = content_cnt;
35✔
252
            lit.length = content_len;
35✔
253
            lit.cap_size = 0;
35✔
254
            res = mstr_concat(str, &lit);
35✔
255
        }
256
        return res;
36✔
257
    }
258
}
259

260
MSTR_EXPORT_API(void) mstr_clear(MString* str)
13✔
261
{
262
    str->count = 0;
13✔
263
    str->length = 0;
13✔
264
}
13✔
265

266
MSTR_EXPORT_API(void) mstr_reverse_self(MString* str)
5✔
267
{
268
    mstr_char_t* pe = str->buff + str->count;
5✔
269
    mstr_reverse_only(str);
5✔
270
    mstr_reverse_unicode_helper(str->buff, pe);
5✔
271
}
5✔
272

273
MSTR_EXPORT_API(void) mstr_reverse_only(MString* str)
125✔
274
{
275
    mstr_char_t* p2 = str->buff + str->count - 1;
125✔
276
    mstr_char_t* p1 = str->buff;
125✔
277
    while (p1 < p2) {
315✔
278
        char v = *p2;
190✔
279
        *p2 = *p1;
190✔
280
        *p1 = v;
190✔
281
        // ++, --
282
        p1 += 1;
190✔
283
        p2 -= 1;
190✔
284
    }
285
}
125✔
286

287
MSTR_EXPORT_API(const char*) mstr_c_str(MString* str)
×
288
{
289
    // 在length的地方补上0
290
    // 因为cap_size至少比length大1, 因此不需要担心内存问题
291
    str->buff[str->count] = 0;
×
292
    return str->buff;
×
293
}
294

295
MSTR_EXPORT_API(mstr_bool_t)
296
mstr_equal(const MString* a, const MString* b)
74✔
297
{
298
    return mstr_equal_cstr(a, b->buff, b->count);
74✔
299
}
300

301
MSTR_EXPORT_API(mstr_bool_t)
302
mstr_equal_cstr(const MString* a, const mstr_char_t* b, usize_t b_cnt)
145✔
303
{
304
    if (a->count != b_cnt) {
145✔
305
        return False;
×
306
    }
307
    else {
308
        return mstr_compare_helper(a->buff, b, b_cnt);
145✔
309
    }
310
}
311

312
MSTR_EXPORT_API(mstr_bool_t)
313
mstr_start_with(
6✔
314
    const MString* str, const char* prefix, usize_t prefix_cnt
315
)
316
{
317
    usize_t len = prefix_cnt;
6✔
318
    if (str->count < len) {
6✔
319
        return False;
1✔
320
    }
321
    else {
322
        return mstr_compare_helper(str->buff, prefix, len);
5✔
323
    }
324
}
325

326
MSTR_EXPORT_API(mstr_bool_t)
327
mstr_end_with(
7✔
328
    const MString* str, const char* suffix, usize_t suffix_cnt
329
)
330
{
331
    usize_t len = suffix_cnt;
7✔
332
    if (str->count < len) {
7✔
333
        return False;
1✔
334
    }
335
    else {
336
        usize_t offset = str->count - len;
6✔
337
        return mstr_compare_helper(str->buff + offset, suffix, len);
6✔
338
    }
339
}
340

341
MSTR_EXPORT_API(mstr_bool_t)
342
mstr_contains(
7✔
343
    const MString* str, const char* pattern, usize_t pattern_cnt
344
)
345
{
346
    mstr_result_t match_ret;
347
    MStringMatchResult match_res;
348
    match_ret = mstr_find(str, &match_res, 0, pattern, pattern_cnt);
7✔
349
    if (MSTR_FAILED(match_ret)) {
7✔
350
        return False;
×
351
    }
352
    else {
353
        return match_res.is_matched;
7✔
354
    }
355
}
356

357
MSTR_EXPORT_API(mstr_codepoint_t)
358
mstr_char_at(const MString* str, usize_t idx)
13✔
359
{
360
#if _MSTR_USE_UTF_8
361
    usize_t offset;
362
    mstr_result_t res = MStr_Ok;
13✔
363
    mstr_codepoint_t out_code = 0;
13✔
364
    mstr_bounding_check(idx < str->length);
365
    offset = mstr_char_offset_at(str, idx);
13✔
366
    res = mstr_codepoint_of(
13✔
367
        &out_code, str->buff + offset, str->count - offset
13✔
368
    );
369
    if (MSTR_SUCC(res)) {
13✔
370
        return out_code;
13✔
371
    }
372
    else {
373
        return 0;
×
374
    }
375
#else
376
    mstr_bounding_check(idx < str->length);
377
    return (mstr_codepoint_t)str->buff[idx];
378
#endif // _MSTR_USE_UTF_8
379
}
380

381
MSTR_EXPORT_API(mstr_result_t)
382
mstr_remove(MString* str, mstr_codepoint_t* removed_ch, usize_t idx)
6✔
383
{
384
    mstr_result_t res = MStr_Ok;
6✔
385
    // 找到需要移除的位置
386
    usize_t offset = mstr_char_offset_at(str, idx);
6✔
387
    // 记录返回的字符
388
    if (removed_ch != NULL) {
6✔
389
#if _MSTR_USE_UTF_8
390
        mstr_codepoint_t out_code = 0;
6✔
391
        res = mstr_codepoint_of(
6✔
392
            &out_code, str->buff + offset, str->count - offset
6✔
393
        );
394
        if (MSTR_SUCC(res)) {
6✔
395
            *removed_ch = out_code;
6✔
396
        }
397
        else {
398
            *removed_ch = 0;
×
399
        }
400
#else
401
        *removed_ch = str->buff[offset];
402
#endif // _MSTR_USE_UTF_8
403
    }
404
    // 移除掉该字符
405
    if (MSTR_SUCC(res)) {
6✔
406
        usize_t ccnt = mstr_char_length(*(str->buff + offset));
6✔
407
        usize_t rems = offset + ccnt;
6✔
408
        memmove(
6✔
409
            str->buff + offset, str->buff + rems, str->count - rems
6✔
410
        );
411
        str->count -= ccnt;
6✔
412
        str->length -= 1;
6✔
413
    }
414
    return res;
6✔
415
}
416

417
MSTR_EXPORT_API(mstr_result_t)
418
mstr_insert(MString* str, usize_t idx, mstr_codepoint_t ch)
10✔
419
{
420
    if (idx == str->length) {
10✔
421
        // 等效为append
422
        // 数组末尾插入的时间复杂度是O(1)的, 因此单独分开一个case
423
        return mstr_append(str, ch);
2✔
424
    }
425
    else {
426
        mstr_result_t res = MStr_Ok;
8✔
427
        // 找到需要插入的位置
428
        usize_t offset = mstr_char_offset_at(str, idx);
8✔
429
        // 对需要插入的字符进行转码
430
        char insert_data[8];
431
        usize_t insert_data_len;
432
#if _MSTR_USE_UTF_8
433
        res = mstr_as_utf8(ch, insert_data, &insert_data_len);
8✔
434
#else
435
        insert_data[0] = (char)ch;
436
        insert_data_len = 1;
437
#endif // _MSTR_USE_UTF_8
438
       // 保证空间足够
439
        if (str->count + insert_data_len + 1 >= str->cap_size) {
8✔
440
            // 保证length < cap_size + 1
441
            // 且有足够的空间存放下一个字符
442
            MSTR_AND_THEN(
1✔
443
                res,
444
                mstr_reserve(
445
                    str,
446
                    mstr_resize_tactic(str->cap_size, insert_data_len)
447
                )
448
            );
449
        }
450
        // 插入该字符
451
        if (MSTR_SUCC(res)) {
8✔
452
            // 留出空间
453
            memmove(
8✔
454
                str->buff + offset + insert_data_len,
8✔
455
                str->buff + offset,
8✔
456
                str->count - offset
8✔
457
            );
458
            // 然后复制内容过去
459
            memcpy(str->buff + offset, insert_data, insert_data_len);
8✔
460
            str->count += insert_data_len;
8✔
461
            str->length += 1;
8✔
462
        }
463
        return res;
8✔
464
    }
465
}
466

467
MSTR_EXPORT_API(void) mstr_iter(MStringIter* it, const MString* str)
×
468
{
469
    it->it = str->buff;
×
470
    it->it_end = str->buff + str->count;
×
471
    it->rem_length = str->length;
×
472
}
×
473

474
MSTR_EXPORT_API(usize_t) mstr_char_length(char lead)
1,512✔
475
{
476
#if _MSTR_USE_UTF_8
477
    // 构造的小欧拉图会帮忙计算utf-8编码的长度
478
    const uint32_t map[8] = {1, 7, 2, 6, 0, 3, 4, 5};
1,512✔
479
    uint8_t uch = (uint8_t)lead;
1,512✔
480
    uint32_t v = (uint32_t)(uch ^ 0xff);
1,512✔
481
    v |= v >> 1;
1,512✔
482
    v |= v >> 2;
1,512✔
483
    v |= v >> 4;
1,512✔
484
    v += 1;
1,512✔
485
    return map[((v * 232) >> 8) & 0x7];
1,512✔
486
#else
487
    (void)lead;
488
    return 1;
489
#endif // _MSTR_USE_UTF_8
490
}
491

492
MSTR_EXPORT_API(usize_t)
493
mstr_lead_char_offset(const mstr_char_t* buff, usize_t hist_len)
22✔
494
{
495
#if _MSTR_USE_UTF_8
496
    usize_t find_len = hist_len > 6 ? 6 : hist_len;
22✔
497
    const mstr_char_t* it = buff;
22✔
498
    while (find_len > 0) {
42✔
499
        mstr_char_t ch = *it;
42✔
500
        if ((ch & 0x80) == 0) {
42✔
501
            // ASCII
502
            it -= 1;
14✔
503
            break;
14✔
504
        }
505
        else if ((ch & 0xc0) == 0xc0) {
28✔
506
            // utf8前导字符
507
            it -= 1;
8✔
508
            break;
8✔
509
        }
510
        else {
511
            // utf8内容
512
            it -= 1;
20✔
513
            find_len -= 1;
20✔
514
        }
515
    }
516
    return (usize_t)(buff - it);
22✔
517
#else
518
    (void)buff;
519
    (void)hist_len;
520
    return 1;
521
#endif // _MSTR_USE_UTF_8
522
}
523

524
#if _MSTR_USE_UTF_8
525

526
MSTR_EXPORT_API(mstr_result_t)
527
mstr_as_utf8(
752✔
528
    mstr_codepoint_t code, mstr_char_t* result, usize_t* result_len
529
)
530
{
531
    if (code <= 0x7f) {
752✔
532
        // 0xxxxxxx, 1bytes
533
        result[0] = (mstr_char_t)(code & 0x7f);
736✔
534
        *result_len = 1;
736✔
535
        return MStr_Ok;
736✔
536
    }
537
    else if (code <= 0x7ff) {
16✔
538
        // 110xxxxx 10xxxxxx, 2bytes
539
        result[0] = (mstr_char_t)((code >> 6) & 0x1f) | 0xc0;
×
540
        result[1] = (mstr_char_t)(code & 0x3f) | 0x80;
×
541
        *result_len = 2;
×
542
        return MStr_Ok;
×
543
    }
544
    else if (code <= 0xffff) {
16✔
545
        // 1110xxxx 10xxxxxx 10xxxxxx, 3bytes
546
        result[0] = (mstr_char_t)((code >> 12) & 0xf) | 0xe0;
4✔
547
        result[1] = (mstr_char_t)((code >> 6) & 0x3f) | 0x80;
4✔
548
        result[2] = (mstr_char_t)(code & 0x3f) | 0x80;
4✔
549
        *result_len = 3;
4✔
550
        return MStr_Ok;
4✔
551
    }
552
    else if (code <= 0x1fffff) {
12✔
553
        // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx, 4bytes
554
        result[0] = (mstr_char_t)((code >> 18) & 0x7) | 0xf0;
12✔
555
        result[1] = (mstr_char_t)((code >> 12) & 0x3f) | 0x80;
12✔
556
        result[2] = (mstr_char_t)((code >> 6) & 0x3f) | 0x80;
12✔
557
        result[3] = (mstr_char_t)(code & 0x3f) | 0x80;
12✔
558
        *result_len = 4;
12✔
559
        return MStr_Ok;
12✔
560
    }
561
    else {
562
        *result_len = 0;
×
563
        return MStr_Err_UnicodeEncodingError;
×
564
    }
565
}
566

567
MSTR_EXPORT_API(mstr_result_t)
568
mstr_codepoint_of(
42✔
569
    mstr_codepoint_t* code, const mstr_char_t* ch, usize_t byte_count
570
)
571
{
572
    uint32_t val = 0;
42✔
573
    mstr_result_t res;
574
    uint8_t lead_char = (uint8_t)ch[0];
42✔
575
    if (lead_char <= 0x7f) {
42✔
576
        // 0xxxxxxx, 1bytes
577
        if (byte_count >= 1) {
28✔
578
            val |= (uint32_t)(ch[0] & 0x7f);
28✔
579
            res = MStr_Ok;
28✔
580
        }
581
        else {
582
            res = MStr_Err_EncodingNotCompleted;
×
583
        }
584
    }
585
    else if (lead_char <= 0xdf) {
14✔
586
        // 110xxxxx 10xxxxxx, 2bytes
587
        if (byte_count >= 2) {
×
588
            val |= (uint32_t)(ch[1]) & 0x3f;
×
589
            val |= ((uint32_t)(ch[0]) & 0x1f) << 6;
×
590
            res = MStr_Ok;
×
591
        }
592
        else {
593
            res = MStr_Err_EncodingNotCompleted;
×
594
        }
595
    }
596
    else if (lead_char <= 0xef) {
14✔
597
        // 1110xxxx 10xxxxxx 10xxxxxx, 3bytes
598
        if (byte_count >= 3) {
6✔
599
            val |= (uint32_t)(ch[2]) & 0x3f;
6✔
600
            val |= ((uint32_t)(ch[1]) & 0x3f) << 6;
6✔
601
            val |= ((uint32_t)(ch[0]) & 0x0f) << (6 + 6);
6✔
602
            res = MStr_Ok;
6✔
603
        }
604
        else {
605
            res = MStr_Err_EncodingNotCompleted;
×
606
        }
607
    }
608
    else if (lead_char <= 0xf7) {
8✔
609
        // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx, 4 bytes
610
        if (byte_count >= 4) {
8✔
611
            val |= (uint32_t)(ch[3]) & 0x3f;
8✔
612
            val |= ((uint32_t)(ch[2]) & 0x3f) << 6;
8✔
613
            val |= ((uint32_t)(ch[1]) & 0x3f) << (6 + 6);
8✔
614
            val |= ((uint32_t)(ch[0]) & 0x07) << (6 + 6 + 6);
8✔
615
            res = MStr_Ok;
8✔
616
        }
617
        else {
618
            res = MStr_Err_EncodingNotCompleted;
×
619
        }
620
    }
621
    else {
622
        // 再长的就不处理了 ( ̄▽ ̄)"
623
        res = MStr_Err_UnicodeEncodingError;
×
624
    }
625
    if (MSTR_SUCC(res)) {
42✔
626
        *code = val;
42✔
627
    }
628
    return res;
42✔
629
}
630
#else
631

632
MSTR_EXPORT_API(mstr_result_t)
633
mstr_as_utf8(
634
    mstr_codepoint_t code, mstr_char_t* result, usize_t* result_len
635
)
636
{
637
    (void)code;
638
    (void)result;
639
    (void)result_len;
640
    return MStr_Err_NoImplemention;
641
}
642

643
MSTR_EXPORT_API(mstr_result_t)
644
mstr_codepoint_of(
645
    mstr_codepoint_t* code, const mstr_char_t* ch, usize_t byte_count
646
)
647
{
648
    (void)code;
649
    (void)ch;
650
    (void)byte_count;
651
    return MStr_Err_NoImplemention;
652
}
653
#endif // _MSTR_USE_UTF_8
654

655
MSTR_EXPORT_API(usize_t)
656
mstr_char_offset_at(const MString* str, usize_t idx)
79✔
657
{
658
#if _MSTR_USE_UTF_8
659
    usize_t cur_idx = 0;
79✔
660
    const char* it = str->buff;
79✔
661
    mstr_bounding_check(idx < str->length);
662
    while (cur_idx != idx) {
221✔
663
        usize_t cnt = mstr_char_length(*it);
142✔
664
        it += cnt;
142✔
665
        cur_idx += 1;
142✔
666
    }
667
    return (usize_t)(it - str->buff);
79✔
668
#else
669
    mstr_bounding_check(idx < str->length);
670
    return idx;
671
#endif // _MSTR_USE_UTF_8
672
}
673

674
MSTR_EXPORT_API(void) mstr_free(MString* str)
484✔
675
{
676
    if (str->buff != NULL && str->buff != str->stack_region) {
484✔
677
        mstr_heap_free(str->buff);
32✔
678
    }
679
    // else: stack上分配的, 不用管它
680
    str->buff = NULL;
484✔
681
    str->count = 0;
484✔
682
    str->cap_size = 0;
484✔
683
}
484✔
684

685
/**
686
 * @brief 计算字符串长度
687
 *
688
 * @param len: 字符长度
689
 * @param count: 字符串占用的字节数
690
 * @param str: 字符串
691
 * @param str_end: 字符串结束, 为NULL表示'\0'自己算
692
 */
693
static mstr_result_t mstr_strlen(
165✔
694
    usize_t* len,
695
    usize_t* count,
696
    const mstr_char_t* str,
697
    const mstr_char_t* str_end
698
)
699
{
700
    usize_t len_val = 0, count_val = 0;
165✔
701
    if (str_end == NULL) {
165✔
702
        // 给一个大大的值让str < str_end恒为true
703
        str_end = (const mstr_char_t*)(uptr_t)(-1);
129✔
704
    }
705
    if (str == NULL) {
165✔
706
        return 0;
×
707
    }
708
#if _MSTR_USE_UTF_8
709
    while (*str && str < str_end) {
1,350✔
710
        usize_t cnt = mstr_char_length(*str);
1,185✔
711
        count_val += cnt;
1,185✔
712
        len_val += 1;
1,185✔
713
        str += cnt;
1,185✔
714
    }
715
    *len = len_val;
165✔
716
    *count = count_val;
165✔
717
    if (str > str_end) {
165✔
718
        // 正常情况应该刚好相等
719
        // 不然说明原字符串不完整
720
        return MStr_Err_EncodingNotCompleted;
1✔
721
    }
722
    else {
723
        return MStr_Ok;
164✔
724
    }
725
#else
726
    while (*str && str < str_end) {
727
        count_val += 1;
728
        len_val += 1;
729
        str += 1;
730
    }
731
    *len = len_val;
732
    *count = count_val;
733
    return MStr_Ok;
734
#endif // _MSTR_USE_UTF_8
735
}
736

737
/**
738
 * @brief 翻转Unicode字符编码, 让其正确, 在UTF-8关闭的情况下,
739
 * 该函数不做任何操作
740
 *
741
 * @param[inout] buff: 操作数组
742
 * @param[in] pe: 数组的末尾位置
743
 */
744
static void mstr_reverse_unicode_helper(
5✔
745
    mstr_char_t* buff, const mstr_char_t* pe
746
)
747
{
748
#if _MSTR_USE_UTF_8
749
    mstr_char_t* p1 = buff;
5✔
750
    mstr_char_t* p2 = buff;
5✔
751
    // UTF-8考虑的地方在于 <= 0x7f 是ASCII
752
    // 而其余情况都是UTF-8字符串
753
    // 那么就可以先反转每个bytes:
754
    // >> [char1: 110xxxxx 10xxxxxx], [char2: 110xxxxx 10xxxxxx]
755
    // => [char2: 10xxxxxx 110xxxxx], [char1: 10xxxxxx 110xxxxx]
756
    // 再去遍历一遍字符串, 跳过ascii, 并在发现lead character的时候
757
    // 把上次的位置到目前lead character的字符交换
758
    while (p2 < pe) {
53✔
759
        mstr_char_t ch = *p2;
48✔
760
        p2 += 1;
48✔
761
        if ((ch & 0x80) == 0) {
48✔
762
            // ASCII
763
            p1 = p2;
26✔
764
        }
765
        else if ((ch & 0xc0) == 0xc0) {
22✔
766
            // 2~6bytes UTF-8的lead character
767
            mstr_char_t* t = p2;
6✔
768
            usize_t byte_len = (usize_t)(p2 - p1);
6✔
769
            // 因为一些编译器会抱怨case后无break
770
            // 因此这里用goto做
771
            switch (byte_len) {
6✔
772
            case 4: goto proc_4;
4✔
773
            case 3: goto proc_3;
2✔
774
            case 2: goto proc_2;
×
775
            default: mstr_unreachable(); goto end;
×
776
            }
777
        proc_4:
4✔
778
            //  3    2    1    0
779
            // /|\            /|\ 4个byte长度
780
            //  p1             p2
781
            // 交换p1和p2, 然后变成下面的样子
782
            //  0    2    1    3
783
            //      /|\  /|\ 2个byte长度
784
            //       p1   p2
785
            // 交给proc_2以一样的方式交换p1和p2即可
786
            ch = *p1;
4✔
787
            *p1++ = *--p2;
4✔
788
            *p2 = ch;
4✔
789
            goto proc_2;
4✔
790
        proc_3:
2✔
791
            // str[1]和str[1]不需要交换
792
            goto proc_2;
2✔
793
        proc_2:
6✔
794
            ch = *p1;
6✔
795
            *p1++ = *--p2;
6✔
796
            *p2 = ch;
6✔
797
            goto end;
6✔
798
        end:
6✔
799
            p1 = t;
6✔
800
            p2 = t;
6✔
801
        }
802
    }
803
#else
804
    (void)buff;
805
    (void)pe;
806
#endif // _MSTR_USE_UTF_8
807
}
5✔
808

809
/**
810
 * @brief 比较相同长度len的字串a和b是否一致
811
 *
812
 * @param a: 字符串a
813
 * @param b: 字符串b
814
 * @param len: 字符串a和b的长度
815
 *
816
 * @return mstr_bool_t: 比较结果
817
 */
818
static mstr_bool_t mstr_compare_helper(
156✔
819
    const char* a, const char* b, usize_t len
820
)
821
{
822
    uint32_t bit = 0;
156✔
823
    for (usize_t i = 0; i < len; i += 1) {
1,444✔
824
        uint32_t ch_a = a[i];
1,288✔
825
        uint32_t ch_b = b[i];
1,288✔
826
        // equ
827
        bit |= ch_a ^ ch_b;
1,288✔
828
    }
829
    return bit == 0;
156✔
830
}
831

832
/**
833
 * @brief 重新分配内存区
834
 *
835
 * @param[in] old_ptr: 以前的内存区位置
836
 * @param[in] is_stack: 是否为stack上分配内存
837
 * @param[in] old_size: 原本的内存区大小
838
 * @param[in] new_size: 需要分配的大小
839
 * @return void*: 新分配的地址, 失败返回NULL
840
 */
841
static void* mstr_string_realloc(
20✔
842
    void* old_ptr,
843
    mstr_bool_t is_stack,
844
    usize_t old_size,
845
    usize_t new_size
846
)
847
{
848
    if (is_stack) {
20✔
849
        void* new_ptr = mstr_heap_alloc(new_size);
17✔
850
        if (new_ptr == NULL) {
17✔
851
            return NULL;
×
852
        }
853
        memcpy(new_ptr, old_ptr, old_size);
17✔
854
        return new_ptr;
17✔
855
    }
856
    else {
857
        return mstr_heap_realloc(old_ptr, new_size, old_size);
3✔
858
    }
859
}
860

861
/**
862
 * @brief 改变cap的策略
863
 *
864
 * @param[in] old_sz: 以前的大小
865
 * @param[in] inc_len: 至少需要增加的大小, 会在此基础上增加1
866
 */
867
static usize_t mstr_resize_tactic(usize_t old_sz, usize_t inc_len)
19✔
868
{
869
    usize_t min_sz = old_sz + inc_len + 1;
19✔
870
    if (old_sz < MSTR_SIZE_EXPAND_MAX) {
19✔
871
        usize_t exp_sz = old_sz * 2;
19✔
872
        return min_sz < exp_sz ? exp_sz : min_sz;
19✔
873
    }
874
    else {
875
        return old_sz + inc_len + MSTR_SIZE_LARGE_CAP_SIZE_STEP;
×
876
    }
877
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc