home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 2 / DATAFILE_PDCD2.iso / utilities2 / desklib / Libraries / Mem / c / Compact next >
Encoding:
Text File  |  1993-05-13  |  4.2 KB  |  126 lines

  1. /*
  2.     ####             #    #     # #
  3.     #   #            #    #       #          The FreeWare C library for 
  4.     #   #  ##   ###  #  # #     # ###             RISC OS machines
  5.     #   # #  # #     # #  #     # #  #   ___________________________________
  6.     #   # ####  ###  ##   #     # #  #                                      
  7.     #   # #        # # #  #     # #  #    Please refer to the accompanying
  8.     ####   ### ####  #  # ##### # ###    documentation for conditions of use
  9.     ________________________________________________________________________
  10.  
  11.     File:    Mem.Compact.c
  12.     Author:  Copyright © 1993 Jason Williams
  13.     Version: 1.00 (12 May 1993)
  14.     Purpose: Dynamic memory manager - heap compaction
  15. */
  16.  
  17. #include "MemDefs.h"
  18.  
  19. #include <string.h>
  20.  
  21.  
  22. static void Mem__ShiftHeap(mem_header *first, mem_header *last, int by)
  23. /*  Shifts all chunks between 'first' and 'last' (INCLUSIVE) up or down
  24.  *  by 'by' bytes, fixing all anchors as it goes, and returning with a
  25.  *  new (& valid) heap. (Assuming that the portions not being moved are
  26.  *  all valid!)
  27.  *
  28.  *  Currently, 'by' MUST be negative.
  29.  */
  30. {
  31.   mem_header *chunk;
  32.   int        tempstore;
  33.  
  34.   /*  Fix all the anchors to point at the new positions of these chunks
  35.    */
  36.   chunk = first;
  37.   while ((int) chunk <= (int) last)
  38.   {
  39.     if (chunk->datasize > 0)
  40.       *(chunk->handle) = (void *) (((int) (*chunk->handle)) + by);
  41.     chunk = Mem__NextChunk(chunk);
  42.   }
  43.  
  44.   /*  Move all these chunks by 'by' bytes.
  45.    *  'chunk' is now set to point at the start of the chunk after 'last'.
  46.    *  (Note that this may point at a non-existant chunk past the end of the
  47.    *  heap)
  48.    */
  49.   chunk = (mem_header *) ( ((int) last) + last->realsize );
  50.   memmove((char *) first + by, (char *) first, ((int) chunk) - ((int) first));
  51.  
  52.   /*  Now we must make a new free chunk with the space we have created
  53.    *  (before or) after the data we have moved. The simplest way to do this
  54.    *  is to add the space onto the end of preceeding chunk, and then call
  55.    *  Mem__SplitOffFreeChunk() to resolve everything for us.
  56.    */
  57.   if (by < 0)
  58.   {
  59.     last->realsize += by;
  60.     if (last != mem__lastchunk)
  61.     {
  62.       chunk = Mem__NextChunk(last);
  63.       chunk->prevrealsize = last->realsize;
  64.     }
  65.     tempstore = mem_autocompact;
  66.     mem_autocompact = mem_NOCOMPACT;           /* Don't call us recursively! */
  67.     Mem__SplitOffFreeChunk(last);   
  68.     mem_autocompact = tempstore;
  69.   }
  70. /*  else
  71.  *    Error_ReportFatalInternal("Mem__ShiftHeap failure");
  72.  */
  73. }
  74.  
  75.  
  76. extern void Mem_Compact(void)
  77. /*  Compacts the heap, moving all freespace to the end of the heap, and then
  78.  *  releases as much of this freespace as possible back into the WIMP freepool.
  79.  *
  80.  *  Note that the current implementation, although short and easy to write,
  81.  *  is extremely inefficient. This shouldn't make much of a difference though
  82.  *  unless you alloc and dealloc a LOT of medium-sized chunks between calls
  83.  *  to Mem_Compact.
  84.  */
  85. {
  86.   mem_header *chunk, *freechunk, *lastdatachunk;
  87.  
  88.   if (mem__iscompact) return;              /* Don't compact if not necessary */
  89.  
  90.   freechunk = (mem_header *) mem__heap;
  91.   while (TRUE)
  92.   {
  93.     while (!ISFREE(freechunk) && freechunk != mem__lastchunk)
  94.       freechunk = Mem__NextChunk(freechunk);
  95.  
  96.     if (freechunk == mem__lastchunk) break;      /* No 'trapped' free chunks */
  97.  
  98.     /*  Have found a free chunk. Shift chunks above it down in memory,
  99.      *  adjusting their anchors as necessary.
  100.      *  For greater efficiency, rather than shifting the rest of the heap,
  101.      *  we search for the end of this run of in-use chunks, and just shift
  102.      *  them down, enlarging the free chunk at the end of them.
  103.      */
  104.     chunk = Mem__NextChunk(freechunk);
  105.     lastdatachunk = chunk;
  106.     while (!ISFREE(lastdatachunk) && lastdatachunk != mem__lastchunk)
  107.       lastdatachunk = Mem__NextChunk(lastdatachunk);
  108.  
  109.     if (ISFREE(lastdatachunk))
  110.       lastdatachunk = Mem__PrevChunk(lastdatachunk);
  111.  
  112.     Mem__ShiftHeap(chunk, lastdatachunk, -freechunk->realsize);
  113.  
  114.     /*  And back around for another go - chunk has been moved down into
  115.      *  the same place as 'freechunk', so we just continue from there...
  116.      */
  117.   }
  118.  
  119.   /* Finally, adjust the WimpSlot to the minimum that we require, and adjust
  120.    * the last (free) chunk as appropriate
  121.    */
  122.  
  123.   Mem__ReduceSlot();
  124.   mem__iscompact = TRUE;
  125. }
  126.