\chapter{MEMORY MANAGER}
The purpose of the memory manager utilities is to allow an applications
programmer to write standard, readable FORTRAN-77 code while employing
dynamic memory management for REAL, INTEGER, and LOGICAL type arrays.

Because the array sizes in most programs are problem dependent, the
program's memory requirements are not known until the program is running.
Since FORTRAN-77 does not provide for dynamic memory allocation, the
programmer has to either predict the maximum memory requirement or use
machine dependent requests for memory.  In addition, dynamic memory
allocation is an error prone exercise which tends to make the source code
difficult to read and maintain.

The memory manager utilities are written in standard FORTRAN-77 and provide
an interface which encourages readable coding and efficient use of memory
resources.  Machine dependencies are isolated through the use of the FORTRAN
extension library (Chapter~\ref{sec:extlib}). All memory requests are in
terms of {\em numeric storage units} (the amount of memory occupied by an
integer, real, or logical datum~\cite{ansi}). 

The memory manager utility is divided into three categories; basic routines,
advanced routines, and development aids.  These categories will be discussed
in sections \ref{sec:mbas} through \ref{sec:mdev}.


\section{Pointer System}
In order to use the memory manager properly, the user must first understand
the concept of a base array with pointers for accessing memory locations.
The memory manager references all memory relative to a user supplied base
array.  A reference to memory is made in terms of an index or pointer to
this base array.  The pointers which the memory manager provides may take on
a wide range of values, including negative numbers.

The base array must comply with the following rules:
\begin{enumerate}
\item The array must be of type INTEGER, REAL, or LOGICAL.  Modified word
length storage arrays such as INTEGER\last2 or REAL\last8 will result in
invalid pointers with no error message. 

\item The lower bound of the array subscript must be one.
\end{enumerate}

The following FORTRAN statement defines a valid base array:

DIMENSION A(1)

ONLY ONE BASE ARRAY MAY BE USED IN A PROGRAM.

In order to use memory allocated by the memory manager, the user merely
needs to pass the base array with the correct pointer to a subprogram.  For
example, for a base array A and a pointer IP, a subroutine call would be:

\verb+CALL SUBBIE ( A(IP) )+

Although the programmer is not restricted to using the allocated memory in
subprograms only, the recommended usage for the memory manager is to
allocate dynamic arrays in the main program and then pass them to
subroutines.


\section{Basic Routines}\label{sec:mbas}
The basic memory manager routines are those which are most commonly used and
require little understanding of the internal workings of the utility.

\subsection{Initialize (MDINIT)}
The memory manager {\em must} be initialized with a call to MDINIT before
any memory can be allocated.  The main purpose of the initialization is to
determine the location of the base array in memory. 

\verb+CALL MDINIT (BASE)+

\begin{argy}{BASE}{INTEGER, LOGICAL or REAL Array}{Read Only}
This array is used as a base reference to all dynamically allocated memory. 
\end{argy}

\subsection{Define Dynamic Array (MDRSRV)}
MDRSRV declares a new dynamic array.  The user supplies the space required,
and a pointer to the new space is returned.  Note that the contents of the
new storage are undefined.

\verb+CALL MDRSRV (NAME, NEWPNT, NEWLEN)+

\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
This is the name of the new dynamic array. The memory manager will add this
name to its internal dictionary; each array must have a unique name.  The
first eight characters are used for comparison, and leading and embedded
blanks are significant. 
\end{argy}

\begin{argy}{NEWPNT}{INTEGER}{Write Only}
This is the pointer to storage allocated to this dynamic array relative to
the base array. 
\end{argy}

\begin{argy}{NEWLEN}{INTEGER}{Read Only}
This is the length to be reserved for the new array. Any nonnegative number
is acceptable.  A zero length does not cause any storage to be allocated and
returns a pointer equal to one. 
\end{argy}

\subsection{Delete Dynamic Array (MDDEL)}
MDDEL releases the memory that is allocated to a dynamic array.

\verb+CALL MDDEL (NAME)+

\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
This is the name of the dynamic array which is to be deleted.  The array
name must match an existing name in the dictionary.  The first eight
characters are used for comparison, and leading and embedded blanks are
significant. 
\end{argy}

\subsection{Reserve Memory Block (MDGET)}
MDGET reserves a contiguous block of memory without associating the block of
memory with an array.  MDGET should be called prior to a series of calls to
MDRSRV to improve efficiency and to reduce memory fragmentation.  Further
discussion of the operation of MDGET is found in section~\ref{sec:table}.

\verb+CALL MDGET (MNGET)+

\begin{argy}{MNGET}{INTEGER}{Read only}
This specifies the desired contiguous block size.
\end{argy}

\subsection{Release Unallocated Memory (MDGIVE)}
MDGIVE causes the memory manager to return unused storage to the operating
system, if possible.

\verb+CALL MDGIVE ()+


\subsection{Obtain Statistics (MDSTAT)}
MDSTAT returns memory manager statistics.  MDSTAT provides the only method
for error checking, and thus should be used after other calls to the memory
manager to assure no errors have occurred.

\verb+CALL MDSTAT (MNERRS, MNUSED)+

\begin{argy}{MNERRS}{INTEGER}{Write Only}
This is the total number of errors detected by the memory manager during the
current execution. 
\end{argy}

\begin{argy}{MNUSED}{INTEGER}{Write Only}
This is the total number of words that are currently allocated to dynamic
arrays. 
\end{argy}

\subsection{Print Error Summary (MDEROR)}
MDEROR prints a summary of all errors detected by the memory manager.  The
return status of the last memory manager routine called is also printed.
MDEROR should be called any time an error is detected by a call to MDSTAT.

