1 // Copyright © 2016–2020 University of Malta
2
3 // This program is free software: you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public License
5 // as published by the Free Software Foundation, either version 3 of
6 // the License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful, but
9 // WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License and a copy of the GNU General Public License along with
15 // this program. If not, see <https://www.gnu.org/licenses/>.
16
17 #![allow(dead_code)]
18
19 use az::{CheckedCast, WrappingCast};
20
21 pub trait UnwrappedCast<Dst> {
unwrapped_cast(self) -> Dst22 fn unwrapped_cast(self) -> Dst;
23 }
24 impl<Dst, Src: CheckedCast<Dst>> UnwrappedCast<Dst> for Src {
25 #[inline]
unwrapped_cast(self) -> Dst26 fn unwrapped_cast(self) -> Dst {
27 self.checked_cast().expect("overflow")
28 }
29 }
30
31 pub trait UnwrappedAs {
unwrapped_as<Dst>(self) -> Dst where Self: UnwrappedCast<Dst>32 fn unwrapped_as<Dst>(self) -> Dst
33 where
34 Self: UnwrappedCast<Dst>;
35 }
36
37 impl<T> UnwrappedAs for T {
38 #[inline]
unwrapped_as<Dst>(self) -> Dst where Self: UnwrappedCast<Dst>,39 fn unwrapped_as<Dst>(self) -> Dst
40 where
41 Self: UnwrappedCast<Dst>,
42 {
43 self.unwrapped_cast()
44 }
45 }
46
47 pub trait NegAbs {
48 type Abs;
neg_abs(self) -> (bool, Self::Abs)49 fn neg_abs(self) -> (bool, Self::Abs);
50 }
51
52 macro_rules! neg_abs {
53 ($I:ty; $U:ty) => {
54 impl NegAbs for $I {
55 type Abs = $U;
56 #[inline]
57 fn neg_abs(self) -> (bool, $U) {
58 if self < 0 {
59 (true, self.wrapping_neg().wrapping_cast())
60 } else {
61 (false, self.wrapping_cast())
62 }
63 }
64 }
65
66 impl NegAbs for $U {
67 type Abs = $U;
68 #[inline]
69 fn neg_abs(self) -> (bool, $U) {
70 (false, self)
71 }
72 }
73 };
74 }
75
76 neg_abs! { i8; u8 }
77 neg_abs! { i16; u16 }
78 neg_abs! { i32; u32 }
79 neg_abs! { i64; u64 }
80 neg_abs! { i128; u128 }
81 neg_abs! { isize; usize }
82
83 #[inline]
trunc_f64_to_f32(f: f64) -> f3284 pub fn trunc_f64_to_f32(f: f64) -> f32 {
85 // f as f32 might round away from zero, so we need to clear
86 // the least significant bits of f.
87 // * If f is a nan, we do NOT want to clear any mantissa bits,
88 // as this may change f into +/- infinity.
89 // * If f is +/- infinity, the bits are already zero, so the
90 // masking has no effect.
91 // * If f is subnormal, f as f32 will be zero anyway.
92 if !f.is_nan() {
93 let u = f.to_bits();
94 // f64 has 29 more significant bits than f32.
95 let trunc_u = u & (!0 << 29);
96 let trunc_f = f64::from_bits(trunc_u);
97 trunc_f as f32
98 } else {
99 f as f32
100 }
101 }
102
lcase(byte: u8) -> u8103 fn lcase(byte: u8) -> u8 {
104 match byte {
105 b'A'..=b'Z' => byte - b'A' + b'a',
106 _ => byte,
107 }
108 }
109
trim_start(bytes: &[u8]) -> &[u8]110 pub fn trim_start(bytes: &[u8]) -> &[u8] {
111 for (start, &b) in bytes.iter().enumerate() {
112 match b {
113 b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d => {}
114 _ => return &bytes[start..],
115 }
116 }
117 &[]
118 }
119
trim_end(bytes: &[u8]) -> &[u8]120 pub fn trim_end(bytes: &[u8]) -> &[u8] {
121 for (end, &b) in bytes.iter().enumerate().rev() {
122 match b {
123 b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d => {}
124 _ => return &bytes[..=end],
125 }
126 }
127 &[]
128 }
129
130 // If bytes starts with a match to one of patterns, return bytes with
131 // the match skipped. Only bytes is converted to lcase.
skip_lcase_match<'a>(bytes: &'a [u8], patterns: &[&[u8]]) -> Option<&'a [u8]>132 pub fn skip_lcase_match<'a>(bytes: &'a [u8], patterns: &[&[u8]]) -> Option<&'a [u8]> {
133 'next_pattern: for pattern in patterns {
134 if bytes.len() < pattern.len() {
135 continue 'next_pattern;
136 }
137 for (&b, &p) in bytes.iter().zip(pattern.iter()) {
138 if lcase(b) != p {
139 continue 'next_pattern;
140 }
141 }
142 return Some(&bytes[pattern.len()..]);
143 }
144 None
145 }
146
147 // If bytes starts with '(' and has a matching ')', returns the
148 // contents and the remainder.
matched_brackets(bytes: &[u8]) -> Option<(&[u8], &[u8])>149 pub fn matched_brackets(bytes: &[u8]) -> Option<(&[u8], &[u8])> {
150 let mut iter = bytes.iter().enumerate();
151 match iter.next() {
152 Some((_, &b'(')) => {}
153 _ => return None,
154 }
155 let mut level = 1;
156 for (i, &b) in iter {
157 match b {
158 b'(' => level += 1,
159 b')' => {
160 level -= 1;
161 if level == 0 {
162 return Some((&bytes[1..i], &bytes[i + 1..]));
163 }
164 }
165 _ => {}
166 }
167 }
168 None
169 }
170
find_outside_brackets(bytes: &[u8], pattern: u8) -> Option<usize>171 pub fn find_outside_brackets(bytes: &[u8], pattern: u8) -> Option<usize> {
172 let mut level = 0;
173 for (i, &b) in bytes.iter().enumerate() {
174 match b {
175 b'(' => level += 1,
176 b')' if level > 0 => level -= 1,
177 _ if level == 0 && b == pattern => return Some(i),
178 _ => {}
179 }
180 }
181 None
182 }
183
find_space_outside_brackets(bytes: &[u8]) -> Option<usize>184 pub fn find_space_outside_brackets(bytes: &[u8]) -> Option<usize> {
185 let mut level = 0;
186 for (i, &b) in bytes.iter().enumerate() {
187 match b {
188 b'(' => level += 1,
189 b')' if level > 0 => level -= 1,
190 b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d if level == 0 => {
191 return Some(i);
192 }
193 _ => {}
194 }
195 }
196 None
197 }
198