t_array.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : test_array                                                        *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *******************************************************************************
00007 * Copyright (c) 1991-$now By Author.  This program is free software; you can  *
00008 * redistribute it and/or modify it under the terms of the GNU General Public  *
00009 * License as published by the Free Software Foundation; either version 2 of   *
00010 * the License or (at your option) any later version.  This is online at:      *
00011 *     http://www.fsf.org/copyleft/gpl.html                                    *
00012 * Please send any updates to: fred@gruntose.com                               *
00013 \*****************************************************************************/
00014 
00015 //#define DEBUG_ARRAY
00016   // when this flag is turned on, extra checking will be done in the allocator.
00017 
00018 //hmmm: catch all outcomes returned from functions under test and complain
00019 //      if they indicate unexpected failures.
00020 
00021 #include <basis/byte_array.h>
00022 #include <basis/chaos.h>
00023 #include <basis/function.h>
00024 #include <basis/guards.h>
00025 #include <basis/istring.h>
00026 #include <data_struct/matrix.cpp>
00027 #include <mathematics/float_plus.h>
00028 #include <mechanisms/time_stamp.h>
00029 #include <opsystem/application_shell.h>
00030 #include <loggers/console_logger.h>
00031 #include <data_struct/static_memory_gremlin.h>
00032 
00033 const int MAX_TEST_DURATION = 0.5 * MINUTE_ms;
00034   // each of the tests calling on the templated tester will take this long.
00035 
00036 const int MAX_SIMULTANEOUS_OBJECTS = 42;  // the maximum arrays tested.
00037 
00038 const int MIN_OBJECT = -30; // the smallest array we'll create.
00039 const int MAX_OBJECT = 98; // the largest array we'll create.
00040 
00041 const int MIN_BLOCK = 100;  // the smallest exemplar we'll use.
00042 const int MAX_BLOCK = MAX_OBJECT * 2;  // the largest exempler.
00043 
00044 //#define DEBUG_TEST_ARRAY
00045   // uncomment for noisy version.
00046 
00047 #define LOG(s) EMERGENCY_LOG(program_wide_logger(), s)
00048 
00050 
00051 class test_array : public application_shell
00052 {
00053 public:
00054   test_array() : application_shell(class_name()) {}
00055   IMPLEMENT_CLASS_NAME("test_array");
00056   virtual int execute();
00057   void dump_array(array<void *> &ar, const char *name);
00058   void test_arrays_of_void_pointer();
00059   void test_iteration_speed();
00060 };
00061 
00063 
00064 void test_array::dump_array(array<void *> &ar, const char *name)
00065 {
00066 #ifdef DEBUG_TEST_ARRAY
00067   LOG(isprintf("array named \"%s\" has:", name)); 
00068   for (int i = 0; i < ar.length(); i++) {
00069     LOG(isprintf("\t%4d: %d", i, (int)ar[i]));
00070   }
00071 #else
00072   if (ar.length() && name) {}
00073 #endif
00074 }
00075 
00076 void test_array::test_arrays_of_void_pointer()
00077 {
00078   FUNCDEF("void pointer test");
00079   if (sizeof(void *) != 4)
00080     deadly_error(class_name(), func, "the void pointer has an unexpected size!");
00081   const int MAX_VOID_ARRAY = 20;
00082   array<void *> argh(MAX_VOID_ARRAY, NIL, byte_array::SIMPLE_COPY
00083       | byte_array::EXPONE | byte_array::FLUSH_INVISIBLE);
00084   array<void *> argh2(argh);
00085   if (argh.length() != MAX_VOID_ARRAY)
00086     deadly_error(class_name(), func, "the first array length is incorrect!");
00087   if (argh2.length() != MAX_VOID_ARRAY)
00088     deadly_error(class_name(), func, "the copied array length is incorrect!");
00089   for (int o = 0; o < MAX_VOID_ARRAY; o++)
00090     if (argh[o] != argh2[o])
00091       deadly_error(class_name(), func, "the arrays have different contents!");
00092     
00093   // fill it with values.
00094   int starter;
00095   for (int i = 0; i < MAX_VOID_ARRAY; i++)
00096     argh[i] = (void *)(&starter + i);
00097   dump_array(argh, "first version");
00098 
00099   // check the values.
00100   for (int j = 0; j < MAX_VOID_ARRAY; j++)
00101     if (argh[j] != (void *)(&starter + j))
00102       deadly_error(class_name(), func, "setting values are incorrect!");
00103 
00104   // add a constant to the values.
00105   for (int k = 0; k < MAX_VOID_ARRAY; k++)
00106     argh[k] = (void *)((int *)argh[k] + 23);
00107   dump_array(argh, "second version");
00108 
00109   // check assignment.
00110   argh2 = argh;
00111   for (int n = 0; n < MAX_VOID_ARRAY; n++)
00112     if (argh2[n] != (void *)(&starter + n + 23))
00113       deadly_error(class_name(), func, "assign values are incorrect!");
00114 
00115   // now test that values are kept in place after rearrangement.
00116   argh.zap(3, 4);
00117   dump_array(argh, "third version");
00118   for (int l = 0; l < 3; l++)
00119     if (argh[l] != (void *)(&starter + l + 23))
00120       deadly_error(class_name(), func, "zap low values are incorrect!");
00121   for (int m = 3; m < MAX_VOID_ARRAY - 2; m++)
00122     if (argh[m] != (void *)(&starter + m + 2 + 23))
00123       deadly_error(class_name(), func, "zap high values are incorrect!");
00124 
00125 //hmmm: add more tests if void pointer arrays seem in question.
00126 }
00127 
00129 
00130 static istring blank_string;
00131 
00132 // jethro is a simple object for containment below.
00133 class jethro
00134 {
00135 public:
00136   jethro(const istring &i = blank_string) : _truck(i) {}
00137 
00138   istring _truck;
00139 
00140   bool operator ==(const jethro &tc) const { return tc._truck == _truck; }
00141   bool operator !=(const jethro &tc) const { return !(*this == tc); }
00142 };
00143 
00145 
00146 // the test_content object is an object with proper copy constructor
00147 // and assignment operator that also has deep contents.
00148 class test_content
00149 {
00150 public:
00151   byte _q;
00152   istring _ted;
00153   istring _jed;
00154   int_array _ned;
00155   matrix<jethro> _med;
00156   int_matrix _red;
00157 
00158   test_content(byte q = 3)
00159   : _q(q), _ted("bl"), _jed("orp"),
00160     _ned(12, NIL),
00161     _med(3, 2),
00162     _red(2, 4)
00163   {
00164     for (int i = 0; i < _ned.length(); i++)
00165       _ned[i] = -i;
00166     for (int r = 0; r < _med.rows(); r++)
00167       for (int c = 0; c < _med.columns(); c++)
00168         _med[r][c] = jethro(istring((r*c) % 256, 1));
00169     for (int j = 0; j < _red.rows(); j++)
00170       for (int k = 0; k < _red.columns(); k++)
00171         _red[j][k] = j * k;
00172   }
00173 
00174   bool operator ==(const test_content &tc) const {
00175     if (tc._q != _q) return false;
00176     if (tc._ted != _ted) return false;
00177     if (tc._jed != _jed) return false;
00178     if (tc._ned.length() != _ned.length()) return false;
00179     for (int i = 0; i < _ned.length(); i++)
00180       if (tc._ned[i] != _ned[i]) return false;
00181     
00182     if (tc._med.rows() != _med.rows()) return false;
00183     if (tc._med.columns() != _med.columns()) return false;
00184     for (int c = 0; c < _med.columns(); c++)
00185       for (int r = 0; r < _med.rows(); r++)
00186         if (tc._med.get(r, c) != _med.get(r, c)) return false;
00187 
00188     if (tc._red.rows() != _red.rows()) return false;
00189     if (tc._red.columns() != _red.columns()) return false;
00190     for (int j = 0; j < _red.rows(); j++)
00191       for (int k = 0; k < _red.columns(); k++)
00192         if (tc._red.get(j, k) != _red.get(j, k)) return false;
00193 
00194     return true;
00195   }
00196   bool operator !=(const test_content &tc) const { return !operator ==(tc); }
00197 
00198   operator byte() const { return _q; }
00199 };
00200 
00202 
00203 template <class contents>
00204 bool compare_arrays(const array<contents> &a, const array<contents> &b)
00205 {
00206   if (a.length() != b.length()) return false;
00207   for (int i = 0; i < a.length(); i++)
00208     if (a[i] != b[i]) return false;
00209   return true;
00210 }
00211 
00213 
00214 // this is a templated test for arrays, with some requirements.  the contents
00215 // object must support a constructor that takes a simple byte, whether
00216 // that's meaningful for the object or not.  if your type to test doesn't
00217 // have that, derive a simple object from it, give it that constructor, and
00218 // then it can be used below.  the object must also support comparison with
00219 // == and != for this test to be used.  it must also provide a conversion
00220 // to integer that returns the value passed to the constructor.
00221 
00222 template <class contents>
00223 void array_tester(test_array &ta, const contents &formal(bogus), u_short flags)
00224 {
00225   // the space that all training for arrays comes from.
00226   contents *junk_space = new contents[MAX_OBJECT + MAX_BLOCK];
00227   for (int i = 0; i < MAX_OBJECT - 1; i++)
00228     junk_space[i] = contents(ta.randomizer().inclusive('a', 'z'));
00229   junk_space[MAX_OBJECT + MAX_BLOCK - 1] = '\0';
00230 
00231   array<contents> *testers[MAX_SIMULTANEOUS_OBJECTS];
00232   for (int c = 0; c < MAX_SIMULTANEOUS_OBJECTS; c++) {
00233     // set up the initial array guys.
00234     testers[c] = new array<contents>(ta.randomizer().inclusive(MIN_OBJECT, MAX_OBJECT),
00235         NIL, flags);
00236     // copy the randomized junk space into the new object.
00237     for (int i = 0; i < testers[c]->length(); i++)
00238       testers[c]->put(i, junk_space[i]);
00239   }
00240 
00241   // these are the actions we try out with the array during the test.
00242   // the first and last elements must be identical to the first and last
00243   // tests to perform.
00244   enum actions { first, do_train = first, do_size, do_assign,
00245       do_access, do_zap, do_resizer, do_shrink, do_reset, do_indices,
00246       do_concatenating, do_concatenating2, do_subarray, do_insert,
00247       do_overwrite, do_stuff, do_memory_paring, do_snarf, do_flush,
00248       do_observe, last = do_observe };
00249 
00250   time_stamp exit_time(MAX_TEST_DURATION);
00251   while (time_stamp() < exit_time) {
00252     int index = ta.randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00253     int choice = ta.randomizer().inclusive(first, last);
00254     switch (choice) {
00255       case do_train: {
00256 #ifdef DEBUG_TEST_ARRAY
00257         LOG(isprintf("do_train"));
00258 #endif
00259         int new_size = ta.randomizer().inclusive(MIN_OBJECT, MAX_OBJECT);
00260         testers[index]->retrain(new_size, (contents *)junk_space);
00261         for (int i = 0; i < new_size; i++) {
00262           if (junk_space[i] != (*testers[index])[i])
00263             deadly_error(ta.class_name(), __WHERE__, "bad contents after retrain");
00264         }
00265         break;
00266       }
00267       case do_size: {
00268 #ifdef DEBUG_TEST_ARRAY
00269         LOG(isprintf("do_size"));
00270 #endif
00271         array<contents> old_version = *testers[index];
00272         bool at_front = bool(ta.randomizer().inclusive(0, 1));
00273         int new_size = ta.randomizer().inclusive(MIN_OBJECT, MAX_OBJECT);
00274         bool smaller = new_size < old_version.length();
00275         int difference = absolute_value(new_size - old_version.length());
00276         testers[index]->resize(new_size,
00277             at_front? common::NEW_AT_BEGINNING
00278                 : common::NEW_AT_END);
00279         if (!smaller && difference) {
00280           // neuter the contents in the new section so we can compare.  this
00281           // space is filled with whatever the object's constructor chooses.
00282           if (at_front) {
00283             for (int i = 0; i < difference; i++)
00284               testers[index]->put(i, 'Q');
00285           } else {
00286             for (int i = old_version.length();
00287                 i < old_version.length() + difference; i++)
00288               testers[index]->put(i, 'Q');
00289           }
00290         }
00291         // now compute an equivalent form of what the state should be.
00292         array<contents> equivalent(0, NIL, flags);
00293         if (at_front) {
00294           if (smaller) {
00295             equivalent = old_version.subarray(difference,
00296                 old_version.length() - 1);
00297           } else {
00298             array<contents> blank(difference, NIL, flags);
00299             for (int i = 0; i < blank.length(); i++)
00300               blank[i] = 'Q';
00301             equivalent = blank + old_version;
00302           }
00303         } else {
00304           if (smaller) {
00305             equivalent = old_version.subarray(0, old_version.length()
00306                 - difference - 1);
00307           } else {
00308             array<contents> blank(difference, NIL, flags);
00309             for (int i = 0; i < blank.length(); i++)
00310               blank[i] = 'Q';
00311             equivalent = old_version + blank;
00312           }
00313         }
00314         if (equivalent.length() != testers[index]->length())
00315           deadly_error(ta.class_name(), __WHERE__, "the resized form had "
00316               "erroneous length");
00317         if (!compare_arrays(*testers[index], equivalent))
00318           deadly_error(ta.class_name(), __WHERE__, "the resized form had "
00319               "erroneous contents");
00320         break;
00321       }
00322       case do_assign: {
00323 #ifdef DEBUG_TEST_ARRAY
00324         LOG(isprintf("do_assign"));
00325 #endif
00326         array<contents> arrh = *testers[index];  // copy old value.
00327         int to_assign = ta.randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00328         *testers[index] = *testers[to_assign];
00329         if (!compare_arrays(*testers[index], *testers[to_assign]))
00330           deadly_error(ta.class_name(), __WHERE__, "assign failed to copy array");
00331         *testers[to_assign] = arrh;  // recopy contents to new place.
00332         if (!compare_arrays(*testers[to_assign], arrh))
00333           deadly_error(ta.class_name(), __WHERE__, "second assign failed");
00334         break;
00335       }
00336       case do_access: {
00337 #ifdef DEBUG_TEST_ARRAY
00338         LOG(isprintf("do_access"));
00339 #endif
00340         int start = ta.randomizer().inclusive(0, testers[index]->length());
00341         int end = ta.randomizer().inclusive(0, testers[index]->length());
00342         flip_increasing(start, end);
00343         array<contents> accumulator(0, NIL, flags);
00344         for (int i = start; i < end; i++) {
00345           contents c = contents(ta.randomizer().inclusive(1, 255));
00346           testers[index]->access()[i] = c;
00347           accumulator += c;
00348         }
00349         for (int j = start; j < end; j++)
00350           if (accumulator[j - start] != (*testers[index])[j])
00351             deadly_error(ta.class_name(), __WHERE__, "accessing failed");
00352         break;
00353       }
00354       case do_indices: {
00355 #ifndef CATCH_ERRORS  // only works if not catching errors.
00356   #ifdef DEBUG_TEST_ARRAY
00357         LOG(isprintf("do_indices"));
00358   #endif
00359         // does some tests on bad indices.
00360         contents c1 = testers[index]->operator[](-50);
00361         contents c2 = testers[index]->operator[](-MAX_OBJECT);
00362         bool test = (c1 == c2);
00363         if (!test)
00364           deadly_error(ta.class_name(), __WHERE__, "invalid values were not same");
00365         int tests = ta.randomizer().inclusive(100, 500);
00366         for (int i = 0; i < tests; i++) {
00367           int indy = ta.randomizer().inclusive(-1000, MAX_OBJECT * 3);
00368           // testing if we can access without explosions.
00369           contents c3 = testers[index]->operator[](indy);
00370           contents c4 = c3;
00371           if (c3 != c4) 
00372             deadly_error(ta.class_name(), __WHERE__, "values were not same");
00373         }
00374 #endif
00375         break;
00376       }
00377       case do_observe: {
00378 #ifdef DEBUG_TEST_ARRAY
00379         LOG(isprintf("do_observe"));
00380 #endif
00381         // tests contents returned by observe.
00382         int start = ta.randomizer().inclusive(0, testers[index]->length());
00383         int end = ta.randomizer().inclusive(0, testers[index]->length());
00384         flip_increasing(start, end);
00385         double total_1 = 0;
00386         for (int i = start; i < end; i++)
00387           total_1 += testers[index]->observe()[i];
00388         double total_2 = 0;
00389         for (int j = end - 1; j >= start; j--)
00390           total_2 += testers[index]->observe()[j];
00391         if (total_1 != total_2)
00392           deadly_error(ta.class_name(), __WHERE__, "totals didn't match");
00393         break;
00394       }
00395       case do_resizer: {
00396 #ifdef DEBUG_TEST_ARRAY
00397         LOG(isprintf("do_resizer"));
00398 #endif
00399         // tests whether the array will reuse space when it should be able to.
00400         array<contents> &arrh = *testers[index];
00401         // fill with known data.
00402         int i;
00403         for (i = 0; i < arrh.length(); i++)
00404           arrh[i] = contents((i + 23) % 256);
00405         // record the old starting point.
00406         const contents *start = arrh.internal_block_start();
00407         int zap_amount = ta.randomizer().inclusive(1, arrh.length() - 1);
00408         // now take out a chunk from the array at the beginning.
00409         arrh.zap(0, zap_amount - 1);
00410         // test the contents.
00411         for (i = 0; i < arrh.length(); i++)
00412           if (arrh[i] != contents((i + 23 + zap_amount) % 256))
00413             deadly_error(ta.class_name(), __WHERE__, "the resized form "
00414                 "had different contents");
00415         // now add back in the space we ate.
00416         arrh.resize(arrh.length() + zap_amount, common::NEW_AT_END);
00417         // check the pointer; it should not have changed.
00418         if (start != arrh.internal_block_start())
00419           deadly_error(ta.class_name(), __WHERE__, "the resized form had "
00420               "a different start address");
00421         // test the contents again.  they should start at zero and have the
00422         // same zap_amount offset.  the stuff past the original point shouldn't
00423         // be tested since we haven't set it.
00424         for (i = 0; i < arrh.length() - zap_amount; i++)
00425           if (arrh[i] != contents((i + 23 + zap_amount) % 256))
00426             deadly_error(ta.class_name(), __WHERE__, "the resized form "
00427                 "had different contents");
00428         // now a test of all values through the zap_amount.
00429         arrh.zap(0, zap_amount - 1);
00430         for (i = 0; i < zap_amount; i++) {
00431           arrh.resize(arrh.length() + 1, common::NEW_AT_END);
00432           if (start != arrh.internal_block_start())
00433             deadly_error(ta.class_name(), __WHERE__, "the slowly resized "
00434                 "form had a different start address");
00435         }
00436         // test the contents once more.  they should start at zero and have
00437         // double the zap_amount offset.  the stuff past the original point
00438         // shouldn't be tested since we haven't set it.
00439         for (i = 0; i < arrh.length() - 2 * zap_amount; i++)
00440           if (arrh[i] != contents((i + 23 + 2 * zap_amount) % 256))
00441             deadly_error(ta.class_name(), __WHERE__, "the slowly resized "
00442                 "form had different contents");
00443 
00444         // the tests below should be nearly identical to the ones above, but
00445         // they use the NEW_AT_BEGINNING style of copying.
00446 
00447         // fill with known data.
00448         for (i = 0; i < arrh.length(); i++)
00449           arrh[i] = contents((i + 23) % 256);
00450         // record the old starting point.
00451         start = arrh.internal_block_start();
00452         zap_amount = ta.randomizer().inclusive(1, arrh.length() - 1);
00453         // now take out a chunk from the array at the beginning.
00454         arrh.zap(0, zap_amount - 1);
00455         // test the contents.
00456         for (i = 0; i < arrh.length(); i++)
00457           if (arrh[i] != contents((i + 23 + zap_amount) % 256))
00458             deadly_error(ta.class_name(), __WHERE__, "the resized form "
00459                 "had different contents");
00460         // now add back in the space we ate.
00461         arrh.resize(arrh.length() + zap_amount,
00462             common::NEW_AT_BEGINNING);
00463         // check the pointer; it should not have changed.
00464         if (start != arrh.internal_block_start())
00465           deadly_error(ta.class_name(), __WHERE__, "the resized form had "
00466               "a different start address");
00467         // test the contents again.  they should start at zap_amount but have
00468         // the same zap_amount offset.  the stuff before the original point
00469         // shouldn't be tested since we haven't set it.
00470         for (i = zap_amount; i < arrh.length(); i++)
00471           if (arrh[i] != contents((i + 23) % 256))
00472             deadly_error(ta.class_name(), __WHERE__, "the resized form "
00473                 "had different contents");
00474         // now a test of all values through the zap_amount.
00475         arrh.zap(0, zap_amount - 1);
00476         for (i = 0; i < zap_amount; i++) {
00477           arrh.resize(arrh.length() + 1, common::NEW_AT_BEGINNING);
00478           if (start != arrh.internal_block_start())
00479             deadly_error(ta.class_name(), __WHERE__, "the slowly resized "
00480                 "form had a different start address");
00481         }
00482         // test the contents once more.  the zap_amount offset should stay the
00483         // same since we clobbered the place we added originally, then added
00484         // more space in.  so we skip the first part still.
00485         for (i = zap_amount; i < arrh.length(); i++)
00486           if (arrh[i] != contents((i + 23) % 256))
00487             deadly_error(ta.class_name(), __WHERE__, "the slowly resized "
00488                 "form had different contents");
00489         break;
00490       }
00491       case do_zap: {
00492 #ifdef DEBUG_TEST_ARRAY
00493         LOG(isprintf("do_zap"));
00494 #endif
00495         int start;
00496         int end;
00497         bool erroneous = false;
00498         int chose = ta.randomizer().inclusive(1, 100);
00499         if (chose <= 90) {
00500           // there's a ninety percent chance we pick a range that's valid.
00501           start = ta.randomizer().inclusive(0, testers[index]->length() - 1);
00502           end = ta.randomizer().inclusive(0, testers[index]->length() - 1);
00503         } else if (chose <= 95) {
00504           // and a 5 percent chance we pick to choose the zero index as our
00505           // start; this gets at the code for fast zapping.
00506           start = 0;
00507           end = ta.randomizer().inclusive(0, testers[index]->length() - 1);
00508         } else {
00509           // and a 5 percent chance we'll allow picking a bad index.  the
00510           // actual chance of picking a bad one is less.
00511           erroneous = true;
00512           start = ta.randomizer().inclusive(-2, testers[index]->length() + 3);
00513           end = ta.randomizer().inclusive(-2, testers[index]->length() + 3);
00514         }
00515         flip_increasing(start, end);
00516         array<contents> old_version = *testers[index];
00517         testers[index]->zap(start, end);
00518         if (!erroneous) {
00519           array<contents> old_head = old_version.subarray(0, start - 1);
00520           array<contents> old_tail = old_version.subarray(end + 1,
00521               old_version.length() - 1);
00522           array<contents> equivalent = old_head + old_tail;
00523           if (equivalent.length() != testers[index]->length())
00524             deadly_error(ta.class_name(), __WHERE__, "the zapped form had "
00525                 "erroneous length");
00526           if (!compare_arrays(*testers[index], equivalent))
00527             deadly_error(ta.class_name(), __WHERE__, "the zapped form had "
00528                 "erroneous contents");
00529         }
00530         break;
00531       }
00532       case do_reset: {
00533 #ifdef DEBUG_TEST_ARRAY
00534         LOG(isprintf("do_reset"));
00535 #endif
00536         int junk_start = ta.randomizer().inclusive(MIN_BLOCK, MAX_BLOCK);
00537         int junk_end = ta.randomizer().inclusive(MIN_BLOCK, MAX_BLOCK);
00538         flip_increasing(junk_start, junk_end);
00539         int len = junk_end - junk_start + 1;
00540         testers[index]->reset(len, (contents *)&junk_space[junk_start]);
00541         if (testers[index]->length() != len)
00542           deadly_error(ta.class_name(), __WHERE__, "reset gave a bad length");
00543         for (int i = 0; i < len; i++)
00544           if (testers[index]->get(i) != junk_space[junk_start + i])
00545             deadly_error(ta.class_name(), __WHERE__, "reset failed to copy data");
00546         break;
00547       }
00548       case do_shrink: {
00549 #ifdef DEBUG_TEST_ARRAY
00550         LOG(isprintf("do_shrink"));
00551 #endif
00552         array<contents> garp = *testers[index];
00553         testers[index]->shrink();
00554         int new_diff = testers[index]->internal_real_length()
00555             - testers[index]->length();
00556         if (!compare_arrays(garp, *testers[index]))
00557           deadly_error(ta.class_name(), __WHERE__, "shrink failed to keep contents");
00558         // now force a real shrinkage.
00559         if (testers[index]->length() < 5) continue;  // need some room.
00560         // pick an element to keep that is not first or last.
00561         int kept = ta.randomizer().inclusive(1, testers[index]->last() - 1);
00562         // whack all but the lucky element.
00563         testers[index]->zap(kept + 1, testers[index]->last());
00564         testers[index]->zap(0, kept - 1);
00565         // shrink it again, now a big shrink.
00566         testers[index]->shrink();
00567         // check the difference now.
00568         new_diff = testers[index]->internal_real_length()
00569             - testers[index]->length();
00570         if (new_diff > 1) 
00571           deadly_error(ta.class_name(), __WHERE__, "massive shrink gave a bad size");
00572 
00573         // restore the original contents and block size.
00574         *testers[index] = garp;
00575         break;
00576       }
00577       case do_concatenating: {
00578 #ifdef DEBUG_TEST_ARRAY
00579         LOG(isprintf("do_concatenating"));
00580 #endif
00581         for (int i = 0; i < ta.randomizer().inclusive(1, 20); i++) {
00582           contents new_c = contents(ta.randomizer().inclusive('a', 'z'));
00583           testers[index]->concatenate(new_c);
00584           if (new_c != testers[index]->get(testers[index]->last()))
00585             deadly_error(ta.class_name(), __WHERE__,
00586                 "value wrong after concatenate");
00587         }
00588         int indy = ta.randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00589         array<contents> flirpan = *testers[indy];
00590         int start = ta.randomizer().inclusive(0, flirpan.length() - 1);
00591         int end = ta.randomizer().inclusive(0, flirpan.length() - 1);
00592         flip_increasing(start, end);
00593         flirpan = flirpan.subarray(start, end);
00594         array<contents> grumzor = *testers[index];  // old copy.
00595         testers[index]->concatenate(flirpan);
00596         array<contents> bubula = grumzor + flirpan;
00597         if (!compare_arrays(bubula, *testers[index]))
00598           deadly_error(ta.class_name(), __WHERE__,
00599               "contents wrong after concatenate or concatenation");
00600         contents first_value;
00601         contents second_value;
00602         if (testers[index]->length() >= 1)
00603           first_value = testers[index]->get(0);
00604         if (testers[index]->length() >= 2)
00605           second_value = testers[index]->get(1);
00606         const int max_iters = ta.randomizer().inclusive(1, 42);
00607         for (int j = 0; j < max_iters; j++) {
00608           contents new_c = contents(ta.randomizer().inclusive('a', 'z'));
00609           *testers[index] = *testers[index] + new_c;
00610           // correct our value checks if new indices became available.
00611           if (testers[index]->length() == 1) {
00612             first_value = testers[index]->get(0);
00613           } else if (testers[index]->length() == 2) {
00614             second_value = testers[index]->get(1);
00615           }
00616 
00617           if (new_c != testers[index]->get(testers[index]->last()))
00618             deadly_error(ta.class_name(), __WHERE__, "value wrong after "
00619                 "concatenation");
00620 
00621           if ( (testers[index]->length() >= 1)
00622               && (first_value != testers[index]->get(0)) )
00623             deadly_error(ta.class_name(), __WHERE__, "first value got "
00624                 "corrupted");
00625           if ( (testers[index]->length() >= 2)
00626               && (second_value != testers[index]->get(1)) )
00627             deadly_error(ta.class_name(), __WHERE__, "second value got "
00628                 "corrupted");
00629 
00630           *testers[index] += new_c;
00631           // we don't have to correct the first value any more, but might have
00632           // to correct the second.
00633           if (testers[index]->length() == 2) {
00634             second_value = testers[index]->get(1);
00635           }
00636           if (new_c != testers[index]->get(testers[index]->last()))
00637             deadly_error(ta.class_name(), __WHERE__, "value wrong after "
00638                 "second concatenation");
00639           if ( (testers[index]->length() >= 1)
00640               && (first_value != testers[index]->get(0)) )
00641             deadly_error(ta.class_name(), __WHERE__, "first value got "
00642                 "corrupted after second concat");
00643           if ( (testers[index]->length() >= 2)
00644               && (second_value != testers[index]->get(1)) )
00645             deadly_error(ta.class_name(), __WHERE__, "second value got "
00646                 "corrupted after second concat");
00647         }
00648         break;
00649       }
00650       case do_concatenating2: {
00651         // this tests the new concatenate content array method for array.
00652 #ifdef DEBUG_TEST_ARRAY
00653         LOG(isprintf("do_concatenating2"));
00654 #endif
00655         array<contents> &flirpan = *testers[index];
00656         int new_len = ta.randomizer().inclusive(0, 140);
00657         contents *to_add = new contents[new_len];
00658         for (int i = 0; i < new_len; i++) {
00659           int rando = ta.randomizer().inclusive(0, MAX_BLOCK - 1);
00660           to_add[i] = junk_space[rando];
00661         }
00662         int old_len = flirpan.length();
00663         flirpan.concatenate(to_add, new_len);
00664         for (int i = 0; i < new_len; i++) {
00665           if (flirpan[i + old_len] != to_add[i])
00666             deadly_error(ta.class_name(), __WHERE__, "value wrong after "
00667                 "content array concatenation");
00668         }
00669         delete [] to_add;  // clean up.
00670         break;
00671       }
00672       case do_subarray: {
00673 #ifdef DEBUG_TEST_ARRAY
00674         LOG(isprintf("do_subarray"));
00675 #endif
00676         array<contents> flirpan = *testers[index];
00677         int start = ta.randomizer().inclusive(0, flirpan.length() - 1);
00678         int end = ta.randomizer().inclusive(0, flirpan.length() - 1);
00679         flip_increasing(start, end);
00680         flirpan = flirpan.subarray(start, end);
00681         for (int i = 0; i < end - start; i++)
00682           if (flirpan[i] != testers[index]->get(i + start))
00683             deadly_error(ta.class_name(), __WHERE__, "subarray produced wrong array");
00684         break;
00685       }
00686       case do_memory_paring: {
00687 #ifdef DEBUG_TEST_ARRAY
00688         LOG(isprintf("do_memory_paring"));
00689 #endif
00690         for (int i = 0; i < MAX_SIMULTANEOUS_OBJECTS; i++) {
00691           // zap extra junk off so we bound the memory usage.
00692           if (testers[i]->length() > MAX_OBJECT) {
00693             testers[i]->zap(MAX_OBJECT, testers[i]->length() - 1);
00694             testers[i]->shrink();
00695           }
00696         }
00697         break;
00698       }
00699       case do_snarf: {
00700 #ifdef DEBUG_TEST_ARRAY
00701         LOG(isprintf("do_snarf"));
00702 #endif
00703         array<contents> flirpan = *testers[index];
00704 //        int start = ta.randomizer().inclusive(0, flirpan.length() - 1);
00705 //        int end = ta.randomizer().inclusive(0, flirpan.length() - 1);
00706 //        flip_increasing(start, end);
00707 //        flirpan = flirpan.subarray(start, end);
00708         int rand_index = ta.randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00709         if (index == rand_index) continue;  // skip it; try again later.
00710         array<contents> nugwort = *testers[rand_index];
00711         // perform a swap between two of our arrays.
00712         array<contents> temp_hold(0, NIL, flags);
00713         temp_hold.snarf(*testers[index]);
00714         testers[index]->snarf(*testers[rand_index]);
00715         testers[rand_index]->snarf(temp_hold);
00716         // the copies should have flipped places now.  check them.
00717         if (flirpan.length() != testers[rand_index]->length())
00718           deadly_error(ta.class_name(), __WHERE__, "snarf produced wrong length A");
00719         for (int i = 0; i < flirpan.length(); i++)
00720           if (flirpan[i] != testers[rand_index]->get(i))
00721             deadly_error(ta.class_name(), __WHERE__, "snarf produced wrong array A");
00722         if (nugwort.length() != testers[index]->length())
00723           deadly_error(ta.class_name(), __WHERE__, "snarf produced wrong length B");
00724         for (int j = 0; j < nugwort.length(); j++)
00725           if (nugwort[j] != testers[index]->get(j))
00726             deadly_error(ta.class_name(), __WHERE__, "snarf produced wrong array B");
00727         break;
00728       }
00729       case do_flush: {
00730 #ifdef DEBUG_TEST_ARRAY
00731         LOG(isprintf("do_flush"));
00732 #endif
00733         array<contents> flirpan = *testers[index];
00734 
00736 
00738 
00739 
00740         break;
00741       }
00742 
00743       case do_insert: {
00744 #ifdef DEBUG_TEST_ARRAY
00745         LOG(isprintf("do_insert"));
00746 #endif
00747         array<contents> hold = *testers[index];
00748         int where = ta.randomizer().inclusive(0, hold.last());
00749         int how_many = ta.randomizer().inclusive(0, 25);
00750         testers[index]->insert(where, how_many);
00751         for (int i = 0; i < where; i++)
00752           if (hold[i] != testers[index]->get(i))
00753             deadly_error(ta.class_name(), __WHERE__, "bad contents on left after insert");
00754         for (int j = where + how_many; j < testers[index]->length(); j++)
00755           if (hold[j - how_many] != testers[index]->get(j))
00756             deadly_error(ta.class_name(), __WHERE__, "bad contents on right after insert");
00757         break;
00758       }
00759       case do_overwrite: {
00760 #ifdef DEBUG_TEST_ARRAY
00761         LOG(isprintf("do_overwrite"));
00762 #endif
00763         if (!testers[index]->length()) continue;
00764         array<contents> hold = *testers[index];
00765         int index2 = index;
00766         while (index2 == index)
00767           index2 = ta.randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00768         array<contents> &hold2 = *testers[index2];
00769         if (!hold2.length()) continue;
00770         int write_indy = ta.randomizer().inclusive(0, hold.last());
00771         int write_len = minimum(hold2.length(), (hold.length() - write_indy));
00772 // LOG(isprintf("len1 = %d len2 = %d wrindy=%d wrlen=%d", hold.length(), hold2.length(), write_indy, write_len));
00773         outcome ret = testers[index]->overwrite(write_indy,
00774             *testers[index2], write_len);
00775         if (ret != common::OKAY)
00776           deadly_error(ta.class_name(), __WHERE__, istring("bad outcome=")
00777               + common::outcome_name(ret));
00778         for (int i = 0; i < write_indy; i++)
00779           if (hold[i] != testers[index]->get(i))
00780             deadly_error(ta.class_name(), __WHERE__,
00781                 "bad contents on left after overwrite");
00782         for (int j = write_indy; j < write_indy + write_len; j++)
00783           if (hold2[j - write_indy] != testers[index]->get(j))
00784             deadly_error(ta.class_name(), __WHERE__,
00785                 "bad contents in middle after overwrite");
00786         for (int k = write_indy + write_len; k < testers[index]->length(); k++)
00787           if (hold[k] != testers[index]->get(k))
00788             deadly_error(ta.class_name(), __WHERE__,
00789                 "bad contents on right after overwrite");
00790         break;
00791       }
00792       case do_stuff: {
00793 #ifdef DEBUG_TEST_ARRAY
00794         LOG(isprintf("do_stuff"));
00795 #endif
00796         array<contents> &hold = *testers[index];
00797         contents burgers[100];
00798         int stuff_len = ta.randomizer().inclusive(0, hold.length());
00799         stuff_len = minimum(stuff_len, 100);
00800         outcome ret = hold.stuff(stuff_len, burgers);
00801         if (ret != common::OKAY)
00802           deadly_error(ta.class_name(), __WHERE__, istring("bad outcome=")
00803               + common::outcome_name(ret));
00804         for (int i = 0; i < stuff_len; i++)
00805           if (burgers[i] != hold[i])
00806             deadly_error(ta.class_name(), __WHERE__, "bad contents after stuff");
00807         break;
00808       }
00809       default: {
00810         deadly_error(ta.class_name(), "action choice", "invalid choice!");
00811         break;
00812       }
00813     }
00814   }
00815 
00816   // clean up.
00817   delete [] junk_space;
00818   for (int d = 0; d < MAX_SIMULTANEOUS_OBJECTS; d++) delete testers[d];
00819 }
00820 
00822 
00823 struct gerkin { int l; byte *p; char *r; void *pffttt; };
00824 
00825 gerkin borgia;
00826 
00827 class foop
00828 {
00829 public:
00830   virtual ~foop() {}
00831   virtual gerkin *boorba() = 0;
00832 };
00833 
00834 class boop : public foop
00835 {
00836 public:
00837   virtual gerkin *boorba() { return &borgia; }
00838 };
00839 
00840 void test_array::test_iteration_speed()
00841 {
00842   const int MAX_CHUNK = 100000;
00843   const int MAX_REPS = 20;
00844   byte_array chunky(MAX_CHUNK);
00845 
00846   {
00847     time_stamp start;
00848     int sum = 0;
00849     for (int j = 0; j < MAX_REPS; j++) {
00850       for (int i = 0; i < MAX_CHUNK; i++) {
00851         sum += chunky[i];
00852       }
00853     }
00854     int duration = int(time_stamp().value() - start.value());
00855 
00856     LOG(isprintf("iteration over %d elements took %d ms,\tor %f ms per 1000 iters.",
00857         MAX_CHUNK * MAX_REPS, duration,
00858         double(duration) / double(MAX_CHUNK * MAX_REPS) * 1000.0));
00859   }
00860 
00861   {
00862     time_stamp start;
00863     int sum = 0;
00864     const byte *head = chunky.observe();
00865     for (int j = 0; j < MAX_REPS; j++) {
00866       for (int i = 0; i < MAX_CHUNK; i++) {
00867         sum += head[i];
00868       }
00869     }
00870     int duration = int(time_stamp().value() - start.value());
00871 
00872     LOG(isprintf("less-safe iteration over %d elements took %d ms,\tor %f ms per 1000 iters.",
00873         MAX_CHUNK * MAX_REPS, duration,
00874         double(duration) / double(MAX_CHUNK * MAX_REPS) * 1000.0));
00875   }
00876   {
00877     time_stamp start;
00878     boop tester;
00879 //    int sum = 0;
00880     for (int j = 0; j < MAX_REPS; j++) {
00881       for (int i = 0; i < MAX_CHUNK; i++) {
00882 //        chunky.modus().sampler();
00883         tester.boorba();
00884       }
00885     }
00886     int duration = int(time_stamp().value() - start.value());
00887 
00888     LOG(isprintf("virtual-function-only over %d elements took %d ms,\tor %f ms per 1000 iters.",
00889         MAX_CHUNK * MAX_REPS, duration,
00890         double(duration) / double(MAX_CHUNK * MAX_REPS) * 1000.0));
00891   }
00892 }
00893 
00895 
00896 int test_array::execute()
00897 {
00898   test_iteration_speed();
00899   LOG(isprintf("did iteration test.")); 
00900 
00901   int_array checking_start;
00902   if (checking_start.length())
00903     deadly_error(class_name(), "int_array length",
00904         "has contents from empty constructor!");
00905 
00906   float_plus<double> bogus4 = float(12.32);
00907   array_tester<float_plus<double> >(*this, bogus4,
00908       byte_array::SIMPLE_COPY | byte_array::EXPONE
00909           | byte_array::FLUSH_INVISIBLE);
00910   LOG(isprintf("did float array test.")); 
00911 
00912   int bogus2 = 39;
00913   array_tester<int>(*this, bogus2,
00914       byte_array::SIMPLE_COPY | byte_array::EXPONE
00915           | byte_array::FLUSH_INVISIBLE);
00916   LOG(isprintf("did int array test.")); 
00917 
00918   test_content bogus3(12);
00919   array_tester<test_content>(*this, bogus3, byte_array::EXPONE
00920       | byte_array::FLUSH_INVISIBLE);
00921   LOG(isprintf("did test_content array test.")); 
00922 
00923   test_arrays_of_void_pointer();
00924   LOG(isprintf("did void * array test.")); 
00925 
00926   byte bogus1 = 'c';
00927   array_tester<byte>(*this, bogus1,
00928       byte_array::SIMPLE_COPY | byte_array::EXPONE
00929           | byte_array::FLUSH_INVISIBLE);
00930   LOG(isprintf("did byte array test.")); 
00931 
00932   guards::alert_message("array:: works for those functions tested.");
00933 
00934   return 0;
00935 }
00936 
00937 HOOPLE_MAIN(test_array, )
00938 

Generated on Fri Nov 21 04:30:05 2008 for HOOPLE Libraries by  doxygen 1.5.1