-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8360023: Add an insertion sort implementation to Hotspot #25895
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
1ff7b27
32f48e2
ef934f6
f13d739
7fc72da
65bd14d
17f30c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* | ||
* Copyright (c) 2025, 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 | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
* | ||
*/ | ||
#ifndef SHARE_UTILITIES_SORT_HPP | ||
#define SHARE_UTILITIES_SORT_HPP | ||
|
||
#include "memory/allStatic.hpp" | ||
|
||
// An insertion sort that is stable and inplace. | ||
// This algorithm should be the ideal solution to sort a sequence with few elements. Arrays::sort | ||
// uses insertion sort for arrays up to around 50 elements. | ||
// comp should return a value > 0 iff the first argument is larger than the second argument. A full | ||
// comparison function satisfies this requirement but a simple a > b ? 1 : 0 also satisfies it. | ||
class InsertionSort : AllStatic { | ||
public: | ||
template <class T, class Compare> | ||
static void sort(T* data, int size, Compare comp) { | ||
if (size == 0) { | ||
return; | ||
} | ||
|
||
T* begin = data; | ||
T* end = data + size; | ||
for (T* current = begin + 1; current < end; current++) { | ||
T current_elem = *current; | ||
|
||
// Elements in [begin, current) has already been sorted, we search backward to find a | ||
// location to insert the element at current. In the meantime, shift all elements on the way | ||
// up by 1. | ||
T* pos = current; | ||
while (pos > begin) { | ||
// Because the sort is stable, we must insert the current element at the first location at | ||
// which the element is not greater than the current element (note that we are traversing | ||
// backward) | ||
T* prev = pos - 1; | ||
if (comp(*prev, current_elem) <= 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: would be better to pass pointers here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apologies, I didn't notice it was a reference. |
||
break; | ||
} | ||
|
||
*pos = *prev; | ||
pos = prev; | ||
} | ||
|
||
// Move current_elem to pos since all elements in [pos, current) have been shifted up by 1 | ||
if (pos < current) { | ||
*pos = current_elem; | ||
} | ||
} | ||
} | ||
}; | ||
|
||
#endif // SHARE_UTILITIES_SORT_HPP |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* | ||
* Copyright (c) 2025, 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 | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
* | ||
*/ | ||
|
||
#include "runtime/os.hpp" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: sort the imports? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have cleaned up the unused import here. What do you mean by sorting the imports? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sort the "#include" lines alphabetically. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume you want to have |
||
#include "unittest.hpp" | ||
#include "utilities/powerOfTwo.hpp" | ||
#include "utilities/sort.hpp" | ||
|
||
constexpr int TEST_ARRAY_SIZE = 128; | ||
|
||
class TwoInt { | ||
public: | ||
int val; | ||
int idx; | ||
|
||
TwoInt() : val(0), idx(0) {} | ||
TwoInt(int val, int idx) : val(val), idx(idx) {} | ||
}; | ||
|
||
int ARRAY0[TEST_ARRAY_SIZE]; | ||
TwoInt ARRAY1[TEST_ARRAY_SIZE]; | ||
|
||
// Verify that the sort is correct, i.e. a[i] <= a[i + 1] | ||
void test_insertion_sort(int size) { | ||
assert(size <= TEST_ARRAY_SIZE, "invalid parameter"); | ||
for (int i = 0; i < size; i++) { | ||
ARRAY0[i] = os::random(); | ||
} | ||
InsertionSort::sort(ARRAY0, size, [](int a, int b) { | ||
return a > b ? 1 : 0; | ||
}); | ||
for (int i = 0; i < size - 1; i++) { | ||
ASSERT_TRUE(ARRAY0[i] <= ARRAY0[i + 1]); | ||
} | ||
} | ||
|
||
// Verify that the sort is stable. Since there are 128 elements but the keys can only take 16 | ||
// values, there will inevitably be a lot of elements with the same key. We then verify that if the | ||
// keys of 2 elements are the same, then the element that has the smaller idx will be ordered | ||
// before the one with the larger idx. | ||
void test_insertion_sort_stable(int size, int key_bound) { | ||
assert(size <= TEST_ARRAY_SIZE, "invalid parameter"); | ||
assert(is_power_of_2(key_bound), "invalid parameter"); | ||
for (int i = 0; i < size; i++) { | ||
ARRAY1[i] = TwoInt(os::random() & (key_bound - 1), i); | ||
} | ||
InsertionSort::sort(ARRAY1, size, [](TwoInt a, TwoInt b) { | ||
return a.val > b.val ? 1 : 0; | ||
}); | ||
for (int i = 0; i < size - 1; i++) { | ||
TwoInt a = ARRAY1[i]; | ||
TwoInt b = ARRAY1[i + 1]; | ||
ASSERT_TRUE(a.val <= b.val); | ||
if (a.val == b.val) { | ||
ASSERT_TRUE(a.idx < b.idx); | ||
} | ||
} | ||
} | ||
|
||
TEST(utilities, insertion_sort) { | ||
for (int i = 0; i < 100; i++) { | ||
test_insertion_sort(0); | ||
test_insertion_sort(1); | ||
test_insertion_sort(2); | ||
test_insertion_sort(10); | ||
test_insertion_sort(TEST_ARRAY_SIZE); | ||
test_insertion_sort_stable(1, 1); | ||
test_insertion_sort_stable(2, 1); | ||
test_insertion_sort_stable(3, 2); | ||
test_insertion_sort_stable(10, 4); | ||
test_insertion_sort_stable(TEST_ARRAY_SIZE, 16); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int size
tosize_t size
? or at leastunsigned int
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hotspot container usually uses signed int for size. So I think
int
here is a sensible choice.