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

MtFmT-Lib / mtfmt / 5636020086

pending completion
5636020086

push

github

XiangYyang
add: mstr_init (用于简单替换mstr_create_empty)

19 of 19 new or added lines in 2 files covered. (100.0%)

3140 of 3428 relevant lines covered (91.6%)

45.2 hits per line

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

85.6
/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 mstr_result_t mstr_expand_size(MString*, usize_t);
43
static usize_t mstr_resize_tactic(usize_t, usize_t);
44
static mstr_result_t
45
    mstr_strlen(usize_t*, usize_t*, const mstr_char_t*, const mstr_char_t*);
46
//
47
// public:
48
//
49

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

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

121
MSTR_EXPORT_API(mstr_result_t)
122
mstr_append(MString* str, mstr_codepoint_t ch)
734✔
123
{
124
    return mstr_repeat_append(str, ch, 1);
734✔
125
}
126

127
MSTR_EXPORT_API(mstr_result_t)
128
mstr_repeat_append(MString* str, mstr_codepoint_t ch, usize_t cnt)
744✔
129
{
130
    if (cnt == 0) {
744✔
131
        return MStr_Ok;
×
132
    }
133
    else {
134
        usize_t code_len;
135
        usize_t need_len;
136
        mstr_char_t buff[8];
137
        mstr_result_t result = MStr_Ok;
744✔
138
#if _MSTR_USE_UTF_8
139
        result = mstr_as_utf8(ch, buff, &code_len);
744✔
140
#else
141
        code_len = 1;
142
        buff[0] = (mstr_char_t)(ch & 0x7f);
143
#endif // _MSTR_USE_UTF_8
144
        need_len = code_len * cnt;
744✔
145
        if (str->count + need_len + 1 >= str->cap_size) {
744✔
146
            // 保证length < cap_size + 1
147
            // 且有足够的空间存放下一个字符
148
            MSTR_AND_THEN(
8✔
149
                result,
150
                mstr_expand_size(
151
                    str, mstr_resize_tactic(str->cap_size, need_len)
152
                )
153
            );
154
        }
155
        if (MSTR_SUCC(result)) {
744✔
156
            usize_t i_cnt = 0;
744✔
157
            mstr_char_t* it = str->buff + str->count;
744✔
158
            while (i_cnt < cnt) {
1,514✔
159
                for (usize_t j = 0; j < code_len; j += 1) {
1,575✔
160
                    *it = buff[j];
805✔
161
                    it += 1;
805✔
162
                }
163
                i_cnt += 1;
770✔
164
            }
165
            str->count += code_len * cnt;
744✔
166
            str->length += cnt;
744✔
167
        }
168
        return result;
744✔
169
    }
170
}
171

172
MSTR_EXPORT_API(mstr_result_t)
173
mstr_concat(MString* str, const MString* other)
305✔
174
{
175
    mstr_result_t result = MStr_Ok;
305✔
176
    if (str->count + other->count >= str->cap_size) {
305✔
177
        // 且有足够的空间存放
178
        MSTR_AND_THEN(
10✔
179
            result,
180
            mstr_expand_size(
181
                str, mstr_resize_tactic(str->cap_size, other->count)
182
            )
183
        );
184
    }
185
    if (MSTR_SUCC(result)) {
305✔
186
        char* dst = str->buff + str->count;
305✔
187
        usize_t cnt = other->count;
305✔
188
        const char* src = other->buff;
305✔
189
        // 复制内容
190
        memcpy(dst, src, cnt);
305✔
191
        str->count += cnt;
305✔
192
        str->length += other->length;
305✔
193
    }
194
    return result;
305✔
195
}
196

197
MSTR_EXPORT_API(mstr_result_t)
198
mstr_concat_cstr(MString* str, const char* other)
15✔
199
{
200
    MString lit;
201
    usize_t content_len, content_cnt;
202
    mstr_result_t res;
203
    res = mstr_strlen(&content_len, &content_cnt, other, NULL);
15✔
204
    if (MSTR_SUCC(res)) {
15✔
205
        // const MString不会被修改, 所以可强转一下
206
        lit.buff = (char*)(iptr_t)other;
15✔
207
        lit.count = content_cnt;
15✔
208
        lit.length = content_len;
15✔
209
        lit.cap_size = 0;
15✔
210
        res = mstr_concat(str, &lit);
15✔
211
    }
212
    return res;
15✔
213
}
214

