Ver Fonte

refactor: 优化json存储结构

RyanCW há 6 dias atrás
pai
commit
9c9d896ce4

+ 2 - 1
.clang-tidy

@@ -27,8 +27,9 @@
 # Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,-misc-const-correctness,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-misc-no-recursion,-misc-use-anonymous-namespace,readability-identifier-naming,-misc-include-cleaner'
 
 Checks: 
-  - "-*,clang-diagnostic-*,clang-analyzer-*,llvm-*,concurrency-*,performance-*,cert-*"
+  - "-*,clang-diagnostic-*,clang-analyzer-*,concurrency-*,performance-*,cert-*"
   # 静默的窄化转换交给编译器来判断?
+  - 'llvm-*,-llvm-include-order'
   - 'bugprone-*,-bugprone-easily-swappable-parameters'
   - 'readability-identifier-naming'
   - 'misc-*,-misc-const-correctness,-misc-no-recursion,-misc-include-cleaner'

+ 10 - 0
.clangd

@@ -0,0 +1,10 @@
+Index:
+  Background: Build      # 开启后台索引
+  
+# 如果你的 compile_commands.json 不在根目录,需要在这里显式指定
+CompileFlags:
+  CompilationDatabase: ".vscode"
+
+Diagnostics:
+  UnusedIncludes: None  # 关键:这会关闭“未使用头文件”的提示
+  MissingIncludes: None # 可选:关闭“缺失头文件”的提示

+ 31 - 48
.vscode/settings.json

@@ -1,8 +1,27 @@
 {
-    "clangd.enable": false,
-    "C_Cpp.intelliSenseEngine": "default",
-    "C_Cpp.codeAnalysis.clangTidy.enabled": true,
-    "c-cpp-flylint.enable": true,
+    "Lua.codeLens.enable": false,
+    "Lua.hint.enable": false,
+    "Lua.completion.enable": false,
+    "Lua.format.enable": false,
+    "Lua.hover.enable": false,
+    "Lua.diagnostics.enable": false,
+    "Lua.semantic.enable": false,
+    "Lua.addonManager.enable": false,
+    "Lua.signatureHelp.enable": false,
+    "clangd.enable": true,
+    "clangd.arguments": [
+    ],
+    "C_Cpp.intelliSenseEngine": "disabled",
+    "C_Cpp.errorSquiggles": "disabled", // 关闭微软的波浪线
+    "C_Cpp.autocomplete": "disabled", // 关闭微软的自动补全
+    "C_Cpp.default.compileCommands": "${workspaceFolder}/.vscode/compile_commands.json",
+    "C_Cpp.codeAnalysis.clangTidy.enabled": false,
+    "C_Cpp.codeAnalysis.clangTidy.args": [
+        // "--extra-arg=-ferror-limit=1"
+        // "--extra-arg=-m32",
+        "--extra-arg=--target=arm-none-eabi-gcc"
+    ],
+    "c-cpp-flylint.enable": false,
     "c-cpp-flylint.cppcheck.severityLevels": {
         "error": "Error",
         "warning": "Warning",
@@ -12,49 +31,13 @@
         "information": "Information"
     },
     "c-cpp-flylint.cppcheck.extraArgs": [
-        // "--suppress=constParameterPointer",
-        // "--suppress=constParameterCallback",
+        "--suppress=constParameterPointer",
+        "--suppress=constParameterCallback",
         "--check-level=exhaustive",
-        // "--suppress=variableScope",
-        // "--suppress=unreadVariable",
-        // "--suppress=constVariablePointer",
-        // "--suppress=constParameter",
-    ],
-    "files.watcherExclude": {
-        "**/test/fuzzer/corpus/**": true,
-        "./coverage": true,
-        "./build": true,
-        "./.xmake": true,
-    },
-    "files.exclude": {
-        "**/test/fuzzer/corpus/**": true,
-        "./coverage": true,
-        "./build": true,
-        "./.xmake": true,
-    },
-    "files.associations": {
-        "*.c": "c",
-        "inttypes.h": "c",
-        "float.h": "c",
-        "stdlib.h": "c",
-        "limits.h": "c",
-        "stdio.h": "c",
-        "stdint.h": "c",
-        "ryanjsontest.h": "c",
-        "dirent.h": "c",
-        "valloc.h": "c",
-        "initializer_list": "c",
-        "array": "c",
-        "string_view": "c",
-        "utility": "c",
-        "math.h": "c",
-        "compare": "c",
-        "type_traits": "c",
-        "cjson.h": "c",
-        "ryanjson.h": "c",
-        "string.h": "c",
-        "stdarg.h": "c",
-        "cstdlib": "c",
-        "ryanjsonconfig.h": "c"
-    },
+        "--suppress=variableScope",
+        "--suppress=unreadVariable",
+        "--suppress=constVariablePointer",
+        "--suppress=constParameter",
+        "--suppress=unusedStructMember",
+    ]
 }

+ 108 - 71
README.md

@@ -28,7 +28,7 @@
 
 ### 2、设计
 
-**RyanJson设计时大量借鉴了 [json](https://api.gitee.com/Lamdonn/json) 和 [cJSON](https://github.com/DaveGamble/cJSON) ! **
+**RyanJson设计时借鉴了 [json](https://api.gitee.com/Lamdonn/json) 和 [cJSON](https://github.com/DaveGamble/cJSON) ! **
 
 Json语法是**JavaScript**对象语法的子集,可通过下面两个连接学习json语法。
 
@@ -46,13 +46,20 @@ struct RyanJsonNode
 {
 	struct RyanJsonNode *next; // 单链表节点指针
 
-	/*
-	 * 在 next 后紧跟一个字节的 flag,用于描述节点的核心信息:
+	/**
+	 * @brief RyanJson 节点结构体
+	 * 每个节点由链表连接,包含元数据标识 (Flag) 与动态载荷存储区。
 	 *
-	 * 位分布如下:
+	 * 内存布局:
+	 * [ next指针 | flag(1字节) | padding/指针空间 | 动态载荷区 ]
+	 *
+	 * @brief 节点元数据标识 (Flag)
+	 * 紧跟 next 指针后,利用 1 字节位域描述节点类型及存储状态。
+	 *
+	 * flag 位分布定义:
 	 * bit7   bit6   bit5   bit4   bit3   bit2   bit1   bit0
 	 * -----------------------------------------------------
-	 * 保留   KeyLen KeyLen HasKey NumExt Type2 Type1 Type0
+	 * strMode KeyLen KeyLen HasKey NumExt Type2  Type1  Type0
 	 *
 	 * 各位含义:
 	 * - bit0-2 : 节点类型
@@ -61,58 +68,88 @@ struct RyanJsonNode
 	 *
 	 * - bit3   : 扩展位
 	 *            Bool 类型:0=false, 1=true
-	 *            Number 类型:0=int, 1=double
+	 *            Number 类型:0=int(4字节), 1=double(8字节)
 	 *
 	 * - bit4   : 是否包含 Key
 	 *            0=无 Key(数组元素)
 	 *            1=有 Key(对象成员)
 	 *
 	 * - bit5-6 : Key 长度字段字节数
-	 *            00=1字节 (≤255)
-	 *            01=2字节 (≤65535)
-	 *            10=3字节 (≤16M)
+	 *            00=1字节 (≤UINT8_MAX)
+	 *            01=2字节 (≤UINT16_MAX)
+	 *            10=3字节 (≤UINT24_MAX)
 	 *            11=4字节 (≤UINT32_MAX)
 	 *
-	 * - bit7   : 保留位(未来可用于压缩标记、特殊类型等)
-	 */
-
-	/*
-	 * flag 后若节点包含 key / strValue,则跟随一个指针,
-	 * 指向存储区:[ keyLen | key | stringValue ]
-	 * 其中 keyLen 的大小由 flag 中的长度信息决定(最多 4 字节)。
-	 *
-	 * 在指针之后,根据节点类型存储具体数据:
-	 * - null / bool : 由 flag 表示
-	 * - string      : 由上述指针指向
-	 * - number      : 根据 flag 决定存储 int(4字节) 或 double(8字节)
-	 * - object      : 动态分配空间存储子节点,链表结构如下:
-	 *
-	 *   {
-	 *       "name": "RyanJson",
-	 *   next (
-	 *       "version": "xxx",
-	 *   next (
-	 *       "repository": "https://github.com/Ryan-CW-Code/RyanJson",
-	 *   next (
-	 *       "keywords": ["json", "streamlined", "parser"],
-	 *   next (
-	 *       "others": { ... }
-	 *   )))
-	 *   }
-	 */
-
-	/*
-	 * 设计特点:
-	 * - 一个 Json 节点最多 malloc 两次(一次节点本身,一次可选的 key/stringValue),
-	 *   对嵌入式系统非常友好,减少 malloc 头部开销, 尽可能的减少内存碎片。
+	 * - bit7   : 表示key / strValue 存储模式
+	 *            1:inline 模式, 0=ptr 模式
 	 *
-	 * - key 和 stringValue 必须通过指针管理:
-	 *   * 如果直接放在节点里,虽然只需一次 malloc,
-	 *     但修改场景会遇到替换/释放困难。
-	 *   * 用户可能传递的 Json 对象不是指针,无法直接替换节点,
-	 *     要求应用层传递指针会增加侵入性,不符合“应用层无需修改”的目标。
+	 * @brief 动态载荷存储区
+     * 目的:
+     * - 在保持 API 易用性和稳定性的同时,最大限度减少 malloc 调用次数。
+     * - 尤其在嵌入式平台,malloc 代价高昂:不仅有堆头部空间浪费,还会产生内存碎片。
+     * - 通过利用结构体内的对齐填充 (Padding) 和指针空间,形成一个灵活的缓冲区。
+     *
+     * 存储策略:
+     * 利用结构体内存对齐产生的 Padding(如 Flag 后的空隙)以及原本用于存储指针的空间,形成一个缓冲区
+     * 若节点包含 key / strValue,则可能有两种方案:
+     * 1. inline 模式 (小数据优化)
+     *    - 当 (KeyLen + Key + Value) 的总长度 ≤ 阈值时,直接存储在结构体内部。
+     *    - 阈值计算公式:
+     *        阈值 = Padding + sizeof(void*) + (malloc头部空间的一半),再向上对齐到字节边界。
+     *      举例:
+     *        - 内存对齐:4字节
+     *        - malloc头部空间:8字节
+     *        - 可用空间 = 3 (flag后padding) + 4 (指针空间) + 4 (malloc头部一半)
+     *        - 向上对齐后得到阈值12字节
+     *    - 存储布局:
+     *        [ KeyLen | Key | Value ]
+     *      起始地址即为 flag 之后,数据紧凑排列,无需额外 malloc。
+     *
+     * 2. ptr 模式 (大数据)
+     *    - 当数据长度 > 阈值时,结构体存储一个指针,指向独立的堆区。
+     *    - 存储布局:
+     *        [ KeyLen | *ptr ] -> (ptr指向) [ Key | Value ]
+     *    - KeyLen 的大小由 flag 中的长度字段决定 (最多 4 字节)。
+     *    - 这样保证大数据不会撑爆结构体,同时保持 API 一致性。
+
+     * 其他类型的存储:
+	 * - null / bool : 由 flag 位直接表示,无需额外空间。
+	 * - number      : 根据 flag 扩展位决定存储 int(4字节) 或 double(8字节)。
+	 * - object      : 动态分配空间存储子节点,采用链表结构。
+     *
+     * 设计考量:
+     * - malloc 在嵌入式平台的开销:
+     *    * RTT 最小内存管理算法中,malloc 头部约 12 字节(可以考虑tlsf算法头部空间仅4字节,内存碎片也控制的很好,适合物联网应用)。
+     *    * 一个 RyanJson 节点本身可能只有个位数字节,头部空间就让内存占用翻倍。
+     * - 因此:
+     *    * 小数据尽量 inline 存储,避免二次 malloc。
+     *    * 大数据 fallback 到 ptr 模式,保证灵活性。
+     * - 修改场景:
+     *    * 理想情况:节点结构体后面直接跟 key/strValue,修改时释放并重新申请节点。
+     *    * 但这样 changKey/changStrValue 接口改动太大,用户层需要修改指针,代价高。
+     *    * 实际策略:提供就地修改接口。
+     *        - 若新值长度 ≤ 原有 inline 缓冲区,直接覆盖。
+     *        - 若超过阈值,自动切换到 ptr 模式,用户层无需关心。
 	 *
-	 * - 因此采用指针方式,保证灵活性和低侵入性。
+     * 链表结构示例:
+     *   {
+     *       "name": "RyanJson",
+     *   next (
+     *       "version": "xxx",
+     *   next (
+     *       "repository": "https://github.com/Ryan-CW-Code/RyanJson",
+     *   next (
+     *       "keywords": [
+     *           "json",
+     *       next (
+     *           "streamlined",
+     *       next (
+     *           "parser"
+     *       ))
+     *       ],
+     *   next (
+     *       "others": { ... }
+     *   }
 	 */
 };
 
@@ -188,7 +225,7 @@ typedef struct RyanJsonNode *RyanJson_t;
 
 
 #### 内存占用测试
-*(20251222 linux平台,**不考虑malloc头部空间)**测试代码可在本项目根目录`RyanJsonExample`文件夹查看。新版本内存占用更低!*
+(20251222 **malloc头部空间8字节,内存对齐4字节**)测试代码可在本项目根目录`RyanJsonExample`文件夹查看。
 
 ```
 *****************************************************************************
@@ -196,27 +233,27 @@ typedef struct RyanJsonNode *RyanJson_t;
 *****************************************************************************
 
 --------------------------- 混合类型json数据测试 --------------------------
-json原始文本长度为 2265, 序列化后RyanJson内存占用: 3613, cJSON内存占用: 9160, yyjson内存占用: 8692
-比cJSON节省: 60.56% 内存占用, 比yyjson节省: 58.43% 内存占用
+json原始文本长度为 2265, 序列化后RyanJson内存占用: 4912, cJSON内存占用: 11336, yyjson内存占用: 8784
+比cJSON节省: 56.67% 内存占用, 比yyjson节省: 44.08% 内存占用
 
---------------------------- 对象占多json数据测试 --------------------------
-json原始文本长度为 3991, 序列化后RyanJson内存占用: 5436, cJSON内存占用: 11633, yyjson内存占用: 12640
-比cJSON节省: 53.27% 内存占用, 比yyjson节省: 56.99% 内存占用
+--------------------------- 全是对象json数据测试 --------------------------
+json原始文本长度为 3991, 序列化后RyanJson内存占用: 7944, cJSON内存占用: 16020, yyjson内存占用: 12884
+比cJSON节省: 50.41% 内存占用, 比yyjson节省: 38.34% 内存占用
 
 --------------------------- 数组占多json数据测试 --------------------------
-json原始文本长度为 1205, 序列化后RyanJson内存占用: 2365, cJSON内存占用: 7340, yyjson内存占用: 5028
-比cJSON节省: 67.78% 内存占用, 比yyjson节省: 52.96% 内存占用
+json原始文本长度为 1205, 序列化后RyanJson内存占用: 3696, cJSON内存占用: 8680, yyjson内存占用: 5068
+比cJSON节省: 57.42% 内存占用, 比yyjson节省: 27.07% 内存占用
 
 --------------------------- 小对象json 混合类型内存占用测试 --------------------------
-json原始文本长度为 90, 序列化后RyanJson内存占用: 131, cJSON内存占用: 309, yyjson内存占用: 636
-比cJSON节省: 57.61% 内存占用, 比yyjson节省: 79.40% 内存占用
+json原始文本长度为 90, 序列化后RyanJson内存占用: 168, cJSON内存占用: 392, yyjson内存占用: 648
+比cJSON节省: 57.14% 内存占用, 比yyjson节省: 74.07% 内存占用
 
 --------------------------- 小对象json 纯字符串内存占用测试 --------------------------
-json原始文本长度为 100, 序列化后RyanJson内存占用: 144, cJSON内存占用: 339, yyjson内存占用: 636
-比cJSON节省: 57.52% 内存占用, 比yyjson节省: 77.36% 内存占用
+json原始文本长度为 100, 序列化后RyanJson内存占用: 216, cJSON内存占用: 472, yyjson内存占用: 648
+比cJSON节省: 54.24% 内存占用, 比yyjson节省: 66.67% 内存占用
 ```
 
-RT-Thread平台考虑malloc**头部空间12字节**情况下,嵌入式平台下占用最高的反而是malloc的内存头开销,所以建议用户优先选择malloc头部空间小的heap管理算法
+RT-Thread平台 **malloc头部空间12字节,内存对齐8字节**测试代码可在本项目根目录`RyanJsonExample`文件夹查看
 
 ```
 *****************************************************************************
@@ -224,24 +261,24 @@ RT-Thread平台考虑malloc**头部空间12字节**情况下,嵌入式平台
 *****************************************************************************
 
 --------------------------- 混合类型json数据测试 --------------------------
-json原始文本长度为 2265, 序列化后RyanJson内存占用: 7993, cJSON内存占用: 13732, yyjson内存占用: 8752
-比cJSON节省: 41.79% 内存占用, 比yyjson节省: 8.67% 内存占用
+json原始文本长度为 2265, 序列化后RyanJson内存占用: 5056, cJSON内存占用: 11336, yyjson内存占用: 8784
+比cJSON节省: 55.40% 内存占用, 比yyjson节省: 42.44% 内存占用
 
---------------------------- 对象占多json数据测试 --------------------------
-json原始文本长度为 3991, 序列化后RyanJson内存占用: 10668, cJSON内存占用: 19109, yyjson内存占用: 12712
-比cJSON节省: 44.17% 内存占用, 比yyjson节省: 16.08% 内存占用
+--------------------------- 全是对象json数据测试 --------------------------
+json原始文本长度为 3991, 序列化后RyanJson内存占用: 7832, cJSON内存占用: 16020, yyjson内存占用: 12884
+比cJSON节省: 51.11% 内存占用, 比yyjson节省: 39.21% 内存占用
 
 --------------------------- 数组占多json数据测试 --------------------------
-json原始文本长度为 1205, 序列化后RyanJson内存占用: 5449, cJSON内存占用: 10424, yyjson内存占用: 5076
-比cJSON节省: 47.73% 内存占用, 比yyjson节省: -7.35% 内存占用
+json原始文本长度为 1205, 序列化后RyanJson内存占用: 3840, cJSON内存占用: 8680, yyjson内存占用: 5068
+比cJSON节省: 55.76% 内存占用, 比yyjson节省: 24.23% 内存占用
 
 --------------------------- 小对象json 混合类型内存占用测试 --------------------------
-json原始文本长度为 90, 序列化后RyanJson内存占用: 287, cJSON内存占用: 477, yyjson内存占用: 672
-比cJSON节省: 39.83% 内存占用, 比yyjson节省: 57.29% 内存占用
+json原始文本长度为 90, 序列化后RyanJson内存占用: 172, cJSON内存占用: 392, yyjson内存占用: 648
+比cJSON节省: 56.12% 内存占用, 比yyjson节省: 73.46% 内存占用
 
 --------------------------- 小对象json 纯字符串内存占用测试 --------------------------
-json原始文本长度为 100, 序列化后RyanJson内存占用: 300, cJSON内存占用: 567, yyjson内存占用: 672
-比cJSON节省: 47.09% 内存占用, 比yyjson节省: 55.36% 内存占用
+json原始文本长度为 100, 序列化后RyanJson内存占用: 180, cJSON内存占用: 472, yyjson内存占用: 648
+比cJSON节省: 61.86% 内存占用, 比yyjson节省: 72.22% 内存占用
 ```
 
 

+ 193 - 96
RyanJson/RyanJson.c

@@ -2,7 +2,7 @@
 
 #ifdef isEnableFuzzer
 #undef RyanJsonNestingLimit
-#define RyanJsonNestingLimit 350
+#define RyanJsonNestingLimit 350U
 
 #undef RyanJsonSnprintf
 #include <stdarg.h>
@@ -34,41 +34,64 @@ static int32_t RyanJsonSnprintf(char *buf, size_t size, const char *fmt, ...)
 
 	va_list args;
 	va_start(args, fmt); // 每 500 次随机触发一次“失败”
-
 	int32_t ret = vsnprintf(buf, size, fmt, args);
-
 	va_end(args);
 	return ret;
 }
 #endif
 
+#ifndef RyanJsonMemmove
+static void *RyanJsonMemmove(void *dest, const void *src, uint32_t count)
+{
+	uint8_t *d = (uint8_t *)dest;
+	const uint8_t *s = (const uint8_t *)src;
+
+	if (d == s || count == 0) { return dest; }
+
+	// 目标在源之前 (dest < src) -> 安全
+	// 目标在源之后,但没有重叠 (dest >= src + n) -> 安全
+	// 这两种情况,标准 memcpy (从前向后拷) 都是安全的,且也是最快的!
+	if (d < s || d >= (s + count)) { return RyanJsonMemcpy(dest, src, count); }
+
+	// 目标在源之后,且发生重叠 (dest > src)
+	// 必须从后往前拷,防止覆盖。
+	d += count - 1;
+	s += count - 1;
+	while (count--) { *d-- = *s--; }
+	return dest;
+}
+#endif
+
 typedef struct
 {
+	const uint8_t *currentPtr; // 待解析字符串地址
 	uint32_t remainSize;       // 待解析字符串剩余长度
 	uint32_t depth;            // How deeply nested (in arrays/objects) is the input at the current offset.
-	const uint8_t *currentPtr; // 待解析字符串地址
 } RyanJsonParseBuffer;
 
 typedef struct
 {
-	RyanJsonBool_e isNoAlloc; // 是否动态申请内存
+	uint8_t *bufAddress;      // 反序列化后的字符串地址
 	uint32_t cursor;          // 解析到那个buf位置上了
 	uint32_t size;            // 待解析字符串剩余长度, 不动态申请内存时,到达此size大小将返回失败
-	uint8_t *bufAddress;      // 反序列化后的字符串地址
+	RyanJsonBool_e isNoAlloc; // 是否动态申请内存
 } RyanJsonPrintBuffer;
 
 // !这部分跟 struct RyanJsonNode 要保持一致
 typedef struct
 {
+	const char *key;
+	const char *strValue;
+
 	RyanjsonType_e type;
 	RyanJsonBool_e boolIsTrueFlag;
 	RyanJsonBool_e numberIsDoubleFlag;
-
-	const char *key;
-	const char *strValue;
 } RyanJsonNodeInfo_t;
 
-#define _checkType(info, type) ((info) == (type))
+#define RyanJsonFlagSize               sizeof(uint8_t)
+#define RyanJsonAlign(size, align)     (((size) + (align) - 1) & ~((align) - 1))
+#define RyanJsonAlignDown(size, align) ((size) & ~((align) - 1))
+#define _checkType(info, type)         ((info) == (type))
 
 /**
  * @brief printBuf相关宏
@@ -163,13 +186,25 @@ static RyanJsonBool_e RyanJsonPrintValue(RyanJson_t pJson, RyanJsonPrintBuffer *
 static RyanJson_t RyanJsonCreateObjectAndKey(const char *key);
 static RyanJson_t RyanJsonCreateArrayAndKey(const char *key);
 
+/**
+ * @brief 获取内联字符串的大小
+ * 用函数可读性更强一点,编译器会优化的
+ * @return uint32_t
+ */
+static uint32_t RyanJsonGetInlineStringSize(void)
+{
+	uint32_t baseSize = sizeof(void *) - RyanJsonFlagSize;     // flag的偏移字节量
+	baseSize += sizeof(void *) + RyanJsonMallocHeaderSize / 2; // 存储指针变量的字节量
+	return (uint32_t)(RyanJsonAlign(baseSize + RyanJsonFlagSize, RyanJsonMallocAlign) - RyanJsonFlagSize);
+}
+
 static uint8_t *RyanJsonGetHiddePrt(RyanJson_t pJson)
 {
 	RyanJsonCheckAssert(NULL != pJson);
 
 	// 用memcpy规避非对其警告
 	void *tmpPtr = NULL;
-	RyanJsonMemcpy((void *)&tmpPtr, (RyanJsonGetPayloadPtr(pJson) + RyanJsonAlign), sizeof(void *));
+	RyanJsonMemcpy((void *)&tmpPtr, (RyanJsonGetPayloadPtr(pJson) + RyanJsonFlagSize + sizeof(uint32_t)), sizeof(void *));
 	return (uint8_t *)tmpPtr;
 }
 static void RyanJsonSetHiddePrt(RyanJson_t pJson, uint8_t *hiddePrt)
@@ -179,7 +214,8 @@ static void RyanJsonSetHiddePrt(RyanJson_t pJson, uint8_t *hiddePrt)
 
 	// 用memcpy规避非对其警告
 	void *tmpPtr = hiddePrt;
-	RyanJsonMemcpy((RyanJsonGetPayloadPtr(pJson) + RyanJsonAlign), (const void *)&tmpPtr, sizeof(void *));
+	// uint8_t是flag,uint32_t是记录key的长度空间
+	RyanJsonMemcpy((RyanJsonGetPayloadPtr(pJson) + RyanJsonFlagSize + sizeof(uint32_t)), (const void *)&tmpPtr, sizeof(void *));
 }
 
 /**
@@ -198,7 +234,7 @@ static uint8_t *RyanJsonGetHiddenPtrAt(RyanJson_t pJson, uint32_t index)
 static void RyanJsonSetLenKey(RyanJson_t pJson, uint32_t value)
 {
 	RyanJsonCheckAssert(NULL != pJson);
-	uint8_t *buf = RyanJsonGetHiddenPtrAt(pJson, 0);
+	uint8_t *buf = RyanJsonGetPayloadPtr(pJson) + RyanJsonFlagSize;
 	uint8_t len = RyanJsonGetPayloadEncodeKeyLenByFlag(pJson);
 	RyanJsonCheckAssert(len <= 4);
 
@@ -208,7 +244,7 @@ static void RyanJsonSetLenKey(RyanJson_t pJson, uint32_t value)
 static uint32_t RyanJsonGetLenKey(RyanJson_t pJson)
 {
 	RyanJsonCheckAssert(NULL != pJson);
-	uint8_t *buf = RyanJsonGetHiddenPtrAt(pJson, 0);
+	uint8_t *buf = RyanJsonGetPayloadPtr(pJson) + RyanJsonFlagSize;
 	uint8_t len = RyanJsonGetPayloadEncodeKeyLenByFlag(pJson);
 	RyanJsonCheckAssert(len <= 4);
 
@@ -221,10 +257,10 @@ static void *RyanJsonGetValue(RyanJson_t pJson)
 {
 	RyanJsonCheckAssert(NULL != pJson);
 
-	uint32_t len = RyanJsonAlign;
+	uint32_t len = RyanJsonFlagSize;
 	if (RyanJsonIsKey(pJson) || RyanJsonIsString(pJson))
 	{
-		len += sizeof(void *);
+		len += RyanJsonGetInlineStringSize();
 		// jsonLog(" keyLen: %d, keyLenField: %d, \r\n", RyanJsonGetLenKey(pJson), RyanJsonGetPayloadEncodeKeyLenByFlag(pJson));
 	}
 
@@ -361,7 +397,7 @@ static RyanJsonBool_e RyanJsonChangeString(RyanJson_t pJson, RyanJsonBool_e isNe
 	{
 		keyLen = RyanJsonStrlen(key);
 		keyLenField = RyanJsonCalcLenBytes(keyLen);
-		mallocSize += keyLen + keyLenField + 1 + 1;
+		mallocSize += keyLen + 1;
 
 #ifdef isEnableFuzzer
 		{
@@ -380,18 +416,43 @@ static RyanJsonBool_e RyanJsonChangeString(RyanJson_t pJson, RyanJsonBool_e isNe
 	}
 	if (0 == mallocSize) { return RyanJsonTrue; }
 
-	// 申请新的空间
-	uint8_t *newPtr = (uint8_t *)jsonMalloc(mallocSize);
-	if (NULL == newPtr) { return RyanJsonFalse; }
-
 	// 释放旧的内存
 	uint8_t *oldPrt = NULL;
 	if (RyanJsonFalse == isNew)
 	{
-		RyanJsonCheckAssert(RyanJsonIsKey(pJson) || RyanJsonIsString(pJson));
-		oldPrt = RyanJsonGetHiddePrt(pJson);
+		if (RyanJsonTrue == RyanJsonGetPayloadStrIsPtrByFlag(pJson))
+		{
+			RyanJsonCheckAssert(RyanJsonIsKey(pJson) || RyanJsonIsString(pJson));
+			oldPrt = RyanJsonGetHiddePrt(pJson);
+		}
+	}
+
+	if ((mallocSize + keyLenField + 1) <= RyanJsonGetInlineStringSize()) { RyanJsonSetPayloadStrIsPtrByFlag(pJson, RyanJsonFalse); }
+	else
+	{
+		// 申请新的空间
+		uint8_t *newPtr = (uint8_t *)jsonMalloc(mallocSize);
+		if (NULL == newPtr) { return RyanJsonFalse; }
+
+		// 先赋值,因为 RyanJsonSetHiddePrt 可能会覆盖key和string的空间
+		if (NULL != key)
+		{
+			if (0 != keyLen) { RyanJsonMemcpy(newPtr, key, keyLen); }
+			newPtr[keyLen] = '\0';
+		}
+
+		if (NULL != strValue)
+		{
+			uint8_t *strValueBuf = newPtr;
+			if (NULL != key) { strValueBuf = newPtr + keyLen + 1; }
+
+			if (0 != strValueLen) { RyanJsonMemcpy(strValueBuf, strValue, strValueLen); }
+			strValueBuf[strValueLen] = '\0';
+		}
+
+		RyanJsonSetHiddePrt(pJson, newPtr);
+		RyanJsonSetPayloadStrIsPtrByFlag(pJson, RyanJsonTrue);
 	}
-	RyanJsonSetHiddePrt(pJson, newPtr);
 
 	// 设置key
 	if (NULL != key)
@@ -401,8 +462,13 @@ static RyanJsonBool_e RyanJsonChangeString(RyanJson_t pJson, RyanJsonBool_e isNe
 		RyanJsonSetLenKey(pJson, keyLen);
 
 		jsonLog(" keyLen: %d, keyLenField: %d, \r\n", RyanJsonGetLenKey(pJson), RyanJsonGetPayloadEncodeKeyLenByFlag(pJson));
-		if (0 != keyLen) { RyanJsonMemcpy(RyanJsonGetKey(pJson), key, keyLen); }
-		RyanJsonGetKey(pJson)[keyLen] = '\0';
+
+		if (RyanJsonFalse == RyanJsonGetPayloadStrIsPtrByFlag(pJson))
+		{
+			char *keyBuf = RyanJsonGetKey(pJson);
+			if (0 != keyLen) { RyanJsonMemmove(keyBuf, key, keyLen); }
+			keyBuf[keyLen] = '\0';
+		}
 	}
 	else
 	{
@@ -414,8 +480,12 @@ static RyanJsonBool_e RyanJsonChangeString(RyanJson_t pJson, RyanJsonBool_e isNe
 	if (NULL != strValue)
 	{
 		jsonLog("stLen: %d, strValue: %s \r\n", strValueLen, strValue);
-		if (0 != strValueLen) { RyanJsonMemcpy(RyanJsonGetStringValue(pJson), strValue, strValueLen); }
-		RyanJsonGetStringValue(pJson)[strValueLen] = '\0';
+		if (RyanJsonFalse == RyanJsonGetPayloadStrIsPtrByFlag(pJson))
+		{
+			char *strValueBuf = RyanJsonGetStringValue(pJson);
+			if (0 != strValueLen) { RyanJsonMemmove(strValueBuf, strValue, strValueLen); }
+			strValueBuf[strValueLen] = '\0';
+		}
 	}
 
 	if (oldPrt) { jsonFree(oldPrt); }
@@ -427,7 +497,7 @@ static RyanJson_t RyanJsonNewNode(RyanJsonNodeInfo_t *info)
 	RyanJsonCheckAssert(NULL != info);
 
 	// 加1是flag的空间
-	uint32_t size = sizeof(struct RyanJsonNode) + RyanJsonAlign;
+	uint32_t size = sizeof(struct RyanJsonNode) + RyanJsonFlagSize;
 
 	if (_checkType(info->type, RyanJsonTypeNumber))
 	{
@@ -439,7 +509,7 @@ static RyanJson_t RyanJsonNewNode(RyanJsonNodeInfo_t *info)
 	}
 	else if (_checkType(info->type, RyanJsonTypeArray) || _checkType(info->type, RyanJsonTypeObject)) { size += sizeof(RyanJson_t); }
 
-	if (NULL != info->key || _checkType(info->type, RyanJsonTypeString)) { size += sizeof(void *); }
+	if (NULL != info->key || _checkType(info->type, RyanJsonTypeString)) { size += RyanJsonGetInlineStringSize(); }
 
 	RyanJson_t pJson = (RyanJson_t)jsonMalloc((size_t)size);
 	if (NULL != pJson)
@@ -490,7 +560,7 @@ static RyanJson_t RyanJsonCreateItem(const char *key, RyanJson_t item)
 	{
 		RyanJsonChangeObjectValue(newItem, RyanJsonGetObjectValue(item));
 
-		if (RyanJsonIsKey(item) || RyanJsonIsString(item)) { jsonFree(RyanJsonGetHiddePrt(item)); }
+		if (RyanJsonTrue == RyanJsonGetPayloadStrIsPtrByFlag(item)) { jsonFree(RyanJsonGetHiddePrt(item)); }
 		jsonFree(item);
 	}
 	else
@@ -522,15 +592,30 @@ RyanJsonBool_e RyanJsonInitHooks(RyanJsonMalloc_t userMalloc, RyanJsonFree_t use
 char *RyanJsonGetKey(RyanJson_t pJson)
 {
 	RyanJsonCheckReturnNull(NULL != pJson);
-	return (char *)RyanJsonGetHiddenPtrAt(pJson, RyanJsonGetPayloadEncodeKeyLenByFlag(pJson));
+	if (RyanJsonFalse == RyanJsonGetPayloadStrIsPtrByFlag(pJson))
+	{
+		uint8_t len = RyanJsonGetPayloadEncodeKeyLenByFlag(pJson);
+		RyanJsonCheckAssert(len <= 4);
+		return (char *)(RyanJsonGetPayloadPtr(pJson) + RyanJsonFlagSize + len);
+	}
+
+	return (char *)RyanJsonGetHiddenPtrAt(pJson, 0);
 }
 
 char *RyanJsonGetStringValue(RyanJson_t pJson)
 {
 	RyanJsonCheckReturnNull(NULL != pJson);
 
+	if (RyanJsonFalse == RyanJsonGetPayloadStrIsPtrByFlag(pJson))
+	{
+		uint32_t len = RyanJsonGetPayloadEncodeKeyLenByFlag(pJson);
+		RyanJsonCheckAssert(len <= 4);
+		if (RyanJsonIsKey(pJson)) { len += RyanJsonGetLenKey(pJson) + 1U; }
+		return (char *)(RyanJsonGetPayloadPtr(pJson) + RyanJsonFlagSize + len);
+	}
+
 	uint32_t len = 0;
-	if (RyanJsonIsKey(pJson)) { len = RyanJsonGetPayloadEncodeKeyLenByFlag(pJson) + RyanJsonGetLenKey(pJson) + 1U; }
+	if (RyanJsonIsKey(pJson)) { len = RyanJsonGetLenKey(pJson) + 1U; }
 
 	return (char *)RyanJsonGetHiddenPtrAt(pJson, len);
 }
@@ -583,7 +668,7 @@ void RyanJsonDelete(RyanJson_t pJson)
 			RyanJsonDelete(RyanJsonGetObjectValue(pJson)); // 递归删除子对象
 		}
 
-		if (RyanJsonIsKey(pJson) || RyanJsonIsString(pJson)) { jsonFree(RyanJsonGetHiddePrt(pJson)); }
+		if (RyanJsonTrue == RyanJsonGetPayloadStrIsPtrByFlag(pJson)) { jsonFree(RyanJsonGetHiddePrt(pJson)); }
 
 		jsonFree(pJson);
 
@@ -790,12 +875,12 @@ static RyanJsonBool_e RyanJsonParseStringBuffer(RyanJsonParseBuffer *parseBuf, c
 		if ('\\' != *parseBuf->currentPtr)
 		{
 			*outCurrentPtr++ = *parseBuf->currentPtr;
-			RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
+			RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
 			continue;
 		}
 
 		// 转义字符
-		RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
+		RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
 		switch (*parseBuf->currentPtr)
 		{
 
@@ -812,28 +897,28 @@ static RyanJsonBool_e RyanJsonParseStringBuffer(RyanJsonParseBuffer *parseBuf, c
 
 			// 获取 Unicode 字符
 			uint64_t codepoint = 0;
-			RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 4), { goto __error; });
+			RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 4), { goto error__; });
 			uint32_t first_code = 0;
-			RyanJsonCheckCode(RyanJsonTrue == RyanJsonParseHex(parseBuf->currentPtr - 3, &first_code), { goto __error; });
+			RyanJsonCheckCode(RyanJsonTrue == RyanJsonParseHex(parseBuf->currentPtr - 3, &first_code), { goto error__; });
 			// 检查是否有效
-			if (first_code >= 0xDC00 && first_code <= 0xDFFF) { goto __error; }
+			if (first_code >= 0xDC00 && first_code <= 0xDFFF) { goto error__; }
 
 			if (first_code >= 0xD800 && first_code <= 0xDBFF) // UTF16 代理对
 			{
-				if (!parseBufHasRemainAtIndex(parseBuf, 2)) { goto __error; }
+				if (!parseBufHasRemainAtIndex(parseBuf, 2)) { goto error__; }
 
 				if (parseBuf->currentPtr[1] != '\\' || parseBuf->currentPtr[2] != 'u')
 				{
-					goto __error; // 缺少代理的后半部分
+					goto error__; // 缺少代理的后半部分
 				}
 
-				RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 6), { goto __error; });
+				RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 6), { goto error__; });
 				uint32_t second_code = 0;
 				RyanJsonCheckCode(RyanJsonTrue == RyanJsonParseHex(parseBuf->currentPtr - 3, &second_code),
-						  { goto __error; });
+						  { goto error__; });
 				if (0 == first_code || second_code < 0xDC00 || second_code > 0xDFFF)
 				{
-					goto __error; // 无效的代理后半部分
+					goto error__; // 无效的代理后半部分
 				}
 
 				codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
@@ -871,7 +956,7 @@ static RyanJsonBool_e RyanJsonParseStringBuffer(RyanJsonParseBuffer *parseBuf, c
 			// 不太可能发生
 			// else
 			// {
-			// 	goto __error; // 无效的 unicode 代码点
+			// 	goto error__; // 无效的 unicode 代码点
 			// }
 
 			// encode as utf8
@@ -893,23 +978,23 @@ static RyanJsonBool_e RyanJsonParseStringBuffer(RyanJsonParseBuffer *parseBuf, c
 
 		default:
 			// *outCurrentPtr++ = *buf->currentPtr;
-			goto __error;
+			goto error__;
 		}
 
-		RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
+		RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
 	}
 	*outCurrentPtr = '\0';
 
 	// todo 不等于的话是不是应该报错?
 	if (parseBufHasRemain(parseBuf) && *parseBuf->currentPtr == '\"')
 	{
-		RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
+		RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
 	}
 
 	*buffer = (char *)outBuffer;
 	return RyanJsonTrue;
 
-__error:
+error__:
 	jsonFree(outBuffer);
 	*buffer = NULL;
 	return RyanJsonFalse;
@@ -956,25 +1041,25 @@ static RyanJsonBool_e RyanJsonParseArray(RyanJsonParseBuffer *parseBuf, char *ke
 	RyanJson_t newItem = RyanJsonCreateArrayAndKey(key);
 	RyanJsonCheckReturnFalse(NULL != newItem);
 
-	RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
-	RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto __error; });
+	RyanJson_t prev = NULL, item;
+	RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
+	RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto error__; });
 
 	// 空数组
-	RyanJsonCheckCode(parseBufHasRemain(parseBuf), { goto __error; });
-	if (*parseBuf->currentPtr == ']') { goto __next; }
+	RyanJsonCheckCode(parseBufHasRemain(parseBuf), { goto error__; });
+	if (*parseBuf->currentPtr == ']') { goto next__; }
 
-	RyanJson_t prev = NULL, item;
 	do
 	{
 		// 跳过 ','
 		if (NULL != prev)
 		{
-			RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
+			RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
 		}
 
-		RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto __error; });
+		RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto error__; });
 
-		if (RyanJsonFalse == RyanJsonParseValue(parseBuf, NULL, &item)) { goto __error; }
+		if (RyanJsonFalse == RyanJsonParseValue(parseBuf, NULL, &item)) { goto error__; }
 
 		RyanJsonCheckAssert(RyanJsonTrue == RyanJsonInsert(newItem, UINT32_MAX, item));
 
@@ -982,16 +1067,16 @@ static RyanJsonBool_e RyanJsonParseArray(RyanJsonParseBuffer *parseBuf, char *ke
 
 	} while (parseBufHasRemain(parseBuf) && *parseBuf->currentPtr == ',');
 
-	RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto __error; });
-	RyanJsonCheckCode(parseBufHasRemain(parseBuf) && *parseBuf->currentPtr == ']', { goto __error; });
+	RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto error__; });
+	RyanJsonCheckCode(parseBufHasRemain(parseBuf) && *parseBuf->currentPtr == ']', { goto error__; });
 
-__next:
-	RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
+next__:
+	RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
 	*out = newItem;
 
 	return RyanJsonTrue;
 
-__error:
+error__:
 	RyanJsonDelete(newItem);
 	*out = NULL;
 	return RyanJsonFalse;
@@ -1013,32 +1098,33 @@ static RyanJsonBool_e RyanJsonParseObject(RyanJsonParseBuffer *parseBuf, char *k
 	RyanJson_t newItem = RyanJsonCreateObjectAndKey(key);
 	RyanJsonCheckReturnFalse(NULL != newItem);
 
-	RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
-	RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto __error; });
-
-	RyanJsonCheckCode(parseBufHasRemain(parseBuf), { goto __error; });
-	if (*parseBuf->currentPtr == '}') { goto __next; }
 	RyanJson_t prev = NULL, item;
+	RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
+	RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto error__; });
+
+	RyanJsonCheckCode(parseBufHasRemain(parseBuf), { goto error__; });
+	if (*parseBuf->currentPtr == '}') { goto next__; }
+
 	do
 	{
 		if (NULL != prev)
 		{
-			RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; }); // 跳过 ','
+			RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; }); // 跳过 ','
 		}
 
-		RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto __error; });
+		RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto error__; });
 
-		if (RyanJsonFalse == RyanJsonParseStringBuffer(parseBuf, &objKey)) { goto __error; }
+		if (RyanJsonFalse == RyanJsonParseStringBuffer(parseBuf, &objKey)) { goto error__; }
 
-		RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto __error; });
+		RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto error__; });
 
 		// 解析指示符 ':'
-		RyanJsonCheckCode(parseBufHasRemain(parseBuf) && ':' == *parseBuf->currentPtr, { goto __error; });
+		RyanJsonCheckCode(parseBufHasRemain(parseBuf) && ':' == *parseBuf->currentPtr, { goto error__; });
 
-		RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
-		RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto __error; });
+		RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
+		RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto error__; });
 
-		if (RyanJsonFalse == RyanJsonParseValue(parseBuf, objKey, &item)) { goto __error; }
+		if (RyanJsonFalse == RyanJsonParseValue(parseBuf, objKey, &item)) { goto error__; }
 		if (objKey)
 		{
 			jsonFree(objKey);
@@ -1051,18 +1137,18 @@ static RyanJsonBool_e RyanJsonParseObject(RyanJsonParseBuffer *parseBuf, char *k
 
 	} while (parseBufHasRemain(parseBuf) && *parseBuf->currentPtr == ',');
 
-	RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto __error; });
+	RyanJsonCheckCode(RyanJsonTrue == parseBufSkipWhitespace(parseBuf), { goto error__; });
 	RyanJsonCheckCode(parseBufHasRemain(parseBuf) && *parseBuf->currentPtr == '}', {
 		objKey = NULL; // 由上层进行删除
-		goto __error;
+		goto error__;
 	});
 
-__next:
-	RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto __error; });
+next__:
+	RyanJsonCheckCode(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1), { goto error__; });
 	*out = newItem;
 	return RyanJsonTrue;
 
-__error:
+error__:
 	if (objKey) { jsonFree(objKey); }
 	RyanJsonDelete(newItem);
 	*out = NULL;
@@ -1776,19 +1862,20 @@ RyanJsonBool_e RyanJsonDeleteByKey(RyanJson_t pJson, const char *key)
  */
 RyanJsonBool_e RyanJsonInsert(RyanJson_t pJson, uint32_t index, RyanJson_t item)
 {
+	RyanJson_t nextItem = NULL;
+	RyanJson_t prev = NULL;
+
 	RyanJsonCheckReturnFalse(NULL != item);
-	RyanJsonCheckCode(NULL != pJson, { goto __exit; });
+	RyanJsonCheckCode(NULL != pJson, { goto error__; });
 
 	RyanJsonCheckCode(_checkType(RyanJsonGetType(pJson), RyanJsonTypeArray) ||
 				  (_checkType(RyanJsonGetType(pJson), RyanJsonTypeObject) && RyanJsonIsKey(item)),
 			  {
-				  jsonLog("__error 不是正确类型 %d\r\n", index);
-				  goto __exit;
+				  jsonLog("error__ 不是正确类型 %d\r\n", index);
+				  goto error__;
 			  });
 
-	RyanJson_t nextItem = RyanJsonGetObjectValue(pJson);
-	RyanJson_t prev = NULL;
-
+	nextItem = RyanJsonGetObjectValue(pJson);
 	while (nextItem && index > 0)
 	{
 		prev = nextItem;
@@ -1807,7 +1894,7 @@ RyanJsonBool_e RyanJsonInsert(RyanJson_t pJson, uint32_t index, RyanJson_t item)
 
 	return RyanJsonTrue;
 
-__exit:
+error__:
 	RyanJsonDelete(item);
 	return RyanJsonFalse;
 }
@@ -2036,16 +2123,26 @@ RyanJsonBool_e RyanJsonIsKey(RyanJson_t pJson) { return RyanJsonMakeBool(NULL !=
 RyanJsonBool_e RyanJsonIsNull(RyanJson_t pJson) { return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeNull == RyanJsonGetType(pJson)); }
 RyanJsonBool_e RyanJsonIsBool(RyanJson_t pJson) { return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeBool == RyanJsonGetType(pJson)); }
 RyanJsonBool_e RyanJsonIsNumber(RyanJson_t pJson)
-{ return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeNumber == RyanJsonGetType(pJson)); }
+{
+	return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeNumber == RyanJsonGetType(pJson));
+}
 RyanJsonBool_e RyanJsonIsString(RyanJson_t pJson)
