Skip to content

Commit 6e489ea

Browse files
committed
Merge branch 'master' into draft
2 parents b3f9de6 + dff6953 commit 6e489ea

File tree

5 files changed

+12
-12
lines changed

5 files changed

+12
-12
lines changed

readme.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@
3838

3939
本教程预计分为 9 个单元,第 1-8 个单元附带练习和解答。
4040

41-
1. [启程](tutorial01/tutorial01.md)(2016/9/15 完成):编译环境、JSON 简介、测试驱动、解析器主要函数及各数据结构。练习 JSON 布尔类型的解析。[启程解答编](tutorial01_answer/tutorial01_answer.md)(2016/9/17 完成)。
42-
2. [解析数字](tutorial02/tutorial02.md)(2016/9/18 完成):JSON number 的语法。练习 JSON number 类型的校验。[解析数字解答编](tutorial02_answer/tutorial02_answer.md)(2016/9/20 完成)。
43-
3. [解析字符串](tutorial03/tutorial03.md)(2016/9/22 完成):使用 union 存储 variant、自动扩展的堆栈、JSON string 的语法、valgrind。练习最基本的 JSON string 类型的解析、内存释放。
41+
1. [启程](tutorial01/tutorial01.md)(2016/9/15 完成):编译环境、JSON 简介、测试驱动、解析器主要函数及各数据结构。练习 JSON 布尔类型的解析。[启程解答篇](tutorial01_answer/tutorial01_answer.md)(2016/9/17 完成)。
42+
2. [解析数字](tutorial02/tutorial02.md)(2016/9/18 完成):JSON number 的语法。练习 JSON number 类型的校验。[解析数字解答篇](tutorial02_answer/tutorial02_answer.md)(2016/9/20 完成)。
43+
3. [解析字符串](tutorial03/tutorial03.md)(2016/9/22 完成):使用 union 存储 variant、自动扩展的堆栈、JSON string 的语法、valgrind。练习最基本的 JSON string 类型的解析、内存释放。[解析字符串解答篇](tutorial03_answer/tutorial03_answer.md)(2016/9/27 完成)。
4444
4. Unicode:Unicode 和 UTF-8 的基本知识、JSON string 的 unicode 处理。练习完成 JSON string 类型的解析。
4545
5. 解析数组:JSON array 的语法。练习完成 JSON array 类型的解析、相关内存释放。
4646
6. 解析对象:JSON object 的语法、重构 string 解析函数。练习完成 JSON object 的解析、相关内存释放。