215
MSTR_EXPORT_API(mstr_result_t)
216
mstr_concat_cstr_slice(MString* str, const char* start, const char* end)
36✔
217
{
218
    MString lit;
219
    usize_t content_len, content_cnt;
220
    mstr_result_t res;
221
    res = mstr_strlen(&content_len, &content_cnt, start, end);
36✔
222
    if (MSTR_SUCC(res)) {
36✔
223
        // const MString不会被修改, 所以可强转一下
224
        lit.buff = (char*)(iptr_t)start;
35✔
225
        lit.count = content_cnt;
35✔
226
        lit.length = content_len;
35✔
227
        lit.cap_size = 0;
35✔
228
        res = mstr_concat(str, &lit);
35✔
229
    }
230
    return res;
36✔
231
}
232

233
MSTR_EXPORT_API(void) mstr_clear(MString* str)
13✔
234
{
235
    str->count = 0;
13✔
236
    str->length = 0;
13✔
237
}
13✔
238

239
MSTR_EXPORT_API(void) mstr_reverse_self(MString* str)
5✔
240
{
241
    mstr_char_t* pe = str->buff + str->count;
5✔
242
    mstr_reverse_only(str);
5✔
243
    mstr_reverse_unicode_helper(str->buff, pe);
5✔
244
}
5✔
245

246
MSTR_EXPORT_API(void) mstr_reverse_only(MString* str)
125✔
247
{
248
    mstr_char_t* p2 = str->buff + str->count - 1;
125✔
249
    mstr_char_t* p1 = str->buff;
125✔
250
    while (p1 < p2) {
315✔
251
        char v = *p2;
190✔
252
        *p2 = *p1;
190✔
253
        *p1 = v;
190✔
254
        // ++, --
255
        p1 += 1;
190✔
256
        p2 -= 1;
190✔
257
    }
258
}
125✔
259

260
MSTR_EXPORT_API(const char*) mstr_c_str(MString* str)
×
261
{
262
    // 在length的地方补上0
263
    // 因为cap_size至少比length大1, 因此不需要担心内存问题
264
    str->buff[str->count] = 0;
×
265
    return str->buff;
×
266
}
267

268
MSTR_EXPORT_API(mstr_bool_t)
269
mstr_equal(const MString* a, const MString* b)
139✔
270
{
271
    if (a->count != b->count) {
139✔
272
        return False;
×
273
    }
274
    else {
275
        usize_t len = a->count;
139✔
276
        return mstr_compare_helper(a->buff, b->buff, len);
139✔
277
    }
278
}
279

280
MSTR_EXPORT_API(mstr_bool_t)
281
mstr_start_with(
4✔
282
    const MString* str, const char* prefix, usize_t prefix_cnt
283
)
284
{
285
    usize_t len = prefix_cnt;
4✔
286
    if (str->count < len) {
4✔
287
        return False;
1✔
288
    }
289
    else {
290
        return mstr_compare_helper(str->buff, prefix, len);
3✔
291
    }
292
}
293

294
MSTR_EXPORT_API(mstr_bool_t)
295
mstr_end_with(
5✔
296
    const MString* str, const char* suffix, usize_t suffix_cnt
297
)
298
{
299
    usize_t len = suffix_cnt;
5✔
300
    if (str->count < len) {
5✔
301
        return False;
1✔
302
    }
303
    else {
304
        usize_t offset = str->count - len;
4✔
305
        return mstr_compare_helper(str->buff + offset, suffix, len);
4✔
306
    }
307
}
308

309
MSTR_EXPORT_API(mstr_bool_t)
310
mstr_contains(
7✔
311
    const MString* str, const char* pattern, usize_t pattern_cnt
312
)
313
{
314
    mstr_result_t match_ret;
315
    MStringMatchResult match_res;
316
    match_ret = mstr_find(str, &match_res, 0, pattern, pattern_cnt);
7✔
317
    if (MSTR_FAILED(match_ret)) {
7✔
318
        return False;
×
319
    }
320
    else {
321
        return match_res.is_matched;
7✔
322
    }
323
}
324