-{ return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeString == RyanJsonGetType(pJson)); }
+{
+	return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeString == RyanJsonGetType(pJson));
+}
 RyanJsonBool_e RyanJsonIsArray(RyanJson_t pJson) { return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeArray == RyanJsonGetType(pJson)); }
 RyanJsonBool_e RyanJsonIsObject(RyanJson_t pJson)
-{ return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeObject == RyanJsonGetType(pJson)); }
+{
+	return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeObject == RyanJsonGetType(pJson));
+}
 RyanJsonBool_e RyanJsonIsInt(RyanJson_t pJson)
-{ return RyanJsonMakeBool(RyanJsonIsNumber(pJson) && (RyanJsonFalse == RyanJsonGetPayloadNumberIsDoubleByFlag(pJson))); }
+{
+	return RyanJsonMakeBool(RyanJsonIsNumber(pJson) && (RyanJsonFalse == RyanJsonGetPayloadNumberIsDoubleByFlag(pJson)));
+}
 RyanJsonBool_e RyanJsonIsDouble(RyanJson_t pJson)
-{ return RyanJsonMakeBool(RyanJsonIsNumber(pJson) && (RyanJsonTrue == RyanJsonGetPayloadNumberIsDoubleByFlag(pJson))); }
+{
+	return RyanJsonMakeBool(RyanJsonIsNumber(pJson) && (RyanJsonTrue == RyanJsonGetPayloadNumberIsDoubleByFlag(pJson)));
+}
 
 /**
  * @brief 深拷贝一份json对象
@@ -2084,14 +2181,14 @@ RyanJson_t RyanJsonDuplicate(RyanJson_t pJson)
 			newItem = RyanJsonCreateObjectAndKey(key);
 		}
 
-		RyanJsonCheckCode(NULL != newItem, { goto err; });
+		RyanJsonCheckCode(NULL != newItem, { goto error__; });
 
 		RyanJson_t item, prev = NULL;
 		RyanJson_t temp = RyanJsonGetObjectValue(pJson);
 		while (temp)
 		{
 			item = RyanJsonDuplicate(temp);
-			RyanJsonCheckCode(NULL != item, { goto err; });
+			RyanJsonCheckCode(NULL != item, { goto error__; });
 
 			// RyanJsonCheckAssert(RyanJsonTrue == RyanJsonInsert(newItem, UINT32_MAX, item));
 
@@ -2111,12 +2208,12 @@ RyanJson_t RyanJsonDuplicate(RyanJson_t pJson)
 		break;
 	}
 
-	default: goto err;
+	default: goto error__;
 	}
 
 	return newItem;
 
-err:
+error__:
 	RyanJsonDelete(newItem);
 	return NULL;
 }

+ 92 - 49
RyanJson/RyanJson.h

@@ -1,5 +1,5 @@
-#ifndef __RyanJson__
-#define __RyanJson__
+#ifndef RyanJson
+#define RyanJson
 
 #ifdef __cplusplus
 extern "C" {
@@ -35,13 +35,20 @@ struct RyanJsonNode
 {
 	struct RyanJsonNode *next; // 单链表节点指针
 
-	/*
-	 * 在 next 后紧跟一个字节的 flag,用于描述节点的核心信息:
+	/**
+	 * @brief RyanJson 节点结构体
+	 * 每个节点由链表连接,包含元数据标识 (Flag) 与动态载荷存储区。
 	 *
-	 * 位分布如下:
+	 * 内存布局:
+	 * [ next指针 | flag(1字节) | padding/指针空间 | 动态载荷区 ]
+	 *
+	 * @brief 节点元数据标识 (Flag)
+	 * 紧跟 next 指针后,利用 1 字节位域描述节点类型及存储状态。
+	 *
+	 * flag 位分布定义:
 	 * bit7   bit6   bit5   bit4   bit3   bit2   bit1   bit0
 	 * -----------------------------------------------------
-	 * 保留   KeyLen KeyLen HasKey NumExt Type2 Type1 Type0
+	 * strMode KeyLen KeyLen HasKey NumExt Type2  Type1  Type0
 	 *
 	 * 各位含义:
 	 * - bit0-2 : 节点类型
@@ -50,58 +57,88 @@ struct RyanJsonNode
 	 *
 	 * - bit3   : 扩展位
 	 *            Bool 类型:0=false, 1=true
-	 *            Number 类型:0=int, 1=double
+	 *            Number 类型:0=int(4字节), 1=double(8字节)
 	 *
 	 * - bit4   : 是否包含 Key
 	 *            0=无 Key(数组元素)
 	 *            1=有 Key(对象成员)
 	 *
 	 * - bit5-6 : Key 长度字段字节数
-	 *            00=1字节 (≤255)
-	 *            01=2字节 (≤65535)
-	 *            10=3字节 (≤16M)
+	 *            00=1字节 (≤UINT8_MAX)
+	 *            01=2字节 (≤UINT16_MAX)
+	 *            10=3字节 (≤UINT24_MAX)
 	 *            11=4字节 (≤UINT32_MAX)
 	 *
-	 * - bit7   : 保留位(未来可用于压缩标记、特殊类型等)
-	 */
-
-	/*
-	 * flag 后若节点包含 key / strValue,则跟随一个指针,
-	 * 指向存储区:[ keyLen | key | stringValue ]
-	 * 其中 keyLen 的大小由 flag 中的长度信息决定(最多 4 字节)。
+	 * - bit7   : 表示key / strValue 存储模式
+	 *            1:inline 模式, 0=ptr 模式
 	 *
-	 * 在指针之后,根据节点类型存储具体数据:
-	 * - null / bool : 由 flag 表示
-	 * - string      : 由上述指针指向
-	 * - number      : 根据 flag 决定存储 int(4字节) 或 double(8字节)
-	 * - object      : 动态分配空间存储子节点,链表结构如下:
+	 * @brief 动态载荷存储区
+     * 目的:
+     * - 在保持 API 易用性和稳定性的同时,最大限度减少 malloc 调用次数。
+     * - 尤其在嵌入式平台,malloc 代价高昂:不仅有堆头部空间浪费,还会产生内存碎片。
+     * - 通过利用结构体内的对齐填充 (Padding) 和指针空间,形成一个灵活的缓冲区。
+     *
+     * 存储策略:
+     * 利用结构体内存对齐产生的 Padding(如 Flag 后的空隙)以及原本用于存储指针的空间,形成一个缓冲区
+     * 若节点包含 key / strValue,则可能有两种方案:
+     * 1. inline 模式 (小数据优化)
+     *    - 当 (KeyLen + Key + Value) 的总长度 ≤ 阈值时,直接存储在结构体内部。
+     *    - 阈值计算公式:
+     *        阈值 = Padding + sizeof(void*) + (malloc头部空间的一半),再向上对齐到字节边界。
+     *      举例:
+     *        - 内存对齐:4字节
+     *        - malloc头部空间:8字节
+     *        - 可用空间 = 3 (flag后padding) + 4 (指针空间) + 4 (malloc头部一半)
+     *        - 向上对齐后得到阈值12字节
+     *    - 存储布局:
+     *        [ KeyLen | Key | Value ]
+     *      起始地址即为 flag 之后,数据紧凑排列,无需额外 malloc。
+     *
+     * 2. ptr 模式 (大数据)
+     *    - 当数据长度 > 阈值时,结构体存储一个指针,指向独立的堆区。
+     *    - 存储布局:
+     *        [ KeyLen | *ptr ] -> (ptr指向) [ Key | Value ]
+     *    - KeyLen 的大小由 flag 中的长度字段决定 (最多 4 字节)。
+     *    - 这样保证大数据不会撑爆结构体,同时保持 API 一致性。
+
+     * 其他类型的存储:
+	 * - null / bool : 由 flag 位直接表示,无需额外空间。
+	 * - number      : 根据 flag 扩展位决定存储 int(4字节) 或 double(8字节)。
+	 * - object      : 动态分配空间存储子节点,采用链表结构。
+     *
+     * 设计考量:
+     * - malloc 在嵌入式平台的开销:
+     *    * RTT 最小内存管理算法中,malloc 头部约 12 字节(可以考虑tlsf算法头部空间仅4字节,内存碎片也控制的很好,适合物联网应用)。
+     *    * 一个 RyanJson 节点本身可能只有个位数字节,头部空间就让内存占用翻倍。
+     * - 因此:
+     *    * 小数据尽量 inline 存储,避免二次 malloc。
+     *    * 大数据 fallback 到 ptr 模式,保证灵活性。
+     * - 修改场景:
+     *    * 理想情况:节点结构体后面直接跟 key/strValue,修改时释放并重新申请节点。
+     *    * 但这样 changKey/changStrValue 接口改动太大,用户层需要修改指针,代价高。
+     *    * 实际策略:提供就地修改接口。
+     *        - 若新值长度 ≤ 原有 inline 缓冲区,直接覆盖。
+     *        - 若超过阈值,自动切换到 ptr 模式,用户层无需关心。
 	 *
-	 *   {
-	 *       "name": "RyanJson",
-	 *   next (
-	 *       "version": "xxx",
-	 *   next (
-	 *       "repository": "https://github.com/Ryan-CW-Code/RyanJson",
-	 *   next (
-	 *       "keywords": ["json", "streamlined", "parser"],
-	 *   next (
-	 *       "others": { ... }
-	 *   )))
-	 *   }
-	 */
-
-	/*
-	 * 设计特点:
-	 * - 一个 Json 节点最多 malloc 两次(一次节点本身,一次可选的 key/stringValue),
-	 *   对嵌入式系统非常友好,减少 malloc 头部开销, 尽可能的减少内存碎片。
-	 *
-	 * - key 和 stringValue 必须通过指针管理:
-	 *   * 如果直接放在节点里,虽然只需一次 malloc,
-	 *     但修改场景会遇到替换/释放困难。
-	 *   * 用户可能传递的 Json 对象不是指针,无法直接替换节点,
-	 *     要求应用层传递指针会增加侵入性,不符合“应用层无需修改”的目标。
-	 *
-	 * - 因此采用指针方式,保证灵活性和低侵入性。
+     * 链表结构示例:
+     *   {
+     *       "name": "RyanJson",
+     *   next (
+     *       "version": "xxx",
+     *   next (
+     *       "repository": "https://github.com/Ryan-CW-Code/RyanJson",
+     *   next (
+     *       "keywords": [
+     *           "json",
+     *       next (
+     *           "streamlined",
+     *       next (
+     *           "parser"
+     *       ))
+     *       ],
+     *   next (
+     *       "others": { ... }
+     *   }
 	 */
 };
 
