Commit 008bc53c authored by Matthew Edwards's avatar Matthew Edwards Committed by GitHub

Add partitioning and sorting operations to libcpp.algorithm (GH-3202)

* Add is_partitioned and partition to libcpp.algorithm
* Add is_sorted and is_sorted_until to libcpp.algorithm
* Add partition_copy, stable_partition, and partition_point to libcpp.algorithm
* Move tests for sort and partial_sort into cpp_stl_algo_sorting_ops, add greater to libcpp.functional
* Add partial_sort_copy to libcpp.algorithm
* Add stable_sort to libcpp.algorithm
* Add nth_element to libcpp.algorithm
* Add missing except specifiers in libcpp.algorithm
parent 1582d97d
......@@ -11,44 +11,45 @@ cdef extern from "<algorithm>" namespace "std" nogil:
void for_each[Iter, UnaryFunction](Iter first, Iter last, UnaryFunction f) except + # actually returns f
ptrdiff_t count[Iter, T](Iter first, Iter last, const T& value)
ptrdiff_t count[Iter, T](Iter first, Iter last, const T& value) except +
ptrdiff_t count_if[Iter, Pred](Iter first, Iter last, Pred pred) except +
pair[Iter1, Iter2] mismatch[Iter1, Iter2](Iter1 first1, Iter1 last1, Iter2 first2) # other overloads are tricky
pair[Iter1, Iter2] mismatch[Iter1, Iter2](
Iter1 first1, Iter1 last1, Iter2 first2) except + # other overloads are tricky
Iter find[Iter, T](Iter first, Iter last, const T& value)
Iter find[Iter, T](Iter first, Iter last, const T& value) except +
Iter find_if[Iter, Pred](Iter first, Iter last, Pred pred) except +
Iter find_if_not[Iter, Pred](Iter first, Iter last, Pred pred) except +
Iter1 find_end[Iter1, Iter2](Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
Iter1 find_end[Iter1, Iter2](Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) except +
Iter1 find_end[Iter1, Iter2, BinaryPred](
Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2, BinaryPred pred) except +
Iter1 find_first_of[Iter1, Iter2](Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
Iter1 find_first_of[Iter1, Iter2](Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) except +
Iter1 find_first_of[Iter1, Iter2, BinaryPred](
Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2, BinaryPred pred) except +
Iter adjacent_find[Iter](Iter first, Iter last)
Iter adjacent_find[Iter](Iter first, Iter last) except +
Iter adjacent_find[Iter, BinaryPred](Iter first, Iter last, BinaryPred pred) except +
Iter1 search[Iter1, Iter2](Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
Iter1 search[Iter1, Iter2](Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) except +
Iter1 search[Iter1, Iter2, BinaryPred](
Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2, BinaryPred pred) except +
Iter search_n[Iter, Size, T](Iter first1, Iter last1, Size count, const T& value)
Iter search_n[Iter, Size, T](Iter first1, Iter last1, Size count, const T& value) except +
Iter search_n[Iter, Size, T, BinaryPred](
Iter first1, Iter last1, Size count, const T& value, BinaryPred pred) except +
# Modifying sequence operations
OutputIt copy[InputIt, OutputIt](InputIt first, InputIt last, OutputIt d_first)
OutputIt copy[InputIt, OutputIt](InputIt first, InputIt last, OutputIt d_first) except +
OutputIt copy_if[InputIt, OutputIt, Pred](InputIt first, InputIt last, OutputIt d_first, Pred pred) except +
OutputIt copy_n[InputIt, Size, OutputIt](InputIt first, Size count, OutputIt result)
Iter2 copy_backward[Iter1, Iter2](Iter1 first, Iter1 last, Iter2 d_last)
OutputIt copy_n[InputIt, Size, OutputIt](InputIt first, Size count, OutputIt result) except +
Iter2 copy_backward[Iter1, Iter2](Iter1 first, Iter1 last, Iter2 d_last) except +
OutputIt move[InputIt, OutputIt](InputIt first, InputIt last, OutputIt d_first)
Iter2 move_backward[Iter1, Iter2](Iter1 first, Iter1 last, Iter2 d_last)
OutputIt move[InputIt, OutputIt](InputIt first, InputIt last, OutputIt d_first) except +
Iter2 move_backward[Iter1, Iter2](Iter1 first, Iter1 last, Iter2 d_last) except +
void fill[Iter, T](Iter first, Iter last, const T& value)
Iter fill_n[Iter, Size, T](Iter first, Size count, const T& value)
void fill[Iter, T](Iter first, Iter last, const T& value) except +
Iter fill_n[Iter, Size, T](Iter first, Size count, const T& value) except +
OutputIt transform[InputIt, OutputIt, UnaryOp](
InputIt first1, InputIt last1, OutputIt d_first, UnaryOp unary_op) except +
......@@ -58,53 +59,75 @@ cdef extern from "<algorithm>" namespace "std" nogil:
void generate[Iter, Generator](Iter first, Iter last, Generator g) except +
void generate_n[Iter, Size, Generator](Iter first, Size count, Generator g) except +
Iter remove[Iter, T](Iter first, Iter last, const T& value)
Iter remove_if[Iter, UnaryPred](Iter first, Iter last, UnaryPred pred)
OutputIt remove_copy[InputIt, OutputIt, T](InputIt first, InputIt last, OutputIt d_first, const T& value)
Iter remove[Iter, T](Iter first, Iter last, const T& value) except +
Iter remove_if[Iter, UnaryPred](Iter first, Iter last, UnaryPred pred) except +
OutputIt remove_copy[InputIt, OutputIt, T](InputIt first, InputIt last, OutputIt d_first, const T& value) except +
OutputIt remove_copy_if[InputIt, OutputIt, UnaryPred](
InputIt first, InputIt last, OutputIt d_first, UnaryPred pred) except +
void replace[Iter, T](Iter first, Iter last, const T& old_value, const T& new_value)
void replace[Iter, T](Iter first, Iter last, const T& old_value, const T& new_value) except +
void replace_if[Iter, UnaryPred, T](Iter first, Iter last, UnaryPred pred, const T& new_value) except +
OutputIt replace_copy[InputIt, OutputIt, T](
InputIt first, InputIt last, OutputIt d_first, const T& old_value, const T& new_value)
InputIt first, InputIt last, OutputIt d_first, const T& old_value, const T& new_value) except +
OutputIt replace_copy_if[InputIt, OutputIt, UnaryPred, T](
InputIt first, InputIt last, OutputIt d_first, UnaryPred pred, const T& new_value) except +
void swap[T](T& a, T& b) # array overload also works
Iter2 swap_ranges[Iter1, Iter2](Iter1 first1, Iter1 last1, Iter2 first2)
void iter_swap[Iter](Iter a, Iter b)
void swap[T](T& a, T& b) except + # array overload also works
Iter2 swap_ranges[Iter1, Iter2](Iter1 first1, Iter1 last1, Iter2 first2) except +
void iter_swap[Iter](Iter a, Iter b) except +
void reverse[Iter](Iter first, Iter last)
OutputIt reverse_copy[InputIt, OutputIt](InputIt first, InputIt last, OutputIt d_first)
void reverse[Iter](Iter first, Iter last) except +
OutputIt reverse_copy[InputIt, OutputIt](InputIt first, InputIt last, OutputIt d_first) except +
Iter rotate[Iter](Iter first, Iter n_first, Iter last)
OutputIt rotate_copy[InputIt, OutputIt](InputIt first, InputIt n_first, InputIt last, OutputIt d_first)
Iter rotate[Iter](Iter first, Iter n_first, Iter last) except +
OutputIt rotate_copy[InputIt, OutputIt](InputIt first, InputIt n_first, InputIt last, OutputIt d_first) except +
Iter unique[Iter](Iter first, Iter last)
Iter unique[Iter](Iter first, Iter last) except +
Iter unique[Iter, BinaryPred](Iter first, Iter last, BinaryPred p) except +
OutputIt unique_copy[InputIt, OutputIt](InputIt first, InputIt last, OutputIt d_first)
OutputIt unique_copy[InputIt, OutputIt](InputIt first, InputIt last, OutputIt d_first) except +
OutputIt unique_copy[InputIt, OutputIt, BinaryPred](
InputIt first, InputIt last, OutputIt d_first, BinaryPred pred) except +
# Partitioning operations
bool is_partitioned[Iter, Pred](Iter first, Iter last, Pred p) except +
Iter partition[Iter, Pred](Iter first, Iter last, Pred p) except +
pair[OutputIt1, OutputIt2] partition_copy[InputIt, OutputIt1, OutputIt2, Pred](
InputIt first, InputIt last, OutputIt1 d_first_true, OutputIt2 d_first_false, Pred p) except +
Iter stable_partition[Iter, Pred](Iter first, Iter last, Pred p) except +
Iter partition_point[Iter, Pred](Iter first, Iter last, Pred p) except +
# Sorting operations
void sort[Iter](Iter first, Iter last)
bool is_sorted[Iter](Iter first, Iter last) except +
bool is_sorted[Iter, Compare](Iter first, Iter last, Compare comp) except +
Iter is_sorted_until[Iter](Iter first, Iter last) except +
Iter is_sorted_until[Iter, Compare](Iter first, Iter last, Compare comp) except +
void sort[Iter](Iter first, Iter last) except +
void sort[Iter, Compare](Iter first, Iter last, Compare comp) except +
void partial_sort[Iter](Iter first, Iter middle, Iter last)
void partial_sort[Iter](Iter first, Iter middle, Iter last) except +
void partial_sort[Iter, Compare](Iter first, Iter middle, Iter last, Compare comp) except +
OutputIt partial_sort_copy[InputIt, OutputIt](
InputIt first, InputIt last, OutputIt d_first, OutputIt d_last) except +
OutputIt partial_sort_copy[InputIt, OutputIt, Compare](
InputIt first, InputIt last, OutputIt d_first, OutputIt d_last, Compare comp) except +
void stable_sort[Iter](Iter first, Iter last) except +
void stable_sort[Iter, Compare](Iter first, Iter last, Compare comp) except +
void nth_element[Iter](Iter first, Iter nth, Iter last) except +
void nth_element[Iter, Compare](Iter first, Iter nth, Iter last, Compare comp) except +
# Binary search operations (on sorted ranges)
Iter lower_bound[Iter, T](Iter first, Iter last, const T& value)
Iter lower_bound[Iter, T](Iter first, Iter last, const T& value) except +
Iter lower_bound[Iter, T, Compare](Iter first, Iter last, const T& value, Compare comp) except +
Iter upper_bound[Iter, T](Iter first, Iter last, const T& value)
Iter upper_bound[Iter, T](Iter first, Iter last, const T& value) except +
Iter upper_bound[Iter, T, Compare](Iter first, Iter last, const T& value, Compare comp) except +
bool binary_search[Iter, T](Iter first, Iter last, const T& value)
bool binary_search[Iter, T](Iter first, Iter last, const T& value) except +
bool binary_search[Iter, T, Compare](Iter first, Iter last, const T& value, Compare comp) except +
# Other operations on sorted ranges
......@@ -112,20 +135,20 @@ cdef extern from "<algorithm>" namespace "std" nogil:
# Set operations (on sorted ranges)
# Heap operations
void make_heap[Iter](Iter first, Iter last)
void make_heap[Iter](Iter first, Iter last) except +
void make_heap[Iter, Compare](Iter first, Iter last, Compare comp) except +
void push_heap[Iter](Iter first, Iter last)
void push_heap[Iter](Iter first, Iter last) except +
void push_heap[Iter, Compare](Iter first, Iter last, Compare comp) except +
void pop_heap[Iter](Iter first, Iter last)
void pop_heap[Iter](Iter first, Iter last) except +
void pop_heap[Iter, Compare](Iter first, Iter last, Compare comp) except +
void sort_heap[Iter](Iter first, Iter last)
void sort_heap[Iter](Iter first, Iter last) except +
void sort_heap[Iter, Compare](Iter first, Iter last, Compare comp) except +
# Minimum/maximum operations
Iter min_element[Iter](Iter first, Iter last)
Iter min_element[Iter](Iter first, Iter last) except +
# Comparison operations
......
from libcpp cimport bool
cdef extern from "<functional>" namespace "std" nogil:
cdef cppclass function[T]:
function() except +
......@@ -10,4 +12,10 @@ cdef extern from "<functional>" namespace "std" nogil:
function operator=(void*)
function operator=[U](U)
bint operator bool()
bool operator bool()
# Comparisons
cdef cppclass greater[T=*]:
# https://github.com/cython/cython/issues/3193
greater() except +
bool operator()(const T& lhs, const T& rhs) except +
# mode: run
# tag: cpp, werror, cpp11
from __future__ import print_function
from libcpp cimport bool
from libcpp.algorithm cimport is_partitioned, partition, partition_copy, stable_partition, partition_point
from libcpp.algorithm cimport for_each, copy, reverse
from libcpp.iterator cimport back_inserter
from libcpp.vector cimport vector
cdef bool is_even(int i):
return i % 2 == 0
def test_is_partitioned():
"""
>>> test_is_partitioned()
False
True
False
"""
cdef vector[int] values = range(10)
print(is_partitioned(values.begin(), values.end(), is_even))
partition(values.begin(), values.end(), &is_even)
print(is_partitioned(values.begin(), values.end(), is_even))
reverse(values.begin(), values.end())
print(is_partitioned(values.begin(), values.end(), is_even))
cdef int print_int(int v) except -1:
print(v, end=" ")
def print_partition(vector[int] values):
"""
Test partition.
>> print_partition(range(10))
0 8 2 6 4 * 5 3 7 1 9
"""
it = partition(values.begin(), values.end(), &is_even)
for_each(values.begin(), it, &print_int)
print("*", end=" ")
for_each(it, values.end(), &print_int)
print()
def partition_ints_even(vector[int] values):
"""
Test partition_copy.
>>> partition_ints_even(range(10))
([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
"""
cdef vector[int] even_values, odd_values
partition_copy(values.begin(), values.end(), back_inserter(even_values), back_inserter(odd_values), &is_even)
return even_values, odd_values
cdef bool is_positive(int v):
return v > 0
def partition_ints_positive(vector[int] values):
"""
Test stable_partition.
>>> partition_ints_positive([0, 0, 3, 0, 2, 4, 5, 0, 7])
[3, 2, 4, 5, 7, 0, 0, 0, 0]
"""
stable_partition(values.begin(), values.end(), &is_positive)
return values
def partition_point_ints_even(vector[int] values):
"""
Test partition_point.
>>> partition_point_ints_even([0, 8, 2, 6, 4, 5, 3, 7, 1, 9])
([0, 8, 2, 6, 4], [5, 3, 7, 1, 9])
"""
it = partition_point(values.begin(), values.end(), is_even)
cdef vector[int] even_values, odd_values
copy(values.begin(), it, back_inserter(even_values))
copy(it, values.end(), back_inserter(odd_values))
return even_values, odd_values
# mode: run
# tag: cpp, werror, cpp11
from __future__ import print_function
from libcpp cimport bool
from libcpp.algorithm cimport is_sorted, is_sorted_until, sort, partial_sort, partial_sort_copy, stable_sort
from libcpp.algorithm cimport nth_element
from libcpp.functional cimport greater
from libcpp.iterator cimport distance
from libcpp.string cimport string
from libcpp.vector cimport vector
def is_sorted_ints(vector[int] values):
"""
Test is_sorted.
>>> is_sorted_ints([3, 1, 4, 1, 5])
False
>>> is_sorted_ints([1, 1, 3, 4, 5])
True
"""
return is_sorted(values.begin(), values.end())
def initial_sorted_elements(vector[int] values):
"""
Test is_sorted_until.
>>> initial_sorted_elements([4, 1, 9, 5, 1, 3])
1
>>> initial_sorted_elements([4, 5, 9, 3, 1, 1])
3
>>> initial_sorted_elements([9, 3, 1, 4, 5, 1])
1
>>> initial_sorted_elements([1, 3, 5, 4, 1, 9])
3
>>> initial_sorted_elements([5, 9, 1, 1, 3, 4])
2
>>> initial_sorted_elements([4, 9, 1, 5, 1, 3])
2
>>> initial_sorted_elements([1, 1, 4, 9, 5, 3])
4
"""
sorted_end = is_sorted_until(values.begin(), values.end())
return distance(values.begin(), sorted_end)
def sort_ints(vector[int] values):
"""Test sort using the default operator<.
>>> sort_ints([5, 7, 4, 2, 8, 6, 1, 9, 0, 3])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
"""
sort(values.begin(), values.end())
return values
def sort_ints_reverse(vector[int] values):
"""Test sort using a standard library comparison function object.
>>> sort_ints_reverse([5, 7, 4, 2, 8, 6, 1, 9, 0, 3])
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
"""
sort(values.begin(), values.end(), greater[int]())
return values
def partial_sort_ints(vector[int] values, int k):
"""
Test partial_sort using the default operator<.
>>> partial_sort_ints([4, 2, 3, 1, 5], 2)[:2]
[1, 2]
"""
partial_sort(values.begin(), values.begin() + k, values.end())
return values
def partial_sort_ints_reverse(vector[int] values, int k):
"""
Test partial_sort using a standard library comparison function object.
>>> partial_sort_ints_reverse([4, 2, 3, 1, 5], 2)[:2]
[5, 4]
"""
partial_sort(values.begin(), values.begin() + k, values.end(), greater[int]())
return values
def partial_sort_ints2(vector[int] values, int k):
"""
Test partial_sort_copy using the default operator<.
>>> partial_sort_ints2([4, 2, 3, 1, 5], 2)
[1, 2]
"""
output = vector[int](2)
partial_sort_copy(values.begin(), values.end(), output.begin(), output.end())
return output
def partial_sort_ints_reverse2(vector[int] values, int k):
"""
Test partial_sort_copy using a standard library comparison function object.
>>> partial_sort_ints_reverse2([4, 2, 3, 1, 5], 2)
[5, 4]
"""
output = vector[int](2)
partial_sort_copy(values.begin(), values.end(), output.begin(), output.end(), greater[int]())
return output
cdef extern from *:
"""
struct Employee
{
Employee() = default;
Employee(int age, std::string name): age(age), name(name) {}
int age;
std::string name; // Does not participate in comparisons
};
bool operator<(const Employee& lhs, const Employee& rhs)
{
return lhs.age < rhs.age;
}
"""
cppclass Employee:
Employee()
Employee(int, string)
int age
string name
cdef bool Employee_greater(const Employee& lhs, const Employee& rhs):
return lhs.age > rhs.age
def test_stable_sort():
"""
Test stable_sort using cppreference example.
>>> test_stable_sort()
32, Arthur
108, Zaphod
108, Ford
108, Zaphod
108, Ford
32, Arthur
"""
cdef vector[Employee] employees
employees.push_back(Employee(108, <string>b"Zaphod"))
employees.push_back(Employee(32, <string>b"Arthur"))
employees.push_back(Employee(108, <string>b"Ford"))
stable_sort(employees.begin(), employees.end())
for e in employees:
print("%s, %s" % (e.age, <str>(e.name).decode("ascii")))
stable_sort(employees.begin(), employees.end(), &Employee_greater)
for e in employees:
print("%s, %s" % (e.age, <str>(e.name).decode("ascii")))
def second_smallest(vector[int] values):
"""
Test nth_element using the default operator<.
>>> second_smallest([5, 6, 4, 3, 2, 6, 7, 9, 3])
3
"""
nth_element(values.begin(), values.begin() + 1, values.end())
return values[1]
def second_largest(vector[int] values):
"""
Test nth_element using a standard library comparison function object.
>>> second_largest([5, 6, 4, 3, 2, 6, 7, 9, 3])
7
"""
nth_element(values.begin(), values.begin() + 1, values.end(), greater[int]())
return values[1]
......@@ -2,7 +2,7 @@
# tag: cpp
from libcpp cimport bool
from libcpp.algorithm cimport make_heap, sort_heap, sort, partial_sort
from libcpp.algorithm cimport make_heap, sort_heap
from libcpp.vector cimport vector
......@@ -28,33 +28,3 @@ def heapsort(l, bool reverse=False):
sort_heap(v.begin(), v.end())
return v
def partialsort(l, int k, reverse=False):
"""
>>> partialsort([4, 2, 3, 1, 5], k=2)[:2]
[1, 2]
>>> partialsort([4, 2, 3, 1, 5], k=2, reverse=True)[:2]
[5, 4]
"""
cdef vector[int] v = l
if reverse:
partial_sort(v.begin(), v.begin() + k, v.end(), &greater)
else:
partial_sort(v.begin(), v.begin() + k, v.end())
return v
def stdsort(l, reverse=False):
"""
>>> stdsort([3, 2, 1, 4, 5])
[1, 2, 3, 4, 5]
>>> stdsort([3, 2, 1, 4, 5], reverse=True)
[5, 4, 3, 2, 1]
"""
cdef vector[int] v = l
if reverse:
sort(v.begin(), v.end(), &greater)
else:
sort(v.begin(), v.end())
return v
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment