Skip to content

Commit 1f56723

Browse files
committed
jim: replace Jim_Sink and Jim_Write with String Builder
1 parent 2070ead commit 1f56723

File tree

6 files changed

+47
-104
lines changed

6 files changed

+47
-104
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CFLAGS=-Wall -Wextra -Wswitch-enum -ggdb
1+
CFLAGS=-Wall -Wextra -Wswitch-enum -ggdb -I./thirdparty/
22

33
.PHONY: all
44
all: examples test

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ Immediate Mode JSON Serialization Library in C. Similar to [imgui](https://githu
1414

1515
int main()
1616
{
17-
Jim jim = {
18-
.sink = stdout,
19-
.write = (Jim_Write) fwrite,
20-
};
17+
Jim jim = {0};
2118

2219
jim_object_begin(&jim);
2320
jim_member_key(&jim, "null");
@@ -61,6 +58,8 @@ int main()
6158
return -1;
6259
}
6360

61+
fwrite(jim.sink, jim.sink_count, 1, stdout);
62+
6463
return 0;
6564
}
6665
```

examples/01_from_readme.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55

66
int main()
77
{
8-
Jim jim = {
9-
.sink = stdout,
10-
.write = (Jim_Write) fwrite,
11-
};
8+
Jim jim = {0};
129

1310
jim_object_begin(&jim);
1411
jim_member_key(&jim, "null");
@@ -52,5 +49,7 @@ int main()
5249
return -1;
5350
}
5451

52+
fwrite(jim.sink, jim.sink_count, 1, stdout);
53+
5554
return 0;
5655
}

examples/02_binary_tree.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Node *generate_tree_of_fruits(size_t level_cur, size_t level_max)
3232
}
3333
}
3434

35-
void print_node_as_json(Jim *jim, Node *node)
35+
void render_node_as_json(Jim *jim, Node *node)
3636
{
3737
if (node == NULL) {
3838
jim_null(jim);
@@ -42,21 +42,19 @@ void print_node_as_json(Jim *jim, Node *node)
4242
jim_string(jim, node->value);
4343

4444
jim_member_key(jim, "left");
45-
print_node_as_json(jim, node->left);
45+
render_node_as_json(jim, node->left);
4646

4747
jim_member_key(jim, "right");
48-
print_node_as_json(jim, node->right);
48+
render_node_as_json(jim, node->right);
4949
jim_object_end(jim);
5050
}
5151
}
5252

5353
int main()
5454
{
5555
srand(time(0));
56-
Jim jim = {
57-
.sink = stdout,
58-
.write = (Jim_Write) fwrite,
59-
};
60-
print_node_as_json(&jim, generate_tree_of_fruits(0, 4));
56+
Jim jim = {0};
57+
render_node_as_json(&jim, generate_tree_of_fruits(0, 4));
58+
fwrite(jim.sink, jim.sink_count, 1, stdout);
6159
return 0;
6260
}

jim.h

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,10 @@
77

88
#include <assert.h>
99
#include <stdlib.h>
10-
11-
typedef void* Jim_Sink;
12-
typedef size_t (*Jim_Write)(const void *ptr, size_t size, size_t nmemb, Jim_Sink sink);
10+
#include <string.h>
1311

1412
typedef enum {
1513
JIM_OK = 0,
16-
JIM_WRITE_ERROR,
1714
JIM_SCOPES_UNDERFLOW,
1815
JIM_OUT_OF_SCOPE_KEY,
1916
JIM_DOUBLE_KEY
@@ -33,9 +30,10 @@ typedef struct {
3330
} Jim_Scope;
3431

3532
typedef struct {
36-
Jim_Sink sink;
37-
Jim_Write write;
3833
Jim_Error error;
34+
char *sink;
35+
size_t sink_count;
36+
size_t sink_capacity;
3937
Jim_Scope *scopes;
4038
size_t scopes_count;
4139
size_t scopes_capacity;
@@ -63,15 +61,6 @@ void jim_object_end(Jim *jim);
6361

6462
#ifdef JIM_IMPLEMENTATION
6563

66-
static size_t jim_strlen(const char *s)
67-
{
68-
size_t count = 0;
69-
while (*(s + count)) {
70-
count += 1;
71-
}
72-
return count;
73-
}
74-
7564
static void jim_scope_push(Jim *jim, Jim_Scope_Kind kind)
7665
{
7766
if (jim->error == JIM_OK) {
@@ -113,16 +102,21 @@ static Jim_Scope *jim_current_scope(Jim *jim)
113102
static void jim_write(Jim *jim, const char *buffer, size_t size)
114103
{
115104
if (jim->error == JIM_OK) {
116-
if (jim->write(buffer, 1, size, jim->sink) < size) {
117-
jim->error = 1;
105+
while (jim->sink_count + size >= jim->sink_capacity) {
106+
// TODO: rename JIM_SCOPES_CAPACITY to something else since it's used by both sink and scopes
107+
if (jim->sink_capacity == 0) jim->sink_capacity = JIM_SCOPES_CAPACITY;
108+
else jim->sink_capacity *= 2;
109+
jim->sink = realloc(jim->sink, sizeof(*jim->sink)*jim->sink_capacity);
118110
}
111+
memcpy(jim->sink + jim->sink_count, buffer, size);
112+
jim->sink_count += size;
119113
}
120114
}
121115

122116
static void jim_write_cstr(Jim *jim, const char *cstr)
123117
{
124118
if (jim->error == JIM_OK) {
125-
jim_write(jim, cstr, jim_strlen(cstr));
119+
jim_write(jim, cstr, strlen(cstr));
126120
}
127121
}
128122

@@ -166,8 +160,6 @@ const char *jim_error_string(Jim_Error error)
166160
switch (error) {
167161
case JIM_OK:
168162
return "There is no error. The developer of this software just had a case of \"Task failed successfully\" https://i.imgur.com/Bdb3rkq.jpg - Please contact the developer and tell them that they are very lazy for not checking errors properly.";
169-
case JIM_WRITE_ERROR:
170-
return "Write error";
171163
case JIM_SCOPES_UNDERFLOW:
172164
return "Stack of Scopes Underflow";
173165
case JIM_OUT_OF_SCOPE_KEY:
@@ -319,7 +311,7 @@ void jim_string_sized(Jim *jim, const char *str, size_t size)
319311
void jim_string(Jim *jim, const char *str)
320312
{
321313
if (jim->error == JIM_OK) {
322-
jim_string_sized(jim, str, jim_strlen(str));
314+
jim_string_sized(jim, str, strlen(str));
323315
}
324316
}
325317

@@ -354,7 +346,7 @@ void jim_object_begin(Jim *jim)
354346
void jim_member_key(Jim *jim, const char *str)
355347
{
356348
if (jim->error == JIM_OK) {
357-
jim_member_key_sized(jim, str, jim_strlen(str));
349+
jim_member_key_sized(jim, str, strlen(str));
358350
}
359351
}
360352

test.c

Lines changed: 20 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,12 @@
44

55
#define JIM_IMPLEMENTATION
66
#include "./jim.h"
7+
#define NOB_IMPLEMENTATION
8+
#define NOB_STRIP_PREFIX
9+
#include "./nob.h"
710

811
#include "./test_expected.h"
912

10-
#define ARRAY_LEN(xs) (sizeof(xs) / sizeof((xs)[0]))
11-
12-
typedef struct {
13-
size_t capacity;
14-
size_t size;
15-
char *data;
16-
} Buffer;
17-
18-
void buffer_clean(Buffer *buffer)
19-
{
20-
buffer->size = 0;
21-
}
22-
23-
size_t buffer_write(const void *ptr, size_t size, size_t nmemb,
24-
Buffer *sink)
25-
{
26-
size_t esize = size * nmemb; // effective size
27-
28-
if (sink->size + esize <= sink->capacity) {
29-
memcpy(sink->data + sink->size,
30-
ptr,
31-
esize);
32-
sink->size += esize;
33-
return esize;
34-
} else {
35-
return 0;
36-
}
37-
}
38-
39-
static char static_memory_for_buffer[1024];
40-
41-
static Buffer buffer = {
42-
.capacity = sizeof(static_memory_for_buffer),
43-
.data = static_memory_for_buffer
44-
};
45-
4613
void null_case(Jim *jim)
4714
{
4815
jim_array_begin(jim);
@@ -144,54 +111,42 @@ const Test_Case test_cases[] = {
144111
TEST_CASE(object_case),
145112
};
146113

147-
void record(const char *header_path)
114+
bool record(const char *header_path)
148115
{
149-
FILE *stream = fopen(header_path, "w");
150-
151-
Jim jim_stream = {
152-
.sink = stream,
153-
.write = (Jim_Write) fwrite,
154-
};
116+
Jim jim_stream = {0};
117+
Jim jim_buffer = {0};
155118

156-
Jim jim_buffer = {
157-
.sink = &buffer,
158-
.write = (Jim_Write) buffer_write,
159-
};
160-
161-
fprintf(stream, "const char *test_cases_expected[] = {\n");
119+
jim_write_cstr(&jim_stream, "const char *test_cases_expected[] = {\n");
162120
for (size_t i = 0; i < ARRAY_LEN(test_cases); ++i) {
163-
buffer_clean(&buffer);
121+
jim_buffer.sink_count = 0;
164122
test_cases[i].run(&jim_buffer);
165-
fprintf(stream, " ");
166-
jim_string_sized(&jim_stream, buffer.data, buffer.size);
167-
fprintf(stream, ",\n");
123+
jim_write_cstr(&jim_stream, " ");
124+
jim_string_sized(&jim_stream, jim_buffer.sink, jim_buffer.sink_count);
125+
jim_write_cstr(&jim_stream, ",\n");
168126
}
169-
fprintf(stream, "};\n");
170-
171-
fclose(stream);
127+
jim_write_cstr(&jim_stream, "};\n");
172128

129+
if (!write_entire_file(header_path, jim_stream.sink, jim_stream.sink_count)) return false;
173130
printf("Updated %s\n", header_path);
131+
return true;
174132
}
175133

176134
void test(void)
177135
{
178-
Jim jim_buffer = {
179-
.sink = &buffer,
180-
.write = (Jim_Write) buffer_write,
181-
};
136+
Jim jim_buffer = {0};
182137

183138
for (size_t i = 0; i < ARRAY_LEN(test_cases); ++i) {
184139
printf("%s ... ", test_cases[i].name);
185140

186-
buffer_clean(&buffer);
141+
jim_buffer.sink_count = 0;
187142
test_cases[i].run(&jim_buffer);
188143

189-
if (buffer.size != strlen(test_cases_expected[i])
190-
|| memcmp(buffer.data, test_cases_expected[i], buffer.size) != 0) {
144+
if (jim_buffer.sink_count != strlen(test_cases_expected[i])
145+
|| memcmp(jim_buffer.sink, test_cases_expected[i], jim_buffer.sink_count) != 0) {
191146
printf("FAILED!\n");
192147
printf("Expected: %s\n", test_cases_expected[i]);
193148
printf("Actual: ");
194-
fwrite(buffer.data, 1, buffer.size, stdout);
149+
fwrite(jim_buffer.sink, jim_buffer.sink_count, 1, stdout);
195150
printf("\n");
196151
exit(1);
197152
}
@@ -204,7 +159,7 @@ int main(int argc, char **argv)
204159
{
205160
if (argc >= 2) {
206161
if (strcmp(argv[1], "record") == 0) {
207-
record("test_expected.h");
162+
if (!record("test_expected.h")) return 1;
208163
} else {
209164
fprintf(stderr, "Usage: ./test [record]\n");
210165
fprintf(stderr, "ERROR: unknown subcommand %s.\n", argv[1]);

0 commit comments

Comments
 (0)