@@ -157,6 +194,10 @@ typedef void *(*RyanJsonRealloc_t)(void *block, size_t size);
 // flag空间不够的时候可以把这个字段弃用,用redis的listpack方法将key和keyLen一起表示,内存占用也挺好,但是复杂度高,有空间就保持现在这样
 #define RyanJsonGetPayloadEncodeKeyLenByFlag(pJson)        ((uint8_t)RyanJsonGetPayloadFlagField((pJson), 5, RyanJsonGetMask(2)) + 1)
 #define RyanJsonSetPayloadEncodeKeyLenByFlag(pJson, value) RyanJsonSetPayloadFlagField((pJson), 5, RyanJsonGetMask(2), (value))
+
+#define RyanJsonGetPayloadStrIsPtrByFlag(pJson)        RyanJsonGetPayloadFlagField((pJson), 7, RyanJsonGetMask(1))
+#define RyanJsonSetPayloadStrIsPtrByFlag(pJson, value) RyanJsonSetPayloadFlagField((pJson), 7, RyanJsonGetMask(1), (value))
+
 extern RyanJsonBool_e RyanJsonInsert(RyanJson_t pJson, uint32_t index, RyanJson_t item);
 /**
  * !!!上面的接口不推荐使用
@@ -166,7 +207,7 @@ extern RyanJsonBool_e RyanJsonInsert(RyanJson_t pJson, uint32_t index, RyanJson_
 /**
  * @brief json对象函数
  */
-extern RyanJsonBool_e RyanJsonInitHooks(RyanJsonMalloc_t _malloc, RyanJsonFree_t _free, RyanJsonRealloc_t _realloc);
+extern RyanJsonBool_e RyanJsonInitHooks(RyanJsonMalloc_t userMalloc, RyanJsonFree_t userFree, RyanJsonRealloc_t userRealloc);
 extern RyanJson_t RyanJsonParseOptions(const char *text, uint32_t size, RyanJsonBool_e requireNullTerminator,
 				       const char **parseEndPtr);                                             // 需用户释放内存
 #define RyanJsonParse(text) RyanJsonParseOptions((text), (uint32_t)RyanJsonStrlen(text), RyanJsonFalse, NULL) // 需用户释放内存
@@ -286,6 +327,8 @@ extern RyanJsonBool_e RyanJsonChangeIntValue(RyanJson_t pJson, int32_t number);
 extern RyanJsonBool_e RyanJsonChangeDoubleValue(RyanJson_t pJson, double number);
 #define RyanJsonChangeBoolValue(pJson, boolean) RyanJsonSetPayloadBoolValueByFlag(pJson, boolean)
 
+// #define RyanJsonChangeStringValue(pJson, strValue) {RyanJson_t* aaaasd = &pJson; RyanJsonChangeStringValue22(aaaasd, strValue);}
+
 // 这是change方法的补充,当需要修改value类型时,使用此函数
 // 请参考 changeJsonTest 示例,严格按照规则来使用
 /**

+ 28 - 13
RyanJson/RyanJsonConfig.h

@@ -1,5 +1,5 @@
-#ifndef __RyanJsonConfig__
-#define __RyanJsonConfig__
+#ifndef RyanJsonConfig
+#define RyanJsonConfig
 
 #ifdef __cplusplus
 extern "C" {
@@ -19,36 +19,45 @@ extern "C" {
 #include "rtthread.h"
 #define RyanJsonMemset             rt_memset
 #define RyanJsonMemcpy             rt_memcpy
+// rtt的memmove实现比较简单
+// 也可以注释掉这个宏,交给RyanJson内部实现的memmove,RyanJson内部会尽量的使用memcpy
+// #define RyanJsonMemmove            rt_memmove
 #define RyanJsonStrlen             rt_strlen
 #define RyanJsonStrcmp             rt_strcmp
 #define RyanJsonSnprintf           rt_snprintf
 #define RyanJsonPlatformAssert(EX) RT_ASSERT(EX)
+#define RyanJsonMallocHeaderSize   12U
+#define RyanJsonMallocAlign        (uint32_t)(RT_ALIGN_SIZE)
 #else
 #include <assert.h>
 #define RyanJsonMemset             memset
 #define RyanJsonMemcpy             memcpy
+#define RyanJsonMemmove            memmove
 #define RyanJsonStrlen             strlen
 #define RyanJsonStrcmp             strcmp
 #define RyanJsonSnprintf           snprintf
 #define RyanJsonPlatformAssert(EX) assert(EX)
+#define RyanJsonMallocHeaderSize   8U
+#define RyanJsonMallocAlign        4U
 #endif
 
 // 是否启用assert
 // #define RyanJsonEnableAssert
 
-// 是否支持未对齐访问,未定义时会根据平台选择,
-// 一般不用管,如果你明白你的需求就自己定义
-// true 表示支持未对齐访问
-// false 表示不支持未对齐访问
-#ifndef RyanJsonUnalignedAccessSupported
-#define RyanJsonUnalignedAccessSupported true
+#ifndef RyanJsonMallocAlign
+#define RyanJsonMallocAlign 8U
+#endif
+
+//
+#ifndef RyanJsonMallocHeaderSize
+#define RyanJsonMallocHeaderSize 8U
 #endif
 
 // 限制解析数组/对象中嵌套的深度
 // RyanJson使用递归 序列化/反序列化 json
 // 请根据单片机资源合理设置以防止堆栈溢出。
 #ifndef RyanJsonNestingLimit
-#define RyanJsonNestingLimit 3000
+#define RyanJsonNestingLimit 500U
 #endif
 
 // 当 RyanJsonPrint 剩余缓冲空间不足时申请的空间大小
@@ -69,10 +78,16 @@ extern "C" {
 #define RyanJsonAssert(EX) (void)(EX)
 #endif
 
-#if true != RyanJsonUnalignedAccessSupported
-#define RyanJsonAlign sizeof(void *)
-#else
-#define RyanJsonAlign sizeof(uint8_t)
+/**
+ * @brief 检查宏是否合法
+ *
+ */
+#if RyanJsonMallocHeaderSize < 4
+#error "RyanJsonMallocHeaderSize 必须大于或等于4"
+#endif
+
+#if RyanJsonMallocAlign % 4 != 0
+#error "RyanJsonMallocAlign 必须是4的倍数"
 #endif
 
 #ifdef __cplusplus

+ 2 - 2
RyanJson/RyanJsonUtils.h

@@ -1,5 +1,5 @@
-#ifndef __RyanJsonUtils__
-#define __RyanJsonUtils__
+#ifndef RyanJsonUtils
+#define RyanJsonUtils
 
 #ifdef __cplusplus
 extern "C" {

+ 22 - 11
test/RyanJsonMemoryFootprintTest.c

@@ -1,13 +1,13 @@
 #include "RyanJsonTest.h"
 
-static void *yy_malloc(void *ctx, size_t size) { return v_malloc(size); }
-static void *yy_realloc(void *ctx, void *ptr, size_t old_size, size_t size) { return v_realloc(ptr, size); }
-static void yy_free(void *ctx, void *ptr) { v_free(ptr); }
+static void *yy_malloc(void *ctx, size_t size) { return v_malloc_tlsf(size); }
+static void *yy_realloc(void *ctx, void *ptr, size_t old_size, size_t size) { return v_realloc_tlsf(ptr, size); }
+static void yy_free(void *ctx, void *ptr) { v_free_tlsf(ptr); }
 
 static int RyanJsonMemoryFootprint(char *jsonstr)
 {
-	int32_t use = vallocGetUse();
-	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
+	int32_t use = vallocGetUseByTlsf();
+	RyanJsonInitHooks(v_malloc_tlsf, v_free_tlsf, v_realloc_tlsf);
 
 	RyanJson_t json = RyanJsonParse(jsonstr);
 	if (json == NULL)
@@ -16,7 +16,7 @@ static int RyanJsonMemoryFootprint(char *jsonstr)
 		return -1;
 	}
 
-	use = vallocGetUse() - use;
+	use = vallocGetUseByTlsf() - use;
 
 	RyanJsonDelete(json);
 	return use;
@@ -24,8 +24,8 @@ static int RyanJsonMemoryFootprint(char *jsonstr)
 
 static int cJSONMemoryFootprint(char *jsonstr)
 {
-	int32_t use = vallocGetUse();
-	cJSON_Hooks hooks = {.malloc_fn = v_malloc, .free_fn = v_free};
+	int32_t use = vallocGetUseByTlsf();
+	cJSON_Hooks hooks = {.malloc_fn = v_malloc_tlsf, .free_fn = v_free_tlsf};
 	cJSON_InitHooks(&hooks);
 
 	cJSON *json = cJSON_Parse(jsonstr);
@@ -35,7 +35,7 @@ static int cJSONMemoryFootprint(char *jsonstr)
 		return -1;
 	}
 
-	use = vallocGetUse() - use;
+	use = vallocGetUseByTlsf() - use;
 	cJSON_Delete(json);
 	return use;
 }
