*/
Got something to write about? Check out our Article Builder.
*/

View \VARRAY.H

Display mazes in three dimensions on your VGA monitor. C++ src.

Submitted By: Unknown
Rating: (Not rated) (Rate It)


#ifndef VARRAY_H
#define VARRAY_H

//      This is a template for a virtual array of type T.

#include <stdio.h>
#include <dos.h>

#ifndef TRUE
#define TRUE -1
#endif
#ifndef FALSE
#define FALSE 0
#endif

template <class T>
class varray
  {
    private:
      int          expanded_memory_allocated(void);
                    // Allocated expanded memory.  If this can't be done,
                    // an attempt will be made to use a disk instead.
      unsigned int expanded_memory_handle;
      int          free_expanded_memory;
      int          free_disk_memory;
                    // The temporary file used for virtual memory needs to be
                    // freed.
      void         free_memory(void);
                    // Free real memory used for pages, etc.
      int          free_real_memory;
                    // Real memory needs to be freed.
      int          map_expanded_memory(int physical_page,long logical_page);
                    // Associate a physical page in the physical page frame
                    // with a logical page of expanded memory.
      int          memory_allocated(void);
                    // Allocate real memory for pages, etc.
      long         num_elements_in_array;
                    // Number of elements in the array.
      unsigned int num_elements_per_page;
                    // Number of array elements in a page.
      int          num_real_pages;
                    // Number of pages kept in real memory.
      char         *page_frame_ptr;
                    // Pointer to expanded memory physical frame.
      T            **real_page;
                    // A page in real memory.
      long         *starting_element_num;
                    // Index of first array element in page in real memory.
      FILE         *vm;
                    // Temporary file used for virtual memory.
      long         *vm_access;
                    // "When" a page in real memory was last accessed.
      long         vm_access_num;
                    // Current "time".
    public:
      int allocated(void) {return (free_real_memory &&
           (free_expanded_memory || free_disk_memory));}

          varray(T& initialized_element,long element_count,
           int real_page_count=4,unsigned int page_size=32768);
//      Construct a virtual array of type T.  The arguments are as follow:
//
//           initialized_element -- an initialized element of type T.
//
//           element_count -- the number of elements in the array.
//   
//           real_page_count -- the number of pages to be kept in memory.
//      This should be at least as large as the maximum number of elements
//      of the array referenced at once.  Small values result in too much
//      paging; large values result in too much overhead searching for the
//      page containing an element.
//
//           page_size -- the number of bytes in a page.  This must be at least
//      sizeof(T).  This is used only when a disk is used for virtual memory.
//      (When expanded memory is used, the page size is effectively 32K.)  32K
//      is probably optimal due to the overhead of searching for a page.

          ~varray(void);
//      If expanded memory was used, free it.  If a temporary file was used,
// close (and so delete) it.  If real memory was allocated, free it.

      T   *vm_ptr(long element_num);
//      Return a pointer to an element of the array.  When T is a structure, it
// is faster to use this pointer than to overload [] and search virtual memory
// for each component of the structure.

      T&  operator[](long element_num) {return *vm_ptr(element_num);}
//     Return an element of the array by overloading [].
  };

template <class T>
varray<T>::varray(T& initialized_element,long element_count,int real_page_count,
 unsigned int page_size)
