181 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			181 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * Copyright (c) 2006-2022, RT-Thread Development Team | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  * | ||
|  |  * Change Logs: | ||
|  |  * Date           Author       Notes | ||
|  |  * 2022-11-14     WangXiaoyao  the first version | ||
|  |  */ | ||
|  | #include <rtdef.h>
 | ||
|  | 
 | ||
|  | #include <avl.h>
 | ||
|  | #include "avl_adpt.h"
 | ||
|  | #include "mm_aspace.h"
 | ||
|  | #include "mm_private.h"
 | ||
|  | 
 | ||
|  | #define DBG_TAG "MM"
 | ||
|  | #define DBG_LVL DBG_INFO
 | ||
|  | #include <rtdbg.h>
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * @brief Adapter Layer for lwp AVL BST | ||
|  |  */ | ||
|  | 
 | ||
|  | rt_err_t _aspace_bst_init(struct rt_aspace *aspace) | ||
|  | { | ||
|  |     aspace->tree.tree.root_node = AVL_ROOT; | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | static int compare_overlap(void *as, void *ae, void *bs, void *be) | ||
|  | { | ||
|  |     LOG_D("as %lx, ae %lx, bs %lx, be %lx", as, ae, bs, be); | ||
|  |     int cmp; | ||
|  |     if (as > be) | ||
|  |     { | ||
|  |         cmp = 1; | ||
|  |     } | ||
|  |     else if (ae < bs) | ||
|  |     { | ||
|  |         cmp = -1; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         cmp = 0; | ||
|  |     } | ||
|  |     LOG_D("ret %d", cmp); | ||
|  |     return cmp; | ||
|  | } | ||
|  | 
 | ||
|  | static int compare_exceed(void *as, void *ae, void *bs, void *be) | ||
|  | { | ||
|  |     LOG_D("as %lx, ae %lx, bs %lx, be %lx", as, ae, bs, be); | ||
|  |     int cmp; | ||
|  |     if (as > bs) | ||
|  |     { | ||
|  |         cmp = 1; | ||
|  |     } | ||
|  |     else if (as < bs) | ||
|  |     { | ||
|  |         cmp = -1; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         cmp = 0; | ||
|  |     } | ||
|  |     LOG_D("ret %d", cmp); | ||
|  |     return cmp; | ||
|  | } | ||
|  | 
 | ||
|  | static struct rt_varea *search(struct util_avl_root *root, | ||
|  |                                struct _mm_range range, | ||
|  |                                int (*compare)(void *as, void *ae, void *bs, | ||
|  |                                               void *be)) | ||
|  | { | ||
|  |     struct util_avl_struct *node = root->root_node; | ||
|  |     while (node) | ||
|  |     { | ||
|  |         rt_varea_t varea = VAREA_ENTRY(node); | ||
|  |         int cmp = compare(range.start, range.end, varea->start, | ||
|  |                           (char *)varea->start + varea->size - 1); | ||
|  | 
 | ||
|  |         if (cmp < 0) | ||
|  |         { | ||
|  |             node = node->avl_left; | ||
|  |         } | ||
|  |         else if (cmp > 0) | ||
|  |         { | ||
|  |             node = node->avl_right; | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             return varea; | ||
|  |         } | ||
|  |     } | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | struct rt_varea *_aspace_bst_search(struct rt_aspace *aspace, void *key) | ||
|  | { | ||
|  |     struct util_avl_root *root = &aspace->tree.tree; | ||
|  |     struct _mm_range range = {key, key}; | ||
|  |     return search(root, range, compare_overlap); | ||
|  | } | ||
|  | 
 | ||
|  | rt_varea_t _aspace_bst_search_exceed(struct rt_aspace *aspace, void *start) | ||
|  | { | ||
|  |     struct util_avl_root *root = &aspace->tree.tree; | ||
|  |     struct util_avl_struct *node = root->root_node; | ||
|  |     rt_varea_t closest = NULL; | ||
|  |     ptrdiff_t min_off = PTRDIFF_MAX; | ||
|  |     while (node) | ||
|  |     { | ||
|  |         rt_varea_t varea = VAREA_ENTRY(node); | ||
|  |         void *va_s = varea->start; | ||
|  |         int cmp = compare_exceed(start, start, va_s, va_s); | ||
|  | 
 | ||
|  |         if (cmp < 0) | ||
|  |         { | ||
|  |             /* varae exceed start */ | ||
|  |             ptrdiff_t off = (char *)va_s - (char *)start; | ||
|  |             if (off < min_off) | ||
|  |             { | ||
|  |                 min_off = off; | ||
|  |                 closest = varea; | ||
|  |             } | ||
|  |             node = node->avl_left; | ||
|  |         } | ||
|  |         else if (cmp > 0) | ||
|  |         { | ||
|  |             /* find the next huger varea */ | ||
|  |             node = node->avl_right; | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             return varea; | ||
|  |         } | ||
|  |     } | ||
|  |     return closest; | ||
|  | } | ||
|  | 
 | ||
|  | struct rt_varea *_aspace_bst_search_overlap(struct rt_aspace *aspace, | ||
|  |                                             struct _mm_range range) | ||
|  | { | ||
|  |     struct util_avl_root *root = &aspace->tree.tree; | ||
|  |     return search(root, range, compare_overlap); | ||
|  | } | ||
|  | 
 | ||
|  | void _aspace_bst_insert(struct rt_aspace *aspace, struct rt_varea *varea) | ||
|  | { | ||
|  |     struct util_avl_root *root = &aspace->tree.tree; | ||
|  |     struct util_avl_struct *current = NULL; | ||
|  |     struct util_avl_struct **next = &(root->root_node); | ||
|  |     rt_ubase_t key = (rt_ubase_t)varea->start; | ||
|  | 
 | ||
|  |     /* Figure out where to put new node */ | ||
|  |     while (*next) | ||
|  |     { | ||
|  |         current = *next; | ||
|  |         struct rt_varea *data = VAREA_ENTRY(current); | ||
|  | 
 | ||
|  |         if (key < (rt_ubase_t)data->start) | ||
|  |             next = &(current->avl_left); | ||
|  |         else if (key > (rt_ubase_t)data->start) | ||
|  |             next = &(current->avl_right); | ||
|  |         else | ||
|  |             return; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* Add new node and rebalance tree. */ | ||
|  |     util_avl_link(&varea->node.node, current, next); | ||
|  |     util_avl_rebalance(current, root); | ||
|  |     return; | ||
|  | } | ||
|  | 
 | ||
|  | void _aspace_bst_remove(struct rt_aspace *aspace, struct rt_varea *varea) | ||
|  | { | ||
|  |     struct util_avl_struct *node = &varea->node.node; | ||
|  |     util_avl_remove(node, &aspace->tree.tree); | ||
|  | } |