3 changed files with 175 additions and 0 deletions
			
			
		@ -0,0 +1,18 @@
					 | 
				
			||||
#library "ZMEMORY" | 
				
			||||
#include "zcommon.acs" | 
				
			||||
 | 
				
			||||
//Simple linked list implementation of malloc | 
				
			||||
 | 
				
			||||
//Memory space | 
				
			||||
global int 63:memory[]; | 
				
			||||
 | 
				
			||||
//NULL "pointer" | 
				
			||||
#libdefine nullptr 0 | 
				
			||||
 | 
				
			||||
//Allocated size bytes in the memory space | 
				
			||||
function int malloc (int size) {return 0;} | 
				
			||||
 | 
				
			||||
//Frees an allocated block in the memory space. | 
				
			||||
//There are no safeguards in this function to guess whether or not the free is  | 
				
			||||
// valid, so be careful. | 
				
			||||
function int free (int p_ptr) {return 0;} | 
				
			||||
@ -0,0 +1,156 @@
					 | 
				
			||||
#library "ZMEMORY" | 
				
			||||
#include "zcommon.acs" | 
				
			||||
 | 
				
			||||
//Simple linked list implementation of malloc | 
				
			||||
 | 
				
			||||
global int 63:memory[]; | 
				
			||||
 | 
				
			||||
#libdefine nullptr 0 | 
				
			||||
 | 
				
			||||
#define malloc_allocated 0 | 
				
			||||
#define malloc_size 1 | 
				
			||||
#define malloc_next_header 2 | 
				
			||||
#define malloc_prev_header 3 | 
				
			||||
#define malloc_num_header_properties 4 | 
				
			||||
 | 
				
			||||
#define p_malloc_init_flag_location 0 | 
				
			||||
#define p_malloc_first_header_location 1 | 
				
			||||
 | 
				
			||||