@@ -43,6 +43,8 @@ static int cJSONMemoryFootprint(char *jsonstr)
 static int yyjsonMemoryFootprint(char *jsonstr)
 {
 	static yyjson_alc yyalc = {yy_malloc, yy_realloc, yy_free, NULL};
+	int32_t use = vallocGetUseByTlsf();
+
 	// 先解析成只读文档(可用自定义分配器 yyalc)
 	yyjson_doc *doc = yyjson_read_opts(jsonstr, strlen(jsonstr), YYJSON_READ_NOFLAG, &yyalc, NULL);
 	if (doc == NULL) { return -1; }
@@ -53,8 +55,7 @@ static int yyjsonMemoryFootprint(char *jsonstr)
 	if (mdoc == NULL) { return -1; }
 
 	// 统计当前分配器的占用
-	int area = 0, use = 0;
-	v_mcheck(&area, &use);
+	use = vallocGetUseByTlsf() - use;
 
 	// 用完释放可变文档
 	yyjson_mut_doc_free(mdoc);
@@ -238,6 +239,16 @@ RyanJsonBool_e RyanJsonMemoryFootprintTest(void)
 		  "\"null\"}";
 	printfJsonCompera(jsonstr);
 
+	printf("\r\n--------------------------- 小对象json 纯字符串内存占用测试 --------------------------\r\n");
+	jsonstr = "{\"0\":\"0\",\"1\":\"189774523\",\"2\":{\"7\":\"3\",\"8\":\"103\",\"9\":\"37\",\"20\":\"0\",\"26\":\"37\",\"27\":"
+		  "\"367\",\"28\":\"367\",\"s\":\"0\",\"t\":\"0\",\"a\":\"24.98\",\"2a\":\"0\",\"1p\":\"23628\"},\"3\":\"0\",\"22\":"
+		  "\"epmgrow1105\",\"23\":\"0\",\"29\":\"0\",\"i\":\"4\",\"b\":\"900\",\"c\":\"1\",\"rsrp\":\"-111\",\"rsrq\":\"-4\","
+		  "\"sinr\":\"0\",\"soc\":\"AIR780EPM\",\"j\":\"0\",\"g\":\"898604021025D0152523\",\"h\":\"866965083262839\",\"d\":\"1.3.5."
+		  "00.20260104\",\"f\":\"0\",\"k\":\"1\",\"l\":\"20000\",\"m\":\"20000\",\"u\":\"0\",\"v\":\"0\",\"e\":\"1\",\"w\":\"0."
+		  "00\",\"n\":\"0\",\"2h\":\"0\",\"o\":\"30\",\"1v\":\"12000\",\"2c\":\"0\",\"p\":\"1\",\"q\":\"1\",\"x\":\"0\",\"y\":"
+		  "\"167\",\"r\":\"0\",\"1x\":\"0\",\"1w\":\"0\",\"1y\":\"100.00\",\"1u\":\"0\"}";
+	printfJsonCompera(jsonstr);
+
 	/**
 	 * @brief 反序列化为文本,内存占用没什么特别的优化点,和cjson实现思路差不多,内存占用也就差不多,就不进行对比了
 	 *

+ 4 - 8
test/RyanJsonRFC8259JsonTest.c

@@ -67,7 +67,7 @@ static int testFile(const char *path, jsonParseData jsonParseDataHandle)
 			int area = 0, use = 0;
 			v_mcheck(&area, &use);
 			printf("内存泄漏 %s len: %ld\r\n", data, len);
-            free(data);
+			free(data);
 			// printf("内存泄漏 %x len: %ld\r\n", (unsigned int)data, len);
 			// printf("内存泄漏 %c len: %ld\r\n", (int)data, len);
 			printf("|||----------->>> area = %d, size = %d\r\n", area, use);
@@ -445,8 +445,7 @@ static void checkadjfladjfl(char *data, uint32_t len, char *str, uint32_t strLen
 static int RyanJsonParseData(char *fileName, char *data, uint32_t len)
 {
 
-	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 ||
-	    strcmp(fileName, "n_structure_open_array_object.json") == 0 || strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
+	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 || strcmp(fileName, "n_structure_open_array_object.json") == 0)
 	{
 		return -1;
 	}
@@ -489,8 +488,7 @@ err:
 static int cJSONParseData(char *fileName, char *data, uint32_t len)
 {
 
-	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 ||
-	    strcmp(fileName, "n_structure_open_array_object.json") == 0 || strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
+	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 || strcmp(fileName, "n_structure_open_array_object.json") == 0)
 	{
 		return -1;
 	}
@@ -530,8 +528,7 @@ err:
  */
 static int yyjsonParseData(char *fileName, char *data, uint32_t len)
 {
-	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 ||
-	    strcmp(fileName, "n_structure_open_array_object.json") == 0 || strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
+	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 || strcmp(fileName, "n_structure_open_array_object.json") == 0)
 	{
 		return -1;
 	}
@@ -566,7 +563,6 @@ err:
 RyanJsonBool_e RFC8259JsonTest(void)
 {
 	int result = 0;
-	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
 
 	cJSON_Hooks hooks = {.malloc_fn = v_malloc, .free_fn = v_free};
 	cJSON_InitHooks(&hooks);

+ 75 - 17
test/RyanJsonTest.c

@@ -1,4 +1,10 @@
+#include "RyanJson.h"
 #include "RyanJsonTest.h"
+#include "tlsf.h"
+
+extern void printJsonDebug(RyanJson_t json);
+#define jsonLogByTest(fmt, ...) printf("%s:%d " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
+#define LV_MEM_SIZE             (1024 * 1024)
 
 static void printfTitle(char *title)
 {
@@ -9,42 +15,92 @@ static void printfTitle(char *title)
 	printf("*****************************************************************************\r\n");
 }
 
+static tlsf_t tlsfHandler;
+
+static int32_t total2 = LV_MEM_SIZE, used2 = 0, available = 0;
+bool tlsf_walker_callback(void *ptr, size_t size, int used, void *user)
+{
+	if (1 == used) { used2 += size + tlsf_alloc_overhead(); }
+	return true;
+}
+
+void showMemoryInfo(void)
+{
+	int32_t total = 0, used = 0, max_used = 0;
+	rt_memory_info22(tlsfHandler, &total, &used, &max_used);
+	jsonLogByTest("total: %d, used: %d, max_used: %d, available: %d\r\n", total, used, max_used, total - used);
+
+	used2 = 0, available = 0;
+	total2 = total;
+	tlsf_walk_pool(tlsf_get_pool(tlsfHandler), tlsf_walker_callback, NULL);
+	jsonLogByTest("total2: %d, used2: %d, max_used2: %d, available2: %d\r\n", total2, used2, 0, total2 - used2);
+}
+
+int32_t vallocGetUseByTlsf(void)
+{
+	int32_t total = 0, used = 0, max_used = 0;
+	rt_memory_info22(tlsfHandler, &total, &used, &max_used);
+	return used;
+}
+
+void *v_malloc_tlsf(size_t size)
+{
+	if (size == 0) { return NULL; }
+
+	return tlsf_malloc(tlsfHandler, size);
+}
+
+void v_free_tlsf(void *block)
+{
+	if (!block) { return; }
+
+	tlsf_free(tlsfHandler, block);
+}
+
+void *v_realloc_tlsf(void *block, size_t size) { return tlsf_realloc(tlsfHandler, block, size); }
+
 #ifndef isEnableFuzzer
-extern void printJsonDebug(RyanJson_t json);
 int main(void)
 {
+	char *tlsfMemBuf = v_malloc(LV_MEM_SIZE);
+	tlsfHandler = tlsf_create_with_pool((void *)tlsfMemBuf, LV_MEM_SIZE, LV_MEM_SIZE);
+	jsonLogByTest("tlsf_size: %d\r\n", tlsf_size(tlsfHandler));
 
 	RyanJsonBool_e result = RyanJsonFalse;
-	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
+	RyanJsonInitHooks(v_malloc_tlsf, v_free_tlsf, v_realloc_tlsf);
 
 	for (uint32_t i = 0; i < 1; i++)
 	{
-
 		char *str = NULL;
 		RyanJson_t jsonRoot, item;
 
+		// const char *jsonstr = "{\"emoji\":\"\\uD83D\\uDE00\"} ";
+		const char *jsonstr = "{\"name\":\"Mash\",\"star\":4,\"hits\":[2,2,1,3]}";
+		// const char *jsonstr = "{\"star\":4}";
+		// const char *jsonstr = "\"name\"";
 		// const char *jsonstr =
-		// 	"{\"emoji\":\"\\uD83D\\uDE00\"} ";
-		// const char *jsonstr = "{\"name\":\"Mash\",\"star\":4,\"hits\":[2,2,1,3]}";
-		const char *jsonstr = "[1";
+		// "{\"n\":0,\"q\":1,\"e\":1,\"p\":1,\"1u\":0,\"r\":0,\"w\":0.0,\"1w\":0,\"1x\":0,\"1y\":100.0,\"23\":0,"
+		// 		      "\"29\":0,\"2h\":0,\"o\":30,\"1v\":12000,\"2c\":0}";
 
 		// extern int LLVMFuzzerTestOneInput(const char *data, int32_t size);
 		// LLVMFuzzerTestOneInput(jsonstr, strlen(jsonstr));
 
 		// 解析json数据
-		// jsonRoot = RyanJsonParse(jsonstr);
-		// if (jsonRoot == NULL) { printf("%s:%d 序列化失败\r\n", __FILE__, __LINE__); }
-		// else
-		// {
-		// 	uint32_t len = 0;
-		// 	str = RyanJsonPrint(jsonRoot, 10, RyanJsonFalse, &len); // 以带格式方式将数据打印出来
-		// 	printf("strLen: %d, data: %s\r\n", len, str);
-
-		// 	RyanJsonFree(str);
-		// 	RyanJsonDelete(jsonRoot);
-		// }
+		jsonRoot = RyanJsonParse(jsonstr);
+		if (jsonRoot == NULL) { printf("%s:%d 序列化失败\r\n", __FILE__, __LINE__); }
+		else
+		{
+			uint32_t len = 0;
+			str = RyanJsonPrint(jsonRoot, 10, RyanJsonFalse, &len); // 以带格式方式将数据打印出来
+			printf("strLen: %d, data: %s\r\n", len, str);
+
+			RyanJsonFree(str);
+			RyanJsonDelete(jsonRoot);
+		}
 	}
 
+	showMemoryInfo();
+
 	RyanJsonExample();
 
 	result = RyanJsonBaseTest();
@@ -61,6 +117,8 @@ int main(void)
 	RyanJsonMemoryFootprintTest();
 	printf("\r\nok\r\n");
 
+	showMemoryInfo();
+	v_free(tlsfMemBuf);
 	displayMem();
 	return 0;
 }

+ 6 - 2
test/RyanJsonTest.h

@@ -1,5 +1,5 @@
-#ifndef __RyanJsonTest__
-#define __RyanJsonTest__
+#ifndef RyanJsonTest
+#define RyanJsonTest
 
 #ifdef __cplusplus
 extern "C" {
@@ -38,6 +38,10 @@ extern "C" {
 	} while (0)
 
 // 定义枚举类型
+extern void *v_malloc_tlsf(size_t size);
+extern void v_free_tlsf(void *block);
+extern void *v_realloc_tlsf(void *block, size_t size);
+extern int32_t vallocGetUseByTlsf(void);
 
 // 定义结构体类型
 

+ 0 - 1
test/baseTest/RyanJsonBaseTest.c

@@ -51,7 +51,6 @@ uint64_t platformUptimeMs(void)
 RyanJsonBool_e RyanJsonBaseTest(void)
 {
 	int32_t result = 0;
-	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
 
 	uint32_t testRunCount = 0;
 	uint64_t funcStartMs;

+ 17 - 33
test/fuzzer/RyanJsonFuzzer.c

@@ -4,18 +4,18 @@
 #define RyanJsonCheckGotoExit(EX)                                                                                                          \
 	RyanJsonCheckCode(EX, {                                                                                                            \
 		result = RyanJsonFalse;                                                                                                    \
-		goto __exit;                                                                                                               \
+		goto exit__;                                                                                                               \
 	})
 
-RyanJsonBool_e isEnableRandomMemFail = RyanJsonTrue;
+static RyanJsonBool_e isEnableRandomMemFail = RyanJsonTrue;
 
 static RyanJsonBool_e RyanJsonFuzzerTestByParseAndPrint(RyanJson_t pJson, const char *data, uint32_t size)
 {
 	RyanJsonAssert(NULL == RyanJsonPrint(NULL, 100, RyanJsonFalse, NULL));
 	RyanJsonAssert(NULL == RyanJsonPrintPreallocated(NULL, NULL, 100, RyanJsonFalse, NULL));
 	RyanJsonAssert(NULL == RyanJsonPrintPreallocated(pJson, NULL, 100, RyanJsonFalse, NULL));
-	RyanJsonAssert(NULL == RyanJsonPrintPreallocated(NULL, data, 100, RyanJsonFalse, NULL));
-	RyanJsonAssert(NULL == RyanJsonPrintPreallocated(pJson, data, 0, RyanJsonFalse, NULL));
+	RyanJsonAssert(NULL == RyanJsonPrintPreallocated(NULL, (char *)data, 100, RyanJsonFalse, NULL));
+	RyanJsonAssert(NULL == RyanJsonPrintPreallocated(pJson, (char *)data, 0, RyanJsonFalse, NULL));
 
 	uint32_t len = 0;
 	char *jsonStr =
@@ -25,8 +25,8 @@ static RyanJsonBool_e RyanJsonFuzzerTestByParseAndPrint(RyanJson_t pJson, const
 
 	uint32_t bufLen = len * 3;
 	if (bufLen < size * 2) { bufLen = size * 2; }
-	if (bufLen < 4096) { bufLen = 4096; }
-	char *buf = malloc((size_t)bufLen);
+	if (bufLen < 2048) { bufLen = 2048; }
+	char *buf = (char *)malloc((size_t)bufLen);
 	{
 		uint32_t len2 = 0;
 		char *jsonStr2 = RyanJsonPrintPreallocated(pJson, buf, bufLen, size % 2 ? RyanJsonFalse : RyanJsonTrue, &len2);
@@ -77,6 +77,7 @@ static RyanJsonBool_e RyanJsonFuzzerTestByDup(RyanJson_t pJson)
 
 	// 测试打印和复制功能
 	uint32_t len = 0;
+	uint32_t dupLen = 0;
 
 	jsonStr = RyanJsonPrint(pJson, 100, RyanJsonFalse, &len);
 	RyanJsonCheckGotoExit(NULL != jsonStr && len > 0);
@@ -107,7 +108,6 @@ static RyanJsonBool_e RyanJsonFuzzerTestByDup(RyanJson_t pJson)
 	RyanJsonCheckGotoExit(RyanJsonFalse == RyanJsonCompareOnlyKey(pJson, NULL));
 	RyanJsonCheckGotoExit(RyanJsonFalse == RyanJsonCompareOnlyKey(NULL, NULL));
 
-	uint32_t dupLen = 0;
 	jsonStrDup = RyanJsonPrint(pJsonDup, 100, RyanJsonFalse, &dupLen); // 以带格式方式将数据打印出来
 	RyanJsonCheckGotoExit(NULL != jsonStrDup && dupLen > 0);
 
@@ -159,7 +159,7 @@ static RyanJsonBool_e RyanJsonFuzzerTestByDup(RyanJson_t pJson)
 		RyanJsonCompare(pJson, pJsonDup);
 		RyanJsonCompareOnlyKey(pJson, pJsonDup);
 	}
-__exit:
+exit__:
 
 	if (jsonStr)
 	{
@@ -233,7 +233,9 @@ static RyanJsonBool_e RyanJsonFuzzerTestByForEachChange(RyanJson_t pJson, uint32
 	{
 		RyanJson_t item;
 		RyanJsonArrayForEach(pJson, item)
-		{ RyanJsonCheckReturnFalse(RyanJsonTrue == RyanJsonFuzzerTestByForEachChange(item, size)); }
+		{
+			RyanJsonCheckReturnFalse(RyanJsonTrue == RyanJsonFuzzerTestByForEachChange(item, size));
+		}
 	}
 
 	return RyanJsonTrue;
@@ -684,24 +686,6 @@ static void *RyanJsonFuzzerRealloc(void *block, size_t size)
 int LLVMFuzzerTestOneInput(const char *data, uint32_t size)
 {
 
-	// !检查分支覆盖率的时候要把这个取消掉,否则不知道是这个测试用例还是Fuzzer触发的,期望的是Fuzzer触发
-	{
-		// // 执行基础测试
-		// static bool isFirst = true;
-		// if (true == isFirst)
-		// {
-		// 	RyanJsonBool_e result = RyanJsonBaseTest();
-		// 	if (RyanJsonTrue != result)
-		// 	{
-		// 		printf("%s:%d RyanJsonTest fail\r\n", __FILE__, __LINE__);
-		// 		return -1;
-		// 	}
-
-		// 	RFC8259JsonTest();
-		// 	isFirst = false;
-		// }
-	}
-
 	// for (int i = 0; i < size; i++) { printf("%c", size, data[i]); }
 	// printf("\r\n");
 
@@ -727,7 +711,7 @@ int LLVMFuzzerTestOneInput(const char *data, uint32_t size)
 			isEnableRandomMemFail = RyanJsonTrue;
 			RyanJsonCheckCode(RyanJsonFuzzerTestByForEachDelete(pJson2, size), {
 				RyanJsonDelete(pJson2);
-				goto __exit;
+				goto exit__;
 			});
 			RyanJsonDelete(pJson2);
 		}
@@ -738,7 +722,7 @@ int LLVMFuzzerTestOneInput(const char *data, uint32_t size)
 			isEnableRandomMemFail = RyanJsonTrue;
 			RyanJsonCheckCode(RyanJsonFuzzerTestByForEachDetach(pJson2, size), {
 				RyanJsonDelete(pJson2);
-				goto __exit;
+				goto exit__;
 			});
 			RyanJsonDelete(pJson2);
 		}
@@ -748,16 +732,16 @@ int LLVMFuzzerTestOneInput(const char *data, uint32_t size)
 		RyanJsonFuzzerTestByForEachGet(pJson, size);
 
 		RyanJsonFuzzerTestByDup(pJson);
-		RyanJsonCheckCode(RyanJsonFuzzerTestByForEachChange(pJson, size), { goto __exit; });
-		RyanJsonCheckCode(RyanJsonFuzzerTestByForEachCreate(pJson, size), { goto __exit; });
-		RyanJsonCheckCode(RyanJsonFuzzerTestByForEachReplace(pJson, size), { goto __exit; });
+		RyanJsonCheckCode(RyanJsonFuzzerTestByForEachChange(pJson, size), { goto exit__; });
+		RyanJsonCheckCode(RyanJsonFuzzerTestByForEachCreate(pJson, size), { goto exit__; });
+		RyanJsonCheckCode(RyanJsonFuzzerTestByForEachReplace(pJson, size), { goto exit__; });
 
 		RyanJsonDelete(pJson);
 	}
 
 	return 0;
 
-__exit:
+exit__:
 	RyanJsonDelete(pJson);
 	return 0;
 }

+ 14 - 0
test/tlsf/rtthread.h

@@ -0,0 +1,14 @@
+#pragma once
+
+// !这个文件仅为了tlsf的测试
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <stddef.h>
+#include <assert.h>
+
+#define rt_memcpy        memcpy
+#define RT_ASSERT(EX)    assert(EX)
+#define rt_always_inline static inline __attribute__((always_inline))

+ 702 - 0
test/tlsf/tlsf.c

@@ -0,0 +1,702 @@
+/*
+ * SPDX-FileCopyrightText: 2006-2016 Matthew Conte
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include "tlsf.h"
+
+#undef printf
+#define printf(...)
+
+#include "tlsf_block_functions.h"
+#include "tlsf_control_functions.h"
+
+/*
+** Static assertion mechanism.
+*/
+
+#define _tlsf_glue2(x, y)       x##y
+#define _tlsf_glue(x, y)        _tlsf_glue2(x, y)
+#define tlsf_static_assert(exp) typedef char _tlsf_glue(static_assert, __LINE__)[(exp) ? 1 : -1]
+
+/* This code has been tested on 32- and 64-bit (LP/LLP) architectures. */
+tlsf_static_assert(sizeof(int) * CHAR_BIT == 32);
+tlsf_static_assert(sizeof(size_t) * CHAR_BIT >= 32);
+tlsf_static_assert(sizeof(size_t) * CHAR_BIT <= 64);
+
+/* Clear structure and point all empty lists at the null block. */
+static control_t *control_construct(control_t *control, size_t bytes)
+{
+	// check that the requested size can at least hold the control_t. This will allow us
+	// to fill in the field of control_t necessary to determine the final size of
+	// the metadata overhead and check that the requested size can hold
+	// this data and at least a block of minimum size
+	if (bytes < sizeof(control_t)) { return NULL; }
+
+	/* Find the closest power of two for first layer */
+	control->fl_index_max = 32 - __builtin_clz(bytes);
+
+	/* Adapt second layer to the pool */
+	if (bytes <= 64 * 1024) { control->sl_index_count_log2 = 3; }
+	else if (bytes <= 256 * 1024) { control->sl_index_count_log2 = 4; }
+	else
+	{
+		control->sl_index_count_log2 = 5;
+	}
+
+	control->fl_index_shift = (control->sl_index_count_log2 + ALIGN_SIZE_LOG2);
+	control->sl_index_count = 1 << control->sl_index_count_log2;
+	control->fl_index_count = control->fl_index_max - control->fl_index_shift + 1;
+	control->small_block_size = 1 << control->fl_index_shift;
+
+	// the total size fo the metadata overhead is the size of the control_t
+	// added to the size of the sl_bitmaps and the size of blocks
+	control->size = sizeof(control_t) + (sizeof(*control->sl_bitmap) * control->fl_index_count) +
+			(sizeof(*control->blocks) * (control->fl_index_count * control->sl_index_count));
+
+	// check that the requested size can hold the whole control structure and
+	// a small block at least
+	if (bytes < control->size + block_size_min) { return NULL; }
+
+	control->block_null.next_free = &control->block_null;
+	control->block_null.prev_free = &control->block_null;
+
+	control->fl_bitmap = 0;
+	control->sl_bitmap = align_ptr(control + 1, sizeof(*control->sl_bitmap));
+	control->blocks = align_ptr(control->sl_bitmap + control->fl_index_count, sizeof(*control->blocks));
+
+	/* SL_INDEX_COUNT must be <= number of bits in sl_bitmap's storage type. */
+	tlsf_assert(sizeof(unsigned int) * CHAR_BIT >= control->sl_index_count && "CHAR_BIT less than sl_index_count");
+
+	/* Ensure we've properly tuned our sizes. */
+	tlsf_assert(ALIGN_SIZE == control->small_block_size / control->sl_index_count); // ALIGN_SIZE does not match");
+
+	for (int i = 0; i < control->fl_index_count; ++i)
+	{
+		control->sl_bitmap[i] = 0;
+		for (int j = 0; j < control->sl_index_count; ++j)
+		{
+			control->blocks[i * control->sl_index_count + j] = &control->block_null;
+		}
+	}
+
+	return control;
+}
+
+/*
+** Debugging utilities.
+*/
+
+typedef struct integrity_t
+{
+	int prev_status;
+	int status;
+} integrity_t;
+
+#define tlsf_insist(x)                                                                                                                     \
+	{                                                                                                                                  \
+		if (!(x)) { status--; }                                                                                                    \
+	}
+
+static bool integrity_walker(void *ptr, size_t size, int used, void *user)
+{
+	block_header_t *block = block_from_ptr(ptr);
+	integrity_t *integ = tlsf_cast(integrity_t *, user);
+	const int this_prev_status = block_is_prev_free(block) ? 1 : 0;
+	const int this_status = block_is_free(block) ? 1 : 0;
+	const size_t this_block_size = block_size(block);
+
+	int status = 0;
+	tlsf_insist(integ->prev_status == this_prev_status && "prev status incorrect");
+	tlsf_insist(size == this_block_size && "block size incorrect");
+
+	if (tlsf_check_hook != NULL)
+	{
+		/* block_size(block) returns the size of the usable memory when the block is allocated.
+		 * As the block under test is free, we need to subtract to the block size the next_free
+		 * and prev_free fields of the block header as they are not a part of the usable memory
+		 * when the block is free. In addition, we also need to subtract the size of prev_phys_block
+		 * as this field is in fact part of the current free block and not part of the next (allocated)
+		 * block. Check the comments in block_split function for more details.
+		 */
+		const size_t actual_free_block_size =
+			used ? this_block_size : this_block_size - offsetof(block_header_t, next_free) - block_header_overhead;
+
+		void *ptr_block = used ? (void *)block + block_start_offset : (void *)block + sizeof(block_header_t);
+
+		tlsf_insist(tlsf_check_hook(ptr_block, actual_free_block_size, !used));
+	}
+
+	integ->prev_status = this_status;
+	integ->status += status;
+
+	return true;
+}
+
+int tlsf_check(tlsf_t tlsf)
+{
+	int i, j;
+
+	control_t *control = tlsf_cast(control_t *, tlsf);
+	int status = 0;
+
+	/* Check that the free lists and bitmaps are accurate. */
+	for (i = 0; i < control->fl_index_count; ++i)
+	{
+		for (j = 0; j < control->sl_index_count; ++j)
+		{
+			const int fl_map = control->fl_bitmap & (1U << i);
+			const int sl_list = control->sl_bitmap[i];
+			const int sl_map = sl_list & (1U << j);
+			const block_header_t *block = control->blocks[i * control->sl_index_count + j];
+
+			/* Check that first- and second-level lists agree. */
+			if (!fl_map) { tlsf_insist(!sl_map && "second-level map must be null"); }
+
+			if (!sl_map)
+			{
+				tlsf_insist(block == &control->block_null && "block list must be null");
+				continue;
+			}
+
+			/* Check that there is at least one free block. */
+			tlsf_insist(sl_list && "no free blocks in second-level map");
+			tlsf_insist(block != &control->block_null && "block should not be null");
+
+			while (block != &control->block_null)
+			{
+				int fli, sli;
+				const bool is_block_free = block_is_free(block);
+				tlsf_insist(is_block_free && "block should be free");
+				tlsf_insist(!block_is_prev_free(block) && "blocks should have coalesced");
+				tlsf_insist(!block_is_free(block_next(block)) && "blocks should have coalesced");
+				tlsf_insist(block_is_prev_free(block_next(block)) && "block should be free");
+				tlsf_insist(block_size(block) >= block_size_min && "block not minimum size");
+
+				mapping_insert(control, block_size(block), &fli, &sli);
+				tlsf_insist(fli == i && sli == j && "block size indexed in wrong list");
+
+				block = block->next_free;
+			}
+		}
+	}
+
+	return status;
+}
+
+#undef tlsf_insist
+
+static bool default_walker(void *ptr, size_t size, int used, void *user)
+{
+	(void)user;
+	printf("\t%p %s size: %x (%p)\n", ptr, used ? "used" : "free", (unsigned int)size, block_from_ptr(ptr));
+	return true;
+}
+
+void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void *user)
+{
+	tlsf_walker pool_walker = walker ? walker : default_walker;
+	block_header_t *block = offset_to_block(pool, -(int)block_header_overhead);
+
+	bool ret_val = true;
+	while (block && !block_is_last(block) && ret_val == true)
+	{
+		ret_val = pool_walker(block_to_ptr(block), block_size(block), !block_is_free(block), user);
+
+		if (ret_val == true) { block = block_next(block); }
+	}
+}
+
+size_t tlsf_block_size(void *ptr)
+{
+	size_t size = 0;
+	if (ptr)
+	{
+		const block_header_t *block = block_from_ptr(ptr);
+		size = block_size(block);
+	}
+	return size;
+}
+
+int tlsf_check_pool(pool_t pool)
+{
+	/* Check that the blocks are physically correct. */
+	integrity_t integ = {0, 0};
+	tlsf_walk_pool(pool, integrity_walker, &integ);
+
+	return integ.status;
+}
+
+size_t tlsf_fit_size(tlsf_t tlsf, size_t size)
+{
+	if (size == 0 || tlsf == NULL) { return 0; }
+
+	control_t *control = tlsf_cast(control_t *, tlsf);
+	if (size < control->small_block_size) { return adjust_request_size(tlsf, size, ALIGN_SIZE); }
+
+	/* because it's GoodFit, allocable size is one range lower */
+	size_t sl_interval;
+	sl_interval = (1 << (32 - __builtin_clz(size) - 1)) / control->sl_index_count;
+	return size & ~(sl_interval - 1);
+}
+
+/*
+** Size of the TLSF structures in a given memory block passed to
+** tlsf_create, equal to the size of a control_t
+*/
+size_t tlsf_size(tlsf_t tlsf)
+{
+	if (tlsf == NULL) { return 0; }
+	control_t *control = tlsf_cast(control_t *, tlsf);
+	return control->size;
+}
+
+/*
+** Overhead of the TLSF structures in a given memory block passed to
+** tlsf_add_pool, equal to the overhead of a free block and the
+** sentinel block.
+*/
+size_t tlsf_pool_overhead(void) { return 2 * block_header_overhead; }
+
+size_t tlsf_alloc_overhead(void) { return block_header_overhead; }
+
+pool_t tlsf_add_pool(tlsf_t tlsf, void *mem, size_t bytes)
+{
+	block_header_t *block;
+	block_header_t *next;
+
+	const size_t pool_overhead = tlsf_pool_overhead();
+	const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE);
+
+	if (((ptrdiff_t)mem % ALIGN_SIZE) != 0)
+	{
+		printf("tlsf_add_pool: Memory must be aligned by %u bytes.\n", (unsigned int)ALIGN_SIZE);
+		return 0;
+	}
+
+	if (pool_bytes < block_size_min || pool_bytes > tlsf_block_size_max(tlsf))
+	{
+#if defined(TLSF_64BIT)
+		printf("tlsf_add_pool: Memory size must be between 0x%x and 0x%x00 bytes.\n",
+		       (unsigned int)(pool_overhead + block_size_min), (unsigned int)((pool_overhead + tlsf_block_size_max(tlsf)) / 256));
+#else
+		printf("tlsf_add_pool: Memory size must be between %u and %u bytes.\n", (unsigned int)(pool_overhead + block_size_min),
+		       (unsigned int)(pool_overhead + tlsf_block_size_max(tlsf)));
+#endif
+		return 0;
+	}
+
+	/*
+	** Create the main free block. Offset the start of the block slightly
+	** so that the prev_phys_block field falls outside of the pool -
+	** it will never be used.
+	*/
+	block = offset_to_block(mem, -(tlsfptr_t)block_header_overhead);
+	block_set_size(block, pool_bytes);
+	block_set_free(block);
+	block_set_prev_used(block);
+	block_insert(tlsf_cast(control_t *, tlsf), block);
+
+	/* Split the block to create a zero-size sentinel block. */
+	next = block_link_next(block);
+	block_set_size(next, 0);
+	block_set_used(next);
+	block_set_prev_free(next);
+
+	return mem;
+}
+
+void tlsf_remove_pool(tlsf_t tlsf, pool_t pool)
+{
+	control_t *control = tlsf_cast(control_t *, tlsf);
+	block_header_t *block = offset_to_block(pool, -(int)block_header_overhead);
+
+	int fl = 0, sl = 0;
+
+	tlsf_assert(block_is_free(block) && "block should be free");
+	tlsf_assert(!block_is_free(block_next(block)) && "next block should not be free");
+	tlsf_assert(block_size(block_next(block)) == 0 && "next block size should be zero");
+
+	mapping_insert(control, block_size(block), &fl, &sl);
+	remove_free_block(control, block, fl, sl);
+}
+
+/*
+** TLSF main interface.
+*/
+
+#if _DEBUG
+int test_ffs_fls()
+{
+	/* Verify ffs/fls work properly. */
+	int rv = 0;
+	rv += (tlsf_ffs(0) == -1) ? 0 : 0x1;
+	rv += (tlsf_fls(0) == -1) ? 0 : 0x2;
+	rv += (tlsf_ffs(1) == 0) ? 0 : 0x4;
+	rv += (tlsf_fls(1) == 0) ? 0 : 0x8;
+	rv += (tlsf_ffs(0x80000000) == 31) ? 0 : 0x10;
+	rv += (tlsf_ffs(0x80008000) == 15) ? 0 : 0x20;
+	rv += (tlsf_fls(0x80000008) == 31) ? 0 : 0x40;
+	rv += (tlsf_fls(0x7FFFFFFF) == 30) ? 0 : 0x80;
+
+#if defined(TLSF_64BIT)
+	rv += (tlsf_fls_sizet(0x80000000) == 31) ? 0 : 0x100;
+	rv += (tlsf_fls_sizet(0x100000000) == 32) ? 0 : 0x200;
+	rv += (tlsf_fls_sizet(0xffffffffffffffff) == 63) ? 0 : 0x400;
+#endif
+
+	if (rv) { printf("test_ffs_fls: %x ffs/fls tests failed.\n", rv); }
+	return rv;
+}
+#endif
+
+tlsf_t tlsf_create(void *mem, size_t max_bytes)
+{
+#if _DEBUG
+	if (test_ffs_fls()) { return NULL; }
+#endif
+
+	if (mem == NULL) { return NULL; }
+
+	if (((tlsfptr_t)mem % ALIGN_SIZE) != 0)
+	{
+		printf("tlsf_create: Memory must be aligned to %u bytes.\n", (unsigned int)ALIGN_SIZE);
+		return NULL;
+	}
+
+	control_t *control_ptr = control_construct(tlsf_cast(control_t *, mem), max_bytes);
+	return tlsf_cast(tlsf_t, control_ptr);
+}
+
+tlsf_t tlsf_create_with_pool(void *mem, size_t pool_bytes, size_t max_bytes)
+{
+	tlsf_t tlsf = tlsf_create(mem, max_bytes ? max_bytes : pool_bytes);
+	if (tlsf != NULL)
+	{
+		tlsf_add_pool(tlsf, (char *)mem + tlsf_size(tlsf), pool_bytes - tlsf_size(tlsf));
+		control_t *control = tlsf_cast(control_t *, tlsf);
+		control->mem_rec.total = pool_bytes - tlsf_size(tlsf) - tlsf_pool_overhead();
+		control->mem_rec.used = 0;
+		control->mem_rec.max_used = 0;
+	}
+	return tlsf;
+}
+
+void tlsf_destroy(tlsf_t tlsf)
+{
+	/* Nothing to do. */
+	(void)tlsf;
+}
+
+pool_t tlsf_get_pool(tlsf_t tlsf) { return tlsf_cast(pool_t, (char *)tlsf + tlsf_size(tlsf)); }
+
+void *tlsf_malloc(tlsf_t tlsf, size_t size)
+{
+	control_t *control = tlsf_cast(control_t *, tlsf);
+	size_t adjust = adjust_request_size(tlsf, size, ALIGN_SIZE);
+	// Returned size is 0 when the requested size is larger than the max block
+	// size.
+	if (adjust == 0) { return NULL; }
+	// block_locate_free() may adjust our allocated size further.
+	block_header_t *block = block_locate_free(control, &adjust);
+	return block_prepare_used(control, block, adjust);
+}
+
+/**
+ * @brief Allocate memory of at least `size` bytes at a given address in the pool.
+ *
+ * @param tlsf TLSF structure to allocate memory from.
+ * @param size Minimum size, in bytes, of the memory to allocate
+ * @param address address at which the allocation must be done
+ *
+ * @return pointer to free memory or NULL in case of incapacity to perform the malloc
+ */
+void *tlsf_malloc_addr(tlsf_t tlsf, size_t size, void *address)
+{
+	control_t *control = tlsf_cast(control_t *, tlsf);
+
+	/* adjust the address to be ALIGN_SIZE bytes aligned. */
+	const uintptr_t addr_adjusted = align_down(tlsf_cast(uintptr_t, address), ALIGN_SIZE);
+
+	/* adjust the size to be ALIGN_SIZE bytes aligned. Add to the size the difference
+	 * between the requested address and the address_adjusted. */
+	size_t size_adjusted = align_up(size + (tlsf_cast(uintptr_t, address) - addr_adjusted), ALIGN_SIZE);
+
+	/* find the free block that starts before the address in the pool and is big enough
+	 * to support the size of allocation at the given address */
+	block_header_t *block = offset_to_block(tlsf_get_pool(tlsf), -(int)block_header_overhead);
+
+	const char *alloc_start = tlsf_cast(char *, addr_adjusted);
+	const char *alloc_end = alloc_start + size_adjusted;
+	bool block_found = false;
+	do
+	{
+		const char *block_start = tlsf_cast(char *, block_to_ptr(block));
+		const char *block_end = tlsf_cast(char *, block_to_ptr(block)) + block_size(block);
+		if (block_start <= alloc_start && block_end > alloc_start)
+		{
+			/* A: block_end >= alloc_end. B: block is free */
+			if (block_end < alloc_end || !block_is_free(block))
+			{
+				/* not(A) || not(B)
+				 * We won't find another suitable block from this point on
+				 * so we can break and return NULL */
+				break;
+			}
+			/* A && B
+			 * The block can fit the alloc and is located at a position allowing for the alloc
+			 * to be placed at the given address. We can return from the while */
+			block_found = true;
+		}
+		else if (!block_is_last(block))
+		{
+			/* the block doesn't match the expected criteria, continue with the next block */
+			block = block_next(block);
+		}
+
+	} while (!block_is_last(block) && block_found == false);
+
+	if (!block_found) { return NULL; }
+
+	/* remove block from the free list since a part of it will be used */
+	block_remove(control, block);
+
+	/* trim any leading space or add the leading space to the overall requested size
+	 * if the leading space is not big enough to store a block of minimum size */
+	const size_t space_before_addr_adjusted = addr_adjusted - tlsf_cast(uintptr_t, block_to_ptr(block));
+	block_header_t *return_block = block;
+	if (space_before_addr_adjusted >= block_size_min)
+	{
+		return_block = block_trim_free_leading(control, block, space_before_addr_adjusted);
+	}
+	else
+	{
+		size_adjusted += space_before_addr_adjusted;
+	}
+
+	/* trim trailing space if any and return a pointer to the first usable byte allocated */
+	return block_prepare_used(control, return_block, size_adjusted);
+}
+
+/**
+ * @brief Allocate memory of at least `size` bytes where byte at `data_offset` will be aligned to `alignment`.
+ *
+ * This function will allocate memory pointed by `ptr`. However, the byte at `data_offset` of
+ * this piece of memory (i.e., byte at `ptr` + `data_offset`) will be aligned to `alignment`.
+ * This function is useful for allocating memory that will internally have a header, and the
+ * usable memory following the header (i.e. `ptr` + `data_offset`) must be aligned.
+ *
+ * For example, a call to `multi_heap_aligned_alloc_impl_offs(heap, 64, 256, 20)` will return a
+ * pointer `ptr` to free memory of minimum 64 bytes, where `ptr + 20` is aligned on `256`.
+ * So `(ptr + 20) % 256` equals 0.
+ *
+ * @param tlsf TLSF structure to allocate memory from.
+ * @param align Alignment for the returned pointer's offset.
+ * @param size Minimum size, in bytes, of the memory to allocate INCLUDING
+ *             `data_offset` bytes.
+ * @param data_offset Offset to be aligned on `alignment`. This can be 0, in
+ *                    this case, the returned pointer will be aligned on
+ *                    `alignment`. If it is not a multiple of CPU word size,
+ *                    it will be aligned up to the closest multiple of it.
+ *
+ * @return pointer to free memory.
+ */
+void *tlsf_memalign_offs(tlsf_t tlsf, size_t align, size_t size, size_t data_offset)
+{
+	control_t *control = tlsf_cast(control_t *, tlsf);
+	const size_t adjust = adjust_request_size(tlsf, size, ALIGN_SIZE);
+	const size_t off_adjust = align_up(data_offset, ALIGN_SIZE);
+
+	/*
+	** We must allocate an additional minimum block size bytes so that if
+	** our free block will leave an alignment gap which is smaller, we can
+	** trim a leading free block and release it back to the pool. We must
+	** do this because the previous physical block is in use, therefore
+	** the prev_phys_block field is not valid, and we can't simply adjust
+	** the size of that block.
+	*/
+	const size_t gap_minimum = sizeof(block_header_t) + off_adjust;
+	/* The offset is included in both `adjust` and `gap_minimum`, so we
+	** need to subtract it once.
+	*/
+	const size_t size_with_gap = adjust_request_size(tlsf, adjust + align + gap_minimum - off_adjust, align);
+
+	/*
+	** If alignment is less than or equal to base alignment, we're done, because
+	** we are guaranteed that the size is at least sizeof(block_header_t), enough
+	** to store next blocks' metadata. Plus, all pointers allocated will all be
+	** aligned on a 4-byte bound, so ptr + data_offset will also have this
+	** alignment constraint. Thus, the gap is not required.
+	** If we requested 0 bytes, return null, as tlsf_malloc(0) does.
+	*/
+	size_t aligned_size = (adjust && align > ALIGN_SIZE) ? size_with_gap : adjust;
+
+	block_header_t *block = block_locate_free(control, &aligned_size);
+
+	/* This can't be a static assert. */
+	tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_overhead);
+
+	if (block)
+	{
+		void *ptr = block_to_ptr(block);
+		void *aligned = align_ptr(ptr, align);
+		size_t gap = tlsf_cast(size_t, tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr));
+
+		/*
+		 ** If gap size is too small or if there is no gap but we need one,
+		 ** offset to next aligned boundary.
+		 ** NOTE: No need for a gap if the alignment required is less than or is
+		 ** equal to ALIGN_SIZE.
+		 */
+		if ((gap && gap < gap_minimum) || (!gap && off_adjust && align > ALIGN_SIZE))
+		{
+			const size_t gap_remain = gap_minimum - gap;
+			const size_t offset = tlsf_max(gap_remain, align);
+			const void *next_aligned = tlsf_cast(void *, tlsf_cast(tlsfptr_t, aligned) + offset);
+
+			aligned = align_ptr(next_aligned, align);
+			gap = tlsf_cast(size_t, tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr));
+		}
+
+		if (gap)
+		{
+			tlsf_assert(gap >= gap_minimum && "gap size too small");
+			block = block_trim_free_leading(control, block, gap - off_adjust);
+		}
+	}
+
+	/* Preparing the block will also the trailing free memory. */
+	return block_prepare_used(control, block, adjust);
+}
+
+/**
+ * @brief Same as `tlsf_memalign_offs` function but with a 0 offset.
+ * The pointer returned is aligned on `align`.
+ */
+void *tlsf_memalign(tlsf_t tlsf, size_t align, size_t size) { return tlsf_memalign_offs(tlsf, align, size, 0); }
+void rt_memory_info22(tlsf_t tlsf, size_t *total, size_t *used, size_t *max_used)
+{
+	control_t *control = tlsf_cast(control_t *, tlsf);
+	if (total) { *total = control->mem_rec.total; }
+	if (used) { *used = control->mem_rec.used; }
+	if (max_used) { *max_used = control->mem_rec.max_used; }
+}
+void tlsf_free(tlsf_t tlsf, void *ptr)
+{
+	/* Don't attempt to free a NULL pointer. */
+	if (ptr)
+	{
+		control_t *control = tlsf_cast(control_t *, tlsf);
+		block_header_t *block = block_from_ptr(ptr);
+		tlsf_assert(!block_is_free(block) && "block already marked as free");
+
+		control->mem_rec.used -= (block_size(block) + tlsf_alloc_overhead());
+
+		block_mark_as_free(block);
+		block = block_merge_prev(control, block);
+		block = block_merge_next(control, block);
+		block_insert(control, block);
+	}
+}
+
+/*
+** The TLSF block information provides us with enough information to
+** provide a reasonably intelligent implementation of realloc, growing or
+** shrinking the currently allocated block as required.
+**
+** This routine handles the somewhat esoteric edge cases of realloc:
+** - a non-zero size with a null pointer will behave like malloc
+** - a zero size with a non-null pointer will behave like free
+** - a request that cannot be satisfied will leave the original buffer
+**   untouched
+** - an extended buffer size will leave the newly-allocated area with
+**   contents undefined
+*/
+void *tlsf_realloc(tlsf_t tlsf, void *ptr, size_t size)
+{
+	control_t *control = tlsf_cast(control_t *, tlsf);
+	void *p = 0;
+
+	/* Zero-size requests are treated as free. */
+	if (ptr && size == 0) { tlsf_free(tlsf, ptr); }
+	/* Requests with NULL pointers are treated as malloc. */
+	else if (!ptr) { p = tlsf_malloc(tlsf, size); }
+	else
+	{
+		block_header_t *block = block_from_ptr(ptr);
+		block_header_t *next = block_next(block);
+
+		const size_t cursize = block_size(block);
+		const size_t combined = cursize + block_size(next) + block_header_overhead;
+		const size_t adjust = adjust_request_size(tlsf, size, ALIGN_SIZE);
+
+		// if adjust if equal to 0, the size is too big
+		if (adjust == 0) { return p; }
+
+		tlsf_assert(!block_is_free(block) && "block already marked as free");
+
+		/*
+		** If the next block is used, or when combined with the current
+		** block, does not offer enough space, we must reallocate and copy.
+		*/
+		if (adjust > cursize && (!block_is_free(next) || adjust > combined))
+		{
+			p = tlsf_malloc(tlsf, size);
+			if (p)
+			{
+				const size_t minsize = tlsf_min(cursize, size);
+				rt_memcpy(p, ptr, minsize);
+				tlsf_free(tlsf, ptr);
+			}
+		}
+		else
+		{
+			/* Do we need to expand to the next block? */
+			if (adjust > cursize)
+			{
+				block_merge_next(control, block);
+				block_mark_as_used(block);
+			}
+
+			/* Trim the resulting block and return the original pointer. */
+			block_trim_used(control, block, adjust);
+			p = ptr;
+
+			/* 更新统计信息:原地调整时需要修正 used */
+			control->mem_rec.used += block_size(block);
+			control->mem_rec.used -= cursize;
+
+            if(control->mem_rec.used > control->mem_rec.max_used)
+			control->mem_rec.max_used = control->mem_rec.used;
+		}
+	}
+
+	return p;
+}
+
+void *tlsf_find_containing_block(pool_t pool, void *ptr)
+{
+	block_header_t *block = offset_to_block(pool, -(int)block_header_overhead);
+
+	while (block && !block_is_last(block))
+	{
+		if (!block_is_free(block))
+		{
+			void *block_end = block_to_ptr(block) + block_size(block);
+			if (block_to_ptr(block) <= ptr && block_end > ptr)
+			{
+				// we found the containing block, return
+				return block_to_ptr(block);
+			}
+		}
+
+		block = block_next(block);
+	}
+
+	return NULL;
+}

