summaryrefslogtreecommitdiffstats
path: root/pstl/test/test_sort.cpp
diff options
context:
space:
mode:
authorJF Bastien <jfbastien@apple.com>2018-12-19 17:45:32 +0000
committerJF Bastien <jfbastien@apple.com>2018-12-19 17:45:32 +0000
commite637637ae46a5b2fa1e9d10c16ae5b0922289f82 (patch)
tree1bd45f3e03d8bbb85a9dca6b46015769d521b186 /pstl/test/test_sort.cpp
parent5d409b22781f5854f1bac3fd60c8499af0c865bf (diff)
downloadbcm5719-llvm-e637637ae46a5b2fa1e9d10c16ae5b0922289f82.tar.gz
bcm5719-llvm-e637637ae46a5b2fa1e9d10c16ae5b0922289f82.zip
Initial PSTL commit
The initial commit of the Parallel STL upstream (under LLVM umbrella) based on Parallel STL 20181204 open source release, which is available by https://github.com/intel/parallelstl Author: Mikhail Dvorskiy <mikhail.dvorskiy@intel.com> Differential Revision: https://reviews.llvm.org/D55889 llvm-svn: 349653
Diffstat (limited to 'pstl/test/test_sort.cpp')
-rw-r--r--pstl/test/test_sort.cpp245
1 files changed, 245 insertions, 0 deletions
diff --git a/pstl/test/test_sort.cpp b/pstl/test/test_sort.cpp
new file mode 100644
index 00000000000..09051ec2a1f
--- /dev/null
+++ b/pstl/test/test_sort.cpp
@@ -0,0 +1,245 @@
+// -*- C++ -*-
+//===-- test_sort.cpp -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Tests for sort and stable_sort
+
+#include "pstl/execution"
+#include "pstl/algorithm"
+#include "utils.h"
+
+using namespace TestUtils;
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <atomic>
+
+static bool Stable;
+
+//! Number of extant keys
+static std::atomic<int32_t> KeyCount;
+
+//! One more than highest index in array to be sorted.
+static uint32_t LastIndex;
+
+//! Keeping Equal() static and a friend of ParanoidKey class (C++, paragraphs 3.5/7.1.1)
+class ParanoidKey;
+static bool
+Equal(const ParanoidKey& x, const ParanoidKey& y);
+
+//! A key to be sorted, with lots of checking.
+class ParanoidKey
+{
+ //! Value used by comparator
+ int32_t value;
+ //! Original position or special value (Empty or Dead)
+ int32_t index;
+ //! Special value used to mark object without a comparable value, e.g. after being moved from.
+ static const int32_t Empty = -1;
+ //! Special value used to mark destroyed objects.
+ static const int32_t Dead = -2;
+ // True if key object has comparable value
+ bool
+ isLive() const
+ {
+ return (uint32_t)(index) < LastIndex;
+ }
+ // True if key object has been constructed.
+ bool
+ isConstructed() const
+ {
+ return isLive() || index == Empty;
+ }
+
+ public:
+ ParanoidKey()
+ {
+ ++KeyCount;
+ index = Empty;
+ value = Empty;
+ }
+ ParanoidKey(const ParanoidKey& k) : value(k.value), index(k.index)
+ {
+ EXPECT_TRUE(k.isLive(), "source for copy-constructor is dead");
+ ++KeyCount;
+ }
+ ~ParanoidKey()
+ {
+ EXPECT_TRUE(isConstructed(), "double destruction");
+ index = Dead;
+ --KeyCount;
+ }
+ ParanoidKey&
+ operator=(const ParanoidKey& k)
+ {
+ EXPECT_TRUE(k.isLive(), "source for copy-assignment is dead");
+ EXPECT_TRUE(isConstructed(), "destination for copy-assignment is dead");
+ value = k.value;
+ index = k.index;
+ return *this;
+ }
+ ParanoidKey(int32_t index, int32_t value, OddTag) : index(index), value(value) {}
+ ParanoidKey(ParanoidKey&& k) : value(k.value), index(k.index)
+ {
+ EXPECT_TRUE(k.isConstructed(), "source for move-construction is dead");
+// std::stable_sort() fails in move semantics on paranoid test before VS2015
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+ k.index = Empty;
+#endif
+ ++KeyCount;
+ }
+ ParanoidKey&
+ operator=(ParanoidKey&& k)
+ {
+ EXPECT_TRUE(k.isConstructed(), "source for move-assignment is dead");
+ EXPECT_TRUE(isConstructed(), "destination for move-assignment is dead");
+ value = k.value;
+ index = k.index;
+// std::stable_sort() fails in move semantics on paranoid test before VS2015
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+ k.index = Empty;
+#endif
+ return *this;
+ }
+ friend class KeyCompare;
+ friend bool
+ Equal(const ParanoidKey& x, const ParanoidKey& y);
+};
+
+class KeyCompare
+{
+ enum statusType
+ {
+ //! Special value used to mark defined object.
+ Live = 0xabcd,
+ //! Special value used to mark destroyed objects.
+ Dead = -1
+ } status;
+
+ public:
+ KeyCompare(OddTag) : status(Live) {}
+ ~KeyCompare() { status = Dead; }
+ bool
+ operator()(const ParanoidKey& j, const ParanoidKey& k) const
+ {
+ EXPECT_TRUE(status == Live, "key comparison object not defined");
+ EXPECT_TRUE(j.isLive(), "first key to operator() is not live");
+ EXPECT_TRUE(k.isLive(), "second key to operator() is not live");
+ return j.value < k.value;
+ }
+};
+
+// Equal is equality comparison used for checking result of sort against expected result.
+static bool
+Equal(const ParanoidKey& x, const ParanoidKey& y)
+{
+ return (x.value == y.value && !Stable) || (x.index == y.index);
+}
+
+static bool
+Equal(float32_t x, float32_t y)
+{
+ return x == y;
+}
+
+static bool
+Equal(int32_t x, int32_t y)
+{
+ return x == y;
+}
+
+struct test_sort_with_compare
+{
+ template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
+ typename Compare>
+ typename std::enable_if<is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
+ void>::type
+ operator()(Policy&& exec, OutputIterator tmp_first, OutputIterator tmp_last, OutputIterator2 expected_first,
+ OutputIterator2 expected_last, InputIterator first, InputIterator last, Size n, Compare compare)
+ {
+ using namespace std;
+ copy_n(first, n, expected_first);
+ copy_n(first, n, tmp_first);
+ if (Stable)
+ std::stable_sort(expected_first + 1, expected_last - 1, compare);
+ else
+ std::sort(expected_first + 1, expected_last - 1, compare);
+ int32_t count0 = KeyCount;
+ if (Stable)
+ stable_sort(exec, tmp_first + 1, tmp_last - 1, compare);
+ else
+ sort(exec, tmp_first + 1, tmp_last - 1, compare);
+
+ for (size_t i = 0; i < n; ++i, ++expected_first, ++tmp_first)
+ {
+ // Check that expected[i] is equal to tmp[i]
+ EXPECT_TRUE(Equal(*expected_first, *tmp_first), "bad sort");
+ }
+ int32_t count1 = KeyCount;
+ EXPECT_EQ(count0, count1, "key cleanup error");
+ }
+ template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
+ typename Compare>
+ typename std::enable_if<!is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
+ void>::type
+ operator()(Policy&& exec, OutputIterator tmp_first, OutputIterator tmp_last, OutputIterator2 expected_first,
+ OutputIterator2 expected_last, InputIterator first, InputIterator last, Size n, Compare compare)
+ {
+ }
+};
+
+template <typename T, typename Compare, typename Convert>
+void
+test_sort(Compare compare, Convert convert)
+{
+ for (size_t n = 0; n < 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
+ {
+ LastIndex = n + 2;
+ // The rand()%(2*n+1) encourages generation of some duplicates.
+ // Sequence is padded with an extra element at front and back, to detect overwrite bugs.
+ Sequence<T> in(n + 2, [=](size_t k) { return convert(k, rand() % (2 * n + 1)); });
+ Sequence<T> expected(in);
+ Sequence<T> tmp(in);
+ invoke_on_all_policies(test_sort_with_compare(), tmp.begin(), tmp.end(), expected.begin(), expected.end(),
+ in.begin(), in.end(), in.size(), compare);
+ }
+}
+
+template <typename T>
+struct test_non_const
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator iter)
+ {
+ sort(exec, iter, iter, non_const(std::less<T>()));
+ stable_sort(exec, iter, iter, non_const(std::less<T>()));
+ }
+};
+
+int32_t
+main()
+{
+ std::srand(42);
+ for (int32_t kind = 0; kind < 2; ++kind)
+ {
+ Stable = kind != 0;
+ test_sort<ParanoidKey>(KeyCompare(OddTag()),
+ [](size_t k, size_t val) { return ParanoidKey(k, val, OddTag()); });
+ test_sort<float32_t>([](float32_t x, float32_t y) { return x < y; },
+ [](size_t, size_t val) { return float32_t(val); });
+ test_sort<int32_t>(
+ [](int32_t x, int32_t y) { return x > y; }, // Reversed so accidental use of < will be detected.
+ [](size_t, size_t val) { return int32_t(val); });
+ }
+
+ test_algo_basic_single<int32_t>(run_for_rnd<test_non_const<int32_t>>());
+
+ std::cout << done() << std::endl;
+ return 0;
+}
OpenPOWER on IntegriCloud