Listing 4 Member functions of class MemoryObject

//  mobject.cpp
//
//  Copyright Singleton Systems Ltd 1994

#include    "stdafx.h"
#include    <new.h>
#include    "farheapb.h"
#include    "mobject.h"
#include    <iomanip.h>
#include    "newtest.h"

// ... debugging code not shown here
//     due to space constraints ...

void FAR * MemoryObject::operator new (size_t size)
// standard operator new, used for derived classes.
   {return new (size) MemoryObject;}

void FAR * MemoryObject::operator new
                 (size_t /*std_size */, size_t size)
//  Extended operator new, used by AllocateBlock and
//  standard operator new
{
FP_FHB allocated_block;
FP_MOBJECT first_fit = FindFreeSpace (size,
                                allocated_block);
if (first_fit == NULL)
   {
   //  Unable to satisfy request, raise memory
   //  exception
   _PNH handler = _set_new_handler (0);
   //  Get current new handler and restore it
   _set_new_handler (handler);
   (* handler) (size);         //  call the handler
   // Fail regardless of value returned by the handler
   return NULL;
   }

_segment cur_seg = (_segment) SELECTOROF (first_fit);

//  We now have a pointer to a free object which
//  satisfies our request. We need to split it so
//  that we get the amount we want, and the rest
//  stays in the free list
ASSERT (AfxIsValidAddress (first_fit,
                       sizeof (MemoryObject)));
ASSERT (first_fit->flags == unallocated);
unsigned int total_block_size = size;
//  Allocate in units of DWORDs
total_block_size = ((total_block_size + 3) >> 2) << 2;
if (first_fit->mo_block_size <
   total_block_size + sizeof (MemoryObject))
   {
   //  We need to have space for this block plus at
   //  least another MemoryObject. Not enough space
   //  to split the block, so do not, just unchain
   //  from free list
   if (first_fit->prev_mo != NULL)
      (cur_seg:>first_fit->prev_mo)->next_mo =
                          first_fit->next_mo;
   else
      //  This is the first block in the free list
      allocated_block->free_list =
                          first_fit->next_mo;
   if (first_fit->next_mo != NULL)
      (cur_seg:>first_fit->next_mo)->prev_mo =
                          first_fit->prev_mo;
   else    //  This is the last block in the list
      allocated_block->end_free_list =
                          first_fit->prev_mo;
   }
else
   {
   FP_MOBJECT new_free =
      (FP_MOBJECT) ((DWORD) first_fit +
                   total_block_size);
   //  Convert first_fit to DWORD, to increment by
   //  units of bytes rather then MemoryObjects
   ASSERT (AfxIsValidAddress (new_free,
                       sizeof (MemoryObject)));
   new_free->my_heap_block = first_fit->my_heap_block;
   new_free->prev_mo = first_fit->prev_mo;
   new_free->next_mo = first_fit->next_mo;
   new_free->mo_block_size =
      first_fit->mo_block_size - total_block_size;
   new_free->SetAllocationFlag (unallocated);
   first_fit->mo_block_size = total_block_size;
   if (first_fit->prev_mo != NULL)
      (cur_seg:>first_fit->prev_mo)->next_mo=
                MO_BASED_VOID_FROM_LP (new_free);
   else   //  This is the first block in the list
      allocated_block->free_list =
                MO_BASED_VOID_FROM_LP (new_free);
   if (first_fit->next_mo != NULL)
      (cur_seg:>first_fit->next_mo)->prev_mo =
                MO_BASED_VOID_FROM_LP (new_free);
   else    //This is the last block in the list
      allocated_block->end_free_list =
                MO_BASED_VOID_FROM_LP (new_free);
   }

//  We have removed the allocated block from the free
//  list, so we need to add it to the in-use list
if (allocated_block->in_use_list == NULL)
   //  This is the first block to be allocated
   {
   allocated_block->end_in_use_list =
          allocated_block->end_in_use_list =
                 MO_BASED_VOID_FROM_LP (first_fit);
   }
else
   //  Scan through the in-use list to insert the
   //  block in address order
   {
   FP_MOBJECT p_mo =
             cur_seg :>allocated_block->in_use_list;
   while (OFFSETOF (p_mo) != NULL)
      if (first_fit > p_mo) p_mo =
                       cur_seg:>p_mo->next_mo;
      else break;
   //  Now insert first_fit before p_mo
   first_fit->next_mo = MO_BASED_VOID_FROM_LP (p_mo);
   if (OFFSETOF (p_mo) == NULL)
      {
      //  We have reached the end of the list, so
      //  insert here
      #if defined (_DEBUG)
      //  For easy display in the MSVC Debugger
      //  Locals window
      FP_MOBJECT trace1 =
         cur_seg:>allocated_block->end_in_use_list;
      #endif
      (cur_seg:>allocated_block->end_in_use_list)
         ->next_mo
            = MO_BASED_VOID_FROM_LP (first_fit);
      first_fit->prev_mo =
                allocated_block->end_in_use_list;
      allocated_block-)end_in_use_list =
                MO_BASED_VOID_FROM_LP (first_fit);
      }
   else
      {
      ASSERT (AfxIsValidAddress (p_mo,
                       sizeof (MemoryObject)));
      first_fit->prev_mo = p_mo->prev_mo;
      if (p_mo->prev_mo == NULL)
         //  This is the first block
         allocated_block->in_use_list =
                MO_BASED_VOID_FROM_LP (first_fit);
      else
         (cur_seg:>p_mo->prev_mo)->next_mo =
                MO_BASED_VOID_FROM_LP (first_fit);
      p_mo->prev_mo =
                MO_BASED_VOID_FROM_LP (first_fit);
      }
   }