+ 95 - 0
test/tlsf/tlsf.h

@@ -0,0 +1,95 @@
+/*
+ * SPDX-FileCopyrightText: 2006-2016 Matthew Conte
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INCLUDED_tlsf
+#define INCLUDED_tlsf
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include "rtthread.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* tlsf_t: a TLSF structure. Can contain 1 to N pools. */
+/* pool_t: a block of memory that TLSF can manage. */
+typedef void* tlsf_t;
+typedef void* pool_t;
+
+/* Create/destroy a memory pool. */
+tlsf_t tlsf_create(void* mem, size_t max_bytes);
+tlsf_t tlsf_create_with_pool(void* mem, size_t pool_bytes, size_t max_bytes);
+void tlsf_destroy(tlsf_t tlsf);
+pool_t tlsf_get_pool(tlsf_t tlsf);
+
+/* Add/remove memory pools. */
+pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes);
+void tlsf_remove_pool(tlsf_t tlsf, pool_t pool);
+
+/* malloc/memalign/realloc/free replacements. */
+void* tlsf_malloc(tlsf_t tlsf, size_t size);
+void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t size);
+void* tlsf_memalign_offs(tlsf_t tlsf, size_t align, size_t size, size_t offset);
+void* tlsf_malloc_addr(tlsf_t tlsf, size_t size, void *address);
+void* tlsf_realloc(tlsf_t tlsf, void* ptr, size_t size);
+void tlsf_free(tlsf_t tlsf, void* ptr);
+
+/* Returns internal block size, not original request size */
+size_t tlsf_block_size(void* ptr);
+
+/* Overheads/limits of internal structures. */
+size_t tlsf_size(tlsf_t tlsf);
+size_t tlsf_pool_overhead(void);
+size_t tlsf_alloc_overhead(void);
+
+void rt_memory_info22(tlsf_t tlsf, size_t *total, size_t *used, size_t *max_used);
+
+/**
+ * @brief Return the allocable size based on the size passed
+ * as parameter
+ * 
+ * @param tlsf Pointer to the tlsf structure
+ * @param size The allocation size
+ * @return size_t The updated allocation size
+ */
+size_t tlsf_fit_size(tlsf_t tlsf, size_t size);
+
+/* Debugging. */
+typedef bool (*tlsf_walker)(void* ptr, size_t size, int used, void* user);
+void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user);
+/* Returns nonzero if any internal consistency check fails. */
+int tlsf_check(tlsf_t tlsf);
+int tlsf_check_pool(pool_t pool);
+
+/**
+ * @brief Find the block containing the pointer passed as parameter
+ * 
+ * @param pool The pool into which to look for the block
+ * @param ptr The pointer we want to find the containing block of
+ * @return void* The pointer to the containing block if found, NULL if not.
+ */
+void* tlsf_find_containing_block(pool_t pool, void *ptr);
+
+/**
+ * @brief Weak function called on every free block of memory allowing the user to implement
+ * application specific checks on the memory.
+ * 
+ * @param start The start pointer to the memory of a block
+ * @param size The size of the memory in the block
+ * @param is_free Set to true when the memory belongs to a free block.
+ * False if it belongs to an allocated block.
+ * @return true The checks found no inconsistency in the memory
+ * @return false The checks in the function highlighted an inconsistency in the memory
+ */
+__attribute__((weak))  bool tlsf_check_hook(void *start, size_t size, bool is_free);
+
+#if defined(__cplusplus)
+};
+#endif
+
+#endif

+ 161 - 0
test/tlsf/tlsf_block_functions.h

@@ -0,0 +1,161 @@
+/*
+ * SPDX-FileCopyrightText: 2006-2016 Matthew Conte
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#pragma once
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*
+** Constants definition for poisoning.
+** These defines are used as 3rd argument of tlsf_poison_fill_region() for readability purposes.
+*/
+#define POISONING_AFTER_FREE   true
+#define POISONING_AFTER_MALLOC !POISONING_AFTER_FREE
+
+/* A type used for casting when doing pointer arithmetic. */
+typedef ptrdiff_t tlsfptr_t;
+
+/*
+** Cast and min/max macros.
+*/
+#if !defined(tlsf_cast)
+#define tlsf_cast(t, exp) ((t)(exp))
+#endif
+#if !defined(tlsf_min)
+#define tlsf_min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#if !defined(tlsf_max)
+#define tlsf_max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+/*
+** Set assert macro, if it has not been provided by the user.
+*/
+#if !defined(tlsf_assert)
+#define tlsf_assert RT_ASSERT
+#endif
+
+typedef struct block_header_t
+{
+	/* Points to the previous physical block. */
+	struct block_header_t *prev_phys_block;
+
+	/* The size of this block, excluding the block header. */
+	size_t size;
+
+	/* Next and previous free blocks. */
+	struct block_header_t *next_free;
+	struct block_header_t *prev_free;
+} block_header_t;
+
+/* User data starts directly after the size field in a used block. */
+#define block_start_offset (offsetof(block_header_t, size) + sizeof(size_t))
+
+/*
+** A free block must be large enough to store its header minus the size of
+** the prev_phys_block field, and no larger than the number of addressable
+** bits for FL_INDEX.
+*/
+#define block_size_min (sizeof(block_header_t) - sizeof(block_header_t *))
+
+/*
+** Since block sizes are always at least a multiple of 4, the two least
+** significant bits of the size field are used to store the block status:
+** - bit 0: whether block is busy or free
+** - bit 1: whether previous block is busy or free
+*/
+#define block_header_free_bit      (1UL << 0)
+#define block_header_prev_free_bit (1UL << 1)
+
+/*
+** The size of the block header exposed to used blocks is the size field.
+** The prev_phys_block field is stored *inside* the previous free block.
+*/
+#define block_header_overhead (sizeof(size_t))
+
+/*
+** block_header_t member functions.
+*/
+#define tlsf_decl rt_always_inline
+
+tlsf_decl size_t block_size(const block_header_t *block)
+{ return block->size & ~(block_header_free_bit | block_header_prev_free_bit); }
+
+tlsf_decl void block_set_size(block_header_t *block, size_t size)
+{
+	const size_t oldsize = block->size;
+	block->size = size | (oldsize & (block_header_free_bit | block_header_prev_free_bit));
+}
+
+tlsf_decl int block_is_last(const block_header_t *block) { return block_size(block) == 0; }
+
+tlsf_decl int block_is_free(const block_header_t *block)
+{ return tlsf_cast(int, block->size &block_header_free_bit); }
+
+tlsf_decl void block_set_free(block_header_t *block) { block->size |= block_header_free_bit; }
+
+tlsf_decl void block_set_used(block_header_t *block) { block->size &= ~block_header_free_bit; }
+
+tlsf_decl int block_is_prev_free(const block_header_t *block)
+{ return tlsf_cast(int, block->size &block_header_prev_free_bit); }
+
+tlsf_decl void block_set_prev_free(block_header_t *block) { block->size |= block_header_prev_free_bit; }
+
+tlsf_decl void block_set_prev_used(block_header_t *block) { block->size &= ~block_header_prev_free_bit; }
+
+tlsf_decl block_header_t *block_from_ptr(const void *ptr)
+{ return tlsf_cast(block_header_t *, tlsf_cast(unsigned char *, ptr) - block_start_offset); }
+
+tlsf_decl void *block_to_ptr(const block_header_t *block)
+{ return tlsf_cast(void *, tlsf_cast(unsigned char *, block) + block_start_offset); }
+
+/* Return location of next block after block of given size. */
+tlsf_decl block_header_t *offset_to_block(const void *ptr, size_t size)
+{ return tlsf_cast(block_header_t *, tlsf_cast(tlsfptr_t, ptr) + size); }
+
+/* Return location of previous block. */
+tlsf_decl block_header_t *block_prev(const block_header_t *block)
+{
+	tlsf_assert(block_is_prev_free(block) && "previous block must be free");
+	return block->prev_phys_block;
+}
+
+/* Return location of next existing block. */
+tlsf_decl block_header_t *block_next(const block_header_t *block)
+{
+	block_header_t *next = offset_to_block(block_to_ptr(block), block_size(block) - block_header_overhead);
+	tlsf_assert(!block_is_last(block));
+	return next;
+}
+
+/* Link a new block with its physical neighbor, return the neighbor. */
+tlsf_decl block_header_t *block_link_next(block_header_t *block)
+{
+	block_header_t *next = block_next(block);
+	next->prev_phys_block = block;
+	return next;
+}
+
+tlsf_decl void block_mark_as_free(block_header_t *block)
+{
+	/* Link the block to the next block, first. */
+	block_header_t *next = block_link_next(block);
+	block_set_prev_free(next);
+	block_set_free(block);
+}
+
+tlsf_decl void block_mark_as_used(block_header_t *block)
+{
+	block_header_t *next = block_next(block);
+	block_set_prev_used(next);
+	block_set_used(block);
+}
+
+#if defined(__cplusplus)
+};
+#endif

+ 630 - 0
test/tlsf/tlsf_control_functions.h

@@ -0,0 +1,630 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Matthew Conte
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#pragma once
+#include "tlsf_block_functions.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#define tlsf_decl static inline
+#else
+#define tlsf_decl rt_always_inline
+#endif
+
+enum tlsf_config
+{
+	/* All allocation sizes and addresses are aligned to 4 bytes. */
+	ALIGN_SIZE_LOG2 = 2,
+	ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2),
+};
+
+typedef struct
+{
+	int32_t total;
+	int32_t used;
+	int32_t max_used;
+} mem_record_t;
+
+/* The TLSF control structure. */
+typedef struct control_t
+{
+	/* Empty lists point at this block to indicate they are free. */
+	block_header_t block_null;
+
+	/* Local parameter for the pool. Given the maximum
+	 * value of each field, all the following parameters
+	 * can fit on 4 bytes when using bitfields
+	 */
+	unsigned int fl_index_count: 5; // 5 cumulated bits
+	unsigned int fl_index_shift: 3; // 8 cumulated bits
+	unsigned int fl_index_max: 6;   // 14 cumulated bits
+	unsigned int sl_index_count: 6; // 20 cumulated bits
+
+	/* log2 of number of linear subdivisions of block sizes. Larger
+	** values require more memory in the control structure. Values of
+	** 4 or 5 are typical.
+	*/
+	unsigned int sl_index_count_log2: 3; // 23 cumulated bits
+	unsigned int small_block_size: 8;    // 31 cumulated bits
+
+	/* size of the metadata ( size of control block,
+	 * sl_bitmap and blocks )
+	 */
+	size_t size;
+
+	/* Bitmaps for free lists. */
+	unsigned int fl_bitmap;
+	unsigned int *sl_bitmap;
+
+	/* Head of free lists. */
+	block_header_t **blocks;
+	mem_record_t mem_rec;
+} control_t;
+
+/*
+** Architecture-specific bit manipulation routines.
+**
+** TLSF achieves O(1) cost for malloc and free operations by limiting
+** the search for a free block to a free list of guaranteed size
+** adequate to fulfill the request, combined with efficient free list
+** queries using bitmasks and architecture-specific bit-manipulation
+** routines.
+**
+** Most modern processors provide instructions to count leading zeroes
+** in a word, find the lowest and highest set bit, etc. These
+** specific implementations will be used when available, falling back
+** to a reasonably efficient generic implementation.
+**
+** NOTE: TLSF spec relies on ffs/fls returning value 0..31.
+** ffs/fls return 1-32 by default, returning 0 for error.
+*/
+
+/*
+** Detect whether or not we are building for a 32- or 64-bit (LP/LLP)
+** architecture. There is no reliable portable method at compile-time.
+*/
+#if defined(__alpha__) || defined(__ia64__) || defined(__x86_64__) || defined(_WIN64) || defined(__LP64__) || defined(__LLP64__)
+#define TLSF_64BIT
+#endif
+
+/*
+** gcc 3.4 and above have builtin support, specialized for architecture.
+** Some compilers masquerade as gcc; patchlevel test filters them out.
+*/
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__GNUC_PATCHLEVEL__)
+
+#if defined(__SNC__)
+/* SNC for Playstation 3. */
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	const unsigned int reverse = word & (~word + 1);
+	const int bit = 32 - __builtin_clz(reverse);
+	return bit - 1;
+}
+
+#else
+
+tlsf_decl int tlsf_ffs(unsigned int word) { return __builtin_ffs(word) - 1; }
+
+#endif
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	const int bit = word ? 32 - __builtin_clz(word) : 0;
+	return bit - 1;
+}
+
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400) && (defined(_M_IX86) || defined(_M_X64))
+/* Microsoft Visual C++ support on x86/X64 architectures. */
+
+#include <intrin.h>
+
+#pragma intrinsic(_BitScanReverse)
+#pragma intrinsic(_BitScanForward)
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	unsigned long index;
+	return _BitScanReverse(&index, word) ? index : -1;
+}
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	unsigned long index;
+	return _BitScanForward(&index, word) ? index : -1;
+}
+
+#elif defined(_MSC_VER) && defined(_M_PPC)
+/* Microsoft Visual C++ support on PowerPC architectures. */
+
+#include <ppcintrinsics.h>
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	const int bit = 32 - _CountLeadingZeros(word);
+	return bit - 1;
+}
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	const unsigned int reverse = word & (~word + 1);
+	const int bit = 32 - _CountLeadingZeros(reverse);
+	return bit - 1;
+}
+
+#elif defined(__ARMCC_VERSION)
+/* RealView Compilation Tools for ARM */
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	const unsigned int reverse = word & (~word + 1);
+	const int bit = 32 - __clz(reverse);
+	return bit - 1;
+}
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	const int bit = word ? 32 - __clz(word) : 0;
+	return bit - 1;
+}
+
+#elif defined(__ghs__)
+/* Green Hills support for PowerPC */
+
+#include <ppc_ghs.h>
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	const unsigned int reverse = word & (~word + 1);
+	const int bit = 32 - __CLZ32(reverse);
+	return bit - 1;
+}
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	const int bit = word ? 32 - __CLZ32(word) : 0;
+	return bit - 1;
+}
+
+#else
+/* Fall back to generic implementation. */
+
+tlsf_decl int tlsf_fls_generic(unsigned int word)
+{
+	int bit = 32;
+
+	if (!word) { bit -= 1; }
+	if (!(word & 0xffff0000))
+	{
+		word <<= 16;
+		bit -= 16;
+	}
+	if (!(word & 0xff000000))
+	{
+		word <<= 8;
+		bit -= 8;
+	}
+	if (!(word & 0xf0000000))
+	{
+		word <<= 4;
+		bit -= 4;
+	}
+	if (!(word & 0xc0000000))
+	{
+		word <<= 2;
+		bit -= 2;
+	}
+	if (!(word & 0x80000000))
+	{
+		word <<= 1;
+		bit -= 1;
+	}
+
+	return bit;
+}
+
+/* Implement ffs in terms of fls. */
+tlsf_decl int tlsf_ffs(unsigned int word) { return tlsf_fls_generic(word & (~word + 1)) - 1; }
+
+tlsf_decl int tlsf_fls(unsigned int word) { return tlsf_fls_generic(word) - 1; }
+
+#endif
+
+/* Possibly 64-bit version of tlsf_fls. */
+#if defined(TLSF_64BIT)
+tlsf_decl int tlsf_fls_sizet(size_t size)
+{
+	int high = (int)(size >> 32);
+	int bits = 0;
+	if (high) { bits = 32 + tlsf_fls(high); }
+	else
+	{
+		bits = tlsf_fls((int)size & 0xffffffff);
+	}
+	return bits;
+}
+#else
+#define tlsf_fls_sizet tlsf_fls
+#endif
+
+tlsf_decl size_t align_up(size_t x, size_t align)
+{
+	tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two");
+	return (x + (align - 1)) & ~(align - 1);
+}
+
+tlsf_decl size_t align_down(size_t x, size_t align)
+{
+	tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two");
+	return x - (x & (align - 1));
+}
+
+tlsf_decl void *align_ptr(const void *ptr, size_t align)
+{
+	const tlsfptr_t aligned = (tlsf_cast(tlsfptr_t, ptr) + (align - 1)) & ~(align - 1);
+	tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two");
+	return tlsf_cast(void *, aligned);
+}
+
+tlsf_decl size_t tlsf_align_size(void) { return ALIGN_SIZE; }
+
+tlsf_decl size_t tlsf_block_size_min(void) { return block_size_min; }
+
+tlsf_decl size_t tlsf_block_size_max(control_t *control)
+{
+	if (control == NULL) { return 0; }
+	return tlsf_cast(size_t, 1) << control->fl_index_max;
+}
+
+/*
+** Adjust an allocation size to be aligned to word size, and no smaller
+** than internal minimum.
+*/
+tlsf_decl size_t adjust_request_size(control_t *control, size_t size, size_t align)
+{
+	size_t adjust = 0;
+	if (size)
+	{
+		const size_t aligned = align_up(size, align);
+
+		/* aligned sized must not exceed block_size_max or we'll go out of bounds on sl_bitmap */
+		if (aligned < tlsf_block_size_max(control)) { adjust = tlsf_max(aligned, block_size_min); }
+	}
+	return adjust;
+}
+
+/*
+** TLSF utility functions. In most cases, these are direct translations of
+** the documentation found in the white paper.
+*/
+
+tlsf_decl void mapping_insert(control_t *control, size_t size, int *fli, int *sli)
+{
+	int fl, sl;
+	if (size < control->small_block_size)
+	{
+		/* Store small blocks in first list. */
+		fl = 0;
+		sl = tlsf_cast(int, size) / (control->small_block_size / control->sl_index_count);
+	}
+	else
+	{
+		fl = tlsf_fls_sizet(size);
+		sl = tlsf_cast(int, size >> (fl - control->sl_index_count_log2)) ^ (1 << control->sl_index_count_log2);
+		fl -= (control->fl_index_shift - 1);
+	}
+	*fli = fl;
+	*sli = sl;
+}
+
+/* This version rounds up to the next block size (for allocations) */
+tlsf_decl void mapping_search(control_t *control, size_t *size, int *fli, int *sli)
+{
+	if (*size >= control->small_block_size)
+	{
+		const size_t round = (1 << (tlsf_fls_sizet(*size) - control->sl_index_count_log2));
+		*size = align_up(*size, round);
+	}
+	mapping_insert(control, *size, fli, sli);
+}
+
+tlsf_decl block_header_t *search_suitable_block(control_t *control, int *fli, int *sli)
+{
+	int fl = *fli;
+	int sl = *sli;
+
+	/*
+	** First, search for a block in the list associated with the given
+	** fl/sl index.
+	*/
+	unsigned int sl_map = control->sl_bitmap[fl] & (~0U << sl);
+	if (!sl_map)
+	{
+		/* No block exists. Search in the next largest first-level list. */
+		const unsigned int fl_map = control->fl_bitmap & (~0U << (fl + 1));
+		if (!fl_map)
+		{
+			/* No free blocks available, memory has been exhausted. */
+			return 0;
+		}
+
+		fl = tlsf_ffs(fl_map);
+		*fli = fl;
+		sl_map = control->sl_bitmap[fl];
+	}
+	tlsf_assert(sl_map && "internal error - second level bitmap is null");
+	sl = tlsf_ffs(sl_map);
+	*sli = sl;
+
+	/* Return the first block in the free list. */
+	return control->blocks[fl * control->sl_index_count + sl];
+}
+
+/* Remove a free block from the free list.*/
+tlsf_decl void remove_free_block(control_t *control, block_header_t *block, int fl, int sl)
+{
+	block_header_t *prev = block->prev_free;
+	block_header_t *next = block->next_free;
+	tlsf_assert(prev && "prev_free field can not be null");
+	tlsf_assert(next && "next_free field can not be null");
+	next->prev_free = prev;
+	prev->next_free = next;
+
+	/* If this block is the head of the free list, set new head. */
+	if (control->blocks[fl * control->sl_index_count + sl] == block)
+	{
+		control->blocks[fl * control->sl_index_count + sl] = next;
+
+		/* If the new head is null, clear the bitmap. */
+		if (next == &control->block_null)
+		{
+			control->sl_bitmap[fl] &= ~(1U << sl);
+
+			/* If the second bitmap is now empty, clear the fl bitmap. */
+			if (!control->sl_bitmap[fl]) { control->fl_bitmap &= ~(1U << fl); }
+		}
+	}
+}
+
+/* Insert a free block into the free block list. */
+tlsf_decl void insert_free_block(control_t *control, block_header_t *block, int fl, int sl)
+{
+	block_header_t *current = control->blocks[fl * control->sl_index_count + sl];
+	tlsf_assert(current && "free list cannot have a null entry");
+	tlsf_assert(block && "cannot insert a null entry into the free list");
+	block->next_free = current;
+	block->prev_free = &control->block_null;
+	current->prev_free = block;
+
+	tlsf_assert(block_to_ptr(block) == align_ptr(block_to_ptr(block), ALIGN_SIZE) && "block not aligned properly");
+	/*
+	** Insert the new block at the head of the list, and mark the first-
+	** and second-level bitmaps appropriately.
+	*/
+	control->blocks[fl * control->sl_index_count + sl] = block;
+	control->fl_bitmap |= (1U << fl);
+	control->sl_bitmap[fl] |= (1U << sl);
+}
+
+/* Remove a given block from the free list. */
+tlsf_decl void block_remove(control_t *control, block_header_t *block)
+{
+	int fl, sl;
+	mapping_insert(control, block_size(block), &fl, &sl);
+	remove_free_block(control, block, fl, sl);
+}
+
+/* Insert a given block into the free list. */
+tlsf_decl void block_insert(control_t *control, block_header_t *block)
+{
+	int fl, sl;
+	mapping_insert(control, block_size(block), &fl, &sl);
+	insert_free_block(control, block, fl, sl);
+}
+
+tlsf_decl int block_can_split(block_header_t *block, size_t size) { return block_size(block) >= sizeof(block_header_t) + size; }
+
+/* Split a block into two, the second of which is free. */
+tlsf_decl block_header_t *block_split(block_header_t *block, size_t size)
+{
+	/* Calculate the amount of space left in the remaining block.
+	 * REMINDER: remaining pointer's first field is `prev_phys_block` but this field is part of the
+	 * previous physical block. */
+	block_header_t *remaining = offset_to_block(block_to_ptr(block), size - block_header_overhead);
+
+	/* `size` passed as an argument is the first block's new size, thus, the remaining block's size
+	 * is `block_size(block) - size`. However, the block's data must be precedeed by the data size.
+	 * This field is NOT part of the size, so it has to be substracted from the calculation. */
+	const size_t remain_size = block_size(block) - (size + block_header_overhead);
+
+	tlsf_assert(block_to_ptr(remaining) == align_ptr(block_to_ptr(remaining), ALIGN_SIZE) && "remaining block not aligned properly");
+
+	tlsf_assert(block_size(block) == remain_size + size + block_header_overhead);
+	block_set_size(remaining, remain_size);
+	tlsf_assert(block_size(remaining) >= block_size_min && "block split with invalid size");
+
+	block_set_size(block, size);
+	block_mark_as_free(remaining);
+
+	/**
+	 * Here is the final outcome of this function:
+	 *
+	 * block             remaining (block_ptr + size - BHO)
+	 * +                                +
+	 * |                                |
+	 * v                                v
+	 * +----------------------------------------------------------------------+
+	 * |0000|    |xxxxxxxxxxxxxxxxxxxxxx|xxxx|    |###########################|
+	 * |0000|    |xxxxxxxxxxxxxxxxxxxxxx|xxxx|    |###########################|
+	 * |0000|    |xxxxxxxxxxxxxxxxxxxxxx|xxxx|    |###########################|
+	 * |0000|    |xxxxxxxxxxxxxxxxxxxxxx|xxxx|    |###########################|
+	 * +----------------------------------------------------------------------+
+	 *      |    |                           |    |
+	 *      +    +<------------------------->+    +<------------------------->
+	 *       BHO    `size` (argument) bytes   BHO      `remain_size` bytes
+	 *
+	 * Where BHO = block_header_overhead,
+	 * 0: part of the memory owned by a `block`'s previous neighbour,
+	 * x: part of the memory owned by `block`.
+	 * #: part of the memory owned by `remaining`.
+	 */
+
+	return remaining;
+}
+
+/*!
+ * @brief Weak function filling the given memory with a given fill pattern.
+ *
+ * @param start: pointer to the start of the memory region to fill
+ * @param size: size of the memory region to fill
+ * @param is_free: Indicate if the pattern to use the fill the region should be
+ * an after free or after allocation pattern.
+ */
+__attribute__((weak)) void block_absorb_post_hook(void *start, size_t size, bool is_free);
+
+/* Absorb a free block's storage into an adjacent previous free block. */
+tlsf_decl block_header_t *block_absorb(block_header_t *prev, block_header_t *block)
+{
+	tlsf_assert(!block_is_last(prev) && "previous block can't be last");
+	/* Note: Leaves flags untouched. */
+	prev->size += block_size(block) + block_header_overhead;
+	block_link_next(prev);
+
+	if (block_absorb_post_hook != NULL) { block_absorb_post_hook(block, sizeof(block_header_t), POISONING_AFTER_FREE); }
+
+	return prev;
+}
+
+/* Merge a just-freed block with an adjacent previous free block. */
+tlsf_decl block_header_t *block_merge_prev(control_t *control, block_header_t *block)
+{
+	if (block_is_prev_free(block))
+	{
+		block_header_t *prev = block_prev(block);
+		tlsf_assert(prev && "prev physical block can't be null");
+		tlsf_assert(block_is_free(prev) && "prev block is not free though marked as such");
+		block_remove(control, prev);
+		block = block_absorb(prev, block);
+	}
+
+	return block;
+}
+
+/* Merge a just-freed block with an adjacent free block. */
+tlsf_decl block_header_t *block_merge_next(control_t *control, block_header_t *block)
+{
+	block_header_t *next = block_next(block);
+	tlsf_assert(next && "next physical block can't be null");
+
+	if (block_is_free(next))
+	{
+		tlsf_assert(!block_is_last(block) && "previous block can't be last");
+		block_remove(control, next);
+		block = block_absorb(block, next);
+	}
+
+	return block;
+}
+
+/* Trim any trailing block space off the end of a block, return to pool. */
+tlsf_decl void block_trim_free(control_t *control, block_header_t *block, size_t size)
+{
+	tlsf_assert(block_is_free(block) && "block must be free");
+	if (block_can_split(block, size))
+	{
+		block_header_t *remaining_block = block_split(block, size);
+		block_link_next(block);
+		block_set_prev_free(remaining_block);
+		block_insert(control, remaining_block);
+	}
+}
+
+/* Trim any trailing block space off the end of a used block, return to pool. */
+tlsf_decl void block_trim_used(control_t *control, block_header_t *block, size_t size)
+{
+	tlsf_assert(!block_is_free(block) && "block must be used");
+	if (block_can_split(block, size))
+	{
+		/* If the next block is free, we must coalesce. */
+		block_header_t *remaining_block = block_split(block, size);
+		block_set_prev_used(remaining_block);
+
+		remaining_block = block_merge_next(control, remaining_block);
+		block_insert(control, remaining_block);
+	}
+}
+
+tlsf_decl block_header_t *block_trim_free_leading(control_t *control, block_header_t *block, size_t size)
+{
+	block_header_t *remaining_block = block;
+	if (block_can_split(block, size))
+	{
+		/* We want to split `block` in two: the first block will be freed and the
+		 * second block will be returned. */
+		remaining_block = block_split(block, size - block_header_overhead);
+
+		/* `remaining_block` is the second block, mark its predecessor (first
+		 * block) as free. */
+		block_set_prev_free(remaining_block);
+
+		block_link_next(block);
+
+		/* Put back the first block into the free memory list. */
+		block_insert(control, block);
+	}
+
+	return remaining_block;
+}
+
+tlsf_decl block_header_t *block_locate_free(control_t *control, size_t *size)
+{
+	int fl = 0, sl = 0;
+	block_header_t *block = 0;
+
+	if (*size)
+	{
+		mapping_search(control, size, &fl, &sl);
+
+		/*
+		** mapping_search can futz with the size, so for excessively large sizes it can sometimes wind up
+		** with indices that are off the end of the block array.
+		** So, we protect against that here, since this is the only callsite of mapping_search.
+		** Note that we don't need to check sl, since it comes from a modulo operation that guarantees it's always in range.
+		*/
+		if (fl < control->fl_index_count) { block = search_suitable_block(control, &fl, &sl); }
+	}
+
+	if (block)
+	{
+		tlsf_assert(block_size(block) >= *size);
+		remove_free_block(control, block, fl, sl);
+	}
+
+	return block;
+}
+
+tlsf_decl void *block_prepare_used(control_t *control, block_header_t *block, size_t size)
+{
+	void *p = 0;
+	if (block)
+	{
+		tlsf_assert(size && "size must be non-zero");
+		block_trim_free(control, block, size);
+		block_mark_as_used(block);
+		p = block_to_ptr(block);
+
+		control->mem_rec.used += (block_size(block) + tlsf_alloc_overhead());
+		if (control->mem_rec.used > control->mem_rec.max_used) { control->mem_rec.max_used = control->mem_rec.used; }
+	}
+	return p;
+}
+
+#undef tlsf_decl
+
+#if defined(__cplusplus)
+};
+#endif

+ 1 - 1
test/valloc/valloc.c

@@ -6,7 +6,7 @@
 #include "valloc.h"
 
 #define HEADER_SIZE        sizeof(int)
-#define MALLOC_HEADER_SIZE 12
+#define MALLOC_HEADER_SIZE 0
 
 static int count = 0;
 static int use = 0;

+ 2 - 2
test/valloc/valloc.h

@@ -8,8 +8,8 @@
  *       \author  Lamdonn
  *      \details  v1.0.0
  ********************************************************************************************************/
-#ifndef __valloc_H
-#define __valloc_H
+#ifndef valloc
+#define valloc
 
 #ifdef __cplusplus
 extern "C" {

+ 13 - 4
xmake.lua

@@ -14,9 +14,9 @@ target("RyanJson", function()
 
     -- 定义宏:启用 Fuzzer 功能
     -- Fuzzer 与覆盖率相关编译/链接选项
-    add_defines("isEnableFuzzer")
-    add_cxflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true})
-    add_ldflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true})
+    -- add_defines("isEnableFuzzer")
+    -- add_cxflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true})
+    -- add_ldflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true})
 
     -- 编译优化策略
     set_policy("build.ccache", false) -- 禁用 ccache 缓存
@@ -92,7 +92,7 @@ target("RyanJson", function()
         "-Wdisabled-optimization", -- 被禁用的优化
         "-Wreturn-local-addr",     -- 返回局部变量地址
         "-Wdeprecated",            -- 使用已弃用特性
-        "-Wunsafe-buffer-usage",   -- 不安全的数组/指针用法
+        -- "-Wunsafe-buffer-usage",   -- 不安全的数组/指针用法
         "-Wuninitialized",         -- 使用未初始化变量
         "-fstack-protector-strong",-- 栈保护
         "-Wmissing-include-dirs",  -- 头文件目录缺失
@@ -108,6 +108,13 @@ target("RyanJson", function()
         "-Wparentheses-equality",
         "-Wno-documentation",      -- 临时关闭文档警告
         -- "-Wno-parentheses-equality", -- 临时关闭括号比较警告
+        "-Wno-extra-semi-stmt",     -- 关闭分号警告
+        "-Wno-unsafe-buffer-usage", -- 关闭不安全的数组/指针用法警告
+        "-Wno-declaration-after-statement", -- 关闭声明在语句后的警告
+        "-Wno-padded",              -- 关闭结构体填充警告
+        "-Wno-switch-default",      -- 关闭 switch 语句缺少 default 的警告
+        "-Wno-unused-macros",       -- 关闭未使用的宏定义警告
+        "-Wno-unused-includes",     -- 关闭未使用的头文件警告
         {force = true}
     )
 
@@ -117,6 +124,7 @@ target("RyanJson", function()
     add_includedirs('./test/fuzzer', {public = true})
     add_includedirs('./test', {public = true})
     add_includedirs('./test/valloc', {public = true})
+    add_includedirs('./test/tlsf', {public = true})
     add_includedirs('./test/baseTest', {public = true})
     add_includedirs('./externalModule/cJSON', {public = true})
     add_includedirs('./externalModule/yyjson', {public = true})
@@ -127,6 +135,7 @@ target("RyanJson", function()
     add_files('./test/fuzzer/*.c', {public = true})
     add_files('./test/*.c', {public = true}, {cxflags = "-w"})          -- 测试代码,关闭警告
     add_files('./test/valloc/*.c', {public = true}, {cxflags = "-w"})   -- valloc 测试,关闭警告
+    add_files('./test/tlsf/*.c', {public = true}, {cxflags = "-w"})   -- valloc 测试,关闭警告
     add_files('./test/baseTest/*.c', {public = true}, {cxflags = "-w"}) -- 基础测试,关闭警告
     add_files('./externalModule/cJSON/*.c', {public = true}, {cxflags = "-w"}) -- 第三方库 cJSON,关闭警告
     add_files('./externalModule/yyjson/*.c', {public = true}, {cxflags = "-w"}) -- 第三方库 yyjson,关闭警告