\verb+CALL MDEROR (IUNIT)+

\begin{argy}{IUNIT}{INTEGER}{Read Only}
This is the unit number of the output device.
\end{argy}

\begin{center}
\begin{tabular}{|rl|} \hline \hline
\multicolumn{2}{|c|}{ERROR CODES}\\ \hline
  1 &  SUCCESSFUL COMPLETION\\
  2 &  UNABLE TO GET REQUESTED STORAGE FROM SYSTEM\\
  3 &  DATA MANAGER NOT INITIALIZED\\
  4 &  DATA MANAGER WAS PREVIOUSLY INITIALIZED\\
  5 &  NAME NOT FOUND IN DICTIONARY\\
  6 &  NAME ALREADY EXISTS IN DICTIONARY\\
  7 &  ILLEGAL LENGTH REQUEST\\
  8 &  UNKNOWN DATA TYPE\\
  9 &  DICTIONARY IS FULL\\
 10 &  VOID TABLE IS FULL\\
 11 &  MEMORY BLOCK TABLE IS FULL\\
 12 &  OVERLAPPING VOIDS - INTERNAL ERROR\\
 13 &  OVERLAPPING MEMORY BLOCKS - INTERNAL ERROR\\
 14 &  INVALID MEMORY BLOCK - EXTENSION LIBRARY ERROR \\ \hline \hline
\end{tabular}
\end{center}

\subsection{Basic Example}
\begin{verbatim}
    DIMENSION BASE(1)
    CALL MDINIT (BASE)
    CALL MDGET (30)
    CALL MDRSRV ('FIRST', I1, 10)
    CALL MDRSRV ('SECOND', I2, 10)
    CALL MDRSRV (' THIRD', I3, 10)
    CALL MDSTAT (MNERRS, MNUSED)
    IF (MNERRS .NE. 0) THEN
    CALL MDEROR (6)
    STOP
    END IF
    CALL MDDEL (' THIRD')
    CALL MDGIVE ()
\end{verbatim}

\section{Advanced Routines}
The advanced routines are supplied to give added capability to the user who
is interested in more sophisticated manipulation of memory.  These routines
are never necessary, but may be very desirable.

\subsection{Rename Dynamic Array (MDNAME)}
MDNAME renames a dynamic array from NAME1 to NAME2.  The location of the
array is not changed, nor is its length.

\verb+CALL MDNAME (NAME1, NAME2)+

\begin{argy}{NAME1}{CHARACTER\last(\last)}{Read Only}
This is the old name of the array.  The first eight characters are used for
comparison. 
\end{argy}

\begin{argy}{NAME2}{CHARACTER\last(\last)}{Read Only}
This is the new name of the array.  The first eight characters are used. 
\end{argy}

\subsection{Adjust Dynamic Array Length (MDLONG)}
MDLONG changes the length of a dynamic array.  The memory manager will
relocate the array and move its data if storage cannot be extended at the
array's current location.  The user should assume that MDLONG invalidates
the previous pointer to this array if the array is extended.

\verb+CALL MDLONG (NAME, NEWPNT, NEWLEN)+

\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
This is the name of the dynamic array which the user wishes to extend or
shorten. 
\end{argy}

\begin{argy}{NEWPNT}{INTEGER}{Write Only}
This is the new pointer to the dynamic array.
\end{argy}

\begin{argy}{NEWLEN}{INTEGER}{Read Only}
This is the new length for the dynamic array.
\end{argy}

\subsection{Locate Dynamic Array (MDFIND)}
MDFIND returns the pointer and length of storage allocated to a dynamic
array.  This routine would be used if the pointer from an earlier call to
MDRSRV was not passed to a different subprogram.

\verb+CALL MDFIND (NAME, NEWPNT, NEWLEN)+

\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
This is the name of the dynamic array to be located.
\end{argy}

\begin{argy}{NEWPNT}{INTEGER}{Write Only}
This is the pointer to the dynamic array relative to the user's reference
array. 
\end{argy}

\begin{argy}{NEWLEN}{INTEGER}{Write Only}
This is the length of the dynamic array.
\end{argy}

\subsection{Compress Storage (MDCOMP)}
MDCOMP causes fragmented memory to be consolidated.  Note that this may
cause array storage locations to change.  It is important to realize that
all pointers must be recalculated by calling MDFIND after a compress
operation.  A call to MDCOMP prior to MDGIVE will result in the return of
the maximum memory to the system.

\verb+CALL MDCOMP ()+


\section{Development Aids}\label{sec:mdev}
The routines in this section are designed to aid the programmer during
development of a program, and probably would not be used during execution of
a mature program.

\subsection{List Storage Tables (MDLIST)}
MDLIST prints the contents of the memory manager's internal tables.
Section~\ref{sec:table} describes these tables. 

\verb+CALL MDLIST (IUNIT)+

\begin{argy}{IUNIT}{INTEGER}{Read Only}
This is the unit number of the output device.
\end{argy}

\subsection{Print Dynamic Array (MDPRNT)}
MDPRNT prints the contents of an individual array.

\verb+CALL MDPRNT (NAME, IUNIT, NTYPE)+

\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
This is the name of the array to be printed.
\end{argy}

\begin{argy}{IUNIT}{INTEGER}{Read Only}
This is the unit number of the output device.
\end{argy}

\begin{argy}{NTYPE}{CHARACTER\last(\last)}{Read Only}
NTYPE indicates the data type of the data to be printed; "R" for REAL, or
"I" for INTEGER.  Note that this is not necessarily the declared type of the
base array. 
\end{argy}