325
MSTR_EXPORT_API(mstr_codepoint_t)
326
mstr_char_at(const MString* str, usize_t idx)
13✔
327
{
328
#if _MSTR_USE_UTF_8
329
    usize_t offset;
330
    mstr_result_t res = MStr_Ok;
13✔
331
    mstr_codepoint_t out_code = 0;
13✔
332
    mstr_bounding_check(idx < str->length);
333
    offset = mstr_char_offset_at(str, idx);
13✔
334
    res = mstr_codepoint_of(
13✔
335
        &out_code, str->buff + offset, str->count - offset
13✔
336
    );
337
    if (MSTR_SUCC(res)) {
13✔
338
        return out_code;
13✔
339
    }
340
    else {
341
        return 0;
×
342
    }
343
#else
344
    mstr_bounding_check(idx < str->length);
345
    return (mstr_codepoint_t)str->buff[idx];
346
#endif // _MSTR_USE_UTF_8
347
}
348

349
MSTR_EXPORT_API(mstr_result_t)
350
mstr_remove(MString* str, mstr_codepoint_t* removed_ch, usize_t idx)
6✔
351
{
352
    mstr_result_t res = MStr_Ok;
6✔
353
    // 找到需要移除的位置
354
    usize_t offset = mstr_char_offset_at(str, idx);
6✔
355
    // 记录返回的字符
356
    if (removed_ch != NULL) {
6✔
357
#if _MSTR_USE_UTF_8
358
        mstr_codepoint_t out_code = 0;
6✔
359
        res = mstr_codepoint_of(
6✔
360
            &out_code, str->buff + offset, str->count - offset
6✔
361
        );
362
        if (MSTR_SUCC(res)) {
6✔
363
            *removed_ch = out_code;
6✔
364
        }
365
        else {
366
            *removed_ch = 0;
×
367
        }
368
#else
369
        *removed_ch = str->buff[offset];
370
#endif // _MSTR_USE_UTF_8
371
    }
372
    // 移除掉该字符
373
    if (MSTR_SUCC(res)) {
6✔
374
        usize_t ccnt = mstr_char_length(*(str->buff + offset));
6✔
375
        usize_t rems = offset + ccnt;
6✔
376
        memmove(
6✔
377
            str->buff + offset, str->buff + rems, str->count - rems
6✔
378
        );
379
        str->count -= ccnt;
6✔
380
        str->length -= 1;
6✔
381
    }
382
    return res;
6✔
383
}
384

385
MSTR_EXPORT_API(mstr_result_t)
386
mstr_insert(MString* str, usize_t idx, mstr_codepoint_t ch)
10✔
387
{
388
    if (idx == str->length) {
10✔
389
        // 等效为append
390
        // 数组末尾插入的时间复杂度是O(1)的, 因此单独分开一个case
391
        return mstr_append(str, ch);
2✔
392
    }
393
    else {
394
        mstr_result_t res = MStr_Ok;
8✔
395
        // 找到需要插入的位置
396
        usize_t offset = mstr_char_offset_at(str, idx);
8✔
397
        // 对需要插入的字符进行转码
398
        char insert_data[8];
399
        usize_t insert_data_len;
400
#if _MSTR_USE_UTF_8
401
        res = mstr_as_utf8(ch, insert_data, &insert_data_len);
8✔
402
#else
403
        insert_data[0] = (char)ch;
404
        insert_data_len = 1;
405
#endif // _MSTR_USE_UTF_8
406
       // 保证空间足够
407
        if (str->count + insert_data_len + 1 >= str->cap_size) {
8✔
408
            // 保证length < cap_size + 1
409
            // 且有足够的空间存放下一个字符
410
            MSTR_AND_THEN(
1✔
411
                res,
412
                mstr_expand_size(
413
                    str,
414
                    mstr_resize_tactic(str->cap_size, insert_data_len)
415
                )
416
            );
417
        }
418
        // 插入该字符
419
        if (MSTR_SUCC(res)) {
8✔
420
            // 留出空间
421
            memmove(
8✔
422
                str->buff + offset + insert_data_len,
8✔
423
                str->buff + offset,
8✔
424
                str->count - offset
8✔
425
            );
426
            // 然后复制内容过去
427
            memcpy(str->buff + offset, insert_data, insert_data_len);
8✔
428
            str->count += insert_data_len;
8✔
429
            str->length += 1;
8✔
430
        }
431
        return res;
8✔
432
    }
433
}
434

