tree_list.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #define TREE_LIST_C
  2. #include "my_assert.h"
  3. #include "app/tlst/tree_list.h"
  4. #if TREE_LIST_DEEP_ENABLE
  5. // @tree_list_foreach
  6. // Tree-List iteration function
  7. // Walks the specified node seaching for derived nodes. Each node found is passed to the specified
  8. // by user function @fcall with the specified user dependent context @ctx
  9. // Function walks the current node while @fcall returns 'true', and returns current node immediately as
  10. // far as @fcall returns 'false'. The function returns NULL if @fcall never returns 'false'.
  11. // @ref_node - the tree node to walk in;
  12. // @fcall - user defined function callback;
  13. // @ctx - user defined function context;
  14. // Returns: tree-list node in case @fcall have returned 'false', or NULL otherwise.
  15. const sTreeList_t * tree_list_foreach( const sTreeList_t * ref_node, fTreeListForEach_t fcall, void * ctx )
  16. {
  17. for( const sTreeList_t * iter = ref_node->c_list; NULL != iter; ++iter )
  18. {
  19. if( ! fcall( iter, ctx ) )
  20. {
  21. return iter;
  22. }
  23. }
  24. return NULL;
  25. }
  26. #endif
  27. // @tree_list_search
  28. // Search in the tree list @in for the node specified by @key using
  29. // ... the compare function @fcmp.
  30. // @in - the tree list to search in, shall not be NULL;
  31. // @search_key - the node key to search for, shall not be NULL;
  32. // @fcmp - nodes comparator, shall not be NULL;
  33. // @def_node - the default node to be returned if no node found by @search_key, can be NULL;
  34. // Returns: the node pointer if found, @def_node otherwise.
  35. // Note: The list @in shall be terminated by DECLARE_TREE_LIST_LAST() element.
  36. const sTreeList_t * tree_list_search( const sTreeList_t * in,
  37. const void * search_key,
  38. fTreeListComparer_t fcmp,
  39. const sTreeList_t * def_node )
  40. {
  41. my_assert( in );
  42. my_assert( search_key );
  43. my_assert( fcmp );
  44. for( const sTreeList_t * iter = in->list; NULL != iter; ++iter )
  45. {
  46. if( NULL == iter->key )
  47. {
  48. break;
  49. }
  50. else
  51. if( fcmp( iter->key, search_key ) )
  52. {
  53. return iter;
  54. }
  55. }
  56. return def_node;
  57. }
  58. #if TREE_LIST_DEEP_ENABLE
  59. // @sTreeListSearchDeepCtx_t
  60. // Internal context structure for @tree_list_search_deep
  61. typedef struct
  62. {
  63. const void * v_nextkey; // next key to search
  64. const void * v_ret_node; // found node
  65. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  66. const void * v_ret_pnode; // parent of found node
  67. #endif
  68. const sTreeList_t * def_node; // this node is considered as default
  69. const sTreeListSearchDeep_FSet_t * fs; // @fs parameter in 'tree_list_search_deep' function
  70. void * user_ctx; // user context
  71. }
  72. sTreeListSearchDeepCtx_t;
  73. // @tl_search_deep_iterator
  74. // Internal function.
  75. // A @tree_list_foreach routine callback in @tree_list_search_deep_int implementation
  76. // Modifies on return:
  77. // [true]:
  78. // - none
  79. // [false]:
  80. // - ctx->v_ret_node
  81. static bool tl_search_deep_iterator( const sTreeList_t * node, void * _ctx )
  82. {
  83. sTreeListSearchDeepCtx_t * ctx = (sTreeListSearchDeepCtx_t*)_ctx;
  84. my_assert( ctx->fs );
  85. my_assert( ctx->fs->fcmp );
  86. my_assert( ctx->v_nextkey );
  87. (void)ctx->v_ret_node; // keep value, do not touch
  88. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  89. (void)ctx->v_ret_pnode; // keep value, do not touch
  90. #endif
  91. if( NULL == node->key ) // end-of-list [DECLARE_TREE_LIST_LAST]
  92. {
  93. (void)ctx->v_ret_node;
  94. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  95. (void)ctx->v_ret_pnode;
  96. #endif
  97. return false; // terminate walking
  98. }
  99. else
  100. if( ctx->fs->fcmp( node->key, ctx->v_nextkey ) )
  101. {
  102. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  103. // check if user agree the result
  104. if( ctx->fs->fagree( node, ctx->v_ret_pnode, ctx->user_ctx ) )
  105. {
  106. #endif
  107. ctx->v_ret_node = node; // found
  108. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  109. (void)ctx->v_ret_pnode; // keep value, do not touch
  110. #endif
  111. return false; // terminate walking
  112. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  113. } // if not then continue searching
  114. #endif
  115. }
  116. // Check if no default node is assigned yet;
  117. // Check if the default node detector function is specified;
  118. // Check if the node is consideted as default;
  119. if( (NULL == ctx->def_node) && (NULL != ctx->fs->fisdef) && ctx->fs->fisdef( node, ctx->user_ctx ) )
  120. {
  121. ctx->def_node = node; // current node is the default node
  122. }
  123. (void)ctx->v_ret_node;
  124. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  125. (void)ctx->v_ret_pnode;
  126. #endif
  127. return true; // continue walking
  128. }
  129. // @tree_list_search_deep_int
  130. // Internal function.
  131. // Extended search for a key chain in the tree-list.
  132. // @ref_node - base node, root, the node to start search from;
  133. // @fs - functional set, see @sTreeListSearchDeep_FSet_t:
  134. // - fnext: user-defined abstract routine to retrieve next key in the chain;
  135. // - fcmp: user-defined abstract predicate to compare nodes;
  136. // - fisdef: user-defined predicate to determine if the node is the "default" node;
  137. // - freclim: user-defined abstract routine to limit recursive calls, see @fTreeListSearchDeepRecursiveLimiter_t;
  138. // @v_nextkey_override - override key to search, shall be NULL to use @fs->fnext, or this value will be used;
  139. // @user_ctx - user-dependent context, will be passed to routines in functional set @fs;
  140. // Returns:
  141. // NON NULL: found node;
  142. // NULL: node not found;
  143. static const sTreeList_t * tree_list_search_deep_int( const sTreeList_t * ref_node,
  144. const sTreeListSearchDeep_FSet_t * fs,
  145. const void * v_nextkey_override,
  146. void * user_ctx )
  147. {
  148. const sTreeList_t * found = NULL;
  149. my_assert( ref_node );
  150. my_assert( fs );
  151. my_assert( fs->fnext );
  152. my_assert( fs->fcmp );
  153. sTreeListSearchDeepCtx_t ctx = {
  154. .v_nextkey = v_nextkey_override,
  155. .v_ret_node = NULL,
  156. .def_node = NULL,
  157. .fs = fs,
  158. .user_ctx = user_ctx,
  159. };
  160. do
  161. {
  162. if( NULL == v_nextkey_override )
  163. {
  164. // get next key to search in the tree list
  165. ctx.v_nextkey = fs->fnext( user_ctx );
  166. }
  167. else
  168. {
  169. // use predefined key to search
  170. (void)ctx.v_nextkey;
  171. }
  172. // check if there no next key
  173. if( NULL == ctx.v_nextkey ) break; // invalid key
  174. ctx.v_ret_node = NULL;
  175. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  176. ctx.v_ret_pnode = ref_node;
  177. #endif
  178. ctx.def_node = NULL;
  179. // search for the key in tree list
  180. if( NULL != tree_list_foreach( ref_node, tl_search_deep_iterator, &ctx ) )
  181. {
  182. // not found?
  183. if( NULL == ctx.v_ret_node )
  184. {
  185. // try the default node if possible
  186. if( NULL != ctx.def_node )
  187. {
  188. // search recursevely (support optional/default nodes):
  189. // - specify the default node found as root node;
  190. // - pass the same function set (@fs);
  191. // - override the key to search (do not use @fs->fnext);
  192. // - limit recursive calls by user defined way;
  193. #if TREE_LIST_RECURSIVE_LIMIT_ENABLE
  194. bool possbile_call = true;
  195. // check if recursive call is possible:
  196. if( NULL != fs->freclim )
  197. {
  198. possbile_call = fs->freclim( true, user_ctx ); // enter recursive call
  199. }
  200. if( possbile_call )
  201. {
  202. found = tree_list_search_deep_int( ctx.def_node, fs, ctx.v_nextkey, user_ctx );
  203. }
  204. if( NULL != fs->freclim )
  205. {
  206. fs->freclim( false, user_ctx ); // leave recursive call
  207. }
  208. #else
  209. found = tree_list_search_deep_int( ctx.def_node, fs, ctx.v_nextkey, user_ctx );
  210. #endif
  211. }
  212. else
  213. {
  214. // assign NULL due to the element not found
  215. found = NULL;
  216. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  217. (void)ctx.v_ret_pnode;
  218. #endif
  219. }
  220. }
  221. else
  222. {
  223. // assign the element found
  224. found = ctx.v_ret_node;
  225. #if TREE_LIST_DEEP_PARENT_SEARCH_ENABLE
  226. (void)ctx.v_ret_pnode;
  227. #endif
  228. }
  229. if( NULL == found )
  230. {
  231. break; // not found
  232. }
  233. else
  234. {
  235. if( NULL != v_nextkey_override )
  236. {
  237. v_nextkey_override = NULL;
  238. }
  239. }
  240. }
  241. else break; // end-of-list, element not found
  242. ref_node = found; // found, go next key in the chain
  243. }
  244. while( NULL != found );
  245. return found;
  246. }
  247. // @tree_list_search_deep_int
  248. // Extended search for a key chain in the tree-list.
  249. // @ref_node - base node, root, the node to start search from;
  250. // @fs - functional set, see @sTreeListSearchDeep_FSet_t:
  251. // - fnext: user-defined abstract routine to retrieve next key in the chain;
  252. // - fcmp: user-defined abstract predicate to compare nodes;
  253. // - fisdef: user-defined predicate to determine if the node is the "default" node;
  254. // - freclim: user-defined abstract routine to limit recursive calls, see @fTreeListSearchDeepRecursiveLimiter_t;
  255. // @user_ctx - user-dependent context, will be passed to routines in functional set @fs;
  256. // Returns:
  257. // NON NULL: found node;
  258. // NULL: node not found;
  259. const sTreeList_t * tree_list_search_deep( const sTreeList_t * ref_node,
  260. const sTreeListSearchDeep_FSet_t * fs,
  261. void * user_ctx )
  262. {
  263. return tree_list_search_deep_int( ref_node, fs, NULL, user_ctx );
  264. }
  265. #endif