#include "private.h"

/*--------------------------------------------------------- */
void *lub_heap_new_alloc_block(lub_heap_t * this, words_t words)
{
	void *result = NULL;
	lub_heap_free_block_t *free_block;
	lub_heap_block_t *new_block;
	lub_heap_key_t key;

	/* initialise the seach key */
	key.words = words;
	key.block = 0;

	/* find the smallest free block which can take this request */
	free_block = lub_bintree_findnext(&this->free_tree, &key);
	if (NULL != free_block) {
		lub_heap_tag_t *tail;
		unsigned int seg_end, seg_start;

		/* remember if this is the end of a segment */
		tail =
		    lub_heap_block__get_tail((lub_heap_block_t *) free_block);
		seg_start = free_block->tag.segment;
		seg_end = tail->segment;

		/* remove the block from the free tree */
		lub_bintree_remove(&this->free_tree, free_block);

		/* now slice the bottom off for the client */
		new_block =
		    lub_heap_slice_from_bottom(this, &free_block, &words,
					       BOOL_FALSE);

		if (NULL != free_block) {
			/* put the block back into the tree */
			lub_bintree_insert(&this->free_tree, free_block);
		}
		if (NULL != new_block) {
			/* set up the tag details */
			new_block->alloc.tag.segment = seg_start;
			new_block->alloc.tag.free = 0;
			new_block->alloc.tag.words = words;

			tail = lub_heap_block__get_tail(new_block);
			if (NULL == free_block) {
				/* we've swallowed the whole free block */
				tail->segment = seg_end;
			} else {
				tail->segment = 0;
			}
			tail->free = 0;
			tail->words = words;

			/* update the stats */
			++this->stats.alloc_blocks;
			this->stats.alloc_bytes += (words << 2);
			this->stats.alloc_bytes -=
			    sizeof(lub_heap_alloc_block_t);
			++this->stats.alloc_total_blocks;
			this->stats.alloc_total_bytes += (words << 2);
			this->stats.alloc_total_bytes -=
			    sizeof(lub_heap_alloc_block_t);
			this->stats.alloc_overhead +=
			    sizeof(lub_heap_alloc_block_t);

			/* fill out the client's pointer */
			result = new_block->alloc.memory;
		}
	}
	return result;
}

/*--------------------------------------------------------- */