//      Construct a virtual array of type T.  The arguments are as follow:
//
//           initialized_element -- an initialized element of type T.
//
//           element_count -- the number of elements in the array.
//   
//           real_page_count -- the number of pages to be kept in memory.
//      This should be at least as large as the maximum number of elements
//      of the array referenced at once.  Small values result in too much
//      paging; large values result in too much overhead searching for the
//      page containing an element.
//
//           page_size -- the number of bytes in a page.  This must be at least
//      sizeof(T).  This is used only when a disk is used for virtual memory.
//      (When expanded memory is used, the page size is effectively 32K.)  32K
//      is probably optimal due to the overhead of searching for a page.
  {
    unsigned int element_index;
    long         element_num;

    free_real_memory=FALSE;
    free_disk_memory=FALSE;
    free_expanded_memory=FALSE;
    num_real_pages=real_page_count;
    num_elements_in_array=element_count;
    if (sizeof(T) <= 32768)
      {     
        num_elements_per_page=32768/sizeof(T);
        free_expanded_memory=expanded_memory_allocated();
      }
    if (free_expanded_memory)
      if (memory_allocated()) // Allocate space for the active pages.
        {
          free_real_memory=TRUE;
          long expanded_memory_page_num=0L;
          int real_page_num=0;
          vm_access_num=0;
          int successful=TRUE;
          for (element_num=(long) 0;
           ((successful) && (element_num < num_elements_in_array));
           element_num+=((long) num_elements_per_page))
            {
              if (real_page_num < real_page_count)
              // Initialize real page.
                {
                  vm_access_num++;
                  for (element_index=(unsigned int) 0;
                   element_index < num_elements_per_page;
                   element_index++)
                    real_page[real_page_num][element_index]
                     =initialized_element;
                  vm_access[real_page_num]=vm_access_num;
                  starting_element_num[real_page_num]=element_num;
                  real_page_num++;
                }
              // Initialize virtual page.
              if (successful=map_expanded_memory(0,expanded_memory_page_num++))
                {
                  if (successful
                   =map_expanded_memory(1,expanded_memory_page_num++))
                    memcpy((void *) page_frame_ptr,(void *) &(real_page[0][0]),
                     num_elements_per_page*sizeof(T));
                }
            }
          if (! successful)
            cerr
             << "Fatal error:  there is an unexpected problem with expanded "
             << "memory." << '\n';
        }
      else
        cerr << "Fatal error:  not enough real memory for virtual array."
         << '\n';
    else
      {
        num_elements_per_page=page_size/sizeof(T);
        if ((vm=tmpfile()) == NULL) // Get a file for the virtual memory.
          cerr << "Fatal error:  cannot open virtual memory." << '\n';
        else
          if (memory_allocated()) // Allocate space for the active pages.
            {
              free_real_memory=TRUE;
              free_disk_memory=TRUE;
              int real_page_num=0;
              vm_access_num=0;
              int successful=TRUE;
              for (element_num=(long) 0;
               ((successful) && (element_num < num_elements_in_array));
               element_num+=((long) num_elements_per_page))
                {
                  if (real_page_num < real_page_count)
                  // Initialize real page.
                    {
                      vm_access_num++;
                      for (element_index=(unsigned int) 0;
                       element_index < num_elements_per_page;
                       element_index++)
                        real_page[real_page_num][element_index]
                         =initialized_element;
                      vm_access[real_page_num]=vm_access_num;
                      starting_element_num[real_page_num]=element_num;
                      real_page_num++;
                    }
                  // Initialize virtual page.
                  successful=(fwrite(&(real_page[0][0]),
                   sizeof(T),num_elements_per_page,vm)
                   == num_elements_per_page);
                }
              if (! successful)
                cerr
                 << "Fatal error:  not enough disk space for virtual array."
                 << '\n';
            }
          else
            cerr << "Fatal error:  not enough real memory for virtual array."
             << '\n';
      }
  }

template <class T>
varray<T>::~varray()
//      If expanded memory was used, free it.  If a temporary file was used,
// close (and so delete) it.  If real memory was allocated, free it.
  {
    if (free_expanded_memory)
      {
        union REGS input_reg;
        union REGS output_reg;

        input_reg.h.ah=0x45;
        input_reg.x.dx=expanded_memory_handle;
        int86(0x67,&input_reg,&output_reg);
      }
    if (free_disk_memory)
      fclose(vm);
    if (free_real_memory)
      free_memory();
  };

template <class T>
int varray<T>::expanded_memory_allocated()
  {
    char              *EMM_device_name = "EMMXXXX0";
    union REGS        input_reg;
    union
      {
        unsigned long device_name_address;
        char          *device_name_ptr;
      };
    union REGS        output_reg;
    union
      {
        unsigned long pf_address;
        char          *pf_ptr;
      };
    long              pages_needed;
    int               result;
    struct SREGS      segment_reg;

    typedef T *t_ptr;

    result=FALSE;
    pages_needed=num_elements_in_array/long(num_elements_per_page);
    if (pages_needed*long(num_elements_per_page) < num_elements_in_array)
      pages_needed++;
    pages_needed+=pages_needed; // VARRAY uses 32K byte pages;
                                // expanded memory uses 16K byte pages.
    if (pages_needed <= 0xffff)
      {     
        input_reg.h.ah=0x35;
        input_reg.h.al=0x67;
        intdosx(&input_reg,&output_reg,&segment_reg);
        device_name_address=(((unsigned long) (segment_reg.es)) << 16) + 10L;
        if (memcmp(EMM_device_name,device_name_ptr,8) == 0)
          {
            input_reg.h.ah=0x42;
            int86(0x67,&input_reg,&output_reg);
            if ((output_reg.h.ah == 0)
            &&  (pages_needed <= long(output_reg.x.bx)))
              {
                input_reg.h.ah=0x43;
                input_reg.x.bx=(unsigned int) pages_needed;
                int86(0x67,&input_reg,&output_reg);
                expanded_memory_handle=output_reg.x.dx;
                if (output_reg.h.ah == 0)
                  {
                    input_reg.h.ah=0x41;
                    int86(0x67,&input_reg,&output_reg);
                    if (result=(output_reg.h.ah == 0))
                      {
                        pf_address=(((unsigned long) (output_reg.x.bx)) << 16);
                        page_frame_ptr=pf_ptr;
                      }
                  }
              }
          }
      }
    return result;
  }

