Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ahSort_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
38#include <gtest/gtest.h>
39
40#include <vector>
41#include <deque>
42#include <algorithm>
43#include <string>
44
45#include <ahSort.H>
46#include <tpl_dynArray.H>
47#include <tpl_dynList.H>
48#include <tpl_dynDlist.H>
49
50using namespace Aleph;
51using namespace std;
52
53// ============================================================================
54// Test Fixtures
55// ============================================================================
56
57class DynListSortTest : public ::testing::Test
58{
59protected:
61
62 void SetUp() override
63 {
64 list = DynList<int>{5, 2, 8, 1, 9, 3, 7, 4, 6, 0};
65 }
66
67 DynList<int> build_list(std::initializer_list<int> items)
68 {
70 for (int x : items)
71 l.append(x);
72 return l;
73 }
74};
75
76class DynDlistSortTest : public ::testing::Test
77{
78protected:
80
81 void SetUp() override
82 {
83 for (int x : {5, 2, 8, 1, 9, 3, 7, 4, 6, 0})
84 list.append(x);
85 }
86
87 DynDlist<int> build_list(std::initializer_list<int> items)
88 {
90 for (int x : items)
91 l.append(x);
92 return l;
93 }
94};
95
96class DynArraySortTest : public ::testing::Test
97{
98protected:
100
101 void SetUp() override
102 {
103 arr.reserve(10);
104 int values[] = {5, 2, 8, 1, 9, 3, 7, 4, 6, 0};
105 for (size_t i = 0; i < 10; ++i)
106 arr(i) = values[i];
107 }
108
109 DynArray<int> build_array(std::initializer_list<int> items)
110 {
112 a.reserve(items.size());
113 size_t i = 0;
114 for (int x : items)
115 a(i++) = x;
116 return a;
117 }
118};
119
120class ArraySortTest : public ::testing::Test
121{
122protected:
124
125 void SetUp() override
126 {
127 int values[] = {5, 2, 8, 1, 9, 3, 7, 4, 6, 0};
128 for (int v : values)
129 arr.append(v);
130 }
131
132 Array<int> build_array(std::initializer_list<int> items)
133 {
134 Array<int> a;
135 for (int x : items)
136 a.append(x);
137 return a;
138 }
139};
140
141// ============================================================================
142// DynList sort() tests
143// ============================================================================
144
146{
147 auto sorted = sort(list);
148
149 // Original unchanged
150 EXPECT_EQ(list.get_first(), 5);
151
152 // Result is sorted
153 int prev = -1;
154 sorted.for_each([&prev](int x) {
155 EXPECT_GT(x, prev);
156 prev = x;
157 });
158}
159
161{
162 auto sorted = sort(list, std::greater<int>());
163
164 // Descending order
165 int prev = 100;
166 sorted.for_each([&prev](int x) {
167 EXPECT_LT(x, prev);
168 prev = x;
169 });
170}
171
173{
174 DynList<int> temp = build_list({3, 1, 2});
175 auto sorted = sort(std::move(temp));
176
177 // Original moved from
179
180 // Result is sorted
183}
184
186{
187 in_place_sort(list);
188
189 // Original is now sorted
190 int prev = -1;
191 list.for_each([&prev](int x) {
192 EXPECT_GT(x, prev);
193 prev = x;
194 });
195}
196
202
204{
205 DynList<int> empty;
206 auto sorted = sort(empty);
208}
209
218
220{
221 DynList<int> already = build_list({1, 2, 3, 4, 5});
222 auto sorted = sort(already);
224}
225
227{
228 DynList<int> reversed = build_list({5, 4, 3, 2, 1});
229 auto sorted = sort(reversed);
232}
233
235{
236 DynList<int> dups = build_list({3, 1, 3, 1, 2, 2});
237 auto sorted = sort(dups);
239}
240
241// ============================================================================
242// DynDlist sort() tests
243// ============================================================================
244
246{
247 auto sorted = sort(list);
249 EXPECT_EQ(list.get_first(), 5); // Original unchanged
250}
251
253{
254 auto sorted = sort(list, std::greater<int>());
255
256 int prev = 100;
257 sorted.for_each([&prev](int x) {
258 EXPECT_LT(x, prev);
259 prev = x;
260 });
261}
262
264{
265 DynDlist<int> temp = build_list({3, 1, 2});
266 auto sorted = sort(std::move(temp));
269}
270
276
277// ============================================================================
278// DynArray sort() tests
279// ============================================================================
280
282{
283 auto sorted = sort(arr);
284
285 // Original unchanged
286 EXPECT_EQ(arr(0), 5);
287
288 // Result is sorted
289 for (size_t i = 1; i < sorted.size(); ++i)
290 EXPECT_LE(sorted(i-1), sorted(i));
291}
292
294{
295 auto sorted = sort(arr, std::greater<int>());
296
297 for (size_t i = 1; i < sorted.size(); ++i)
298 EXPECT_GE(sorted(i-1), sorted(i));
299}
300
302{
303 DynArray<int> temp = build_array({3, 1, 2});
304 auto sorted = sort(std::move(temp));
305
306 // Original should be empty after move
307 EXPECT_EQ(temp.size(), 0u);
308
309 // Result is sorted
310 EXPECT_EQ(sorted(0), 1);
311 EXPECT_EQ(sorted(1), 2);
312 EXPECT_EQ(sorted(2), 3);
313}
314
316{
317 in_place_sort(arr);
318
319 for (size_t i = 1; i < arr.size(); ++i)
320 EXPECT_LE(arr(i-1), arr(i));
321}
322
328
330{
331 DynArray<int> empty;
332 auto sorted = sort(empty);
333 EXPECT_EQ(sorted.size(), 0u);
334}
335
337{
339 single.reserve(1);
340 single.touch(0) = 42;
341 auto sorted = sort(single);
342 EXPECT_EQ(sorted.size(), 1u);
343 EXPECT_EQ(sorted(0), 42);
344}
345
346// ============================================================================
347// Array sort() tests
348// ============================================================================
349
351{
352 auto sorted = sort(arr);
353 EXPECT_EQ(arr(0), 5); // Original unchanged
354
355 for (size_t i = 1; i < sorted.size(); ++i)
356 EXPECT_LE(sorted(i-1), sorted(i));
357}
358
360{
361 Array<int> temp = build_array({3, 1, 2});
362 auto sorted = sort(std::move(temp));
363 EXPECT_EQ(sorted(0), 1);
364 EXPECT_EQ(sorted(2), 3);
365}
366
368{
369 in_place_sort(arr);
370 for (size_t i = 1; i < arr.size(); ++i)
371 EXPECT_LE(arr(i-1), arr(i));
372}
373
374// ============================================================================
375// stdsort() tests
376// ============================================================================
377
379{
380 std::vector<int> v = {5, 2, 8, 1, 9};
381 auto sorted = stdsort(v);
382
383 EXPECT_EQ(v[0], 5); // Original unchanged
384 EXPECT_EQ(sorted, (std::vector<int>{1, 2, 5, 8, 9}));
385}
386
388{
389 std::vector<int> v = {5, 2, 8, 1, 9};
390 auto sorted = stdsort(v, std::greater<int>());
391 EXPECT_EQ(sorted, (std::vector<int>{9, 8, 5, 2, 1}));
392}
393
395{
396 std::deque<int> d = {5, 2, 8, 1, 9};
397 auto sorted = stdsort(d);
398 EXPECT_EQ(sorted, (std::deque<int>{1, 2, 5, 8, 9}));
399}
400
402{
403 std::vector<int> empty;
404 auto sorted = stdsort(empty);
406}
407
408// ============================================================================
409// ranks() tests
410// ============================================================================
411
413{
414 DynArray<int> arr;
415 arr.reserve(3);
416 arr(0) = 30; // rank 2
417 arr(1) = 10; // rank 0
418 arr(2) = 20; // rank 1
419
420 auto r = ranks(arr);
421
422 EXPECT_EQ(r(0), 2u); // 30 is largest -> rank 2
423 EXPECT_EQ(r(1), 0u); // 10 is smallest -> rank 0
424 EXPECT_EQ(r(2), 1u); // 20 is middle -> rank 1
425}
426
428{
429 Array<int> arr;
430 arr.append(30);
431 arr.append(10);
432 arr.append(20);
433
434 auto r = ranks(arr);
435
436 EXPECT_EQ(r(0), 2u);
437 EXPECT_EQ(r(1), 0u);
438 EXPECT_EQ(r(2), 1u);
439}
440
442{
443 DynList<int> list;
444 list.append(30);
445 list.append(10);
446 list.append(20);
447
448 auto r = ranks(list);
449
450 EXPECT_EQ(r(0), 2u);
451 EXPECT_EQ(r(1), 0u);
452 EXPECT_EQ(r(2), 1u);
453}
454
456{
457 DynDlist<int> list;
458 list.append(30);
459 list.append(10);
460 list.append(20);
461
462 auto r = ranks(list);
463
464 EXPECT_EQ(r(0), 2u);
465 EXPECT_EQ(r(1), 0u);
466 EXPECT_EQ(r(2), 1u);
467}
468
470{
471 DynArray<int> empty;
472 auto r = ranks(empty);
473 EXPECT_EQ(r.size(), 0u);
474}
475
477{
479 single.reserve(1);
480 single.touch(0) = 42;
481 auto r = ranks(single);
482 EXPECT_EQ(r.size(), 1u);
483 EXPECT_EQ(r(0), 0u);
484}
485
487{
488 DynArray<int> arr;
489 arr.reserve(5);
490 for (size_t i = 0; i < 5; ++i)
491 arr(i) = static_cast<int>(i);
492
493 auto r = ranks(arr);
494
495 for (size_t i = 0; i < 5; ++i)
496 EXPECT_EQ(r(i), i);
497}
498
500{
501 DynArray<int> arr;
502 arr.reserve(5);
503 for (size_t i = 0; i < 5; ++i)
504 arr(i) = static_cast<int>(4 - i);
505
506 auto r = ranks(arr);
507
508 for (size_t i = 0; i < 5; ++i)
509 EXPECT_EQ(r(i), 4 - i);
510}
511
512// ============================================================================
513// pair_ranks() tests
514// ============================================================================
515
517{
518 DynArray<int> arr;
519 arr.reserve(3);
520 arr(0) = 30;
521 arr(1) = 10;
522 arr(2) = 20;
523
524 auto pr = pair_ranks(arr);
525
526 EXPECT_EQ(pr(0).first, 30);
527 EXPECT_EQ(pr(0).second, 2u);
528 EXPECT_EQ(pr(1).first, 10);
529 EXPECT_EQ(pr(1).second, 0u);
530 EXPECT_EQ(pr(2).first, 20);
531 EXPECT_EQ(pr(2).second, 1u);
532}
533
535{
536 Array<int> arr;
537 arr.append(30);
538 arr.append(10);
539 arr.append(20);
540
541 auto pr = pair_ranks(arr);
542
543 EXPECT_EQ(pr(0).first, 30);
544 EXPECT_EQ(pr(0).second, 2u);
545}
546
548{
549 DynList<int> list;
550 list.append(30);
551 list.append(10);
552 list.append(20);
553
554 auto pr = pair_ranks(list);
555
556 EXPECT_EQ(pr(0).first, 30);
557 EXPECT_EQ(pr(0).second, 2u);
558 EXPECT_EQ(pr(1).first, 10);
559 EXPECT_EQ(pr(1).second, 0u);
560}
561
563{
564 DynDlist<int> list;
565 list.append(30);
566 list.append(10);
567 list.append(20);
568
569 auto pr = pair_ranks(list);
570
571 EXPECT_EQ(pr(0).first, 30);
572 EXPECT_EQ(pr(0).second, 2u);
573}
574
575// ============================================================================
576// in_place_multisort_arrays() tests
577// ============================================================================
578
580{
581 std::vector<int> keys = {3, 1, 2};
582 std::vector<std::string> names = {"Charlie", "Alice", "Bob"};
583
584 in_place_multisort_arrays(std::less<int>(), keys, names);
585
586 EXPECT_EQ(keys, (std::vector<int>{1, 2, 3}));
587 EXPECT_EQ(names, (std::vector<std::string>{"Alice", "Bob", "Charlie"}));
588}
589
591{
592 std::vector<int> ids = {3, 1, 2};
593 std::vector<std::string> names = {"Charlie", "Alice", "Bob"};
594 std::vector<int> ages = {30, 25, 28};
595
596 in_place_multisort_arrays(std::less<int>(), ids, names, ages);
597
598 EXPECT_EQ(ids, (std::vector<int>{1, 2, 3}));
599 EXPECT_EQ(names, (std::vector<std::string>{"Alice", "Bob", "Charlie"}));
600 EXPECT_EQ(ages, (std::vector<int>{25, 28, 30}));
601}
602
604{
605 std::vector<int> keys = {1, 2, 3};
606 std::vector<char> values = {'a', 'b', 'c'};
607
608 in_place_multisort_arrays(std::greater<int>(), keys, values);
609
610 EXPECT_EQ(keys, (std::vector<int>{3, 2, 1}));
611 EXPECT_EQ(values, (std::vector<char>{'c', 'b', 'a'}));
612}
613
615{
616 std::vector<int> keys;
617 std::vector<int> values;
618
619 // Should not throw
620 in_place_multisort_arrays(std::less<int>(), keys, values);
621
622 EXPECT_TRUE(keys.empty());
623 EXPECT_TRUE(values.empty());
624}
625
627{
628 std::vector<int> keys = {42};
629 std::vector<std::string> values = {"answer"};
630
631 in_place_multisort_arrays(std::less<int>(), keys, values);
632
633 EXPECT_EQ(keys, (std::vector<int>{42}));
634 EXPECT_EQ(values, (std::vector<std::string>{"answer"}));
635}
636
638{
639 std::vector<int> keys = {2, 1, 2, 1, 2};
640 std::vector<char> aux = {'a', 'b', 'c', 'd', 'e'};
641
642 in_place_multisort_arrays(std::less<int>(), keys, aux);
643
644 EXPECT_EQ(keys, (std::vector<int>{1, 1, 2, 2, 2}));
645 // Stable: elements with equal keys preserve relative order
646 EXPECT_EQ(aux, (std::vector<char>{'b', 'd', 'a', 'c', 'e'}));
647}
648
650{
651 std::vector<int> keys = {1, 2, 3, 4, 5};
652 std::vector<int> values = {10, 20, 30, 40, 50};
653
654 in_place_multisort_arrays(std::less<int>(), keys, values);
655
656 EXPECT_EQ(keys, (std::vector<int>{1, 2, 3, 4, 5}));
657 EXPECT_EQ(values, (std::vector<int>{10, 20, 30, 40, 50}));
658}
659
661{
662 std::vector<int> keys = {5, 4, 3, 2, 1};
663 std::vector<int> values = {50, 40, 30, 20, 10};
664
665 in_place_multisort_arrays(std::less<int>(), keys, values);
666
667 EXPECT_EQ(keys, (std::vector<int>{1, 2, 3, 4, 5}));
668 EXPECT_EQ(values, (std::vector<int>{10, 20, 30, 40, 50}));
669}
670
672{
673 std::vector<int> keys = {1, 2};
674 std::vector<int> values = {10};
675
676 EXPECT_THROW(in_place_multisort_arrays(std::less<int>(), keys, values),
677 std::invalid_argument);
678}
679
681{
682 Array<int> keys;
683 keys.append(3); keys.append(1); keys.append(2);
684
685 Array<std::string> values;
686 values.append("c"); values.append("a"); values.append("b");
687
688 in_place_multisort_arrays(std::less<int>(), keys, values);
689
690 EXPECT_EQ(keys(0), 1);
691 EXPECT_EQ(keys(1), 2);
692 EXPECT_EQ(keys(2), 3);
693 EXPECT_EQ(values(0), "a");
694 EXPECT_EQ(values(1), "b");
695 EXPECT_EQ(values(2), "c");
696}
697
698// ============================================================================
699// Type traits and compile-time checks
700// ============================================================================
701
703{
704 // The [[nodiscard]] attribute is tested implicitly:
705 // If we call sort() without using the result, the compiler would warn.
706 // This test just verifies the functions compile correctly.
707 DynList<int> list;
708 list.append(1);
709 [[maybe_unused]] auto s1 = sort(list);
710 [[maybe_unused]] auto s2 = sort(std::move(list));
711}
712
714{
715 DynArray<int> arr;
716 arr.reserve(1);
717 arr.touch(0) = 1;
718 [[maybe_unused]] auto r = ranks(arr);
719}
720
722{
723 DynArray<int> arr;
724 arr.reserve(1);
725 arr.touch(0) = 1;
726 [[maybe_unused]] auto pr = pair_ranks(arr);
727}
728
729// ============================================================================
730// Edge cases and stress tests
731// ============================================================================
732
734{
735 DynList<int> list;
736 for (int i = 999; i >= 0; --i)
737 list.append(i);
738
739 auto sorted = sort(list);
742 EXPECT_EQ(sorted.get_last(), 999);
743}
744
746{
747 DynArray<int> arr;
748 arr.reserve(1000);
749 for (size_t i = 0; i < 1000; ++i)
750 arr(i) = static_cast<int>(999 - i);
751
752 in_place_sort(arr);
753
754 for (size_t i = 1; i < arr.size(); ++i)
755 EXPECT_LE(arr(i-1), arr(i));
756}
757
759{
760 DynList<int> list;
761 for (int i = 0; i < 100; ++i)
762 list.append(42);
763
764 auto sorted = sort(list);
766
767 sorted.for_each([](int x) {
768 EXPECT_EQ(x, 42);
769 });
770}
771
773{
775 list.append("banana");
776 list.append("apple");
777 list.append("cherry");
778
779 auto sorted = sort(list);
780
781 EXPECT_EQ(sorted.get_first(), "apple");
782 EXPECT_EQ(sorted.get_last(), "cherry");
783}
784
786{
787 DynArray<int> arr;
788 arr.reserve(5);
789 arr(0) = 1; arr(1) = 2; arr(2) = 3; arr(3) = 4; arr(4) = 5;
790
791 // Sort by absolute difference from 3
792 auto sorted = sort(arr, [](int a, int b) {
793 return std::abs(a - 3) < std::abs(b - 3);
794 });
795
796 EXPECT_EQ(sorted(0), 3); // difference 0
797}
High-level sorting functions for Aleph containers.
TEST_F(DynListSortTest, SortReturnsSortedCopy)
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:239
T & touch(const size_t i)
Touch the entry i.
size_t size() const noexcept
Return the current dimension of array.
void reserve(const size_t l, const size_t r)
Allocate a range of entries.
Dynamic doubly linked list with O(1) size and bidirectional access.
T & append(const T &item)
Append a copied item at the end of the list.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
T & get_last() const
Return the last item of the list.
Definition htlist.H:1663
T & get_first() const
Return the first item of the list.
Definition htlist.H:1675
void empty() noexcept
empty the list
Definition htlist.H:1689
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
void SetUp() override
Array< int > arr
Array< int > build_array(std::initializer_list< int > items)
DynArray< int > arr
void SetUp() override
DynArray< int > build_array(std::initializer_list< int > items)
DynDlist< int > list
void SetUp() override
DynDlist< int > build_list(std::initializer_list< int > items)
DynList< int > list
void SetUp() override
DynList< int > build_list(std::initializer_list< int > items)
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:685
#define TEST(name)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool is_sorted(const Container< T > &cont, const Compare &cmp=Compare())
Check if a container is sorted in ascending order.
auto pair_ranks(const Array< T > &c)
Computes (value, rank) pairs for each element in an Array.
Definition ahSort.H:587
void in_place_multisort_arrays(Cmp cmp, C &first, Args &... args)
Sorts multiple arrays in place, using the first array as the key.
Definition ahSort.H:668
DynArray< T > sort(const DynArray< T > &a, Cmp &&cmp=Cmp())
Returns a sorted copy of a DynArray.
Definition ahSort.H:227
DynArray< T > & in_place_sort(DynArray< T > &c, Cmp cmp=Cmp())
Sorts a DynArray in place.
Definition ahSort.H:321
Array< T > build_array(Args ... args)
Definition tpl_array.H:457
Array< size_t > ranks(const Array< T > &array)
Computes the rank of each element in an Array.
Definition ahSort.H:524
Container stdsort(const Container &c, Cmp cmp=Cmp())
Sorts an STL-compatible container using std::sort.
Definition ahSort.H:300
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Lazy and scalable dynamic array implementation.
Dynamic doubly linked list implementation.
Alias for htlist.H (DynList implementation).
DynList< int > l