435
MSTR_EXPORT_API(void) mstr_iter(MStringIter* it, const MString* str)
×
436
{
437
    it->it = str->buff;
×
438
    it->it_end = str->buff + str->count;
×
439
    it->rem_length = str->length;
×
440
}
×
441

442
MSTR_EXPORT_API(usize_t) mstr_char_length(char lead)
1,757✔
443
{
444
#if _MSTR_USE_UTF_8
445
    // 构造的小欧拉图会帮忙计算utf-8编码的长度
446
    const uint32_t map[8] = {1, 7, 2, 6, 0, 3, 4, 5};
1,757✔
447
    uint8_t uch = (uint8_t)lead;
1,757✔
448
    uint32_t v = (uint32_t)(uch ^ 0xff);
1,757✔
449
    v |= v >> 1;
1,757✔
450
    v |= v >> 2;
1,757✔
451
    v |= v >> 4;
1,757✔
452
    v += 1;
1,757✔
453
    return map[((v * 232) >> 8) & 0x7];
1,757✔
454
#else
455
    (void)lead;
456
    return 1;
457
#endif // _MSTR_USE_UTF_8
458
}
459

460
MSTR_EXPORT_API(usize_t)
461
mstr_lead_char_offset(const mstr_char_t* buff, usize_t hist_len)
22✔
462
{
463
#if _MSTR_USE_UTF_8
464
    usize_t find_len = hist_len > 6 ? 6 : hist_len;
22✔
465
    const mstr_char_t* it = buff;
22✔
466
    while (find_len > 0) {
42✔
467
        mstr_char_t ch = *it;
42✔
468
        if ((ch & 0x80) == 0) {
42✔
469
            // ASCII
470
            it -= 1;
14✔
471
            break;
14✔
472
        }
473
        else if ((ch & 0xc0) == 0xc0) {
28✔
474
            // utf8前导字符
475
            it -= 1;
8✔
476
            break;
8✔
477
        }
478
        else {
479
            // utf8内容
480
            it -= 1;
20✔
481
            find_len -= 1;
20✔
482
        }
483
    }
484
    return (usize_t)(buff - it);
22✔
485
#else
486
    (void)buff;
487
    (void)hist_len;
488
    return 1;
489
#endif // _MSTR_USE_UTF_8
490
}
491

492
#if _MSTR_USE_UTF_8
493

494
MSTR_EXPORT_API(mstr_result_t)
495
mstr_as_utf8(
752✔
496
    mstr_codepoint_t code, mstr_char_t* result, usize_t* result_len
497
)
498
{
499
    if (code <= 0x7f) {
752✔
500
        // 0xxxxxxx, 1bytes
501
        result[0] = (mstr_char_t)(code & 0x7f);
736✔
502
        *result_len = 1;
736✔
503
        return MStr_Ok;
736✔
504
    }
505
    else if (code <= 0x7ff) {
16✔
506
        // 110xxxxx 10xxxxxx, 2bytes
507
        result[0] = (mstr_char_t)((code >> 6) & 0x1f) | 0xc0;
×
508
        result[1] = (mstr_char_t)(code & 0x3f) | 0x80;
×
509
        *result_len = 2;
×
510
        return MStr_Ok;
×
511
    }
512
    else if (code <= 0xffff) {
16✔
513
        // 1110xxxx 10xxxxxx 10xxxxxx, 3bytes
514
        result[0] = (mstr_char_t)((code >> 12) & 0xf) | 0xe0;
4✔
515
        result[1] = (mstr_char_t)((code >> 6) & 0x3f) | 0x80;
4✔
516
        result[2] = (mstr_char_t)(code & 0x3f) | 0x80;
4✔
517
        *result_len = 3;
4✔
518
        return MStr_Ok;
4✔
519
    }
520
    else if (code <= 0x1fffff) {
12✔
521
        // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx, 4bytes
522
        result[0] = (mstr_char_t)((code >> 18) & 0x7) | 0xf0;
12✔
523
        result[1] = (mstr_char_t)((code >> 12) & 0x3f) | 0x80;
12✔
524
        result[2] = (mstr_char_t)((code >> 6) & 0x3f) | 0x80;
12✔
525
        result[3] = (mstr_char_t)(code & 0x3f) | 0x80;
12✔
526
        *result_len = 4;
12✔
527
        return MStr_Ok;
12✔
528
    }
529
    else {
530
        *result_len = 0;
×
531
        return MStr_Err_UnicodeEncodingError;
×
532
    }
533
}
534

