// file: mm_cstr_0.cc
//

// isip include files
//
#include "memory_manager.h"
#include "memory_manager_constants.h"

// method: reorder_blocks_cc
//
// arguments: none
//
// return: logical value indicating status
//
// method to reorder the memory blocks so they are contiguously ordered
// this is useful when memory gets scattered in the internal lists due
// to many random accesses of memory locales.
//
logical_1 Memory_manager::reorder_blocks_cc() {

  // sort the lists by item address
  //
  sort_nodes_cc(lex_list_d, lex_count_d);
  sort_nodes_cc(lat_list_d, lat_count_d);
  sort_nodes_cc(lpath_list_d, lpath_count_d);
  sort_nodes_cc(hist_list_d, hist_count_d);
  sort_nodes_cc(instance_list_d, instance_count_d);
  sort_nodes_cc(hash_list_d, hash_count_d);
  sort_nodes_cc(trace_list_d, trace_count_d);
  sort_nodes_cc(ngram_list_d, ngram_count_d);

  // exit gracefully
  //
  return ISIP_TRUE;
}

static Link_node** sort_array = (Link_node**)NULL;
static int_4 num_elems = 0;

static int compare_link_nodes_cc(const void* first, const void* second) {
  return Memory_manager::item_sort_cc((Link_node**)first, (Link_node**)second);
}

// method: sort_nodes_cc
//
// arguments:
//  Link_node*& in_list: (input) list to sort
//  int_4 size: (input) size of the list
//
// return: logical value indicating status
//
// method to reorder the memory blocks so they are contiguously ordered
// this is useful when memory gets scattered in the internal lists due
// to many random accesses of memory locales. Here, we first copy the data
// to an array and use quicksort to do the sorting. This makes the worst
// case runtime at N+NlogN which is still generally better than the N^2
// seen in other sorts
//
logical_1 Memory_manager::sort_nodes_cc(Link_node*& in_list_a, int_4 size_a) {

  if ((in_list_a == (Link_node*)NULL) || (size_a <= 0)) {
    return true;
  }
  
  // reallocate memory if necessary
  //
  if (num_elems < size_a) {
    if (sort_array != (Link_node**)NULL) {
      delete [] sort_array;
    }
    sort_array = new Link_node*[size_a];
    num_elems = size_a;
  }

  Link_node* tmp_node = (Link_node*)NULL;
  
  // declare local variables
  //
  int_4 i = 0;
  for (Link_node* node = in_list_a; node != (Link_node*)NULL;
       node = tmp_node) {

    tmp_node = node->get_next_cc();
    sort_array[i++] = node;
  }

  // quicksort the array
  //
  qsort(sort_array, size_a, sizeof(Link_node*), compare_link_nodes_cc);

  // reconnect the nodes in the array
  //
  for (int_4 n = 1; n < size_a; n++) {
    sort_array[n]->set_prev_cc(sort_array[n-1]);
    sort_array[n-1]->set_next_cc(sort_array[n]);
  }
  
  // connect the end-points
  //
  sort_array[0]->set_prev_cc((Link_node*)NULL);
  sort_array[i-1]->set_next_cc((Link_node*)NULL);

  // set the list pointer
  //
  in_list_a = sort_array[0];
  
  // exit gracefully
  //
  return true;
}

// method: item_sort_cc
//
// arguments:
//  Link_node** first: (input) a Link_node** to compare
//  Link_node** second: (input) a second Link_node** to compare
//
// return: an integer specifying the sort order based on the item address
//         if the address of first is greater than the address of
//         second then a positive number is returned
//         if the address of second is greater than the address of first
//         then a negative number is returned
//         if the addresses are equal then a zero is returned
//
// this method compares the two inputs for sort order
//
int Memory_manager::item_sort_cc(Link_node** first_a, Link_node** second_a) {

  if ((*first_a)->get_item_cc() > (*second_a)->get_item_cc()) {
    return 1;
  }
  if ((*first_a)->get_item_cc() < (*second_a)->get_item_cc()) {
    return -1;
  }
  return 0;
}
