1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
//! 配列上の区間に関する関数。
use std::fmt::Debug;
use std::ops::Bound::{Excluded, Included, Unbounded};
use std::ops::{Range, RangeBounds};
/// 区間を配列サイズに収まるように丸める。
///
/// 与えられた区間 `r` と `0..len` の共通部分を、有界な半開区間として返す。
///
/// # Notes
///
/// 終端が陽に与えられたとき(有限のとき)は out of bounds でもそのまま返す。
/// 潜在的なバグの原因を見逃すのを防ぎたいので。
///
/// # Examples
/// ```
/// use nekolib::utils::bounds_within;
///
/// assert_eq!(bounds_within(.., 7), 0..7);
/// assert_eq!(bounds_within(..=4, 7), 0..5);
/// ```
pub fn bounds_within<R: RangeBounds<usize>>(r: R, len: usize) -> Range<usize> {
let e_ex = match r.end_bound() {
Included(&e) => e + 1,
Excluded(&e) => e,
Unbounded => len,
};
let s_in = match r.start_bound() {
Included(&s) => s,
Excluded(&s) => s + 1,
Unbounded => 0,
}
.min(e_ex);
s_in..e_ex
}
/// 境界チェックを行う。
///
/// # Examples
/// ```
/// use nekolib::utils::check_bounds;
///
/// let a = [0, 1, 2];
/// check_bounds(2, a.len());
/// ```
///
/// ```should_panic
/// use nekolib::utils::check_bounds;
///
/// let a = [0, 1, 2];
/// // panicked at 'index out of bounds: the len is 3 but the index is 3'
/// check_bounds(3, a.len());
/// ```
pub fn check_bounds(i: usize, len: usize) {
assert!(
i < len,
"index out of bounds: the len is {} but the index is {}",
len,
i
);
}
/// 境界チェックを行う。
///
/// # Examples
/// ```
/// use nekolib::utils::check_bounds_range;
///
/// let a = [0, 1, 2];
/// check_bounds_range(2, 0..a.len());
/// check_bounds_range(3, 0..=a.len());
/// ```
///
/// ```should_panic
/// use nekolib::utils::check_bounds_range;
///
/// let a = [0, 1, 2];
/// // panicked at 'index out of bounds: the range is 0..=3 but the index is 4'
/// check_bounds_range(4, 0..=a.len());
/// ```
pub fn check_bounds_range(i: usize, range: impl RangeBounds<usize> + Debug) {
assert!(
range.contains(&i),
"index out of bounds: the range is {:?} but the index is {}",
range,
i
);
}
#[test]
#[should_panic]
fn test_panic_bound_large() { check_bounds_range(4, 0..=3); }
#[test]
#[should_panic]
fn test_panic_bound_small() { check_bounds_range(0, 1..=3); }
#[test]
fn test_check() {
check_bounds_range(0, 0..=3);
check_bounds_range(3, 0..=3);
check_bounds_range(2, 0..3);
}
#[test]
fn test_range() {
assert_eq!(bounds_within(0..3, 2), 0..3);
assert_eq!(bounds_within(0..3, 3), 0..3);
assert_eq!(bounds_within(0..3, 4), 0..3);
assert_eq!(bounds_within(0.., 2), 0..2);
assert_eq!(bounds_within(0.., 3), 0..3);
assert_eq!(bounds_within(0.., 4), 0..4);
assert_eq!(bounds_within((Excluded(2), Included(5)), 8), 3..6);
assert_eq!(bounds_within(.., 5), 0..5);
}