Skip to content

Commit 5341c24

Browse files
add missing priority_queue constructors, document emplace limitations
1 parent 457ea94 commit 5341c24

1 file changed

Lines changed: 195 additions & 14 deletions

File tree

‎cpp-overload-test/src/stdcpp/priority_queue.rs‎

Lines changed: 195 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,33 @@ cpp! {{
1313
#include <queue>
1414
#include <vector>
1515
#include <functional>
16+
#include <ranges>
1617
#include <cstddef>
1718
}}
1819

1920
/// Workaround for missing generic support in the `overload!` macro.
2021
pub type T = std::ffi::c_int;
2122

2223
/// Wrapper holding a heap-allocated C++ `std::priority_queue<int>` pointer.
23-
///
24-
/// ### Limitations
25-
///
26-
/// Only the default container and comparator are used, so constructors taking them are skipped.
2724
#[cfg_attr(not(test), expect(dead_code, reason = "Only used in tests"))]
2825
pub struct StdPriorityQueue(*mut c_void, PhantomData<T>);
2926

27+
pub struct StdLess;
28+
3029
#[cfg_attr(not(test), expect(dead_code, reason = "Only used in tests"))]
3130
#[allow(
3231
non_upper_case_globals,
3332
reason = "Triggered by cpp! macro in rust-analyzer"
3433
)]
3534
impl StdPriorityQueue {
35+
fn as_ptr_or_null(items: &[T]) -> *const T {
36+
if items.is_empty() {
37+
std::ptr::null()
38+
} else {
39+
items.as_ptr()
40+
}
41+
}
42+
3643
fn default() -> StdPriorityQueue {
3744
let pq = unsafe {
3845
cpp!([] -> *mut c_void as "std::priority_queue<int>*" {
@@ -42,12 +49,53 @@ impl StdPriorityQueue {
4249
StdPriorityQueue(pq, PhantomData)
4350
}
4451

52+
fn from_compare(_compare: &StdLess) -> StdPriorityQueue {
53+
let pq = unsafe {
54+
cpp!([] -> *mut c_void as "std::priority_queue<int>*" {
55+
return new std::priority_queue<int>(std::less<int>());
56+
})
57+
};
58+
StdPriorityQueue(pq, PhantomData)
59+
}
60+
61+
fn from_container_copy(_compare: &StdLess, cont: &[T]) -> StdPriorityQueue {
62+
let len = cont.len();
63+
let cont: *const T = StdPriorityQueue::as_ptr_or_null(cont);
64+
let pq = unsafe {
65+
cpp!([cont as "const int*", len as "size_t"] -> *mut c_void as "std::priority_queue<int>*" {
66+
const std::vector<int> container(cont, cont + len);
67+
return new std::priority_queue<int>(std::less<int>(), container);
68+
})
69+
};
70+
StdPriorityQueue(pq, PhantomData)
71+
}
72+
73+
fn from_container_move(_compare: &StdLess, cont: Vec<T>) -> StdPriorityQueue {
74+
let len = cont.len();
75+
let cont: *const T = StdPriorityQueue::as_ptr_or_null(&cont);
76+
let pq = unsafe {
77+
cpp!([cont as "const int*", len as "size_t"] -> *mut c_void as "std::priority_queue<int>*" {
78+
std::vector<int> container(cont, cont + len);
79+
return new std::priority_queue<int>(std::less<int>(), std::move(container));
80+
})
81+
};
82+
StdPriorityQueue(pq, PhantomData)
83+
}
84+
4585
fn from_slice(items: &[T]) -> StdPriorityQueue {
46-
if items.is_empty() {
47-
return StdPriorityQueue::default();
48-
}
4986
let len = items.len();
50-
let items: *const T = items.as_ptr();
87+
let items: *const T = StdPriorityQueue::as_ptr_or_null(items);
88+
let pq = unsafe {
89+
cpp!([items as "const int*", len as "size_t"] -> *mut c_void as "std::priority_queue<int>*" {
90+
return new std::priority_queue<int>(items, items + len);
91+
})
92+
};
93+
StdPriorityQueue(pq, PhantomData)
94+
}
95+
96+
fn from_slice_with_compare(items: &[T], _compare: &StdLess) -> StdPriorityQueue {
97+
let len = items.len();
98+
let items: *const T = StdPriorityQueue::as_ptr_or_null(items);
5199
let pq = unsafe {
52100
cpp!([items as "const int*", len as "size_t"] -> *mut c_void as "std::priority_queue<int>*" {
53101
return new std::priority_queue<int>(items, items + len, std::less<int>());
@@ -56,20 +104,74 @@ impl StdPriorityQueue {
56104
StdPriorityQueue(pq, PhantomData)
57105
}
58106

107+
fn from_slice_container_copy(items: &[T], _compare: &StdLess, cont: &[T]) -> StdPriorityQueue {
108+
let len = items.len();
109+
let items: *const T = StdPriorityQueue::as_ptr_or_null(items);
110+
let cont_len = cont.len();
111+
let cont: *const T = StdPriorityQueue::as_ptr_or_null(cont);
112+
let pq = unsafe {
113+
cpp!([items as "const int*", len as "size_t", cont as "const int*", cont_len as "size_t"] -> *mut c_void as "std::priority_queue<int>*" {
114+
const std::vector<int> container(cont, cont + cont_len);
115+
return new std::priority_queue<int>(items, items + len, std::less<int>(), container);
116+
})
117+
};
118+
StdPriorityQueue(pq, PhantomData)
119+
}
120+
121+
fn from_slice_container_move(
122+
items: &[T],
123+
_compare: &StdLess,
124+
cont: Vec<T>,
125+
) -> StdPriorityQueue {
126+
let len = items.len();
127+
let items: *const T = StdPriorityQueue::as_ptr_or_null(items);
128+
let cont_len = cont.len();
129+
let cont: *const T = StdPriorityQueue::as_ptr_or_null(&cont);
130+
let pq = unsafe {
131+
cpp!([items as "const int*", len as "size_t", cont as "const int*", cont_len as "size_t"] -> *mut c_void as "std::priority_queue<int>*" {
132+
std::vector<int> container(cont, cont + cont_len);
133+
return new std::priority_queue<int>(items, items + len, std::less<int>(), std::move(container));
134+
})
135+
};
136+
StdPriorityQueue(pq, PhantomData)
137+
}
138+
59139
/// ### Limitations
60140
///
61141
/// `overload!` can't take a generic iterator, so callers must cast to `&mut dyn Iterator`.
62-
/// This also stands in for the C++23 `from_range` constructor, whose tag isn't needed in Rust.
142+
/// This stands in for the C++23 `from_range` constructor, whose tag isn't needed in Rust.
63143
fn from_iter(iter: &mut dyn Iterator<Item = T>) -> StdPriorityQueue {
64144
let items: Vec<T> = iter.collect();
65-
if items.is_empty() {
66-
return StdPriorityQueue::default();
67-
}
68145
let len = items.len();
69-
let items: *const T = items.as_ptr();
146+
let items: *const T = StdPriorityQueue::as_ptr_or_null(&items);
70147
let pq = unsafe {
71148
cpp!([items as "const int*", len as "size_t"] -> *mut c_void as "std::priority_queue<int>*" {
72-
return new std::priority_queue<int>(items, items + len, std::less<int>());
149+
std::vector<int> vec(items, items + len);
150+
#ifdef __cpp_lib_containers_ranges
151+
return new std::priority_queue<int>(std::from_range, vec);
152+
#else
153+
#error "std::from_range is not available, try using `-std=c++23` or a newer compiler"
154+
#endif
155+
})
156+
};
157+
StdPriorityQueue(pq, PhantomData)
158+
}
159+
160+
fn from_iter_with_compare(
161+
iter: &mut dyn Iterator<Item = T>,
162+
_compare: &StdLess,
163+
) -> StdPriorityQueue {
164+
let items: Vec<T> = iter.collect();
165+
let len = items.len();
166+
let items: *const T = StdPriorityQueue::as_ptr_or_null(&items);
167+
let pq = unsafe {
168+
cpp!([items as "const int*", len as "size_t"] -> *mut c_void as "std::priority_queue<int>*" {
169+
std::vector<int> vec(items, items + len);
170+
#ifdef __cpp_lib_containers_ranges
171+
return new std::priority_queue<int>(std::from_range, vec, std::less<int>());
172+
#else
173+
#error "std::from_range is not available, try using `-std=c++23` or a newer compiler"
174+
#endif
73175
})
74176
};
75177
StdPriorityQueue(pq, PhantomData)
@@ -182,14 +284,42 @@ overload! {
182284
StdPriorityQueue::default()
183285
}
184286

287+
pub fn new(compare: &StdLess) -> StdPriorityQueue {
288+
StdPriorityQueue::from_compare(compare)
289+
}
290+
291+
pub fn new(compare: &StdLess, cont: &[T]) -> StdPriorityQueue {
292+
StdPriorityQueue::from_container_copy(compare, cont)
293+
}
294+
295+
pub fn new(compare: &StdLess, cont: Vec<T>) -> StdPriorityQueue {
296+
StdPriorityQueue::from_container_move(compare, cont)
297+
}
298+
185299
pub fn new(items: &[T]) -> StdPriorityQueue {
186300
StdPriorityQueue::from_slice(items)
187301
}
188302

303+
pub fn new(items: &[T], compare: &StdLess) -> StdPriorityQueue {
304+
StdPriorityQueue::from_slice_with_compare(items, compare)
305+
}
306+
307+
pub fn new(items: &[T], compare: &StdLess, cont: &[T]) -> StdPriorityQueue {
308+
StdPriorityQueue::from_slice_container_copy(items, compare, cont)
309+
}
310+
311+
pub fn new(items: &[T], compare: &StdLess, cont: Vec<T>) -> StdPriorityQueue {
312+
StdPriorityQueue::from_slice_container_move(items, compare, cont)
313+
}
314+
189315
pub fn new(iter: &mut dyn Iterator<Item = T>) -> StdPriorityQueue {
190316
StdPriorityQueue::from_iter(iter)
191317
}
192318

319+
pub fn new(iter: &mut dyn Iterator<Item = T>, compare: &StdLess) -> StdPriorityQueue {
320+
StdPriorityQueue::from_iter_with_compare(iter, compare)
321+
}
322+
193323
pub fn new(other: &StdPriorityQueue) -> StdPriorityQueue {
194324
StdPriorityQueue::copy_from(other)
195325
}
@@ -214,6 +344,11 @@ overload! {
214344

215345
overload! {
216346
impl StdPriorityQueue {
347+
/// ### Limitations
348+
///
349+
/// `self` is ignored when picking overloads, the macro only looks at the other arguments.
350+
/// Constructor argument types that end up as the same Rust type will clash (`long` and `long long` are both `i64`, for example).
351+
/// `int` is fine, no conflict there.
217352
pub fn emplace(&mut self) {
218353
self.emplace_default()
219354
}
@@ -231,19 +366,65 @@ pub fn test_priority_queue() {
231366
assert_eq!(default_pq.len(), 0);
232367
assert_eq!(default_pq.top_const(), None);
233368

369+
let from_compare = StdPriorityQueue::new(&StdLess);
370+
assert!(from_compare.is_empty());
371+
372+
let from_container_copy = StdPriorityQueue::new(&StdLess, [3, 1, 4].as_slice());
373+
assert_eq!(from_container_copy.top_const(), Some(&4));
374+
assert_eq!(from_container_copy.len(), 3);
375+
let from_empty_container_copy = StdPriorityQueue::new(&StdLess, [].as_slice());
376+
assert!(from_empty_container_copy.is_empty());
377+
378+
let from_container_move = StdPriorityQueue::new(&StdLess, vec![3, 1, 4]);
379+
assert_eq!(from_container_move.top_const(), Some(&4));
380+
assert_eq!(from_container_move.len(), 3);
381+
let from_empty_container_move = StdPriorityQueue::new(&StdLess, Vec::new());
382+
assert!(from_empty_container_move.is_empty());
383+
234384
let from_slice: StdPriorityQueue = StdPriorityQueue::new([3, 1, 4, 1, 5].as_slice());
235385
assert_eq!(from_slice.top_const(), Some(&5));
236386
assert_eq!(from_slice.len(), 5);
237387
let from_empty_slice = StdPriorityQueue::new([].as_slice());
238388
assert!(from_empty_slice.is_empty());
239389

390+
let from_slice_with_compare = StdPriorityQueue::new([3, 1, 4].as_slice(), &StdLess);
391+
assert_eq!(from_slice_with_compare.top_const(), Some(&4));
392+
let from_empty_slice_with_compare = StdPriorityQueue::new([].as_slice(), &StdLess);
393+
assert!(from_empty_slice_with_compare.is_empty());
394+
395+
let from_slice_container_copy =
396+
StdPriorityQueue::new([5, 2].as_slice(), &StdLess, [9, 1].as_slice());
397+
assert_eq!(from_slice_container_copy.top_const(), Some(&9));
398+
assert_eq!(from_slice_container_copy.len(), 4);
399+
let from_empty_slice_container_copy =
400+
StdPriorityQueue::new([].as_slice(), &StdLess, [].as_slice());
401+
assert!(from_empty_slice_container_copy.is_empty());
402+
403+
let from_slice_container_move = StdPriorityQueue::new([5, 2].as_slice(), &StdLess, vec![9, 1]);
404+
assert_eq!(from_slice_container_move.top_const(), Some(&9));
405+
assert_eq!(from_slice_container_move.len(), 4);
406+
let from_empty_slice_container_move =
407+
StdPriorityQueue::new([].as_slice(), &StdLess, Vec::new());
408+
assert!(from_empty_slice_container_move.is_empty());
409+
240410
let mut iter: std::array::IntoIter<T, 3> = [10, 20, 30].into_iter();
241411
let from_iter = StdPriorityQueue::new(&mut iter as &mut dyn Iterator<Item = _>);
242412
assert_eq!(from_iter.top_const(), Some(&30));
243413
let mut empty_iter: std::array::IntoIter<T, 0> = [].into_iter();
244414
let from_empty_iter = StdPriorityQueue::new(&mut empty_iter as &mut dyn Iterator<Item = _>);
245415
assert!(from_empty_iter.is_empty());
246416

417+
let mut compare_iter: std::array::IntoIter<T, 3> = [10, 20, 30].into_iter();
418+
let from_iter_with_compare =
419+
StdPriorityQueue::new(&mut compare_iter as &mut dyn Iterator<Item = _>, &StdLess);
420+
assert_eq!(from_iter_with_compare.top_const(), Some(&30));
421+
let mut empty_compare_iter: std::array::IntoIter<T, 0> = [].into_iter();
422+
let from_empty_iter_with_compare = StdPriorityQueue::new(
423+
&mut empty_compare_iter as &mut dyn Iterator<Item = _>,
424+
&StdLess,
425+
);
426+
assert!(from_empty_iter_with_compare.is_empty());
427+
247428
let ref_clone = StdPriorityQueue::new(&from_slice);
248429
assert_eq!(ref_clone.top_const(), Some(&5));
249430
assert_eq!(ref_clone.len(), 5);

0 commit comments

Comments
 (0)