gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

ptypes_test.cxx (32897B)


      1 /*
      2  *
      3  *  C++ Portable Types Library (PTypes)
      4  *  Version 2.1.1  Released 27-Jun-2007
      5  *
      6  *  Copyright (C) 2001-2007 Hovik Melikyan
      7  *
      8  *  http://www.melikyan.com/ptypes/
      9  *
     10  */
     11 #include <stdlib.h>
     12 #include <stdio.h>
     13 
     14 #include "pport.h"
     15 #include "ptypes.h"
     16 #include "pstreams.h"
     17 #include "pinet.h"
     18 #include "ptime.h"
     19 
     20 
     21 #ifndef PTYPES_ST
     22 #include "pasync.h"
     23 #endif
     24 
     25 
     26 USING_PTYPES
     27 
     28 
     29 void passert(bool cond)
     30 {
     31     if (!cond)
     32     {
     33         fatal(0xa3, "*** ASSERTION FAILED ***");
     34     }
     35 }
     36 
     37 
     38 void showstr(const char* shouldbe, const char* is) 
     39 {
     40     passert(strcmp(shouldbe, is) == 0);
     41     pout.putf("[%s] %s\n", shouldbe, is);
     42 }
     43 
     44 
     45 void showstr(const char* shouldbe, const string& is) 
     46 {
     47     showstr(shouldbe, pconst(is));
     48 }
     49 
     50 
     51 void showhex(const char* shouldbe, const char* is, int islen) 
     52 {
     53     string s;
     54     int i;
     55     for (i = 0; i < islen; i++)
     56         s += itostring((unsigned char)is[i], 16, 2);
     57     s = lowercase(s);
     58     showstr(shouldbe, s);
     59 }
     60 
     61 
     62 void showint(int shouldbe, int is) 
     63 {
     64     passert(shouldbe == is);
     65     pout.putf("[%d] %d\n", shouldbe, is);
     66 }
     67 
     68 
     69 void showint(large shouldbe, large is) 
     70 {
     71     passert(shouldbe == is);
     72     pout.putf("[%lld] %lld\n", shouldbe, is);
     73 }
     74 
     75 
     76 void showchar(char shouldbe, char is) 
     77 {
     78     passert(shouldbe == is);
     79     pout.putf("[%c] %c\n", shouldbe, is);
     80 }
     81 
     82 
     83 //
     84 // string test
     85 //
     86 
     87 
     88 void const_string_call(const string& s)
     89 {
     90     showchar('R', s[2]);
     91 }
     92 
     93 
     94 void string_test1() 
     95 {
     96     pout.put("\n--- STRING CLASS\n");
     97 
     98     static char strbuf[10] = "STRING";
     99 
    100     char c = 'A';
    101 
    102     string s1 = "string";
    103     s1 = s1;
    104     s1 += s1;
    105     del(s1, 6, 6);
    106     string s2 = s1;
    107     string s3;
    108     string s4(strbuf, strlen(strbuf));
    109     string s5 = 'A';
    110     string s6 = c;
    111 
    112     showstr("string", s1);
    113     showstr(s1, s2);
    114     showstr("", s3);
    115     showstr("STRING", s4);
    116     const_string_call(s4);
    117     showchar('I', s4[3]);
    118     showint(6, length(s4));
    119     showint(2, refcount(s1));
    120     clear(s2);
    121     showint(1, refcount(s1));
    122     s2 = s1;
    123     unique(s1);
    124     showint(1, refcount(s1));
    125     setlength(s1, 64);
    126     string s7 = s1;
    127     setlength(s1, 3);
    128     showstr("str", s1);
    129     showstr("strING", s1 += copy(s4, 3, 3));
    130     del(s1, 3, 3);
    131     showstr("str", s1);
    132     ins("ing", s1, 0);
    133     showstr("ingstr", s1);
    134     s2 = "str" + s1 + "ing";
    135     showstr("stringstring", s2);
    136     s3 = s2;
    137     s3 = "strungstrung";
    138     s3 = s2;
    139     s3 = "strung";
    140     del(s3, 4);
    141     showstr("stru", s3);
    142 
    143     s2 = "str" + s1;
    144     s2 = s1 + "str";
    145     s2 += "str";
    146 
    147     s2 = 's' + s1;
    148     s2 = s1 + 's';
    149     s2 += 's';
    150     
    151     s2 = c + s1;
    152     s2 = s1 + c;
    153     s2 += c;
    154 
    155     s2 = 'a';
    156     s2 = c;
    157 }
    158 
    159 
    160 void string_test2() 
    161 {
    162     pout.put("\n--- STRING CLASS\n");
    163 
    164     string s1 = "ingstr";
    165     string s2 = "stringstring";
    166     string s4 = "STRING";
    167 
    168     showint(1, pos('t', s2));
    169     showint(2, pos("ri", s2));
    170     showint(3, pos(s1, s2));
    171     showint(1, contains("tr", s2, 1));
    172     showint(0, contains("tr", s2, 2));
    173     showint(1, s4 == "STRING");
    174     showint(1, "STRING" == s4);
    175     showchar('R', s4[2]);
    176 
    177     string s5 = 'A';
    178     showint(1, s5 == 'A');
    179     showint(1, 'A' == s5);
    180 
    181     showstr("123456789", itostring(123456789));
    182     showstr("123", itostring(char(123)));
    183     showstr("-000123", itostring(-123, 10, 7, '0'));
    184     showstr("0ABCDE", itostring(0xabcde, 16, 6));
    185     showstr("-9223372036854775808", itostring(LARGE_MIN));
    186     showstr("18446744073709551615", itostring(ULARGE_MAX));
    187 
    188     showint(1234, (int)stringtoi("1234"));
    189     showint(large(0x15AF), stringtoue("15AF", 16));
    190     showint(LARGE_MAX, stringtoue("5zzzzzzzzzz", 64));
    191 
    192     try
    193     {
    194         // out of range by 1
    195         stringtoue("18446744073709551616", 10);
    196         fatal(0xb0, "Conversion overflow not detected");
    197     }
    198     catch (econv* e)
    199     {
    200         showstr("Out of range: '18446744073709551616'", e->get_message());
    201         delete e;
    202     }
    203 
    204     showint(large(123), stringtoie("123"));
    205     showint(large(-123), stringtoie("-123"));
    206     showint(LARGE_MIN, stringtoie("-9223372036854775808"));
    207     showint(LARGE_MAX, stringtoie("9223372036854775807"));
    208 
    209     try
    210     {
    211         // out of range by 1
    212         stringtoie("9223372036854775808");
    213         fatal(0xb0, "Conversion overflow not detected");
    214     }
    215     catch (econv* e)
    216     {
    217         showstr("Out of range: '9223372036854775808'", e->get_message());
    218         delete e;
    219     }
    220 
    221     showstr("abcabc", lowercase(s1 = "aBCAbc"));
    222     showstr("abcabc", lowercase(s1));
    223 }
    224 
    225 
    226 void string_benchmarks()
    227 {
    228     pout.put("\n--- STRING BENCHMARKS\n");
    229 
    230     int i;
    231     string s1 = "string";
    232     string s2;
    233 
    234     // for the first time we run the test to let the VM settle down and stop swapping
    235     for (i = 0; i < 156000; i++)
    236         s2 += s1;
    237 
    238     // here is the actual test
    239     clear(s2);
    240     datetime start = now();
    241     for (i = 0; i < 156000; i++)
    242         s2 += s1;
    243     datetime diff = now() - start;
    244 
    245     pout.putf("Performance index compared to WinNT on P3/800MHz (smaller = better):\n%.3f\n", diff / 1000.0);
    246 }
    247 
    248 
    249 //
    250 // cset test
    251 //
    252 
    253 void cset_test() 
    254 {
    255     pout.put("\n--- CSET CLASS\n");
    256 
    257     cset s1 = "~09~0a~0d~F0 A-Z~~";
    258     cset s2 = "A-F";
    259     char c = 'B';
    260 
    261     showstr("~09~0a~0d A-Z~~~f0", asstring(s1));
    262     s1 -= char(0xf0);
    263     s1 -= cset("~00-~20");
    264     showstr("A-Z~~", asstring(s1));
    265     s1 -= s2;
    266     showstr("G-Z~~", asstring(s1));
    267     s1 += s2;
    268     s1 += ' ';
    269     showstr(" A-Z~~", asstring(s1));
    270     showint(1, s2 == cset("A-F"));
    271     showint(1, s2 <= s1);
    272     s1 -= 'A';
    273     s1 -= c;
    274     showint(0, s2 <= s1);
    275     s1 = s1 + char(0xf1);
    276     showint(1, char(0xf1) & s1);
    277     showint(0, char(0xf2) & s1);
    278 }
    279 
    280 
    281 //
    282 // podlist
    283 //
    284 
    285 
    286 void const_podlist_test(const tpodlist<int, true>& p)
    287 {
    288 //    int& i = p[0];
    289     showint(7, p[1]);
    290 }
    291 
    292 
    293 void podlist_test()
    294 {
    295     pout.put("\n--- PODLIST\n");
    296 
    297     tpodlist<int, true> p;
    298     p.add() = 6;
    299     p.add(8);
    300     p.ins(1, 7);
    301     showint(7, p[1]);
    302     const_podlist_test(p);
    303     showint(3, p.get_count());
    304     p.set_count(5);
    305     p.ins(5) = 10;
    306     showint(10, p.top());
    307     p.pop();
    308 
    309     tpodlist<int, true> p1;
    310     p1.add(p);
    311     p1.pop();
    312     p1.add(p);
    313 }
    314 
    315 
    316 //
    317 // ptrlist
    318 //
    319 
    320 
    321 struct known: public unknown
    322 {
    323     int value;
    324     known(int ivalue): value(ivalue) {}
    325 };
    326 
    327 typedef tobjlist<known> knownlist;
    328 
    329 
    330 string ol_asstring(const knownlist& s)
    331 {
    332     string ret = "{";
    333     for (int i = 0; i < s.get_count(); i++) {
    334         if (i > 0)
    335             concat(ret, ", ");
    336         ret += itostring(s[i]->value);
    337     }
    338     concat(ret, '}');
    339     return ret;
    340 }
    341 
    342 
    343 void ptrlist_test()
    344 {
    345     pout.put("\n--- PTRLIST\n");
    346 
    347     knownlist s1(true);
    348     known* obj;
    349 
    350     s1.add(new known(10));
    351     s1.ins(0, new known(5));
    352     s1.ins(2, obj = new known(20));
    353     s1.add(new known(30));
    354     s1.add(new known(40));
    355     s1.put(4, new known(45));
    356     s1.del(4);
    357     s1.del(1);
    358 
    359     s1[0];
    360     showint(3, s1.get_count());
    361     showint(1, s1.indexof(obj));
    362     showstr("{5, 20, 30}", ol_asstring(s1));
    363 
    364     s1.clear();
    365     showstr("{}", ol_asstring(s1));
    366 }
    367 
    368 
    369 
    370 //
    371 // strlist
    372 //
    373 
    374 
    375 typedef tstrlist<known> knownstrlist;
    376 
    377 
    378 string sl_asstring(const knownstrlist& s)
    379 {
    380     string ret = "{";
    381     for (int i = 0; i < s.get_count(); i++)
    382     {
    383         if (i > 0)
    384             concat(ret, ", ");
    385         ret += s.getkey(i) + ":" + itostring(s[i]->value);
    386     }
    387     concat(ret, '}');
    388     return ret;
    389 }
    390 
    391 
    392 void strlist_test()
    393 {
    394     pout.put("\n--- STRLIST\n");
    395 
    396     knownstrlist s1(SL_OWNOBJECTS);
    397     known* obj;
    398 
    399     s1.add("ten", new known(10));
    400     s1.ins(0, "five", new known(5));
    401     s1.ins(2, "twenty", obj = new known(20));
    402     s1.add("thirty", new known(30));
    403     s1.add("forty", new known(40));
    404     s1.put(4, "forty five", new known(45));
    405     s1.del(4);
    406     s1.del(1);
    407 
    408     showint(3, s1.get_count());
    409     showint(1, s1.indexof(obj));
    410     showint(2, s1.indexof("thirty"));
    411     showint(2, s1.indexof("THIRTY"));
    412     showint(-1, s1.indexof("forty"));
    413 
    414     showstr("{five:5, twenty:20, thirty:30}", sl_asstring(s1));
    415 
    416     knownstrlist s2(SL_OWNOBJECTS | SL_SORTED | SL_CASESENS);
    417     s2.add("five", new known(5));
    418     s2.add("ten", new known(10));
    419     s2.add("twenty", new known(20));
    420     s2.add("thirty", new known(30));
    421     s2.add("forty", new known(40));
    422 
    423     showint(5, s2.get_count());
    424     showint(3, s2.indexof("thirty"));
    425     showint(-1, s2.indexof("THIRTY"));
    426     showint(-1, s2.indexof("hovik"));
    427 
    428     showstr("{five:5, forty:40, ten:10, thirty:30, twenty:20}", sl_asstring(s2));
    429 
    430     s2.clear();
    431     showstr("{}", sl_asstring(s2));
    432 
    433     tstrlist<known> s3(SL_OWNOBJECTS | SL_SORTED | SL_DUPLICATES);
    434 
    435     s3.add("a", nil);
    436     s3.add("b", nil);
    437     s3.add("b", nil);
    438     s3.add("b", nil);
    439     s3.add("b", nil);
    440     s3.add("b", nil);
    441     s3.add("b", nil);
    442     s3.add("c", nil);
    443 
    444     showint(1, s3.indexof("b"));
    445     s3.del(1, 2);
    446 
    447     tstrlist<known> s(SL_OWNOBJECTS | SL_SORTED);
    448 
    449     s.put("five", new known(5));
    450     s.put("ten", new known(10));
    451     s.put("twenty", new known(20));
    452     s.put("thirty", new known(30));
    453     s.put("forty", new known(40));
    454 
    455     showint(20, s["twenty"]->value);
    456     showint(0, pintptr(s["hovik"]));
    457     showint(5, s.get_count());
    458     s.put("twenty", nil);
    459     showint(4, s.get_count());
    460 }
    461 
    462 
    463 //
    464 // textmap
    465 //
    466 
    467 
    468 void textmap_test()
    469 {
    470     pout.put("\n--- TEXTMAP CLASS\n");
    471 
    472     textmap c;
    473 
    474     c.put("name1", "value1");
    475     c.put("name2", "value2");
    476     c.put("name1", "value3");
    477     showstr("name2", c.getkey(1));
    478     c.put("name2", "");
    479     showint(1, c.get_count());
    480     showstr("value3", c["name1"]);
    481     showstr("", c["name2"]);
    482 }
    483 
    484 
    485 
    486 //
    487 // streams
    488 //
    489 
    490 
    491 char buf1[] = "This is a test.";
    492 char buf2[] = "The file should contain readable text.";
    493 
    494 const char* fname = "stmtest.txt";
    495 
    496 void outfile_test() 
    497 {
    498     pout.put("\n--- OUTFILE CLASS\n");
    499 
    500     showint(8, sizeof(off_t));
    501 
    502     outfile f(fname, false);
    503     f.set_umode(0600);
    504     f.set_bufsize(3);
    505 
    506     f.open();
    507     f.put(buf1[0]);
    508     f.put(buf1[1]);
    509     f.put("is is a TEST.");
    510     f.seek(-5, IO_END);
    511     f.put("tes*/");
    512     f.seek(13);
    513     f.put("t.");
    514     f.puteol();
    515     f.close();
    516 
    517     f.set_append(true);
    518     f.open();
    519     f.write(buf2, strlen(buf2));
    520     f.puteol();
    521     f.close();
    522 
    523     pnull.put("This should go to nowhere I");
    524     pnull.put("This should go to nowhere II");
    525 }
    526 
    527 
    528 void infile_test() 
    529 {
    530     pout.put("\n--- INFILE CLASS\n");
    531 
    532     compref<instm> f = &pin;
    533     f = new infile(fname);
    534     f->set_bufsize(3);
    535 
    536     char temp[4];
    537 
    538     f->open();
    539     pout.putf("%c", f->get());
    540     pout.putf("%s\n", pconst(f->line()));
    541     f->read(temp, sizeof temp - 1);
    542     temp[sizeof temp - 1] = 0;
    543     pout.putf("%s", temp);
    544     f->get();
    545     f->putback();
    546     pout.putf("%s", pconst(f->token(cset("~20-~FF"))));
    547     f->preview();
    548     if (f->get_eol()) 
    549     {
    550         f->skipline();
    551         pout.put("\n");
    552     }
    553     if (f->get_eof())
    554         pout.put("EOF\n");
    555 //    f.error(1, "Test error message");
    556 
    557 }
    558 
    559 
    560 void mem_test()
    561 {
    562     pout.put("\n--- OUT/IN MEMORY CLASS\n");
    563 
    564     {
    565         outmemory m(12);
    566         m.open();
    567         m.put("MEMOry");
    568         m.put(" c");
    569         m.put("lass is working");
    570         m.seek(1);
    571         m.put("emo");
    572         showstr("Memory class", m.get_strdata());
    573         // try reuse
    574         m.open();
    575         m.put("memory");
    576         showstr("memory", m.get_strdata());
    577     }
    578     {
    579         inmemory m("");
    580         m.open();
    581         showstr("", m.token("*"));
    582         m.set_strdata("gArbaGe");
    583         m.open();
    584         // try reuse
    585         m.set_strdata("string strong");
    586         m.set_bufsize(2); // has no effect
    587         m.open();
    588         showstr("string", m.token("a-z"));
    589         m.seek(-6, IO_END);
    590         showstr("strong", m.token("a-z"));
    591     }
    592 }
    593 
    594 
    595 #ifndef PTYPES_ST
    596 
    597 //
    598 // multithreading
    599 //
    600 
    601 //
    602 // rwlock test
    603 //
    604 
    605 const int rw_max_threads = 30;
    606 const int rw_max_tries = 30;
    607 const int rw_max_delay = 20;
    608 const int rw_rw_ratio = 5;
    609 const bool rw_swap = false;
    610 
    611 
    612 class rwthread: public thread
    613 {
    614 protected:
    615     virtual void execute();
    616 public:
    617     rwthread(): thread(false)  {}
    618     virtual ~rwthread()        { waitfor(); }
    619 };
    620 
    621 
    622 rwlock rw;
    623 
    624 int reader_cnt = 0;
    625 int writer_cnt = 0;
    626 int total_writers = 0;
    627 int total_readers = 0;
    628 int max_readers = 0;
    629 
    630 
    631 int prand(int max)
    632 {
    633     return rand() % max;
    634 }
    635 
    636 
    637 void rwthread::execute()
    638 {
    639 
    640     for(int i = 0; i < rw_max_tries; i++)
    641     {
    642         psleep(prand(rw_max_delay));
    643         bool writer = prand(rw_rw_ratio) == 0;
    644         if (writer ^ rw_swap)
    645         {
    646             rw.wrlock();
    647             pout.put('w');
    648             if (pincrement(&writer_cnt) > 1)
    649                 fatal(0xa0, "Writer: Huh?! Writers in here?");
    650             pincrement(&total_writers);
    651         }
    652         else
    653         {
    654             rw.rdlock();
    655             pout.put('.');
    656             int t;
    657             if ((t = pincrement(&reader_cnt)) > max_readers) 
    658                 max_readers = t;
    659             if (writer_cnt > 0)
    660                 fatal(0xa1, "Reader: Huh?! Writers in here?");
    661             pincrement(&total_readers);
    662         }
    663         psleep(prand(rw_max_delay));
    664         if (writer ^ rw_swap)
    665             pdecrement(&writer_cnt);
    666         else
    667             pdecrement(&reader_cnt);
    668         rw.unlock();
    669     }
    670 }
    671 
    672 
    673 
    674 void rwlock_test()
    675 {
    676 // #ifdef __PTYPES_RWLOCK__
    677     pout.put("\n--- RWLOCK\n");
    678 
    679     rwthread* threads[rw_max_threads];
    680 
    681     srand((unsigned)time(0));
    682 
    683     int i;
    684     for(i = 0; i < rw_max_threads; i++)
    685     {
    686         threads[i] = new rwthread();
    687         threads[i]->start();
    688     }
    689     for(i = 0; i < rw_max_threads; i++)
    690         delete threads[i];
    691 
    692     pout.putf("\nmax readers: %d\n", max_readers);
    693     pout.putline("do writers 'starve'?");
    694 // #endif
    695 }
    696 
    697 
    698 //
    699 // jobqueue test ----------------------------------------------------------
    700 //
    701 
    702 
    703 const int MSG_MYJOB = MSG_USER + 1;
    704 const int NUM_JOB_THREADS = 3;
    705 
    706 
    707 class jobthread: public thread
    708 {
    709 protected:
    710     int id;
    711     jobqueue* jq;
    712     virtual void execute();
    713 public:
    714     jobthread(int iid, jobqueue* ijq): thread(false), id(iid), jq(ijq) {}
    715     ~jobthread()  { waitfor(); }
    716 };
    717 
    718 
    719 void jobthread::execute()
    720 {
    721     bool quit = false;
    722     while (!quit)
    723     {
    724         message* m = jq->getmessage();
    725         try
    726         {
    727             switch (m->id)
    728             {
    729             case MSG_MYJOB:
    730                 // ... do the job ...
    731                 psleep(prand(10));
    732                 // report
    733                 pout.putf("Thread %d finished the job (param=%d)\n", id, m->param);
    734                 break;
    735             case MSG_QUIT:
    736                 quit = true;
    737                 break;
    738             }
    739         }
    740         catch(...)
    741         {
    742             // the message object must be freed!
    743             delete m;
    744             throw;
    745         }
    746         delete m;
    747     }
    748 }
    749 
    750 
    751 void jobqueue_test()
    752 {
    753     pout.put("\n--- JOBQUEUE\n");
    754 
    755     jobqueue jq(3);
    756     tobjlist<jobthread> threads(true);
    757 
    758     srand((unsigned)time(0));
    759 
    760     // create the thread pool and start all threads
    761     int i;
    762     for(i = 0; i < NUM_JOB_THREADS; i++)
    763     {
    764         jobthread* j = new jobthread(i + 1, &jq);
    765         j->start();
    766         threads.add(j);
    767     }
    768 
    769     // post jobs for processing
    770     jq.post(MSG_MYJOB, 1);
    771     jq.post(MSG_MYJOB, 2);
    772     jq.post(MSG_MYJOB, 3);
    773     jq.post(MSG_MYJOB, 4);
    774     jq.post(MSG_MYJOB, 5);
    775     jq.post(MSG_MYJOB, 6);
    776     jq.post(MSG_MYJOB, 7);
    777     jq.post(MSG_MYJOB, 8);
    778 
    779     // terminate all threads
    780     for(i = 0; i < NUM_JOB_THREADS; i++)
    781         jq.post(MSG_QUIT);
    782 
    783     // threads are being waitfor()'ed and destroyed
    784     // automatically by the list object
    785 }
    786 
    787 
    788 
    789 //
    790 // msgqueue test ----------------------------------------------------------
    791 //
    792 
    793 
    794 const int MSG_DIAG = MSG_USER + 1;
    795 
    796 
    797 //
    798 // msgqueue test
    799 //
    800 
    801 //
    802 // class diagmessage
    803 //
    804 
    805 class diagmessage: public message
    806 {
    807 protected:
    808     string module;
    809     string diagstr;
    810     friend class diagthread;
    811 public:
    812     diagmessage(string imodule, string idiagstr)
    813         : message(MSG_DIAG), module(imodule),
    814           diagstr(idiagstr)  {}
    815 };
    816 
    817 
    818 //
    819 // class diagthread
    820 //
    821 
    822 class diagthread: public thread, protected msgqueue
    823 {
    824 protected:
    825     virtual void execute();     // override thread::execute()
    826     virtual void cleanup();     // override thread::cleanup()
    827     virtual void msghandler(message& msg);  // override msgqueue::msghandler()
    828 public:
    829     diagthread(): thread(false), msgqueue()  { }
    830     void postdiag(string module, string diagstr);
    831     void postquit();
    832 };
    833 
    834 
    835 void diagthread::postdiag(string module, string diagstr)
    836 {  
    837     msgqueue::post(new diagmessage(module, diagstr));
    838 }
    839 
    840 
    841 void diagthread::postquit()
    842 { 
    843     msgqueue::post(MSG_QUIT); 
    844 }
    845 
    846 
    847 void diagthread::execute()
    848 {
    849     // starts message queue processing; calls
    850     // msghandler for each message
    851     msgqueue::run();
    852 }
    853 
    854 
    855 void diagthread::cleanup()
    856 {
    857 }
    858 
    859 
    860 void diagthread::msghandler(message& msg)
    861 {
    862     switch (msg.id)
    863     {
    864     case MSG_DIAG:
    865         {
    866             diagmessage& m = (diagmessage&)msg;
    867             pout.putf("%s: %s\n", pconst(m.module), pconst(m.diagstr));
    868         }
    869         break;
    870     default:
    871         defhandler(msg);
    872     }
    873 }
    874 
    875 
    876 //
    877 // class testthread
    878 //
    879 
    880 
    881 class testthread: public thread
    882 {
    883 protected:
    884     diagthread* diag;
    885     string myname;
    886     virtual void execute();
    887     virtual void cleanup();
    888 public:
    889     semaphore sem;
    890     timedsem tsem;
    891     testthread(diagthread* idiag)
    892         : thread(false), diag(idiag), myname("testthread"), sem(0), tsem(0)  {}
    893 };
    894 
    895 
    896 void testthread::execute()
    897 {
    898     diag->postdiag(myname, "starts and enters sleep for 1 second");
    899     psleep(1000);
    900     diag->postdiag(myname, "signals the timed semaphore");
    901     tsem.post();
    902     diag->postdiag(myname, "releases the simple semaphore");
    903     sem.post();
    904     diag->postdiag(myname, "enters sleep for 1 more second");
    905     psleep(1000);
    906 }
    907 
    908 
    909 void testthread::cleanup()
    910 {
    911     diag->postdiag(myname, "terminates");
    912 }
    913 
    914 
    915 int thread_test()
    916 {
    917     pout.put("\n--- THREAD AND SEMAPHORE CLASSES\n");
    918 
    919     int v = 0;
    920     showint(0, pexchange(&v, 5));
    921     showint(5, pexchange(&v, 10));
    922 
    923     void* pv = 0;
    924     passert(pexchange(&pv, &v) == 0);
    925     passert(pexchange(&pv, 0) == &v);
    926 
    927     showint(11, pincrement(&v));
    928     showint(10, pdecrement(&v));
    929 
    930     diagthread diag;
    931     testthread thr(&diag);
    932 
    933     string myname = "main";
    934 
    935     diag.start();
    936     thr.start();
    937 
    938     diag.postdiag(myname, "waits 5 secs for the timed semaphore (actually wakes up after a second)");
    939     thr.tsem.wait(5000);    // must exit after 1 second instead of 5
    940 
    941     diag.postdiag(myname, "waits for the semaphore");
    942     thr.sem.wait();
    943     diag.postdiag(myname, "now waits for testthread to terminate");
    944     thr.waitfor();
    945 
    946     diag.postquit();
    947     diag.waitfor();
    948     return 0;
    949 }
    950 
    951 
    952 //
    953 // trigger test
    954 //
    955 
    956 
    957 class trigthread: public thread
    958 {
    959 protected:
    960     diagthread* diag;
    961     string myname;
    962     virtual void execute();
    963 public:
    964     trigger trig;
    965     trigthread(diagthread* idiag)
    966         : thread(false), diag(idiag), myname("trigthread"), trig(true, false)  {}
    967     virtual ~trigthread()  { waitfor(); }
    968 };
    969 
    970 
    971 void trigthread::execute()
    972 {
    973     diag->postdiag(myname, "waits on the trigger");
    974     trig.wait();
    975 
    976     psleep(2000);
    977     diag->postdiag(myname, "waits on the trigger");
    978     trig.wait();
    979     
    980     diag->postdiag(myname, "terminates");
    981 }
    982 
    983 
    984 int trigger_test()
    985 {
    986     pout.put("\n--- TRIGGER\n");
    987 
    988     diagthread diag;
    989     trigthread thr(&diag);
    990 
    991     string myname = "main";
    992 
    993     diag.start();
    994     thr.start();
    995 
    996     psleep(1000);
    997     diag.postdiag(myname, "posts the trigger");
    998     thr.trig.post();
    999     
   1000     psleep(1000);
   1001     diag.postdiag(myname, "posts the trigger again");
   1002     thr.trig.post();
   1003 
   1004     thr.waitfor();
   1005     diag.postquit();
   1006     diag.waitfor();
   1007     return 0;
   1008 }
   1009 
   1010 
   1011 
   1012 #endif // PTYPES_ST
   1013 
   1014 
   1015 //
   1016 // md5 test
   1017 //
   1018 
   1019 static md5_digest digest;
   1020 
   1021 char* md5str(string data)
   1022 {
   1023     outmd5 m;
   1024     m.open();
   1025     m.put(data);
   1026     memcpy(digest, m.get_bindigest(), sizeof(md5_digest));
   1027     return (char*)digest;
   1028 }
   1029 
   1030 string cryptpw(string username, string password)
   1031 {
   1032     outmd5 m;
   1033     m.open();
   1034     m.put(username);
   1035     m.put(password);
   1036     m.close();
   1037     return m.get_digest();
   1038 }
   1039 
   1040 void md5_test()
   1041 {
   1042     pout.put("\n--- MD5 OUTPUT STREAM\n");
   1043     // MD5 test suite from RFC1321
   1044     showhex("d41d8cd98f00b204e9800998ecf8427e", md5str(""), md5_digsize);
   1045     showhex("0cc175b9c0f1b6a831c399e269772661", md5str("a"), md5_digsize);
   1046     showhex("900150983cd24fb0d6963f7d28e17f72", md5str("abc"), md5_digsize);
   1047     showhex("f96b697d7cb7938d525a2f31aaf161d0", md5str("message digest"), md5_digsize);
   1048     showhex("c3fcd3d76192e4007dfb496cca67e13b", md5str("abcdefghijklmnopqrstuvwxyz"), md5_digsize);
   1049     showhex("d174ab98d277d9f5a5611c2c9f419d9f", md5str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), md5_digsize);
   1050     showhex("57edf4a22be3c955ac49da2e2107b67a", md5str("12345678901234567890123456789012345678901234567890123456789012345678901234567890"), md5_digsize);
   1051     
   1052     showstr("t0htL.C9vunX8SPPsJjDmk", cryptpw("hovik", "myfavoritelonglonglongpassword"));
   1053 }
   1054 
   1055 
   1056 //
   1057 // outstm::putf() test
   1058 //
   1059 
   1060 void putf_test()
   1061 {
   1062     pout.put("\n--- PUTF TEST\n");
   1063     outmemory m;
   1064     m.open();
   1065 
   1066     m.putf("%s, %c, %d, %llx", "string", 'A', 1234, large(-1));
   1067     showstr("string, A, 1234, ffffffffffffffff", m.get_strdata());
   1068 
   1069     m.open();
   1070 
   1071     m.putf(" %%, %#o, %+010d", 0765, -3);
   1072     showstr(" %, 0765, -000000003", m.get_strdata());
   1073 }
   1074 
   1075 
   1076 //
   1077 // pinet/socket tests
   1078 //
   1079 
   1080 
   1081 void inet_test1()
   1082 {
   1083     try
   1084     {
   1085         pout.put("\n--- INET SOCKET & UTILITIES\n");
   1086         
   1087         ipaddress ip(127, 0, 0, 1);
   1088         
   1089         // as a test target host we use the one that would never be down! :)
   1090         string testname = "www.apache.org";
   1091         
   1092         ip = phostbyname(testname);
   1093         string ips = iptostring(ip);
   1094         pout.putf("IP address of %s: %s\n", pconst(testname), (ip == ipnone) ? "failed" : pconst(ips));
   1095         
   1096         if (ip != ipnone)
   1097         {
   1098             string hs = phostbyaddr(ip);
   1099             pout.putf("Name of %s: %s\n", pconst(ips), pconst(hs));
   1100         }
   1101         
   1102         pout.putf("Canonical name of your local www: %s\n", pconst(phostcname("www")));
   1103         
   1104         testname = "www.melikyan.com";
   1105         pout.putf("\nTrying %s:80...\n", pconst(testname));
   1106         ipstream s(testname, 80);
   1107 
   1108         const char* request = 
   1109             "GET /ptypes/test.txt HTTP/1.1\r\n"
   1110             "Accept: * /*\r\n"
   1111             "User-Agent: ptypes_test/2.1\r\n"
   1112             "Host: www.melikyan.com\r\n"
   1113             "Connection: close\r\n\r\n";
   1114 
   1115         s.open();
   1116         s.put(request);
   1117         s.flush();
   1118         
   1119         while (!s.get_eof())
   1120         {
   1121             char buf[16];
   1122             int r = s.read(buf, sizeof(buf));
   1123             pout.write(buf, r);
   1124         }
   1125         pout.put("\n");
   1126         
   1127         s.close();
   1128     }
   1129     catch(estream* e)
   1130     {
   1131         perr.putf("Socket error: %s\n", pconst(e->get_message()));
   1132         delete e;
   1133     }
   1134 }
   1135 
   1136 
   1137 #ifndef PTYPES_ST
   1138 
   1139 
   1140 const int testport = 8085;
   1141 
   1142 
   1143 class svthread: public thread, protected ipstmserver
   1144 {
   1145 protected:
   1146     virtual void execute();     // override thread::execute()
   1147     virtual void cleanup();     // override thread::cleanup()
   1148 public:
   1149     svthread(): thread(false)  {}
   1150     virtual ~svthread();
   1151 };
   1152 
   1153 
   1154 svthread::~svthread()
   1155 {
   1156     waitfor();
   1157 }
   1158 
   1159 
   1160 void svthread::execute()
   1161 {
   1162     ipstream client;            // a socket object to communicate with the client
   1163 
   1164     try
   1165     {
   1166         bindall(testport);      // listen to all local addresses on port 8081
   1167         serve(client);          // wait infinitely for a connection request
   1168         
   1169         if (client.get_active())
   1170         {
   1171             // read one line from the stream; note that theoretically the line can be long,
   1172             // so calling client.line(buf, sizeof(buf)) here is a much better idea
   1173             string req = lowercase(client.line());
   1174             if (req == "hello")
   1175             {
   1176                 // try to reverse-lookup the client's IP
   1177                 string host = phostbyaddr(client.get_ip());
   1178                 if (isempty(host))
   1179                     host = iptostring(client.get_ip());
   1180                 
   1181                 // now send our greeting to the client
   1182                 client.putf("Hello, %s (%a), nice to see you!\n",
   1183                     pconst(host), long(client.get_ip()));
   1184                 client.flush();
   1185             }
   1186 
   1187             // close() should be called explicitly to shut down the socket
   1188             // *gracefully*; otherwise ipstream's destructor may close the 
   1189             // socket but in a less polite manner
   1190             client.close();
   1191         }
   1192     }
   1193     catch(estream* e)
   1194     {
   1195         perr.putf("Server error: %s\n", pconst(e->get_message()));
   1196         delete e;
   1197     }
   1198     
   1199     // a real server could enter an infinite loop serving requests
   1200     // and producing separate threads for each connection
   1201 }
   1202 
   1203 
   1204 void svthread::cleanup()
   1205 {
   1206 }
   1207 
   1208 
   1209 void inet_test2()
   1210 {
   1211     pout.put("\n--- INET CLIENT/SERVER\n");
   1212         
   1213     // we run the server in a separate thread in order to be able
   1214     // to imitate a client connection from the main thread
   1215     svthread server;
   1216 
   1217     pout.put("\nStarting the server thread...\n");
   1218     server.start();         // it's that easy! :)
   1219 
   1220     // sleep some time to let the server start its job
   1221     psleep(1000);
   1222 
   1223     try
   1224     {
   1225         // now create a client socket and send a greeting to our server
   1226         ipstream client(ipaddress(127, 0, 0, 1), testport);
   1227         client.open();
   1228         
   1229         pout.put("Sending a request to the server...\n");
   1230         client.putline("Hello");
   1231         client.flush();
   1232         string rsp = client.line();
   1233         pout.putf("Received: %s\n", pconst(rsp));
   1234         pout.putf("My address and port: %s:%d\n", 
   1235             pconst(iptostring(client.get_myip())), client.get_myport());
   1236 
   1237         client.close();
   1238     }
   1239     catch(estream* e)
   1240     {
   1241         perr.putf("Error: %s\n", pconst(e->get_message()));
   1242         delete e;
   1243     }
   1244 
   1245 }
   1246 
   1247 
   1248 //
   1249 // UDP test
   1250 //
   1251 
   1252 
   1253 class msgsvthread: public thread
   1254 {
   1255 protected:
   1256     void execute();
   1257 public:
   1258     msgsvthread(): thread(false) {}
   1259     virtual ~msgsvthread() { waitfor(); }
   1260 };
   1261 
   1262 
   1263 void msgsvthread::execute()
   1264 {
   1265     ipmsgserver s;
   1266     s.bindall(testport);
   1267     try
   1268     {
   1269         string req = s.receive(1024);
   1270         pout.putf("Server received: %s\n", pconst(req));
   1271         string rsp = "gotcha";
   1272         s.send(rsp);
   1273     }
   1274     catch(estream* e)
   1275     {
   1276         perr.putf("Server error: %s\n", pconst(e->get_message()));
   1277         delete e;
   1278     }
   1279 }
   1280 
   1281 
   1282 void inet_test3()
   1283 {
   1284     pout.put("\n--- INET MESSAGE CLIENT/SERVER\n");
   1285 
   1286     msgsvthread sv;
   1287     sv.start();
   1288     psleep(1000);
   1289 
   1290     ipmessage m(ipbcast /* ipaddress(127, 0, 0, 1) */, testport);
   1291     try
   1292     {
   1293         string msg = "hello";
   1294         m.send(msg);
   1295         string rsp = m.receive(1024);
   1296         pout.putf("Client received: %s\n", pconst(rsp));
   1297     }
   1298     catch(estream* e)
   1299     {
   1300         perr.putf("Client error: %s\n", pconst(e->get_message()));
   1301         delete e;
   1302     }
   1303 }
   1304 
   1305 
   1306 //
   1307 // named pipes test
   1308 //
   1309 
   1310 
   1311 #define TEST_PIPE "ptypes.test"
   1312 
   1313 
   1314 class npthread: public thread, protected npserver
   1315 {
   1316 protected:
   1317     virtual void execute();
   1318     virtual void cleanup();
   1319 public:
   1320     npthread(): thread(false), npserver(TEST_PIPE)  {}
   1321     virtual ~npthread();
   1322 };
   1323 
   1324 
   1325 npthread::~npthread()
   1326 {
   1327     waitfor();
   1328 }
   1329 
   1330 
   1331 void npthread::execute()
   1332 {
   1333     namedpipe client;
   1334 
   1335     try
   1336     {
   1337         serve(client);
   1338         
   1339         if (client.get_active())
   1340         {
   1341             string req = lowercase(client.line());
   1342             if (req == "hello")
   1343             {
   1344                 client.putline("Hello, nice to see you!");
   1345                 client.flush();
   1346             }
   1347             
   1348             client.close();
   1349         }
   1350     }
   1351     catch(estream* e)
   1352     {
   1353         perr.putf("Pipe server error: %s\n", pconst(e->get_message()));
   1354         delete e;
   1355     }
   1356 }
   1357 
   1358 
   1359 void npthread::cleanup()
   1360 {
   1361 }
   1362 
   1363 
   1364 void pipe_test()
   1365 {
   1366     npthread server;
   1367 
   1368     pout.put("\n--- NAMED PIPES\n");
   1369     pout.put("Starting the pipe server thread...\n");
   1370     server.start();
   1371 
   1372     psleep(1000);
   1373 
   1374     namedpipe client(TEST_PIPE);
   1375 
   1376     try
   1377     {
   1378         client.open();
   1379         
   1380         pout.put("Sending a request to the server...\n");
   1381         client.putline("Hello");
   1382         client.flush();
   1383         string rsp = client.line();
   1384         pout.putf("Received: %s\n", pconst(rsp));
   1385 
   1386         client.close();
   1387     }
   1388     catch(estream* e)
   1389     {
   1390         perr.putf("Error: %s\n", pconst(e->get_message()));
   1391         delete e;
   1392     }
   1393 }
   1394 
   1395 
   1396 #endif // PTYPES_ST
   1397 
   1398 
   1399 //
   1400 // date/time/calendar
   1401 //
   1402 
   1403 
   1404 void time_test()
   1405 {
   1406     pout.put("\n--- DATE/TIME/CALENDAR\n");
   1407 
   1408     tzupdate();
   1409 
   1410     int year, month, day;
   1411     datetime d = encodedate(9999, 12, 31);
   1412     decodedate(d, year, month, day);
   1413     d = encodedate(1970, 1, 1);
   1414     decodedate(d, year, month, day);
   1415 
   1416     datetime dt;
   1417     dt = invdatetime;
   1418     int hour, min, sec, msec;
   1419     dt = encodetime(23, 59, 59, 998);
   1420     decodetime(dt, hour, min, sec, msec);
   1421 
   1422     dt = encodedate(2001, 8, 27) + encodetime(14, 33, 10);
   1423     d = encodedate(2001, 8, 28) + encodetime(14, 33, 10, 500);
   1424     dayofweek(dt);
   1425 
   1426     dt = now(false);
   1427     pout.putf("Local time: %s\n", pconst(dttostring(dt, "%x %X %Z")));
   1428     datetime utc = now();
   1429     pout.putf("UTC time:   %t GMT\n", utc);
   1430 
   1431     time_t ut;
   1432     time(&ut);
   1433     pout.putline(dttostring(utodatetime(ut), "%c"));
   1434 
   1435     int t = tzoffset();
   1436     bool neg = t < 0;
   1437     if (neg)
   1438         t = -t;
   1439     pout.putf("Time zone offset: %c%02d%02d\n", neg ? '-' : '+', t / 60, t % 60);
   1440     {
   1441         // PTypes' birthday (birth moment, if you wish)
   1442         datetime d = encodedate(2000, 3, 30) + encodetime(13, 24, 58, 995);
   1443         pout.putf("PTypes' birth moment: %T GMT\n", d);
   1444 
   1445         // now see how old is PTypes in days, hours, minutes, etc
   1446         datetime diff = now() - d;
   1447         int hours, mins, secs, msecs;
   1448         decodetime(diff, hours, mins, secs, msecs);
   1449         pout.putf("PTypes' life time: %d days %d hours %d minutes %d seconds and %d milliseconds\n",
   1450             days(diff), hours, mins, secs, msecs);
   1451 
   1452 #ifndef PTYPES_ST
   1453         // measure the difference in milliseconds between two calls to now()
   1454         datetime m = now();
   1455         psleep(17);  // sleep for 17 milliseconds
   1456         pout.putf("A 17 millisecond dream lasted actually %d milliseconds\n", int(now() - m));
   1457         // this will show the actual precision of the clock on the given platform;
   1458         // Windows, f.ex., always shows the difference in 10 msec increments
   1459 #endif
   1460     }
   1461 }
   1462 
   1463 
   1464 //
   1465 // streams documentation example #2
   1466 //
   1467 
   1468 
   1469 const cset letters("_A-Za-z");
   1470 const cset digits("0-9");
   1471 const cset identchars = letters + digits;
   1472 const cset otherchars = !letters;
   1473 
   1474 
   1475 void doc_example() 
   1476 {
   1477     tstrlist<void*> dic(SL_SORTED);
   1478 
   1479     infile f("../src/ptypes_test.cxx");
   1480 
   1481     try 
   1482     {
   1483         f.open();
   1484 
   1485         while (!f.get_eof()) 
   1486         {
   1487             char c = f.preview();
   1488 
   1489             // a C identifier starts with a letter
   1490             if (c & letters)
   1491             {
   1492                 // ... and may contain letters and digits
   1493                 string ident = f.token(identchars);
   1494                 int i;
   1495                 if (!dic.search(ident, i))
   1496                     dic.add(ident, 0);
   1497             }
   1498 
   1499             else
   1500                 f.skiptoken(otherchars);
   1501         }
   1502 
   1503     }
   1504 
   1505     catch (estream* e) 
   1506     {
   1507         pout.putf("Error: %s\n", pconst(e->get_message()));
   1508         delete e;
   1509     }
   1510 
   1511     // now print the dictionary
   1512     for (int i = 0; i < dic.get_count(); i++)
   1513         pout.putline(dic.getkey(i));
   1514 }
   1515 
   1516 
   1517 //
   1518 // variant
   1519 //
   1520 
   1521 
   1522 void variant_test()
   1523 {
   1524     pout.put("\n--- VARIANT\n");
   1525 
   1526     variant v0 = 'A';
   1527     variant v1 = short(33);
   1528     variant v2 = "456";
   1529     variant v3 = int(v1) + int(v2);
   1530     variant v4 = string(v1) + " cows";
   1531     string s = string(v4);
   1532 //    s = v4;
   1533     variant v5 = new component();
   1534     variant v6;
   1535 
   1536     put(v6, 291, v1);
   1537     put(v6, "key", v2);
   1538     put(v6, "another-key", "another-value");
   1539     showstr("33 cows", string(v4));
   1540     showint(456, v6["key"]);
   1541     showstr("33", string(v1));
   1542     showint(1, bool(v6));
   1543     v2 = aclone(v6);
   1544     v5 = v6;
   1545 
   1546     variant vi;
   1547     int i;
   1548     for (i = 0; anext(v6, i, vi);)
   1549         pout.putf("%d\n", int(vi));
   1550 
   1551     variant v7;
   1552     aadd(v7, v1);
   1553     aadd(v7, v3);
   1554     aadd(v7, v4);
   1555     adel(v7, 2);
   1556     for (i = 0; i < alength(v7); i++)
   1557         pout.putf("%s\n", pconst(string(aget(v7, i))));
   1558 }
   1559 
   1560 
   1561 //
   1562 // main
   1563 //
   1564 
   1565 
   1566 int main()
   1567 {
   1568     try
   1569     {
   1570         string_test1();
   1571         string_test2();
   1572         string_benchmarks();
   1573         cset_test();
   1574 
   1575         podlist_test();
   1576         ptrlist_test();
   1577         strlist_test();
   1578         textmap_test();
   1579 
   1580         outfile_test();
   1581         infile_test();
   1582         mem_test();
   1583         md5_test();
   1584         putf_test();
   1585 
   1586         time_test();
   1587         variant_test();
   1588 
   1589         inet_test1();
   1590 
   1591 #ifndef PTYPES_ST
   1592         pipe_test();
   1593 
   1594         jobqueue_test();
   1595         thread_test();
   1596         rwlock_test();
   1597         trigger_test();
   1598 
   1599         inet_test2();
   1600         inet_test3();
   1601 #endif
   1602 
   1603     }
   1604 
   1605     catch (estream* e) 
   1606     {
   1607         perr.putf("\nError: %s\n", pconst(e->get_message()));
   1608         exit(1);
   1609         delete e;
   1610     }
   1611 
   1612 #ifdef DEBUG
   1613     if (stralloc != 0 || objalloc != 0) 
   1614     {
   1615         perr.putf("DBG stralloc: %d, objalloc: %d\n", stralloc, objalloc);
   1616         fatal(255, "Allocation problems");
   1617     }
   1618 #endif
   1619 
   1620     return 0;
   1621 }
   1622