home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Black Box 4
/
BlackBox.cdr
/
progc
/
ebksrc.arj
/
FLEXLIST.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-05
|
17KB
|
815 lines
/*
flexlist.cpp
11-28-90
Homogeneous-heterogeneous
hybrid stack-queue-list-array generic class.
C++ versions 1 & 2
Copyright 1990
John W. Small
All rights reserved
PSW / Power SoftWare
P.O. Box 10072,
McLean, Virginia 22102 8072
(703) 759-3838
*/
#include <flexlist.hpp>
#ifndef ANSI_C_STD_LIB
int strcmp(const char *s1, const char *s2)
{
while (*s1++ == *s2++)
if (!*s1) return 0;
return (*s1 - *s2);
}
void *memcpy(void *dest, const void *src, size_t n)
{
if (dest && src && n)
while (n--)
((char *)dest)[n]
= ((const char *)src)[n];
return dest;
}
void *memset(void *s, int c, size_t n)
{
if (s && n)
while (n--)
((char *)s)[n] = (char) c;
return s;
}
#endif
/* String variant FlexNode virtual functions */
/*
FNnew() is called by FlexList functions (member
functions) that need to allocate new variant length
FlexNodes, e.g. pushD(), insQD(), insD(),
insSortD(). A pointer to the data to be placed in
the new node is passed to FNnew(). Your FNnew()
function must decide how large that data is and
allocate a new FlexNode big enough to hold that
data, i.e.
FlexN N = new char [sizeof(FlexNode) +
sizeofYourData - 1];
Your FNnew() function must also copy that data to
the new node. "D" is never NULL!
Please note that FNnew() could call a known function
member (function) in the data to determine its size.
It could also call another function to copy/initialize
the FlexNode data area from the data. Data that
contains its own functions for interfacing with itself
are called objects. Thus FlexLists can be made to
hold polymorphic objects via the Variant FlexNode
virtual functions functionology.
Study all four virtual functions FNnew(), FNwrite(),
FNread(), and FNdestruct() for strings and how they
are called by the various FlexList functions to get
a better understanding of variant FlexLists.
*/
FlexN FlexList::FNnew(const void *D)
{
FlexN N;
for (size_t i = 0; ((char *)D)[i++];
/* no reinit */)
/* null statement */;
if ((N = (FlexN) new char [sizeof(FlexNode)+i-1])
!= FlexN0) (void) memcpy(N->data,D,i);
return N;
}
/* FNwrite() is called by storeD() to write variant data
to a variant FlexNode. FNwrite() returns true if
the write is successful. Make sure the new data
doesn't write pass the end of the old. "ND" and
"D" are never NULL! */
int FlexList::FNwrite(void *ND, const void *D)
{
char *nd, *d;
nd = (char *) ND;
d = (char *) D;
while (*nd)
if ((*nd++ = *d++) == '\0')
break;
return 1;
}
/* FNread() is called by topD(), nextD(), prevD(), and
recallD() to read variant data from a variant
FlexNode. FNread() returns true if the read is
successful or if there is no place to read the data
to. "ND" and "D" are never NULL! */
int FlexList::FNread(const void *ND, void *D)
{
char *nd, *d;
nd = (char *) ND;
d = (char *) D;
while ((*d++ = *nd++) != '\0')
/* null statement */;
return 1;
}
/* FNdestruct() is called by clear(), ~FlexList() via
clear(), popD(), and delD() to destruct variant
data in a FlexNode. Please note that references
to suballocated memory may be copied to the outgoing
data structure instead of being cloned and then
deallocated. You must keep any scheme straight
though. Clear() always passes NULL to the second
parameter of FNdestruct() via a call to delD(L,0),
however, so any suballocated memory must be freed in
that case! "ND" is never NULL but "D" can be! */
int FlexList::FNdestruct(void *ND, void *D)
{
char *nd, *d;
nd = (char *)ND;
if ((d = (char *)D) != (char *)0)
while ((*d++ = *nd++) != '\0')
/* null statement */;
return 1;
}
/* Any of the virtual functions can be inhibited by returning
0. The FlexList functions that call them will simply
return a failure indication. */
// FlexList constructors:
FlexList::FlexList(size_t sizeofNodeData, unsigned maxNodes)
{
front = rear = current = FlexN0;
curNum = nodes = this->maxNodes = 0;
this->sizeofNodeData = sizeofNode = 0;
sorted = 0;
compare = 0;
if (sizeofNodeData <= FLmaxSizeofNodeData) {
this->maxNodes = maxNodes;
this->sizeofNodeData = sizeofNodeData;
if (sizeofNodeData)
sizeofNode = sizeof(FlexNode)
+ sizeofNodeData - 1;
else
sizeofNode = 0;
sorted = 1;
}
}
FlexList::FlexList(size_t sizeofCell, unsigned cells,
const void *array)
{
front = rear = current = FlexN0;
curNum = nodes = maxNodes = 0;
sizeofNodeData = sizeofNode = 0;
sorted = 0;
compare = 0;
if ((sizeofCell <= FLmaxSizeofNodeData) &&
sizeofCell && cells && array) {
maxNodes = FLmaxMaxNodes;
sizeofNodeData = sizeofCell;
sizeofNode = sizeof(FlexNode)
+ sizeofCell - 1;
for (;cells && insQD(array); cells--)
array = (char *) array + sizeofCell;
}
}
// FlexList destructor:
int FlexList::clear()
{
while (popD())
/* null statement */;
if (!nodes)
return (sorted = 1);
return 0;
}
// FlexList stack and queue functions:
void * FlexList::pushN(FlexN N)
{
if (!N || nodes >= maxNodes)
return (void *) 0;
N->prev = FlexN0;
if ((N->next = front) != FlexN0)
N->next->prev = N;
else
rear = N;
front = N;
nodes++;
if (curNum)
curNum++;
sorted = 0;
return N->data;
}
void * FlexList::pushD(const void *D)
{
FlexN N;
if (nodes >= maxNodes)
return (void *) 0;
if (sizeofNode) { // fixed size FlexNodes
if ((N = (FlexN) new char [sizeofNode])
== FlexN0) return (void *) 0;
if (D)
memcpy(N->data,D,sizeofNodeData);
else
memset(N->data,0,sizeofNodeData);
}
else if (!D)
return (void *) 0;
else if ((N = FNnew(D)) == FlexN0)
return (void *) 0;
N->prev = FlexN0;
if ((N->next = front) != FlexN0)
N->next->prev = N;
else
rear = N;
front = N;
nodes++;
if (curNum)
curNum++;
sorted = 0;
return N->data;
}
FlexN FlexList::popN()
{
FlexN N;
if ((N = front) == FlexN0)
return FlexN0;
if (front == rear)
rear = FlexN0;
else
N->next->prev = FlexN0;
front = N->next;
nodes--;
if (curNum)
if (!--curNum)
current = FlexN0;
N->next = N->prev = FlexN0;
return N;
}
int FlexList::popD(void *D)
{
FlexN N;
if ((N = front) == FlexN0)
return 0;
if (sizeofNodeData) {
if (D)
memcpy(D,N->data,sizeofNodeData);
}
else if (!FNdestruct(N->data,D))
return 0;
if (front == rear)
rear = FlexN0;
else
N->next->prev = FlexN0;
front = N->next;
nodes--;
if (curNum)
if (!--curNum)
current = FlexN0;
delete N;
return 1;
}
void * FlexList::topD(void *D)
{
if (!front)
return (void *) 0;
if (D) if (sizeofNodeData)
memcpy(D,front->data,sizeofNodeData);
else if (!FNread(front->data,D))
return (void *) 0;
return front->data;
}
void * FlexList::insQN(FlexN N)
{
if (!N || nodes >= maxNodes)
return (void *) 0;
N->next = FlexN0;
if (rear)
rear->next = N;
else
front = N;
N->prev = rear;
rear = N;
nodes++;
sorted = 0;
return N->data;
}
void * FlexList::insQD(const void *D)
{
FlexN N;
if (nodes >= maxNodes)
return (void *) 0;
if (sizeofNode) { // fixed size FlexNodes
if ((N = (FlexN) new char [sizeofNode])
== FlexN0) return (void *) 0;
if (D)
memcpy(N->data,D,sizeofNodeData);
else
memset(N->data,0,sizeofNodeData);
}
else if (!D)
return (void *) 0;
else if ((N = FNnew(D)) == FlexN0)
return (void *) 0;
N->next = FlexN0;
if (rear)
rear->next = N;
else
front = N;
N->prev = rear;
rear = N;
nodes++;
sorted = 0;
return N->data;
}
void * FlexList::mkcur(unsigned n)
{
if (!n || (n > nodes)) { // out of range
current = 0;
curNum = 0;
return (void *) 0;
}
else if (n == curNum) // already there
return current->data;
if (current) // divide list into two parts
if (n > curNum) // in last half of list
if (((nodes >> 1) + (curNum >> 1)) < n)
// rear closest
for (current = rear, curNum = nodes;
curNum > n; curNum--)
current = current->prev;
else // current closest
for (;curNum < n; curNum++)
current = current->next;
else // in first half of list
if ((curNum >> 1) < n) // current closest
for (;curNum > n; curNum--)
current = current->prev;
else // front closest
for (current = front, curNum = 1;
curNum < n; curNum++)
current = current->next;
else // consider whole list
if ((nodes >> 1) < n) // closer to rear
for (current = rear, curNum = nodes;
curNum > n; curNum--)
current = current->prev;
else // closer to front
for (current = front, curNum = 1;
curNum < n; curNum++)
current = current->next;
return current->data;
}
void * FlexList::insN(FlexN N)
{
if (!N || nodes >= maxNodes)
return (void *) 0;
if ((N->prev = current) == FlexN0) {
if ((N->next = front) == FlexN0)
rear = N;
else
N->next->prev = N;
front = N;
}
else { // after current
if ((N->next = current->next) == FlexN0)
rear = N; // last node
else
N->next->prev = N;
current->next = N;
}
current = N;
curNum++;
nodes++;
sorted = 0;
return N->data;
}
void * FlexList::insD(const void *D)
{
FlexN N;
if (nodes >= maxNodes)
return (void *) 0;
if (sizeofNode) { // fixed size FlexNodes
if ((N = (FlexN) new char [sizeofNode])
== FlexN0) return (void *) 0;
if (D)
memcpy(N->data,D,sizeofNodeData);
else
memset(N->data,0,sizeofNodeData);
}
else if (!D)
return (void *) 0;
else if ((N = FNnew(D)) == FlexN0)
return (void *) 0;
if ((N->prev = current) == FlexN0) {
if ((N->next = front) == FlexN0)
rear = N;
else
N->next->prev = N;
front = N;
}
else { // after current
if ((N->next = current->next) == FlexN0)
rear = N; // last node
else
N->next->prev = N;
current->next = N;
}
current = N;
curNum++;
nodes++;
sorted = 0;
return N->data;
}
void * FlexList::insSortN(FlexN N)
{
unsigned long low, high;
void *ok;
if (!N || nodes >= maxNodes || !compare)
return (void *) 0;
if (!sorted)
(void) sort();
low = 1UL;
high = (unsigned long) nodes;
while (low <= high)
if ((*compare)(mkcur((unsigned)
((low+high) >> 1)),
N->data) <= 0)
low = (unsigned long)
(curNum + 1);
else
high = (unsigned long)
(curNum - 1);
(void) mkcur((unsigned)high);
ok = insN(N);
sorted = 1;
return ok;
}
void * FlexList::insSortD(const void *D)
{
FlexN N;
unsigned long low, high;
void *ok;
if (!D || nodes >= maxNodes || !compare)
return (void *) 0;
if (sizeofNode) { // fixed size FlexNodes
if ((N = (FlexN) new char [sizeofNode])
== FlexN0) return (void *) 0;
memcpy(N->data,D,sizeofNodeData);
}
else if ((N = FNnew(D)) == FlexN0)
return (void *) 0;
if (!sorted)
(void) sort();
low = 1UL;
high = (unsigned long) nodes;
while (low <= high)
if ((*compare)(mkcur((unsigned)
((low+high) >> 1)),
N->data) <= 0)
low = (unsigned long)
(curNum + 1);
else
high = (unsigned long)
(curNum - 1);
(void) mkcur((unsigned)high);
ok = insN(N);
sorted = 1;
return ok;
}
FlexN FlexList::delN()
{
FlexN N;
if ((N = current) == FlexN0)
return FlexN0;
current = N->prev;
curNum--;
if (N->next)
N->next->prev = N->prev;
else
rear = N->prev;
if (N->prev)
N->prev->next = N->next;
else
front = N->next;
nodes--;
N->next = N->prev = FlexN0;
return N;
}
int FlexList::delD(void *D)
{
FlexN N;
if ((N = current) == FlexN0)
return 0;
if (sizeofNodeData) {
if (D)
memcpy(D,N->data,sizeofNodeData);
}
else if (!FNdestruct(N->data,D))
return 0;
current = N->prev;
curNum--;
if (N->next)
N->next->prev = N->prev;
else
rear = N->prev;
if (N->prev)
N->prev->next = N->next;
else
front = N->next;
nodes--;
delete N;
return 1;
}
void * FlexList::nextD(void *D)
{
FlexN oldCurrent;
if ((oldCurrent = current) != FlexN0)
current = current->next;
else
current = front;
if (!current) {
curNum = 0;
return (void *) 0;
}
if (D) if (sizeofNodeData)
memcpy(D,current->data,sizeofNodeData);
else if (!FNread(current->data,D)) {
current = oldCurrent;
return (void *) 0;
}
curNum++;
return current->data;
}
void * FlexList::prevD(void *D)
{
FlexN oldCurrent;
unsigned oldCurNum;
oldCurNum = curNum;
if ((oldCurrent = current) != FlexN0) {
current = current->prev;
curNum--;
}
else {
current = rear;
curNum = nodes;
}
if (!current)
return (void *) 0;
if (D) if (sizeofNodeData)
memcpy(D,current->data,sizeofNodeData);
else if (!FNread(current->data,D)) {
curNum = oldCurNum;
current = oldCurrent;
return (void *) 0;
}
return current->data;
}
void * FlexList::findFirstD(const void *D)
{
unsigned long low, high;
if (!D || !compare)
return (void *) 0;
if (sorted) {
low = 1UL;
high = (unsigned long) nodes;
while (low <= high)
if ((*compare)(mkcur((unsigned)
((low+high) >> 1)),D) < 0)
low = (unsigned long) (curNum + 1);
else
high = (unsigned long) (curNum - 1);
if (mkcur((unsigned)high+1))
if (!(*compare)(current->data,D))
return current->data;
// leave at insertion point
(void) mkcur((unsigned)high);
}
else {
(void) mkcur();
while (nextD())
if (!(*compare)(current->data,D))
return current->data;
}
return (void *) 0;
}
void * FlexList::findNextD(const void *D)
{
if (!D || !compare)
return (void *) 0;
while (nextD())
if (!(*compare)(current->data,D))
return current->data;
else if (sorted)
break;
return (void *) 0;
}
void * FlexList::findLastD(const void *D)
{
unsigned long low, high;
if (!D || !compare)
return (void *) 0;
if (sorted) {
low = 1UL;
high = (unsigned long) nodes;
while (low <= high)
if ((*compare)(mkcur((unsigned)
((low+high) >> 1)),D) <= 0)
low = (unsigned long) (curNum + 1);
else
high = (unsigned long) (curNum - 1);
if (mkcur((unsigned)high))
if (!(*compare)(current->data,D))
return current->data;
}
else {
(void) mkcur();
while (prevD())
if (!(*compare)(current->data,D))
return current->data;
}
return (void *) 0;
}
void * FlexList::findPrevD(const void *D)
{
if (!D || !compare)
return (void *) 0;
while (prevD())
if (!(*compare)(current->data,D))
return current->data;
else if (sorted)
break;
return (void *) 0;
}
int FlexList::sort(int (*compare)
(const void *D1, const void *D2))
{
if (sorted) {
if (this->compare == compare || !compare)
{ mkcur(); return 1; }
}
else if (!this->compare && !compare)
return 0;
if (compare)
this->compare = compare;
if (!nodes)
return (sorted = 1);
FlexList tmp(sizeofNodeData);
tmp.setCompare(this->compare);
while (nodes)
(void) tmp.insSortN(popN());
front = tmp.front;
rear = tmp.rear;
nodes = tmp.nodes;
tmp.front = tmp.current = tmp.rear = FlexN0;
tmp.curNum = tmp.nodes = 0;
return (sorted = 1);
}
int FlexList::storeD(const void *D, unsigned n)
{
unsigned oldn;
if (!D || n > nodes || !n && !current)
return 0;
if (sizeofNodeData) {
if (n) (void) mkcur(n);
memcpy(current->data,D,sizeofNodeData);
}
else {
oldn = curNum;
if (n) (void) mkcur(n);
if (!FNwrite(current->data,D))
{
(void) mkcur(oldn);
return 0;
}
}
sorted = 0;
return 1;
}
int FlexList::recallD(void *D, unsigned n)
{
unsigned oldn;
if (!D || n > nodes || !n && !current)
return 0;
if (sizeofNodeData) {
if (n) (void) mkcur(n);
memcpy(D,current->data,sizeofNodeData);
}
else {
oldn = curNum;
if (n) (void) mkcur(n);
if (!FNread(current->data,D))
{
(void) mkcur(oldn);
return 0;
}
}
return 1;
}
void * FlexList::pack() // Only fixed nodes!
{
long sizeofArray;
char *A, *Ai;
FlexN N;
sizeofArray = ((long)sizeofNodeData)
* ((long)nodes);
if ((sizeofArray <= 0) ||
(sizeofArray > FLmaxSizeofArray))
return (void *) 0;
if ((A = new char [(unsigned) sizeofArray])
== (char *) 0)
return (void *) 0;
for (Ai = A, N = front; N; N = N->next,
Ai += sizeofNodeData)
memcpy(Ai,N->data,sizeofNodeData);
return A;
}
void **FlexList::packPtrs()
{
long sizeofArray;
void **A;
unsigned Ai;
FlexN N;
sizeofArray = sizeof(void *) * ((long)nodes + 1);
if ((sizeofArray <= 0) ||
(sizeofArray > FLmaxSizeofArray))
return (void **) 0;
if ((A = (void **) new char [(unsigned)
sizeofArray]) == (void **) 0)
return (void **) 0;
for (Ai = 0, N = front; N; Ai++, N = N->next)
A[Ai] = N->data;
A[Ai] = (void *) 0;
return A;
}