diff options
Diffstat (limited to 'lib/prio_tree.c')
| -rw-r--r-- | lib/prio_tree.c | 156 | 
1 files changed, 69 insertions, 87 deletions
| diff --git a/lib/prio_tree.c b/lib/prio_tree.c index ccfd850b0dec..8d443af03b4c 100644 --- a/lib/prio_tree.c +++ b/lib/prio_tree.c @@ -85,6 +85,17 @@ static inline unsigned long prio_tree_maxindex(unsigned int bits)  	return index_bits_to_maxindex[bits - 1];  } +static void prio_set_parent(struct prio_tree_node *parent, +			    struct prio_tree_node *child, bool left) +{ +	if (left) +		parent->left = child; +	else +		parent->right = child; + +	child->parent = parent; +} +  /*   * Extend a priority search tree so that it can store a node with heap_index   * max_heap_index. In the worst case, this algorithm takes O((log n)^2). @@ -94,45 +105,32 @@ static inline unsigned long prio_tree_maxindex(unsigned int bits)  static struct prio_tree_node *prio_tree_expand(struct prio_tree_root *root,  		struct prio_tree_node *node, unsigned long max_heap_index)  { -	struct prio_tree_node *first = NULL, *prev, *last = NULL; +	struct prio_tree_node *prev;  	if (max_heap_index > prio_tree_maxindex(root->index_bits))  		root->index_bits++; +	prev = node; +	INIT_PRIO_TREE_NODE(node); +  	while (max_heap_index > prio_tree_maxindex(root->index_bits)) { +		struct prio_tree_node *tmp = root->prio_tree_node; +  		root->index_bits++;  		if (prio_tree_empty(root))  			continue; -		if (first == NULL) { -			first = root->prio_tree_node; -			prio_tree_remove(root, root->prio_tree_node); -			INIT_PRIO_TREE_NODE(first); -			last = first; -		} else { -			prev = last; -			last = root->prio_tree_node; -			prio_tree_remove(root, root->prio_tree_node); -			INIT_PRIO_TREE_NODE(last); -			prev->left = last; -			last->parent = prev; -		} -	} - -	INIT_PRIO_TREE_NODE(node); - -	if (first) { -		node->left = first; -		first->parent = node; -	} else -		last = node; +		prio_tree_remove(root, root->prio_tree_node); +		INIT_PRIO_TREE_NODE(tmp); -	if (!prio_tree_empty(root)) { -		last->left = root->prio_tree_node; -		last->left->parent = last; +		prio_set_parent(prev, tmp, true); +		prev = tmp;  	} +	if (!prio_tree_empty(root)) +		prio_set_parent(prev, root->prio_tree_node, true); +  	root->prio_tree_node = node;  	return node;  } @@ -151,25 +149,15 @@ struct prio_tree_node *prio_tree_replace(struct prio_tree_root *root,  		 * We can reduce root->index_bits here. However, it is complex  		 * and does not help much to improve performance (IMO).  		 */ -		node->parent = node;  		root->prio_tree_node = node; -	} else { -		node->parent = old->parent; -		if (old->parent->left == old) -			old->parent->left = node; -		else -			old->parent->right = node; -	} +	} else +		prio_set_parent(old->parent, node, old->parent->left == old); -	if (!prio_tree_left_empty(old)) { -		node->left = old->left; -		old->left->parent = node; -	} +	if (!prio_tree_left_empty(old)) +		prio_set_parent(node, old->left, true); -	if (!prio_tree_right_empty(old)) { -		node->right = old->right; -		old->right->parent = node; -	} +	if (!prio_tree_right_empty(old)) +		prio_set_parent(node, old->right, false);  	return old;  } @@ -229,16 +217,14 @@ struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root,  		if (index & mask) {  			if (prio_tree_right_empty(cur)) {  				INIT_PRIO_TREE_NODE(node); -				cur->right = node; -				node->parent = cur; +				prio_set_parent(cur, node, false);  				return res;  			} else  				cur = cur->right;  		} else {  			if (prio_tree_left_empty(cur)) {  				INIT_PRIO_TREE_NODE(node); -				cur->left = node; -				node->parent = cur; +				prio_set_parent(cur, node, true);  				return res;  			} else  				cur = cur->left; @@ -305,6 +291,40 @@ void prio_tree_remove(struct prio_tree_root *root, struct prio_tree_node *node)  		cur = prio_tree_replace(root, cur->parent, cur);  } +static void iter_walk_down(struct prio_tree_iter *iter) +{ +	iter->mask >>= 1; +	if (iter->mask) { +		if (iter->size_level) +			iter->size_level++; +		return; +	} + +	if (iter->size_level) { +		BUG_ON(!prio_tree_left_empty(iter->cur)); +		BUG_ON(!prio_tree_right_empty(iter->cur)); +		iter->size_level++; +		iter->mask = ULONG_MAX; +	} else { +		iter->size_level = 1; +		iter->mask = 1UL << (BITS_PER_LONG - 1); +	} +} + +static void iter_walk_up(struct prio_tree_iter *iter) +{ +	if (iter->mask == ULONG_MAX) +		iter->mask = 1UL; +	else if (iter->size_level == 1) +		iter->mask = 1UL; +	else +		iter->mask <<= 1; +	if (iter->size_level) +		iter->size_level--; +	if (!iter->size_level && (iter->value & iter->mask)) +		iter->value ^= iter->mask; +} +  /*   * Following functions help to enumerate all prio_tree_nodes in the tree that   * overlap with the input interval X [radix_index, heap_index]. The enumeration @@ -323,21 +343,7 @@ static struct prio_tree_node *prio_tree_left(struct prio_tree_iter *iter,  	if (iter->r_index <= *h_index) {  		iter->cur = iter->cur->left; -		iter->mask >>= 1; -		if (iter->mask) { -			if (iter->size_level) -				iter->size_level++; -		} else { -			if (iter->size_level) { -				BUG_ON(!prio_tree_left_empty(iter->cur)); -				BUG_ON(!prio_tree_right_empty(iter->cur)); -				iter->size_level++; -				iter->mask = ULONG_MAX; -			} else { -				iter->size_level = 1; -				iter->mask = 1UL << (BITS_PER_LONG - 1); -			} -		} +		iter_walk_down(iter);  		return iter->cur;  	} @@ -364,22 +370,7 @@ static struct prio_tree_node *prio_tree_right(struct prio_tree_iter *iter,  	if (iter->r_index <= *h_index) {  		iter->cur = iter->cur->right; -		iter->mask >>= 1; -		iter->value = value; -		if (iter->mask) { -			if (iter->size_level) -				iter->size_level++; -		} else { -			if (iter->size_level) { -				BUG_ON(!prio_tree_left_empty(iter->cur)); -				BUG_ON(!prio_tree_right_empty(iter->cur)); -				iter->size_level++; -				iter->mask = ULONG_MAX; -			} else { -				iter->size_level = 1; -				iter->mask = 1UL << (BITS_PER_LONG - 1); -			} -		} +		iter_walk_down(iter);  		return iter->cur;  	} @@ -389,16 +380,7 @@ static struct prio_tree_node *prio_tree_right(struct prio_tree_iter *iter,  static struct prio_tree_node *prio_tree_parent(struct prio_tree_iter *iter)  {  	iter->cur = iter->cur->parent; -	if (iter->mask == ULONG_MAX) -		iter->mask = 1UL; -	else if (iter->size_level == 1) -		iter->mask = 1UL; -	else -		iter->mask <<= 1; -	if (iter->size_level) -		iter->size_level--; -	if (!iter->size_level && (iter->value & iter->mask)) -		iter->value ^= iter->mask; +	iter_walk_up(iter);  	return iter->cur;  } | 
