thant@horus.esd.sgi.com (Thant Tessman) (03/01/91)
Here's an array class folks may or may not find usefull. It is completely unsupported, comes with no guarantees, and you use it at your own risk. But I like it. It can hold objects of any size, it holds them in contiguous memory, and it is type safe. I wrote it in c++ 2.0 so those using 1.2 or gnu may have to bang on it a little bit. Enjoy... #!/bin/sh -v # this is a shell archive (once) named array.mail # created by thant@horus at Thu Feb 28 15:48:31 PST 1991 # # The rest of this file is a shell script which will extract: # Makefile # testArray.h # testArray.c++ # Array.h # Array.c++ # # to use, type sh array.mail # echo x - Makefile cat > Makefile << 'EndOfRecord' #!smake # include ${ROOT}/usr/include/make/commondefs C++FILES = \ testArray.c++ \ Array.c++ \ ${NULL} OPTIMIZER = -g LDFLAGS = -lgl_s -lm TARGETS = testArray all default: ${TARGETS} include ${ROOT}/usr/include/make/commonrules ${TARGETS}: ${OBJECTS} ${C++F} -o $@ ${OBJECTS} ${LDFLAGS} EndOfRecord len=`wc -c < Makefile ` if [ $len != 298 ] ; then echo error: Makefile was $len bytes long, should have been 298 fi echo x - testArray.h cat > testArray.h << 'EndOfRecord' #pragma once #include "Array.h" declareArray(MyArray,char*); /* The reason that declareArray() and implementArray() are separate is that the declareArray() generates a declaration, and like declarations can appear in many places, which makes it good for header (.h) files. The implementArray() can only appear once per list type (usually in a .c++ file). */ EndOfRecord len=`wc -c < testArray.h ` if [ $len != 385 ] ; then echo error: testArray.h was $len bytes long, should have been 385 fi echo x - testArray.c++ cat > testArray.c++ << 'EndOfRecord' #include <stdio.h> #include <stdlib.h> #include "testArray.h" implementArray(MyArray,char*); MyArray myArray; main() { int i; char* three = "three"; myArray.add("one"); myArray.add("two"); myArray.add(three); myArray.add("four"); myArray.insert("zero"); printf("\nall:\n"); for (i=0; i<myArray.size(); i++) printf("%s ", myArray[i]); printf("\n"); printf("\nfound three at %d\n", myArray.find(three)); myArray.remove(1); myArray.remove(three); printf("\neven:\n"); for (i=0; i<myArray.size(); i++) printf("%s ", myArray[i]); printf("\n"); MyArray newArray; newArray = myArray; printf("\ncopy of list:\n"); for (i=0; i<myArray.size(); i++) printf("%s ", newArray[i]); printf("\n\n"); } EndOfRecord len=`wc -c < testArray.c++ ` if [ $len != 784 ] ; then echo error: testArray.c++ was $len bytes long, should have been 784 fi echo x - Array.h cat > Array.h << 'EndOfRecord' #pragma once // This is what the declaration of a Array looks like to the user: /* declareArray(ARRAY,ITEM); implementArray(ARRAY,ITEM); struct ARRAY<ITEM> : Array { ARRAY(); ARRAY(ARRAY&); virtual ~ARRAY(); void add(ITEM const &item); void insert(ITEM const &item, int index=0); void remove(ITEM const &); void remove(int index); void removeAll(); int find(ITEM const &); ITEM& operator[](int index); ARRAY& operator=(ARRAY&); int size() {return listsize;}; operator ITEM*(); } */ /* NOTE: There is a bug in the C++ compiler that won't allow 'this' to be passed by reference. So if you build a list of class pointers, and you want to pass 'this' to a list member function, it must be preceeded by &* For example: myArray.insert(&*this); */ struct Array { int size() {return listSize;}; protected: Array(Array&); Array(); Array(int elementSize); virtual ~Array(); void insert(void const *item, int index=0); void remove(void const *); void remove(int index); void removeAll(); Array& operator=(Array&); struct Address { // will be local to scope eventually Address() { ptr = 0; } Address(void* p) { ptr = (char*)p; } Address operator+(int offset) { return ptr + offset; } operator void*() { return ptr;} protected: char* ptr; } data; int listSize; int elementSize; private: void makeRoom(int index); int room; // >=listSize*elementSize }; #define declareArray(ARRAY,ITEM) \ \ struct ARRAY : Array { \ ARRAY(); \ ARRAY(ARRAY&); \ ~ARRAY(); \ int find(ITEM const &); \ void add(ITEM const &item) { \ ARRAY::insert(item, listSize); \ } \ \ void insert(ITEM const &item, int index=0) { \ Array::insert((void*)(&item), index); \ } \ \ void remove(ITEM const &item) { \ Array::remove((void*)(&item)); \ } \ \ void remove(int index) {Array::remove(index);} \ \ void removeAll() {Array::removeAll();} \ \ ITEM& operator[](int index) { \ return ((ITEM*)((void*)data))[index]; \ } \ \ operator ITEM*() { \ return (ITEM*)((void*)data); \ } \ \ ARRAY& operator=(ARRAY&); \ \ } \ #define implementArray(ARRAY,ITEM) \ \ ARRAY::ARRAY() : Array (sizeof(ITEM)) {} \ ARRAY& ARRAY::operator=(ARRAY& old) { \ return (ARRAY&) Array::operator=(old); \ } \ ARRAY::ARRAY(ARRAY& old) : Array(old) {} \ ARRAY::~ARRAY() {} \ \ int ARRAY::find(ITEM const &item) { \ for (int i=0; i<listSize; i++) { \ if (((ITEM*)((void*)data))[i]==item) return i; \ } \ return(-1); \ } \ \ \ EndOfRecord len=`wc -c < Array.h ` if [ $len != 2911 ] ; then echo error: Array.h was $len bytes long, should have been 2911 fi echo x - Array.c++ cat > Array.c++ << 'EndOfRecord' #include "Array.h" #include <stdio.h> #include <stdlib.h> #include <libc.h> Array::Array(int s) { listSize = 0; elementSize = s; data = 0; room = 0; } Array::Array(Array& old) { listSize = old.listSize; elementSize = old.elementSize; room = old.room; if (room) { data = malloc(room); bcopy(old.data, data, listSize*elementSize); } } Array::~Array() { listSize = 0; elementSize = 0; if (data) free(data); data = NULL; room = 0; } Array& Array::operator=(Array& old) { listSize = old.listSize; room = old.room; if (data) {free(data); data=NULL;} if (room) { data = malloc(room); bcopy(old.data, data, listSize*elementSize); } return *this; } void Array::insert(void const * item, int index) { if ((index>listSize) || (index<0)) { fprintf(stderr, "\nArray::insert(%d) out of bounds. (size: %d)\n", index, listSize); abort(); } if (!listSize) { room = elementSize; data = malloc(room); } else if (((listSize+1)*elementSize) > room) { room = listSize*2*elementSize; data = realloc(data, room); } if (!data) { fprintf(stderr, "\nArray::insert(%d) out of memory.\n", index); abort(); } if (index<listSize) makeRoom(index); listSize++; bcopy(item, data+elementSize*index, elementSize); } void Array::remove(int index) { if ( (index<0) || (index>=listSize) ) { fprintf(stderr, "\nArray::remove(%d) out of bounds.\n", index); abort(); } bcopy(data+elementSize*(index+1), data+elementSize*index, (listSize-index-1)*elementSize); listSize--; if (listSize*2*elementSize == room) { room = listSize*elementSize; if (!room) {free(data); data=NULL;} else data = realloc(data, room); } } void Array::remove(void const * item) { for (int i=0; i<elementSize; i++) { if (!bcmp(item, data+i*elementSize, elementSize)) { remove(i); return; } } fprintf(stderr, "\nArray::remove(item) item doesn't exist.\n"); abort(); } void Array::removeAll() { listSize=0; if (data) {free(data); data=NULL;} room = 0; } void Array::makeRoom(int index) { bcopy(data+elementSize*index, data+elementSize*(index+1), (listSize-index)*elementSize); } EndOfRecord len=`wc -c < Array.c++ ` if [ $len != 2272 ] ; then echo error: Array.c++ was $len bytes long, should have been 2272 fi