Example: Using Based Pointers
Previous programs have shown how to sort files in various situations. The object, of course, is to illustrate different ways to manage memory, not to discuss sorting techniques. Program 5-1 uses a binary search tree that is destroyed after each sort, and Program 5-4 sorts an array of fixed-size records in mapped memory. Appendix C shows performance results for different implementations, including the next one in Program 5-4.
Figure 5-5 shows the relationship of the index file to the file to be sorted. Program 5-5, sortMM, is the main program that sets up the file mapping, sorts the index file, and displays the results. It calls a function, CreateIndexFile, which is shown in Program 5-6.
Program 5-5. sortMM: Based Pointers in an Index File
/* Chapter 5. sortMM command.
Memory Mapped sorting -- one file only. Options:
-r Sort in reverse order.
-I Use existing index file to produce sorted file. */
#include "EvryThng.h"
int KeyCompare (LPCTSTR , LPCTSTR);
DWORD CreateIndexFile (DWORD, LPCTSTR, LPTSTR);
DWORD KStart, KSize; /* Key start position & size (TCHAR). */
BOOL Revrs;
int _tmain (int argc, LPTSTR argv [])
{
HANDLE hInFile, hInMap; /* Input file handles. */
HANDLE hXFile, hXMap; /* Index file handles. */
HANDLE hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
BOOL IdxExists;
DWORD FsIn, FsX, RSize, iKey, nWrite, *pSizes;
LPTSTR pInFile = NULL;
LPBYTE pXFile = NULL, pX;
TCHAR _based (pInFile) *pIn;
TCHAR IdxFlNam [MAX_PATH], ChNewLine = TNEWLINE;
int FlIdx =
Options (argc, argv, _T ("rI"), &Revrs, &IdxExists, NULL);
/* Step 1: Open and map the input file. */
hInFile = CreateFile (argv [FlIdx], GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
hInMap = CreateFileMapping (hInFile, NULL,
PAGE_READWRITE, 0, 0, NULL);
pInFile = MapViewOfFile (hInMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
FsIn = GetFileSize (hInFile, NULL);
/* Steps 2 and 3: Create the index file name. */
_stprintf (IdxFlNam, _T ("%s%s"), argv [FlIdx], _T (".idx"));
if (!IdxExists)
RSize = CreateIndexFile (FsIn, IdxFlNam, pInFile);
/* Step 4: Map the index file. */
hXFile = CreateFile (IdxFlNam, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
hXMap = CreateFileMapping (hXFile, NULL, PAGE_READWRITE,
0, 0, NULL);
pXFile = MapViewOfFile (hXMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
FsX = GetFileSize (hXFile, NULL);
pSizes = (LPDWORD) pXFile; /* Size fields in .idx file. */
KSize = *pSizes; /* Key size */
KStart = *(pSizes + 1); /* Start position of key in record. */
FsX -= 2 * sizeof (DWORD);
/* Step 5: Sort the index file with qsort. */
if (!IdxExists)
qsort (pXFile + 2 * sizeof (DWORD), FsX / RSize,
RSize, KeyCompare);
/* Step 6: Output the input file in sorted order. */
pX = pXFile + 2 * sizeof (DWORD) + RSize - sizeof (LPTSTR);
for (iKey = 0; iKey < FsX / RSize; iKey++) {
WriteFile (hStdOut, &ChNewLine, TSIZE, &nWrite, NULL);
/* The cast on pX is necessary! */
pIn = (TCHAR _based (pInFile)*) *(LPDWORD) pX;
while ((*pIn != CR || *(pIn + 1) != LF)
&& (DWORD) pIn < FsIn) {
WriteFile (hStdOut, pIn, TSIZE, &nWrite, NULL);
pIn++;
}
pX += RSize;
}
UnmapViewOfFile (pInFile);
CloseHandle (hInMap);
CloseHandle (hInFile);
UnmapViewOfFile (pXFile);
CloseHandle (hXMap);
CloseHandle (hXFile);
return 0;
}
Figure 5-5. Sorting with a Memory-Mapped Index File
[View full size image]

Program 5-6. sortMM: Creating the Index File
DWORD CreateIndexFile (DWORD FsIn, LPCTSTR IdxFlNam, LPTSTR pInFile)
{
HANDLE hXFile;
TCHAR _based (pInFile) *pInScan = 0;
DWORD nWrite;
/* Step 2a: Create an index file. Do not map it yet. */
hXFile = CreateFile (IdxFlNam, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
/* Step 2b: Get first key & determine key size/start.
Skip white space and get key length. */
KStart = (DWORD) pInScan;
while (*pInScan != TSPACE && *pInScan != TAB)
pInScan++; /* Find the first key field. */
KSize = ((DWORD) pInScan - KStart) / TSIZE;
/* Step 3: Scan the complete file, writing keys
and record pointers to the key file. */
WriteFile (hXFile, &KSize, sizeof (DWORD), &nWrite, NULL);
WriteFile (hXFile, &KStart, sizeof (DWORD), &nWrite, NULL);
pInScan = 0;
while ((DWORD) pInScan < FsIn) {
WriteFile (hXFile, pInScan + KStart, KSize * TSIZE,
&nWrite, NULL);
WriteFile (hXFile, &pInScan, sizeof (LPTSTR),
&nWrite, NULL);
while ((DWORD) pInScan < FsIn && ((*pInScan != CR)
|| (*(pInScan + 1) != LF))) {
pInScan++; /* Skip to end of line. */
}
pInScan += 2; /* Skip past CR, LF. */
}
CloseHandle (hXFile);
/* Size of an individual record. */
return KSize * TSIZE + sizeof (LPTSTR);
}
