1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#define NONSTD_IMPLEMENTATION
#include "../nonstd.h"
#include <stdio.h>
// Helper function to print string builder content
void print_sb(const char *label, const stringb *sb) {
printf("%s (len=%zu, cap=%zu): \"%s\"\n", label, sb->length, sb->capacity, sb->data);
}
int main(void) {
// Example 1: Basic string building
stringb sb1;
sb_init(&sb1, 0); // 0 means use default capacity (16)
sb_append_cstr(&sb1, "Hello");
sb_append_cstr(&sb1, ", ");
sb_append_cstr(&sb1, "World");
sb_append_char(&sb1, '!');
print_sb(" sb1", &sb1);
sb_free(&sb1);
printf("\n");
// Example 2: Building with initial capacity
stringb sb2;
sb_init(&sb2, 100); // Start with larger capacity to avoid reallocations
print_sb(" Initial", &sb2);
sb_append_cstr(&sb2, "This is a longer string that benefits from pre-allocation");
print_sb(" After append", &sb2);
sb_free(&sb2);
printf("\n");
// Example 3: Appending string views
stringb sb3;
sb_init(&sb3, 0);
const char *text = "The quick brown fox";
stringv word = sv_from_parts(text + 4, 5); // "quick"
sb_append_cstr(&sb3, "Extracted: ");
sb_append_sv(&sb3, word);
sb_append_cstr(&sb3, " (from a view)");
print_sb(" sb3", &sb3);
sb_free(&sb3);
printf("\n");
// Example 4: Converting builder to view for reading
stringb sb4;
sb_init(&sb4, 0);
sb_append_cstr(&sb4, "Builder content");
// Get a read-only view of the builder
stringv view = sb_as_sv(&sb4);
printf(" Builder as view (len=%zu): \"", view.length);
fwrite(view.data, 1, view.length, stdout);
printf("\"\n");
// You can use all string view operations on it
stringv prefix = sv_from_cstr("Builder");
printf(" Starts with 'Builder': %s\n", sv_starts_with(view, prefix) ? "yes" : "no");
sb_free(&sb4);
printf("\n");
// Example 5: Building a formatted message
stringb sb5;
sb_init(&sb5, 0);
const char *names[] = {"Alice", "Bob", "Charlie"};
int ages[] = {25, 30, 35};
sb_append_cstr(&sb5, "People:\n");
for (size_t i = 0; i < countof(names); i++) {
sb_append_cstr(&sb5, " - ");
sb_append_cstr(&sb5, names[i]);
sb_append_cstr(&sb5, " (age ");
// Note: For numbers, you'd typically use sprintf with a temp buffer
char age_buf[32];
snprintf(age_buf, sizeof(age_buf), "%d", ages[i]);
sb_append_cstr(&sb5, age_buf);
sb_append_cstr(&sb5, ")\n");
}
printf("%s", sb5.data);
sb_free(&sb5);
printf("\n");
// Example 6: Building CSV data
stringb csv;
sb_init(&csv, 64);
sb_append_cstr(&csv, "Name,Age,City\n");
sb_append_cstr(&csv, "Alice,25,NYC\n");
sb_append_cstr(&csv, "Bob,30,LA\n");
sb_append_cstr(&csv, "Charlie,35,Chicago\n");
printf(" CSV output:\n%s", csv.data);
sb_free(&csv);
printf("\n");
// Example 7: Practical use case - building a SQL query
stringb query;
sb_init(&query, 128);
sb_append_cstr(&query, "SELECT * FROM users WHERE ");
const char *conditions[] = {"age > 18", "active = 1", "country = 'US'"};
for (size_t i = 0; i < countof(conditions); i++) {
if (i > 0) {
sb_append_cstr(&query, " AND ");
}
sb_append_cstr(&query, conditions[i]);
}
sb_append_char(&query, ';');
print_sb(" Query", &query);
sb_free(&query);
printf("\n");
return 0;
}
|