/////////////////////////////////////////////////////////////////////////////// // g++ -fhandle-exceptions Array.C -o Array /////////////////////////////////////////////////////////////////////////////// //================================< Array.h >================================= // WARNING: Requires exceptions (use g++ -fhandle-exceptions) #ifndef Array_First #define Array_First template class Array { enum { log2BucketSize = 4, // LOG (BASE 2) OF HOW MANY ELEMENTS PER BUCKET bucketSize = 1<; public: explicit Size(int s) : myElemCount(s) {} private: int myElemCount; }; // THIS CLASS IMPLEMENTS AN EXCEPTION ON BOUNDS ERROR struct BoundsError { BoundsError(int i, int m) : index(i) , max(m) {} int index; int max; }; private: int myBucketCount; // NUMBER OF BUCKETS ALLOCATED int myNextFree; // INDEX OF NEXT FREE ELEMENT ElementType** myElement; // POINTER TO VECTOR OF BUCKETS // 1. CONVERT AN INDEX INTO A BUCKET NUMBER AND INDEX WITHIN THAT BUCKET // RETURN A REFERENCE TO THE CORRESPONDING ELEMENT ElementType& access(int index) const { return myElement[index>>divBucketSize][index&modBucketSize]; } // 2. REALLOCATE THE REQUIRED NUMBER OF BUCKETS // IF THE REQUIRED NUMBER IS 0, ALLOCATE ENOUGH SPACE // FOR AT LEAST ONE EXTRA ELEMENT void reallocate(int reqBucketCount = 0) { if (reqBucketCount>0 && reqBucketCount>myBucketCount) { // ALLOCATE A VECTOR OF THE REQUIRED NUMBER OF BUCKETS ElementType** newelement = new ElementType* [reqBucketCount]; int i; // MOVE EACH EXISTING BUCKET TO NEW BUCKET VECTOR for (i=0;i & array) : myBucketCount(0) , myNextFree(array.myNextFree) , myElement(0) { // ALLOCATE AS MANY BUCKETS AS REQUIRED TO STORE THE // NUMBER OF ELEMENTS IN THE EXISTING ARRAY array reallocate(array.myNextFree+modBucketSize >> divBucketSize); // COPY EACH ELEMENT ACROSS for (int i=0; i::Size initsize) : myBucketCount(0) , myNextFree(0) , myElement(0) { // CONVERT ELEMENT COUNT TO BUCKET COUNT reallocate(initsize.myElemCount+modBucketSize >> divBucketSize); } Array(Size initsize, const ElementType& initval) : myBucketCount(0) , myNextFree(initsize.myElemCount) , myElement(0) { // CONVERT ELEMENT COUNT TO BUCKET COUNT reallocate(initsize.myElemCount+modBucketSize >> divBucketSize); // INITIALIZE EACH REQUESTED BUCKET for (int i=0;i> divBucketSize); // COPY EACH ELEMENT for (int i=0; i=0 && i=0 && i> divBucketSize); access(myNextFree) = elem; myNextFree++; return *this; } Array& Append(const Array& array) { // ENSURE ENOUGH SPACE FOR THE EXTRA ELEMENTS reallocate(myNextFree+array.myNextFree+modBucketSize>>divBucketSize); // COPY EACH EXTRA ELEMENT TO THE NEXT EMPTY SLOT for (int i=0; i=0) { myNextFree -= n; } return *this; } // 11. CHECK FOR AN ELEMENT VALUE IN THE ARRAY // RETURNS: 0 ON FAILURE OR // (index+1) WHERE index IS THE INDEX OF THE FIRST // ELEMENT WITH A MATCHING VALUE int Contains(const ElementType& elem) const { for (int i=0;i================================ #include int lastshow = 0; #define TESTING(text) \ cout << "\nTesting " << #text << "..." << endl; #define REQUEST(var, okaycond) \ cout << "Enter " << #var << " (" << #okaycond << "): "; \ cin >> var; \ if (!(var okaycond)) break; #define SHOW(expr) \ if (lastshow<__LINE__-1) cout << endl; \ cout << "\t" << #expr << ": " << (expr) << endl; \ lastshow = __LINE__; //================================< test.C >================================= #include template ostream& operator<<(ostream& os, const Array& array) { os << "["; for (int i=0; i0) { os << ","; } os << array[i]; } os << "]"; return os; } int main(void) { TESTING(Array ctors); Array ai1; Array ai2 (2); Array ai3 (Array::Size(10)); Array ai4 (Array::Size(10),7); Array ai5 (ai4); SHOW(ai1); SHOW(ai2); SHOW(ai3); SHOW(ai4); SHOW(ai5); TESTING(Array::Count); SHOW(ai1.Count()); SHOW(ai2.Count()); SHOW(ai3.Count()); SHOW(ai4.Count()); SHOW(ai5.Count()); TESTING(Array::Append); SHOW(ai3.Append(1)); SHOW(ai3.Append(2)); SHOW(ai3.Append(3)); SHOW(ai3.Append(4)); SHOW(ai3.Append(5)); SHOW(ai3.Append(6)); SHOW(ai3.Append(7)); SHOW(ai3.Append(8)); SHOW(ai3.Append(9)); SHOW(ai3.Append(10)); SHOW(ai3.Append(ai5)); SHOW(ai5.Append(ai5)); TESTING(Array::operator=) SHOW((ai5 = ai3)); SHOW((ai5 = 99)); TESTING(Array::Contains) while (1) { int index; REQUEST( index, >0 ); try { int val = ai3[index]; SHOW(ai3[index]); } catch (Array::BoundsError be) { cout << ">>> Invalid index: " << be.index << endl; } } TESTING(Array::RemoveLast) SHOW(ai3.RemoveLast(1)); SHOW(ai3.RemoveLast(4)); SHOW(ai3.RemoveLast(-4)); TESTING(Array::RemoveLast) SHOW(ai3.Reset()); TESTING(Other ElementTypes) Array as1 ("as1"); Array as2 (Array::Size(5),"as2"); Array as3 (as2); SHOW(as1); SHOW(as2); SHOW(as3); SHOW((as3[2] = as1[0])); Array< Array > aas (Array< Array >::Size(3),as3); SHOW(aas); SHOW(aas[1]); SHOW(aas[1][1]); TESTING(Equality test); SHOW((as1==as3)); SHOW((as3==as3)); SHOW((aas[1]==as3)); }