#if defined (_DEBUG)
   first_fit->Lno = 0;
   first_fit->Fname = NULL;
#endif
return first_fit;
}

void MemoryObject::operator delete (void FAR * p_void)
{
FP_MOBJECT p_mo = (FP_MOBJECT) p_void;
ASSERT (AfxIsValidAddress (p_mo,
                       sizeof (MemoryObject)));
FP_FHB this_block = FarHeapBlock::GetHbFromHandle
                           (p_mo->my_heap_block);
if (this_block == NULL){
   //  Unable to access block, raise memory exception
   //    in non-debug build
   AfxThrowMemoryException();
   return;
   }

__segment cur_seg = (__segment) SELECTOROF (p_void);

// ... debugging code not shown here
//     due to space constraints ...

//  First, unlink this block from the in-use list
if (p_mo->prev_mo != NULL)
   //  Point the previous block at the next block
   (cur_seg:>p_mo->prev_mo)->next_mo = p_mo->next_mo;
else
   {
   //  This is the first block in the list
   //  Check that the management structures also
   //  think that it is the first block in the list
   ASSERT (OFFSETOF (p_mo) ==
             (WORD) (this_block->in_use_list));
   //  The first block will now be the next block
   this_block->in_use_list = p_mo->next_mo;
   }

if (p_mo->next_me != NULL)
   //  Set the next block to point to the previous
   //    block
   (cur_seg:>p_mo->next_mo)->prev_mo = p_mo->prev_mo;
else
   {
   //  This is the last block in the list
   //  Check that the management structures also
   //  think that it is the last block in the list
   ASSERT (OFFSETOF (p_mo) ==
          (WORD) (this_block->end_in_use_list));
   this_block->end_in_use_list = p_mo->prev_mo;
   }

//  Now chain the block back into the list of free
//    blocks,
if (this_block->free_list == NULL)
   {
   //  The free list is currently empty
   //  Check that the management structures also
   //  think that it is free
   ASSERT (this_block->end_free_list == NULL);
   this_block->free_list =
             this_block->end_free_list =
                MO_BASED_VOID_FROM_LP (p_mo);
   p_mo->next_mo = p_mo->prev_mo = NULL;
   }
else
   {
   FP_MOBJECT insert_point =
                cur_seg:>this_block->free_list;
   //  Starting at the beginning, scan through
   //  the free list to find the insertion point.
   //  Insert in memory order
   while (OFFSETOF (insert_point) != NULL &&
                 insert_point <p_mo)
      insert_point = cur_seg:>insert_point->next_mo;

   if (OFFSETOF (insert_point) == NULL)
      {   //  insert at the end of the list
      ASSERT ((cur_seg:>this_block->end_free_list)
                              ->next_mo == NULL);
      (cur_seg:>this_block->end_free_list)->next_mo
                    = MO_BASED_VOID_FROM_LP (p_mo):
      p_mo->prev_mo = this_block->end_free_list;
      p_mo->next_mo = NULL;
      this_block->end_free_list
                    MO_BASED_VOID_FROM_LP (p_mo);
      }
   else
      {
      //  Insert the block before insert_point
      ASSERT (AfxIsValidAddress (insert_point,
                       sizeof (MemoryObject)));
      ASSERT (AfxIsValidAddress (p_mo,
                       sizeof (MemoryObject)));
      p_mo->next_mo =
             MO_BASED_VOID_FROM_LP(insert_point);
      p_mo->prev_mo = insert_point->prev_mo;
      if (insert_point-)prev_mo == NULL)
         {
         //  p_mo to be the new first free block
         ASSERT (insert_point ==
                cur_seg:>this_block->free_list);
         this_block->free_list =
                   MO_BASED_VOID_FROM_LP (p_mo);
         }
      else
         (cur_seg:>insert_point-)prev_mo)->next_mo
                    = MO_BASED_VOID_FROM_LP (p_mo);
      insert_point->prev_mo =
                    MO_BASED_VOID_FROM_LP (p_mo);
      }
   }