template <class T>
int varray<T>::memory_allocated()
//      Allocate real memory for pages, etc.
    {
      int result;
      int real_page_num;

      typedef T *t_ptr;

      if (result=((vm_access=new long[num_real_pages]) != NULL))
        {
          if (result=((starting_element_num=new long[num_real_pages]) != NULL))
            if (result=((real_page=new t_ptr[num_real_pages]) != NULL))
              {
                for (real_page_num=0;
                 ((result) && (real_page_num < num_real_pages));
                 real_page_num++)
                  result=((real_page[real_page_num]
                   =new T[num_elements_per_page]) != NULL);
                if (! result)
                  {
                    --real_page_num;
                    while (real_page_num > 0)
                      delete[] real_page[--real_page_num];
                    delete[] real_page;
                  }
              }
            else
              {
                delete[] starting_element_num;
                delete[] vm_access;
              }
          else
            delete[] vm_access;
        }
      return(result);
    };

template <class T>
void varray<T>::free_memory()
//      Free real memory used for pages, etc.
    {
      for (int real_page_num=0; real_page_num < num_real_pages; real_page_num++)
        delete[] real_page[real_page_num];
      delete[] real_page;
      delete[] starting_element_num;
      delete[] vm_access;
      return;
    };

template <class T>
T *varray<T>::vm_ptr(
  long element_num)
//      Return a pointer to an element of the array.
    {
      long earliest_access;
      long expanded_memory_page_num;
      int  num_oldest_real_page;
      int  page_found;
      int  real_page_num;
      T    *result;
      long virtual_page_num;

      vm_access_num++;
      page_found=FALSE;
      num_oldest_real_page=0;
      earliest_access=vm_access[0];
      for (real_page_num=0;
       ((! page_found) && (real_page_num < num_real_pages));
       real_page_num++)
        if ((element_num >= starting_element_num[real_page_num])
        &&  (element_num < ((long) num_elements_per_page)
         +(starting_element_num[real_page_num])))
          page_found=TRUE;
        else
          {
            if (vm_access[real_page_num] < earliest_access)
              {
                earliest_access=vm_access[real_page_num];
                num_oldest_real_page=real_page_num;
              }
          }
      if (page_found) // Page is already in real memory.
        {
          real_page_num--;
          result=&(real_page[real_page_num]
           [element_num-starting_element_num[real_page_num]]);
          vm_access[real_page_num]=vm_access_num;
        }
      else // Swap oldest page in real memory for the one sought.
        if (free_expanded_memory)
          {
            virtual_page_num=starting_element_num[num_oldest_real_page]
             /((long) num_elements_per_page);
            expanded_memory_page_num=virtual_page_num;
            expanded_memory_page_num+=expanded_memory_page_num;
            map_expanded_memory(0,expanded_memory_page_num++);
            map_expanded_memory(1,expanded_memory_page_num);
            memcpy((void *) page_frame_ptr,
             (void *) &(real_page[num_oldest_real_page][0]),
             num_elements_per_page*sizeof(T));
            virtual_page_num=element_num/((long) num_elements_per_page);
            expanded_memory_page_num=virtual_page_num;
            expanded_memory_page_num+=expanded_memory_page_num;
            map_expanded_memory(0,expanded_memory_page_num++);
            map_expanded_memory(1,expanded_memory_page_num);
            memcpy((void *) &(real_page[num_oldest_real_page][0]),
             (void *) page_frame_ptr,
             num_elements_per_page*sizeof(T));
            starting_element_num[num_oldest_real_page]
             =virtual_page_num*((long) num_elements_per_page);
            result=&(real_page[num_oldest_real_page][
             element_num-starting_element_num[num_oldest_real_page]]);
            vm_access[num_oldest_real_page]=vm_access_num;
          }
        else
          {
            fseek(vm,
             starting_element_num[num_oldest_real_page]*((long) sizeof(T)),
             SEEK_SET);
            fwrite(&(real_page[num_oldest_real_page][0]),sizeof(T),
             num_elements_per_page,vm);
            starting_element_num[num_oldest_real_page]
             =element_num/((long) num_elements_per_page);
            (starting_element_num[num_oldest_real_page])
             *=((long) num_elements_per_page);
            fseek(vm,
             starting_element_num[num_oldest_real_page]*((long) sizeof(T)),
             SEEK_SET);
            fread(&(real_page[num_oldest_real_page][0]),sizeof(T),
             num_elements_per_page,vm);
            result=&(real_page[num_oldest_real_page][
             element_num-starting_element_num[num_oldest_real_page]]);
            vm_access[num_oldest_real_page]=vm_access_num;
          }
      return result;
    };

template <class T>
int varray<T>::map_expanded_memory(
  int  physical_page,
  long logical_page)
//      Associate a physical page in the physical page frame with a logical page
// of expanded memory.
    {
      union REGS input_reg;
      union REGS output_reg;

      input_reg.h.ah=0x44;
      input_reg.h.al=physical_page;
      input_reg.x.bx=(unsigned int) logical_page;
      input_reg.x.dx=expanded_memory_handle;
      int86(0x67,&input_reg,&output_reg);
      return (output_reg.h.ah == 0);
    }

#endif

corner
© 1996-2008 CommunityHeaven LLC. All rights reserved. Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
North American business development: Nicolai Wadstrom. Publisher: Lars Hagelin.