From 26547c296ba89d20872eeda9d334fc1e07ddb43e Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 16 Jul 2020 15:13:36 +0200 Subject: Purge qalgorithm.h of deprecated API A large slice of it has been deprecated since 5.2. Reflowed a doc paragraph pointed out, in the deprecation commit, as having been left ragged by its edits. Note: qSwap() is documented as \deprecated but not marked, where it's defined, as deprecated. Change-Id: Iaff10ac0c4c38e5b85f10eca4eedeab861f09959 Reviewed-by: Thiago Macieira --- .../corelib/tools/qalgorithms/tst_qalgorithms.cpp | 809 +-------------------- 1 file changed, 1 insertion(+), 808 deletions(-) (limited to 'tests/auto/corelib/tools') diff --git a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp index 44e6bef6f0..e0062b9118 100644 --- a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp +++ b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -54,31 +54,6 @@ private slots: void swap2(); void convenienceAPI(); -#if QT_DEPRECATED_SINCE(5, 2) - void test_qLowerBound_data(); - void test_qLowerBound(); - void test_qUpperBound_data(); - void test_qUpperBound(); - void test_qBinaryFind_data(); - void test_qBinaryFind(); - void qBinaryFindOneEntry(); - void sortEmptyList(); - void sortedList(); - void sortAPItest(); - void stableSortTest(); - void stableSortCorrectnessTest_data(); - void stableSortCorrectnessTest(); - void convenienceAPI_deprecated(); - void qCountIterators() const; - void qCountContainer() const; - void binaryFindOnLargeContainer() const; - -#if Q_TEST_PERFORMANCE - void performance(); -#endif - -#endif // QT_DEPRECATED_SINCE(5, 2) - void popCount08_data() { popCount_data_impl(sizeof(quint8 )); } void popCount16_data() { popCount_data_impl(sizeof(quint16)); } void popCount32_data() { popCount_data_impl(sizeof(quint32)); } @@ -120,155 +95,6 @@ private: void countLeading_impl(); }; -#if QT_DEPRECATED_SINCE(5, 2) - -class TestInt -{ -public: - TestInt(int number) :m_number(number) {} ; - TestInt() : m_number(0) {}; - bool operator<(const TestInt &other) const { ++TestInt::lessThanRefCount; return (m_number < other.m_number); } - int m_number; -static long int lessThanRefCount; -}; - -long int TestInt::lessThanRefCount; - - -QStringList dataSetTypes = QStringList() << "Random" << "Ascending" - << "Descending" << "Equal" << "Duplicates" << "Almost Sorted" ; - -template -QList generateData(QString dataSetType, const int length) -{ - QList container; - if (dataSetType == "Random") { - for (int i = 0; i < length; ++i) - container.append(QRandomGenerator::global()->generate()); - } else if (dataSetType == "Ascending") { - for (int i = 0; i < length; ++i) - container.append(i); - } else if (dataSetType == "Descending") { - for (int i = 0; i < length; ++i) - container.append(length - i); - } else if (dataSetType == "Equal") { - for (int i = 0; i < length; ++i) - container.append(43); - } else if (dataSetType == "Duplicates") { - for (int i = 0; i < length; ++i) - container.append(i % 10); - } else if (dataSetType == "Almost Sorted") { - for (int i = 0; i < length; ++i) - container.append(i); - for (int i = 0; i <= length / 10; ++i) { - const int iswap = i * 9; - DataType tmp = container.at(iswap); - container[iswap] = container.at(iswap + 1); - container[iswap + 1] = tmp; - } - } - return container; -} - -struct ResultSet -{ - int numSorts; - long int lessThanRefCount; -}; - - -template -ResultSet testRun(ContainerType &container, Algorithm &algorithm, int millisecs) -{ - TestInt::lessThanRefCount = 0; - int count = 0; - QElapsedTimer t; - t.start(); - while(t.elapsed() < millisecs) { - ++count; - algorithm(container); - } - ResultSet result; - result.numSorts = count; - result.lessThanRefCount = TestInt::lessThanRefCount; - return result; -} - -template -bool isSorted(ContainerType &container, LessThan lessThan) -{ - for (int i=0; i < container.count() - 1; ++i) - if (lessThan(container.at(i+1), container.at(i))) { - return false; - } - return true; -} - -template -bool isSorted(ContainerType &container) -{ - return isSorted(container, qLess()); -} - - -#if Q_TEST_PERFORMANCE -void printHeader(QStringList &headers) -{ - cout << setw(10) << setiosflags(ios_base::left) << " "; - for (int h = 0; h < headers.count(); ++h) { - cout << setw(20) << setiosflags(ios_base::left) << headers.at(h).toLatin1().constData(); - } - cout << Qt::endl; -} - -template -void print(ContainerType testContainer) -{ - typedef typename ContainerType::value_type T; - - foreach(T value, testContainer) { - cout << value << " "; - } - - cout << Qt::endl; -} - -template -QList testAlgorithm(Algorithm &algorithm, QStringList dataSetTypes, int size, int time) -{ - QList results; - foreach(QString dataSetType, dataSetTypes) { - QList container = generateData(dataSetType, size); - results.append(testRun(container, algorithm, time)); - if (!isSorted(container)) - qWarning("%s: container is not sorted after test", Q_FUNC_INFO); - } - return results; -} - -template -void testAlgorithm(Algorithm algorithm, QStringList &dataSetTypes) -{ - QList sizes = QList() << 5 << 15 << 35 << 70 << 200 << 1000 << 10000; - printHeader(dataSetTypes); - for (int s = 0; s < sizes.count(); ++s){ - cout << setw(10) << setiosflags(ios_base::left)<< sizes.at(s); - QList results = - testAlgorithm(algorithm, dataSetTypes, sizes.at(s), 100); - foreach(ResultSet result, results) { - stringstream numSorts; - numSorts << setiosflags(ios_base::left) << setw(10) << result.numSorts; - stringstream lessThan; - lessThan << setiosflags(ios_base::left) << setw(10) << result.lessThanRefCount / result.numSorts; - cout << numSorts.str() << lessThan.str(); - } - cout << Qt::endl; - } -} -#endif - -#endif // QT_DEPRECATED_SINCE(5, 2) - void tst_QAlgorithms::swap() { { @@ -412,639 +238,6 @@ void tst_QAlgorithms::convenienceAPI() qDeleteAll(pointerList.begin(), pointerList.end()); } -#if QT_DEPRECATED_SINCE(5, 2) - -void tst_QAlgorithms::sortEmptyList() -{ - // Only test if it crashes - QStringList stringList; - stringList.sort(); - QVERIFY(true); -} - -void tst_QAlgorithms::sortedList() -{ - QList list; - list << 4 << 3 << 6; - - ::qSort(list.begin(), list.end()); - - QCOMPARE(list.count(), 3); - QCOMPARE(list.at(0), 3); - QCOMPARE(list.at(1), 4); - QCOMPARE(list.at(2), 6); - - list.insert(qUpperBound(list.begin(), list.end(), 5), 5); - list.insert(qUpperBound(list.begin(), list.end(), 1), 1); - list.insert(qUpperBound(list.begin(), list.end(), 8), 8); - - QCOMPARE(list.count(), 6); - QCOMPARE(list.at(0), 1); - QCOMPARE(list.at(1), 3); - QCOMPARE(list.at(2), 4); - QCOMPARE(list.at(3), 5); - QCOMPARE(list.at(4), 6); - QCOMPARE(list.at(5), 8); -} - - -void tst_QAlgorithms::test_qLowerBound_data() -{ - QTest::addColumn >("data"); - QTest::addColumn("resultValue"); - QTest::addColumn("resultIndex"); - - QTest::newRow("sorted-duplicate") << (QList() << 1 << 2 << 2 << 3) << 2 << 1; -} - -void tst_QAlgorithms::test_qLowerBound() -{ - QFETCH(QList, data); - QFETCH(int, resultValue); - QFETCH(int, resultIndex); - - - QCOMPARE(qLowerBound(data.constBegin(), data.constEnd(), resultValue), data.constBegin() + resultIndex); - QCOMPARE(qLowerBound(data.begin(), data.end(), resultValue), data.begin() + resultIndex); - QCOMPARE(qLowerBound(data, resultValue), data.constBegin() + resultIndex); - QCOMPARE(qLowerBound(data.constBegin(), data.constEnd(), resultValue, qLess()), data.constBegin() + resultIndex); -} - -void tst_QAlgorithms::test_qUpperBound_data() -{ - QTest::addColumn >("data"); - QTest::addColumn("resultValue"); - QTest::addColumn("resultIndex"); - - QTest::newRow("sorted-duplicate") << (QList() << 1 << 2 << 2 << 3) << 2 << 3; -} - -void tst_QAlgorithms::test_qUpperBound() -{ - QFETCH(QList, data); - QFETCH(int, resultValue); - QFETCH(int, resultIndex); - - QCOMPARE(qUpperBound(data.constBegin(), data.constEnd(), resultValue), data.constBegin() + resultIndex); - QCOMPARE(qUpperBound(data.begin(), data.end(), resultValue), data.begin() + resultIndex); - QCOMPARE(qUpperBound(data, resultValue), data.constBegin() + resultIndex); - QCOMPARE(qUpperBound(data.constBegin(), data.constEnd(), resultValue, qLess()), data.constBegin() + resultIndex); -} - -void tst_QAlgorithms::test_qBinaryFind_data() -{ - QTest::addColumn >("data"); - QTest::addColumn("resultValue"); // -42 means not found - - QTest::newRow("sorted-duplicate") << (QList() << 1 << 2 << 2 << 3) << 2; - QTest::newRow("sorted-end") << (QList() << -5 << -2 << 0 << 8) << 8; - QTest::newRow("sorted-beginning") << (QList() << -5 << -2 << 0 << 8) << -5; - QTest::newRow("sorted-duplicate-beginning") << (QList() << -5 << -5 << -2 << 0 << 8) << -5; - QTest::newRow("empty") << (QList()) << -42; - QTest::newRow("not found 1 ") << (QList() << 1 << 5 << 8 << 65) << -42; - QTest::newRow("not found 2 ") << (QList() << -456 << -5 << 8 << 65) << -42; -} - -void tst_QAlgorithms::test_qBinaryFind() -{ - QFETCH(QList, data); - QFETCH(int, resultValue); - - //-42 means not found - if (resultValue == -42) { - QVERIFY(qBinaryFind(data.constBegin(), data.constEnd(), resultValue) == data.constEnd()); - QVERIFY(qBinaryFind(data, resultValue) == data.constEnd()); - QVERIFY(qBinaryFind(data.begin(), data.end(), resultValue) == data.end()); - QVERIFY(qBinaryFind(data.begin(), data.end(), resultValue, qLess()) == data.end()); - return; - } - - QCOMPARE(*qBinaryFind(data.constBegin(), data.constEnd(), resultValue), resultValue); - QCOMPARE(*qBinaryFind(data.begin(), data.end(), resultValue), resultValue); - QCOMPARE(*qBinaryFind(data, resultValue), resultValue); - QCOMPARE(*qBinaryFind(data.constBegin(), data.constEnd(), resultValue, qLess()), resultValue); -} - -void tst_QAlgorithms::qBinaryFindOneEntry() -{ - QList list; - list << 2; - - QVERIFY(::qBinaryFind(list.constBegin(), list.constEnd(), 2) != list.constEnd()); -} - - -void tst_QAlgorithms::sortAPItest() -{ - QList testList = generateData("Random", 101).toList(); - qSort(testList); - QVERIFY(isSorted(testList)); - qSort(testList.begin(), testList.end()); - QVERIFY(isSorted(testList)); - qSort(testList.begin(), testList.end(), qLess()); - QVERIFY(isSorted(testList)); - - testList = generateData("Random", 71).toList(); - qStableSort(testList); - QVERIFY(isSorted(testList)); - qStableSort(testList.begin(), testList.end()); - QVERIFY(isSorted(testList)); - qStableSort(testList.begin(), testList.end(), qLess()); - QVERIFY(isSorted(testList)); -} - - -class StableSortTest -{ -public: - StableSortTest(){}; - StableSortTest(int Major, int Minor) : Major(Major), Minor(Minor) {} - bool operator<(const StableSortTest &other) const {return (Major < other.Major); } - bool testMinor(const StableSortTest &other) const {return Minor < other.Minor; } - -int Major; -int Minor; -}; - -ostream &operator<<(ostream &out, const StableSortTest& obj) { out << obj.Major << "-" << obj.Minor; return out; } - -QList createStableTestList() -{ - QList stableTestList; - for (int i = 500; i >= 0; --i) { - for (int j = 0; j < 10; ++j) - stableTestList.append(StableSortTest(i, j)); - } - return stableTestList; -} - -template -bool isStableSorted(ContainerType &container, LessThan lessThan) -{ - for (int i=0; i < container.count() - 1; ++i) { - //not sorted? - if (lessThan(container.at(i + 1), container.at(i))) - return false; - // equal? - if (lessThan(container.at(i), container.at(i + 1))) - continue; - // minor version? - if(container.at(i + 1).testMinor(container.at(i))) - return false; - } - return true; -} - -void tst_QAlgorithms::stableSortTest() -{ - // Selftests: - { - QList stableTestList = createStableTestList(); - qSort(stableTestList.begin(), stableTestList.end(), qLess()); - QVERIFY(isSorted(stableTestList, qLess())); - QVERIFY(!isStableSorted(stableTestList, qLess())); - } - { - QList stableTestList = createStableTestList(); - qSort(stableTestList.begin(), stableTestList.end(), qGreater()); - QVERIFY(isSorted(stableTestList, qGreater())); - QVERIFY(!isStableSorted(stableTestList, qGreater())); - } - { - QList stableTestList = createStableTestList(); - qSort(stableTestList.begin(), stableTestList.end(), qGreater()); - QVERIFY(!isSorted(stableTestList, qLess())); - QVERIFY(!isStableSorted(stableTestList, qGreater())); - } - - - // Stable sort with qLess - { - QList stableTestList = createStableTestList(); - std::stable_sort(stableTestList.begin(), stableTestList.end(), qLess()); - QVERIFY(isSorted(stableTestList, qLess())); - QVERIFY(isStableSorted(stableTestList, qLess())); - } - { - QList stableTestList = createStableTestList(); - qStableSort(stableTestList.begin(), stableTestList.end(), qLess()); - QVERIFY(isSorted(stableTestList, qLess())); - QVERIFY(isStableSorted(stableTestList, qLess())); - } - - // Stable sort with qGreater - { - QList stableTestList = createStableTestList(); - std::stable_sort(stableTestList.begin(), stableTestList.end(), qGreater()); - QVERIFY(isSorted(stableTestList, qGreater())); - QVERIFY(isStableSorted(stableTestList, qGreater())); - } - - { - QList stableTestList = createStableTestList(); - qStableSort(stableTestList.begin(), stableTestList.end(), qGreater()); - QVERIFY(isSorted(stableTestList, qGreater())); - QVERIFY(isStableSorted(stableTestList, qGreater())); - } -} - - -void tst_QAlgorithms::stableSortCorrectnessTest_data() -{ - const int dataSize = 1000; - QTest::addColumn>("unsorted"); - QTest::newRow("From documentation") << (QList() << 33 << 12 << 68 << 6 << 12); - QTest::newRow("Equal") << (generateData("Equal", dataSize)); - QTest::newRow("Ascending") << (generateData("Ascending", dataSize)); - QTest::newRow("Descending") << (generateData("Descending", dataSize)); - QTest::newRow("Duplicates") << (generateData("Duplicates", dataSize)); - QTest::newRow("Almost Sorted") << (generateData("Almost Sorted", dataSize)); - QTest::newRow("Random") << (generateData("Random", dataSize)); -} - -void tst_QAlgorithms::stableSortCorrectnessTest() -{ - QFETCH(QList, unsorted); - - QList sorted = unsorted; - qStableSort(sorted.begin(), sorted.end()); - - // Verify that sorted contains the same numbers as unsorted. - foreach(int value, unsorted) { - QVERIFY(sorted.contains(value)); - int unsortedCount = 0; - qCount(unsorted.begin(), unsorted.end(), value, unsortedCount); - int sortedCount = 0; - qCount(sorted.begin(), sorted.end(), value, sortedCount); - QCOMPARE(sortedCount, unsortedCount); - } - - QVERIFY(isSorted(sorted)); -} - -void tst_QAlgorithms::convenienceAPI_deprecated() -{ - // Compile-test for QAlgorithm convenience functions. - QList list, list2; - - qCopy(list.begin(), list.end(), list2.begin()); - qCopyBackward(list.begin(), list.end(), list2.begin()); - qEqual(list.begin(), list.end(), list2.begin()); - - qFill(list, 1); - qFill(list.begin(), list.end(), 1); - - qFind(list, 1); - qFind(list.begin(), list.end(), 1); - - int count1 = 0 , count2 = 0, count3 = 0; - qCount(list, 1, count1); - qCount(list.begin(), list.end(), 1, count2); - QCOMPARE(count1, count2); - QCOMPARE(count2, count3); - - qSort(list); - qSort(list.begin(), list.end()); - qSort(list.begin(), list.end(), qLess()); - - qStableSort(list); - qStableSort(list.begin(), list.end()); - qStableSort(list.begin(), list.end(), qLess()); - - qLowerBound(list, 1);; - qLowerBound(list.begin(), list.end(), 1); - qLowerBound(list.begin(), list.end(), 1, qLess()); - - qUpperBound(list, 1); - qUpperBound(list.begin(), list.end(), 1); - qUpperBound(list.begin(), list.end(), 1, qLess()); - - qBinaryFind(list, 1); - qBinaryFind(list.begin(), list.end(), 1); - qBinaryFind(list.begin(), list.end(), 1, qLess()); -} - -template -class QuickSortHelper -{ -public: - void operator()(QList list) - { - ::qSort(list); - } -}; - -template -class StableSortHelper -{ -public: - void operator()(QList list) - { - ::qStableSort(list); - } -}; - -template -class StlSortHelper -{ -public: - void operator()(QList list) - { - std::sort(list.begin(), list.end()); - } -}; - -template -class StlStableSortHelper -{ -public: - void operator()(QList list) - { - std::stable_sort(list.begin(), list.end()); - } -}; - -#if Q_TEST_PERFORMANCE -void tst_QAlgorithms::performance() -{ - cout << Qt::endl << "Quick sort" << Qt::endl; - testAlgorithm, TestInt>(QuickSortHelper(), dataSetTypes); - cout << Qt::endl << "stable sort" << Qt::endl; - testAlgorithm, TestInt>(StableSortHelper(), dataSetTypes); - cout << Qt::endl << "std::sort" << Qt::endl; - testAlgorithm, TestInt>(StlSortHelper(), dataSetTypes); - cout << Qt::endl << "std::stable_sort" << Qt::endl; - testAlgorithm, TestInt>(StlStableSortHelper(), dataSetTypes); -/* - cout << Qt::endl << "Sorting lists of ints" << Qt::endl; - cout << Qt::endl << "Quick sort" << Qt::endl; - testAlgorithm, int>(QuickSortHelper(), dataSetTypes); - cout << Qt::endl << "std::sort" << Qt::endl; - testAlgorithm, int>(StlSortHelper(), dataSetTypes); - cout << Qt::endl << "std::stable_sort" << Qt::endl; - testAlgorithm, int>(StlStableSortHelper(), dataSetTypes); -*/ -} -#endif - -void tst_QAlgorithms::qCountIterators() const -{ - QList list; - list << 3 << 3 << 6 << 6 << 6 << 8; - - { - int countOf7 = 0; - ::qCount(list.begin(), list.end(), 7, countOf7); - QCOMPARE(countOf7, 0); - } - - { - int countOf3 = 0; - ::qCount(list.begin(), list.end(), 3, countOf3); - QCOMPARE(countOf3, 2); - } - - { - int countOf6 = 0; - ::qCount(list.begin(), list.end(), 6, countOf6); - QCOMPARE(countOf6, 3); - } - - { - int countOf8 = 0; - ::qCount(list.begin(), list.end(), 8, countOf8); - QCOMPARE(countOf8, 1); - } - - /* Check that we add to the count, not set it. */ - { - int countOf8 = 5; - ::qCount(list.begin(), list.end(), 8, countOf8); - QCOMPARE(countOf8, 6); - } -} - -void tst_QAlgorithms::qCountContainer() const -{ - QList list; - list << 3 << 3 << 6 << 6 << 6 << 8; - - { - int countOf7 = 0; - ::qCount(list, 7, countOf7); - QCOMPARE(countOf7, 0); - } - - { - int countOf3 = 0; - ::qCount(list, 3, countOf3); - QCOMPARE(countOf3, 2); - } - - { - int countOf6 = 0; - ::qCount(list, 6, countOf6); - QCOMPARE(countOf6, 3); - } - - { - int countOf8 = 0; - ::qCount(list, 8, countOf8); - QCOMPARE(countOf8, 1); - } - - /* Check that we add to the count, not set it. */ - { - int countOf8 = 5; - ::qCount(list, 8, countOf8); - QCOMPARE(countOf8, 6); - } -} - -class RAI -{ - public: - typedef int difference_type; - typedef int value_type; - typedef std::random_access_iterator_tag iterator_category; - typedef int *pointer; - typedef int &reference; - - RAI(int searched = 5, int hidePos = 4, int len = 10) - : curPos_(0) - , length_(len) - , searchedVal_(searched) - , searchedValPos_(hidePos) - { - } - - int at(int pos) const - { - if (pos == searchedValPos_) { - return searchedVal_; - } - else if (pos < searchedValPos_) { - return searchedVal_ - 1; - } - - return searchedVal_ + 1; - } - - RAI begin() const - { - RAI rai = *this; - rai.setCurPos(0); - return rai; - } - - RAI end() const - { - RAI rai = *this; - rai.setCurPos(length_); - return rai; - } - - int pos() const - { - return curPos(); - } - - int size() const - { - return length_; - } - - RAI operator+(int i) const - { - RAI rai = *this; - rai.setCurPos( rai.curPos() + i ); - if (rai.curPos() > length_) { - rai.setCurPos(length_); - } - return rai; - } - - RAI operator-(int i) const - { - RAI rai = *this; - rai.setCurPos( rai.curPos() - i ); - if (rai.curPos() < 0) { - rai.setCurPos(0); - } - return rai; - } - - int operator-(const RAI& it) const - { - return curPos() - it.curPos(); - } - - RAI& operator+=(int i) - { - setCurPos( curPos() + i ); - if (curPos() > length_) { - setCurPos(length_); - } - return *this; - } - - RAI& operator-=(int i) - { - setCurPos( curPos() - i); - if (curPos() < 0) { - setCurPos(0); - } - return *this; - } - - RAI& operator++() - { - if (curPos() < length_) { - setCurPos( curPos() + 1 ); - } - return *this; - } - - RAI operator++(int) - { - RAI rai = *this; - - if (curPos() < length_) { - setCurPos( curPos() + 1 ); - } - - return rai; - } - - RAI& operator--() - { - if (curPos() > 0) { - setCurPos( curPos() - 1 ); - } - return *this; - } - - RAI operator--(int) - { - RAI rai = *this; - - if (curPos() > 0) { - setCurPos( curPos() - 1 ); - } - - return rai; - } - - bool operator==(const RAI& rai) const - { - return rai.curPos() == curPos(); - } - - bool operator!=(const RAI& rai) const - { - return !operator==(rai); - } - - int operator*() const - { - return at(curPos()); - } - - int operator[](int i) const - { - return at(i); - } - - private: - - int curPos() const - { - return curPos_; - } - - void setCurPos(int pos) - { - curPos_ = pos; - } - - int curPos_; - int length_; - int searchedVal_; - int searchedValPos_; -}; - -void tst_QAlgorithms::binaryFindOnLargeContainer() const -{ - const int len = 2 * 1000 * 1000 * 537; - const int pos = len - 12345; - RAI rai(5, pos, len); - - RAI foundIt = qBinaryFind(rai.begin(), rai.end(), 5); - QCOMPARE(foundIt.pos(), 1073987655); -} - -#endif // QT_DEPRECATED_SINCE(5, 2) - // alternative implementation of qPopulationCount for comparison: static constexpr const uint bitsSetInNibble[] = { 0, 1, 1, 2, 1, 2, 2, 3, -- cgit v1.2.3