| 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 | |