function int malloc (int size) { | 
				
			||||
  log(s:"Invoked malloc"); | 
				
			||||
  //Do the setup on the first run of this function. | 
				
			||||
  if(memory[p_malloc_init_flag_location] == FALSE) { //Default values for global values is 0, so this is true. | 
				
			||||
    memory[p_malloc_init_flag_location] = TRUE; | 
				
			||||
    memory[p_malloc_first_header_location+malloc_allocated] = FALSE; | 
				
			||||
    memory[p_malloc_first_header_location+malloc_size] = -1; //"infinite" | 
				
			||||
    memory[p_malloc_first_header_location+malloc_next_header] = nullptr; //nullptr | 
				
			||||
    memory[p_malloc_first_header_location+malloc_prev_header] = nullptr; //nullptr | 
				
			||||
  } | 
				
			||||
   | 
				
			||||
  int p_previous_header = nullptr; | 
				
			||||
  int p_current_header = p_malloc_first_header_location; | 
				
			||||
  int p_retval = nullptr; | 
				
			||||
   | 
				
			||||
  while(p_retval == nullptr) { | 
				
			||||
    int memalloced = memory[p_current_header+malloc_allocated]; | 
				
			||||
    int memsize = memory[p_current_header+malloc_size]; | 
				
			||||
    if(memsize == -1) { //The end of the list. | 
				
			||||
      memory[p_current_header+malloc_allocated] = TRUE; | 
				
			||||
      memory[p_current_header+malloc_size] = size; | 
				
			||||
      memory[p_current_header+malloc_next_header] = p_current_header+malloc_num_header_properties+size; //New EOL | 
				
			||||
      memory[p_current_header+malloc_prev_header] = p_previous_header; | 
				
			||||
       | 
				
			||||
      //Retrieve the return value while we are at the allocated space. | 
				
			||||
      p_retval = p_current_header+malloc_num_header_properties; | 
				
			||||
       | 
				
			||||
      //Remember to initialize the new end list node. | 
				
			||||
      p_previous_header = p_current_header; //This is the header previous to the EOL. | 
				
			||||
      p_current_header = memory[p_current_header+malloc_next_header]; | 
				
			||||
      //Set the tail node constants. | 
				
			||||
      memory[p_current_header+malloc_allocated] = FALSE; | 
				
			||||
      memory[p_current_header+malloc_size] = -1; | 
				
			||||
      memory[p_current_header+malloc_next_header] = nullptr; | 
				
			||||
      memory[p_current_header+malloc_prev_header] = p_previous_header; | 
				
			||||
    } else if(memsize >= size && memalloced == FALSE) { //There is room here AND it isn't in use, | 
				
			||||
      memory[p_current_header+malloc_allocated] = TRUE; | 
				
			||||
      //The size isn't modified because we are re-using an existing space. | 
				
			||||
      // It would be a good idea to check just how large this space is and act accordingly rather | 
				
			||||
      //  than using a 500 indexes large space for a 4 indexes large object. | 
				
			||||
      // Objects allocated in a doom mod probably won't be outside the 1-16 indexes range so it | 
				
			||||
      //  should still be fine for most applications. | 
				
			||||
      //The next header isn't changed either for the same reason. | 
				
			||||
      if(memsize >= (size+malloc_num_header_properties+5)) { //Assume that 5 is the smallest useful allocation size. | 
				
			||||
        int p_split_newheader = p_current_header+malloc_num_header_properties+size; //Just to the end of the allocation. | 
				
			||||
        memory[p_split_newheader+malloc_allocated] = FALSE; | 
				
			||||
        memory[p_split_newheader+malloc_size] = memory[p_current_header+malloc_size]-malloc_num_header_properties-size; | 
				
			||||
        memory[p_split_newheader+malloc_next_header] = memory[p_current_header+malloc_next_header]; | 
				
			||||
        memory[p_split_newheader+malloc_prev_header] = p_current_header; | 
				
			||||
        memory[p_current_header+malloc_next_header] = p_split_newheader; //The header whose block was split should have its next pointer set to its other half. | 
				
			||||
        memory[p_current_header+malloc_size] = size; //Set the size of the allocation to reflect the split. | 
				
			||||
      } | 
				
			||||
       | 
				
			||||
      //Retrieve the return value while we are at the allocated space. | 
				
			||||
      p_retval = p_current_header+malloc_num_header_properties; | 
				
			||||
    } else { | 
				
			||||
      //The observed node isn't useful for allocating the request. Go to the next node. | 
				
			||||
      p_previous_header = p_current_header; | 
				
			||||
      p_current_header = memory[p_current_header+malloc_next_header]; | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
   | 
				
			||||
  log(s:"Malloc allocated ", d:size, s:" indexes at location ", d:p_retval, s:" with header location ", d:p_current_header); | 
				
			||||
   | 
				
			||||
  return p_retval; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
function int free (int p_ptr) { | 
				
			||||
  log(s:"Invoked free"); | 
				
			||||
   | 
				
			||||
  int p_header = p_ptr - malloc_num_header_properties; | 
				
			||||
   | 
				
			||||
  memory[p_header+malloc_allocated] = FALSE; | 
				
			||||
   | 
				
			||||
  int p_next = memory[p_header+malloc_next_header]; | 
				
			||||
  int p_prev = memory[p_header+malloc_prev_header]; | 
				
			||||
   | 
				
			||||
  //Below is the merging of free blocks. | 
				
			||||
  //It merges to the left (lower indexes) first becaue the right (larger  | 
				
			||||
  // indexes) has a special case. (the end of the list) | 
				
			||||
   | 
				
			||||
  //the previous block is unused. Merge. | 
				
			||||
  if(p_prev != nullptr //This doesn't make sense if the previous block doesn't exist. | 
				
			||||
  && memory[p_prev+malloc_allocated] == FALSE) { | 
				
			||||
    log(s:"Free attempting merge of header ", d:p_header, s: " to the left with header ", d:p_prev); | 
				
			||||
    memory[p_prev+malloc_size] += memory[p_header+malloc_size] + malloc_num_header_properties; | 
				
			||||
    memory[p_prev+malloc_next_header] = p_next; //The prev header needs to know the new next. | 
				
			||||
    memory[p_next+malloc_prev_header] = p_prev; //The next header needs to know the new prev. | 
				
			||||
     | 
				
			||||
    //Now the two blocks are the same block. requires new initializations of the | 
				
			||||
    // variables for the other check to function correctly. | 
				
			||||
    //The header is the result of the merge, and the prev is the one before it. | 
				
			||||
    p_header = p_prev; | 
				
			||||
    p_prev = memory[p_header+malloc_prev_header]; | 
				
			||||
  } | 
				
			||||
   | 
				
			||||
  //The next block is unused. Merge. | 
				
			||||
  //Note that p_next will never be a nullptr with correct usage. | 
				
			||||
  if(memory[p_next+malloc_allocated] == FALSE) { | 
				
			||||
    if(memory[p_next+malloc_size] == -1) { //EOL | 
				
			||||
      memory[p_header+malloc_size] = -1; | 
				
			||||
      memory[p_header+malloc_next_header] = nullptr; | 
				
			||||
    } else { | 
				
			||||
      int p_next_next = memory[p_next+malloc_next_header]; | 
				
			||||
      memory[p_header+malloc_size] += memory[p_next+malloc_size] + malloc_num_header_properties; | 
				
			||||
      memory[p_header+malloc_next_header] = p_next_next; //The header on the other side of the next header needs to know its new prev. | 
				
			||||
      memory[p_next_next+malloc_prev_header] = p_header; //This header needs to know its new next. | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
   | 
				
			||||
   | 
				
			||||
  return -1; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
//These are for debugging | 
				
			||||
script "memory_write" (int index, int value) { | 
				
			||||
  memory[index] = value; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
script "memory_read" (int index) { | 
				
			||||
  log(d:memory[index]); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
script "memory_print_allocation_list" (void) { | 
				
			||||
  int p_current_header = p_malloc_first_header_location; | 
				
			||||
   | 
				
			||||
  while(p_current_header != nullptr) { | 
				
			||||
    log(s:  "Header location: ", d:p_current_header, | 
				
			||||
        s:"\n Allocated flag: ", d:memory[p_current_header+malloc_allocated], | 
				
			||||
        s:"\n Allocation size: ", d:memory[p_current_header+malloc_size], | 
				
			||||
        s:"\n Prev header pointer: ", d:memory[p_current_header+malloc_prev_header], | 
				
			||||
        s:"\n Next header pointer: ", d:memory[p_current_header+malloc_next_header], | 
				
			||||
        s:"\n" | 
				
			||||
        ); | 
				
			||||
     | 
				
			||||
    p_current_header = memory[p_current_header+malloc_next_header]; | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue