#ifdef DEBUG
static void print_region_list(void);
static int check_block_list(queue_entry * block_list, malloc_block * new_block);
#endif DEBUG


void print_region_list(void) {
    unsigned int i;
    malloc_region * cur_region;

    cur_region = (malloc_region *)&malloc_region_list;
    printf("First region:\n");
    printf("curr: 0x%8x    prev: 0x%8x    next: 0x%8x\n",
        (unsigned int)cur_region,
        (unsigned int)(cur_region->links.prev),
        (unsigned int)(cur_region->links.next));

    printf("Region list contents:\n");

    i = 0;
    queue_iterate(&malloc_region_list, cur_region, malloc_region *, links) {
        if (i > num_regions) {
            break;
        }
        printf("curr: 0x%8x    prev: 0x%8x    next: 0x%8x\n",
            (unsigned int)cur_region,
            (unsigned int)(cur_region->links.prev),
            (unsigned int)(cur_region->links.next));
        i++;
    }
    return;
}

void print_block_list(queue_entry * block_list) {
    malloc_block * cur_block;

    queue_iterate(block_list, cur_block, malloc_block *, links) {
        printf("curr: 0x%8x    prev: 0x%8x    next: 0x%8x\n",
            (unsigned int)cur_block,
            (unsigned int)(cur_block->links.prev),
            (unsigned int)(cur_block->links.next));
    }
    return;
}

int break_here(void) {
    return 0;
}


int check_block_list(queue_entry * block_list, malloc_block * new_block) {
    void * end_of_new_block;
    malloc_block * cur_block;
    unsigned int i = 0;

    end_of_new_block = new_block + sizeof(malloc_block);

    queue_iterate(block_list, cur_block, malloc_block *, links) {
        malloc_region * cur_region;
        void * end_of_region;
        void * scratch_block;
        void * end_of_block;

        cur_region = cur_block->region;
        end_of_region = cur_region + cur_region->region_size;
        scratch_block = cur_block;
        end_of_block = scratch_block + sizeof(malloc_block);

        if ( ((void *)new_block >= scratch_block && (void *)new_block <= end_of_block) ||
             (end_of_new_block >= scratch_block && end_of_new_block <= end_of_block) ||
             (scratch_block >= (void *)new_block && scratch_block <= end_of_new_block) ||
             (end_of_block >= (void *)new_block && end_of_block <= end_of_new_block) ) {

            printf("New block %p overlaps existing block %p.\n",
                new_block, scratch_block);
            break_here();
            exit(1);
            return 1;

        }

        if (scratch_block < (void *)cur_region ||
            end_of_block >= end_of_region) {

            printf("Found invalid block link at block %d.\n", i);
            printf("curr: 0x%8x    prev: 0x%8x    next: 0x%8x\n",
                (unsigned int)cur_block,
                (unsigned int)(cur_block->links.prev),
                (unsigned int)(cur_block->links.next));
            break_here();
            exit(1);
            return 1;
        }

        scratch_block = (malloc_block *)cur_block->links.prev;
        end_of_block = scratch_block + sizeof(malloc_block);

        if (scratch_block < (void *)cur_region ||
            end_of_block >= end_of_region) {

            printf("Found invalid block link at block %d.\n", i);
            printf("curr: 0x%8x    prev: 0x%8x    next: 0x%8x\n",
                (unsigned int)cur_block,
                (unsigned int)(cur_block->links.prev),
                (unsigned int)(cur_block->links.next));
            break_here();
            exit(1);
            return 1;
        }

        scratch_block = (malloc_block *)cur_block->links.next;
        end_of_block = scratch_block + sizeof(malloc_block);

        if (scratch_block < (void *)cur_region ||
            end_of_block >= end_of_region) {
            printf("Found invalid block link at block %d.\n", i);

            printf("curr: 0x%8x    prev: 0x%8x    next: 0x%8x\n",
                (unsigned int)cur_block,
                (unsigned int)(cur_block->links.prev),
                (unsigned int)(cur_block->links.next));
            break_here();
            exit(1);
            return 1;
        }

        i++;
    }
    return 0;
}


