1 | use std::{ |
2 | mem::ManuallyDrop, |
3 | num::NonZeroUsize, |
4 | sync::atomic::{AtomicUsize, Ordering::Relaxed}, |
5 | }; |
6 | |
7 | use regex::Regex; |
8 | |
9 | #[macro_use ] |
10 | mod macros; |
11 | |
12 | pub mod fmt; |
13 | pub mod sort; |
14 | pub mod split_vec; |
15 | pub mod sync; |
16 | pub mod thread; |
17 | pub mod ty; |
18 | |
19 | /// Public-in-private type like `()` but meant to be externally-unreachable. |
20 | /// |
21 | /// Using this in place of `()` for `GenI` prevents `Bencher::with_inputs` from |
22 | /// working with `()` unintentionally. |
23 | #[non_exhaustive ] |
24 | pub struct Unit; |
25 | |
26 | /// Public-in-private trait to make `DivanConfig::skip_regex` polymorphic over |
27 | /// regular expression types. |
28 | pub trait IntoRegex { |
29 | fn into_regex(self) -> Regex; |
30 | } |
31 | |
32 | impl IntoRegex for Regex { |
33 | #[inline ] |
34 | fn into_regex(self) -> Regex { |
35 | self |
36 | } |
37 | } |
38 | |
39 | impl IntoRegex for &str { |
40 | #[inline ] |
41 | #[track_caller ] |
42 | fn into_regex(self) -> Regex { |
43 | Regex::new(self).unwrap() |
44 | } |
45 | } |
46 | |
47 | impl IntoRegex for String { |
48 | #[inline ] |
49 | #[track_caller ] |
50 | fn into_regex(self) -> Regex { |
51 | Regex::new(&self).unwrap() |
52 | } |
53 | } |
54 | |
55 | /// [`std::hint::assert_unchecked`] polyfill. |
56 | #[inline ] |
57 | pub(crate) const unsafe fn assert_unchecked(cond: bool) { |
58 | if !cond { |
59 | std::hint::unreachable_unchecked(); |
60 | } |
61 | } |
62 | |
63 | #[inline ] |
64 | pub(crate) fn defer<F: FnOnce()>(f: F) -> impl Drop { |
65 | struct Defer<F: FnOnce()>(ManuallyDrop<F>); |
66 | |
67 | impl<F: FnOnce()> Drop for Defer<F> { |
68 | #[inline ] |
69 | fn drop(&mut self) { |
70 | let f: F = unsafe { ManuallyDrop::take(&mut self.0) }; |
71 | |
72 | f(); |
73 | } |
74 | } |
75 | |
76 | Defer(ManuallyDrop::new(f)) |
77 | } |
78 | |
79 | /// Returns the index of `ptr` in the slice, assuming it is in the slice. |
80 | #[inline ] |
81 | pub(crate) fn slice_ptr_index<T>(slice: &[T], ptr: *const T) -> usize { |
82 | // Safe pointer `offset_from`. |
83 | (ptr as usize - slice.as_ptr() as usize) / size_of::<T>() |
84 | } |
85 | |
86 | /// Returns the values in the middle of `slice`. |
87 | /// |
88 | /// If the slice has an even length, two middle values exist. |
89 | #[inline ] |
90 | pub(crate) fn slice_middle<T>(slice: &[T]) -> &[T] { |
91 | let len: usize = slice.len(); |
92 | |
93 | if len == 0 { |
94 | slice |
95 | } else if len % 2 == 0 { |
96 | &slice[(len / 2) - 1..][..2] |
97 | } else { |
98 | &slice[len / 2..][..1] |
99 | } |
100 | } |
101 | |
102 | /// Cached [`std::thread::available_parallelism`]. |
103 | #[inline ] |
104 | pub(crate) fn known_parallelism() -> NonZeroUsize { |
105 | static CACHED: AtomicUsize = AtomicUsize::new(0); |
106 | |
107 | #[cold ] |
108 | fn slow() -> NonZeroUsize { |
109 | let n: NonZero = std::thread::available_parallelism().unwrap_or(default:NonZeroUsize::MIN); |
110 | |
111 | match CACHED.compare_exchange(current:0, new:n.get(), success:Relaxed, failure:Relaxed) { |
112 | Ok(_) => n, |
113 | |
114 | // SAFETY: Zero is checked by us and competing threads. |
115 | Err(n: usize) => unsafe { NonZeroUsize::new_unchecked(n) }, |
116 | } |
117 | } |
118 | |
119 | match NonZeroUsize::new(CACHED.load(order:Relaxed)) { |
120 | Some(n: NonZero) => n, |
121 | None => slow(), |
122 | } |
123 | } |
124 | |
125 | /// Returns `true` if running under [`cargo-nextest`](https://nexte.st). |
126 | pub(crate) fn is_cargo_nextest() -> bool { |
127 | std::env::var_os(key:"NEXTEST" ).unwrap_or_default() == "1" |
128 | } |
129 | |
130 | #[cfg (test)] |
131 | mod tests { |
132 | use crate::black_box; |
133 | |
134 | use super::*; |
135 | |
136 | #[test ] |
137 | fn known_parallelism() { |
138 | let f: fn() -> NonZeroUsize = super::known_parallelism; |
139 | assert_eq!(black_box(f)(), black_box(f)()); |
140 | } |
141 | |
142 | #[test ] |
143 | fn slice_middle() { |
144 | use super::slice_middle; |
145 | |
146 | assert_eq!(slice_middle::<i32>(&[]), &[]); |
147 | |
148 | assert_eq!(slice_middle(&[1]), &[1]); |
149 | assert_eq!(slice_middle(&[1, 2]), &[1, 2]); |
150 | assert_eq!(slice_middle(&[1, 2, 3]), &[2]); |
151 | assert_eq!(slice_middle(&[1, 2, 3, 4]), &[2, 3]); |
152 | assert_eq!(slice_middle(&[1, 2, 3, 4, 5]), &[3]); |
153 | } |
154 | } |
155 | |