//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LIBCXX_TEST_BENCHMARKS_ALGORITHMS_SORTING_COMMON_H #define LIBCXX_TEST_BENCHMARKS_ALGORITHMS_SORTING_COMMON_H #include #include #include #include #include #include namespace support { // This function creates a vector with N int-like values. // // These values are arranged in such a way that they would invoke O(N^2) // behavior on any quick sort implementation that satisifies certain conditions. // Details are available in the following paper: // // "A Killer Adversary for Quicksort", M. D. McIlroy, Software-Practice & // Experience Volume 29 Issue 4 April 10, 1999 pp 341-344. // https://dl.acm.org/doi/10.5555/311868.311871. template std::vector quicksort_adversarial_data(std::size_t n) { static_assert(std::is_integral_v); assert(n > 0); // If an element is equal to gas, it indicates that the value of the element // is still to be decided and may change over the course of time. T gas = n - 1; std::vector v; v.resize(n); for (unsigned int i = 0; i < n; ++i) { v[i] = gas; } // Candidate for the pivot position. int candidate = 0; int nsolid = 0; // Populate all positions in the generated input to gas. std::vector ascending_values(v.size()); // Fill up with ascending values from 0 to v.size()-1. These will act as // indices into v. std::iota(ascending_values.begin(), ascending_values.end(), 0); std::sort(ascending_values.begin(), ascending_values.end(), [&](int x, int y) { if (v[x] == gas && v[y] == gas) { // We are comparing two inputs whose value is still to be decided. if (x == candidate) { v[x] = nsolid++; } else { v[y] = nsolid++; } } if (v[x] == gas) { candidate = x; } else if (v[y] == gas) { candidate = y; } return v[x] < v[y]; }); return v; } // ascending sorted values template std::vector ascending_sorted_data(std::size_t n) { std::vector v(n); std::iota(v.begin(), v.end(), 0); return v; } // descending sorted values template std::vector descending_sorted_data(std::size_t n) { std::vector v(n); std::iota(v.begin(), v.end(), 0); std::reverse(v.begin(), v.end()); return v; } // pipe-organ pattern template std::vector pipe_organ_data(std::size_t n) { std::vector v(n); std::iota(v.begin(), v.end(), 0); auto half = v.begin() + v.size() / 2; std::reverse(half, v.end()); return v; } // heap pattern template std::vector heap_data(std::size_t n) { std::vector v(n); std::iota(v.begin(), v.end(), 0); std::make_heap(v.begin(), v.end()); return v; } // shuffled randomly template std::vector shuffled_data(std::size_t n) { std::vector v(n); std::iota(v.begin(), v.end(), 0); std::mt19937 rng; std::shuffle(v.begin(), v.end(), rng); return v; } // single element in the whole sequence template std::vector single_element_data(std::size_t n) { std::vector v(n); return v; } struct NonIntegral { NonIntegral() : value_(0) {} NonIntegral(int i) : value_(i) {} friend auto operator<(NonIntegral const& a, NonIntegral const& b) { return a.value_ < b.value_; } friend auto operator>(NonIntegral const& a, NonIntegral const& b) { return a.value_ > b.value_; } friend auto operator<=(NonIntegral const& a, NonIntegral const& b) { return a.value_ <= b.value_; } friend auto operator>=(NonIntegral const& a, NonIntegral const& b) { return a.value_ >= b.value_; } friend auto operator==(NonIntegral const& a, NonIntegral const& b) { return a.value_ == b.value_; } friend auto operator!=(NonIntegral const& a, NonIntegral const& b) { return a.value_ != b.value_; } private: int value_; }; } // namespace support #endif // LIBCXX_TEST_BENCHMARKS_ALGORITHMS_SORTING_COMMON_H