535
MSTR_EXPORT_API(mstr_result_t)
536
mstr_codepoint_of(
42✔
537
    mstr_codepoint_t* code, const mstr_char_t* ch, usize_t byte_count
538
)
539
{
540
    uint32_t val = 0;
42✔
541
    mstr_result_t res;
542
    uint8_t lead_char = (uint8_t)ch[0];
42✔
543
    if (lead_char <= 0x7f) {
42✔
544
        // 0xxxxxxx, 1bytes
545
        if (byte_count >= 1) {
28✔
546
            val |= (uint32_t)(ch[0] & 0x7f);
28✔
547
            res = MStr_Ok;
28✔
548
        }
549
        else {
550
            res = MStr_Err_EncodingNotCompleted;
×
551
        }
552
    }
553
    else if (lead_char <= 0xdf) {
14✔
554
        // 110xxxxx 10xxxxxx, 2bytes
555
        if (byte_count >= 2) {
×
556
            val |= (uint32_t)(ch[1]) & 0x3f;
×
557
            val |= ((uint32_t)(ch[0]) & 0x1f) << 6;
×
558
            res = MStr_Ok;
×
559
        }
560
        else {
561
            res = MStr_Err_EncodingNotCompleted;
×
562
        }
563
    }
564
    else if (lead_char <= 0xef) {
14✔
565
        // 1110xxxx 10xxxxxx 10xxxxxx, 3bytes
566
        if (byte_count >= 3) {
6✔
567
            val |= (uint32_t)(ch[2]) & 0x3f;
6✔
568
            val |= ((uint32_t)(ch[1]) & 0x3f) << 6;
6✔
569
            val |= ((uint32_t)(ch[0]) & 0x0f) << (6 + 6);
6✔
570
            res = MStr_Ok;
6✔
571
        }
572
        else {
573
            res = MStr_Err_EncodingNotCompleted;
×
574
        }
575
    }
576
    else if (lead_char <= 0xf7) {
8✔
577
        // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx, 4 bytes
578
        if (byte_count >= 4) {
8✔
579
            val |= (uint32_t)(ch[3]) & 0x3f;
8✔
580
            val |= ((uint32_t)(ch[2]) & 0x3f) << 6;
8✔
581
            val |= ((uint32_t)(ch[1]) & 0x3f) << (6 + 6);
8✔
582
            val |= ((uint32_t)(ch[0]) & 0x07) << (6 + 6 + 6);
8✔
583
            res = MStr_Ok;
8✔
584
        }
585
        else {
586
            res = MStr_Err_EncodingNotCompleted;
×
587
        }
588
    }
589
    else {
590
        // 再长的就不处理了 ( ̄▽ ̄)"
591
        res = MStr_Err_UnicodeEncodingError;
×
592
    }
593
    if (MSTR_SUCC(res)) {
42✔
594
        *code = val;
42✔
595
    }
596
    return res;
42✔
597
}
598
#else
599

600
MSTR_EXPORT_API(mstr_result_t)
601
mstr_as_utf8(
602
    mstr_codepoint_t code, mstr_char_t* result, usize_t* result_len
603
)
604
{
605
    (void)code;
606
    (void)result;
607
    (void)result_len;
608
    return MStr_Err_NoImplemention;
609
}
610

611
MSTR_EXPORT_API(mstr_result_t)
612
mstr_codepoint_of(
613
    mstr_codepoint_t* code, const mstr_char_t* ch, usize_t byte_count
614
)
615
{
616
    (void)code;
617
    (void)ch;
618
    (void)byte_count;
619
    return MStr_Err_NoImplemention;
620
}
621
#endif // _MSTR_USE_UTF_8
622

