home *** CD-ROM | disk | FTP | other *** search
- /*
-
- 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;
- }
-