xref: /rockchip-linux_mpp/mpp/base/mpp_trie.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1*437bfbebSnyanmisaka /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2*437bfbebSnyanmisaka /*
3*437bfbebSnyanmisaka  * Copyright (c) 2024 Rockchip Electronics Co., Ltd.
4*437bfbebSnyanmisaka  */
5*437bfbebSnyanmisaka 
6*437bfbebSnyanmisaka #define MODULE_TAG "mpp_trie"
7*437bfbebSnyanmisaka 
8*437bfbebSnyanmisaka #include "mpp_env.h"
9*437bfbebSnyanmisaka #include "mpp_mem.h"
10*437bfbebSnyanmisaka #include "mpp_time.h"
11*437bfbebSnyanmisaka #include "mpp_debug.h"
12*437bfbebSnyanmisaka #include "mpp_common.h"
13*437bfbebSnyanmisaka 
14*437bfbebSnyanmisaka #include "mpp_trie.h"
15*437bfbebSnyanmisaka 
16*437bfbebSnyanmisaka #define MPP_TRIE_DBG_PAVE               (0x00000001)
17*437bfbebSnyanmisaka #define MPP_TRIE_DBG_SET                (0x00000002)
18*437bfbebSnyanmisaka #define MPP_TRIE_DBG_GET                (0x00000004)
19*437bfbebSnyanmisaka #define MPP_TRIE_DBG_CNT                (0x00000008)
20*437bfbebSnyanmisaka #define MPP_TRIE_DBG_WALK               (0x00000010)
21*437bfbebSnyanmisaka #define MPP_TRIE_DBG_LAST               (0x00000020)
22*437bfbebSnyanmisaka #define MPP_TRIE_DBG_LAST_STEP          (0x00000040)
23*437bfbebSnyanmisaka #define MPP_TRIE_DBG_LAST_CHECK         (0x00000080)
24*437bfbebSnyanmisaka #define MPP_TRIE_DBG_IMPORT             (0x00000100)
25*437bfbebSnyanmisaka 
26*437bfbebSnyanmisaka #define trie_dbg(flag, fmt, ...)        _mpp_dbg_f(mpp_trie_debug, flag, fmt, ## __VA_ARGS__)
27*437bfbebSnyanmisaka #define trie_dbg_pave(fmt, ...)         trie_dbg(MPP_TRIE_DBG_PAVE, fmt, ## __VA_ARGS__)
28*437bfbebSnyanmisaka #define trie_dbg_set(fmt, ...)          trie_dbg(MPP_TRIE_DBG_SET, fmt, ## __VA_ARGS__)
29*437bfbebSnyanmisaka #define trie_dbg_get(fmt, ...)          trie_dbg(MPP_TRIE_DBG_GET, fmt, ## __VA_ARGS__)
30*437bfbebSnyanmisaka #define trie_dbg_cnt(fmt, ...)          trie_dbg(MPP_TRIE_DBG_CNT, fmt, ## __VA_ARGS__)
31*437bfbebSnyanmisaka #define trie_dbg_walk(fmt, ...)         trie_dbg(MPP_TRIE_DBG_WALK, fmt, ## __VA_ARGS__)
32*437bfbebSnyanmisaka #define trie_dbg_last(fmt, ...)         trie_dbg(MPP_TRIE_DBG_LAST, fmt, ## __VA_ARGS__)
33*437bfbebSnyanmisaka 
34*437bfbebSnyanmisaka #define MPP_TRIE_KEY_LEN                (4)
35*437bfbebSnyanmisaka #define MPP_TRIE_KEY_MAX                (1 << (MPP_TRIE_KEY_LEN))
36*437bfbebSnyanmisaka #define MPP_TRIE_INFO_MAX               (1 << 12)
37*437bfbebSnyanmisaka #define MPP_TRIE_NAME_MAX               (1 << 12)
38*437bfbebSnyanmisaka 
39*437bfbebSnyanmisaka #define DEFAULT_NODE_COUNT              900
40*437bfbebSnyanmisaka #define DEFAULT_INFO_COUNT              80
41*437bfbebSnyanmisaka #define INVALID_NODE_ID                 (-1)
42*437bfbebSnyanmisaka #define MPP_TRIE_TAG_LEN_MAX            ((sizeof(rk_u64) * 8) / MPP_TRIE_KEY_LEN)
43*437bfbebSnyanmisaka 
44*437bfbebSnyanmisaka /* spatial optimized trie tree */
45*437bfbebSnyanmisaka typedef struct MppTrieNode_t {
46*437bfbebSnyanmisaka     /* next         - next trie node index */
47*437bfbebSnyanmisaka     rk_s16          next[MPP_TRIE_KEY_MAX];
48*437bfbebSnyanmisaka     /* id           - payload data offset of current trie node */
49*437bfbebSnyanmisaka     rk_s32          id;
50*437bfbebSnyanmisaka     /* idx          - trie node index in ascending order */
51*437bfbebSnyanmisaka     rk_s16          idx;
52*437bfbebSnyanmisaka     /* prev         - previous trie node index */
53*437bfbebSnyanmisaka     rk_s16          prev;
54*437bfbebSnyanmisaka 
55*437bfbebSnyanmisaka     /* tag_val      - prefix tag */
56*437bfbebSnyanmisaka     rk_u64          tag_val;
57*437bfbebSnyanmisaka     /* key          - current key value in previous node as next */
58*437bfbebSnyanmisaka     rk_u16          key;
59*437bfbebSnyanmisaka     /*
60*437bfbebSnyanmisaka      * tag len      - prefix tag length
61*437bfbebSnyanmisaka      * zero         - normal node with 16 next node
62*437bfbebSnyanmisaka      * positive     - tag node with 64bit prefix tag
63*437bfbebSnyanmisaka      */
64*437bfbebSnyanmisaka     rk_s16          tag_len;
65*437bfbebSnyanmisaka 
66*437bfbebSnyanmisaka     /* next_cnt     - valid next node count */
67*437bfbebSnyanmisaka     rk_u16          next_cnt;
68*437bfbebSnyanmisaka } MppTrieNode;
69*437bfbebSnyanmisaka 
70*437bfbebSnyanmisaka typedef struct MppTrieImpl_t {
71*437bfbebSnyanmisaka     char            *name;
72*437bfbebSnyanmisaka     rk_s32          name_len;
73*437bfbebSnyanmisaka     rk_s32          buf_size;
74*437bfbebSnyanmisaka 
75*437bfbebSnyanmisaka     rk_s32          node_count;
76*437bfbebSnyanmisaka     rk_s32          node_used;
77*437bfbebSnyanmisaka     MppTrieNode     *nodes;
78*437bfbebSnyanmisaka 
79*437bfbebSnyanmisaka     /* info and name record buffer */
80*437bfbebSnyanmisaka     void            *info_buf;
81*437bfbebSnyanmisaka     rk_s32          info_count;
82*437bfbebSnyanmisaka     rk_s32          info_buf_size;
83*437bfbebSnyanmisaka     rk_s32          info_buf_pos;
84*437bfbebSnyanmisaka     rk_s32          info_name_max;
85*437bfbebSnyanmisaka } MppTrieImpl;
86*437bfbebSnyanmisaka 
87*437bfbebSnyanmisaka /* work structure for trie traversal */
88*437bfbebSnyanmisaka typedef struct MppTrieWalk_t {
89*437bfbebSnyanmisaka     MppTrieNode     *root;
90*437bfbebSnyanmisaka     rk_u64          tag;
91*437bfbebSnyanmisaka     rk_u32          len;
92*437bfbebSnyanmisaka     rk_s32          match;
93*437bfbebSnyanmisaka } MppTrieWalk;
94*437bfbebSnyanmisaka 
95*437bfbebSnyanmisaka rk_u32 mpp_trie_debug = 0;
96*437bfbebSnyanmisaka 
trie_get_node(MppTrieImpl * trie,rk_s32 prev,rk_u64 key)97*437bfbebSnyanmisaka static rk_s32 trie_get_node(MppTrieImpl *trie, rk_s32 prev, rk_u64 key)
98*437bfbebSnyanmisaka {
99*437bfbebSnyanmisaka     MppTrieNode *node;
100*437bfbebSnyanmisaka     rk_s32 idx;
101*437bfbebSnyanmisaka 
102*437bfbebSnyanmisaka     if (trie->node_used >= trie->node_count) {
103*437bfbebSnyanmisaka         rk_s32 old_count = trie->node_count;
104*437bfbebSnyanmisaka         rk_s32 new_count = old_count * 2;
105*437bfbebSnyanmisaka         MppTrieNode *new_nodes = mpp_realloc(trie->nodes, MppTrieNode, new_count);
106*437bfbebSnyanmisaka 
107*437bfbebSnyanmisaka         if (!new_nodes) {
108*437bfbebSnyanmisaka             mpp_err_f("failed to realloc new nodes %d\n", new_count);
109*437bfbebSnyanmisaka             return -1;
110*437bfbebSnyanmisaka         }
111*437bfbebSnyanmisaka 
112*437bfbebSnyanmisaka         /* NOTE: new memory should be memset to zero */
113*437bfbebSnyanmisaka         memset(new_nodes + old_count, 0, sizeof(*new_nodes) * old_count);
114*437bfbebSnyanmisaka 
115*437bfbebSnyanmisaka         trie_dbg_cnt("trie %p enlarge node %p:%d -> %p:%d\n",
116*437bfbebSnyanmisaka                      trie, trie->nodes, trie->node_count, new_nodes, new_count);
117*437bfbebSnyanmisaka 
118*437bfbebSnyanmisaka         trie->nodes = new_nodes;
119*437bfbebSnyanmisaka         trie->node_count = new_count;
120*437bfbebSnyanmisaka     }
121*437bfbebSnyanmisaka 
122*437bfbebSnyanmisaka     idx = trie->node_used++;
123*437bfbebSnyanmisaka     node = &trie->nodes[idx];
124*437bfbebSnyanmisaka     node->idx = idx;
125*437bfbebSnyanmisaka     node->prev = (prev > 0) ? prev : 0;
126*437bfbebSnyanmisaka     node->key = key;
127*437bfbebSnyanmisaka     node->id = INVALID_NODE_ID;
128*437bfbebSnyanmisaka 
129*437bfbebSnyanmisaka     if (prev >= 0)
130*437bfbebSnyanmisaka         trie->nodes[prev].next_cnt++;
131*437bfbebSnyanmisaka 
132*437bfbebSnyanmisaka     trie_dbg_cnt("get node %d\n", idx);
133*437bfbebSnyanmisaka 
134*437bfbebSnyanmisaka     return idx;
135*437bfbebSnyanmisaka }
136*437bfbebSnyanmisaka 
trie_prepare_buf(MppTrieImpl * p,rk_s32 info_size)137*437bfbebSnyanmisaka static rk_s32 trie_prepare_buf(MppTrieImpl *p, rk_s32 info_size)
138*437bfbebSnyanmisaka {
139*437bfbebSnyanmisaka     if (p->info_count >= MPP_TRIE_INFO_MAX) {
140*437bfbebSnyanmisaka         mpp_loge_f("invalid trie info count %d larger than max %d\n",
141*437bfbebSnyanmisaka                    p->info_count, MPP_TRIE_INFO_MAX);
142*437bfbebSnyanmisaka         return rk_nok;
143*437bfbebSnyanmisaka     }
144*437bfbebSnyanmisaka 
145*437bfbebSnyanmisaka     /* check and enlarge info buffer */
146*437bfbebSnyanmisaka     if (p->info_buf_pos + info_size > p->info_buf_size) {
147*437bfbebSnyanmisaka         rk_s32 old_size = p->info_buf_size;
148*437bfbebSnyanmisaka         rk_s32 new_size = old_size * 2;
149*437bfbebSnyanmisaka         void *ptr = mpp_realloc(p->info_buf, void, new_size);
150*437bfbebSnyanmisaka 
151*437bfbebSnyanmisaka         if (!ptr) {
152*437bfbebSnyanmisaka             mpp_loge_f("failed to realloc new info buffer %d\n", new_size);
153*437bfbebSnyanmisaka             return rk_nok;
154*437bfbebSnyanmisaka         }
155*437bfbebSnyanmisaka 
156*437bfbebSnyanmisaka         trie_dbg_cnt("trie %p enlarge info_buf %p:%d -> %p:%d\n",
157*437bfbebSnyanmisaka                      p, p->info_buf, old_size, ptr, new_size);
158*437bfbebSnyanmisaka 
159*437bfbebSnyanmisaka         p->info_buf = ptr;
160*437bfbebSnyanmisaka         p->info_buf_size = new_size;
161*437bfbebSnyanmisaka     }
162*437bfbebSnyanmisaka 
163*437bfbebSnyanmisaka     return rk_ok;
164*437bfbebSnyanmisaka }
165*437bfbebSnyanmisaka 
trie_pave_node(MppTrieImpl * p,const char * name,rk_s32 str_len)166*437bfbebSnyanmisaka static rk_s32 trie_pave_node(MppTrieImpl *p, const char *name, rk_s32 str_len)
167*437bfbebSnyanmisaka {
168*437bfbebSnyanmisaka     MppTrieNode *node = NULL;
169*437bfbebSnyanmisaka     const char *s = name;
170*437bfbebSnyanmisaka     rk_s32 next = 0;
171*437bfbebSnyanmisaka     rk_s32 idx = 0;
172*437bfbebSnyanmisaka     rk_s32 i;
173*437bfbebSnyanmisaka 
174*437bfbebSnyanmisaka     trie_dbg_pave("trie %p add info %s len %d\n", p, s, str_len);
175*437bfbebSnyanmisaka 
176*437bfbebSnyanmisaka     for (i = 0; i < str_len && s[i]; i++) {
177*437bfbebSnyanmisaka         rk_u32 key = s[i];
178*437bfbebSnyanmisaka         rk_s32 key0 = (key >> 4) & 0xf;
179*437bfbebSnyanmisaka         rk_s32 key1 = (key >> 0) & 0xf;
180*437bfbebSnyanmisaka 
181*437bfbebSnyanmisaka         node = p->nodes + idx;
182*437bfbebSnyanmisaka         next = node->next[key0];
183*437bfbebSnyanmisaka 
184*437bfbebSnyanmisaka         trie_dbg_pave("trie %p add %s at %2d char %c:%3d:%x:%x node %d -> %d\n",
185*437bfbebSnyanmisaka                       p, name, i, key, key, key0, key1, idx, next);
186*437bfbebSnyanmisaka 
187*437bfbebSnyanmisaka         if (!next) {
188*437bfbebSnyanmisaka             next = trie_get_node(p, idx, key0);
189*437bfbebSnyanmisaka             if (next < 0)
190*437bfbebSnyanmisaka                 return next;
191*437bfbebSnyanmisaka 
192*437bfbebSnyanmisaka             /* realloc may cause memory address change */
193*437bfbebSnyanmisaka             node = p->nodes + idx;
194*437bfbebSnyanmisaka             node->next[key0] = next;
195*437bfbebSnyanmisaka 
196*437bfbebSnyanmisaka             trie_dbg_pave("trie %p add %s at %2d char %c:%3d node %d -> %d as new key0\n",
197*437bfbebSnyanmisaka                           p, name, i, key, key, node->idx, next);
198*437bfbebSnyanmisaka         }
199*437bfbebSnyanmisaka 
200*437bfbebSnyanmisaka         idx = next;
201*437bfbebSnyanmisaka         node = p->nodes + idx;
202*437bfbebSnyanmisaka         next = node->next[key1];
203*437bfbebSnyanmisaka 
204*437bfbebSnyanmisaka         trie_dbg_pave("trie %p add %s at %2d char %c:%3d:%x:%x node %d -> %d as key0\n",
205*437bfbebSnyanmisaka                       p, s, i, key, key, key0, key1, idx, next);
206*437bfbebSnyanmisaka 
207*437bfbebSnyanmisaka         if (!next) {
208*437bfbebSnyanmisaka             next = trie_get_node(p, idx, key1);
209*437bfbebSnyanmisaka             if (next < 0)
210*437bfbebSnyanmisaka                 return next;
211*437bfbebSnyanmisaka 
212*437bfbebSnyanmisaka             /* realloc may cause memory address change */
213*437bfbebSnyanmisaka             node = p->nodes + idx;
214*437bfbebSnyanmisaka             node->next[key1] = next;
215*437bfbebSnyanmisaka 
216*437bfbebSnyanmisaka             trie_dbg_pave("trie %p add %s at %2d char %c:%3d node %d -> %d as new child\n",
217*437bfbebSnyanmisaka                           p, name, i, key, key, node->idx, next);
218*437bfbebSnyanmisaka         }
219*437bfbebSnyanmisaka 
220*437bfbebSnyanmisaka         idx = next;
221*437bfbebSnyanmisaka 
222*437bfbebSnyanmisaka         trie_dbg_pave("trie %p add %s at %2d char %c:%3d:%x:%x node %d -> %d as key1\n",
223*437bfbebSnyanmisaka                       p, name, i, key, key, key0, key1, idx, next);
224*437bfbebSnyanmisaka     }
225*437bfbebSnyanmisaka 
226*437bfbebSnyanmisaka     return idx;
227*437bfbebSnyanmisaka }
228*437bfbebSnyanmisaka 
mpp_trie_init(MppTrie * trie,const char * name)229*437bfbebSnyanmisaka rk_s32 mpp_trie_init(MppTrie *trie, const char *name)
230*437bfbebSnyanmisaka {
231*437bfbebSnyanmisaka     MppTrieImpl *p;
232*437bfbebSnyanmisaka     rk_s32 name_len;
233*437bfbebSnyanmisaka     rk_s32 ret = rk_nok;
234*437bfbebSnyanmisaka 
235*437bfbebSnyanmisaka     if (!trie || !name) {
236*437bfbebSnyanmisaka         mpp_loge_f("invalid trie %p name %p\n", trie, name);
237*437bfbebSnyanmisaka         return ret;
238*437bfbebSnyanmisaka     }
239*437bfbebSnyanmisaka 
240*437bfbebSnyanmisaka     mpp_env_get_u32("mpp_trie_debug", &mpp_trie_debug, 0);
241*437bfbebSnyanmisaka 
242*437bfbebSnyanmisaka     name_len = strnlen(name, MPP_TRIE_NAME_MAX) + 1;
243*437bfbebSnyanmisaka     p = mpp_calloc_size(MppTrieImpl, sizeof(*p) + name_len);
244*437bfbebSnyanmisaka     if (!p) {
245*437bfbebSnyanmisaka         mpp_loge_f("create trie impl %s failed\n", name);
246*437bfbebSnyanmisaka         goto done;
247*437bfbebSnyanmisaka     }
248*437bfbebSnyanmisaka 
249*437bfbebSnyanmisaka     p->name = (char *)(p + 1);
250*437bfbebSnyanmisaka     p->name_len = name_len;
251*437bfbebSnyanmisaka     strncpy(p->name, name, name_len);
252*437bfbebSnyanmisaka 
253*437bfbebSnyanmisaka     p->node_count = DEFAULT_NODE_COUNT;
254*437bfbebSnyanmisaka     p->nodes = mpp_calloc(MppTrieNode, p->node_count);
255*437bfbebSnyanmisaka     if (!p->nodes) {
256*437bfbebSnyanmisaka         mpp_loge_f("create %d nodes failed\n", p->node_count);
257*437bfbebSnyanmisaka         goto done;
258*437bfbebSnyanmisaka     }
259*437bfbebSnyanmisaka 
260*437bfbebSnyanmisaka     p->info_buf_size = 4096;
261*437bfbebSnyanmisaka     p->info_buf = mpp_calloc(void, p->info_buf_size);
262*437bfbebSnyanmisaka     if (!p->info_buf) {
263*437bfbebSnyanmisaka         mpp_loge_f("failed to alloc %d info buffer\n", p->info_buf_size);
264*437bfbebSnyanmisaka         goto done;
265*437bfbebSnyanmisaka     }
266*437bfbebSnyanmisaka 
267*437bfbebSnyanmisaka     /* get node 0 as root node*/
268*437bfbebSnyanmisaka     trie_get_node(p, -1, 0);
269*437bfbebSnyanmisaka 
270*437bfbebSnyanmisaka     ret = rk_ok;
271*437bfbebSnyanmisaka 
272*437bfbebSnyanmisaka done:
273*437bfbebSnyanmisaka     if (ret && p) {
274*437bfbebSnyanmisaka         MPP_FREE(p->info_buf);
275*437bfbebSnyanmisaka         MPP_FREE(p->nodes);
276*437bfbebSnyanmisaka         MPP_FREE(p);
277*437bfbebSnyanmisaka     }
278*437bfbebSnyanmisaka 
279*437bfbebSnyanmisaka     *trie = p;
280*437bfbebSnyanmisaka     return ret;
281*437bfbebSnyanmisaka }
282*437bfbebSnyanmisaka 
mpp_trie_init_by_root(MppTrie * trie,void * root)283*437bfbebSnyanmisaka rk_s32 mpp_trie_init_by_root(MppTrie *trie, void *root)
284*437bfbebSnyanmisaka {
285*437bfbebSnyanmisaka     MppTrieImpl *p;
286*437bfbebSnyanmisaka     MppTrieInfo *info;
287*437bfbebSnyanmisaka     rk_s32 i;
288*437bfbebSnyanmisaka 
289*437bfbebSnyanmisaka     if (!trie || !root) {
290*437bfbebSnyanmisaka         mpp_loge_f("invalid trie %p root %p\n", trie, root);
291*437bfbebSnyanmisaka         return rk_nok;
292*437bfbebSnyanmisaka     }
293*437bfbebSnyanmisaka 
294*437bfbebSnyanmisaka     *trie = NULL;
295*437bfbebSnyanmisaka     p = mpp_calloc(MppTrieImpl, 1);
296*437bfbebSnyanmisaka     if (!p) {
297*437bfbebSnyanmisaka         mpp_loge_f("create trie impl failed\n");
298*437bfbebSnyanmisaka         return rk_nok;
299*437bfbebSnyanmisaka     }
300*437bfbebSnyanmisaka 
301*437bfbebSnyanmisaka     info = mpp_trie_get_info_from_root(root, "__name__");
302*437bfbebSnyanmisaka     if (info)
303*437bfbebSnyanmisaka         p->name = mpp_trie_info_ctx(info);
304*437bfbebSnyanmisaka 
305*437bfbebSnyanmisaka     info = mpp_trie_get_info_from_root(root, "__node__");
306*437bfbebSnyanmisaka     if (info)
307*437bfbebSnyanmisaka         p->node_used = *(rk_u32 *)mpp_trie_info_ctx(info);
308*437bfbebSnyanmisaka 
309*437bfbebSnyanmisaka     info = mpp_trie_get_info_from_root(root, "__info__");
310*437bfbebSnyanmisaka     if (info)
311*437bfbebSnyanmisaka         p->info_count = *(rk_u32 *)mpp_trie_info_ctx(info);
312*437bfbebSnyanmisaka 
313*437bfbebSnyanmisaka     /* import and update new buffer */
314*437bfbebSnyanmisaka     p->nodes = (MppTrieNode *)root;
315*437bfbebSnyanmisaka 
316*437bfbebSnyanmisaka     if (mpp_trie_debug & MPP_TRIE_DBG_IMPORT)
317*437bfbebSnyanmisaka         mpp_trie_dump(p, "root import");
318*437bfbebSnyanmisaka 
319*437bfbebSnyanmisaka     info = mpp_trie_get_info_first(p);
320*437bfbebSnyanmisaka 
321*437bfbebSnyanmisaka     for (i = 0; i < p->info_count; i++) {
322*437bfbebSnyanmisaka         const char *name = mpp_trie_info_name(info);
323*437bfbebSnyanmisaka         MppTrieInfo *info_set = info;
324*437bfbebSnyanmisaka         MppTrieInfo *info_ret = mpp_trie_get_info(p, name);
325*437bfbebSnyanmisaka 
326*437bfbebSnyanmisaka         info = mpp_trie_get_info_next(p, info);
327*437bfbebSnyanmisaka 
328*437bfbebSnyanmisaka         if (info_ret && info_set == info_ret && info_ret->index == i)
329*437bfbebSnyanmisaka             continue;
330*437bfbebSnyanmisaka 
331*437bfbebSnyanmisaka         mpp_loge_f("trie check on import found mismatch info %s [%d:%p] - [%d:%p]\n",
332*437bfbebSnyanmisaka                    name, i, info_set, info_ret ? info_ret->index : -1, info_ret);
333*437bfbebSnyanmisaka         return rk_nok;
334*437bfbebSnyanmisaka     }
335*437bfbebSnyanmisaka 
336*437bfbebSnyanmisaka     *trie = p;
337*437bfbebSnyanmisaka 
338*437bfbebSnyanmisaka     return rk_ok;
339*437bfbebSnyanmisaka }
340*437bfbebSnyanmisaka 
mpp_trie_deinit(MppTrie trie)341*437bfbebSnyanmisaka rk_s32 mpp_trie_deinit(MppTrie trie)
342*437bfbebSnyanmisaka {
343*437bfbebSnyanmisaka     if (trie) {
344*437bfbebSnyanmisaka         MppTrieImpl *p = (MppTrieImpl *)trie;
345*437bfbebSnyanmisaka 
346*437bfbebSnyanmisaka         /* NOTE: do not remvoe imported root */
347*437bfbebSnyanmisaka         if (p->node_count)
348*437bfbebSnyanmisaka             mpp_free(p->nodes);
349*437bfbebSnyanmisaka         else
350*437bfbebSnyanmisaka             p->nodes = NULL;
351*437bfbebSnyanmisaka 
352*437bfbebSnyanmisaka         MPP_FREE(p->info_buf);
353*437bfbebSnyanmisaka         MPP_FREE(p);
354*437bfbebSnyanmisaka         return rk_ok;
355*437bfbebSnyanmisaka     }
356*437bfbebSnyanmisaka 
357*437bfbebSnyanmisaka     return rk_nok;
358*437bfbebSnyanmisaka }
359*437bfbebSnyanmisaka 
mpp_trie_walk(MppTrieWalk * p,rk_s32 idx,rk_u32 key,rk_u32 keyx,rk_u32 end)360*437bfbebSnyanmisaka static rk_s32 mpp_trie_walk(MppTrieWalk *p, rk_s32 idx, rk_u32 key, rk_u32 keyx, rk_u32 end)
361*437bfbebSnyanmisaka {
362*437bfbebSnyanmisaka     MppTrieNode *node = &p->root[idx];
363*437bfbebSnyanmisaka     char log_buf[128];
364*437bfbebSnyanmisaka     rk_u32 log_size = sizeof(log_buf) - 1;
365*437bfbebSnyanmisaka     rk_u32 log_len = 0;
366*437bfbebSnyanmisaka     rk_u32 log_en = (mpp_trie_debug & MPP_TRIE_DBG_WALK) ? 1 : 0;
367*437bfbebSnyanmisaka     rk_s32 next = -1;
368*437bfbebSnyanmisaka 
369*437bfbebSnyanmisaka     if (log_en)
370*437bfbebSnyanmisaka         log_len += snprintf(log_buf + log_len, log_size - log_len,
371*437bfbebSnyanmisaka                             "node %d:%d key %02x:%x -> ",
372*437bfbebSnyanmisaka                             node->idx, node->id, key, keyx);
373*437bfbebSnyanmisaka 
374*437bfbebSnyanmisaka     /* check high 4 bits */
375*437bfbebSnyanmisaka     if (!node->tag_len || p->match == node->idx) {
376*437bfbebSnyanmisaka         /* not tag or tag has be matched -> normal next switch node */
377*437bfbebSnyanmisaka         next = node->next[keyx];
378*437bfbebSnyanmisaka         if (log_en)
379*437bfbebSnyanmisaka             log_len += snprintf(log_buf + log_len, log_size - log_len,
380*437bfbebSnyanmisaka                                 "tag %s -> ",
381*437bfbebSnyanmisaka                                 !node->tag_len ? "n/a" : "match");
382*437bfbebSnyanmisaka         p->tag = 0;
383*437bfbebSnyanmisaka         p->len = 0;
384*437bfbebSnyanmisaka         p->match = -1;
385*437bfbebSnyanmisaka     } else {
386*437bfbebSnyanmisaka         /* with tag check len to fill or to stop */
387*437bfbebSnyanmisaka         rk_u64 val_new = (p->tag << 4) | keyx;
388*437bfbebSnyanmisaka         rk_s32 len_new = p->len + 1;
389*437bfbebSnyanmisaka 
390*437bfbebSnyanmisaka         if (log_en)
391*437bfbebSnyanmisaka             log_len += snprintf(log_buf + log_len, log_size - log_len,
392*437bfbebSnyanmisaka                                 "tag %0*llx:%d - st %0*llx:%d -> ",
393*437bfbebSnyanmisaka                                 node->tag_len, node->tag_val, node->tag_len,
394*437bfbebSnyanmisaka                                 node->tag_len, val_new, len_new);
395*437bfbebSnyanmisaka 
396*437bfbebSnyanmisaka         /* clear old matched node */
397*437bfbebSnyanmisaka         p->match = -1;
398*437bfbebSnyanmisaka         if (node->tag_len > len_new && !end) {
399*437bfbebSnyanmisaka             /* more tag to fill keep current node */
400*437bfbebSnyanmisaka             p->tag = val_new;
401*437bfbebSnyanmisaka             p->len = len_new;
402*437bfbebSnyanmisaka             next = node->idx;
403*437bfbebSnyanmisaka             if (log_en)
404*437bfbebSnyanmisaka                 log_len += snprintf(log_buf + log_len, log_size - log_len,
405*437bfbebSnyanmisaka                                     "fill -> ");
406*437bfbebSnyanmisaka         } else {
407*437bfbebSnyanmisaka             /* check tag match with new value */
408*437bfbebSnyanmisaka             p->tag = 0;
409*437bfbebSnyanmisaka             p->len = 0;
410*437bfbebSnyanmisaka 
411*437bfbebSnyanmisaka             if (node->tag_val != val_new) {
412*437bfbebSnyanmisaka                 if (log_en)
413*437bfbebSnyanmisaka                     log_len += snprintf(log_buf + log_len, log_size - log_len,
414*437bfbebSnyanmisaka                                         "mismatch -> ");
415*437bfbebSnyanmisaka                 next = INVALID_NODE_ID;
416*437bfbebSnyanmisaka             } else {
417*437bfbebSnyanmisaka                 if (log_en)
418*437bfbebSnyanmisaka                     log_len += snprintf(log_buf + log_len, log_size - log_len,
419*437bfbebSnyanmisaka                                         "match -> ");
420*437bfbebSnyanmisaka                 next = node->idx;
421*437bfbebSnyanmisaka                 p->match = node->idx;
422*437bfbebSnyanmisaka             }
423*437bfbebSnyanmisaka         }
424*437bfbebSnyanmisaka     }
425*437bfbebSnyanmisaka 
426*437bfbebSnyanmisaka     if (log_en) {
427*437bfbebSnyanmisaka         snprintf(log_buf + log_len, log_size - log_len, "%d", next);
428*437bfbebSnyanmisaka         mpp_logi_f("%s\n", log_buf);
429*437bfbebSnyanmisaka     }
430*437bfbebSnyanmisaka 
431*437bfbebSnyanmisaka     return next;
432*437bfbebSnyanmisaka }
433*437bfbebSnyanmisaka 
mpp_trie_get_node(MppTrieNode * root,const char * name)434*437bfbebSnyanmisaka static MppTrieNode *mpp_trie_get_node(MppTrieNode *root, const char *name)
435*437bfbebSnyanmisaka {
436*437bfbebSnyanmisaka     MppTrieNode *ret = NULL;
437*437bfbebSnyanmisaka     const char *s = name;
438*437bfbebSnyanmisaka     MppTrieWalk walk;
439*437bfbebSnyanmisaka     rk_s32 idx = 0;
440*437bfbebSnyanmisaka 
441*437bfbebSnyanmisaka     if (!root || !name) {
442*437bfbebSnyanmisaka         mpp_err_f("invalid root %p name %p\n", root, name);
443*437bfbebSnyanmisaka         return NULL;
444*437bfbebSnyanmisaka     }
445*437bfbebSnyanmisaka 
446*437bfbebSnyanmisaka     trie_dbg_get("root %p search %s start\n", root, name);
447*437bfbebSnyanmisaka 
448*437bfbebSnyanmisaka     walk.root = root;
449*437bfbebSnyanmisaka     walk.tag = 0;
450*437bfbebSnyanmisaka     walk.len = 0;
451*437bfbebSnyanmisaka     walk.match = 0;
452*437bfbebSnyanmisaka 
453*437bfbebSnyanmisaka     do {
454*437bfbebSnyanmisaka         char key = *s++;
455*437bfbebSnyanmisaka         rk_u32 key0 = (key >> 4) & 0xf;
456*437bfbebSnyanmisaka         rk_u32 key1 = key & 0xf;
457*437bfbebSnyanmisaka         rk_u32 end = s[0] == '\0';
458*437bfbebSnyanmisaka 
459*437bfbebSnyanmisaka         idx = mpp_trie_walk(&walk, idx, key, key0, 0);
460*437bfbebSnyanmisaka         if (idx < 0)
461*437bfbebSnyanmisaka             break;
462*437bfbebSnyanmisaka 
463*437bfbebSnyanmisaka         idx = mpp_trie_walk(&walk, idx, key, key1, end);
464*437bfbebSnyanmisaka         if (idx < 0 || end)
465*437bfbebSnyanmisaka             break;
466*437bfbebSnyanmisaka     } while (1);
467*437bfbebSnyanmisaka 
468*437bfbebSnyanmisaka     ret = (idx >= 0) ? &root[idx] : NULL;
469*437bfbebSnyanmisaka 
470*437bfbebSnyanmisaka     trie_dbg_get("get %s ret node %d:%d\n", name, idx, ret ? ret->id : INVALID_NODE_ID);
471*437bfbebSnyanmisaka 
472*437bfbebSnyanmisaka     return ret;
473*437bfbebSnyanmisaka }
474*437bfbebSnyanmisaka 
mpp_trie_check(MppTrie trie,const char * log)475*437bfbebSnyanmisaka static rk_s32 mpp_trie_check(MppTrie trie, const char *log)
476*437bfbebSnyanmisaka {
477*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
478*437bfbebSnyanmisaka     char *base = p->info_buf;
479*437bfbebSnyanmisaka     rk_s32 info_size = 0;
480*437bfbebSnyanmisaka     rk_s32 pos = 0;
481*437bfbebSnyanmisaka     rk_s32 i;
482*437bfbebSnyanmisaka 
483*437bfbebSnyanmisaka     for (i = 0; i < p->info_count; i++, pos += info_size) {
484*437bfbebSnyanmisaka         MppTrieInfo *info = (MppTrieInfo *)(base + pos);
485*437bfbebSnyanmisaka         const char *name = (const char *)(info + 1);
486*437bfbebSnyanmisaka         MppTrieNode *node = mpp_trie_get_node(p->nodes, name);
487*437bfbebSnyanmisaka 
488*437bfbebSnyanmisaka         info_size = sizeof(*info) + info->str_len + info->ctx_len;
489*437bfbebSnyanmisaka 
490*437bfbebSnyanmisaka         if (node && node->id >= 0 && node->id == pos)
491*437bfbebSnyanmisaka             continue;
492*437bfbebSnyanmisaka 
493*437bfbebSnyanmisaka         mpp_loge("trie check on %s found mismatch info %s %d - %d\n",
494*437bfbebSnyanmisaka                  log, name, i, node ? node->id : -1);
495*437bfbebSnyanmisaka         return rk_nok;
496*437bfbebSnyanmisaka     }
497*437bfbebSnyanmisaka 
498*437bfbebSnyanmisaka     return rk_ok;
499*437bfbebSnyanmisaka }
500*437bfbebSnyanmisaka 
mpp_trie_last_info(MppTrie trie)501*437bfbebSnyanmisaka rk_s32 mpp_trie_last_info(MppTrie trie)
502*437bfbebSnyanmisaka {
503*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
504*437bfbebSnyanmisaka     MppTrieNode *root;
505*437bfbebSnyanmisaka     MppTrieNode *node;
506*437bfbebSnyanmisaka     char *buf;
507*437bfbebSnyanmisaka     rk_s32 node_count;
508*437bfbebSnyanmisaka     rk_s32 node_valid;
509*437bfbebSnyanmisaka     rk_s32 nodes_size;
510*437bfbebSnyanmisaka     rk_s32 len = 0;
511*437bfbebSnyanmisaka     rk_s32 pos = 0;
512*437bfbebSnyanmisaka     rk_s32 i;
513*437bfbebSnyanmisaka     rk_s32 j;
514*437bfbebSnyanmisaka 
515*437bfbebSnyanmisaka     if (!trie) {
516*437bfbebSnyanmisaka         mpp_loge_f("invalid NULL trie\n");
517*437bfbebSnyanmisaka         return rk_nok;
518*437bfbebSnyanmisaka     }
519*437bfbebSnyanmisaka 
520*437bfbebSnyanmisaka     /* write trie self entry info */
521*437bfbebSnyanmisaka     pos = p->info_count + 3;
522*437bfbebSnyanmisaka     mpp_trie_add_info(trie, "__name__", p->name, p->name_len);
523*437bfbebSnyanmisaka     mpp_trie_add_info(trie, "__info__", &pos, sizeof(pos));
524*437bfbebSnyanmisaka     /* NOTE: node count need to be update after shrinking */
525*437bfbebSnyanmisaka     mpp_trie_add_info(trie, "__node__", &p->node_used, sizeof(p->node_used));
526*437bfbebSnyanmisaka 
527*437bfbebSnyanmisaka     root = p->nodes;
528*437bfbebSnyanmisaka     node_count = p->node_used;
529*437bfbebSnyanmisaka     node_valid = node_count;
530*437bfbebSnyanmisaka 
531*437bfbebSnyanmisaka     trie_dbg_last("shrink trie node start node %d info %d\n", node_count, p->info_count);
532*437bfbebSnyanmisaka 
533*437bfbebSnyanmisaka     if (mpp_trie_debug & MPP_TRIE_DBG_LAST_STEP)
534*437bfbebSnyanmisaka         mpp_trie_dump_f(trie);
535*437bfbebSnyanmisaka 
536*437bfbebSnyanmisaka     for (i = node_count - 1; i > 0; i--) {
537*437bfbebSnyanmisaka         MppTrieNode *prev;
538*437bfbebSnyanmisaka         rk_s32 prev_idx;
539*437bfbebSnyanmisaka 
540*437bfbebSnyanmisaka         node = &root[i];
541*437bfbebSnyanmisaka         prev_idx = node->prev;
542*437bfbebSnyanmisaka         prev = &root[prev_idx];
543*437bfbebSnyanmisaka 
544*437bfbebSnyanmisaka         if (prev->next_cnt > 1) {
545*437bfbebSnyanmisaka             trie_dbg_last("node %d:%d prev %d next count %d stop shrinking for multi next\n",
546*437bfbebSnyanmisaka                           i, node->id, prev_idx, prev->next_cnt);
547*437bfbebSnyanmisaka             continue;
548*437bfbebSnyanmisaka         }
549*437bfbebSnyanmisaka 
550*437bfbebSnyanmisaka         if (node->tag_len >= (rk_s16)MPP_TRIE_TAG_LEN_MAX) {
551*437bfbebSnyanmisaka             trie_dbg_last("node %d:%d tag %d - %016llx stop shrinking for max tag len\n",
552*437bfbebSnyanmisaka                           i, node->id, node->tag_len, node->tag_val);
553*437bfbebSnyanmisaka             continue;
554*437bfbebSnyanmisaka         }
555*437bfbebSnyanmisaka 
556*437bfbebSnyanmisaka         if (prev->id >= 0) {
557*437bfbebSnyanmisaka             trie_dbg_last("node %d:%d tag %d - %016llx stop shrinking for valid info node\n",
558*437bfbebSnyanmisaka                           i, node->id, node->tag_len, node->tag_val);
559*437bfbebSnyanmisaka             continue;
560*437bfbebSnyanmisaka         }
561*437bfbebSnyanmisaka 
562*437bfbebSnyanmisaka         prev->id = node->id;
563*437bfbebSnyanmisaka         /* NOTE: do NOT increase tag length on root node */
564*437bfbebSnyanmisaka         prev->tag_len = node->tag_len + 1;
565*437bfbebSnyanmisaka         prev->tag_val = ((rk_u64)node->key << (node->tag_len * 4)) | node->tag_val;
566*437bfbebSnyanmisaka         prev->next_cnt = node->next_cnt;
567*437bfbebSnyanmisaka         memcpy(prev->next, node->next, sizeof(node->next));
568*437bfbebSnyanmisaka 
569*437bfbebSnyanmisaka         trie_dbg_last("node %d:%d shrink prev %d key %x tag %016llx -> %016llx\n",
570*437bfbebSnyanmisaka                       i, node->id, prev->idx, prev->key, node->tag_val, prev->tag_val);
571*437bfbebSnyanmisaka 
572*437bfbebSnyanmisaka         for (j = 0; j < MPP_TRIE_KEY_MAX; j++) {
573*437bfbebSnyanmisaka             if (!prev->next[j])
574*437bfbebSnyanmisaka                 continue;
575*437bfbebSnyanmisaka 
576*437bfbebSnyanmisaka             root[prev->next[j]].prev = prev_idx;
577*437bfbebSnyanmisaka         }
578*437bfbebSnyanmisaka 
579*437bfbebSnyanmisaka         memset(node, 0, sizeof(*node));
580*437bfbebSnyanmisaka         node->id = INVALID_NODE_ID;
581*437bfbebSnyanmisaka         node_valid--;
582*437bfbebSnyanmisaka     }
583*437bfbebSnyanmisaka 
584*437bfbebSnyanmisaka     trie_dbg_last("shrink trie node finish count %d -> %d\n", node_count, node_valid);
585*437bfbebSnyanmisaka 
586*437bfbebSnyanmisaka     if (mpp_trie_debug & MPP_TRIE_DBG_LAST_STEP)
587*437bfbebSnyanmisaka         mpp_trie_dump_f(trie);
588*437bfbebSnyanmisaka 
589*437bfbebSnyanmisaka     if (mpp_trie_debug & MPP_TRIE_DBG_LAST_CHECK)
590*437bfbebSnyanmisaka         mpp_trie_check(trie, "shrink merge tag stage");
591*437bfbebSnyanmisaka 
592*437bfbebSnyanmisaka     trie_dbg_last("move trie node start to reduce memory %d -> %d\n", node_count, node_valid);
593*437bfbebSnyanmisaka 
594*437bfbebSnyanmisaka     for (i = 1; i < node_valid; i++) {
595*437bfbebSnyanmisaka         node = &root[i];
596*437bfbebSnyanmisaka 
597*437bfbebSnyanmisaka         /* skip valid node */
598*437bfbebSnyanmisaka         if (node->idx)
599*437bfbebSnyanmisaka             continue;
600*437bfbebSnyanmisaka 
601*437bfbebSnyanmisaka         for (j = i; j < node_count; j++) {
602*437bfbebSnyanmisaka             MppTrieNode *tmp = &root[j];
603*437bfbebSnyanmisaka             MppTrieNode *prev;
604*437bfbebSnyanmisaka             rk_s32 k;
605*437bfbebSnyanmisaka 
606*437bfbebSnyanmisaka             /* skip empty node */
607*437bfbebSnyanmisaka             if (!tmp->idx)
608*437bfbebSnyanmisaka                 continue;
609*437bfbebSnyanmisaka 
610*437bfbebSnyanmisaka             trie_dbg_last("move node %d to %d prev %d\n", j, i, tmp->prev);
611*437bfbebSnyanmisaka 
612*437bfbebSnyanmisaka             prev = &root[tmp->prev];
613*437bfbebSnyanmisaka 
614*437bfbebSnyanmisaka             /* relink previous node */
615*437bfbebSnyanmisaka             for (k = 0; k < MPP_TRIE_KEY_MAX; k++) {
616*437bfbebSnyanmisaka                 if (prev->next[k] != tmp->idx)
617*437bfbebSnyanmisaka                     continue;
618*437bfbebSnyanmisaka 
619*437bfbebSnyanmisaka                 prev->next[k] = i;
620*437bfbebSnyanmisaka                 break;
621*437bfbebSnyanmisaka             }
622*437bfbebSnyanmisaka 
623*437bfbebSnyanmisaka             memcpy(node, tmp, sizeof(*node));
624*437bfbebSnyanmisaka             node->idx = i;
625*437bfbebSnyanmisaka             memset(tmp, 0, sizeof(*tmp));
626*437bfbebSnyanmisaka 
627*437bfbebSnyanmisaka             /* relink next node */
628*437bfbebSnyanmisaka             for (k = 0; k < MPP_TRIE_KEY_MAX; k++) {
629*437bfbebSnyanmisaka                 if (!node->next[k])
630*437bfbebSnyanmisaka                     continue;
631*437bfbebSnyanmisaka 
632*437bfbebSnyanmisaka                 root[node->next[k]].prev = i;
633*437bfbebSnyanmisaka             }
634*437bfbebSnyanmisaka 
635*437bfbebSnyanmisaka             break;
636*437bfbebSnyanmisaka         }
637*437bfbebSnyanmisaka     }
638*437bfbebSnyanmisaka 
639*437bfbebSnyanmisaka     p->node_used = node_valid;
640*437bfbebSnyanmisaka 
641*437bfbebSnyanmisaka     trie_dbg_last("move trie node finish used %d\n", p->node_used);
642*437bfbebSnyanmisaka 
643*437bfbebSnyanmisaka     if (mpp_trie_debug & MPP_TRIE_DBG_LAST_STEP)
644*437bfbebSnyanmisaka         mpp_trie_dump_f(trie);
645*437bfbebSnyanmisaka 
646*437bfbebSnyanmisaka     if (mpp_trie_debug & MPP_TRIE_DBG_LAST_CHECK)
647*437bfbebSnyanmisaka         mpp_trie_check(trie, "shrink move node stage");
648*437bfbebSnyanmisaka 
649*437bfbebSnyanmisaka     trie_dbg_last("create user buffer start\n");
650*437bfbebSnyanmisaka 
651*437bfbebSnyanmisaka     nodes_size = sizeof(MppTrieNode) * p->node_used;
652*437bfbebSnyanmisaka     p->buf_size = nodes_size + p->info_buf_pos;
653*437bfbebSnyanmisaka     p->buf_size = MPP_ALIGN(p->buf_size, sizeof(void *));
654*437bfbebSnyanmisaka 
655*437bfbebSnyanmisaka     buf = mpp_calloc(char, p->buf_size);
656*437bfbebSnyanmisaka     if (!buf) {
657*437bfbebSnyanmisaka         mpp_loge("failed to alloc trie buffer size %d\n", p->buf_size);
658*437bfbebSnyanmisaka         return rk_nok;
659*437bfbebSnyanmisaka     }
660*437bfbebSnyanmisaka 
661*437bfbebSnyanmisaka     p->nodes = (MppTrieNode *)buf;
662*437bfbebSnyanmisaka     memcpy(p->nodes, root, nodes_size);
663*437bfbebSnyanmisaka     pos = nodes_size;
664*437bfbebSnyanmisaka     len = 0;
665*437bfbebSnyanmisaka 
666*437bfbebSnyanmisaka     for (i = 0; i < p->info_count; i++) {
667*437bfbebSnyanmisaka         MppTrieInfo *src = (MppTrieInfo *)(p->info_buf + len);
668*437bfbebSnyanmisaka         MppTrieInfo *dst = (MppTrieInfo *)(buf + pos);
669*437bfbebSnyanmisaka         rk_s32 info_size = sizeof(MppTrieInfo) + src->str_len + src->ctx_len;
670*437bfbebSnyanmisaka         const char *name = (char *)(src + 1);
671*437bfbebSnyanmisaka 
672*437bfbebSnyanmisaka         node = mpp_trie_get_node(p->nodes, name);
673*437bfbebSnyanmisaka         node->id = pos;
674*437bfbebSnyanmisaka 
675*437bfbebSnyanmisaka         memcpy(dst, src, info_size);
676*437bfbebSnyanmisaka         pos += info_size;
677*437bfbebSnyanmisaka         len += info_size;
678*437bfbebSnyanmisaka     }
679*437bfbebSnyanmisaka 
680*437bfbebSnyanmisaka     MPP_FREE(root);
681*437bfbebSnyanmisaka     MPP_FREE(p->info_buf);
682*437bfbebSnyanmisaka 
683*437bfbebSnyanmisaka     /* NOTE: udpate final shrinked node count */
684*437bfbebSnyanmisaka     {
685*437bfbebSnyanmisaka         MppTrieInfo *info = mpp_trie_get_info_from_root(p->nodes, "__node__");
686*437bfbebSnyanmisaka 
687*437bfbebSnyanmisaka         if (info)
688*437bfbebSnyanmisaka             *(rk_u32 *)mpp_trie_info_ctx(info) = p->node_used;
689*437bfbebSnyanmisaka     }
690*437bfbebSnyanmisaka 
691*437bfbebSnyanmisaka     return rk_ok;
692*437bfbebSnyanmisaka }
693*437bfbebSnyanmisaka 
mpp_trie_add_info(MppTrie trie,const char * name,void * ctx,rk_u32 ctx_len)694*437bfbebSnyanmisaka rk_s32 mpp_trie_add_info(MppTrie trie, const char *name, void *ctx, rk_u32 ctx_len)
695*437bfbebSnyanmisaka {
696*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
697*437bfbebSnyanmisaka     rk_s32 info_size;
698*437bfbebSnyanmisaka     rk_u32 ctx_real;
699*437bfbebSnyanmisaka     rk_s32 str_real;
700*437bfbebSnyanmisaka     rk_s32 str_len;
701*437bfbebSnyanmisaka     rk_s32 idx;
702*437bfbebSnyanmisaka 
703*437bfbebSnyanmisaka     if (!p) {
704*437bfbebSnyanmisaka         mpp_loge_f("invalid trie %p name %s ctx %p\n", p, name, ctx);
705*437bfbebSnyanmisaka         return rk_nok;
706*437bfbebSnyanmisaka     }
707*437bfbebSnyanmisaka 
708*437bfbebSnyanmisaka     if (!name)
709*437bfbebSnyanmisaka         return mpp_trie_last_info(p);
710*437bfbebSnyanmisaka 
711*437bfbebSnyanmisaka     str_real = strnlen(name, MPP_TRIE_NAME_MAX) + 1;
712*437bfbebSnyanmisaka     str_len = MPP_ALIGN(str_real, 4);
713*437bfbebSnyanmisaka     /* NOTE: align all ctx_len to four bytes */
714*437bfbebSnyanmisaka     ctx_real = ctx_len;
715*437bfbebSnyanmisaka     ctx_len = MPP_ALIGN(ctx_real, 4);
716*437bfbebSnyanmisaka     info_size = sizeof(MppTrieInfo) + str_len + ctx_len;
717*437bfbebSnyanmisaka 
718*437bfbebSnyanmisaka     if (str_len >= MPP_TRIE_NAME_MAX) {
719*437bfbebSnyanmisaka         mpp_loge_f("invalid trie name %s len %d larger than max %d\n",
720*437bfbebSnyanmisaka                    name, str_len, MPP_TRIE_NAME_MAX);
721*437bfbebSnyanmisaka         return rk_nok;
722*437bfbebSnyanmisaka     }
723*437bfbebSnyanmisaka 
724*437bfbebSnyanmisaka     if (trie_prepare_buf(p, info_size))
725*437bfbebSnyanmisaka         return rk_nok;
726*437bfbebSnyanmisaka 
727*437bfbebSnyanmisaka     idx = trie_pave_node(p, name, str_real);
728*437bfbebSnyanmisaka     if (idx < 0) {
729*437bfbebSnyanmisaka         mpp_loge_f("trie %p pave node %s failed\n", p, name);
730*437bfbebSnyanmisaka         return rk_nok;
731*437bfbebSnyanmisaka     }
732*437bfbebSnyanmisaka     if (p->nodes[idx].id != -1) {
733*437bfbebSnyanmisaka         mpp_loge_f("trie %p add info %s already exist\n", p, name);
734*437bfbebSnyanmisaka         return rk_nok;
735*437bfbebSnyanmisaka     }
736*437bfbebSnyanmisaka 
737*437bfbebSnyanmisaka     p->nodes[idx].id = p->info_buf_pos;
738*437bfbebSnyanmisaka     if (p->info_name_max < str_real - 1)
739*437bfbebSnyanmisaka         p->info_name_max = str_real - 1;
740*437bfbebSnyanmisaka 
741*437bfbebSnyanmisaka     {
742*437bfbebSnyanmisaka         MppTrieInfo *info = (MppTrieInfo *)(p->info_buf + p->info_buf_pos);
743*437bfbebSnyanmisaka         char *buf = (char *)(info + 1);
744*437bfbebSnyanmisaka 
745*437bfbebSnyanmisaka         info->index = p->info_count;
746*437bfbebSnyanmisaka         info->ctx_len = ctx_len;
747*437bfbebSnyanmisaka         info->str_len = str_len;
748*437bfbebSnyanmisaka 
749*437bfbebSnyanmisaka         memcpy(buf, name, str_real);
750*437bfbebSnyanmisaka         while (str_real < str_len)
751*437bfbebSnyanmisaka             buf[str_real++] = 0;
752*437bfbebSnyanmisaka 
753*437bfbebSnyanmisaka         buf += str_len;
754*437bfbebSnyanmisaka 
755*437bfbebSnyanmisaka         memcpy(buf, ctx, ctx_real);
756*437bfbebSnyanmisaka         while (ctx_real < ctx_len)
757*437bfbebSnyanmisaka             buf[ctx_real++] = 0;
758*437bfbebSnyanmisaka     }
759*437bfbebSnyanmisaka 
760*437bfbebSnyanmisaka     trie_dbg_set("trie %p add info %d - %s at node %d pos %d ctx %p size %d\n",
761*437bfbebSnyanmisaka                  p, p->info_count, name, idx, p->info_buf_pos, ctx, ctx_len);
762*437bfbebSnyanmisaka 
763*437bfbebSnyanmisaka     p->info_buf_pos += info_size;
764*437bfbebSnyanmisaka     p->info_count++;
765*437bfbebSnyanmisaka 
766*437bfbebSnyanmisaka     return rk_ok;
767*437bfbebSnyanmisaka }
768*437bfbebSnyanmisaka 
mpp_trie_get_node_count(MppTrie trie)769*437bfbebSnyanmisaka rk_s32 mpp_trie_get_node_count(MppTrie trie)
770*437bfbebSnyanmisaka {
771*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
772*437bfbebSnyanmisaka 
773*437bfbebSnyanmisaka     return (p) ? p->node_used : 0;
774*437bfbebSnyanmisaka }
775*437bfbebSnyanmisaka 
mpp_trie_get_info_count(MppTrie trie)776*437bfbebSnyanmisaka rk_s32 mpp_trie_get_info_count(MppTrie trie)
777*437bfbebSnyanmisaka {
778*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
779*437bfbebSnyanmisaka 
780*437bfbebSnyanmisaka     return (p) ? p->info_count : 0;
781*437bfbebSnyanmisaka }
782*437bfbebSnyanmisaka 
mpp_trie_get_buf_size(MppTrie trie)783*437bfbebSnyanmisaka rk_s32 mpp_trie_get_buf_size(MppTrie trie)
784*437bfbebSnyanmisaka {
785*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
786*437bfbebSnyanmisaka 
787*437bfbebSnyanmisaka     return (p) ? p->buf_size : 0;
788*437bfbebSnyanmisaka }
789*437bfbebSnyanmisaka 
mpp_trie_get_name_max(MppTrie trie)790*437bfbebSnyanmisaka rk_s32 mpp_trie_get_name_max(MppTrie trie)
791*437bfbebSnyanmisaka {
792*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
793*437bfbebSnyanmisaka 
794*437bfbebSnyanmisaka     return (p) ? p->info_name_max : 0;
795*437bfbebSnyanmisaka }
796*437bfbebSnyanmisaka 
mpp_trie_get_node_root(MppTrie trie)797*437bfbebSnyanmisaka void *mpp_trie_get_node_root(MppTrie trie)
798*437bfbebSnyanmisaka {
799*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
800*437bfbebSnyanmisaka 
801*437bfbebSnyanmisaka     return (p) ? p->nodes : NULL;
802*437bfbebSnyanmisaka }
803*437bfbebSnyanmisaka 
mpp_trie_get_info(MppTrie trie,const char * name)804*437bfbebSnyanmisaka MppTrieInfo *mpp_trie_get_info(MppTrie trie, const char *name)
805*437bfbebSnyanmisaka {
806*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
807*437bfbebSnyanmisaka     MppTrieNode *node;
808*437bfbebSnyanmisaka 
809*437bfbebSnyanmisaka     if (!trie || !name) {
810*437bfbebSnyanmisaka         mpp_err_f("invalid trie %p name %p\n", trie, name);
811*437bfbebSnyanmisaka         return NULL;
812*437bfbebSnyanmisaka     }
813*437bfbebSnyanmisaka 
814*437bfbebSnyanmisaka     node = mpp_trie_get_node(p->nodes, name);
815*437bfbebSnyanmisaka     if (!node || node->id < 0)
816*437bfbebSnyanmisaka         return NULL;
817*437bfbebSnyanmisaka 
818*437bfbebSnyanmisaka     return (MppTrieInfo *)(((char *)p->nodes) + node->id);
819*437bfbebSnyanmisaka }
820*437bfbebSnyanmisaka 
mpp_trie_get_info_first(MppTrie trie)821*437bfbebSnyanmisaka MppTrieInfo *mpp_trie_get_info_first(MppTrie trie)
822*437bfbebSnyanmisaka {
823*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
824*437bfbebSnyanmisaka 
825*437bfbebSnyanmisaka     return (p) ? (MppTrieInfo *)(((char *)p->nodes) + p->node_used * sizeof(MppTrieNode)) : NULL;
826*437bfbebSnyanmisaka }
827*437bfbebSnyanmisaka 
mpp_trie_get_info_next(MppTrie trie,MppTrieInfo * info)828*437bfbebSnyanmisaka MppTrieInfo *mpp_trie_get_info_next(MppTrie trie, MppTrieInfo *info)
829*437bfbebSnyanmisaka {
830*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
831*437bfbebSnyanmisaka 
832*437bfbebSnyanmisaka     if (!p || !info || info->index >= p->info_count - 1)
833*437bfbebSnyanmisaka         return NULL;
834*437bfbebSnyanmisaka 
835*437bfbebSnyanmisaka     return (MppTrieInfo *)((char *)(info + 1) + info->str_len + info->ctx_len);
836*437bfbebSnyanmisaka }
837*437bfbebSnyanmisaka 
mpp_trie_get_info_from_root(void * root,const char * name)838*437bfbebSnyanmisaka MppTrieInfo *mpp_trie_get_info_from_root(void *root, const char *name)
839*437bfbebSnyanmisaka {
840*437bfbebSnyanmisaka     MppTrieNode *node;
841*437bfbebSnyanmisaka 
842*437bfbebSnyanmisaka     if (!root || !name) {
843*437bfbebSnyanmisaka         mpp_loge_f("invalid root %p name %p\n", root, name);
844*437bfbebSnyanmisaka         return NULL;
845*437bfbebSnyanmisaka     }
846*437bfbebSnyanmisaka 
847*437bfbebSnyanmisaka     mpp_env_get_u32("mpp_trie_debug", &mpp_trie_debug, 0);
848*437bfbebSnyanmisaka 
849*437bfbebSnyanmisaka     node = mpp_trie_get_node((MppTrieNode *)root, name);
850*437bfbebSnyanmisaka     if (!node || node->id < 0)
851*437bfbebSnyanmisaka         return NULL;
852*437bfbebSnyanmisaka 
853*437bfbebSnyanmisaka     return (MppTrieInfo *)(((char *)root) + node->id);
854*437bfbebSnyanmisaka }
855*437bfbebSnyanmisaka 
mpp_trie_dump(MppTrie trie,const char * func)856*437bfbebSnyanmisaka void mpp_trie_dump(MppTrie trie, const char *func)
857*437bfbebSnyanmisaka {
858*437bfbebSnyanmisaka     MppTrieImpl *p = (MppTrieImpl *)trie;
859*437bfbebSnyanmisaka     char *base = p->info_buf ? (char *)p->info_buf : (char *)p->nodes;
860*437bfbebSnyanmisaka     rk_s32 i;
861*437bfbebSnyanmisaka     rk_s32 next_cnt[17];
862*437bfbebSnyanmisaka     rk_s32 tag_len[17];
863*437bfbebSnyanmisaka 
864*437bfbebSnyanmisaka     memset(next_cnt, 0, sizeof(next_cnt));
865*437bfbebSnyanmisaka     memset(tag_len, 0, sizeof(tag_len));
866*437bfbebSnyanmisaka 
867*437bfbebSnyanmisaka     mpp_logi("%s dumping trie %p\n", func, trie);
868*437bfbebSnyanmisaka     mpp_logi("name %s size %d node %d info %d\n",
869*437bfbebSnyanmisaka              p->name, p->buf_size, p->node_used, p->info_count);
870*437bfbebSnyanmisaka 
871*437bfbebSnyanmisaka     for (i = 0; i < p->node_used; i++) {
872*437bfbebSnyanmisaka         MppTrieNode *node = &p->nodes[i];
873*437bfbebSnyanmisaka         rk_s32 valid_count = 0;
874*437bfbebSnyanmisaka         rk_s32 j;
875*437bfbebSnyanmisaka 
876*437bfbebSnyanmisaka         if (i && !node->idx)
877*437bfbebSnyanmisaka             continue;
878*437bfbebSnyanmisaka 
879*437bfbebSnyanmisaka         if (node->id >= 0) {
880*437bfbebSnyanmisaka             MppTrieInfo *info = (MppTrieInfo *)((char *)base + node->id);
881*437bfbebSnyanmisaka 
882*437bfbebSnyanmisaka             /* check before and after last info */
883*437bfbebSnyanmisaka             if (node->id < (rk_s32)(p->node_used * sizeof(MppTrieNode)))
884*437bfbebSnyanmisaka                 mpp_logi("node %d key %x info %d - %s\n", node->idx, node->key, node->id,
885*437bfbebSnyanmisaka                          mpp_trie_info_name(info));
886*437bfbebSnyanmisaka             else
887*437bfbebSnyanmisaka                 mpp_logi("node %d key %x info %d - %s\n", node->idx, node->key, node->id,
888*437bfbebSnyanmisaka                          mpp_trie_info_name(info));
889*437bfbebSnyanmisaka         } else
890*437bfbebSnyanmisaka             mpp_logi("node %d key %x\n", node->idx, node->key);
891*437bfbebSnyanmisaka 
892*437bfbebSnyanmisaka         if (node->tag_len)
893*437bfbebSnyanmisaka             mpp_logi("    prev %d count %d tag %d - %llx\n", node->prev, node->next_cnt, node->tag_len, node->tag_val);
894*437bfbebSnyanmisaka         else
895*437bfbebSnyanmisaka             mpp_logi("    prev %d count %d\n", node->prev, node->next_cnt);
896*437bfbebSnyanmisaka 
897*437bfbebSnyanmisaka         for (j = 0; j < MPP_TRIE_KEY_MAX; j++) {
898*437bfbebSnyanmisaka             if (node->next[j] > 0) {
899*437bfbebSnyanmisaka                 mpp_logi("    next %d:%d -> %d\n", valid_count, j, node->next[j]);
900*437bfbebSnyanmisaka                 valid_count++;
901*437bfbebSnyanmisaka             }
902*437bfbebSnyanmisaka         }
903*437bfbebSnyanmisaka 
904*437bfbebSnyanmisaka         next_cnt[valid_count]++;
905*437bfbebSnyanmisaka         tag_len[node->tag_len]++;
906*437bfbebSnyanmisaka     }
907*437bfbebSnyanmisaka 
908*437bfbebSnyanmisaka     mpp_logi("node | next |  tag | used %d\n", p->node_used);
909*437bfbebSnyanmisaka 
910*437bfbebSnyanmisaka     for (i = 0; i < 17; i++) {
911*437bfbebSnyanmisaka         if (next_cnt[i] || tag_len[i])
912*437bfbebSnyanmisaka             mpp_logi("%2d   | %4d | %4d |\n", i, next_cnt[i], tag_len[i]);
913*437bfbebSnyanmisaka     }
914*437bfbebSnyanmisaka 
915*437bfbebSnyanmisaka     mpp_logi("%s dumping node end\n", func, p->node_used);
916*437bfbebSnyanmisaka }
917*437bfbebSnyanmisaka 
mpp_trie_timing_test(MppTrie trie)918*437bfbebSnyanmisaka void mpp_trie_timing_test(MppTrie trie)
919*437bfbebSnyanmisaka {
920*437bfbebSnyanmisaka     MppTrieInfo *root = mpp_trie_get_info_first(trie);
921*437bfbebSnyanmisaka     MppTrieInfo *info = root;
922*437bfbebSnyanmisaka     rk_s64 sum = 0;
923*437bfbebSnyanmisaka     rk_s32 loop = 0;
924*437bfbebSnyanmisaka 
925*437bfbebSnyanmisaka     do {
926*437bfbebSnyanmisaka         rk_s64 start, end;
927*437bfbebSnyanmisaka 
928*437bfbebSnyanmisaka         start = mpp_time();
929*437bfbebSnyanmisaka         mpp_trie_get_info(trie, mpp_trie_info_name(info));
930*437bfbebSnyanmisaka         end = mpp_time();
931*437bfbebSnyanmisaka 
932*437bfbebSnyanmisaka         info = mpp_trie_get_info_next(trie, info);
933*437bfbebSnyanmisaka         sum += end - start;
934*437bfbebSnyanmisaka         loop++;
935*437bfbebSnyanmisaka     } while (info);
936*437bfbebSnyanmisaka 
937*437bfbebSnyanmisaka     mpp_logi("trie access %d info %lld us averga %lld us\n",
938*437bfbebSnyanmisaka              loop, sum, sum / loop);
939*437bfbebSnyanmisaka }
940