//  Now see whether it is possible to compact the
//  inserted block with either (or both) of the
//  adjacent blocks. First, can we combine it with
//  the previous block?
if (p_mo->prev_mo != NULL)
   {
   if ((DWORD) p_mo == (DWORD)(cur_seg:>p_mo->prev_mo)
          + (cur_seg:>p_mo->prev_mo)->mo_block_size)
      {   //  Compact with the previous block
      (cur_seg:>p_mo-)prev_mo)->next_mo =
                                 p_mo->next_mo;
      if (p_mo->next_mo == NULL)
         {   //  this was the last block in the list
         ASSERT (cur_seg:>this_block->end_free_list
                == p_mo);
         this_block->end_free_list = p_mo->prev_mo;
         }
      else
         (cur_seg:>p_mo->next_mo)->prev_mo =
                          p_mo->prev_mo;
      (cur_seg:>p_mo->prev_mo)->mo_block_size +=
                          p_mo->mo_block_size;
      //  Finally, as the block has been combined
      //  with the one before, set the pointer to
      //  that block
      p_mo = cur_seg:>p_mo->prev_mo;
      }
   }
//  Can we combine it with the next block
if (p_mo->next_mo != NULL)
   {
   if ((DWORD) p_mo + p_mo->mo_block_size ==
                (DWORD) (cur_seg:>p_mo->next_mo))
      {   //  Compact with the next block
      p_mo->mo_block_size +=
         (cur_seg:>p_mo->next_mo)->mo_block_size;
      if ((cur_seg:>p_mo->next_mo == NULL)
         {
         //  Next block is the last block in list
         ASSERT (this_block->end_free_list ==
                p_mo->next_mo);
         this_block->end_free_list =
             MO_BASED_VOID_FROM_LP (p_mo);
         }
      else
         (cur_seg:>(cur_seg:>p_mo->next_mo)
                   ->next_mo)->prev_mo =
             MO_BASED_VOID_FROM_LP (p_mo);
      p_mo->next_mo =
            (cur_seg:>p_mo->next_mo)->next_mo;
      }
   }

//  Finally, see if the FarHeapBlock is empty.
//  If so, return it to Windows
if (this_block->in_use_list == NULL)
   {   //  The block is empty, return it to Windows
   ASSERT (this_block->end_in_use_list == NULL);
   delete this_block;
   }
}

MemoryObject::MemoryObject ()
{
#if defined (_DEBUG)
   flags = allocated;
   _fstrcpy (validity_tag, validity_tag_value);
#endif
}

MemoryObject::~MemoryObject ()
{
#if defined (_DEBUG)
   if (_fstrcmp (validity_tag, validity_tag_value)
      != 0)
      {
      TRACE0 ("MemoryObject::~MemoryObject()"
             "attempting to delete an object with"
             "an invalid tag!\n");
      ASSERT (FALSE);
      }
   flags = unallocated;
#endif
}

inline FP_MOBJECT MemoryObject::FindFreeSpace
      (size_t size, FP_FHB & block_allocated)
{
//  As this routine is only called once, from
//  MemoryObject::new, it is declared as 'inline' for
//  efficiency and speed

//  First check that the requested size is within
//  limits. We cannot allocate a block that is bigger
//  that a FarHeapBlock less overheads.
ASSERT (block_allocated->DefaultSize () >
      sizeof (FarHeapBlock) + sizeof(MemoryObject));
if (size + sizeof (FarHeapBlock) +
   sizeof (MemoryObject) > block_allocated->DefaultSize ())
   {
   TRACE ("MemoryObject::FindFreeSpace cannot"
         "allocate requested space\n");
   ASSERT (FALSE);
   return NULL;
   }

// ... code not shown here
//     due to space constraints ...
// End of File