8333133: Simplify QuickSort::sort
Reviewed-by: shade, dholmes
This commit is contained in:
parent
c66f785fb6
commit
25c3845be2
@ -568,7 +568,7 @@ Array<ModuleEntry*>* ModuleEntryTable::allocate_archived_entries() {
|
||||
|
||||
if (n > 1) {
|
||||
// Always allocate in the same order to produce deterministic archive.
|
||||
QuickSort::sort(archived_modules->data(), n, (_sort_Fn)compare_module_by_name, true);
|
||||
QuickSort::sort(archived_modules->data(), n, compare_module_by_name);
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
archived_modules->at_put(i, archived_modules->at(i)->allocate_archived_entry());
|
||||
|
@ -300,7 +300,8 @@ Array<PackageEntry*>* PackageEntryTable::allocate_archived_entries() {
|
||||
_table.iterate_all(grab);
|
||||
|
||||
if (n > 1) {
|
||||
QuickSort::sort(archived_packages->data(), n, (_sort_Fn)compare_package_by_name, true);
|
||||
// Always allocate in the same order to produce deterministic archive.
|
||||
QuickSort::sort(archived_packages->data(), n, compare_package_by_name);
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
archived_packages->at_put(i, archived_packages->at(i)->allocate_archived_entry());
|
||||
|
@ -604,7 +604,7 @@ void CompilationMemoryStatistic::print_all_by_size(outputStream* st, bool human_
|
||||
st->print_cr("(%d/%d)", num, _the_table->number_of_entries());
|
||||
}
|
||||
if (num > 0) {
|
||||
QuickSort::sort(filtered, num, diff_entries_by_size, false);
|
||||
QuickSort::sort(filtered, num, diff_entries_by_size);
|
||||
// Now print. Has to happen under lock protection too, since entries may be changed.
|
||||
for (int i = 0; i < num; i ++) {
|
||||
filtered[i]->print_on(st, human_readable);
|
||||
|
@ -383,7 +383,7 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) {
|
||||
double non_young_end_time_sec = os::elapsedTime();
|
||||
phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0);
|
||||
|
||||
QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx, true);
|
||||
QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx);
|
||||
}
|
||||
|
||||
void G1CollectionSet::move_candidates_to_collection_set(G1CollectionCandidateRegionList* regions) {
|
||||
|
@ -359,8 +359,7 @@ class G1RefineBufferedCards : public StackObj {
|
||||
void sort_cards(size_t start_index) {
|
||||
QuickSort::sort(&_node_buffer[start_index],
|
||||
_node_buffer_capacity - start_index,
|
||||
compare_cards,
|
||||
false);
|
||||
compare_cards);
|
||||
}
|
||||
|
||||
// Returns the index to the first clean card in the buffer.
|
||||
|
@ -97,7 +97,7 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand
|
||||
byte_size_in_proper_unit(min_garbage), proper_unit_for_byte_size(min_garbage));
|
||||
|
||||
// Better select garbage-first regions
|
||||
QuickSort::sort<RegionData>(data, (int)size, compare_by_garbage, false);
|
||||
QuickSort::sort(data, size, compare_by_garbage);
|
||||
|
||||
size_t cur_cset = 0;
|
||||
size_t cur_garbage = 0;
|
||||
|
@ -322,7 +322,7 @@ void LogSelection::suggest_similar_matching(outputStream* out) const {
|
||||
|
||||
// Sort found suggestions to suggest the best one first
|
||||
SimilarityComparator sc(*this);
|
||||
QuickSort::sort(suggestions, nsuggestions, sc, false);
|
||||
QuickSort::sort(suggestions, nsuggestions, sc);
|
||||
|
||||
out->print("Did you mean any of the following?");
|
||||
for (size_t i = 0; i < nsuggestions; i++) {
|
||||
|
@ -1733,7 +1733,7 @@ void Method::sort_methods(Array<Method*>* methods, bool set_idnums, method_compa
|
||||
}
|
||||
{
|
||||
NoSafepointVerifier nsv;
|
||||
QuickSort::sort(methods->data(), length, func, /*idempotent=*/false);
|
||||
QuickSort::sort(methods->data(), length, func);
|
||||
}
|
||||
// Reset method ordering
|
||||
if (set_idnums) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,25 +26,23 @@
|
||||
#define SHARE_UTILITIES_QUICKSORT_HPP
|
||||
|
||||
#include "memory/allStatic.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class QuickSort : AllStatic {
|
||||
|
||||
private:
|
||||
template<class T>
|
||||
static void swap(T* array, size_t x, size_t y) {
|
||||
T tmp = array[x];
|
||||
array[x] = array[y];
|
||||
array[y] = tmp;
|
||||
static void swap_elements(T* array, size_t x, size_t y) {
|
||||
swap(array[x], array[y]);
|
||||
}
|
||||
|
||||
// As pivot we use the median of the first, last and middle elements.
|
||||
// We swap in these three values at the right place in the array. This
|
||||
// means that this method not only returns the index of the pivot
|
||||
// element. It also alters the array so that:
|
||||
// We swap these three values as needed so that
|
||||
// array[first] <= array[middle] <= array[last]
|
||||
// A side effect of this is that arrays of length <= 3 are sorted.
|
||||
// As a result, the first and last elements are placed in the proper
|
||||
// partition, and arrays of length <= 3 are sorted.
|
||||
// The middle index is returned, designating that element as the pivot.
|
||||
template<class T, class C>
|
||||
static size_t find_pivot(T* array, size_t length, C comparator) {
|
||||
assert(length > 1, "length of array must be > 0");
|
||||
@ -53,20 +51,20 @@ class QuickSort : AllStatic {
|
||||
size_t last_index = length - 1;
|
||||
|
||||
if (comparator(array[0], array[middle_index]) > 0) {
|
||||
swap(array, 0, middle_index);
|
||||
swap_elements(array, 0, middle_index);
|
||||
}
|
||||
if (comparator(array[0], array[last_index]) > 0) {
|
||||
swap(array, 0, last_index);
|
||||
swap_elements(array, 0, last_index);
|
||||
}
|
||||
if (comparator(array[middle_index], array[last_index]) > 0) {
|
||||
swap(array, middle_index, last_index);
|
||||
swap_elements(array, middle_index, last_index);
|
||||
}
|
||||
// Now the value in the middle of the array is the median
|
||||
// of the fist, last and middle values. Use this as pivot.
|
||||
// of the first, last and middle values. Use this as pivot.
|
||||
return middle_index;
|
||||
}
|
||||
|
||||
template<bool idempotent, class T, class C>
|
||||
template<class T, class C>
|
||||
static size_t partition(T* array, size_t pivot, size_t length, C comparator) {
|
||||
size_t left_index = 0;
|
||||
size_t right_index = length - 1;
|
||||
@ -74,27 +72,22 @@ class QuickSort : AllStatic {
|
||||
|
||||
for ( ; true; ++left_index, --right_index) {
|
||||
for ( ; comparator(array[left_index], pivot_val) < 0; ++left_index) {
|
||||
assert(left_index < length, "reached end of partition");
|
||||
assert(left_index < (length - 1), "reached end of partition");
|
||||
}
|
||||
for ( ; comparator(array[right_index], pivot_val) > 0; --right_index) {
|
||||
assert(right_index > 0, "reached start of partition");
|
||||
}
|
||||
|
||||
if (left_index < right_index) {
|
||||
if (!idempotent || comparator(array[left_index], array[right_index]) != 0) {
|
||||
swap(array, left_index, right_index);
|
||||
}
|
||||
swap_elements(array, left_index, right_index);
|
||||
} else {
|
||||
return right_index;
|
||||
}
|
||||
}
|
||||
|
||||
ShouldNotReachHere();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<bool idempotent, class T, class C>
|
||||
static void inner_sort(T* array, size_t length, C comparator) {
|
||||
public:
|
||||
template<class T, class C>
|
||||
static void sort(T* array, size_t length, C comparator) {
|
||||
if (length < 2) {
|
||||
return;
|
||||
}
|
||||
@ -103,28 +96,11 @@ class QuickSort : AllStatic {
|
||||
// arrays up to length 3 will be sorted after finding the pivot
|
||||
return;
|
||||
}
|
||||
size_t split = partition<idempotent>(array, pivot, length, comparator);
|
||||
size_t split = partition(array, pivot, length, comparator);
|
||||
size_t first_part_length = split + 1;
|
||||
inner_sort<idempotent>(array, first_part_length, comparator);
|
||||
inner_sort<idempotent>(&array[first_part_length], length - first_part_length, comparator);
|
||||
}
|
||||
|
||||
public:
|
||||
// The idempotent parameter prevents the sort from
|
||||
// reordering a previous valid sort by not swapping
|
||||
// fields that compare as equal. This requires extra
|
||||
// calls to the comparator, so the performance
|
||||
// impact depends on the comparator.
|
||||
template<class T, class C>
|
||||
static void sort(T* array, size_t length, C comparator, bool idempotent) {
|
||||
// Switch "idempotent" from function parameter to template parameter
|
||||
if (idempotent) {
|
||||
inner_sort<true>(array, length, comparator);
|
||||
} else {
|
||||
inner_sort<false>(array, length, comparator);
|
||||
}
|
||||
sort(array, first_part_length, comparator);
|
||||
sort(&array[first_part_length], length - first_part_length, comparator);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // SHARE_UTILITIES_QUICKSORT_HPP
|
||||
|
@ -461,7 +461,7 @@ public:
|
||||
*to_release[i] = nullptr;
|
||||
}
|
||||
if (sorted) {
|
||||
QuickSort::sort(to_release, nrelease, PointerCompare(), false);
|
||||
QuickSort::sort(to_release, nrelease, PointerCompare());
|
||||
}
|
||||
|
||||
storage().release(to_release, nrelease);
|
||||
|
@ -48,23 +48,11 @@ static bool compare_arrays(int* actual, int* expected, size_t length) {
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static bool sort_and_compare(int* arrayToSort, int* expectedResult, size_t length, C comparator, bool idempotent = false) {
|
||||
QuickSort::sort(arrayToSort, length, comparator, idempotent);
|
||||
static bool sort_and_compare(int* arrayToSort, int* expectedResult, size_t length, C comparator) {
|
||||
QuickSort::sort(arrayToSort, length, comparator);
|
||||
return compare_arrays(arrayToSort, expectedResult, length);
|
||||
}
|
||||
|
||||
static int test_even_odd_comparator(int a, int b) {
|
||||
bool a_is_odd = ((a % 2) == 1);
|
||||
bool b_is_odd = ((b % 2) == 1);
|
||||
if (a_is_odd == b_is_odd) {
|
||||
return 0;
|
||||
}
|
||||
if (a_is_odd) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static int test_stdlib_comparator(const void* a, const void* b) {
|
||||
int ai = *(int*)a;
|
||||
@ -126,50 +114,6 @@ TEST(QuickSort, quicksort) {
|
||||
int expected_array[] = {6,7,8,8,9,9,11,11,13,21,22,24,24,25,27,27,28,31,32,39,40,40,40,41,44,46,51,55,56,59,64,64,65,69,71,74,75,75,76,78,81,82};
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 42, test_comparator));
|
||||
}
|
||||
{
|
||||
int test_array[] = {2,8,1,4};
|
||||
int expected_array[] = {1,4,2,8};
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 4, test_even_odd_comparator));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(QuickSort, idempotent) {
|
||||
{
|
||||
// An array of lenght 3 is only sorted by find_pivot. Make sure that it is idempotent.
|
||||
int test_array[] = {1, 4, 8};
|
||||
int expected_array[] = {1, 4, 8};
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 3, test_even_odd_comparator, true));
|
||||
}
|
||||
{
|
||||
int test_array[] = {1, 7, 9, 4, 8, 2};
|
||||
int expected_array[] = {1, 7, 9, 4, 8, 2};
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
|
||||
}
|
||||
{
|
||||
int test_array[] = {1, 9, 7, 4, 2, 8};
|
||||
int expected_array[] = {1, 9, 7, 4, 2, 8};
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
|
||||
}
|
||||
{
|
||||
int test_array[] = {7, 9, 1, 2, 8, 4};
|
||||
int expected_array[] = {7, 9, 1, 2, 8, 4};
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
|
||||
}
|
||||
{
|
||||
int test_array[] = {7, 1, 9, 2, 4, 8};
|
||||
int expected_array[] = {7, 1, 9, 2, 4, 8};
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
|
||||
}
|
||||
{
|
||||
int test_array[] = {9, 1, 7, 4, 8, 2};
|
||||
int expected_array[] = {9, 1, 7, 4, 8, 2};
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
|
||||
}
|
||||
{
|
||||
int test_array[] = {9, 7, 1, 4, 2, 8};
|
||||
int expected_array[] = {9, 7, 1, 4, 2, 8};
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(QuickSort, random) {
|
||||
@ -186,18 +130,6 @@ TEST(QuickSort, random) {
|
||||
// Compare sorting to stdlib::qsort()
|
||||
qsort(expected_array, length, sizeof(int), test_stdlib_comparator);
|
||||
EXPECT_TRUE(sort_and_compare(test_array, expected_array, length, test_comparator));
|
||||
|
||||
// Make sure sorting is idempotent.
|
||||
// Both test_array and expected_array are sorted by the test_comparator.
|
||||
// Now sort them once with the test_even_odd_comparator. Then sort the
|
||||
// test_array one more time with test_even_odd_comparator and verify that
|
||||
// it is idempotent.
|
||||
QuickSort::sort(expected_array, length, test_even_odd_comparator, true);
|
||||
QuickSort::sort(test_array, length, test_even_odd_comparator, true);
|
||||
EXPECT_TRUE(compare_arrays(test_array, expected_array, length));
|
||||
QuickSort::sort(test_array, length, test_even_odd_comparator, true);
|
||||
EXPECT_TRUE(compare_arrays(test_array, expected_array, length));
|
||||
|
||||
FREE_C_HEAP_ARRAY(int, test_array);
|
||||
FREE_C_HEAP_ARRAY(int, expected_array);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user