623
MSTR_EXPORT_API(usize_t)
624
mstr_char_offset_at(const MString* str, usize_t idx)
79✔
625
{
626
#if _MSTR_USE_UTF_8
627
    usize_t cur_idx = 0;
79✔
628
    const char* it = str->buff;
79✔
629
    mstr_bounding_check(idx < str->length);
630
    while (cur_idx != idx) {
221✔
631
        usize_t cnt = mstr_char_length(*it);
142✔
632
        it += cnt;
142✔
633
        cur_idx += 1;
142✔
634
    }
635
    return (usize_t)(it - str->buff);
79✔
636
#else
637
    mstr_bounding_check(idx < str->length);
638
    return idx;
639
#endif // _MSTR_USE_UTF_8
640
}
641

642
MSTR_EXPORT_API(void) mstr_free(MString* str)
541✔
643
{
644
    if (str->buff != NULL && str->buff != str->stack_region) {
541✔
645
        mstr_heap_free(str->buff);
31✔
646
    }
647
    // else: stack上分配的, 不用管它
648
    str->buff = NULL;
541✔
649
    str->count = 0;
541✔
650
    str->cap_size = 0;
541✔
651
}
541✔
652

653
/**
654
 * @brief 计算字符串长度
655
 *
656
 * @param len: 字符长度
657
 * @param count: 字符串占用的字节数
658
 * @param str: 字符串
659
 * @param str_end: 字符串结束, 为NULL表示'\0'自己算
660
 */
661
static mstr_result_t mstr_strlen(
224✔
662
    usize_t* len,
663
    usize_t* count,
664
    const mstr_char_t* str,
665
    const mstr_char_t* str_end
666
)
667
{
668
    usize_t len_val = 0, count_val = 0;
224✔
669
    if (str_end == NULL) {
224✔
670
        // 给一个大大的值让str < str_end恒为true
671
        str_end = (const mstr_char_t*)(uptr_t)(-1);
188✔
672
    }
673
    if (str == NULL) {
224✔
674
        return 0;
×
675
    }
676
#if _MSTR_USE_UTF_8
677
    while (*str && str < str_end) {
1,675✔
678
        usize_t cnt = mstr_char_length(*str);
1,451✔
679
        count_val += cnt;
1,451✔
680
        len_val += 1;
1,451✔
681
        str += cnt;
1,451✔
682
    }
683
    *len = len_val;
224✔
684
    *count = count_val;
224✔
685
    if (str > str_end) {
224✔
686
        // 正常情况应该刚好相等
687
        // 不然说明原字符串不完整
688
        return MStr_Err_EncodingNotCompleted;
1✔
689
    }
690
    else {
691
        return MStr_Ok;
223✔
692
    }
693
#else
694
    while (*str && str < str_end) {
695
        count_val += 1;
696
        len_val += 1;
697
        str += 1;
698
    }
699
    *len = len_val;
700
    *count = count_val;
701
    return MStr_Ok;
702
#endif // _MSTR_USE_UTF_8
703
}
704

705
/**
706
 * @brief 翻转Unicode字符编码, 让其正确, 在UTF-8关闭的情况下,
707
 * 该函数不做任何操作
708
 *
709
 * @param[inout] buff: 操作数组
710
 * @param[in] pe: 数组的末尾位置
711
 */