tutorial03/leptjson.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ static int lept_parse_string(lept_context* c, lept_value* v) {
9696
switch (ch) {
9797
case '\"':
9898
len = c->top - head;
99-
lept_set_string(v, lept_context_pop(c, len), len);
99+
lept_set_string(v, (const char*)lept_context_pop(c, len), len);
100100
c->json = p;
101101
return LEPT_PARSE_OK;
102102
case '\0':

tutorial03/tutorial03.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ int lept_parse(lept_value* v, const char* json) {
197197
198198
然后,我们实现堆栈的压入及弹出操作。和普通的堆栈不一样,我们这个堆栈是以字节储存的。每次可要求压入任意大小的数据,它会返回数据起始的指针(会 C++ 的同学可再参考[1]):
199199
200-
~~~
200+
~~~c
201201
#ifndef LEPT_PARSE_STACK_INIT_SIZE
202202
#define LEPT_PARSE_STACK_INIT_SIZE 256
203203
#endif
@@ -246,7 +246,7 @@ static int lept_parse_string(lept_context* c, lept_value* v) {
246246
switch (ch) {
247247
case '\"':
248248
len = c->top - head;
249-
lept_set_string(v, lept_context_pop(c, len), len);
249+
lept_set_string(v, (const char*)lept_context_pop(c, len), len);
250250
c->json = p;
251251
return LEPT_PARSE_OK;
252252
case '\0':

tutorial03_answer/leptjson.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ static int lept_parse_string(lept_context* c, lept_value* v) {
100100
switch (ch) {
101101
case '\"':
102102
len = c->top - head;
103-
lept_set_string(v, lept_context_pop(c, len), len);
103+
lept_set_string(v, (const char*)lept_context_pop(c, len), len);
104104
c->json = p;
105105
return LEPT_PARSE_OK;
106106
case '\\':

tutorial03_answer/tutorial03_answer.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
# 从零开始的 JSON 库教程(三):解析字符串解答编
1+
# 从零开始的 JSON 库教程(三):解析字符串解答篇
22

33
* Milo Yip
4-
* 2016/9/24
4+
* 2016/9/27
55

66
本文是[《从零开始的 JSON 库教程》](https://zhuanlan.zhihu.com/json-tutorial)的第三个单元解答编。解答代码位于 [json-tutorial/tutorial03_answer](https://github.com/miloyip/json-tutorial/blob/master/tutorial03_answer)
77

@@ -101,7 +101,7 @@ C:\GitHub\json-tutorial\tutorial03_answer\leptjson.c(212) : {79} normal block at
101101
Object dump complete.
102102
~~~
103103

104-
这正是我们在单元测试中,先设置字符串,然后设布尔值时设释放字符串所分配的内存。比较麻烦的是,它没有显示调用堆栈。从输出信息中 `... {79} ...` 我们知道是第 79 次分配的内存做成问题,我们可以加上 `_CrtSetBreakAlloc(79);` 来调试,那么它便会在第 79 次时中断于分配调用的位置,那时候就能从调用堆栈去找出来龙去脉。
104+
这正是我们在单元测试中,先设置字符串,然后设布尔值时没释放字符串所分配的内存。比较麻烦的是,它没有显示调用堆栈。从输出信息中 `... {79} ...` 我们知道是第 79 次分配的内存做成问题,我们可以加上 `_CrtSetBreakAlloc(79);` 来调试,那么它便会在第 79 次时中断于分配调用的位置,那时候就能从调用堆栈去找出来龙去脉。
105105

106106
## 1B. Linux/OSX 下的内存泄漏检测方法
107107

@@ -221,8 +221,8 @@ unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
221221

222222
这是本教程第一次的开放式问题,没有标准答案。以下列出一些我想到的。
223223

224-
1. 如果整个字符串都没有转义符,我们不就是把字符复制了两次?第一次是从 `json``stack`,第二次是从 `stack``v->u.s.s`。我们可以在 `json` 扫瞄 `'\0'``'\"'``'\\'` 3 个字符( `ch < 0x20` 还是要检查),直至它们其中一个出现,才开始用现在的解析方法。这样做的话,前半没转义的部分可以只复制一次。缺点是,代码变得复杂一些,我们也不能使用 `lept_set_string()`
225-
2. 对于扫瞄没转义部分,我们可考虑用 SIMD 加速,如 [RapidJSON 代码剖析(二):使用 SSE4.2 优化字符串扫描](https://zhuanlan.zhihu.com/p/20037058) 的做法。这类底层优化的缺点是不跨平台,需要设置编译选项等。
224+
1. 如果整个字符串都没有转义符,我们不就是把字符复制了两次?第一次是从 `json``stack`,第二次是从 `stack``v->u.s.s`。我们可以在 `json` 扫描 `'\0'``'\"'``'\\'` 3 个字符( `ch < 0x20` 还是要检查),直至它们其中一个出现,才开始用现在的解析方法。这样做的话,前半没转义的部分可以只复制一次。缺点是,代码变得复杂一些,我们也不能使用 `lept_set_string()`
225+
2. 对于扫描没转义部分,我们可考虑用 SIMD 加速,如 [RapidJSON 代码剖析(二):使用 SSE4.2 优化字符串扫描](https://zhuanlan.zhihu.com/p/20037058) 的做法。这类底层优化的缺点是不跨平台,需要设置编译选项等。
226226
3. 在 gcc/clang 上使用 `__builtin_expect()` 指令来处理低概率事件,例如需要对每个字符做 `LEPT_PARSE_INVALID_STRING_CHAR` 检测,我们可以假设出现不合法字符是低概率事件,然后用这个指令告之编译器,那么编译器可能可生成较快的代码。然而,这类做法明显是不跨编译器,甚至是某个版本后的 gcc 才支持。
227227

228228
## 5. 总结

0 commit comments

Comments
 (0)