home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_12_09 / single2 / mobject.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-07  |  24.8 KB  |  746 lines

  1. //  Listing 6
  2. //  mobject.cpp
  3. //
  4. //  Copyright Singleton Systems Ltd 1994 
  5.  
  6. #include    "stdafx.h" 
  7. #include    <new.h>
  8. #include    "farheapb.h"
  9. #include    "mobject.h"
  10. #include    <iomanip.h>
  11. #include    "newtest.h"
  12.  
  13. #if defined (_DEBUG)
  14.     char MemoryObject::validity_tag_value [4] = "DfK";
  15. #endif
  16.  
  17. #if defined (_DEBUG)
  18. //  For file name and line number tracking during debug
  19. void FAR * MemoryObject::operator new 
  20.     (size_t size, const char FAR * FileName, int Line)
  21. {
  22. MemoryObject * p_allocated = new (size) MemoryObject;
  23. #if defined (_DEBUG)
  24.     if(p_allocated != NULL)
  25.         {
  26.         ASSERT (p_allocated->Lno == 0);
  27.         ASSERT (p_allocated->Fname == 0);
  28.         p_allocated->Lno = Line;
  29.         p_allocated->Fname = (char FAR *) FileName;
  30.         }
  31. #endif
  32. return p_allocated;
  33. }   
  34. #endif
  35.  
  36. void FAR * MemoryObject::operator new (size_t size) 
  37. // standard operator new, used for derived classes.
  38.     {return new (size) MemoryObject;}
  39.  
  40. void FAR * MemoryObject::operator new 
  41.                     (size_t /*std_size */, size_t size)
  42. //  Extended operator new, used by AllocateBlock and 
  43. //  standard operator new
  44. {
  45. FP_FHB allocated_block;
  46. FP_MOBJECT first_fit = FindFreeSpace (size, 
  47.                                       allocated_block);
  48. if (first_fit == NULL) 
  49.     {   
  50.     //  Unable to satisfy request, raise memory 
  51.     //  exception
  52.     _PNH handler = _set_new_handler (0);    
  53.     //  Get current new handler and restore it
  54.     _set_new_handler (handler);
  55.     (* handler) (size);         //  call the handler 
  56.     // Fail regardless of value returned by the handler
  57.     return NULL;                 
  58.     }
  59.  
  60. __segment cur_seg = (__segment) SELECTOROF (first_fit);
  61.  
  62. //  We now have a pointer to a free object which 
  63. //  satisfies our request.  We need to split it so 
  64. //  that we get the amount we want, and the rest 
  65. //  stays in the free list   
  66. ASSERT (AfxIsValidAddress (first_fit, 
  67.                            sizeof (MemoryObject)));
  68. ASSERT (first_fit->flags == unallocated);
  69. unsigned int total_block_size = size; 
  70. //  Allocate in units of DWORDs
  71. total_block_size = ((total_block_size + 3) >> 2) << 2;
  72. if (first_fit->mo_block_size < 
  73.     total_block_size + sizeof (MemoryObject))
  74.     {   
  75.     //  We need to have space for this block plus at 
  76.     //  least another MemoryObject.  Not enough space 
  77.     //  to split the block, so do not, just unchain
  78.     //  from free list
  79.     if (first_fit->prev_mo != NULL)
  80.         (cur_seg:>first_fit->prev_mo)->next_mo = 
  81.                                 first_fit->next_mo;
  82.     else    
  83.         //  This is the first block in the free list
  84.         allocated_block->free_list = 
  85.                                 first_fit->next_mo;
  86.     if (first_fit->next_mo != NULL)
  87.         (cur_seg:>first_fit->next_mo)->prev_mo = 
  88.                                 first_fit->prev_mo;
  89.     else    //  This is the last block in the list
  90.         allocated_block->end_free_list = 
  91.                                 first_fit->prev_mo;
  92.     }
  93. else
  94.     {
  95.     FP_MOBJECT new_free = 
  96.         (FP_MOBJECT) ((DWORD) first_fit + 
  97.                        total_block_size);
  98.     //  Convert first_fit to DWORD, to increment by 
  99.     //  units of bytes rather then MemoryObjects
  100.     ASSERT (AfxIsValidAddress (new_free, 
  101.                             sizeof (MemoryObject)));
  102.     new_free->my_heap_block = first_fit->my_heap_block;
  103.     new_free->prev_mo = first_fit->prev_mo;
  104.     new_free->next_mo = first_fit->next_mo; 
  105.     new_free->mo_block_size = 
  106.         first_fit->mo_block_size - total_block_size; 
  107.     new_free->SetAllocationFlag (unallocated);
  108.     first_fit->mo_block_size = total_block_size;
  109.     if (first_fit->prev_mo != NULL)
  110.         (cur_seg:>first_fit->prev_mo)->next_mo = 
  111.                     MO_BASED_VOID_FROM_LP (new_free);
  112.     else    //  This is the first block in the list
  113.         allocated_block->free_list = 
  114.                     MO_BASED_VOID_FROM_LP (new_free);
  115.     if (first_fit->next_mo != NULL)
  116.         (cur_seg:>first_fit->next_mo)->prev_mo = 
  117.                     MO_BASED_VOID_FROM_LP (new_free);
  118.     else    //This is the last block in the list
  119.         allocated_block->end_free_list = 
  120.                     MO_BASED_VOID_FROM_LP (new_free);
  121.     }
  122.  
  123. //  We have removed the allocated block from the free 
  124. //  list, so we need to add it to the in-use list
  125. if (allocated_block->in_use_list == NULL)   
  126.     //  This is the first block to be allocated
  127.     {
  128.     allocated_block->in_use_list = 
  129.             allocated_block->end_in_use_list = 
  130.                     MO_BASED_VOID_FROM_LP (first_fit);
  131.     }
  132. else    
  133.     //  Scan through the in-use list to insert the 
  134.     //  block in address order
  135.     {
  136.     FP_MOBJECT p_mo = 
  137.                 cur_seg:>allocated_block->in_use_list;
  138.     while (OFFSETOF (p_mo) != NULL)
  139.         if (first_fit > p_mo) p_mo = 
  140.                             cur_seg:>p_mo->next_mo;
  141.         else break; 
  142.     //  Now insert first_fit before p_mo 
  143.     first_fit->next_mo = MO_BASED_VOID_FROM_LP (p_mo);
  144.     if (OFFSETOF (p_mo) == NULL)
  145.         {   
  146.         //  We have reached the end of the list, so 
  147.         //  insert here
  148.         #if defined (_DEBUG)
  149.         //  For easy display in the MSVC Debugger 
  150.         //  Locals window
  151.         FP_MOBJECT trace1 = 
  152.             cur_seg:>allocated_block->end_in_use_list;
  153.         #endif      
  154.         (cur_seg:>allocated_block->end_in_use_list)
  155.             ->next_mo 
  156.                 = MO_BASED_VOID_FROM_LP (first_fit);
  157.         first_fit->prev_mo = 
  158.                     allocated_block->end_in_use_list;
  159.         allocated_block->end_in_use_list = 
  160.                     MO_BASED_VOID_FROM_LP (first_fit);
  161.         }
  162.     else 
  163.         {
  164.         ASSERT (AfxIsValidAddress (p_mo, 
  165.                             sizeof (MemoryObject)));
  166.         first_fit->prev_mo = p_mo->prev_mo;
  167.         if (p_mo->prev_mo == NULL)      
  168.             //  This is the first block
  169.             allocated_block->in_use_list = 
  170.                     MO_BASED_VOID_FROM_LP (first_fit);
  171.         else 
  172.             (cur_seg:>p_mo->prev_mo)->next_mo = 
  173.                     MO_BASED_VOID_FROM_LP (first_fit);
  174.         p_mo->prev_mo = 
  175.                     MO_BASED_VOID_FROM_LP (first_fit);
  176.         }
  177.     }                    
  178. #if defined (_DEBUG)
  179.     first_fit->Lno = 0;
  180.     first_fit->Fname = NULL;
  181. #endif
  182. return first_fit;    
  183. }
  184.  
  185. void MemoryObject::operator delete (void FAR * p_void)
  186. {
  187. FP_MOBJECT p_mo = (FP_MOBJECT) p_void;
  188. ASSERT (AfxIsValidAddress (p_mo, 
  189.                             sizeof (MemoryObject)));
  190. FP_FHB this_block = FarHeapBlock::GetHbFromHandle 
  191.                                 (p_mo->my_heap_block);
  192. if (this_block == NULL)
  193.     {   
  194.     //  Unable to access block, raise memory exception 
  195.     //    in non-debug build
  196.     AfxThrowMemoryException();
  197.     return;
  198.     }
  199.  
  200. __segment cur_seg = (__segment) SELECTOROF (p_void);
  201.  
  202. #if defined (_DEBUG)
  203.     //  For debugging purposes only.  Makes it much 
  204.     //    easier to watch variables if we use full 
  205.     //    addressing rather than segment-based 
  206.     //    addressing
  207.     FP_MOBJECT p_prev_object = cur_seg:>p_mo->prev_mo;
  208.     FP_MOBJECT p_next_object = cur_seg:>p_mo->next_mo;
  209. #endif
  210.  
  211. //  First, unlink this block from the in-use list
  212. if (p_mo->prev_mo != NULL)
  213.     //  Point the previous block at the next block 
  214.     (cur_seg:>p_mo->prev_mo)->next_mo = p_mo->next_mo;
  215. else    
  216.     {   
  217.     //  This is the first block in the list
  218.     //  Check that the management structures also
  219.     //  think that it is the first block in the list
  220.     ASSERT (OFFSETOF (p_mo) == 
  221.                 (WORD) (this_block->in_use_list));
  222.     //  The first block will now be the next block
  223.     this_block->in_use_list = p_mo->next_mo;
  224.     }
  225.     
  226. if (p_mo->next_mo != NULL)
  227.     //  Set the next block to point to the previous 
  228.     //    block
  229.     (cur_seg:>p_mo->next_mo)->prev_mo = p_mo->prev_mo;
  230. else
  231.     {   
  232.     //  This is the last block in the list
  233.     //  Check that the management structures also
  234.     //  think that it is the last block in the list
  235.     ASSERT (OFFSETOF (p_mo) == 
  236.             (WORD) (this_block->end_in_use_list));
  237.     this_block->end_in_use_list = p_mo->prev_mo;
  238.     }
  239.     
  240. //  Now chain the block back into the list of free 
  241. //    blocks, 
  242. if (this_block->free_list == NULL)
  243.     {   
  244.     //  The free list is currently empty
  245.     //  Check that the management structures also
  246.     //  think that it is free
  247.     ASSERT (this_block->end_free_list == NULL);
  248.     this_block->free_list = 
  249.                 this_block->end_free_list =
  250.                     MO_BASED_VOID_FROM_LP (p_mo);
  251.     p_mo->next_mo = p_mo->prev_mo = NULL;
  252.     }
  253. else
  254.     {
  255.     FP_MOBJECT insert_point = 
  256.                     cur_seg:>this_block->free_list;
  257.     //  Starting at the beginning, scan through 
  258.     //  the free list to find the insertion point.  
  259.     //  Insert in memory order
  260.     while (OFFSETOF (insert_point) != NULL && 
  261.                      insert_point < p_mo)
  262.         insert_point = cur_seg:>insert_point->next_mo;
  263.                          
  264.     if (OFFSETOF (insert_point) == NULL)
  265.         {   //  insert at the end of the list
  266.         ASSERT ((cur_seg:>this_block->end_free_list)
  267.                                     ->next_mo == NULL);
  268.         (cur_seg:>this_block->end_free_list)->next_mo 
  269.                         = MO_BASED_VOID_FROM_LP (p_mo);
  270.         p_mo->prev_mo = this_block->end_free_list;
  271.         p_mo->next_mo = NULL;
  272.         this_block->end_free_list = 
  273.                         MO_BASED_VOID_FROM_LP (p_mo);
  274.         } 
  275.     else
  276.         {   
  277.         //  Insert the block before insert_point
  278.         ASSERT (AfxIsValidAddress (insert_point, 
  279.                             sizeof (MemoryObject)));
  280.         ASSERT (AfxIsValidAddress (p_mo, 
  281.                             sizeof (MemoryObject)));
  282.         p_mo->next_mo = 
  283.                 MO_BASED_VOID_FROM_LP (insert_point);
  284.         p_mo->prev_mo = insert_point->prev_mo;
  285.         if (insert_point->prev_mo == NULL)
  286.             {   
  287.             //  p_mo to be the new first free block
  288.             ASSERT (insert_point == 
  289.                     cur_seg:>this_block->free_list);
  290.             this_block->free_list = 
  291.                         MO_BASED_VOID_FROM_LP (p_mo);
  292.             }                            
  293.         else
  294.             (cur_seg:>insert_point->prev_mo)->next_mo 
  295.                         = MO_BASED_VOID_FROM_LP (p_mo);
  296.         insert_point->prev_mo = 
  297.                         MO_BASED_VOID_FROM_LP (p_mo);
  298.         }
  299.     }
  300.  
  301. //  Now see whether it is possible to compact the 
  302. //  inserted block with either (or both) of the 
  303. //  adjacent blocks.  First, can we combine it with 
  304. //  the previous block?
  305. if (p_mo->prev_mo != NULL)
  306.     {
  307.     if ((DWORD) p_mo == (DWORD)(cur_seg:>p_mo->prev_mo)
  308.             + (cur_seg:>p_mo->prev_mo)->mo_block_size)
  309.         {   //  Compact with the previous block
  310.         (cur_seg:>p_mo->prev_mo)->next_mo = 
  311.                                         p_mo->next_mo;
  312.         if (p_mo->next_mo == NULL)
  313.             {   //  This was the last block in the list
  314.             ASSERT (cur_seg:>this_block->end_free_list
  315.                     == p_mo);
  316.             this_block->end_free_list = p_mo->prev_mo;
  317.             }
  318.         else
  319.             (cur_seg:>p_mo->next_mo)->prev_mo = 
  320.                                 p_mo->prev_mo;
  321.         (cur_seg:>p_mo->prev_mo)->mo_block_size += 
  322.                                 p_mo->mo_block_size;
  323.         //  Finally, as the block has been combined 
  324.         //  with the one before, set the pointer to 
  325.         //  that block
  326.         p_mo = cur_seg:>p_mo->prev_mo;
  327.         } 
  328.     } 
  329. //  Can we combine it with the next block
  330. if (p_mo->next_mo != NULL)
  331.     {
  332.     if ((DWORD) p_mo + p_mo->mo_block_size == 
  333.                     (DWORD) (cur_seg:>p_mo->next_mo))
  334.         {   //  Compact with the next block 
  335.         p_mo->mo_block_size += 
  336.             (cur_seg:>p_mo->next_mo)->mo_block_size;
  337.         if ((cur_seg:>p_mo->next_mo)->next_mo == NULL)
  338.             {   
  339.             //  Next block is the last block in list
  340.             ASSERT (this_block->end_free_list == 
  341.                     p_mo->next_mo);
  342.             this_block->end_free_list = 
  343.                  MO_BASED_VOID_FROM_LP (p_mo);
  344.             }                                     
  345.         else
  346.             (cur_seg:>(cur_seg:>p_mo->next_mo)
  347.                         ->next_mo)->prev_mo =
  348.                  MO_BASED_VOID_FROM_LP (p_mo);
  349.         p_mo->next_mo = 
  350.                 (cur_seg:>p_mo->next_mo)->next_mo;
  351.         }
  352.     }
  353.  
  354. //  Finally, see if the FarHeapBlock is empty.  
  355. //  If so, return it to Windows
  356. if (this_block->in_use_list == NULL)
  357.     {   //  The block is empty, return it to Windows
  358.     ASSERT (this_block->end_in_use_list == NULL);
  359.     delete this_block;
  360.     }
  361. }
  362.  
  363. MemoryObject::MemoryObject ()
  364. {
  365. #if defined (_DEBUG)
  366.     flags = allocated;
  367.     _fstrcpy (validity_tag, validity_tag_value);
  368. #endif
  369. }
  370.  
  371. MemoryObject::~MemoryObject ()
  372. {
  373. #if defined (_DEBUG)
  374.     if (_fstrcmp (validity_tag, validity_tag_value) 
  375.         != 0)
  376.         {
  377.         TRACE0 ("MemoryObject::~MemoryObject() "
  378.                 "attempting to delete an object with "
  379.                 "an invalid tag!\n");
  380.         ASSERT (FALSE);
  381.         }
  382.     flags = unallocated;
  383. #endif
  384. }
  385.  
  386. inline FP_MOBJECT MemoryObject::FindFreeSpace 
  387.         (size_t size, FP_FHB & block_allocated)
  388. {
  389. //  As this routine is only called once, from 
  390. //  MemoryObject::new, it is declared as 'inline' for 
  391. //  efficiency and speed
  392.  
  393. //  First check that the requested size is within 
  394. //  limits.  We cannot allocate a block that is bigger
  395. //  that a FarHeapBlock less overheads.
  396. ASSERT (block_allocated->DefaultSize () > 
  397.         sizeof (FarHeapBlock) + sizeof(MemoryObject));
  398. if (size + sizeof (FarHeapBlock) + 
  399.     sizeof (MemoryObject) > block_allocated->DefaultSize ())
  400.     {
  401.     TRACE ("MemoryObject::FindFreeSpace cannot "
  402.            "allocate requested space\n");
  403.     ASSERT (FALSE);
  404.     return NULL;
  405.     }
  406.          
  407. if (FarHeapBlock::IsEmpty ())
  408.     {
  409.     //  No FarHeapBlocks in existance at the moment, 
  410.     //  so create one.  
  411.     FarHeapBlock FAR * p_fhb = new FarHeapBlock;
  412.     //  We do not need to keep this pointer, as it is 
  413.     //  automatically inserted into the list of 
  414.     //  FarHeapBlocks 
  415.     }
  416.     
  417. FHB_POSITION p = FarHeapBlock::GetHeadPosition ();
  418. BOOL free_space_found = FALSE;
  419. do  {
  420.     FP_FHB p_fhb = FarHeapBlock::GetNext (p);
  421.     __segment cur_seg = (__segment) SELECTOROF (p_fhb);
  422.     FP_MOBJECT current_free = 
  423.                             cur_seg:>p_fhb->free_list;
  424.     while (OFFSETOF (current_free) != NULL)
  425.         {
  426.         ASSERT (AfxIsValidAddress (current_free, 
  427.                             sizeof (MemoryObject)));
  428.         if(current_free->mo_block_size > 
  429.            size + sizeof (MemoryObject))
  430.             {
  431.             block_allocated = p_fhb;
  432.             return current_free;
  433.             }
  434.         else
  435.             current_free = 
  436.                     cur_seg:>current_free->next_mo;
  437.         }
  438.     //  If we come out of the bottom of this while 
  439.     //  loop, we did not find a large-enough 
  440.     //  MemoryObject block in this FarHeapBlock.
  441.     //  So try the next block
  442.     }
  443. while (p != NULL);
  444. //  If we fall out of the bottom of this loop, then 
  445. //  we did not find anything in the current list of 
  446. //  blocks, so create a new one (new will 
  447. //  automatically chain it into the list of existing 
  448. //  FarHeapBlocks
  449.  
  450. block_allocated = new FarHeapBlock;
  451. __segment new_seg = 
  452.         (__segment) SELECTOROF  (block_allocated);
  453. return new_seg:>block_allocated->free_list;
  454. }
  455.  
  456. void FAR * MemoryObject::AllocateBlock 
  457.                                 (int required_size)
  458. {
  459. MemoryObject * p_new_obj
  460.             = new (required_size + 
  461.                    sizeof(MemoryObject)) MemoryObject;
  462. //  We need to return a pointer to the required block,
  463. //  so step over the CMemoryObject header provided it
  464. //  is not NULL (ie no error has occurred)
  465. return p_new_obj != NULL 
  466.        ? ++p_new_obj 
  467.        : NULL;
  468. }
  469.  
  470. void MemoryObject::ReturnBlock (void FAR * p_block)
  471. {
  472. MemoryObject * p_old_obj = (MemoryObject *) p_block;
  473. //  Get the MemoryObject header and delete it.
  474. delete --p_old_obj;
  475. }
  476.  
  477. void MemoryObject::PrintHeapReport (ostream & fout, 
  478.                                     char * msg)
  479. {
  480. #pragma warning (disable: 4270)     
  481. //  Stop unwanted warning from iomanip.h
  482. fout << hex;
  483. fout << "Singleton's Heap Reporter"; 
  484. if (msg != NULL)
  485.     fout << " - " << msg;
  486. fout << endl << endl;
  487.  
  488. fout << "FarHeapBlock::first_fhb = " 
  489.      << FarHeapBlock::first_fhb 
  490.      << ", last_fhb = " << FarHeapBlock::last_fhb 
  491.      << endl;
  492.  
  493. if (!FarHeapBlock::IsEmpty ())
  494.     {   //  Summarise heap details
  495.     FHB_POSITION p = FarHeapBlock::GetHeadPosition ();
  496.     int heap_block_count = 0;
  497.     fout << endl << "Heap Block Summary" << endl 
  498.          << endl; 
  499.     char * titles [] = {"MY_HG", "PREV_HG", "NEXT_HG",
  500.                         "SIZE", "FST_FR", "LST_FR", 
  501.                         "FST_USE", "LST_USE"};
  502.     int col_widths [] = {6, 8, 8, 6, 9, 9, 9, 9};
  503.     int no_of_cols = sizeof (col_widths) / 
  504.                      sizeof (col_widths [1]);
  505.     for (int i = 0; i < no_of_cols; i++)
  506.         fout << setiosflags (ios::right) 
  507.              << setw (col_widths [i]) 
  508.              << titles [i];
  509.     fout << endl;                    
  510.     while (p != NULL)
  511.         {
  512.         FP_FHB p_fhb = FarHeapBlock::GetNext (p);
  513.         for (int i = 0; i < no_of_cols; i++)
  514.             {
  515.             fout << setiosflags (ios::right) 
  516.                  << setw (col_widths [i]);
  517.             switch (i)
  518.             {                          
  519.             case 0: fout << p_fhb->my_hglobal; break;
  520.             case 1: 
  521.                 fout << p_fhb->previous_hglobal; 
  522.                 break;
  523.             case 2: 
  524.                 fout << p_fhb->next_hglobal; break;
  525.             case 3: 
  526.                 fout << p_fhb->Size (); break;
  527.             case 4: 
  528.                 fout << (WORD) p_fhb->free_list; 
  529.                 break;
  530.             case 5: 
  531.                 fout << (WORD) p_fhb->end_free_list; 
  532.                 break;
  533.             case 6: 
  534.                 fout << (WORD) p_fhb->in_use_list; 
  535.                 break;
  536.             case 7: 
  537.                 fout << (WORD) p_fhb->end_in_use_list; 
  538.                 break;
  539.             default:    ASSERT (FALSE);
  540.             }
  541.             }    
  542.         fout << endl;
  543.         heap_block_count++;
  544.         } 
  545.     
  546.     //  Now output the details for the individual 
  547.     //  heap blocks
  548.     p = FarHeapBlock::GetHeadPosition ();
  549.     for (int block_count = 0; 
  550.         block_count < heap_block_count; 
  551.         block_count++)
  552.         {
  553.         FP_FHB p_fhb = FarHeapBlock::GetNext (p);
  554.         fout << endl 
  555.              << "Heap Block Details for block "
  556.              << block_count << ", HGLOB = " << p
  557.              << ", base = " << (DWORD) p_fhb 
  558.              << endl << endl;
  559.         char * btitles [] = {"BASE", "SIZE", "FLAGS",
  560.                              "PREV", "NEXT"};
  561.         int bwidths [] = {8, 8, 8, 9, 9};
  562.         int no_of_bcols = sizeof(bwidths) / 
  563.                           sizeof (bwidths [0]);
  564.         for (int i = 0; i < no_of_bcols; i++)
  565.             fout << setiosflags (ios::right) 
  566.                  << setw (bwidths [i])
  567.                  << btitles [i];
  568.         fout << endl;                   
  569.         //  First print the free list
  570.         if (p_fhb->free_list != NULL)
  571.             {
  572.             __segment cur_seg = 
  573.                     (__segment) SELECTOROF (p_fhb);
  574.             FP_MOBJECT p_mo = 
  575.                     cur_seg:>p_fhb->free_list;
  576.             while (OFFSETOF (p_mo) != NULL)
  577.                 {
  578.                 ASSERT (AfxIsValidAddress (p_mo, 
  579.                             sizeof (MemoryObject)));
  580.                 for (int i = 0; i < no_of_bcols; i++)
  581.                     {
  582.                     fout << setiosflags (ios::right) 
  583.                          << setw (bwidths [i]);
  584.                     switch (i)
  585.                     {
  586.                     case 0: 
  587.                         fout << (DWORD) p_mo; break;
  588.                     case 1: 
  589.                         fout << p_mo->mo_block_size; 
  590.                         break;
  591.                     case 2: 
  592.                         #if defined (_DEBUG)
  593.                             fout << p_mo->flags; 
  594.                         #else
  595.                             fout << 0;
  596.                         #endif
  597.                         break;
  598.                     case 3: 
  599.                         fout << (WORD) p_mo->prev_mo; 
  600.                         break;
  601.                     case 4: 
  602.                         fout << (WORD) p_mo->next_mo; 
  603.                         break; 
  604.                     case 5: break;
  605.                     default: ASSERT (FALSE);
  606.                     }
  607.                     }
  608.                 fout << endl;
  609.                 p_mo = cur_seg:>p_mo->next_mo;
  610.                 }   
  611.             }
  612.         else fout << "Free list is empty" << endl;
  613.         
  614.         //  Now print the in-use list
  615.         if (p_fhb->in_use_list != NULL)
  616.             {
  617.             __segment cur_seg = 
  618.                         (__segment) SELECTOROF (p_fhb);
  619.             FP_MOBJECT p_mo = 
  620.                         cur_seg:>p_fhb->in_use_list;
  621.             while (OFFSETOF (p_mo) != NULL)
  622.                 {
  623.                 ASSERT (AfxIsValidAddress (p_mo, 
  624.                               sizeof (MemoryObject)));
  625.                 for (int i = 0; i < no_of_bcols; i++)
  626.                     {
  627.                     fout << setiosflags (ios::right) 
  628.                          << setw (bwidths [i]);
  629.                     switch (i)
  630.                     {
  631.                     case 0: 
  632.                         fout << (DWORD) p_mo; break;
  633.                     case 1: 
  634.                         fout << p_mo->mo_block_size; 
  635.                         break;
  636.                     case 2: 
  637.                         #if defined (_DEBUG)
  638.                             fout << p_mo->flags; 
  639.                         #else
  640.                             fout << 0;
  641.                         #endif
  642.                         break;
  643.                     case 3: 
  644.                         fout << (WORD) p_mo->prev_mo; 
  645.                         break;
  646.                     case 4: 
  647.                         fout << (WORD) p_mo->next_mo; 
  648.                         break; 
  649.                     case 5: break;
  650.                     default: ASSERT (FALSE);
  651.                     }
  652.                     }
  653.                 fout << endl;
  654.                 p_mo = cur_seg:>p_mo->next_mo;
  655.                 }   
  656.             }
  657.         else fout << "In use list is empty" << endl;
  658.         
  659.         fout << endl;
  660.         }
  661.     }
  662. #pragma warning (default: 4270)
  663. }
  664.  
  665. BOOL MemoryObject::MemoryHeapIsEmpty ()
  666.     {return FarHeapBlock::IsEmpty ();}
  667.  
  668. int MemoryObject::MemoryHeapInUseCount ()
  669. {
  670. if (FarHeapBlock::IsEmpty ())
  671.     return 0;
  672.     
  673. int usage_count = 0;;
  674. FHB_POSITION p = FarHeapBlock::GetHeadPosition ();
  675. while (p != NULL)
  676.     {
  677.     FP_FHB p_fhb = FarHeapBlock::GetNext (p);
  678.     ASSERT(p_fhb->in_use_list != NULL); 
  679.     //  NULL blocks should have been returned to 
  680.     //  Windows
  681.     __segment cur_seg = (__segment) SELECTOROF (p_fhb);
  682.     FP_MOBJECT p_mo = cur_seg:>p_fhb->in_use_list;
  683.     while (OFFSETOF (p_mo) != NULL)
  684.         {
  685.         ASSERT (AfxIsValidAddress (p_mo, 
  686.                              sizeof (MemoryObject)));
  687.         usage_count++;
  688.         p_mo = cur_seg:>p_mo->next_mo;
  689.         }
  690.     }   
  691. return usage_count;
  692. }
  693.  
  694. int MemoryObject::HeapBlockInUseCount ()
  695.     {return FarHeapBlock::GetCount ();} 
  696.  
  697. void MemoryObject::SetAllocationFlag (int flag_val)
  698. {
  699. #if defined (_DEBUG)
  700.     flags = flag_val;
  701. #endif
  702. }
  703.  
  704. void MemoryObject::SetFirstMemoryObject(HGLOBAL hglob, 
  705.                                         unsigned size)
  706. {
  707. my_heap_block = hglob;
  708. prev_mo = NULL;
  709. next_mo = NULL;
  710. mo_block_size = size;
  711. SetAllocationFlag (unallocated);
  712. }
  713.  
  714. #if defined (_DEBUG)
  715. void MemoryObject::DumpAllObjects ()
  716. {
  717. if (FarHeapBlock::IsEmpty ())
  718.     return;
  719.  
  720. FHB_POSITION p = FarHeapBlock::GetHeadPosition ();
  721. while (p != NULL)
  722.     {
  723.     FP_FHB p_fhb = FarHeapBlock::GetNext (p);
  724.     ASSERT(p_fhb->in_use_list != NULL); 
  725.     //  NULL blocks should have been returned to 
  726.     //  Windows
  727.     __segment cur_seg = (__segment) SELECTOROF (p_fhb);
  728.     FP_MOBJECT p_mo = cur_seg:>p_fhb->in_use_list;
  729.     while (OFFSETOF (p_mo) != NULL)
  730.         {
  731.         ASSERT (AfxIsValidAddress (p_mo, 
  732.                 sizeof (MemoryObject)));
  733.         TRACE1 ("MemoryObject, size %d, ", 
  734.                 p_mo->mo_block_size);
  735.         if (p_mo->Lno == 0)
  736.             TRACE0 ("no location details\n");
  737.         else
  738.             TRACE2 ("allocated at line %d of %s\n",
  739.                      p_mo->Lno, p_mo->Fname);
  740.         p_mo = cur_seg:>p_mo->next_mo;
  741.         }
  742.     }   
  743.  
  744. }
  745. #endif
  746.