712
static void mstr_reverse_unicode_helper(
5✔
713
    mstr_char_t* buff, const mstr_char_t* pe
714
)
715
{
716
#if _MSTR_USE_UTF_8
717
    mstr_char_t* p1 = buff;
5✔
718
    mstr_char_t* p2 = buff;
5✔
719
    // UTF-8考虑的地方在于 <= 0x7f 是ASCII
720
    // 而其余情况都是UTF-8字符串
721
    // 那么就可以先反转每个bytes:
722
    // >> [char1: 110xxxxx 10xxxxxx], [char2: 110xxxxx 10xxxxxx]
723
    // => [char2: 10xxxxxx 110xxxxx], [char1: 10xxxxxx 110xxxxx]
724
    // 再去遍历一遍字符串, 跳过ascii, 并在发现lead character的时候
725
    // 把上次的位置到目前lead character的字符交换
726
    while (p2 < pe) {
53✔
727
        mstr_char_t ch = *p2;
48✔
728
        p2 += 1;
48✔
729
        if ((ch & 0x80) == 0) {
48✔
730
            // ASCII
731
            p1 = p2;
26✔
732
        }
733
        else if ((ch & 0xc0) == 0xc0) {
22✔
734
            // 2~6bytes UTF-8的lead character
735
            mstr_char_t* t = p2;
6✔
736
            usize_t byte_len = (usize_t)(p2 - p1);
6✔
737
            // 因为一些编译器会抱怨case后无break
738
            // 因此这里用goto做
739
            switch (byte_len) {
6✔
740
            case 4: goto proc_4;
4✔
741
            case 3: goto proc_3;
2✔
742
            case 2: goto proc_2;
×
743
            default: mstr_unreachable(); goto end;
×
744
            }
745
        proc_4:
4✔
746
            //  3    2    1    0
747
            // /|\            /|\ 4个byte长度
748
            //  p1             p2
749
            // 交换p1和p2, 然后变成下面的样子
750
            //  0    2    1    3
751
            //      /|\  /|\ 2个byte长度
752
            //       p1   p2
753
            // 交给proc_2以一样的方式交换p1和p2即可
754
            ch = *p1;
4✔
755
            *p1++ = *--p2;
4✔
756
            *p2 = ch;
4✔
757
            goto proc_2;
4✔
758
        proc_3:
2✔
759
            // str[1]和str[1]不需要交换
760
            goto proc_2;
2✔
761
        proc_2:
6✔
762
            ch = *p1;
6✔
763
            *p1++ = *--p2;
6✔
764
            *p2 = ch;
6✔
765
            goto end;
6✔
766
        end:
6✔
767
            p1 = t;
6✔
768
            p2 = t;
6✔
769
        }
770
    }
771
#else
772
    (void)buff;
773
    (void)pe;
774
#endif // _MSTR_USE_UTF_8
775
}
5✔
776

777
/**
778
 * @brief 比较相同长度len的字串a和b是否一致
779
 *
780
 * @param a: 字符串a
781
 * @param b: 字符串b
782
 * @param len: 字符串a和b的长度
783
 *
784
 * @return mstr_bool_t: 比较结果
785
 */
786
static mstr_bool_t mstr_compare_helper(
146✔
787
    const char* a, const char* b, usize_t len
788
)
789
{
790
    uint32_t bit = 0;
146✔
791
    for (usize_t i = 0; i < len; i += 1) {
1,349✔
792
        uint32_t ch_a = a[i];
1,203✔
793
        uint32_t ch_b = b[i];
1,203✔
794
        // equ
795
        bit |= ch_a ^ ch_b;
1,203✔
796
    }
797
    return bit == 0;
146✔
798
}
799

800
/**
801
 * @brief 扩展str的size
802
 *
803
 * @param[inout] str: 需要调整大小的str
804
 * @param[in] new_size: 调整到的新的大小
805
 * @return mstr_result_t: 调整结果
806
 */
807
static mstr_result_t mstr_expand_size(MString* str, usize_t new_size)
19✔
808
{
809
    if (new_size > str->cap_size) {
19✔
810
        char* new_ptr = (char*)mstr_string_realloc(
19✔
811
            str->buff,
19✔
812
            str->buff == str->stack_region,
19✔
813
            str->count,
814
            new_size
815
        );
816
        if (new_ptr == NULL) {
19✔
817
            // 分配失败
818
            return MStr_Err_HeapTooSmall;
×
819
        }
820
        str->buff = new_ptr;
19✔
821
        str->cap_size = new_size;
19✔
822
        return MStr_Ok;
19✔
823
    }
824
    else {
825
        return MStr_Ok;
×
826
    }
827
}
828

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

858
/**
859
 * @brief 改变cap的策略
860
 *
861
 * @param[in] old_sz: 以前的大小
862
 * @param[in] inc_len: 至少需要增加的大小, 会在此基础上增加1
863
 */
864
static usize_t mstr_resize_tactic(usize_t old_sz, usize_t inc_len)
19✔
865
{
866
    usize_t min_sz = old_sz + inc_len + 1;
19✔
867
    if (old_sz < MSTR_SIZE_EXPAND_MAX) {
19✔
868
        usize_t exp_sz = old_sz * 2;
19✔
869
        return min_sz < exp_sz ? exp_sz : min_sz;
19✔
870
    }
871
    else {
872
        return old_sz + inc_len + MSTR_SIZE_LARGE_CAP_SIZE_STEP;
×
873
    }
874
}
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