diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/algorithm_ut.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/algorithm_ut.cpp')
-rw-r--r-- | util/generic/algorithm_ut.cpp | 850 |
1 files changed, 850 insertions, 0 deletions
diff --git a/util/generic/algorithm_ut.cpp b/util/generic/algorithm_ut.cpp new file mode 100644 index 0000000000..8d732fcc0c --- /dev/null +++ b/util/generic/algorithm_ut.cpp @@ -0,0 +1,850 @@ +#include <library/cpp/testing/unittest/registar.h> + +#include "algorithm.h" +#include "strbuf.h" +#include "string.h" + +static auto isOne = [](char c) { return c == '1'; }; + +Y_UNIT_TEST_SUITE(TAlgorithm) { + Y_UNIT_TEST(AnyTest) { + UNIT_ASSERT(0 == AnyOf(TStringBuf("00"), isOne)); + UNIT_ASSERT(1 == AnyOf(TStringBuf("01"), isOne)); + UNIT_ASSERT(1 == AnyOf(TStringBuf("10"), isOne)); + UNIT_ASSERT(1 == AnyOf(TStringBuf("11"), isOne)); + UNIT_ASSERT(0 == AnyOf(TStringBuf(), isOne)); + + const char array00[]{'0', '0'}; + UNIT_ASSERT(0 == AnyOf(array00, isOne)); + const char array01[]{'0', '1'}; + UNIT_ASSERT(1 == AnyOf(array01, isOne)); + } + + Y_UNIT_TEST(AllOfTest) { + UNIT_ASSERT(0 == AllOf(TStringBuf("00"), isOne)); + UNIT_ASSERT(0 == AllOf(TStringBuf("01"), isOne)); + UNIT_ASSERT(0 == AllOf(TStringBuf("10"), isOne)); + UNIT_ASSERT(1 == AllOf(TStringBuf("11"), isOne)); + UNIT_ASSERT(1 == AllOf(TStringBuf(), isOne)); + + const char array01[]{'0', '1'}; + UNIT_ASSERT(0 == AllOf(array01, isOne)); + const char array11[]{'1', '1'}; + UNIT_ASSERT(1 == AllOf(array11, isOne)); + } + + Y_UNIT_TEST(CountIfTest) { + UNIT_ASSERT(3 == CountIf(TStringBuf("____1________1____1_______"), isOne)); + UNIT_ASSERT(5 == CountIf(TStringBuf("1____1________1____1_______1"), isOne)); + UNIT_ASSERT(0 == CountIf(TStringBuf("___________"), isOne)); + UNIT_ASSERT(0 == CountIf(TStringBuf(), isOne)); + UNIT_ASSERT(1 == CountIf(TStringBuf("1"), isOne)); + + const char array[] = "____1________1____1_______"; + UNIT_ASSERT(3 == CountIf(array, isOne)); + } + + Y_UNIT_TEST(CountTest) { + UNIT_ASSERT(3 == Count("____1________1____1_______", '1')); + UNIT_ASSERT(3 == Count(TStringBuf("____1________1____1_______"), '1')); + UNIT_ASSERT(5 == Count(TStringBuf("1____1________1____1_______1"), '1')); + UNIT_ASSERT(0 == Count(TStringBuf("___________"), '1')); + UNIT_ASSERT(0 == Count(TStringBuf(), '1')); + UNIT_ASSERT(1 == Count(TStringBuf("1"), '1')); + + const char array[] = "____1________1____1_______"; + UNIT_ASSERT(3 == Count(array, '1')); + } + + struct TStrokaNoCopy: TString { + public: + TStrokaNoCopy(const char* p) + : TString(p) + { + } + + private: + TStrokaNoCopy(const TStrokaNoCopy&); + void operator=(const TStrokaNoCopy&); + }; + + Y_UNIT_TEST(CountOfTest) { + UNIT_ASSERT_VALUES_EQUAL(CountOf(1, 2), 0); + UNIT_ASSERT_VALUES_EQUAL(CountOf(1, 1), 1); + UNIT_ASSERT_VALUES_EQUAL(CountOf(2, 4, 5), 0); + UNIT_ASSERT_VALUES_EQUAL(CountOf(2, 4, 2), 1); + UNIT_ASSERT_VALUES_EQUAL(CountOf(3, 3, 3), 2); + + // Checking comparison of different types. + UNIT_ASSERT_VALUES_EQUAL(CountOf(0x61, 'x', 'y', 'z'), 0); + UNIT_ASSERT_VALUES_EQUAL(CountOf(0x61, 'a', 'b', 'c', 0x61), 2); + UNIT_ASSERT_VALUES_EQUAL(CountOf(0x61, 'a', 'b', 'c', 0x61ll), 2); + + // TString and const char * + UNIT_ASSERT_VALUES_EQUAL(CountOf(TString("xyz"), "123", "poi"), 0); + UNIT_ASSERT_VALUES_EQUAL(CountOf(TString("xyz"), "123", "poi", "xyz"), 1); + + // TString and TStringBuf + UNIT_ASSERT_VALUES_EQUAL(CountOf(TString("xyz"), TStringBuf("123"), TStringBuf("poi")), 0); + UNIT_ASSERT_VALUES_EQUAL(CountOf(TString("xyz"), TStringBuf("123"), TStringBuf("poi"), + TStringBuf("xyz")), + 1); + + // TStringBuf and const char * + UNIT_ASSERT_VALUES_EQUAL(CountOf(TStringBuf("xyz"), "123", "poi"), 0); + UNIT_ASSERT_VALUES_EQUAL(CountOf(TStringBuf("xyz"), "123", "poi", "xyz"), 1); + + // TStringBuf and TString + UNIT_ASSERT_VALUES_EQUAL(CountOf(TStringBuf("xyz"), TString("123"), TString("poi")), 0); + UNIT_ASSERT_VALUES_EQUAL(CountOf(TStringBuf("xyz"), TString("123"), TString("poi"), + TString("xyz")), + 1); + } + + Y_UNIT_TEST(EqualToOneOfTest) { + UNIT_ASSERT(1 == EqualToOneOf(1, 1, 2)); + UNIT_ASSERT(1 == EqualToOneOf(2, 1, 2)); + UNIT_ASSERT(0 == EqualToOneOf(3, 1, 2)); + UNIT_ASSERT(1 == EqualToOneOf(1, 1)); + UNIT_ASSERT(0 == EqualToOneOf(1, 2)); + UNIT_ASSERT(0 == EqualToOneOf(3)); + + //test, that EqualToOneOf can compare different types, and don't copy objects: + TStrokaNoCopy x("x"); + TStrokaNoCopy y("y"); + TStrokaNoCopy z("z"); + const char* px = "x"; + const char* py = "y"; + const char* pz = "z"; + + UNIT_ASSERT(1 == EqualToOneOf(x, px, py)); + UNIT_ASSERT(1 == EqualToOneOf(y, px, py)); + UNIT_ASSERT(1 == EqualToOneOf(y, px, y)); + UNIT_ASSERT(1 == EqualToOneOf(y, x, py)); + UNIT_ASSERT(0 == EqualToOneOf(z, px, py)); + UNIT_ASSERT(1 == EqualToOneOf(px, x, y)); + UNIT_ASSERT(1 == EqualToOneOf(py, x, y)); + UNIT_ASSERT(0 == EqualToOneOf(pz, x, y)); + } + + template <class TTestConstPtr> + void TestFindPtrFoundValue(int j, TTestConstPtr root) { + if (j == 3) { + UNIT_ASSERT(root && *root == 3); + } else if (j == 4) { + UNIT_ASSERT(root == nullptr); + } else { + ythrow yexception() << "invalid param " << j; + } + } + + template <class TTestConstPtr> + void TestFindIfPtrFoundValue(int j, TTestConstPtr root) { + if (j == 3) { + UNIT_ASSERT(root == nullptr); + } else if (j == 4) { + UNIT_ASSERT(root && *root == 2); + } else { + ythrow yexception() << "invalid param " << j; + } + } + + struct TVectorNoCopy: std::vector<int> { + public: + TVectorNoCopy() = default; + + private: + TVectorNoCopy(const TVectorNoCopy&); + void operator=(const TVectorNoCopy&); + }; + + Y_UNIT_TEST(FindPtrTest) { + TVectorNoCopy v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + + int array[3] = {1, 2, 3}; + const int array_const[3] = {1, 2, 3}; + + //test (const, non-const) * (iterator, vector, array) * (found, not found) variants. + // value '3' is in container, value '4' is not + for (int j = 3; j <= 4; ++j) { + TestFindPtrFoundValue<int*>(j, FindPtr(v, j)); + TestFindPtrFoundValue<int*>(j, FindPtr(v.begin(), v.end(), j)); + const TVectorNoCopy& q = v; + TestFindPtrFoundValue<const int*>(j, FindPtr(q, j)); + TestFindPtrFoundValue<const int*>(j, FindPtr(q.begin(), q.end(), j)); + TestFindPtrFoundValue<int*>(j, FindPtr(array, j)); + TestFindPtrFoundValue<const int*>(j, FindPtr(array_const, j)); + } + } + + Y_UNIT_TEST(FindIfPtrTest) { + TVectorNoCopy v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + + int array[3] = {1, 2, 3}; + const int array_const[3] = {1, 2, 3}; + + //test (const, non-const) * (iterator, vector, array) * (found, not found) variants. + // search, that 2*2 == 4, but there is no value 'x' in array that (x*x == 3) + for (int j = 3; j <= 4; ++j) { + TestFindIfPtrFoundValue<int*>(j, FindIfPtr(v, [j](int i) { return i * i == j; })); + TestFindIfPtrFoundValue<int*>(j, FindIfPtr(v.begin(), v.end(), [j](int i) { return i * i == j; })); + const TVectorNoCopy& q = v; + TestFindIfPtrFoundValue<const int*>(j, FindIfPtr(q, [j](int i) { return i * i == j; })); + + TestFindIfPtrFoundValue<const int*>(j, FindIfPtr(q.begin(), q.end(), [j](int i) { return i * i == j; })); + TestFindIfPtrFoundValue<int*>(j, FindIfPtr(array, [j](int i) { return i * i == j; })); + TestFindIfPtrFoundValue<const int*>(j, FindIfPtr(array_const, [j](int i) { return i * i == j; })); + } + } + + Y_UNIT_TEST(FindIndexTest) { + TVectorNoCopy v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + + UNIT_ASSERT_EQUAL(0, FindIndex(v, 1)); + UNIT_ASSERT_EQUAL(1, FindIndex(v, 2)); + UNIT_ASSERT_EQUAL(2, FindIndex(v, 3)); + UNIT_ASSERT_EQUAL(NPOS, FindIndex(v, 42)); + + int array[3] = {1, 2, 3}; + + UNIT_ASSERT_EQUAL(0, FindIndex(array, 1)); + UNIT_ASSERT_EQUAL(1, FindIndex(array, 2)); + UNIT_ASSERT_EQUAL(2, FindIndex(array, 3)); + UNIT_ASSERT_EQUAL(NPOS, FindIndex(array, 42)); + + TVector<int> empty; + UNIT_ASSERT_EQUAL(NPOS, FindIndex(empty, 0)); + } + + Y_UNIT_TEST(FindIndexIfTest) { + TVectorNoCopy v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + + UNIT_ASSERT_EQUAL(0, FindIndexIf(v, [](int x) { return x == 1; })); + UNIT_ASSERT_EQUAL(1, FindIndexIf(v, [](int x) { return x == 2; })); + UNIT_ASSERT_EQUAL(2, FindIndexIf(v, [](int x) { return x == 3; })); + UNIT_ASSERT_EQUAL(NPOS, FindIndexIf(v, [](int x) { return x == 42; })); + + int array[3] = {1, 2, 3}; + + UNIT_ASSERT_EQUAL(0, FindIndexIf(array, [](int x) { return x == 1; })); + UNIT_ASSERT_EQUAL(1, FindIndexIf(array, [](int x) { return x == 2; })); + UNIT_ASSERT_EQUAL(2, FindIndexIf(array, [](int x) { return x == 3; })); + UNIT_ASSERT_EQUAL(NPOS, FindIndexIf(array, [](int x) { return x == 42; })); + + TVector<int> empty; + UNIT_ASSERT_EQUAL(NPOS, FindIndexIf(empty, [](int x) { return x == 3; })); + } + + Y_UNIT_TEST(SortUniqueTest) { + { + TVector<TString> v; + SortUnique(v); + UNIT_ASSERT_EQUAL(v, TVector<TString>()); + } + + { + const char* ar[] = {"345", "3", "123", "2", "23", "3", "2"}; + TVector<TString> v(ar, ar + Y_ARRAY_SIZE(ar)); + SortUnique(v); + + const char* suAr[] = {"123", "2", "23", "3", "345"}; + TVector<TString> suV(suAr, suAr + Y_ARRAY_SIZE(suAr)); + + UNIT_ASSERT_EQUAL(v, suV); + } + } + + Y_UNIT_TEST(EraseTest) { + TVector<int> data = {5, 4, 3, 2, 1, 0}; + TVector<int> expected = {5, 4, 2, 1, 0}; + Erase(data, 3); + UNIT_ASSERT_EQUAL(data, expected); + } + + Y_UNIT_TEST(EraseIfTest) { + TVector<int> data = {5, 4, 3, 2, 1, 0}; + TVector<int> expected = {2, 1, 0}; + EraseIf(data, [](int i) { return i >= 3; }); + UNIT_ASSERT_EQUAL(data, expected); + } + + Y_UNIT_TEST(EraseNodesIfTest) { + TMap<int, int> map{{1, 1}, {2, 2}, {3, 5}}; + TMap<int, int> expectedMap{{1, 1}}; + EraseNodesIf(map, [](auto p) { return p.first >= 2; }); + UNIT_ASSERT_EQUAL(map, expectedMap); + + TMultiMap<int, int> multiMap{{1, 1}, {1, 3}, {2, 2}, {3, 5}}; + TMultiMap<int, int> expectedMultiMap{{1, 1}, {1, 3}}; + EraseNodesIf(multiMap, [](auto p) { return p.first >= 2; }); + UNIT_ASSERT_EQUAL(multiMap, expectedMultiMap); + + TSet<int> set{1, 2, 3, 4, 5, 6, 7}; + TSet<int> expectedSet{1, 3, 5, 7}; + EraseNodesIf(set, [](int i) { return i % 2 == 0; }); + UNIT_ASSERT_EQUAL(set, expectedSet); + + TMultiSet<int> multiSet{1, 1, 2, 3, 4, 4, 4, 5, 5, 5, 6, 7}; + TMultiSet<int> expectedMultiSet{1, 1, 3, 5, 5, 5, 7}; + EraseNodesIf(multiSet, [](int i) { return i % 2 == 0; }); + UNIT_ASSERT_EQUAL(multiSet, expectedMultiSet); + + THashMap<int, int> hashMap{{1, 0}, {3, 0}, {4, 0}, {10, 0}, {2, 0}, {5, 2}}; + THashMap<int, int> expectedHashMap{{1, 0}, {3, 0}, {5, 2}}; + EraseNodesIf(hashMap, [](auto p) { return p.first % 2 == 0; }); + UNIT_ASSERT_EQUAL(hashMap, expectedHashMap); + + THashMultiMap<int, int> hashMultiMap{{1, 0}, {3, 0}, {4, 0}, {10, 0}, {2, 0}, {5, 0}, {1, 0}, {1, 0}, {2, 0}, {2, 2}}; + THashMultiMap<int, int> expectedHashMultiMap{{1, 0}, {1, 0}, {1, 0}, {3, 0}, {5, 0}}; + EraseNodesIf(hashMultiMap, [](auto p) { return p.first % 2 == 0; }); + UNIT_ASSERT_EQUAL(hashMultiMap, expectedHashMultiMap); + } + + Y_UNIT_TEST(NthElementTest) { + { + TVector<TString> v; + NthElement(v.begin(), v.begin(), v.end()); + UNIT_ASSERT_EQUAL(v, TVector<TString>()); + } + + { + int data[] = {3, 2, 1, 4, 6, 5, 7, 9, 8}; + TVector<int> testVector(data, data + Y_ARRAY_SIZE(data)); + + size_t medianInd = testVector.size() / 2; + + NthElement(testVector.begin(), testVector.begin() + medianInd, testVector.end()); + UNIT_ASSERT_EQUAL(testVector[medianInd], 5); + + NthElement(testVector.begin(), testVector.begin() + medianInd, testVector.end(), [](int lhs, int rhs) { return lhs > rhs; }); + UNIT_ASSERT_EQUAL(testVector[medianInd], 5); + } + + { + const char* data[] = {"3", "234", "1231", "333", "545345", "11", "111", "55", "66"}; + TVector<TString> testVector(data, data + Y_ARRAY_SIZE(data)); + + size_t medianInd = testVector.size() / 2; + NthElement(testVector.begin(), testVector.begin() + medianInd, testVector.end()); + + auto median = testVector.begin() + medianInd; + for (auto it0 = testVector.begin(); it0 != median; ++it0) { + for (auto it1 = median; it1 != testVector.end(); ++it1) { + UNIT_ASSERT(*it0 <= *it1); + } + } + } + } + + Y_UNIT_TEST(BinarySearchTest) { + { + TVector<TString> v; + bool test = BinarySearch(v.begin(), v.end(), "test"); + UNIT_ASSERT_EQUAL(test, false); + } + + { + int data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + + bool test = BinarySearch(data, data + Y_ARRAY_SIZE(data), 2); + UNIT_ASSERT_EQUAL(test, true); + + test = BinarySearch(data, data + Y_ARRAY_SIZE(data), 10); + UNIT_ASSERT_EQUAL(test, false); + } + + { + TVector<size_t> data = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + bool test = BinarySearch(data.begin(), data.end(), (size_t)9, TGreater<size_t>()); + UNIT_ASSERT_EQUAL(test, true); + + test = BinarySearch(data.begin(), data.end(), (size_t)11, TGreater<size_t>()); + UNIT_ASSERT_EQUAL(test, false); + + test = BinarySearch(data.rbegin(), data.rend(), (size_t)1); + UNIT_ASSERT_EQUAL(test, true); + } + } + + Y_UNIT_TEST(EqualRangeTest) { + { + TVector<TString> v; + using PairOfVector = std::pair<TVector<TString>::iterator, TVector<TString>::iterator>; + PairOfVector tmp = EqualRange(v.begin(), v.end(), "tmp"); + + UNIT_ASSERT_EQUAL(tmp.first, tmp.second); + UNIT_ASSERT_EQUAL(tmp.first, v.end()); + } + + { + int data[] = {1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 5}; + using PairOfInt = std::pair<int*, int*>; + PairOfInt tmp = EqualRange(data, data + Y_ARRAY_SIZE(data), 3); + + UNIT_ASSERT_EQUAL(tmp.second - tmp.first, 4); + UNIT_ASSERT_EQUAL(tmp.first - data, 7); + UNIT_ASSERT_EQUAL(data + Y_ARRAY_SIZE(data) - tmp.second, 2); + } + + { + TVector<size_t> data = {9, 9, 8, 8, 8, 5, 4, 3, 3, 0, 0}; + + using PairOfVector = std::pair<TVector<size_t>::iterator, TVector<size_t>::iterator>; + PairOfVector tmp = EqualRange(data.begin(), data.end(), 8, TGreater<size_t>()); + + UNIT_ASSERT_EQUAL(tmp.first - data.begin(), 2); + UNIT_ASSERT_EQUAL(tmp.second - tmp.first, 3); + + using PairOfVectorReverse = std::pair<TVector<size_t>::reverse_iterator, TVector<size_t>::reverse_iterator>; + PairOfVectorReverse tmpR = EqualRange(data.rbegin(), data.rend(), (size_t)0); + + UNIT_ASSERT_EQUAL(tmpR.first, data.rbegin()); + UNIT_ASSERT_EQUAL(tmpR.second - tmpR.first, 2); + } + } + + Y_UNIT_TEST(IsSortedTest) { + TVector<int> v0; + UNIT_ASSERT_VALUES_EQUAL(IsSorted(v0.begin(), v0.end()), true); + + TVector<int> v1 = {1, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8}; + UNIT_ASSERT_VALUES_EQUAL(IsSorted(v1.begin(), v1.end()), true); + UNIT_ASSERT_VALUES_EQUAL(IsSorted(v1.begin(), v1.end(), TLess<int>()), true); + UNIT_ASSERT_VALUES_EQUAL(IsSorted(v1.begin(), v1.end(), TGreater<int>()), false); + + TVector<int> v2 = {1, 2, 1}; + UNIT_ASSERT_VALUES_EQUAL(IsSorted(v2.begin(), v2.end()), false); + UNIT_ASSERT_VALUES_EQUAL(IsSorted(v2.begin(), v2.end(), TLess<int>()), false); + UNIT_ASSERT_VALUES_EQUAL(IsSorted(v2.begin(), v2.end(), TGreater<int>()), false); + } + + Y_UNIT_TEST(IsSortedByTest) { + TVector<int> v0; + UNIT_ASSERT_VALUES_EQUAL(IsSortedBy(v0.begin(), v0.end(), std::negate<int>()), true); + + TVector<int> v1 = {1}; + UNIT_ASSERT_VALUES_EQUAL(IsSortedBy(v1.begin(), v1.end(), std::negate<int>()), true); + + TVector<int> v2 = {8, 7, 6, 6, 5, 5, 5, 4, 3, 2, 1}; + UNIT_ASSERT_VALUES_EQUAL(IsSortedBy(v2.begin(), v2.end(), std::negate<int>()), true); + + TVector<int> v3 = {1, 2, 1}; + UNIT_ASSERT_VALUES_EQUAL(IsSortedBy(v3.begin(), v3.end(), std::negate<int>()), false); + } + + Y_UNIT_TEST(SortTestTwoIterators) { + TVector<int> collection = {10, 2, 7}; + Sort(collection.begin(), collection.end()); + TVector<int> expected = {2, 7, 10}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(SortTestTwoIteratorsAndComparator) { + TVector<int> collection = {10, 2, 7}; + Sort(collection.begin(), collection.end(), [](int l, int r) { return l > r; }); + TVector<int> expected = {10, 7, 2}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(SortTestContainer) { + TVector<int> collection = {10, 2, 7}; + Sort(collection); + TVector<int> expected = {2, 7, 10}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(SortTestContainerAndComparator) { + TVector<int> collection = {10, 2, 7}; + Sort(collection, [](int l, int r) { return l > r; }); + TVector<int> expected = {10, 7, 2}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(StableSortTestTwoIterators) { + TVector<int> collection = {10, 2, 7}; + StableSort(collection.begin(), collection.end()); + TVector<int> expected = {2, 7, 10}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(StableSortTestTwoIteratorsAndComparator) { + TVector<int> collection = {404, 101, 106, 203, 102, 205, 401}; + StableSort(collection.begin(), collection.end(), [](int l, int r) { return (l / 100) < (r / 100); }); + TVector<int> expected = {101, 106, 102, 203, 205, 404, 401}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(StableSortTestContainer) { + TVector<int> collection = {10, 2, 7}; + StableSort(collection); + TVector<int> expected = {2, 7, 10}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(StableSortTestContainerAndComparator) { + TVector<int> collection = {404, 101, 106, 203, 102, 205, 401}; + StableSort(collection, [](int l, int r) { return (l / 100) < (r / 100); }); + TVector<int> expected = {101, 106, 102, 203, 205, 404, 401}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(SortByTest) { + TVector<int> collection = {10, 2, 7}; + SortBy(collection, [](int x) { return -x; }); + TVector<int> expected = {10, 7, 2}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(StableSortByTest) { + TVector<int> collection = {404, 101, 106, 203, 102, 205, 401}; + StableSortBy(collection, [](int x) { return x / 100; }); + TVector<int> expected = {101, 106, 102, 203, 205, 404, 401}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(SortUniqueByTest) { + TVector<int> collection = {404, 101, 101, 203, 101, 203, 404}; + StableSortUniqueBy(collection, [](int x) { return x / 100; }); + TVector<int> expected = {101, 203, 404}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(StableSortUniqueByTest) { + TVector<int> collection = {404, 101, 106, 203, 102, 205, 401}; + StableSortUniqueBy(collection, [](int x) { return x / 100; }); + TVector<int> expected = {101, 203, 404}; + UNIT_ASSERT_VALUES_EQUAL(collection, expected); + } + + Y_UNIT_TEST(IotaTest) { + TVector<int> v(10); + + Iota(v.begin(), v.end(), 0); + UNIT_ASSERT_VALUES_EQUAL(v[0], 0); + UNIT_ASSERT_VALUES_EQUAL(v[5], 5); + UNIT_ASSERT_VALUES_EQUAL(v[9], 9); + + Iota(v.begin() + 2, v.begin() + 5, 162); + UNIT_ASSERT_VALUES_EQUAL(v[0], 0); + UNIT_ASSERT_VALUES_EQUAL(v[3], 163); + UNIT_ASSERT_VALUES_EQUAL(v[9], 9); + } + + Y_UNIT_TEST(CopyNTest) { + int data[] = {1, 2, 3, 4, 8, 7, 6, 5}; + const size_t vSize = 10; + TVector<int> result(10, 0); + size_t toCopy = 5; + + TVector<int>::iterator iter = CopyN(data, toCopy, result.begin()); + UNIT_ASSERT_VALUES_EQUAL(iter - result.begin(), toCopy); + UNIT_ASSERT_VALUES_EQUAL(result.size(), 10); + for (size_t idx = 0; idx < toCopy; ++idx) { + UNIT_ASSERT_VALUES_EQUAL(data[idx], result[idx]); + } + for (size_t idx = toCopy; idx < vSize; ++idx) { + UNIT_ASSERT_VALUES_EQUAL(result[idx], 0); + } + + toCopy = 8; + const size_t start = 1; + result.assign(vSize, 0); + iter = CopyN(data, toCopy, result.begin() + start); + UNIT_ASSERT_VALUES_EQUAL(iter - result.begin(), start + toCopy); + for (size_t idx = 0; idx < start; ++idx) { + UNIT_ASSERT_VALUES_EQUAL(result[idx], 0); + } + for (size_t idx = 0; idx < toCopy; ++idx) { + UNIT_ASSERT_VALUES_EQUAL(result[start + idx], data[idx]); + } + for (size_t idx = start + toCopy; idx < vSize; ++idx) { + UNIT_ASSERT_VALUES_EQUAL(result[idx], 0); + } + } + + Y_UNIT_TEST(CopyIfTest) { + const size_t count = 9; + int data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + const size_t vSize = 10; + TVector<int> v(vSize, 0); + + TVector<int>::iterator iter = CopyIf(data, data + count, v.begin(), [](int x) { return !(x % 3); }); + UNIT_ASSERT_VALUES_EQUAL(v.size(), vSize); + UNIT_ASSERT_VALUES_EQUAL(iter - v.begin(), 3); + v.resize(iter - v.begin()); + for (size_t idx = 0; idx < v.size(); ++idx) { + UNIT_ASSERT_VALUES_EQUAL(v[idx], 3 * (idx + 1)); + } + } + + Y_UNIT_TEST(MinMaxElementTest) { + TVector<int> v(10); + Iota(v.begin(), v.end(), 0); + UNIT_ASSERT_EQUAL(*MinMaxElement(v.begin(), v.end()).first, 0); + UNIT_ASSERT_EQUAL(*MinMaxElement(v.begin(), v.end()).second, 9); + + v[3] = -2; + v[7] = 11; + UNIT_ASSERT_EQUAL(*MinMaxElement(v.begin(), v.end()).first, -2); + UNIT_ASSERT_EQUAL(*MinMaxElement(v.begin(), v.end()).second, 11); + } + + Y_UNIT_TEST(MinMaxTest) { + std::pair<int, int> p1 = MinMax(5, 12); + UNIT_ASSERT_EQUAL(p1.first, 5); + UNIT_ASSERT_EQUAL(p1.second, 12); + + std::pair<TString, TString> p2 = MinMax(TString("test"), TString("data")); + UNIT_ASSERT_EQUAL(p2.first, TString("data")); + UNIT_ASSERT_EQUAL(p2.second, TString("test")); + } + + Y_UNIT_TEST(TestMaxElementBy) { + const int array[] = {1, 2, 5, 3, 4, 5}; + UNIT_ASSERT_VALUES_EQUAL(*MaxElementBy(array, [](int x) { + return x * x; + }), 5); + + const TVector<int> vec(array, array + Y_ARRAY_SIZE(array)); + UNIT_ASSERT_VALUES_EQUAL(*MaxElementBy(vec, [](int x) { + return -1.0 * x; + }), 1); + + int arrayMutable[] = {1, 2, 5, 3, 4, 5}; + auto maxPtr = MaxElementBy(arrayMutable, [](int x) { return x; }); + *maxPtr += 100; + UNIT_ASSERT_VALUES_EQUAL(*maxPtr, 105); + + auto identity = [](char x) { + return x; + }; + auto singleElementSequence = {'z'}; + UNIT_ASSERT_VALUES_EQUAL(*MaxElementBy(singleElementSequence, identity), 'z'); + + const TString strings[] = {"one", "two", "three", "four"}; + UNIT_ASSERT_STRINGS_EQUAL(*MaxElementBy(strings, [](TString s) { return s.size(); }), "three"); + } + + Y_UNIT_TEST(TestMinElementBy) { + const int array[] = {2, 3, 4, 1, 5}; + UNIT_ASSERT_VALUES_EQUAL(*MinElementBy(array, [](int x) -> char { + return 'a' + x; + }), 1); + + const TVector<int> vec(std::begin(array), std::end(array)); + UNIT_ASSERT_VALUES_EQUAL(*MinElementBy(vec, [](int x) { + return -x; + }), 5); + + int arrayMutable[] = {1, 2, 5, 3, 4, 5}; + auto minPtr = MinElementBy(arrayMutable, [](int x) { return x; }); + *minPtr += 100; + UNIT_ASSERT_VALUES_EQUAL(*minPtr, 101); + + auto identity = [](char x) { + return x; + }; + auto singleElementSequence = {'z'}; + UNIT_ASSERT_VALUES_EQUAL(*MinElementBy(singleElementSequence, identity), 'z'); + + const TVector<TStringBuf> strings = {"one", "two", "three", "four"}; + auto stringLength = [](TStringBuf s) { + return s.size(); + }; + UNIT_ASSERT_STRINGS_EQUAL(*MinElementBy(strings, stringLength), "one"); + UNIT_ASSERT_STRINGS_EQUAL(*MinElementBy(strings.rbegin(), strings.rend(), stringLength), "two"); + } + + Y_UNIT_TEST(MaxElementByReturnsEndForEmptyRange) { + const TVector<int> empty; + UNIT_ASSERT_EQUAL(MaxElementBy(empty, [](int) { return 0; }), empty.end()); + } + + Y_UNIT_TEST(MaxElementByDoesntCallFunctorForEmptyRange) { + const TVector<int> empty; + auto functor = [](int) { + UNIT_ASSERT(false); + return 0; + }; + MaxElementBy(empty, functor); + } + + Y_UNIT_TEST(MinElementByReturnsEndForEmptyRange) { + const TVector<int> empty; + UNIT_ASSERT_EQUAL(MinElementBy(empty, [](int) { return 0; }), empty.end()); + } + + Y_UNIT_TEST(MinElementByDoesntCallFunctorForEmptyRange) { + const TVector<int> empty; + auto functor = [](int) { + UNIT_ASSERT(false); + return 0; + }; + MinElementBy(empty, functor); + } + + Y_UNIT_TEST(TestApplyToMany) { + int res = 0; + ApplyToMany([&res](auto v) { res += v; }, 1, 2, 3, 4, 5); + UNIT_ASSERT_EQUAL(res, 15); + + struct TVisitor { + TVisitor(int& acc) + : Acc(acc) + { + } + void operator()(const TString& s) { + Acc += s.size(); + }; + void operator()(int v) { + Acc += v * 2; + }; + int& Acc; + }; + TString s{"8-800-555-35-35"}; + ApplyToMany(TVisitor{res = 0}, 1, s, 5, s); + UNIT_ASSERT_EQUAL(res, 12 + 2 * static_cast<int>(s.size())); + } + + Y_UNIT_TEST(TestTupleForEach) { + ForEach(std::tuple<>{}, [&](auto) { UNIT_ASSERT(false); }); + auto t = std::make_tuple(5, 6, 2, 3, 6); + ForEach(t, [](auto& v) { v *= -1; }); + UNIT_ASSERT_EQUAL(t, std::make_tuple(-5, -6, -2, -3, -6)); + } + + Y_UNIT_TEST(TestTupleAllOf) { + UNIT_ASSERT(AllOf(std::tuple<>{}, [](auto) { return false; })); + UNIT_ASSERT(!AllOf(std::make_tuple(1, 2, 0, 4, 5), [&](auto v) { UNIT_ASSERT_LT(v, 3); return 0 != v; })); + UNIT_ASSERT(AllOf(std::make_tuple(1, 2, 3, 4, 5), [](auto v) { return 0 != v; })); + { + auto pred = std::function<bool(int)>([x = TVector<int>(1, 0)](auto v) { return x.front() != v; }); + UNIT_ASSERT(AllOf(std::make_tuple(1, 2), pred)); + UNIT_ASSERT(AllOf(std::make_tuple(1, 2), pred)); + } + { + auto ts = std::make_tuple(TString{"foo"}, TString{"bar"}); + auto pred = [](auto s) { return s.size() == 3; }; + UNIT_ASSERT_VALUES_EQUAL(AllOf(ts, pred), AllOf(ts, pred)); + } + } + + Y_UNIT_TEST(TestTupleAnyOf) { + UNIT_ASSERT(!AnyOf(std::tuple<>{}, [](auto) { return true; })); + UNIT_ASSERT(AnyOf(std::make_tuple(0, 1, 2, 3, 4), [&](auto v) { UNIT_ASSERT_LT(v, 2); return 1 == v; })); + UNIT_ASSERT(AnyOf(std::make_tuple(1, 2, 3, 4, 5), [](auto v) { return 5 == v; })); + auto pred = std::function<bool(int)>([x = TVector<int>(1, 0)](auto v) { return x.front() == v; }); + UNIT_ASSERT(!AnyOf(std::make_tuple(1, 2), pred)); + UNIT_ASSERT(!AnyOf(std::make_tuple(1, 2), pred)); + { + auto ts = std::make_tuple(TString{"f"}, TString{"bar"}); + auto pred = [](auto s) { return s.size() == 3; }; + UNIT_ASSERT_VALUES_EQUAL(AnyOf(ts, pred), AnyOf(ts, pred)); + } + } + + Y_UNIT_TEST(FindIfForContainer) { + using std::begin; + using std::end; + + int array[] = {1, 2, 3, 4, 5}; + UNIT_ASSERT_EQUAL(FindIf(array, [](int x) { return x == 1; }), begin(array)); + UNIT_ASSERT_EQUAL(FindIf(array, [](int x) { return x > 5; }), end(array)); + + TVector<int> vector = {1, 2, 3, 4, 5}; + UNIT_ASSERT_EQUAL(FindIf(vector, [](int x) { return x == 1; }), begin(vector)); + UNIT_ASSERT_EQUAL(FindIf(vector, [](int x) { return x > 5; }), end(vector)); + + // Compilability test. Check if the returned iterator is non const + auto iter = FindIf(vector, [](int x) { return x == 1; }); + *iter = 5; + + // Compilability test. Check if the returned iterator is const. Should not compile + const TVector<int> constVector = {1, 2, 3, 4, 5}; + auto constIter = FindIf(constVector, [](int x) { return x == 1; }); + Y_UNUSED(constIter); + // *constIter = 5; + } + + struct TRange { + }; + + const TRange* begin(const TRange& r) { + return &r; + } + + const TRange* end(const TRange& r) { + return &r + 1; + } + + Y_UNIT_TEST(FindIfForUserType) { + // Compileability test. Should work for user types with begin/end overloads + TRange range; + auto i = FindIf(range, [](auto) { return false; }); + Y_UNUSED(i); + } + + Y_UNIT_TEST(TestLowerBoundBy) { + using TIntPairs = TVector<std::pair<i32, i32>>; + + auto data = TIntPairs{{1, 5}, {3, 2}, {3, 4}, {8, 0}, {5, 4}}; + auto getKey = [](const auto& x) { return x.second; }; + + StableSortBy(data, getKey); + + auto it = LowerBoundBy(data.begin(), data.end(), 4, getKey); + UNIT_ASSERT(it != data.end()); + UNIT_ASSERT_EQUAL(it->second, 4); + UNIT_ASSERT_EQUAL(it->first, 3); + + UNIT_ASSERT(it > data.begin()); + UNIT_ASSERT_EQUAL((it - 1)->second, 2); + + UNIT_ASSERT((it + 1) < data.end()); + UNIT_ASSERT_EQUAL((it + 1)->second, 4); + } + + Y_UNIT_TEST(TestUpperBoundBy) { + using TIntPairs = TVector<std::pair<i32, i32>>; + + auto data = TIntPairs{{1, 5}, {3, 2}, {3, 4}, {8, 0}, {5, 4}}; + auto getKey = [](const auto& x) { return x.second; }; + + StableSortBy(data, getKey); + + auto it = UpperBoundBy(data.begin(), data.end(), 4, getKey); + UNIT_ASSERT(it != data.end()); + UNIT_ASSERT_EQUAL(it->second, 5); + UNIT_ASSERT_EQUAL(it->first, 1); + + UNIT_ASSERT(it > data.begin()); + UNIT_ASSERT_EQUAL((it - 1)->second, 4); + + UNIT_ASSERT((it + 1) == data.end()); + } + + Y_UNIT_TEST(TestFindInContainer) { + std::vector<int> v = {1, 2, 1000, 15, 100}; + UNIT_ASSERT(Find(v, 5) == v.end()); + UNIT_ASSERT(Find(v, 1) == v.begin()); + UNIT_ASSERT(Find(v, 100) == v.end() - 1); + } + + Y_UNIT_TEST(AccumulateWithBinOp) { + std::vector<int> v = {1, 2, 777}; + UNIT_ASSERT_VALUES_EQUAL(TString("begin;1;2;777"), Accumulate(v, TString("begin"), [](auto&& a, auto& b) { return a + ";" + ToString(b); })); + } +}; |