#include "xrange.h" #include "algorithm.h" #include "maybe.h" #include "vector.h" #include <library/cpp/testing/unittest/registar.h> #include <util/string/builder.h> Y_UNIT_TEST_SUITE(XRange) { void TestXRangeImpl(size_t begin, size_t end) { size_t count = 0; size_t sum = 0; size_t first = 42; bool firstInited = false; size_t last = 0; for (auto i : xrange(begin, end)) { ++count; sum += i; last = i; if (!firstInited) { first = i; firstInited = true; } } UNIT_ASSERT_VALUES_EQUAL(count, end - begin); UNIT_ASSERT_VALUES_EQUAL(first, begin); UNIT_ASSERT_VALUES_EQUAL(last, end - 1); UNIT_ASSERT_VALUES_EQUAL(sum, count * (first + last) / 2); } void TestSteppedXRangeImpl(int begin, int end, int step, const TVector<int>& expected) { size_t expInd = 0; for (auto i : xrange(begin, end, step)) { UNIT_ASSERT(expInd < expected.size()); UNIT_ASSERT_VALUES_EQUAL(i, expected[expInd]); ++expInd; } UNIT_ASSERT_VALUES_EQUAL(expInd, expected.size()); } Y_UNIT_TEST(IncrementWorks) { TestXRangeImpl(0, 10); TestXRangeImpl(10, 20); } Y_UNIT_TEST(DecrementWorks) { TestSteppedXRangeImpl(10, 0, -1, {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}); TestSteppedXRangeImpl(10, -1, -1, {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}); TestSteppedXRangeImpl(20, 9, -1, {20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10}); } Y_UNIT_TEST(StepWorks) { TestSteppedXRangeImpl(0, 0, 1, {}); TestSteppedXRangeImpl(0, 9, 3, {0, 3, 6}); TestSteppedXRangeImpl(0, 10, 3, {0, 3, 6, 9}); TestSteppedXRangeImpl(0, 11, 3, {0, 3, 6, 9}); TestSteppedXRangeImpl(0, 12, 3, {0, 3, 6, 9}); TestSteppedXRangeImpl(0, 13, 3, {0, 3, 6, 9, 12}); TestSteppedXRangeImpl(0, 10, 2, {0, 2, 4, 6, 8}); TestSteppedXRangeImpl(15, 0, -4, {15, 11, 7, 3}); TestSteppedXRangeImpl(15, -1, -4, {15, 11, 7, 3}); TestSteppedXRangeImpl(15, -2, -4, {15, 11, 7, 3, -1}); } Y_UNIT_TEST(PointersWorks) { TVector<size_t> data = {3, 1, 4, 1, 5, 9, 2, 6}; const size_t digSumExpected = Accumulate(data.begin(), data.end(), static_cast<size_t>(0)); size_t digSumByIt = 0; for (auto ptr : xrange(data.begin(), data.end())) { digSumByIt += *ptr; } UNIT_ASSERT_VALUES_EQUAL(digSumByIt, digSumExpected); size_t digSumByPtr = 0; for (auto ptr : xrange(&data[0], &data[0] + data.size())) { digSumByPtr += *ptr; } UNIT_ASSERT_VALUES_EQUAL(digSumByPtr, digSumExpected); } Y_UNIT_TEST(SizeMethodCheck) { UNIT_ASSERT_VALUES_EQUAL(xrange(5).size(), 5); UNIT_ASSERT_VALUES_EQUAL(xrange(0, 5, 2).size(), 3); UNIT_ASSERT_VALUES_EQUAL(xrange(0, 6, 2).size(), 3); } class TVectorChild: public TVector<size_t> { public: template <typename TIterator> TVectorChild(TIterator a, TIterator b) : TVector<size_t>(a, b) { } }; Y_UNIT_TEST(ConvertionWorks) { TVector<size_t> data = {0, 1, 2, 3, 4, 5, 6, 7, 8}; TVector<size_t> convertionResults[] = {xrange<size_t>(9), xrange<ui32>(0, 9), xrange(0, 9, 1)}; for (const auto& arr : convertionResults) { UNIT_ASSERT(arr == data); } TVectorChild sons[] = {xrange(0, 9), xrange(0, 9, 1)}; for (const auto& arr : sons) { UNIT_ASSERT(arr == data); } } template <class XRangeContainer> void TestEmptyRanges(const XRangeContainer& c) { for (const auto& emptyRange : c) { UNIT_ASSERT_VALUES_EQUAL(emptyRange.size(), 0); for (auto i : emptyRange) { Y_UNUSED(i); UNIT_ASSERT(false); } using TValueType = decltype(*emptyRange.begin()); const TVector<TValueType> asVector = emptyRange; UNIT_ASSERT(asVector.empty()); } } Y_UNIT_TEST(EmptySimpleRange) { using TSimpleRange = decltype(xrange(1)); const TSimpleRange emptySimpleRanges[] = { xrange(-1), xrange(-10), xrange(0, -5), xrange(10, 10), xrange(10, 9), }; TestEmptyRanges(emptySimpleRanges); } Y_UNIT_TEST(EmptySteppedRange) { using TSteppedRange = decltype(xrange(1, 10, 1)); const TSteppedRange emptySteppedRanges[] = { xrange(5, 5, 1), xrange(5, 0, 5), xrange(0, -1, 5), xrange(0, 1, -1), xrange(0, -10, 10), }; TestEmptyRanges(emptySteppedRanges); } template <class TRange> static void TestIteratorDifferenceImpl(TRange range, int a, int b, TMaybe<int> step) { auto fmtCase = [&]() -> TString { return TStringBuilder() << "xrange(" << a << ", " << b << (step ? ", " + ToString(*step) : TString{}) << ")"; }; auto begin = std::begin(range); auto end = std::end(range); auto distance = end - begin; UNIT_ASSERT_VALUES_EQUAL_C(range.size(), distance, fmtCase()); UNIT_ASSERT_EQUAL_C(end, begin + distance, fmtCase()); } Y_UNIT_TEST(IteratorDifference) { for (int a = -20; a <= 20; ++a) { for (int b = -20; b <= 20; ++b) { for (int step = -25; step <= 25; ++step) { if (step != 0) { TestIteratorDifferenceImpl(xrange(a, b, step), a, b, step); } } TestIteratorDifferenceImpl(xrange(a, b), a, b, Nothing()); } } } Y_UNIT_TEST(Advance) { { auto range = xrange(30, 160, 7); auto it = std::begin(range); it += 5; UNIT_ASSERT_VALUES_EQUAL(*(std::begin(range) + 5), *it); UNIT_ASSERT_VALUES_EQUAL(65, *it); it -= 2; UNIT_ASSERT_VALUES_EQUAL(*(std::begin(range) + 3), *it); UNIT_ASSERT_VALUES_EQUAL(51, *it); std::advance(it, 10); UNIT_ASSERT_VALUES_EQUAL(*(std::begin(range) + 13), *it); UNIT_ASSERT_VALUES_EQUAL(121, *it); std::advance(it, -5); UNIT_ASSERT_VALUES_EQUAL(*(std::begin(range) + 8), *it); UNIT_ASSERT_VALUES_EQUAL(86, *it); } { auto range = xrange(-20, 100); auto it = std::begin(range); it += 5; UNIT_ASSERT_VALUES_EQUAL(*(std::begin(range) + 5), *it); UNIT_ASSERT_VALUES_EQUAL(-15, *it); it -= 2; UNIT_ASSERT_VALUES_EQUAL(*(std::begin(range) + 3), *it); UNIT_ASSERT_VALUES_EQUAL(-17, *it); std::advance(it, 30); UNIT_ASSERT_VALUES_EQUAL(*(std::begin(range) + 33), *it); UNIT_ASSERT_VALUES_EQUAL(13, *it); std::advance(it, -8); UNIT_ASSERT_VALUES_EQUAL(*(std::begin(range) + 25), *it); UNIT_ASSERT_VALUES_EQUAL(5, *it); } } }