int malloc_sanity_check(void) {
    unsigned int i;
    malloc_region * cur_region;

    i = 0;
    queue_iterate(&malloc_region_list, cur_region, malloc_region *, links) {
        if (i > num_regions) {
            return 0;
        }
        if (cur_region->links.next != &malloc_region_list &&
            cur_region->links.next < (queue_entry *)cur_region) {
            printf("inconsistency detected\n");
            return 0;
        }
        i++;
    }
    return 1;
}


/*********************************************************************
* malloc_hiwat()
*
* Returns the maximum amount of memory ever reserved by this package.
*********************************************************************/
size_t malloc_hiwat() {
    return malloc_hiwater_mark;
}

void malloc_clear_hiwat(void) {
    malloc_hiwater_mark = 0;
    return;
}

size_t malloc_current_usage(void)
{
    return current_block_total;
}

size_t malloc_region_usage(void) {
    size_t total = 0;
    malloc_region * cur_region;

    queue_iterate(&malloc_region_list, cur_region, malloc_region *, links) {
        total += cur_region->region_size - sizeof(malloc_region);

    }
    return total;
}


double malloc_peak_usage(void)
{
    return peak_usage;
}

double malloc_min_usage(void)
{
    return min_usage;
}

size_t malloc_unused(void) {
    size_t total = 0;
    malloc_region * cur_region;
    malloc_block * cur_block;

    queue_iterate(&malloc_region_list, cur_region, malloc_region *, links) {
        total += cur_region->free_size;

    }
    queue_iterate(&sorted_free_block_list, cur_block, malloc_block *, links) {
        total += cur_block->block_size;
    }

    return total;
}

double malloc_current_efficiency(void)
{
    double efficiency = 0.0;
    double total_block_size = 0;
    double total_request_size = 0;
    unsigned long total_block_sizeL = 0;
    unsigned long total_request_sizeL = 0;
    size_t discrepancy;
    size_t max_discrepancy = 0;
    malloc_region * cur_region;
    malloc_block * cur_block;

    queue_iterate(&malloc_region_list, cur_region, malloc_region *, links) {
        queue_iterate(&cur_region->block_list, cur_block, malloc_block *, links) {
            size_t cur_block_size = cur_block->block_size - sizeof(malloc_block);
            total_block_sizeL += cur_block_size;
            total_request_sizeL += cur_block->request_size;
            total_block_size += (double)cur_block_size;
            total_request_size += (double)cur_block->request_size;
            discrepancy = cur_block_size - cur_block->request_size;
            if (discrepancy > max_discrepancy) {
                max_discrepancy = discrepancy;
            }
        }
    }

    if (total_block_size > 0) {
        efficiency = (double)total_request_size / (double)total_block_size;
    } else {
        efficiency = 1.0;
    }

    printf("requested %.2f, actual %.2f\n", total_request_size, total_block_size);
    printf("requested %ld, actual %ld\n", total_request_sizeL, total_block_sizeL);
    printf("max discrepancy %ld\n", max_discrepancy);

    return efficiency;
}


/*********************************************************************
* malloc_report()
*
* Print stats on allocated regions and blocks.
*********************************************************************/
void malloc_report(void) {
    malloc_region * cur_region;
    malloc_block  * cur_block;
    size_t          total_block_size;

    queue_iterate(&malloc_region_list, cur_region, malloc_region *, links) {

        printf("VM Region, size, free: ");
        printf("%p, %d, %d\n", cur_region,
            cur_region->region_size,
            cur_region->free_size);

        total_block_size = 0;

        queue_iterate(&cur_region->block_list, cur_block, malloc_block *, links) {

            total_block_size += cur_block->block_size;
            printf("    Block address, size: %p,  %ld (%ld)\n",
                cur_block->buffer, cur_block->block_size,
                cur_block->block_size - sizeof(malloc_block));
            printf("          Block content: %s\n",
                (char *)cur_block->buffer);
        }
        printf("  Total blocks size: %ld\n", total_block_size);
#if 0
        queue_iterate(&cur_region->free_list, cur_block, malloc_block *, links) {

            total_block_size += cur_block->block_size;
            printf("    Free block address, size: %p,  %ld (%ld)\n",
                cur_block->buffer, cur_block->block_size,
                cur_block->block_size - sizeof(malloc_block));
        }
#endif 0
    }

    printf("High water mark: %ld\n", malloc_hiwater_mark);

    return;
} /* malloc_report() */

