├── README.md ├── doc ├── CODING_STANDARDS ├── INSTALL ├── LICENSE ├── P0310R0.pdf ├── VIMRC ├── book.pdf └── node_alloc.pdf ├── rtcpp.hpp └── src ├── CMakeLists.txt ├── brazil_middle_point.cpp ├── config.h.in ├── ex_matrix.cpp ├── interview_bit_img.cpp ├── interview_bits.cpp ├── interview_interval_map.cpp ├── interview_logging_thread.cpp ├── interview_str_arithmetic.cpp ├── test.hpp ├── test_algorithm.cpp ├── test_align.cpp ├── test_combinatorics.cpp ├── test_matrix.cpp ├── test_sort.cpp ├── test_tree.cpp ├── tool_bench_sort.cpp └── tool_book.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Fundamental algorithms 2 | 3 | I began this project to experiment with data structures and algorithms 4 | in `C++`, as a result I ended up writing a book which is still ongoig 5 | work. You can find it in doc/book.pdf or [Fundamental Algorithms](https://github.com/mzimbres/rtcpp/blob/a9634ab4fa3076d2ebfc4e34c22b324af5f99b16/doc/book.pdf) 6 | 7 | Another topic that I touched is memory allocation in `C++`. Most 8 | specifically how to improve allocation performance for node based 9 | containers. The proposal can be found at [Splitting node and array allocations in allocators](http://open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0310r0.pdf) 10 | Slides are also available in doc/p0310r0.pdf or [here](https://github.com/mzimbres/rtcpp/blob/a9634ab4fa3076d2ebfc4e34c22b324af5f99b16/doc/P0310R0.pdf) 11 | 12 | # Samples 13 | 14 | Implementation of some algorithms found in the book. 15 | 16 | ## Binary search tree 17 | 18 | Assume a node in the form 19 | 20 | ```cpp 21 | struct bst_node { 22 | int info; 23 | bst_node* left; 24 | bst_node* right; 25 | }; 26 | ``` 27 | 28 | ### Insertion 29 | 30 | ```cpp 31 | void bst_insert(bst_node& head, int key) 32 | { 33 | if (!head.left) { 34 | head.left = new bst_node {key, nullptr, nullptr}; 35 | return; 36 | } 37 | 38 | auto* p = head.left; 39 | while (p) { 40 | if (key < p->info) { 41 | if (!p->left) { 42 | p->left = new bst_node {key, nullptr, nullptr}; 43 | return; 44 | } 45 | p = p->left; 46 | } else if (p->info < key) { 47 | if (!p->right) { 48 | p->right = new bst_node {key, nullptr, nullptr}; 49 | return; 50 | } 51 | p = p->right; 52 | } else { 53 | return; 54 | } 55 | } 56 | } 57 | ``` 58 | 59 | ### Pre-order traversal (recursive) 60 | 61 | ```cpp 62 | void preorder_recursive(bst_node* p) 63 | { 64 | if (!p) 65 | return; 66 | 67 | visit(p); 68 | preorder_recursive(p->left); 69 | preorder_recursive(p->right); 70 | } 71 | 72 | ``` 73 | 74 | ### Pre-order traversal (iterative) 75 | 76 | ```cpp 77 | void preorder_traversal(const bst_node* p) 78 | { 79 | std::stack s; 80 | while (p) { 81 | visit(p); 82 | if (p->right) 83 | s.push(p->right); 84 | 85 | p = p->left; 86 | if (!p && !s.empty()) { 87 | p = s.top(); 88 | s.pop(); 89 | } 90 | } 91 | } 92 | ``` 93 | 94 | ### In-order traversal (recursive) 95 | 96 | ```cpp 97 | void inorder_recursive(bst_node* p) 98 | { 99 | if (!p) 100 | return; 101 | 102 | inorder_recursive(p->left); 103 | visit(p); 104 | inorder_recursive(p->right); 105 | } 106 | ``` 107 | 108 | ### In-order traversal (iterative) 109 | 110 | ```cpp 111 | void inorder_traversal(const bst_node* p) 112 | { 113 | std::stack s; 114 | for (;;) { 115 | while (p) { 116 | s.push(p); 117 | p = p->left; 118 | } 119 | if (s.empty()) 120 | return; 121 | p = s.top(); 122 | s.pop(); 123 | visit(p); 124 | p = p->right; 125 | } 126 | } 127 | ``` 128 | 129 | ### Post-order traversal (recursive) 130 | 131 | ```cpp 132 | void postorder_recursive(bst_node* p) 133 | { 134 | if (!p) 135 | return; 136 | 137 | postorder_recursive(p->left); 138 | postorder_recursive(p->right); 139 | visit(p); 140 | } 141 | ``` 142 | 143 | ### Post-order traversal (iterative) 144 | 145 | ```cpp 146 | void postorder_traversal(const bst_node* p) 147 | { 148 | std::stack s; 149 | const bst_node* q = nullptr; 150 | for (;;) { 151 | while (p) { 152 | s.push(p); 153 | p = p->left; 154 | } 155 | 156 | for (;;) { 157 | if (s.empty()) 158 | return; 159 | 160 | p = s.top(); 161 | s.pop(); 162 | 163 | if (!p->right || p->right == q) { 164 | visit(p); 165 | q = p; 166 | continue; 167 | } 168 | s.push(p); 169 | p = p->right; 170 | break; 171 | } 172 | } 173 | } 174 | ``` 175 | 176 | ### Copy 177 | 178 | Copies a binary search tree to another location 179 | 180 | ```cpp 181 | void copy(bst_node* from, bst_node* to) 182 | { 183 | preorder_successor p(from); 184 | preorder_successor q(to); 185 | 186 | for (;;) { 187 | if (p.p->left) 188 | q.p->left = new bst_node {{}, nullptr, nullptr}; 189 | 190 | p.next(); 191 | q.next(); 192 | 193 | if (p.p == from) 194 | return; 195 | 196 | if (p.p->right) 197 | q.p->right = new bst_node {{}, nullptr, nullptr}; 198 | 199 | q.p->info = p.p->info; 200 | } 201 | } 202 | ``` 203 | 204 | ## Searching 205 | 206 | Some searching algorithms. 207 | 208 | ### Binary search (recursive) 209 | 210 | ```cpp 211 | template 212 | bool binary_search_recursive(Iter begin, Iter end, const T& K) 213 | { 214 | if (begin == end) 215 | return false; 216 | 217 | auto mid = (end - begin) / 2; 218 | if (K < begin[mid]) 219 | return binary_search_recursive(begin, begin + mid, K); 220 | else if (begin[mid] < K) 221 | return binary_search_recursive(begin + mid + 1, end, K); 222 | else 223 | return true; 224 | } 225 | ``` 226 | 227 | ### Binary search 228 | 229 | ```cpp 230 | template 231 | bool binary_search(Iter begin, Iter end, const T& K) 232 | { 233 | if (begin == end) 234 | return false; 235 | 236 | auto low = 0; 237 | auto high = end - begin - 1; 238 | 239 | while (low <= high) { 240 | auto mid = (low + high) / 2; 241 | if (K < begin[mid]) 242 | high = mid - 1; 243 | else if (begin[mid] < K) 244 | low = mid + 1; 245 | else 246 | return true; 247 | } 248 | return false; 249 | } 250 | ``` 251 | 252 | ### Binary search (STL) 253 | 254 | In the STL the binary search requires only forward iterator so the 255 | implementation above has to be changed. 256 | 257 | ```cpp 258 | template 259 | bool binary_search_stl(Iter begin, Iter end, const T& K) 260 | { 261 | auto l = std::distance(begin, end); 262 | 263 | while (l > 0) { 264 | auto half = l / 2; 265 | auto mid = begin; 266 | std::advance(mid, half); 267 | 268 | if (K < *mid) { 269 | l = half; 270 | } else if (*mid < K) { 271 | begin = mid; 272 | ++begin; 273 | l = l - half - 1; 274 | } else { 275 | return true; 276 | } 277 | } 278 | return false; 279 | } 280 | ``` 281 | 282 | ### Binary search (rotated) 283 | 284 | This algorithm is sometimes asked in interview questions 285 | 286 | ```cpp 287 | template 288 | bool binary_search_rotated(Iter begin, Iter end, const T& K) 289 | { 290 | auto is_sorted = [&](auto a, auto b) 291 | { return !(begin[b - 1] < begin[a]); }; 292 | 293 | auto in_range = [&](auto a, auto b) 294 | { return !(K < begin[a] || begin[b - 1] < K); }; 295 | 296 | auto low = 0; 297 | auto high = end - begin; 298 | while (low < high) { 299 | auto mid = (low + high) / 2; 300 | if (is_sorted(mid, high)) { 301 | if (in_range(mid, high)) 302 | return rt::binary_search(begin + mid, begin + high, K); 303 | high = mid; 304 | } else { 305 | if (in_range(low, mid)) 306 | return rt::binary_search(begin + low, begin + mid, K); 307 | low = mid; 308 | } 309 | } 310 | return false; 311 | } 312 | ``` 313 | 314 | ## Combinatorics 315 | 316 | Some combinatorics algorithms. 317 | 318 | ### Next tuple 319 | 320 | Calculates the next tuple based on the current one. The first element 321 | in the array is used for convenience and does not belong in the tuple. 322 | Minimum and maximum values for each element in the tuple are passed in 323 | paramenter min and max. 324 | 325 | ```cpp 326 | template 327 | auto next_tuple(Iter begin, Iter end, Iter min, Iter max) 328 | { 329 | auto j = end - begin - 1; 330 | while (begin[j] == max[j]) { 331 | begin[j] = min[j]; 332 | --j; 333 | } 334 | ++begin[j]; 335 | 336 | return j != 0; 337 | } 338 | ``` 339 | 340 | Example usage 341 | 342 | ```cpp 343 | void all_tuples() 344 | { 345 | std::vector min {0, 1, 1, 1}; 346 | std::vector max {min[0] + 1, 3, 2, 3}; 347 | auto arr = min; 348 | 349 | do { 350 | visit(arr); 351 | } while (next_tuple( std::begin(arr), std::end(arr) 352 | , std::begin(min), std::begin(max))); 353 | } 354 | ``` 355 | 356 | ### Next tuple (STL) 357 | 358 | An implementation that is suitable for the STL can be seen below 359 | 360 | ```cpp 361 | template 362 | auto next_tuple(Iter begin, Iter end, Iter min, Iter max) 363 | { 364 | auto j = end - begin - 1; 365 | while (begin[j] == max[j]) { 366 | begin[j] = min[j]; 367 | --j; 368 | } 369 | ++begin[j]; 370 | 371 | return j != 0; 372 | } 373 | ``` 374 | 375 | ### Next combination 376 | 377 | ```cpp 378 | auto next_combination(std::vector& v) 379 | { 380 | int t = v.size() - 2; 381 | auto i = 0; 382 | while ((v[i] + 1) == v[i + 1]) { 383 | v[i] = i; 384 | ++i; 385 | } 386 | if (i == t) return false; 387 | 388 | ++v[i]; 389 | return true; 390 | } 391 | ``` 392 | 393 | Example usage 394 | 395 | ```cpp 396 | void all_combinations() 397 | { 398 | int n = 5; 399 | std::vector v {0, 1, 2, n, 0}; 400 | 401 | do { 402 | visit_combination(v); 403 | } while (next_combination(v)); 404 | } 405 | ``` 406 | ### Permutations 407 | 408 | Some algorithms that deal with permutations 409 | 410 | #### Next permutation 411 | 412 | ```cpp 413 | template 414 | bool next_permutation(Iter begin, Iter end) 415 | { 416 | auto b = end; 417 | auto a = std::prev(b); 418 | 419 | while (!(*--a < *--b)); 420 | 421 | if (a == begin) { 422 | std::reverse(++a, end); 423 | return false; 424 | } 425 | 426 | b = end; 427 | while (!(*a < *--b)); 428 | 429 | std::iter_swap(a, b); 430 | 431 | std::reverse(++a, end); 432 | 433 | return true; 434 | } 435 | ``` 436 | 437 | Example usage 438 | 439 | ```cpp 440 | void all_permutations() 441 | { 442 | std::vector v{0, 1, 2, 3, 4}; 443 | do { 444 | visit_permutation(v); 445 | } while (rt::next_permutation(std::begin(v), std::end(v))); 446 | } 447 | ``` 448 | 449 | #### Permute 450 | 451 | ```cpp 452 | template 453 | void permute(Iter begin, Iter end, Iter perm) 454 | { 455 | auto n = end - begin; 456 | for (auto i = 0; i < n; ++i) { 457 | if (perm[i] != i) { 458 | auto t = begin[i]; 459 | auto j = i; 460 | do { 461 | auto k = perm[j]; 462 | begin[j] = begin[k]; 463 | perm[j] = j; 464 | j = k; 465 | } while (perm[j] != i); 466 | begin[j] = t; 467 | perm[j] = j; 468 | } 469 | } 470 | } 471 | ``` 472 | 473 | #### Unpermute 474 | 475 | ```cpp 476 | template 477 | void unpermute(Iter begin, Iter end, Iter table) 478 | { 479 | auto n = end - begin; 480 | for (auto i = 0; i < n; ++i) { 481 | while (table[i] != i) { 482 | std::swap(begin[i], begin[table[i]]); 483 | std::swap(table[i], table[table[i]]); 484 | } 485 | } 486 | } 487 | ``` 488 | 489 | #### Unpermute (on the fly) 490 | 491 | ```cpp 492 | 493 | const auto index = [=](auto i) 494 | { return c - 1 - (i % c) + c * (i / c); }; 495 | 496 | template 497 | void unpermute_on_the_fly(Iter begin, Iter end, Index index) 498 | { 499 | const auto n = end - begin; 500 | for (auto i = 0; i < n; ++i) { 501 | auto k = index(i); 502 | while (k > i) 503 | k = index(k); 504 | if (k == i) { 505 | k = index(i); 506 | while (k != i) { 507 | std::swap(begin[i], begin[k]); 508 | k = index(k); 509 | } 510 | } 511 | } 512 | } 513 | ``` 514 | 515 | #### Unpermute (on the fly with bit) 516 | 517 | ```cpp 518 | constexpr auto bit = 1 << 30; 519 | auto set_bit = [=](auto& o) {o |= bit;}; 520 | auto unset_bit = [=](auto& o) {o &= ~bit;}; 521 | auto is_set = [=](auto& o) {return o & bit;}; 522 | 523 | template 524 | void unpermute_on_the_fly_bit(Iter begin, Iter end) 525 | { 526 | const auto n = end - begin; 527 | for (auto i = 0; i < n; ++i) { 528 | auto k = index(i); 529 | if (!is_set(begin[i])) { 530 | while (k != i) { 531 | std::swap(begin[i], begin[k]); 532 | set_bit(begin[k]); 533 | k = index(k); 534 | } 535 | } 536 | unset_bit(begin[i]); 537 | } 538 | } 539 | ``` 540 | 541 | #### Random permutation 542 | 543 | Generates a random permutation with elements in the range [1, n]. 544 | 545 | ```cpp 546 | template 547 | auto random_permutation(int n, Rand& rand) 548 | { 549 | std::vector ret(n); 550 | for (auto j = 0; j < n; ++j) { 551 | auto k = static_cast((j + 1) * rand()); 552 | ret[j] = ret[k]; 553 | ret[k] = j + 1; 554 | } 555 | 556 | return ret; 557 | } 558 | ``` 559 | 560 | #### Shuffle 561 | 562 | Shuffles the input array. Expects a parameter rand that produces 563 | random numbers uniformily distributed in the interval [0, 1). 564 | 565 | ```cpp 566 | template 567 | void shuffle(std::vector& v, Rand& rand) 568 | { 569 | auto j = v.size(); 570 | do { 571 | auto k = static_cast(j * rand()); 572 | std::swap(v[k], v[--j]); 573 | } while (j != 0); 574 | } 575 | ``` 576 | 577 | ### Partition 578 | 579 | The algorithm to calculate the next partition can be found in the 580 | source code, here I will show how to calculate them in a loop 581 | 582 | ```cpp 583 | void all_partitions_loop(int n) 584 | { 585 | std::vector a(n + 1, 1); 586 | a[0] = 0; 587 | 588 | int m = 1; 589 | for (;;) { 590 | a[m] = n; 591 | int q = m - (n == 1 ? 1 : 0); 592 | 593 | for (;;) { 594 | visit_partition(a, m); 595 | if (a[q] != 2) break; 596 | a[q--] = 1; 597 | ++m; 598 | } 599 | 600 | if (q == 0) return; 601 | 602 | int x = a[q] - 1; 603 | a[q] = x; 604 | n = m - q + 1; 605 | m = q + 1; 606 | 607 | while (x < n) { 608 | a[m++] = x; 609 | n -= x; 610 | } 611 | } 612 | } 613 | ``` 614 | 615 | ## Sort 616 | 617 | Some elementary sorting algorithms 618 | 619 | ## Bubble sort 620 | 621 | ```cpp 622 | template 623 | void bubble_sort(Iter begin, Iter end) 624 | { 625 | if (begin == end) return; 626 | 627 | auto B = end - begin - 1; 628 | while (B != 0) { 629 | auto t = 0; 630 | for (auto j = 0; j < B; ++j) { 631 | if (begin[j] > begin[j + 1]) { 632 | std::swap(begin[j], begin[j + 1]); 633 | t = j + 1; 634 | } 635 | } 636 | B = t; 637 | } 638 | } 639 | ``` 640 | 641 | #### Comparison counting sort 642 | 643 | ```cpp 644 | template 645 | auto calc_address_table(Iter begin, Iter end) 646 | { 647 | const auto n = end - begin; 648 | std::vector count(n, 0); 649 | 650 | for (auto i = 1; i < n; ++i) 651 | for (auto j = 0; j < i; ++j) 652 | if (begin[i] < begin[j]) 653 | ++count[j]; 654 | else 655 | ++count[i]; 656 | 657 | return count; 658 | } 659 | 660 | template 661 | void comparison_counting_sort(Iter begin, Iter end) 662 | { 663 | auto n = end - begin; 664 | auto count = calc_address_table(begin, end); 665 | 666 | std::vector tmp(n, 0); 667 | for (auto i = 0; i < n; ++i) 668 | tmp[count[i]] = begin[i]; 669 | 670 | std::copy(std::begin(tmp), std::end(tmp), begin); 671 | } 672 | ``` 673 | 674 | #### Comparison counting sort (inplace) 675 | 676 | ```cpp 677 | template 678 | void inplace_comparison_counting_sort(Iter begin, Iter end) 679 | { 680 | auto table = calc_address_table(begin, end); 681 | unpermute(begin, end, std::begin(table)); 682 | } 683 | ``` 684 | 685 | #### Distribution counting sort 686 | 687 | ```cpp 688 | template 689 | void dist_counting_sort(Iter begin, Iter end, int min, int max) 690 | { 691 | auto n = end - begin; 692 | auto m = max - min + 1; 693 | 694 | std::vector count(m, 0); 695 | for (auto i = 0; i < n; ++i) 696 | ++count[begin[i] - min]; 697 | 698 | for (auto i = 1; i < m; ++i) 699 | count[i] += count[i - 1]; 700 | 701 | std::vector out(n, 0); 702 | for (auto i = 0; i < n; ++i) 703 | out[--count[begin[i] - min]] = begin[i]; 704 | 705 | std::copy(std::begin(out), std::end(out), begin); 706 | } 707 | ``` 708 | 709 | #### Straight insertion sort 710 | 711 | ```cpp 712 | template 713 | void straight_insertion(Iter begin, Iter end) 714 | { 715 | if (begin == end) return; 716 | 717 | auto N = end - begin; 718 | for (auto j = 1; j < N; ++j) { 719 | auto i = j - 1; 720 | auto k = begin[j]; 721 | while (k < begin[i]) { 722 | begin[i + 1] = begin[i]; 723 | if (--i < 0) break; 724 | } 725 | 726 | begin[i + 1] = k; 727 | } 728 | } 729 | ``` 730 | 731 | #### Binary insertion sort 732 | 733 | ```cpp 734 | template 735 | void binary_insertion(Iter begin, Iter end) 736 | { 737 | for (auto pos = begin; pos != end; ++pos) 738 | std::rotate( std::upper_bound(begin, pos, *pos) 739 | , pos 740 | , std::next(pos)); 741 | } 742 | ``` 743 | 744 | ## Interview questions 745 | 746 | ### Inverval map 747 | 748 | This data structure came up in an interview 749 | 750 | ```cpp 751 | template 752 | struct interval_map { 753 | std::map map; 754 | interval_map(V v = {}) : map({{std::numeric_limits::min(), v}}) {} 755 | 756 | void assign(const K& a, const K& b, const V& v) 757 | { 758 | auto comp = map.key_comp(); 759 | 760 | if (!comp(a, b)) 761 | return; 762 | 763 | auto lbb = map.lower_bound(b); 764 | auto vb = lbb == std::end(map) ? map.rbegin()->second 765 | : comp(b, lbb->first) ? std::prev(lbb)->second 766 | : lbb->second; 767 | 768 | if (v == vb) 769 | return; 770 | 771 | auto lba = map.lower_bound(a); 772 | auto va = lba == std::end(map) ? map.rbegin()->second 773 | : lba == std::begin(map) ? lba->second 774 | : std::prev(lba)->second; 775 | 776 | if (v == va && lba != std::begin(map)) 777 | return; 778 | 779 | map.erase( std::next(map.insert_or_assign(lba, a, v)) 780 | , map.insert_or_assign(lbb, b, vb)); 781 | } 782 | 783 | const V& operator[](K const& key) const 784 | { return (--map.upper_bound(key))->second; } 785 | }; 786 | ``` 787 | 788 | -------------------------------------------------------------------------------- /doc/CODING_STANDARDS: -------------------------------------------------------------------------------- 1 | 2 | Some motivation for the coding standards 3 | 4 | Simplicity 5 | ====================================================================== 6 | 7 | * Simplicity is the ultimate sophistication. 8 | (Leonardo da Vinci) 9 | 10 | * Simplicity is prerequisite for reliability. 11 | (Dijkstra) 12 | 13 | * The unavoidable price of reliability is simplicity. 14 | (Hoare) 15 | 16 | * The computing scientist’s main challenge is not to get 17 | confused by the complexities of his own making. 18 | (Dijkstra) 19 | 20 | * Controlling complexity is the essence of computer 21 | programming. 22 | (Brian Kernighan) 23 | 24 | * The central enemy of reliability is complexity. 25 | (Geer et al.) 26 | 27 | * Simplicity carried to the extreme becomes elegance. 28 | (Jon Franklin) 29 | 30 | * Complexity has nothing to do with intelligence, simplicity 31 | does. 32 | (Larry Bossidy) 33 | 34 | * Increasingly, people seem to misinterpret complexity as 35 | sophistication, which is baffling — the incomprehensible should 36 | cause suspicion rather than admiration. 37 | (Niklaus Wirth) 38 | 39 | Object oientation 40 | ====================================================================== 41 | 42 | * Object-oriented design is the roman numerals of computing. 43 | (Rob Pike) 44 | 45 | * Object-oriented programming is an exceptionally bad idea which could 46 | only have originated in California. 47 | (Edsger Dijkstra) 48 | 49 | * The phrase "object-oriented” means a lot of things. Half are 50 | obvious, and the other half are mistakes. 51 | (Paul Graham) 52 | 53 | * Sometimes, the elegant implementation is just a function. Not a 54 | method. Not a class. Not a framework. Just a function. 55 | (John Carmack) 56 | 57 | * And, at least in it’s most popular forms, it can be extremely 58 | harmful and dramatically increase complexity. 59 | 60 | * State is the root of all evil. In particular functions with side 61 | effects should be avoided. 62 | (Joe Armstrong) 63 | 64 | * The object-oriented model makes it easy to build up programs 65 | by accretion. What this often means, in practice, is that it 66 | provides a structured way to write spaghetti code. 67 | (Paul Graham) 68 | 69 | * I will, in fact, claim that the difference between a bad 70 | programmer and a good one is whether he considers his code or 71 | his data structures more important. Bad programmers worry about 72 | the code. Good programmers worry about data structures and 73 | their relationships. 74 | (Linus Torvalds) 75 | 76 | Coding Standards 77 | ====================================================================== 78 | 79 | * Use spaces for indentation. Tabs are not allowed. 80 | * Do not end a line with spaces. 81 | * Limit line length to 79 characters. 82 | * Use standard c++ naming convention. 83 | * Keep names short. 84 | * Write stateless code as much as possible. 85 | * Use unsigned types ONLY for bitwise operations. 86 | * Again, avoid unsigned. 87 | 88 | Some further cosmetic guidelines 89 | 90 | Classes 91 | ====================================================================== 92 | 93 | Braces 94 | 95 | class foo { // Open braces in the same line you declare the class. 96 | ... 97 | }; 98 | 99 | class foo { 100 | private: // put the private here, do not omit it. 101 | int a; 102 | }; 103 | 104 | Initializer list. 105 | ====================================================================== 106 | 107 | - Indentation is done this way: 108 | 109 | foo::foo(int a, int b, int c) 110 | : data1(a) 111 | , data1(b) 112 | , data2(c) 113 | {} 114 | 115 | Functions 116 | ====================================================================== 117 | 118 | Different from classes, we do not open braces in the same line. 119 | 120 | void function() 121 | { 122 | // code 123 | } 124 | 125 | There is no space between function names and (): 126 | 127 | function(); // <=== rigth 128 | function (); // <=== wrong 129 | 130 | Mind the spaces between arguments 131 | 132 | foo(a, b, c, e); // Right. 133 | foo(a,b,c,e); // Wrong. 134 | 135 | The same reasoning applies to templates 136 | 137 | std::pair foo; // Right. 138 | std::pair foo; // Wrong. 139 | 140 | if - else 141 | ====================================================================== 142 | 143 | One line if's do not get braces: 144 | 145 | if (condition) 146 | do_something(); 147 | else 148 | another_thing(); 149 | 150 | There is a space between if and (): 151 | 152 | if (condition) // right 153 | if(condition) // wrong 154 | 155 | Return as early as possible from a function. 156 | 157 | void foo() 158 | { 159 | if (ready1) 160 | return; 161 | 162 | if (ready2) 163 | return; 164 | 165 | // Do further stuff. 166 | } 167 | 168 | for, while, do - while 169 | ====================================================================== 170 | 171 | for (condition) // right 172 | for(condition) // wrong 173 | 174 | for (condition) { // right 175 | } 176 | 177 | for (condition) // wrong 178 | { 179 | } 180 | 181 | The same reasoning above applies for while loops. If you need an 182 | infinite loop, use 183 | 184 | for (;;) { // right 185 | } 186 | 187 | while (1) { // wrong 188 | } 189 | 190 | Pointers 191 | ====================================================================== 192 | 193 | int* a = nullptr; 194 | 195 | if (!a) // right 196 | 197 | if (a == nullptr) // wrong 198 | 199 | if (a == NULL) // wrong 200 | 201 | But if a is not a pointer or a boolean variable prefer 202 | 203 | if (a == value) // It makes sense for the reader to know the value. 204 | 205 | Equations: 206 | ====================================================================== 207 | 208 | Use space with "*" "/" etc: 209 | 210 | const double a = b * c / std::pow(d, e); // Right 211 | const double a = b*c/std::pow(d,e); // Wrong 212 | 213 | From the kernel coding style 214 | ====================================================================== 215 | 216 | Encoding the type of a function into the name (so-called Hungarian 217 | notation) is brain damaged - the compiler knows the types anyway and 218 | can check those, and it only confuses the programmer. 219 | 220 | LOCAL variable names should be short, and to the point. If you have 221 | some random integer loop counter, it should probably be called "i". 222 | Calling it "loop_counter" is non-productive, if there is no chance 223 | of it being mis-understood. Similarly, "tmp" can be just about any 224 | type of variable that is used to hold a temporary value. 225 | 226 | From fftw coding style: 227 | ====================================================================== 228 | 229 | " NAMES: keep them short. Shorter than you think. The Bible was 230 | written without vowels. Don't outsmart the Bible. 231 | 232 | Getters and Setters: 233 | ====================================================================== 234 | 235 | Getters and setters are sometimes a (big) waste of time and can also 236 | hide bad program design. For example: 237 | 238 | class foo { 239 | private: 240 | int m_a; 241 | public: 242 | void set(int a) {m_a = a;} 243 | int get() const {return m_a;} 244 | }; 245 | 246 | is generaly not better than 247 | 248 | struct foo { 249 | int a; 250 | }; 251 | 252 | The advantages of the later are: 253 | 1 - It uses 3 lines of code instead of 7. 254 | 2 - It does not pretend variable a is encapsulated. 255 | 256 | Now some people would argue that it is easier to add code to check 257 | inside setter, but fail to say that such changes can break the 258 | contract assumed by the programmer when he used it and the code has to 259 | be reviewed anyway. The lesson is to make variables private if they 260 | are really encapsulated. Otherwise, make it public and evolve the 261 | design. 262 | 263 | -------------------------------------------------------------------------------- /doc/INSTALL: -------------------------------------------------------------------------------- 1 | Building 2 | ============================ 3 | 4 | $ cmake YOUR_PATH_TO/rtcpp/src \ 5 | -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror -std=c++17" \ 6 | -DCMAKE_BUILD_TYPE=Debug \ 7 | -DCMAKE_EXE_LINKER_FLAGS="-pthread" 8 | $ make 9 | $ make test 10 | 11 | If you are on windows and there is no "make" so you can use 12 | 13 | $ cmake --build . # Build all targets 14 | $ cmake --build . --target foo # Build a specific target. 15 | 16 | To generate the dependency graph: 17 | 18 | $ cmake --graphviz=foo.graph ${RTCPP_SOURCE} 19 | $ dot -Tpng foo.graph.foo > fig.png 20 | 21 | I have tested this software with GCC 4.7, 5.0 and 6.0, Clang 3.4 22 | and 3.8 (libstd++) and VS2015. Please let me know if you failed 23 | to build this project. 24 | 25 | -------------------------------------------------------------------------------- /doc/LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . -------------------------------------------------------------------------------- /doc/P0310R0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimbres/rtcpp/3012daa86f7ebdce0b30c50c2f9fb25fe2ef4472/doc/P0310R0.pdf -------------------------------------------------------------------------------- /doc/VIMRC: -------------------------------------------------------------------------------- 1 | imap jj 2 | syntax on 3 | set autoindent 4 | set shiftwidth=2 5 | set ignorecase 6 | set expandtab 7 | set noswapfile 8 | nnoremap :buffers:buffer 9 | set hidden 10 | set smartindent 11 | map :Explore 12 | map :split 13 | map :vsplit 14 | map :w 15 | map :nohlsearch 16 | map :make 17 | "map :bprevious 18 | "map :bnext 19 | set foldmethod=marker 20 | set hlsearch 21 | set nowrap 22 | 23 | "compiler msvc 24 | "set makeprg=cmake\ --build\ . 25 | "nmap :set invnumber 26 | 27 | set path=.,**,, 28 | " start of line 29 | :cnoremap 30 | " back one character 31 | :cnoremap 32 | " delete character under cursor 33 | :cnoremap 34 | " end of line 35 | :cnoremap 36 | " forward one character 37 | :cnoremap 38 | " recall newer command-line 39 | :cnoremap 40 | " recall previous (older) command-line 41 | :cnoremap 42 | " back one word 43 | :cnoremap 44 | " forward one word 45 | :cnoremap 46 | 47 | 48 | -------------------------------------------------------------------------------- /doc/book.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimbres/rtcpp/3012daa86f7ebdce0b30c50c2f9fb25fe2ef4472/doc/book.pdf -------------------------------------------------------------------------------- /doc/node_alloc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimbres/rtcpp/3012daa86f7ebdce0b30c50c2f9fb25fe2ef4472/doc/node_alloc.pdf -------------------------------------------------------------------------------- /rtcpp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace rt 20 | { 21 | 22 | template 23 | void reverse(Iter begin, Iter end) noexcept 24 | { 25 | auto i = 0; 26 | auto j = end - begin; 27 | while (i < --j) 28 | std::swap(begin[i++], begin[j]); 29 | } 30 | 31 | template 32 | auto max_element(Iter begin, Iter end) 33 | { 34 | if (begin == end) 35 | return end; 36 | 37 | auto max = begin; 38 | while (++begin != end) 39 | if (*max < *begin) 40 | max = begin; 41 | 42 | return max; 43 | } 44 | 45 | template 46 | auto min_element(Iter begin, Iter end) 47 | { 48 | if (begin == end) 49 | return end; 50 | 51 | auto min = begin; 52 | while (++begin != end) 53 | if (*begin < *min) 54 | min = begin; 55 | 56 | return min; 57 | } 58 | 59 | struct bst_node { 60 | int info; 61 | bst_node* left; 62 | bst_node* right; 63 | }; 64 | 65 | void visit(bst_node const* p) 66 | { 67 | std::cout << p->info << "\n"; 68 | } 69 | 70 | //______________________________________________________ 71 | inline 72 | void bst_insert(bst_node& head, int key) 73 | { 74 | if (!head.left) { 75 | head.left = new bst_node {key, nullptr, nullptr}; 76 | return; 77 | } 78 | 79 | auto* p = head.left; 80 | while (p) { 81 | if (key < p->info) { 82 | if (!p->left) { 83 | p->left = new bst_node {key, nullptr, nullptr}; 84 | return; 85 | } 86 | p = p->left; 87 | } else if (p->info < key) { 88 | if (!p->right) { 89 | p->right = new bst_node {key, nullptr, nullptr}; 90 | return; 91 | } 92 | p = p->right; 93 | } else { 94 | return; 95 | } 96 | } 97 | } 98 | 99 | //______________________________________________________ 100 | inline 101 | void bst_insertion_sort_impl(bst_node& head, int key) 102 | { 103 | if (!head.left) { 104 | head.left = new bst_node {key, nullptr, nullptr}; 105 | return; 106 | } 107 | 108 | auto* p = head.left; 109 | while (p) { 110 | if (key < p->info) { 111 | if (!p->left) { 112 | p->left = new bst_node {key, nullptr, nullptr}; 113 | return; 114 | } 115 | p = p->left; 116 | } else { 117 | if (!p->right) { 118 | p->right = new bst_node {key, nullptr, nullptr}; 119 | return; 120 | } 121 | p = p->right; 122 | } 123 | } 124 | } 125 | 126 | //______________________________________________________ 127 | void preorder_recursive(bst_node* p) 128 | { 129 | if (!p) 130 | return; 131 | 132 | visit(p); 133 | preorder_recursive(p->left); 134 | preorder_recursive(p->right); 135 | } 136 | 137 | void preorder_traversal(const bst_node* p) 138 | { 139 | std::stack s; 140 | while (p) { 141 | visit(p); 142 | if (p->right) 143 | s.push(p->right); 144 | 145 | p = p->left; 146 | if (!p && !s.empty()) { 147 | p = s.top(); 148 | s.pop(); 149 | } 150 | } 151 | } 152 | 153 | struct preorder_successor { 154 | std::stack s; 155 | bst_node* p; 156 | void next() 157 | { 158 | if (p->right) 159 | s.push(p->right); 160 | 161 | p = p->left; 162 | if (!p && !s.empty()) { 163 | p = s.top(); 164 | s.pop(); 165 | } 166 | } 167 | preorder_successor(bst_node* root) : p(root) {} 168 | }; 169 | 170 | void preorder_traversal2(bst_node* root) 171 | { 172 | preorder_successor obj(root); 173 | while (obj.p) { 174 | visit(obj.p); 175 | obj.next(); 176 | } 177 | } 178 | 179 | template 180 | class bst_iter { 181 | private: 182 | Successor s; 183 | public: 184 | using value_type = int; 185 | using pointer = bst_node*; 186 | using reference = bst_node&; 187 | using difference_type = std::ptrdiff_t; 188 | using iterator_category = std::forward_iterator_tag; 189 | bst_iter(bst_node* root = nullptr) noexcept 190 | : s(root) {} 191 | auto& operator++() noexcept { s.next(); return *this; } 192 | auto operator++(int) noexcept 193 | { auto tmp(*this); operator++(); return tmp; } 194 | 195 | const auto& operator*() const noexcept {return s.p->info;} 196 | friend auto operator==( const bst_iter& rhs 197 | , const bst_iter& lhs) noexcept 198 | { return lhs.s.p == rhs.s.p; } 199 | friend auto operator!=( const bst_iter& rhs 200 | , const bst_iter& lhs) noexcept 201 | { return !(lhs == rhs); } 202 | }; 203 | 204 | void copy(bst_node* from, bst_node* to) 205 | { 206 | preorder_successor p(from); 207 | preorder_successor q(to); 208 | 209 | for (;;) { 210 | if (p.p->left) 211 | q.p->left = new bst_node {{}, nullptr, nullptr}; 212 | 213 | p.next(); 214 | q.next(); 215 | 216 | if (p.p == from) 217 | return; 218 | 219 | if (p.p->right) 220 | q.p->right = new bst_node {{}, nullptr, nullptr}; 221 | 222 | q.p->info = p.p->info; 223 | } 224 | } 225 | 226 | //______________________________________________________ 227 | void inorder_recursive(bst_node* p) 228 | { 229 | if (!p) 230 | return; 231 | 232 | inorder_recursive(p->left); 233 | visit(p); 234 | inorder_recursive(p->right); 235 | } 236 | 237 | void inorder_traversal(const bst_node* p) 238 | { 239 | std::stack s; 240 | for (;;) { 241 | while (p) { 242 | s.push(p); 243 | p = p->left; 244 | } 245 | if (s.empty()) 246 | return; 247 | p = s.top(); 248 | s.pop(); 249 | visit(p); 250 | p = p->right; 251 | } 252 | } 253 | 254 | struct inorder_successor { 255 | std::stack s; 256 | const bst_node* p; 257 | void left_most() 258 | { 259 | while (p) { 260 | s.push(p); 261 | p = p->left; 262 | } 263 | if (s.empty()) 264 | return; 265 | 266 | p = s.top(); 267 | s.pop(); 268 | } 269 | void next() 270 | { 271 | p = p->right; 272 | left_most(); 273 | } 274 | inorder_successor(const bst_node* root) 275 | : p(root) {left_most();} 276 | }; 277 | 278 | void inorder_traversal2(const bst_node* root) 279 | { 280 | inorder_successor obj(root); 281 | while (obj.p) { 282 | visit(obj.p); 283 | obj.next(); 284 | } 285 | } 286 | 287 | //______________________________________________________ 288 | 289 | void postorder_recursive(bst_node* p) 290 | { 291 | if (!p) 292 | return; 293 | 294 | postorder_recursive(p->left); 295 | postorder_recursive(p->right); 296 | visit(p); 297 | } 298 | 299 | void postorder_traversal(const bst_node* p) 300 | { 301 | std::stack s; 302 | const bst_node* q = nullptr; 303 | for (;;) { 304 | while (p) { 305 | s.push(p); 306 | p = p->left; 307 | } 308 | 309 | for (;;) { 310 | if (s.empty()) 311 | return; 312 | 313 | p = s.top(); 314 | s.pop(); 315 | 316 | if (!p->right || p->right == q) { 317 | visit(p); 318 | q = p; 319 | continue; 320 | } 321 | s.push(p); 322 | p = p->right; 323 | break; 324 | } 325 | } 326 | } 327 | 328 | template 329 | auto find(Iter begin, Iter end, T const& k) 330 | { 331 | while (begin != end && *begin != k) 332 | ++begin; 333 | 334 | return begin; 335 | } 336 | 337 | // Linear search with a sentinel. Assumes the searched for element 338 | // in the last array element. 339 | template 340 | auto find_with_sentinel(Iter begin, const T& v) 341 | { 342 | while (*begin != v) 343 | ++begin; 344 | 345 | return begin; 346 | } 347 | 348 | template 349 | auto lower_bound(Iter begin, Iter end, const T& K) 350 | { 351 | if (begin == end) 352 | return end; 353 | 354 | auto low = 0; 355 | auto high = end - begin - 1; 356 | 357 | while (low <= high) { 358 | int mid = (low + high) / 2; 359 | 360 | if (K < begin[mid]) 361 | high = mid - 1; 362 | else if (begin[mid] < K) 363 | low = mid + 1; 364 | else 365 | return begin + mid; 366 | } 367 | 368 | return begin + high + 1; 369 | } 370 | 371 | template 372 | bool binary_search(Iter begin, Iter end, const T& K) 373 | { 374 | if (begin == end) 375 | return false; 376 | 377 | auto low = 0; 378 | auto high = end - begin - 1; 379 | 380 | while (low <= high) { 381 | auto mid = (low + high) / 2; 382 | if (K < begin[mid]) 383 | high = mid - 1; 384 | else if (begin[mid] < K) 385 | low = mid + 1; 386 | else 387 | return true; 388 | } 389 | return false; 390 | } 391 | 392 | template 393 | bool binary_search2(Iter begin, Iter end, const T& K) 394 | { 395 | auto l = std::distance(begin, end); 396 | 397 | while (l > 0) { 398 | auto half = l / 2; 399 | auto mid = begin; 400 | std::advance(mid, half); 401 | 402 | if (K < *mid) { 403 | l = half; 404 | } else if (*mid < K) { 405 | begin = mid; 406 | ++begin; 407 | l = l - half - 1; 408 | } else { 409 | return true; 410 | } 411 | } 412 | return false; 413 | } 414 | 415 | template 416 | bool binary_search_recursive(Iter begin, Iter end, const T& K) 417 | { 418 | if (begin == end) 419 | return false; 420 | 421 | auto mid = (end - begin) / 2; 422 | if (K < begin[mid]) 423 | return binary_search_recursive(begin, begin + mid, K); 424 | else if (begin[mid] < K) 425 | return binary_search_recursive(begin + mid + 1, end, K); 426 | else 427 | return true; 428 | } 429 | 430 | template 431 | bool binary_search_rotated(Iter begin, Iter end, const T& K) 432 | { 433 | auto is_sorted = [&](auto a, auto b) 434 | { return !(begin[b - 1] < begin[a]); }; 435 | 436 | auto in_range = [&](auto a, auto b) 437 | { return !(K < begin[a] || begin[b - 1] < K); }; 438 | 439 | auto low = 0; 440 | auto high = end - begin; 441 | while (low < high) { 442 | auto mid = (low + high) / 2; 443 | if (is_sorted(mid, high)) { 444 | if (in_range(mid, high)) 445 | return rt::binary_search(begin + mid, begin + high, K); 446 | high = mid; 447 | } else { 448 | if (in_range(low, mid)) 449 | return rt::binary_search(begin + low, begin + mid, K); 450 | low = mid; 451 | } 452 | } 453 | return false; 454 | } 455 | 456 | // #### 457 | //_____________________________________________________________________ 458 | 459 | /* 460 | Calculates the next tuple based on the current one. The first element in 461 | the array is used for convenience and does not belong in the tuple. Minimum 462 | and maximum values for each element in the tuple are passed in paramenter 463 | min and max. 464 | 465 | Example: To Generate all tuples with size 3. 466 | 467 | void all_tuples() 468 | { 469 | std::vector min {0, 1, 1, 1}; 470 | std::vector max {min[0] + 1, 3, 2, 3}; 471 | auto arr = min; 472 | 473 | do { 474 | visit(arr); 475 | } while (next_tuple( std::begin(arr), std::end(arr) 476 | , std::begin(min), std::begin(max))); 477 | } 478 | 479 | It is important that max[0] != min[0]. 480 | */ 481 | 482 | template 483 | auto next_tuple( Iter begin, Iter end 484 | , Iter min, Iter max) 485 | { 486 | auto j = end - begin - 1; 487 | while (begin[j] == max[j]) { 488 | begin[j] = min[j]; 489 | --j; 490 | } 491 | ++begin[j]; 492 | 493 | return j != 0; 494 | } 495 | 496 | // Same as next_tuple but requires only bidirectional iterators. 497 | template 498 | auto next_tuple_stl( Iter begin, Iter end 499 | , Iter min, Iter max) 500 | { 501 | auto size = std::distance(begin, end); 502 | std::advance(min, size); 503 | std::advance(max, size); 504 | 505 | while (*--end == *--max) 506 | *end = *--min; 507 | 508 | *end += 1; 509 | return end != begin; 510 | } 511 | 512 | // #### 513 | //_____________________________________________________________________ 514 | 515 | auto next_combination(std::vector& v) 516 | { 517 | int t = v.size() - 2; 518 | auto i = 0; 519 | while ((v[i] + 1) == v[i + 1]) { 520 | v[i] = i; 521 | ++i; 522 | } 523 | if (i == t) return false; 524 | 525 | ++v[i]; 526 | return true; 527 | } 528 | 529 | // #### 530 | //_____________________________________________________________________ 531 | 532 | template 533 | bool next_permutation(Iter begin, Iter end) 534 | { 535 | auto b = end; 536 | auto a = std::prev(b); 537 | 538 | while (!(*--a < *--b)); 539 | 540 | if (a == begin) { 541 | std::reverse(++a, end); 542 | return false; 543 | } 544 | 545 | b = end; 546 | while (!(*a < *--b)); 547 | 548 | std::iter_swap(a, b); 549 | 550 | std::reverse(++a, end); 551 | 552 | return true; 553 | } 554 | 555 | template 556 | void inplace_inverse_perm(Iter begin, Iter end, bool begin_at_zero) 557 | { 558 | auto n = end - begin; 559 | auto m = n; 560 | auto j = -1; 561 | 562 | auto k = begin_at_zero ? 1 : 0; 563 | do { 564 | auto i = begin[m - 1] + k; 565 | if (i > -1) { 566 | do { 567 | begin[m - 1] = j - k; 568 | j = -m; 569 | m = i; 570 | i = begin[m - 1] + k; 571 | } while (i > 0); 572 | i = j; 573 | } 574 | begin[m - 1] = -i - k; 575 | --m; 576 | } while (m > 0); 577 | } 578 | 579 | template 580 | void permute(Iter begin, Iter end, Iter perm) 581 | { 582 | auto n = end - begin; 583 | for (auto i = 0; i < n; ++i) { 584 | if (perm[i] != i) { 585 | auto t = begin[i]; 586 | auto j = i; 587 | do { 588 | auto k = perm[j]; 589 | begin[j] = begin[k]; 590 | perm[j] = j; 591 | j = k; 592 | } while (perm[j] != i); 593 | begin[j] = t; 594 | perm[j] = j; 595 | } 596 | } 597 | } 598 | 599 | template 600 | void unpermute(Iter begin, Iter end, Iter table) 601 | { 602 | auto n = end - begin; 603 | for (auto i = 0; i < n; ++i) { 604 | while (table[i] != i) { 605 | std::swap(begin[i], begin[table[i]]); 606 | std::swap(table[i], table[table[i]]); 607 | } 608 | } 609 | } 610 | 611 | template 612 | void unpermute_on_the_fly(Iter begin, Iter end, Index index) 613 | { 614 | const auto n = end - begin; 615 | for (auto i = 0; i < n; ++i) { 616 | auto k = index(i); 617 | while (k > i) 618 | k = index(k); 619 | if (k == i) { 620 | k = index(i); 621 | while (k != i) { 622 | std::swap(begin[i], begin[k]); 623 | k = index(k); 624 | } 625 | } 626 | } 627 | } 628 | 629 | template 630 | void unpermute_on_the_fly_bit( Iter begin, Iter end, auto index 631 | , auto set_bit, auto unset_bit, auto is_set) 632 | { 633 | const auto n = end - begin; 634 | for (auto i = 0; i < n; ++i) { 635 | auto k = index(i); 636 | if (!is_set(begin[i])) { 637 | while (k != i) { 638 | std::swap(begin[i], begin[k]); 639 | set_bit(begin[k]); 640 | k = index(k); 641 | } 642 | } 643 | unset_bit(begin[i]); 644 | } 645 | } 646 | 647 | // Shuffles the input array. Expects a parameter rand that produces 648 | // random numbers uniformily distributed in the interval [0, 1). 649 | template 650 | void shuffle(std::vector& v, Rand& rand) 651 | { 652 | auto j = v.size(); 653 | do { 654 | auto k = static_cast(j * rand()); 655 | std::swap(v[k], v[--j]); 656 | } while (j != 0); 657 | } 658 | 659 | // Generates a random permutation with elements in the range [1, n]. 660 | template 661 | auto random_permutation(int n, Rand& rand) 662 | { 663 | std::vector ret(n); 664 | for (auto j = 0; j < n; ++j) { 665 | auto k = static_cast((j + 1) * rand()); 666 | ret[j] = ret[k]; 667 | ret[k] = j + 1; 668 | } 669 | 670 | return ret; 671 | } 672 | 673 | // #### 674 | //_____________________________________________________________________ 675 | 676 | void visit_partition(std::vector a, int m) 677 | { 678 | for (int i = 1; i <= m; ++i) 679 | std::cout << a[i] << " "; 680 | std::cout << std::endl; 681 | } 682 | 683 | void all_partitions_loop(int n) 684 | { 685 | std::vector a(n + 1, 1); 686 | a[0] = 0; 687 | 688 | int m = 1; 689 | for (;;) { 690 | a[m] = n; 691 | int q = m - (n == 1 ? 1 : 0); 692 | 693 | for (;;) { 694 | visit_partition(a, m); 695 | if (a[q] != 2) break; 696 | a[q--] = 1; 697 | ++m; 698 | } 699 | 700 | if (q == 0) return; 701 | 702 | int x = a[q] - 1; 703 | a[q] = x; 704 | n = m - q + 1; 705 | m = q + 1; 706 | 707 | while (x < n) { 708 | a[m++] = x; 709 | n -= x; 710 | } 711 | } 712 | } 713 | 714 | auto kdelta(int a, int b) { return a == b ? 1 : 0; } 715 | 716 | struct next_partition { 717 | int last, q; 718 | std::vector a; 719 | 720 | next_partition(int n) 721 | : last(1), q(last - kdelta(n, 1)), a(n + 1, 1) 722 | { 723 | a[0] = 0; 724 | a[1] = n; 725 | } 726 | 727 | auto next() 728 | { 729 | if (a[q] == 2) { 730 | a[q--] = 1; 731 | ++last; 732 | return true; 733 | }; 734 | 735 | if (q == 0) return false; 736 | 737 | int x = a[q] - 1; 738 | a[q] = x; 739 | auto n = last - q + 1; 740 | last = q + 1; 741 | 742 | while (x < n) { 743 | a[last++] = x; 744 | n -= x; 745 | } 746 | 747 | a[last] = n; 748 | q = last - kdelta(n, 1); 749 | return true; 750 | } 751 | }; 752 | 753 | template 754 | void tree_insertion_sort(Iter begin, Iter end) 755 | { 756 | bst_node root {}; 757 | auto tmp = begin; 758 | while (tmp != end) 759 | bst_insertion_sort_impl(root, *tmp++); 760 | 761 | using iter = rt::bst_iter; 762 | 763 | std::copy(iter {root.left}, iter {}, begin); 764 | } 765 | 766 | template 767 | void bubble_sort(Iter begin, Iter end) 768 | { 769 | if (begin == end) return; 770 | 771 | auto B = end - begin - 1; 772 | while (B != 0) { 773 | auto t = 0; 774 | for (auto j = 0; j < B; ++j) { 775 | if (begin[j] > begin[j + 1]) { 776 | std::swap(begin[j], begin[j + 1]); 777 | t = j + 1; 778 | } 779 | } 780 | B = t; 781 | } 782 | } 783 | 784 | template 785 | auto calc_address_table(Iter begin, Iter end) 786 | { 787 | const auto n = end - begin; 788 | std::vector count(n, 0); 789 | 790 | for (auto i = 1; i < n; ++i) 791 | for (auto j = 0; j < i; ++j) 792 | if (begin[i] < begin[j]) 793 | ++count[j]; 794 | else 795 | ++count[i]; 796 | 797 | return count; 798 | } 799 | 800 | template 801 | void comparison_counting_sort(Iter begin, Iter end) 802 | { 803 | auto n = end - begin; 804 | auto count = calc_address_table(begin, end); 805 | 806 | std::vector tmp(n, 0); 807 | for (auto i = 0; i < n; ++i) 808 | tmp[count[i]] = begin[i]; 809 | 810 | std::copy(std::begin(tmp), std::end(tmp), begin); 811 | } 812 | 813 | template 814 | void inplace_comparison_counting_sort(Iter begin, Iter end) 815 | { 816 | auto table = calc_address_table(begin, end); 817 | rt::unpermute(begin, end, std::begin(table)); 818 | } 819 | 820 | template 821 | void dist_counting_sort( Iter begin, Iter end 822 | , int min, int max) 823 | { 824 | auto n = end - begin; 825 | auto m = max - min + 1; 826 | 827 | std::vector count(m, 0); 828 | for (auto i = 0; i < n; ++i) 829 | ++count[begin[i] - min]; 830 | 831 | for (auto i = 1; i < m; ++i) 832 | count[i] += count[i - 1]; 833 | 834 | std::vector out(n, 0); 835 | for (auto i = 0; i < n; ++i) 836 | out[--count[begin[i] - min]] = begin[i]; 837 | 838 | std::copy(std::begin(out), std::end(out), begin); 839 | } 840 | 841 | template 842 | void straight_insertion(Iter begin, Iter end) 843 | { 844 | if (begin == end) return; 845 | 846 | auto N = end - begin; 847 | for (auto j = 1; j < N; ++j) { 848 | auto i = j - 1; 849 | auto k = begin[j]; 850 | while (k < begin[i]) { 851 | begin[i + 1] = begin[i]; 852 | if (--i < 0) break; 853 | } 854 | 855 | begin[i + 1] = k; 856 | } 857 | } 858 | 859 | template 860 | void binary_insertion(Iter begin, Iter end) 861 | { 862 | for (auto pos = begin; pos != end; ++pos) 863 | std::rotate( std::upper_bound(begin, pos, *pos) 864 | , pos 865 | , std::next(pos)); 866 | } 867 | 868 | template 869 | void straight_selection(Iter begin, Iter end) 870 | { 871 | if (begin == end) 872 | return; 873 | 874 | for (; begin != std::prev(end); ++begin) 875 | std::iter_swap( begin 876 | , rt::min_element(begin, end)); 877 | } 878 | 879 | template 880 | auto merge( Iter begin1, Iter end1 881 | , Iter begin2, Iter end2 882 | , Iter2 output) 883 | { 884 | if (begin1 == end1) return output; 885 | 886 | for (;;) { 887 | if (*begin1 <= *begin2) { 888 | *output++ = *begin1++; 889 | if (begin1 == end1) { 890 | std::copy(begin2, end2, output++); 891 | return output; 892 | } 893 | } else { 894 | *output++ = *begin2++; 895 | if (begin2 == end2) { 896 | std::copy(begin1, end1, output++); 897 | return output; 898 | } 899 | } 900 | } 901 | 902 | return output; 903 | } 904 | 905 | //____________________________________________________________________ 906 | 907 | constexpr auto is_power_of_two(std::size_t N) noexcept 908 | { 909 | return N > 0 && (N & (N - 1)) == 0; 910 | } 911 | 912 | // Returns true if a is aligned with respect to N i.e. the remainder of a 913 | // divided by b is zero. N must be a power of two. 914 | constexpr auto is_aligned(std::size_t a, std::size_t N) noexcept 915 | { 916 | return (a & (N - 1)) == 0; 917 | } 918 | 919 | constexpr auto align_previous(std::size_t a, std::size_t N) noexcept 920 | { 921 | return (a & ~(N - 1)); 922 | } 923 | 924 | constexpr auto align_next(std::size_t a, std::size_t N) noexcept 925 | { 926 | return align_previous(a, N) + N; 927 | } 928 | 929 | // If p is not aligned on an N boundary, this function will align it and 930 | // update s if alignment took place. 931 | void align_if_needed(void*& p, std::size_t& s, std::size_t N) noexcept 932 | { 933 | const auto a = reinterpret_cast(p); 934 | const auto c = is_aligned(a, N) ? a : align_next(a, N); 935 | p = reinterpret_cast(c); 936 | s -= c - a; 937 | } 938 | 939 | class timer { 940 | private: 941 | std::chrono::time_point m_start; 942 | public: 943 | timer() : m_start(std::chrono::system_clock::now()) {} 944 | auto get_count() const 945 | { 946 | std::chrono::time_point end = std::chrono::system_clock::now(); 947 | auto diff = end - m_start; 948 | auto diff2 = std::chrono::duration_cast(diff); 949 | return diff2.count(); 950 | } 951 | ~timer() 952 | { 953 | //std::chrono::time_point end = std::chrono::system_clock::now(); 954 | //auto diff = end - m_start; 955 | //auto diff2 = std::chrono::duration_cast(diff); 956 | //std::cout << diff2.count() << " "; 957 | } 958 | }; 959 | 960 | template 961 | struct dot_product_impl { 962 | template // P is a random access iter. 963 | static typename std::iterator_traits::value_type apply(RIter1 p1, RIter2 p2) 964 | { return p1[n - 1] * p2[n - 1] + dot_product_impl::apply(p1, p2); } 965 | }; 966 | 967 | template <> 968 | struct dot_product_impl<1> { 969 | template 970 | static typename std::iterator_traits::value_type apply(RIter1 p1, RIter2 p2) 971 | { return p1[0] * p2[0]; } 972 | }; 973 | 974 | template 975 | typename std::iterator_traits::value_type dot_product(RIter1 p1, RIter2 p2) 976 | { return dot_product_impl::apply(p1, p2); } 977 | 978 | template 979 | typename std::iterator_traits::value_type snorm(RandomAccessIter iter) 980 | { return dot_product(iter, iter); } 981 | 982 | inline 983 | std::size_t row_major_idx(std::size_t i, std::size_t j, 984 | std::size_t n_cols) { return i * n_cols + j; } 985 | 986 | template 987 | struct matrix_traits; 988 | 989 | template 990 | class matrix_expr { 991 | public: 992 | using value_type = typename matrix_traits::value_type; 993 | using size_type = typename matrix_traits::size_type; 994 | static constexpr std::size_t rows = matrix_traits::rows; 995 | static constexpr std::size_t cols = matrix_traits::cols; 996 | value_type operator()(size_type i, size_type j) const 997 | {return static_cast(*this)(i, j);} 998 | operator E&() {return static_cast(*this);} 999 | operator const E&() const {return static_cast(*this);} 1000 | }; 1001 | 1002 | template 1003 | class matrix : public matrix_expr > { 1004 | public: 1005 | static constexpr std::size_t rows = M; 1006 | static constexpr std::size_t cols = N; 1007 | static constexpr std::size_t data_size = rows * cols; 1008 | private: 1009 | using data_type = std::array; 1010 | public: 1011 | using value_type = typename data_type::value_type; 1012 | using size_type = typename data_type::size_type; 1013 | using iterator = typename data_type::iterator; 1014 | using const_iterator = typename data_type::const_iterator; 1015 | using reference = typename data_type::reference; 1016 | using const_reference = typename data_type::const_reference; 1017 | private: 1018 | data_type m_data; 1019 | public: 1020 | constexpr matrix() : m_data() {} 1021 | explicit matrix(const T& val) { fill(val);}; 1022 | reference operator[](size_type i) {return m_data[i];} 1023 | const_reference operator[](size_type i) const {return m_data[i];} 1024 | value_type operator()(size_type i, size_type j) const 1025 | {return m_data[row_major_idx(i, j, N)];} 1026 | reference operator()(size_type i, size_type j) 1027 | {return m_data[row_major_idx(i, j, N)];} 1028 | iterator begin() {return m_data.begin();} 1029 | iterator end() {return m_data.end();} 1030 | constexpr auto size() const {return M * N;} 1031 | const_iterator begin() const {return m_data.begin();} 1032 | const_iterator end() const {return m_data.end();} 1033 | const_iterator cbegin() const {return m_data.begin();} 1034 | const_iterator cend() const {return m_data.end();} 1035 | const_iterator row_cbegin(size_type i) const 1036 | {return m_data.begin() + row_major_idx(i, 0, N);} 1037 | reference front() {return *begin();} 1038 | const_reference front() const {return *cbegin();} 1039 | reference back() {return *(begin() + data_size - 1);} 1040 | const_reference back() const 1041 | {return *(cbegin() + data_size - 1);} 1042 | const_iterator row_cend(size_type i) const 1043 | {return row_cbegin(i) + N;} 1044 | iterator row_begin(size_type i) 1045 | {return m_data.begin() + row_major_idx(i, 0, N);} 1046 | iterator row_end(size_type i) {return row_begin(i) + N;} 1047 | template 1048 | matrix(const matrix_expr& mat) 1049 | { 1050 | static_assert(E::rows == rows, "Matrix with incompatible number of rows."); 1051 | static_assert(E::cols == cols, "Matrix with incompatible number of columns."); 1052 | for (size_type i = 0; i < rows; ++i) 1053 | for (size_type j = 0; j < cols; ++j) 1054 | m_data[row_major_idx(i, j, cols)] = mat(i, j); 1055 | } 1056 | matrix(std::initializer_list init) 1057 | { std::copy(std::begin(init), std::end(init), begin()); } 1058 | matrix& operator=(const matrix& rhs) 1059 | { 1060 | if (this != &rhs) 1061 | std::copy(std::begin(rhs), std::end(rhs), begin()); 1062 | return *this; 1063 | } 1064 | matrix& operator=(std::initializer_list init) 1065 | { std::copy(std::begin(init), std::end(init), begin()); } 1066 | bool operator==(const matrix& rhs) const 1067 | { return std::equal(cbegin(), cend(), rhs.cbegin()); } 1068 | bool operator!=(const matrix& rhs) const 1069 | { return !(*this == rhs);} 1070 | void fill(const T& val) 1071 | { std::fill(std::begin(m_data), std::end(m_data), val);}; 1072 | }; 1073 | 1074 | template 1075 | struct matrix_traits > { 1076 | using container_type = std::array; 1077 | using value_type = typename container_type::value_type; 1078 | using reference = typename container_type::reference; 1079 | using const_reference = typename container_type::const_reference; 1080 | using size_type = typename container_type::size_type; 1081 | using iterator = typename container_type::iterator; 1082 | using const_iterator = typename container_type::const_iterator; 1083 | using difference_type = typename container_type::difference_type; 1084 | static constexpr size_type rows = M; 1085 | static constexpr size_type cols = N; 1086 | }; 1087 | 1088 | template 1089 | class matrix_diff : public matrix_expr > { 1090 | const E1& m_u; 1091 | const E2& m_v; 1092 | public: 1093 | using size_type = typename E1::size_type; 1094 | using value_type = typename E1::value_type; 1095 | static constexpr size_type rows = E1::rows; 1096 | static constexpr size_type cols = E1::cols; 1097 | matrix_diff(const matrix_expr& u, const matrix_expr& v) 1098 | : m_u(u) 1099 | , m_v(v) 1100 | {} 1101 | value_type operator()(size_type i, size_type j) const 1102 | {return m_u(i, j) - m_v(i, j);} 1103 | }; 1104 | 1105 | template 1106 | struct matrix_traits > { 1107 | using value_type = typename E1::value_type; 1108 | using size_type = typename E1::size_type; 1109 | static constexpr size_type rows = E1::rows; 1110 | static constexpr size_type cols = E1::cols; 1111 | }; 1112 | 1113 | template 1114 | matrix_diff const operator-(const matrix_expr& u, const matrix_expr& v) 1115 | { return matrix_diff(u, v); } 1116 | 1117 | template 1118 | class matrix_sum : public matrix_expr > { 1119 | const E1& m_u; 1120 | const E2& m_v; 1121 | public: 1122 | using size_type = typename E1::size_type; 1123 | using value_type = typename E1::value_type; 1124 | static constexpr size_type rows = E1::rows; 1125 | static constexpr size_type cols = E1::cols; 1126 | matrix_sum(const matrix_expr& u, const matrix_expr& v) 1127 | : m_u(u) 1128 | , m_v(v) 1129 | {} 1130 | value_type operator()(size_type i, size_type j) const {return m_u(i, j) + m_v(i, j);} 1131 | }; 1132 | 1133 | template 1134 | struct matrix_traits > { 1135 | using value_type = typename E1::value_type; 1136 | using size_type = typename E1::size_type; 1137 | static constexpr size_type rows = E1::rows; 1138 | static constexpr size_type cols = E1::cols; 1139 | }; 1140 | 1141 | template 1142 | matrix_sum const operator+(const matrix_expr& u, const matrix_expr& v) 1143 | { return matrix_sum(u, v); } 1144 | 1145 | template 1146 | class matrix_scaled : public matrix_expr > { 1147 | public: 1148 | using value_type = typename E::value_type; 1149 | using size_type = typename E::size_type; 1150 | static constexpr size_type rows = E::rows; 1151 | static constexpr size_type cols = E::cols; 1152 | private: 1153 | value_type m_val; 1154 | const E& m_v; 1155 | public: 1156 | matrix_scaled(value_type val, const matrix_expr& v) 1157 | : m_val(val) 1158 | , m_v(v) 1159 | {} 1160 | value_type operator()(size_type i, size_type j) const 1161 | {return m_val * m_v(i, j);} 1162 | }; 1163 | 1164 | template 1165 | struct matrix_traits > { 1166 | using value_type = typename E::value_type; 1167 | using size_type = typename E::size_type; 1168 | static constexpr size_type rows = E::rows; 1169 | static constexpr size_type cols = E::cols; 1170 | }; 1171 | 1172 | template 1173 | matrix_scaled const operator*(typename E::value_type val, const matrix_expr& v) 1174 | { return matrix_scaled(val, v); } 1175 | 1176 | template 1177 | matrix_scaled const operator*(const matrix_expr& v, typename E::value_type val) 1178 | { return matrix_scaled(val, v); } 1179 | 1180 | template 1181 | matrix_scaled const operator/(const matrix_expr& v, typename E::value_type val) 1182 | { 1183 | const double tmp = static_cast(1) / val; 1184 | return matrix_scaled(tmp, v); 1185 | } 1186 | 1187 | template 1188 | class matrix_prod : public matrix_expr > { 1189 | private: 1190 | static_assert(E1::cols == E2::rows, "Incompatible number of rows and columns."); 1191 | const E1& m_u; 1192 | const E2& m_v; 1193 | public: 1194 | using size_type = typename E1::size_type; 1195 | using value_type = typename E1::value_type; 1196 | static constexpr size_type rows = E1::rows; 1197 | static constexpr size_type cols = E2::cols; 1198 | matrix_prod(const matrix_expr& u, const matrix_expr& v) 1199 | : m_u(u) 1200 | , m_v(v) 1201 | {} 1202 | value_type operator()(size_type i, size_type j) const 1203 | { 1204 | value_type tmp = 0; 1205 | for (size_type k = 0; k < E2::rows; ++k) 1206 | tmp += m_u(i, k) * m_v(k, j); 1207 | 1208 | return tmp; 1209 | } 1210 | }; 1211 | 1212 | template 1213 | struct matrix_traits > { 1214 | using value_type = typename E1::value_type; 1215 | using size_type = typename E1::size_type; 1216 | static constexpr size_type rows = E1::rows; 1217 | static constexpr size_type cols = E2::cols; 1218 | }; 1219 | 1220 | template 1221 | matrix_prod const operator*(const matrix_expr& u, const matrix_expr& v) 1222 | { return matrix_prod(u, v); } 1223 | 1224 | template 1225 | void operator+=( matrix& u 1226 | , const matrix_expr& v) 1227 | { 1228 | const matrix tmp = u + v; 1229 | u = tmp; 1230 | } 1231 | 1232 | template 1233 | void operator-=( matrix< typename E::value_type, E::rows, E::cols>& u 1234 | , const matrix_expr& v) 1235 | { 1236 | const matrix tmp = u - v; 1237 | u = tmp; 1238 | } 1239 | 1240 | template 1241 | void operator*=(matrix< T1, M, N>& u, T2 val) 1242 | { 1243 | const matrix tmp = u * val; 1244 | u = tmp; 1245 | } 1246 | 1247 | template 1248 | void operator/=(matrix< T1, M, N>& u, T2 val) 1249 | { 1250 | const matrix tmp = u / val; 1251 | u = tmp; 1252 | } 1253 | 1254 | template 1255 | void operator*=( matrix< typename E::value_type, E::rows, E::cols>& u 1256 | , const matrix_expr& v) 1257 | { 1258 | const matrix tmp = u * v; 1259 | u = tmp; 1260 | } 1261 | 1262 | template 1263 | matrix transpose(const matrix& mat) 1264 | { 1265 | matrix tmp; 1266 | for (std::size_t i = 0; i < M; ++i) 1267 | for (std::size_t j = 0; j < N; ++j) 1268 | tmp(j, i) = mat(i, j); 1269 | 1270 | return tmp; 1271 | } 1272 | 1273 | template 1274 | T snorm(const matrix& mat) // Squared norm. 1275 | { return snorm(mat.cbegin());} 1276 | 1277 | template 1278 | T snorm(const matrix& mat) 1279 | { return snorm(mat.cbegin());} 1280 | 1281 | template 1282 | std::ostream& operator<<(std::ostream& os, const matrix& mat) 1283 | { 1284 | for (std::size_t i = 0; i < M; ++i) { 1285 | std::copy( mat.row_cbegin(i) 1286 | , mat.row_cend(i) 1287 | , std::ostream_iterator(os, " ")); 1288 | os << "\n"; 1289 | } 1290 | os << std::endl; 1291 | return os; 1292 | } 1293 | 1294 | // Generates a uniform distribution of integers in the range 1295 | // [first, last] with size size. 1296 | // The following options for the argument type are available. 1297 | // 1 - The returned vector can have repeated elements. 1298 | // 2 - All elements appear only once. The vector can have size less the 1299 | // "size". 1300 | 1301 | auto make_rand_data(int size, int first, int last, int type = 2) 1302 | { 1303 | std::random_device rd; 1304 | std::mt19937 gen(rd()); 1305 | std::uniform_int_distribution dis(first, last); 1306 | 1307 | std::vector data; 1308 | std::generate_n( std::back_inserter(data), size, 1309 | [&](){return dis(gen);}); 1310 | if (type == 1) 1311 | return data; 1312 | 1313 | std::sort(std::begin(data), std::end(data)); 1314 | data.erase(std::unique(std::begin(data), std::end(data)), 1315 | std::end(data)); 1316 | shuffle(std::begin(data), std::end(data), gen); 1317 | return data; 1318 | } 1319 | 1320 | } // rt 1321 | 1322 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0 FATAL_ERROR) 2 | 3 | project(rtcpp) 4 | 5 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 6 | set(GNU_FOUND true) 7 | endif() 8 | 9 | configure_file( 10 | ${PROJECT_SOURCE_DIR}/config.h.in 11 | ${PROJECT_BINARY_DIR}/config.h 12 | ) 13 | 14 | enable_testing() 15 | include(CTest) 16 | include(CPack) 17 | 18 | include_directories(..) 19 | include_directories(${PROJECT_BINARY_DIR}) 20 | 21 | install( DIRECTORY ${PROJECT_SOURCE_DIR}/include/rtcpp 22 | DESTINATION ${CMAKE_INSTALL_PREFIX}/include) 23 | 24 | add_executable(ex_matrix ${PROJECT_SOURCE_DIR}/ex_matrix.cpp) 25 | add_executable(test_align ${PROJECT_SOURCE_DIR}/test_align.cpp) 26 | add_executable(test_matrix ${PROJECT_SOURCE_DIR}/test_matrix.cpp) 27 | add_executable(test_sort ${PROJECT_SOURCE_DIR}/test_sort.cpp) 28 | add_executable(test_algorithm ${PROJECT_SOURCE_DIR}/test_algorithm.cpp) 29 | add_executable(test_tree ${PROJECT_SOURCE_DIR}/test_tree.cpp) 30 | add_executable(test_combinatorics ${PROJECT_SOURCE_DIR}/test_combinatorics.cpp) 31 | 32 | add_executable(interview_bit_img ${PROJECT_SOURCE_DIR}/interview_bit_img.cpp) 33 | add_executable(interview_bits ${PROJECT_SOURCE_DIR}/interview_bits.cpp) 34 | add_executable(interview_interval_map ${PROJECT_SOURCE_DIR}/interview_interval_map.cpp) 35 | add_executable(interview_logging_thread ${PROJECT_SOURCE_DIR}/interview_logging_thread.cpp) 36 | add_executable(interview_str_arithmetic ${PROJECT_SOURCE_DIR}/interview_str_arithmetic.cpp) 37 | 38 | add_executable(tool_book ${PROJECT_SOURCE_DIR}/tool_book.cpp) 39 | add_executable(tool_bench_sort ${PROJECT_SOURCE_DIR}/tool_bench_sort.cpp) 40 | 41 | add_test(NAME ex_matrix COMMAND ex_matrix) 42 | add_test(NAME test_sort COMMAND test_sort) 43 | add_test(NAME test_align COMMAND test_align) 44 | add_test(NAME test_tree COMMAND test_tree) 45 | add_test(NAME test_combinatorics COMMAND test_combinatorics) 46 | add_test(NAME test_matrix COMMAND test_matrix) 47 | add_test(NAME test_algorithm COMMAND test_algorithm) 48 | 49 | add_test(NAME interview_bit_img COMMAND interview_bit_img) 50 | add_test(NAME interview_bits COMMAND interview_bits) 51 | add_test(NAME interview_interval_map COMMAND interview_interval_map) 52 | add_test(NAME interview_logging_thread COMMAND interview_logging_thread) 53 | add_test(NAME interview_str_arithmetic COMMAND interview_str_arithmetic) 54 | 55 | -------------------------------------------------------------------------------- /src/brazil_middle_point.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using arr_type = std::array; 11 | 12 | struct acc { 13 | auto operator()(double init, arr_type const& value) const 14 | { 15 | init += value.at(0); 16 | return init; 17 | }; 18 | }; 19 | 20 | struct sort_cond { 21 | int i = 1; 22 | auto operator()(arr_type const& u, arr_type const& v) const 23 | { 24 | return u.at(i) < v.at(i); 25 | }; 26 | }; 27 | 28 | int acc_up_to(std::vector const& v, double area) 29 | { 30 | auto d = 0.0; 31 | auto i = 0; 32 | 33 | while (d < area) 34 | d += v.at(++i).at(0); 35 | 36 | return i; 37 | } 38 | 39 | auto find_partitions(std::vector v) 40 | { 41 | auto const total_area = 42 | std::accumulate( std::cbegin(v) 43 | , std::cend(v) 44 | , 0.0 45 | , acc{}); 46 | 47 | auto const half = total_area / 2; 48 | 49 | std::sort(std::begin(v), std::end(v), sort_cond{1}); 50 | auto const i1 = acc_up_to(v, half); 51 | auto const v1 = v.at(i1).at(1); 52 | 53 | std::sort(std::begin(v), std::end(v), sort_cond{2}); 54 | auto const i2 = acc_up_to(v, half); 55 | auto const v2 = v.at(i2).at(2); 56 | 57 | return std::make_pair(v1, v2); 58 | } 59 | 60 | std::vector 61 | split_line(std::string const& line, char sep) 62 | { 63 | std::string item; 64 | std::istringstream iss(line); 65 | std::vector fields; 66 | while (std::getline(iss, item, sep)) 67 | fields.push_back(item); 68 | 69 | return fields; 70 | } 71 | 72 | auto central_point(std::string const& str) 73 | { 74 | std::istringstream iss(str); 75 | 76 | std::vector table; 77 | std::string line; 78 | while (std::getline(iss, line)) { 79 | auto fields = split_line(line, ':'); 80 | 81 | if (std::size(fields) != 4) { 82 | std::cerr << "Incompatible line size on line: "; 83 | std::copy( std::cbegin(fields) 84 | , std::cend(fields) 85 | , std::ostream_iterator(std::cerr, " ")); 86 | std::cerr << std::endl; 87 | return std::pair{0.0, 0.0}; 88 | } 89 | 90 | table.push_back({ std::stod(fields.at(1)) 91 | , std::stod(fields.at(2)) 92 | , std::stod(fields.at(3))}); 93 | } 94 | 95 | return find_partitions(table); 96 | } 97 | 98 | int main() 99 | { 100 | using iter_type = std::istreambuf_iterator; 101 | 102 | std::ifstream ifs {"merge.txt"}; 103 | std::string str {iter_type {ifs}, {}}; 104 | 105 | auto const out = central_point(str); 106 | 107 | std::cout << out.first << " " << out.second << std::endl; 108 | } 109 | -------------------------------------------------------------------------------- /src/config.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #cmakedefine Boost_FOUND @Boost_FOUND@ 4 | #cmakedefine GNU_FOUND 5 | 6 | -------------------------------------------------------------------------------- /src/ex_matrix.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "rtcpp.hpp" 3 | 4 | int main() 5 | { 6 | using vec3 = rt::matrix; 7 | using mat3 = rt::matrix; 8 | 9 | const vec3 v = {2, 4, 6}; 10 | const mat3 m = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 11 | 12 | const vec3 r = 2 * m * v + 3 * v + v / 2; 13 | 14 | std::cout << r; 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/interview_bit_img.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | constexpr auto get_bit(T o, int i) // i in [0, sizeof i) 8 | { return (o & (1 << i)) != 0; } 9 | 10 | template 11 | void set_bit(T& o, int i) { o |= 1 << i; } 12 | 13 | template 14 | void print_bits(T o) 15 | { 16 | constexpr auto s = 8 * sizeof o; 17 | for (unsigned i = 0; i < s; ++i) 18 | std::cout << get_bit(o, i); 19 | } 20 | 21 | template 22 | void print_img(const std::vector& img, int n) 23 | { 24 | constexpr auto s = 8 * sizeof T {}; 25 | for (unsigned i = 0; i < img.size(); ++i) { 26 | if ((i * s) % (n * s) == 0) 27 | std::cout << "\n"; 28 | print_bits(img[i]); 29 | std::cout << "|"; 30 | } 31 | std::cout << "\n"; 32 | } 33 | 34 | template 35 | void set_bits_slow( std::vector& img, int cols 36 | , int row_bit_begin, int row_bit_end 37 | , int col_bit_begin, int col_bit_end) 38 | { 39 | constexpr int s = 8 * sizeof T {}; 40 | 41 | for (auto i = row_bit_begin; i < row_bit_end; ++i) 42 | for (auto j = col_bit_begin; j < col_bit_end; ++j) 43 | set_bit(img[i * cols + j / s], j % s); 44 | } 45 | 46 | template 47 | void set_bits_fast( std::vector& img, int cols 48 | , int row_bit_begin, int row_bit_end 49 | , int col_bit_begin, int col_bit_end) 50 | { 51 | constexpr int s = 8 * sizeof T {}; 52 | 53 | auto begin = col_bit_begin / s; 54 | T begin_mask = T(-1) << col_bit_begin % s; 55 | 56 | auto end = col_bit_end / s; 57 | T end_mask = (1 << col_bit_end % s) - 1; 58 | 59 | if (begin == end) { 60 | for (auto i = row_bit_begin; i < row_bit_end; ++i) 61 | img[i * cols + begin] |= begin_mask & end_mask; 62 | 63 | return; 64 | } 65 | 66 | for (auto i = row_bit_begin; i < row_bit_end; ++i) { 67 | img[cols * i + begin] |= begin_mask; 68 | 69 | for (auto j = begin + 1; j < end; ++j) 70 | img[i * cols + j] = T(-1); 71 | 72 | if (end != cols) 73 | img[i * cols + end] |= end_mask; 74 | } 75 | } 76 | 77 | int main() 78 | { 79 | using type = std::uint16_t; 80 | 81 | constexpr int s = 8 * sizeof type {}; 82 | 83 | constexpr auto rows = 16; 84 | constexpr auto cols = 6; 85 | 86 | std::vector img1(rows * cols); 87 | std::vector img2(rows * cols); 88 | 89 | auto height = 5; 90 | auto row_bit_begin = std::min(2, rows * s - 1); 91 | auto row_bit_end = std::min(row_bit_begin + height, rows); 92 | 93 | auto width = 50; 94 | auto col_bit_begin = std::min(12, cols * s - 1); 95 | auto col_bit_end = std::min(col_bit_begin + width, cols * s); 96 | 97 | set_bits_slow( img1, cols 98 | , row_bit_begin, row_bit_end 99 | , col_bit_begin, col_bit_end); 100 | 101 | print_img(img1, cols); 102 | 103 | set_bits_fast( img2, cols 104 | , row_bit_begin, row_bit_end 105 | , col_bit_begin, col_bit_end); 106 | 107 | print_img(img2, cols); 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/interview_bits.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int count_bits(int v) 5 | { 6 | int c = 0; 7 | for (; v; ++c) 8 | v &= v - 1; 9 | 10 | return c; 11 | } 12 | 13 | auto op(unsigned o, unsigned m, unsigned s) 14 | { 15 | return ((o >> s) & m) | (o & m) << s; 16 | } 17 | 18 | auto reverse(unsigned o) 19 | { 20 | o = op(o, 0x55555555, 1); 21 | o = op(o, 0x33333333, 2); 22 | o = op(o, 0x0F0F0F0F, 4); 23 | o = op(o, 0x00FF00FF, 8); 24 | o = op(o, 0x0000FFFF, 16); 25 | 26 | return o; 27 | } 28 | 29 | auto add(unsigned a, unsigned b) 30 | { 31 | while (b != 0) { 32 | auto sum = a ^ b; // Without carry. 33 | b = (a & b) << 1; 34 | a = sum; 35 | } 36 | 37 | return a; 38 | } 39 | 40 | int main() 41 | { 42 | std::cout << count_bits(8) << std::endl; 43 | std::cout << count_bits(15) << std::endl; 44 | std::cout << count_bits(10) << std::endl; 45 | std::cout << count_bits(100) << std::endl; 46 | std::cout << count_bits(127) << std::endl; 47 | 48 | std::cout << std::bitset<4 * 8>(182927) << std::endl; 49 | std::cout << std::bitset<4 * 8>(reverse(182927)) << std::endl; 50 | 51 | int a = 23; 52 | int b = 22; 53 | std::cout << a << " + " << b << ": " << add(a, b) << std::endl; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/interview_interval_map.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | template 13 | struct interval_map { 14 | std::map map; 15 | interval_map(V v = {}) : map({{std::numeric_limits::min(), v}}) {} 16 | 17 | void assign(const K& a, const K& b, const V& v) 18 | { 19 | auto comp = map.key_comp(); 20 | 21 | if (!comp(a, b)) 22 | return; 23 | 24 | auto lbb = map.lower_bound(b); 25 | auto vb = lbb == std::end(map) ? map.rbegin()->second 26 | : comp(b, lbb->first) ? std::prev(lbb)->second 27 | : lbb->second; 28 | 29 | if (v == vb) 30 | return; 31 | 32 | auto lba = map.lower_bound(a); 33 | auto va = lba == std::end(map) ? map.rbegin()->second 34 | : lba == std::begin(map) ? lba->second 35 | : std::prev(lba)->second; 36 | 37 | if (v == va && lba != std::begin(map)) 38 | return; 39 | 40 | map.erase( std::next(map.insert_or_assign(lba, a, v)) 41 | , map.insert_or_assign(lbb, b, vb)); 42 | } 43 | 44 | const V& operator[](K const& key) const 45 | { return (--map.upper_bound(key))->second; } 46 | }; 47 | 48 | template 49 | void print(const interval_map& m) 50 | { 51 | for (const auto& item : m.map) 52 | std::cout << std::setw(3) << item.first << " " << item.second << std::endl; 53 | } 54 | 55 | template 56 | auto check_valid_map(const std::map& map) 57 | { 58 | auto func = [](const auto& a, const auto& b) 59 | {return a.second == b.second;}; 60 | 61 | return std::adjacent_find( std::cbegin(map), std::cend(map) 62 | , func) == std::cend(map); 63 | } 64 | bool test1() 65 | { 66 | std::mt19937 gen {}; 67 | 68 | std::uniform_int_distribution dis1(0, 50); 69 | std::uniform_int_distribution dis2(0, 50); 70 | 71 | interval_map map; 72 | for (auto j = 0; j < 20; ++j) { 73 | map = {}; 74 | for (auto i = 0; i < 10000; ++i) { 75 | const auto a = dis2(gen); 76 | const auto b = dis2(gen); 77 | const auto c = dis1(gen); 78 | auto map_copy = map.map; 79 | map.assign(a, b, c); 80 | } 81 | 82 | if (!check_valid_map(map.map)) { 83 | print(map); 84 | return false; 85 | } 86 | } 87 | print(map); 88 | return true; 89 | } 90 | 91 | bool test2() 92 | { 93 | interval_map map {'a'}; 94 | 95 | std::map m1 {{0, 'a'}}; 96 | if (map.map != m1) { 97 | std::cout << "T1 failed." << std::endl; 98 | return false; 99 | } 100 | 101 | map.assign(3, 8, 'b'); 102 | 103 | m1 = {{0, 'a'}, {3, 'b'}, {8, 'a'}}; 104 | if (map.map != m1) { 105 | std::cout << "T2 failed." << std::endl; 106 | return false; 107 | } 108 | 109 | map.assign(5, 9, 'c'); 110 | 111 | m1 = {{0, 'a'}, {3, 'b'}, {5, 'c'}, {9, 'a'}}; 112 | if (map.map != m1) { 113 | std::cout << "T3 failed." << std::endl; 114 | return false; 115 | } 116 | 117 | map.assign(2, 10, 'd'); 118 | 119 | m1 = {{0, 'a'}, {2, 'd'}, {10, 'a'}}; 120 | if (map.map != m1) { 121 | std::cout << "T4 failed." << std::endl; 122 | return false; 123 | } 124 | return true; 125 | } 126 | 127 | 128 | int main() 129 | { 130 | try { 131 | if (!test1()) 132 | return 1; 133 | 134 | if (!test2()) 135 | return 1; 136 | 137 | std::cout << "Tests succeed" << std::endl; 138 | } catch (const std::exception& e) { 139 | std::cout << e.what() << std::endl; 140 | } 141 | return 0; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /src/interview_logging_thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | std::mutex mutex; 11 | std::condition_variable cv; 12 | bool has_new_msg; 13 | std::queue msg_queue; 14 | 15 | void logger() 16 | { 17 | std::ofstream ofs("log.txt"); 18 | for (;;) { 19 | std::unique_lock lock(mutex); 20 | cv.wait(lock, [&] { return has_new_msg; }); 21 | 22 | if (msg_queue.empty()) 23 | break; 24 | 25 | while (!msg_queue.empty()) { 26 | ofs << msg_queue.front() << std::endl; 27 | msg_queue.pop(); 28 | } 29 | has_new_msg = false; 30 | } 31 | } 32 | 33 | void post_msg(std::string msg = {}) 34 | { 35 | std::unique_lock lock(mutex); 36 | msg_queue.push(msg); 37 | if (msg.empty()) 38 | std::queue{}.swap(msg_queue); 39 | has_new_msg = true; 40 | lock.unlock(); 41 | cv.notify_one(); 42 | } 43 | 44 | int main() 45 | { 46 | using namespace std::literals::chrono_literals; 47 | 48 | std::thread logging_thread(logger); 49 | 50 | for (auto i = 0; i < 10; ++i) { 51 | std::this_thread::sleep_for(20ms); 52 | post_msg("Message: " + std::to_string(i)); 53 | } 54 | post_msg(); 55 | logging_thread.join(); 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/interview_str_arithmetic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void visit(std::stack stack) 11 | { 12 | while (!stack.empty()) { 13 | std::cout << stack.top() << " "; 14 | stack.pop(); 15 | } 16 | std::cout << "\n"; 17 | } 18 | 19 | template 20 | void handle_op(std::stack& stack, C c) 21 | { 22 | if (stack.size() < 2) 23 | return; 24 | 25 | auto a = stack.top(); 26 | stack.pop(); 27 | auto b = stack.top(); 28 | stack.pop(); 29 | stack.push(c(a, b)); 30 | } 31 | 32 | void iterative(const std::string& s) 33 | { 34 | using iter_type = std::istream_iterator; 35 | 36 | std::stringstream ss(s); 37 | 38 | std::stack stack; 39 | auto f = [&](const auto& o) 40 | { 41 | if (o == "+") 42 | handle_op(stack, std::plus{}); 43 | else if (o == "-") 44 | handle_op(stack, std::minus{}); 45 | else 46 | stack.push(std::stoi(o)); 47 | }; 48 | 49 | std::for_each(iter_type{ss}, iter_type{}, f); 50 | visit(stack); 51 | } 52 | 53 | void recursive( std::stack stack 54 | , std::istream_iterator iter) 55 | { 56 | using iter_type = std::istream_iterator; 57 | 58 | if (iter == iter_type {}) { 59 | visit(stack); 60 | return; 61 | } 62 | 63 | auto s = *iter; 64 | if (s == "+") 65 | handle_op(stack, std::plus{}); 66 | else if (s == "-") 67 | handle_op(stack, std::minus{}); 68 | else 69 | stack.push(std::stoi(s)); 70 | 71 | recursive(std::move(stack), ++iter); 72 | } 73 | 74 | int main() 75 | { 76 | iterative("1 13 - 6 + 9 8 +"); 77 | using iter_type = std::istream_iterator; 78 | std::istringstream ss("1 13 - 6 + 9 8 +"); 79 | iter_type iter(ss); 80 | recursive(std::stack{}, iter); 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/test.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define RT_TEST(name) \ 6 | void name(const char* f = #name) 7 | 8 | #define RT_CHECK(b) \ 9 | if (!(b)) \ 10 | throw std::runtime_error(f); 11 | 12 | namespace rt 13 | { 14 | 15 | void print(std::vector const& v) 16 | { 17 | for (auto o: v) 18 | std::cout << o << " "; 19 | std::cout << std::endl; 20 | } 21 | 22 | } // rt 23 | 24 | -------------------------------------------------------------------------------- /src/test_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "rtcpp.hpp" 10 | #include "test.hpp" 11 | 12 | RT_TEST(test_find_intrusive1) 13 | { 14 | std::vector data {2, 4, 6, 9, 3, 12}; 15 | rt::print(data); 16 | 17 | for (unsigned i = 0; i < data.size() - 1; ++i) { 18 | data.back() = data[i]; 19 | auto iter = rt::find_with_sentinel(std::begin(data), data[i]); 20 | std::cout << "K = " << data[i] << "\n"; 21 | if (iter == std::end(data)) 22 | throw std::runtime_error(f); 23 | } 24 | } 25 | 26 | RT_TEST(test_find_intrusive2) 27 | { 28 | std::vector data {2, 4, 6, 9, 3, 12}; 29 | rt::print(data); 30 | 31 | // Searches for a number that is not in the array. 32 | data.back() = 13; 33 | auto iter = rt::find_with_sentinel(std::begin(data), 13); 34 | RT_CHECK(*iter == data.back()) 35 | } 36 | 37 | RT_TEST(test_reverse) 38 | { 39 | using namespace rt; 40 | 41 | std::array arr1 = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}; 42 | std::array tmp1 = {{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}}; 43 | std::array arr2 = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}}; 44 | std::array tmp2 = {{11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}}; 45 | 46 | rt::reverse(std::begin(arr1), std::end(arr1)); 47 | rt::reverse(std::begin(arr2), std::end(arr2)); 48 | 49 | RT_CHECK(std::equal(std::begin(arr1), std::end(arr1), std::begin(tmp1))) 50 | RT_CHECK(std::equal(std::begin(arr2), std::end(arr2), std::begin(tmp2))) 51 | } 52 | 53 | RT_TEST(test_binary_search) 54 | { 55 | std::array data = {1, 20, 32, 44, 51, 69, 70, 87, 91, 101}; 56 | 57 | for (unsigned i = 0; i < data.size(); ++i) 58 | RT_CHECK(rt::binary_search(std::begin(data), std::end(data), data[i])) 59 | 60 | RT_CHECK(!rt::binary_search(std::begin(data), std::end(data), 10)) 61 | } 62 | 63 | RT_TEST(test_binary_search2) 64 | { 65 | std::forward_list data {1, 20, 32, 44, 51, 69, 70, 87, 91, 101}; 66 | 67 | for (auto o : data) 68 | RT_CHECK(rt::binary_search2(std::begin(data), std::end(data), o)) 69 | 70 | RT_CHECK(!rt::binary_search2(std::begin(data), std::end(data), 10)) 71 | } 72 | 73 | RT_TEST(test_binary_search_rec) 74 | { 75 | std::vector data {1, 20, 32, 44, 51, 69, 70, 87, 91, 101}; 76 | 77 | for (std::size_t i = 0; i < data.size(); ++i) 78 | RT_CHECK(rt::binary_search_recursive( std::begin(data) 79 | , std::end(data), data[i])) 80 | 81 | RT_CHECK(!rt::binary_search_recursive( std::begin(data) 82 | , std::end(data), 10)) 83 | } 84 | 85 | RT_TEST(test_binary_search_rotated) 86 | { 87 | (void)f; 88 | std::array data = {5, 7, 9, 13, 15, 19, 1, 2, 3, 4}; 89 | 90 | for (int i = 0; i < 25; ++i) { 91 | auto b = rt::binary_search_rotated( std::begin(data) 92 | , std::end(data), i); 93 | std::cout << i << ": " << b << std::endl; 94 | } 95 | } 96 | 97 | RT_TEST(test_find) 98 | { 99 | std::array data = {5, 7, 9, 13, 15, 19, 1, 2, 3, 4}; 100 | 101 | for (unsigned i = 0; i < data.size(); ++i) { 102 | auto match = rt::find(std::begin(data), std::end(data), data[i]); 103 | if (match == std::end(data)) 104 | throw std::runtime_error(f); 105 | } 106 | 107 | auto match = rt::find(std::begin(data), std::end(data), 222); 108 | if (match != std::end(data)) 109 | throw std::runtime_error(f); 110 | 111 | // Empty range 112 | std::vector tmp; 113 | auto match2 = rt::find(std::begin(tmp), std::end(tmp), 222); 114 | if (match2 != std::end(tmp)) 115 | throw std::runtime_error(f); 116 | 117 | std::cout << "test_find ok" << std::endl; 118 | } 119 | 120 | RT_TEST(test_max_element) 121 | { 122 | std::array data = {5, 7, 9, 13, 15, 19, 1, 2, 3, 4}; 123 | 124 | auto max = rt::max_element(std::begin(data), std::end(data)); 125 | 126 | if (max == std::end(data)) 127 | throw std::runtime_error(f); 128 | 129 | if (*max != 19) 130 | throw std::runtime_error(f); 131 | 132 | std::cout << "test_max_element ok" << std::endl; 133 | } 134 | 135 | RT_TEST(test_min_element) 136 | { 137 | std::array data = {5, 7, 9, 13, 15, 19, 1, 2, 3, 4}; 138 | 139 | auto min = rt::min_element(std::begin(data), std::end(data)); 140 | 141 | RT_CHECK(min != std::end(data)) 142 | RT_CHECK(*min == 1) 143 | 144 | std::cout << "test_min_element ok" << std::endl; 145 | } 146 | 147 | int main() 148 | { 149 | try { 150 | test_binary_search(); 151 | test_binary_search2(); 152 | test_binary_search_rec(); 153 | test_binary_search_rotated(); 154 | test_reverse(); 155 | test_find_intrusive1(); 156 | test_find_intrusive2(); 157 | test_find(); 158 | test_max_element(); 159 | test_min_element(); 160 | } catch (std::exception const& e) { 161 | std::cerr << e.what() << std::endl; 162 | return 1; 163 | } catch (...) { 164 | std::cerr << "Error" << std::endl; 165 | return 1; 166 | } 167 | 168 | return 0; 169 | } 170 | 171 | -------------------------------------------------------------------------------- /src/test_align.cpp: -------------------------------------------------------------------------------- 1 | #include "rtcpp.hpp" 2 | 3 | void test_align() 4 | { 5 | 6 | static_assert(rt::is_power_of_two( 2), "Error: 2 is a power of two."); 7 | static_assert(rt::is_power_of_two( 4), "Error: 4 is a power of two."); 8 | static_assert(rt::is_power_of_two( 8), "Error: 8 is a power of two."); 9 | static_assert(rt::is_power_of_two(16), "Error: 16 is a power of two."); 10 | static_assert(rt::is_power_of_two(32), "Error: 32 is a power of two."); 11 | static_assert(rt::is_power_of_two(64), "Error: 64 is a power of two."); 12 | 13 | static_assert(rt::is_aligned(16, 8), "Error: rt::is_aligned(16, 8)"); 14 | 15 | static_assert(rt::align_next(13, 8) == 16, "Error."); 16 | static_assert(rt::align_next( 1, 4) == 4, "Error."); 17 | static_assert(rt::align_next(27, 4) == 28, "Error."); 18 | static_assert(rt::align_next(27, 8) == 32, "Error."); 19 | } 20 | 21 | int main() 22 | { 23 | test_align(); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/test_combinatorics.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "rtcpp.hpp" 9 | #include "test.hpp" 10 | 11 | void visit_tuple(std::vector const& arr) 12 | { 13 | if (arr.size() < 2) 14 | return; 15 | 16 | for (unsigned i = 1; i < arr.size(); ++i) 17 | std::cout << arr[i]; 18 | std::cout << std::endl; 19 | } 20 | 21 | void all_tuples_stl() 22 | { 23 | std::vector min {1, 1, 1, 1}; 24 | std::vector max {2, 3, 2, 3}; 25 | auto arr = min; 26 | 27 | do { 28 | visit_tuple(arr); 29 | } while (rt::next_tuple_stl( std::begin(arr) 30 | , std::end(arr) 31 | , std::begin(min) 32 | , std::begin(max))); 33 | } 34 | 35 | void all_tuples() 36 | { 37 | std::vector min {0, 1, 1, 1}; 38 | std::vector max {2, 3, 2, 3}; 39 | auto arr = min; 40 | 41 | do { 42 | visit_tuple(arr); 43 | } while (rt::next_tuple( std::begin(arr), std::end(arr) 44 | , std::begin(min), std::begin(max))); 45 | } 46 | 47 | template 48 | void visit2(const std::vector& arr) 49 | { 50 | for (unsigned i = 0; i < arr.size(); ++i) 51 | std::cout << arr[i]; 52 | std::cout << std::endl; 53 | } 54 | 55 | void all_tuples_recursive(std::vector arr, unsigned idx) 56 | { 57 | static const std::vector min {0, 1, 1, 1}; 58 | static const std::vector max {2, 3, 2, 3}; 59 | 60 | if (idx == arr.size()) { 61 | visit2(arr); 62 | return; 63 | } 64 | 65 | for (auto i = min[idx]; i <= max[idx]; ++i) { 66 | arr[idx] = i; 67 | all_tuples_recursive(arr, idx + 1); 68 | } 69 | } 70 | 71 | void visit_binary_tuple(int v, const std::string& str) 72 | { 73 | for (unsigned i = 0; i < str.size(); ++i) 74 | if (v & (1 << i)) 75 | std::cout << str[str.size() - i - 1]; 76 | std::cout << "\n"; 77 | } 78 | 79 | void binary_tuples() 80 | { 81 | std::string str {'z', 'r', 'k', 'g'}; 82 | 83 | auto v = (1 << str.size()) - 1; 84 | do { 85 | visit_binary_tuple(v, str); 86 | } while (v-- != 0); 87 | } 88 | 89 | void visit_combination(const std::vector& arr) 90 | { 91 | if (arr.size() < 2) 92 | return; 93 | 94 | for (unsigned i = 0; i < arr.size() - 2; ++i) 95 | std::cout << arr[i]; 96 | std::cout << std::endl; 97 | } 98 | 99 | void all_combinations() 100 | { 101 | int n = 5; 102 | std::vector v {0, 1, 2, n, 0}; 103 | 104 | do { 105 | visit_combination(v); 106 | } while (rt::next_combination(v)); 107 | } 108 | 109 | void all_partitions() 110 | { 111 | rt::next_partition part(6); 112 | do { 113 | rt::visit_partition(part.a, part.last); 114 | } while (part.next()); 115 | } 116 | 117 | //________________________________________________ 118 | 119 | void visit_permutation(const std::vector& v, int b = 1) 120 | { 121 | for (unsigned i = b; i < v.size(); ++i) 122 | std::cout << v[i] << " "; 123 | std::cout << std::endl; 124 | } 125 | 126 | void all_permutations() 127 | { 128 | std::vector v{0, 1, 2, 3, 4}; 129 | do { 130 | visit_permutation(v); 131 | } while (rt::next_permutation(std::begin(v), std::end(v))); 132 | } 133 | 134 | void visit_permutation(const std::deque& v) 135 | { 136 | for (unsigned i = 0; i < v.size(); ++i) 137 | std::cout << v[i]; 138 | std::cout << std::endl; 139 | } 140 | 141 | void perm_rec( std::stack s 142 | , std::deque d = {}) 143 | { 144 | if (s.empty()) { 145 | visit_permutation(d); 146 | return; 147 | } 148 | 149 | d.push_front(s.top()); 150 | s.pop(); 151 | 152 | unsigned i = 0, j = 1; 153 | for (;;) { 154 | perm_rec(s, d); 155 | if (j == d.size()) break; 156 | std::swap(d[i++], d[j++]); 157 | } 158 | } 159 | 160 | template 161 | void shuffle_recursive( std::stack s, Rand& rand 162 | , std::deque d = {}) 163 | { 164 | if (s.empty()) { 165 | visit_permutation(d); 166 | return; 167 | } 168 | 169 | d.push_front(s.top()); 170 | s.pop(); 171 | 172 | auto i = rand() % d.size(); 173 | std::swap(d.front(), d[i]); 174 | shuffle_recursive(s, rand, d); 175 | } 176 | 177 | template 178 | void shuffle_recursive2( std::vector& v, int i 179 | , Rand& rand) 180 | { 181 | if (i == 0) 182 | return; 183 | 184 | shuffle_recursive2(v, i - 1, rand); 185 | 186 | auto j = rand() % (i + 1); 187 | std::swap(v[i], v[j]); 188 | visit_permutation(v, 0); 189 | } 190 | 191 | void test_inverse_perm( std::vector a, std::vector b 192 | , bool begin_at_zero) 193 | { 194 | rt::inplace_inverse_perm(std::begin(a), std::end(a), begin_at_zero); 195 | 196 | if (b != a) 197 | throw std::runtime_error("Inverse permutation."); 198 | } 199 | 200 | void test_unpermute() 201 | { 202 | std::vector input {4, 8, 2, 5, 1, 6, 7, 3, 9}; 203 | std::vector perm {3, 7, 1, 4, 0, 5, 6, 2, 8}; 204 | rt::unpermute(std::begin(input), std::end(input), std::begin(perm)); 205 | 206 | const auto b = std::is_sorted(std::begin(input), std::end(input)); 207 | if (!b) 208 | throw std::runtime_error("test_unpermute"); 209 | 210 | for (auto o : input) 211 | std::cout << o << " "; 212 | std::cout << std::endl; 213 | 214 | for (auto o : perm) 215 | std::cout << o << " "; 216 | std::cout << std::endl; 217 | } 218 | 219 | void test_permute() 220 | { 221 | std::vector input {4, 8, 2, 5, 1, 6, 7, 3, 9}; 222 | std::vector perm {4, 2, 7, 0, 3, 5, 6, 1, 8}; 223 | rt::permute(std::begin(input), std::end(input), std::begin(perm)); 224 | 225 | const auto b = std::is_sorted(std::begin(input), std::end(input)); 226 | if (!b) 227 | throw std::runtime_error("test_unpermute"); 228 | 229 | for (auto o : input) 230 | std::cout << o << " "; 231 | std::cout << std::endl; 232 | 233 | for (auto o : perm) 234 | std::cout << o << " "; 235 | std::cout << std::endl; 236 | } 237 | 238 | RT_TEST(test_transpose1) 239 | { 240 | constexpr auto r = 2; 241 | constexpr auto c = 4; 242 | 243 | const std::vector mat {1, 2, 3, 4, 5, 6, 7, 8}; 244 | const std::vector trans {1, 5, 2, 6, 3, 7, 4, 8}; 245 | 246 | auto m1 = mat; 247 | rt::print(m1); 248 | 249 | const auto index1 = [=](auto i) 250 | { return (r * i) % (r * c - 1); }; 251 | 252 | rt::unpermute_on_the_fly(std::begin(m1), std::end(m1) - 1, index1); 253 | rt::print(m1); 254 | RT_CHECK(m1 == trans) 255 | 256 | const auto index2 = [=](auto i) 257 | { return (c * i) % (r * c - 1); }; 258 | 259 | rt::unpermute_on_the_fly(std::begin(m1), std::end(m1) - 1, index2); 260 | rt::print(m1); 261 | 262 | RT_CHECK(m1 == mat) 263 | } 264 | 265 | RT_TEST(test_transpose3) 266 | { 267 | constexpr auto r = 2; 268 | constexpr auto c = 4; 269 | 270 | const std::vector mat {1, 2, 3, 4, 5, 6, 7, 8}; 271 | const std::vector trans {1, 5, 2, 6, 3, 7, 4, 8}; 272 | 273 | constexpr auto bit = 1 << 30; 274 | const auto set_bit = [=](auto& o) {o |= bit;}; 275 | const auto unset_bit = [=](auto& o) {o &= ~bit;}; 276 | const auto is_set = [=](auto& o) {return o & bit;}; 277 | 278 | auto m1 = mat; 279 | rt::print(m1); 280 | 281 | const auto index_a = [=](auto i) 282 | { return (r * i) % (r * c - 1); }; 283 | 284 | rt::unpermute_on_the_fly_bit( std::begin(m1), std::end(m1) - 1 285 | , index_a, set_bit, unset_bit, is_set); 286 | rt::print(m1); 287 | RT_CHECK(m1 == trans) 288 | 289 | const auto index_b = [=](auto i) 290 | { return (c * i) % (r * c - 1); }; 291 | 292 | rt::unpermute_on_the_fly_bit( std::begin(m1), std::end(m1) - 1 293 | , index_b, set_bit, unset_bit, is_set); 294 | rt::print(m1); 295 | 296 | RT_CHECK(m1 == mat) 297 | } 298 | 299 | RT_TEST(test_mirror_x) 300 | { 301 | constexpr auto c = 4; 302 | 303 | const std::vector mat {1, 2, 3, 4, 5, 6, 7, 8}; 304 | const std::vector trans {4, 3, 2, 1, 8, 7, 6, 5}; 305 | 306 | auto m1 = mat; 307 | rt::print(m1); 308 | 309 | const auto index = [=](auto i) 310 | { return c - 1 - (i % c) + c * (i / c); }; 311 | 312 | rt::unpermute_on_the_fly(std::begin(m1), std::end(m1), index); 313 | rt::print(m1); 314 | RT_CHECK(m1 == trans) 315 | 316 | rt::unpermute_on_the_fly(std::begin(m1), std::end(m1), index); 317 | rt::print(m1); 318 | 319 | RT_CHECK(m1 == mat) 320 | } 321 | 322 | int main() 323 | { 324 | try { 325 | std::cout << "Next Combination." << std::endl; 326 | all_combinations(); 327 | std::cout << "All all_partitions." << std::endl; 328 | rt::all_partitions_loop(6); 329 | std::cout << "Next partition." << std::endl; 330 | all_partitions(); 331 | std::cout << "All tuples rucursive" << std::endl; 332 | all_tuples_recursive(std::vector{1, 1, 1}, 0); 333 | std::cout << "Next tuple." << std::endl; 334 | all_tuples(); 335 | std::cout << "Next tuple stl." << std::endl; 336 | all_tuples_stl(); 337 | std::cout << "Binary tuple." << std::endl; 338 | binary_tuples(); 339 | std::cout << "All permutations." << std::endl; 340 | all_permutations(); 341 | 342 | std::cout << "All permutations recursive." << std::endl; 343 | std::stack s{{1, 2, 3}}; 344 | perm_rec(s); 345 | 346 | std::cout << "Shuffle array recursive1." << std::endl; 347 | 348 | std::mt19937 gen {}; 349 | std::uniform_int_distribution dist(0, 51); 350 | 351 | const auto rand = [&](){return dist(gen);}; 352 | 353 | std::stack s2 {{1, 2, 3, 4, 5, 6, 7}}; 354 | shuffle_recursive(s2, rand); 355 | 356 | std::cout << "Shuffle array recursive2." << std::endl; 357 | std::vector vec {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; 358 | shuffle_recursive2(vec, vec.size() - 1, rand); 359 | 360 | std::cout << "Shuffle array." << std::endl; 361 | std::vector vec2 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; 362 | std::uniform_real_distribution<> real_dist {}; 363 | const auto real_rand = [&](){ return real_dist(gen);}; 364 | rt::shuffle(vec2, real_rand); 365 | visit_permutation(vec2, 0); 366 | std::cout << "Random permutation." << std::endl; 367 | visit_permutation(rt::random_permutation(30, real_rand), 0); 368 | 369 | test_inverse_perm({4, 1, 3, 2}, {2, 4, 3, 1}, false); 370 | test_inverse_perm({3, 0, 1, 2}, {1, 2, 3, 0}, true); 371 | std::cout << "Test unpermute." << std::endl; 372 | test_unpermute(); 373 | std::cout << "Test permute." << std::endl; 374 | test_permute(); 375 | std::cout << "Test unpermute_on_the_fly." << std::endl; 376 | test_transpose1(); 377 | std::cout << "Test unpermute_on_the_fly_bit." << std::endl; 378 | test_transpose3(); 379 | std::cout << "Test mirror_x." << std::endl; 380 | test_mirror_x(); 381 | } catch (...) { 382 | return 1; 383 | } 384 | return 0; 385 | } 386 | 387 | -------------------------------------------------------------------------------- /src/test_matrix.cpp: -------------------------------------------------------------------------------- 1 | #include "rtcpp.hpp" 2 | 3 | using namespace rt; 4 | 5 | typedef matrix vec3; 6 | typedef matrix vec4; 7 | typedef matrix vec6; 8 | typedef matrix mat1; 9 | typedef matrix mat3; 10 | typedef matrix mat6; 11 | 12 | 13 | template 14 | matrix gen_mat() 15 | { 16 | matrix mat = {1, 2, 3, 4}; 17 | return mat; 18 | } 19 | 20 | bool test_div1() 21 | { 22 | typedef matrix mat_type; 23 | 24 | mat_type m1(1); 25 | const mat_type tmp = m1 / 2 + m1 / 2; 26 | const bool b1 = std::abs(tmp(0, 0) - 1) < 1e-15; 27 | const bool b2 = std::abs(tmp(0, 1) - 1) < 1e-15; 28 | const bool b3 = std::abs(tmp(1, 0) - 1) < 1e-15; 29 | const bool b4 = std::abs(tmp(1, 1) - 1) < 1e-15; 30 | return b1 && b2 && b3 && b4; 31 | } 32 | 33 | bool test_div2() 34 | { 35 | typedef matrix mat_type; 36 | 37 | mat_type m1(2); 38 | m1 /= 2; 39 | const bool b1 = std::abs(m1(0, 0) - 1) < 1e-15; 40 | const bool b2 = std::abs(m1(0, 1) - 1) < 1e-15; 41 | const bool b3 = std::abs(m1(1, 0) - 1) < 1e-15; 42 | const bool b4 = std::abs(m1(1, 1) - 1) < 1e-15; 43 | return b1 && b2 && b3 && b4; 44 | } 45 | 46 | bool test_mult1() 47 | { 48 | typedef matrix mat_type; 49 | 50 | mat_type m1(1); 51 | const mat_type m2 = 1024 * m1; 52 | const mat_type m3 = m1 * m1 * m1 * m1 * m1 * m1 * m1 * m1 * m1 * m1 * m1; 53 | return m3 == m2; 54 | } 55 | 56 | bool test_mult2() 57 | { 58 | typedef matrix mat_type1; 59 | typedef matrix mat_type2; 60 | typedef matrix mat_type3; 61 | 62 | mat_type1 m1(1); 63 | mat_type2 m2(1); 64 | const mat_type3 m3 = m1 * m2; 65 | return m3(0, 0) == 2; 66 | } 67 | 68 | bool test_mult3() 69 | { 70 | typedef matrix mat_type1; 71 | 72 | mat_type1 m1; 73 | m1(0, 0) = 5; 74 | m1(0, 1) = 7; 75 | m1(1, 0) = 3; 76 | m1(1, 1) = 4; 77 | mat_type1 m2; 78 | m2(0, 0) = 1; 79 | m2(0, 1) = 8; 80 | m2(1, 0) = 10; 81 | m2(1, 1) = 6; 82 | mat_type1 m3; 83 | m3(0, 0) = 75; 84 | m3(0, 1) = 82; 85 | m3(1, 0) = 43; 86 | m3(1, 1) = 48; 87 | const mat_type1 m4 = m1 * m2; 88 | return m3 == m4; 89 | } 90 | 91 | bool test_assign_plus_minus() 92 | { 93 | typedef matrix mat_type; 94 | mat_type m1(1), m2(1), m3(2), m4(3); 95 | 96 | m1 += m1; 97 | if (m1 != m3) 98 | return false; 99 | m1 -= m2; 100 | if (m1 != m2) 101 | return false; 102 | m1 += m1 + m2; 103 | if (m1 != m4) 104 | return false; 105 | return true; 106 | } 107 | 108 | bool test_assign_scalar_mult() 109 | { 110 | typedef matrix mat_type; 111 | mat_type m1(1), m2(3); 112 | m1 *= 3; 113 | if (m1 == m2) 114 | return true; 115 | return false; 116 | } 117 | 118 | bool test_assign_mult() 119 | { 120 | typedef matrix mat_type; 121 | mat_type m1(1), m2(2), m3(3), m4(12); 122 | m1 *= m3; 123 | 124 | if (m1 != m3) 125 | return false; 126 | 127 | m2 *= m2 * m3; 128 | if (m1 != m4) 129 | return false; 130 | 131 | return true; 132 | } 133 | 134 | int main() 135 | { 136 | typedef matrix mat_type; 137 | 138 | const mat_type mat1 = gen_mat(); 139 | 140 | // Tests operator() 141 | if ((mat1(0, 0) != 1) || (mat1(0, 1) != 2) || (mat1(1, 0) != 3) || (mat1(1, 1) != 4)) 142 | return 1; 143 | 144 | const mat_type mat2 = gen_mat(); 145 | if (mat1 != mat2) 146 | return 1; 147 | 148 | const mat_type tmp1(mat1); 149 | if (tmp1 != mat1) 150 | return 1; 151 | 152 | const mat_type tmp2 = mat1; 153 | if (tmp2 != mat1) 154 | return 1; 155 | 156 | const mat_type tmp3 = 2 * tmp2 + 3 * mat2 - 4 * tmp1; 157 | if (tmp3 != mat1) 158 | return 1; 159 | 160 | if (!test_mult1()) 161 | return 1; 162 | 163 | if (!test_mult2()) 164 | return 1; 165 | 166 | if (!test_mult3()) 167 | return 1; 168 | 169 | if (!test_assign_plus_minus()) 170 | return 1; 171 | 172 | if (!test_assign_scalar_mult()) 173 | return 1; 174 | 175 | if (!test_div1()) 176 | return 1; 177 | 178 | if (!test_div2()) 179 | return 1; 180 | 181 | std::cout << "tmp1:\n"; 182 | std::cout << tmp1 << "\n"; 183 | std::cout << "tmp2:\n"; 184 | std::cout << tmp2 << "\n"; 185 | std::cout << "tmp3:\n"; 186 | std::cout << tmp3 << "\n"; 187 | 188 | return 0; 189 | } 190 | 191 | -------------------------------------------------------------------------------- /src/test_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "rtcpp.hpp" 9 | #include "test.hpp" 10 | 11 | namespace 12 | { 13 | const auto sort_size = 5000; 14 | } 15 | 16 | #define TEST_SORT(name) \ 17 | void test_##name() \ 18 | { \ 19 | auto data = \ 20 | rt::make_rand_data(sort_size, 1, \ 21 | std::numeric_limits::max()); \ 22 | \ 23 | rt::name(std::begin(data), std::end(data)); \ 24 | \ 25 | const auto b = \ 26 | std::is_sorted(std::begin(data), std::end(data)); \ 27 | if (!b) \ 28 | throw std::runtime_error(#name); \ 29 | } 30 | 31 | // Code fragment useful to debug. 32 | //void test_sort() 33 | //{ 34 | // std::vector data {4, 7, 2, 1, 8, 9, 4, 5, 2, 1, 8}; 35 | // rt::print(data); 36 | // 37 | // rt::straight_selection(std::begin(data), std::end(data)); 38 | // 39 | // const auto b = std::is_sorted(std::begin(data), std::end(data)); 40 | // if (!b) 41 | // throw std::runtime_error("Insertion sort error."); 42 | // 43 | // rt::print(data); 44 | //} 45 | 46 | TEST_SORT(bubble_sort); 47 | TEST_SORT(comparison_counting_sort); 48 | TEST_SORT(inplace_comparison_counting_sort); 49 | TEST_SORT(straight_insertion); 50 | TEST_SORT(straight_selection); 51 | TEST_SORT(tree_insertion_sort); 52 | TEST_SORT(binary_insertion); 53 | 54 | void test_merge_sort() 55 | { 56 | //auto data = rt::make_rand_data(20, 1, 100, 1); 57 | std::vector data1 {1, 2, 3, 5, 7, 9}; 58 | std::vector data2 {3, 4, 5, 6, 8, 10}; 59 | rt::print(data1); 60 | rt::print(data2); 61 | 62 | std::vector vec; 63 | rt::merge( std::begin(data1), std::end(data1) 64 | , std::begin(data2), std::end(data2) 65 | , std::back_inserter(vec)); 66 | 67 | const auto b = std::is_sorted(std::begin(vec), std::end(vec)); 68 | if (!b) 69 | throw std::runtime_error("Merge sort error."); 70 | 71 | rt::print(vec); 72 | } 73 | 74 | void test_dist_count_sort() 75 | { 76 | auto N = 200000; 77 | auto A = -20; 78 | auto B = 200; 79 | auto data = rt::make_rand_data(N ,A ,B); 80 | 81 | rt::dist_counting_sort(std::begin(data), std::end(data), A, B); 82 | 83 | const auto b = std::is_sorted(std::begin(data), std::end(data)); 84 | if (!b) 85 | throw std::runtime_error("test_dist_count_sort"); 86 | } 87 | 88 | int main() 89 | { 90 | try { 91 | test_bubble_sort(); 92 | test_comparison_counting_sort(); 93 | test_tree_insertion_sort(); 94 | std::cout << "test_inplace_comparison_counting_sort" << std::endl; 95 | test_inplace_comparison_counting_sort(); 96 | std::cout << "Insertion sort." << std::endl; 97 | test_dist_count_sort(); 98 | std::cout << "Insertion sort." << std::endl; 99 | test_straight_insertion(); 100 | std::cout << "Straight selection." << std::endl; 101 | test_straight_selection(); 102 | std::cout << "Merge sort." << std::endl; 103 | test_merge_sort(); 104 | std::cout << "Test binary insertion sort." << std::endl; 105 | test_binary_insertion(); 106 | } catch (const std::exception& e) { 107 | std::cerr << "Error: " << e.what() << std::endl; 108 | return 1; 109 | } 110 | return 0; 111 | } 112 | 113 | -------------------------------------------------------------------------------- /src/test_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "rtcpp.hpp" 9 | #include "test.hpp" 10 | 11 | template 12 | void traversal_tester( const std::vector& input 13 | , const std::vector& expected) 14 | { 15 | rt::bst_node root {}; 16 | for (auto o : input) 17 | rt::bst_insert(root, o); 18 | 19 | using iter = rt::bst_iter; 20 | 21 | auto b = std::equal( iter {root.left} 22 | , iter {} 23 | , std::begin(expected)); 24 | if (!b) 25 | throw std::runtime_error("traversal_tester"); 26 | } 27 | 28 | RT_TEST(test_bst_inorder) 29 | { 30 | (void)f; 31 | std::vector v {20, 3, 2, 8, 5}; 32 | 33 | rt::bst_node root {}; 34 | for (auto o : v) 35 | bst_insert(root, o); 36 | 37 | std::cout << "test_bst_inorder" << std::endl; 38 | std::cout << "inorder_recursive" << std::endl; 39 | rt::inorder_recursive(root.left); 40 | std::cout << "inorder_traversal" << std::endl; 41 | inorder_traversal(root.left); 42 | std::cout << "inorder_traversal2" << std::endl; 43 | inorder_traversal2(root.left); 44 | std::cout << "inorder_traversal3" << std::endl; 45 | 46 | using iter = rt::bst_iter; 47 | std::for_each( iter {root.left}, iter {} 48 | , [](auto o){std::cout << o << std::endl;}); 49 | std::cout << "inorder_traversal4" << std::endl; 50 | std::copy( iter {root.left}, iter {} 51 | , std::ostream_iterator(std::cout, " ")); 52 | std::cout << std::endl; 53 | 54 | traversal_tester({}, {}); 55 | 56 | traversal_tester( {6, 3, 5, 2, 4, 1} 57 | , {1, 2, 3, 4, 5, 6}); 58 | } 59 | 60 | void test_bst_preorder() 61 | { 62 | std::cout << "test_bst_preorder" << std::endl; 63 | 64 | std::vector v {20, 3, 2, 8, 5}; 65 | 66 | rt::bst_node root {}; 67 | for (auto o : v) 68 | bst_insert(root, o); 69 | 70 | std::cout << "preorder_recursive" << std::endl; 71 | rt::preorder_recursive(root.left); 72 | 73 | std::cout << "preorder_traversal" << std::endl; 74 | preorder_traversal(root.left); 75 | 76 | std::cout << "preorder_traversal2" << std::endl; 77 | preorder_traversal2(root.left); 78 | 79 | traversal_tester({}, {}); 80 | 81 | traversal_tester( {8, 3, 2, 7, 5, 9} 82 | , {8, 3, 2, 7, 5, 9}); 83 | 84 | traversal_tester( {1, 2, 3, 4, 5, 6} 85 | , {1, 2, 3, 4, 5, 6}); 86 | 87 | traversal_tester( {6, 5, 4, 3, 2, 1} 88 | , {6, 5, 4, 3, 2, 1}); 89 | } 90 | 91 | void test_bst_postorder() 92 | { 93 | std::cout << "test_bst_postorder" << std::endl; 94 | 95 | std::vector v {20, 3, 2, 8, 5}; 96 | 97 | rt::bst_node root {}; 98 | for (auto o : v) 99 | bst_insert(root, o); 100 | 101 | std::cout << "postorder_recursive" << std::endl; 102 | rt::postorder_recursive(root.left); 103 | std::cout << "postorder_traversal" << std::endl; 104 | rt::postorder_traversal(root.left); 105 | 106 | //traversal_tester({}, {}); 107 | 108 | //traversal_tester( {8, 3, 2, 7, 5, 9} 109 | // , {2, 5, 7, 3, 9, 8}); 110 | 111 | //traversal_tester( {1, 2, 3, 4, 5, 6} 112 | // , {6, 5, 4, 3, 2, 1}); 113 | 114 | } 115 | 116 | void test_bst_copy() 117 | { 118 | std::cout << "test_bst_copy" << std::endl; 119 | 120 | std::vector v {20, 3, 2, 8, 5}; 121 | 122 | rt::bst_node from {}; 123 | for (auto o : v) 124 | bst_insert(from, o); 125 | 126 | rt::bst_node to {}; 127 | copy(&from, &to); 128 | 129 | using preorder_iter = rt::bst_iter; 130 | auto b = std::equal( preorder_iter {from.left} 131 | , preorder_iter {} 132 | , preorder_iter {to.left}); 133 | if (!b) 134 | throw std::runtime_error("test_bst_copy"); 135 | 136 | using inorder_iter = rt::bst_iter; 137 | b = std::equal( inorder_iter {from.left} 138 | , inorder_iter {} 139 | , inorder_iter {to.left}); 140 | if (!b) 141 | throw std::runtime_error("test_bst_copy"); 142 | 143 | //using postorder_iter = rt::bst_iter; 144 | //auto b = std::equal( postorder_iter {from.left} 145 | // , postorder_iter {} 146 | // , postorder_iter {to.left}); 147 | //if (!b) 148 | // throw std::runtime_error("test_bst_copy"); 149 | } 150 | 151 | int main() 152 | { 153 | try { 154 | test_bst_preorder(); 155 | test_bst_inorder(); 156 | test_bst_postorder(); 157 | } catch (...) { 158 | std::cerr << "Error." << std::endl; 159 | return 1; 160 | } 161 | return 0; 162 | } 163 | 164 | -------------------------------------------------------------------------------- /src/tool_bench_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rtcpp.hpp" 5 | 6 | using namespace rt; 7 | 8 | void sort_benchmark(int size, int repeat) 9 | { 10 | auto first = std::numeric_limits::min(); 11 | auto last = std::numeric_limits::max(); 12 | 13 | auto vec = make_rand_data(size * repeat, first, last, 1); 14 | 15 | { // std::sort 16 | auto vec_copy = vec; 17 | timer t; 18 | for (auto i = 0; i < repeat; ++i) { 19 | auto begin = std::begin(vec_copy) + i * size; 20 | auto end = begin + size; 21 | std::sort(begin, end); 22 | } 23 | auto c = t.get_count(); 24 | std::cout << c << " "; 25 | } 26 | 27 | { // Insertion sort 28 | auto vec_copy = vec; 29 | timer t; 30 | for (auto i = 0; i < repeat; ++i) { 31 | auto begin = std::begin(vec_copy) + i * size; 32 | auto end = begin + size; 33 | rt::straight_insertion(begin, end); 34 | } 35 | auto c = t.get_count(); 36 | std::cout << c << " "; 37 | } 38 | 39 | { // Straight selection 40 | auto vec_copy = vec; 41 | timer t; 42 | for (auto i = 0; i < repeat; ++i) { 43 | auto begin = std::begin(vec_copy) + i * size; 44 | auto end = begin + size; 45 | rt::straight_selection(begin, end); 46 | } 47 | auto c = t.get_count(); 48 | std::cout << c << " "; 49 | } 50 | 51 | std::cout << std::endl; 52 | } 53 | 54 | int main() 55 | { 56 | auto size = 15; 57 | auto repeat = 80000; 58 | 59 | for (auto i = 0; i < 30; ++i) { 60 | auto s = size + i * 5; 61 | std::cout << s << " "; 62 | sort_benchmark(s, repeat); 63 | } 64 | std::cin.ignore(); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/tool_book.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | void print(int a, int b, int step, Mean mean, Sigma sigma) 7 | { 8 | std::cout.precision(2); 9 | for (auto i = a; i < b; i += step) 10 | std::cout << "(" << std::setw(3) << i << ", " 11 | << std::fixed << std::right << mean(i) << ") +- (0, " 12 | << std::fixed << std::right << sigma(i) << ")" 13 | << std::endl; 14 | } 15 | 16 | auto harm_number = [](auto n) 17 | { 18 | double sum = 1; 19 | for (auto i = 2; i <= n; ++i) 20 | sum += double(1) / i; 21 | 22 | return sum; 23 | }; 24 | 25 | auto riemann_zeta2 = [] (auto n) 26 | { 27 | double sum = 1; 28 | for (auto i = 2; i <= n; ++i) 29 | sum += double(1) / (i * i); 30 | 31 | return sum; 32 | }; 33 | 34 | void linear_search_stat() 35 | { 36 | // Equal prob. 37 | const auto mean_equal_prob = [](auto n) 38 | { 39 | return double(n + 1) / 2; 40 | }; 41 | 42 | const auto sigma_equal_prob = [](auto n) 43 | { 44 | double v = n * n - 1; 45 | return std::sqrt(v / 12); 46 | }; 47 | 48 | // Zipf 49 | const auto mean_zipf = [=](auto n) 50 | { 51 | return double(n) / harm_number(n); 52 | }; 53 | 54 | const auto sigma_zipf = [=](auto n) 55 | { 56 | auto hn = harm_number(n); 57 | double v = double(n * (n + 1)) / (2 * hn) - n * n / (hn * hn); 58 | return std::sqrt(v); 59 | }; 60 | 61 | auto a = 50; 62 | auto b = 151; 63 | auto step = 8; 64 | 65 | std::cout << "\nEqual Probs\n\n"; 66 | print(a, b, step, mean_equal_prob, sigma_equal_prob); 67 | std::cout << "\nZipf law\n\n"; 68 | print(a + 4, b + 4, step, mean_zipf, sigma_zipf); 69 | } 70 | 71 | 72 | void max_element_stat() 73 | { 74 | auto a = 10; 75 | auto b = a + 151; 76 | auto step = 12; 77 | 78 | const auto sigma = [&] (auto n) 79 | { 80 | auto hn = harm_number(n); 81 | auto rz2 = riemann_zeta2(n); 82 | return std::sqrt(hn + rz2); 83 | }; 84 | 85 | print(a, b, step, harm_number, sigma); 86 | } 87 | 88 | void inversions_stat() 89 | { 90 | auto a = 10; 91 | auto b = a + 21; 92 | auto step = 2; 93 | 94 | const auto mean = [&] (auto n) 95 | { 96 | return n * (n - 1) / 4; 97 | }; 98 | 99 | const auto sigma = [&] (auto n) 100 | { 101 | auto v = n * (n - 1) * (2 * n + 5) / 72; 102 | return std::sqrt(v); 103 | }; 104 | 105 | print(a, b, step, mean, sigma); 106 | } 107 | 108 | int main() 109 | { 110 | std::cout << "\nLinear search\n"; 111 | linear_search_stat(); 112 | std::cout << "\nMax element\n"; 113 | max_element_stat(); 114 | std::cout << "\nInversions\n"; 115 | inversions_stat(); 116 | } 117 | 118 | --------------------------------------------------------------------------------