📄 mem_test.cpp
字号:
/***************************************************************************
Test out the Tree, List, Stack, and Queue Routines in EDS.LIB
****************************************************************************/
#include <stdio.h>
#if C_UNIX
#include <signal.h>
#endif
#include "cmemlib.h"
#define C_ANSI 1
// #define DEBUG
#if C_ANSI
#include <string.h>
#include <stdlib.h>
#include <conio.h>
#include <iostream.h>
#endif
#define MAX_STR_LEN 20 /* maximum length of any string */
#define TEST_MEMBERS (500) /* number of test elements/cases */
#define TEST_MAX_RUNS 400
#define E_LIST 1 /* Link list */
#define E_TREE 2 /* Binary tree */
#define E_STACK 3 /* stack (LIFO) */
#define E_QUEUE 4 /* queue (FIFO) */
#define E_HEAP 5 /* heap (priority queue) */
#define E_TEST_ALL 6
/*
** The TEST_S structure is used as an independant data store to verify
** the accuracy of the data store being tested. It is the 'control'
** for these experiments
*/
struct TEST_S{
CHAR szName[MAX_STR_LEN]; /* alpha form of id = number */
SHORT sId; /* numeric of id */
SHORT sMode; /* sMode, TRUE = in data store,
FALSE = not in data store */
};
typedef struct TEST_S TEST_T;
typedef TEST_T * TEST_P;
typedef TEST_T ** TEST_PP;
/*
** (ANSI) Prototypes for local functions
*/
#if C_ANSI
SHORT
CompareData(PVOID pvData1,PVOID pvData2);
#else
SHORT
CompareData();
#endif
#if C_UNIX
void set_signal();
void KILL();
#endif
#if C_ANSI
VOID SpinCheck(PSHORT psSpinner);
#else
VOID SpinCheck();
#endif
int fKILL = 0; /* set if UNIX stop */;
/*
** Init Menu Selections for user
*/
CHAR szTestName[E_TEST_ALL][40] = { "Link List",
"Binary Tree",
"Stack",
"Queue",
"Heap",
"All" };
#define BACK_SPACE 8
#define SPIN_SIZE 8
CHAR cSpin[SPIN_SIZE + 1] = { "|/-\\|/-\\" };
int main()
{
TREE_C clTree; // Tree Object
LLIST_C clList; // Link List object
HEAP_C clHeap(TEST_MEMBERS); // Heap Object
STACK_C clStack;
QUEUE_C clQueue;
SHORT sPriority; // heap priority
PVOID pvData; /* work variable */
TEST_P pstTest; /* working test type */
SHORT sSel; /* current test case */
LONG lTestErrors[E_HEAP]; /* counter for errors if any occur */
int sSelection; /* menu selection, test types */
BOOL fInData; /* if test in data structures */
int iCnt;
ULONG ulTestIterations[E_HEAP];
ULONG ulMasterIterations[E_HEAP];
SHORT sTestMode;
static TEST_T stTest[TEST_MEMBERS + 1]; /* test cases */
SHORT sSpinner = 0;
#if C_UNIX
set_signal();
#endif
clTree.SetCompareFunc(CompareData);
clList.SetCompareFunc(CompareData);
clHeap.SetCompareFunc(CompareData);
clQueue.SetCompareFunc(CompareData);
clStack.SetCompareFunc(CompareData);
for(sSelection = 0; sSelection < E_HEAP; sSelection++)
{
lTestErrors[sSelection] = 0;
ulTestIterations[sSelection] = 0;
ulMasterIterations[sSelection] = 0;
}
cout << "\n\n";
cout << "C++ Algorithms v 1.0 - Test program\n\n";
cout << "1 Link List\n";
cout << "2 Binary Tree\n";
cout << "3 Stack\n";
cout << "4 Queue\n";
cout << "5 Heap\n";
cout << "6 Test All\n\n";
cin >> sSelection;
/*
** Make sure selection in range, else exit
*/
if(
(sSelection >= E_LIST) &&
(sSelection <= E_TEST_ALL)
)
{
;
}
else
exit(1);
sTestMode = sSelection; /* remember */
/*
** Load up the test control data
*/
for(sSel = 1; sSel < TEST_MEMBERS; sSel++)
{
sprintf(stTest[sSel].szName,"%d",sSel);
stTest[sSel].sId = sSel;
stTest[sSel].sMode = C_FALSE;
}
/*
** Heap is only data type requiring initialization beyond just
** setting pointer to NULL. The heap is implemented in an array
** so the array must be alloc'd before use.
*/
if(sSelection > E_HEAP)
sSelection = E_LIST;
cout << "Errors will be printed if they occur......";
#if C_ANSI
cout << "\nHit any key to end test\n";
#else
cout << "\nHit Ctrl-C to end test\n";
#endif
cout << "\nTesting " << szTestName[sSelection - 1];
while(!fKILL)
{
/*
** Select test member at random
*/
sSel = rand() % TEST_MEMBERS;
#ifdef DEBUG
#else
SpinCheck(&sSpinner);
#endif
#ifdef DEBUG
cout << sSel;
#endif
/*
** Process if control says should not be in data store
*/
/*
** Check everything
*/
for(iCnt = 0; iCnt < TEST_MEMBERS; iCnt++)
{
switch(sSelection)
{
case E_LIST:
clList.Find((PVOID) stTest[iCnt].szName, &pvData);
fInData = (pvData != NULL);
break;
case E_STACK:
clStack.Find((PVOID) stTest[iCnt].szName, &pvData);
fInData = (pvData != NULL);
break;
case E_QUEUE:
clQueue.Find((PVOID) stTest[iCnt].szName, &pvData);
fInData = (pvData != NULL);
break;
case E_TREE:
clTree.Find((PVOID) stTest[iCnt].szName, &pvData);
fInData = (pvData != NULL);
break;
case E_HEAP:
clHeap.Find((PVOID) stTest[iCnt].szName, &pvData);
fInData = (pvData != NULL);
break;
}
if(fInData != stTest[iCnt].sMode)
{
if(stTest[iCnt].sMode)
cout << "\nDid not find " << iCnt << " - should have been in " << szTestName[sSelection - 1] << "\n";
else
cout << "\nFound " << iCnt << " - should not have been in " << szTestName[sSelection - 1] << "\n";
lTestErrors[sSelection -1]++;
cout << "Total errors = " << lTestErrors[sSelection - 1] << "\n";
}
}
if(stTest[sSel].sMode == C_FALSE)
{
#ifdef DEBUG
cout << "+"
#endif
/*
** Add to data store
*/
switch(sSelection)
{
case E_LIST:
clList.Insert((PVOID) &stTest[sSel]);
break;
case E_STACK:
clStack.Push((PVOID) &stTest[sSel]);
break;
case E_QUEUE:
clQueue.Enq((PVOID) &stTest[sSel]);
break;
case E_TREE:
clTree.Insert((PVOID) &stTest[sSel]);
break;
case E_HEAP:
clHeap.Enq(sPriority,(PVOID) &stTest[sSel]);
}
/*
** Mark control as being in data store
*/
stTest[sSel].sMode = C_TRUE;
}
else if(stTest[sSel].sMode == C_TRUE)
{
/*
** Process if control says should be in data store
*/
#ifdef DEBUG
cout << "-";
#endif
/*
** Remove from data store
*/
/*
** Usage of Stacks, Queues, and Heaps requires that
** the member removed is not selectable.
**
** For stacks, it is the item on top.
** For queues, it is the oldest item.
** For heaps, it is the item with the highest priority
**
** Because of this, stack, queue, and heap item removals
** also reset the control number (sSel) to that of the
** item which was removed
*/
switch(sSelection)
{
case E_LIST:
clList.Find((PVOID) stTest[sSel].szName,&pvData);
clList.DeleteCur();
break;
case E_STACK:
clStack.Pop((PPVOID) &pvData);
pstTest = (TEST_P) pvData;
sSel = pstTest -> sId;
break;
case E_QUEUE:
clQueue.Deq((PPVOID) &pvData);
pstTest = (TEST_P) pvData;
sSel = pstTest -> sId;
break;
case E_TREE:
clTree.Delete((PVOID) stTest[sSel].szName);
break;
case E_HEAP:
clHeap.Deq(&sPriority,(PPVOID)&pvData);
pstTest = (TEST_P) pvData;
sSel = pstTest -> sId;
}
#ifdef DEBUG
cout << "D " << sSel;
#endif
stTest[sSel].sMode = C_FALSE;
}
/*
** You will note that this program uses 'goto'. After years of
** heartburn with goto's, there has developed in the programming
** community a phobia of using goto at all. Even the SLC shows this.
** There have even been languages created which do not have a goto
** (Modula-2). I feel there is a case for using goto only under
** 1 condition, there is only one label to 'goto' and the goto
** is always towards the bottom of the function or to exit
** the function.
**
** Without using any goto's, you end up with extra levels of 'if'
** statements and code that is harder to read and has higher
** essential and cyclomatic complexities (cf. Software Metrics, McCabe).
**
** If you are in a module and have encountered a condition that means
** there is nothing else you can do there, GET OUT!. Don't keep
** setting return codes and checking return codes as you fall-through
** the module, just get out. There should be only one entry point and
** exit point from the module so you should NOT have multiple return
** statements. You should goto the common exit label and return
** from there. The goto itself should normally be masked with a
** define (cf C_LEAVE() in EDSDEF.H).
**
*/
LOOP_BOT:
ulTestIterations[sSelection - 1]++;
ulMasterIterations[sSelection - 1]++;
if(sTestMode == E_TEST_ALL)
{
if(ulTestIterations[sSelection - 1] >= TEST_MAX_RUNS)
{
sSpinner = 0;
switch(sSelection)
{
#ifdef DEBUG
cout << "\nVACATE\n";
#endif
case E_LIST:
clList.Vacate(C_FALSE);
break;
case E_QUEUE:
clQueue.Vacate(C_FALSE);
break;
case E_TREE:
clTree.Vacate(C_FALSE);
break;
case E_STACK:
clStack.Vacate(C_FALSE);
break;
case E_HEAP:
clHeap.Vacate(C_FALSE);
break;
}
ulTestIterations[sSelection - 1] = 0;
for(sSel = 0; sSel < TEST_MEMBERS; sSel++)
{
stTest[sSel].sMode = C_FALSE;
}
sSelection++;
if(sSelection > E_HEAP)
sSelection = E_LIST;
cout << "\nTesting " << szTestName[sSelection - 1];
}
}
#if C_ANSI
if(kbhit())
fKILL = 1;
#endif
#if C_UNIX
usleep(1); /* give cpu a break */
#endif
}
/* getch(); */ /* get the character at the keyboard */
if(sTestMode >= E_HEAP)
clHeap.Vacate(C_FALSE);
cout << "\n";
if(sTestMode <= E_HEAP)
{
cout << szTestName[sSelection - 1] << " Test";
cout << " = " << ulMasterIterations[sSelection -1] << " iterations ";
cout << "with " << lTestErrors[sSelection -1] << " errors\n";
}
else
{
for(sSelection = 0; sSelection < E_HEAP; sSelection++)
{
cout << "\n" << szTestName[sSelection] << " Test";
cout << " = " << ulMasterIterations[sSelection] << " iterations ";
cout << "with " << lTestErrors[sSelection] << " errors\n";
}
}
}
SHORT
CompareData(PVOID pvData1,PVOID pvData2)
{
return(strcmp((PCHAR) pvData1,(PCHAR) pvData2));
}
#if C_UNIX
void set_signal()
{
signal(SIGHUP, KILL);
signal(SIGINT, KILL); /* this one works for cntl c */
signal(SIGQUIT, KILL);
signal(SIGILL, KILL);
signal(SIGTRAP, KILL);
signal(SIGABRT, KILL);
signal(SIGEMT, KILL);
signal(SIGFPE, KILL);
signal(SIGKILL, KILL);
signal(SIGBUS, KILL);
signal(SIGSYS, KILL);
signal(SIGPIPE, KILL);
signal(SIGALRM, KILL);
signal(SIGTERM, KILL);
}
void KILL()
{
fKILL = 1;
}
#endif
#if C_ANSI
void SpinCheck(PSHORT psSpinner)
#else
void SpinCheck(psSpinner)
PSHORT psSpinner;
#endif
{
static SHORT sCnt = 0;
char szBuf[3];
(*psSpinner)++;
if((*psSpinner) > (SPIN_SIZE * 100))
*psSpinner = 0;
if((*psSpinner) % 50)
{
sCnt++;
if(sCnt >= SPIN_SIZE)
sCnt = 0;
sprintf(szBuf,"%c%c",cSpin[sCnt],BACK_SPACE);
cout << szBuf;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -