Skip to main content

nekolib/utils/
buf_range.rs

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