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