malachite_base/chars/
crement.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::chars::constants::{
10    CHAR_JUST_BELOW_SURROGATES, FIRST_SURROGATE_CODE_POINT, NUMBER_OF_CHARS,
11    NUMBER_OF_SURROGATE_CODE_POINTS,
12};
13
14/// Converts a [`char`] to a [`u32`].
15///
16/// The conversion is done in such a way that if the next largest [`char`] after $x$ is $y$, then
17/// $\mathrm{char\\_to\\_contiguous\\_range(x)}+1 = \mathrm{char\\_to\\_contiguous\\_range(y)}$.
18/// This can't be accomplished just through casting, because there is a range of [`u32`]s (the
19/// [surrogate code points](https://www.unicode.org/glossary/#surrogate_code_point)) that do not
20/// correspond to any [`char`].
21///
22/// The inverse of this function is [`contiguous_range_to_char`].
23///
24/// # Worst-case complexity
25/// Constant time and additional memory.
26///
27/// # Examples
28/// ```
29/// use malachite_base::chars::crement::char_to_contiguous_range;
30/// use std::char;
31///
32/// assert_eq!(char_to_contiguous_range('\u{0}'), 0);
33/// assert_eq!(char_to_contiguous_range('a'), 97);
34/// assert_eq!(char_to_contiguous_range(char::MAX), 1112063);
35/// ```
36pub const fn char_to_contiguous_range(c: char) -> u32 {
37    match c {
38        '\u{0}'..=CHAR_JUST_BELOW_SURROGATES => c as u32,
39        _ => c as u32 - NUMBER_OF_SURROGATE_CODE_POINTS,
40    }
41}
42
43/// Converts a [`u32`] to a [`char`]; if all [`char`]s were arranged in ascending order, passing $u$
44/// to this function would return the $u$th [`char`].
45///
46/// This function is the inverse of [`char_to_contiguous_range`]. Every [`u32`] between $0$ and
47/// $\mathrm{NUMBER\\_OF\\_CHARS} - 1$, inclusive, is mapped to a distinct [`char`]. Passing a
48/// larger [`u32`] yields `None`.
49///
50/// # Worst-case complexity
51/// Constant time and additional memory.
52///
53/// # Examples
54/// ```
55/// use malachite_base::chars::crement::contiguous_range_to_char;
56/// use std::char;
57///
58/// assert_eq!(contiguous_range_to_char(0), Some('\u{0}'));
59/// assert_eq!(contiguous_range_to_char(97), Some('a'));
60/// assert_eq!(contiguous_range_to_char(1112063), Some(char::MAX));
61/// ```
62pub const fn contiguous_range_to_char(u: u32) -> Option<char> {
63    const ONE_BELOW_FIRST_SURROGATE_CODE_POINT: u32 = FIRST_SURROGATE_CODE_POINT - 1;
64    const ONE_BELOW_NUMBER_OF_CHARS: u32 = NUMBER_OF_CHARS - 1;
65    match u {
66        0..=ONE_BELOW_FIRST_SURROGATE_CODE_POINT => core::char::from_u32(u),
67        FIRST_SURROGATE_CODE_POINT..=ONE_BELOW_NUMBER_OF_CHARS => {
68            core::char::from_u32(u + NUMBER_OF_SURROGATE_CODE_POINTS)
69        }
70        _ => None,
71    }
72}
73
74/// Increments this [`char`], skipping over the [surrogate code
75/// points](https://www.unicode.org/glossary/#surrogate_code_point).
76///
77/// # Panics
78/// Panics if `self` is `char::MAX`.
79///
80/// # Examples
81/// ```
82/// use malachite_base::chars::crement::increment_char;
83///
84/// let mut c = '\u{0}';
85/// increment_char(&mut c);
86/// assert_eq!(c, '\u{1}');
87///
88/// let mut c = 'a';
89/// increment_char(&mut c);
90/// assert_eq!(c, 'b');
91/// ```
92#[inline]
93pub fn increment_char(c: &mut char) {
94    *c = contiguous_range_to_char(char_to_contiguous_range(*c) + 1)
95        .expect("Cannot increment char::MAX");
96}
97
98/// Decrements this [`char`], skipping over the [surrogate code
99/// points](https://www.unicode.org/glossary/#surrogate_code_point).
100///
101/// # Worst-case complexity
102/// Constant time and additional memory.
103///
104/// # Panics
105/// Panics if `self` is `'\u{0}'`.
106///
107/// # Examples
108/// ```
109/// use malachite_base::chars::crement::decrement_char;
110///
111/// let mut c = '\u{1}';
112/// decrement_char(&mut c);
113/// assert_eq!(c, '\u{0}');
114///
115/// let mut c = 'b';
116/// decrement_char(&mut c);
117/// assert_eq!(c, 'a');
118/// ```
119#[inline]
120pub fn decrement_char(c: &mut char) {
121    if *c == char::MIN {
122        panic!("Cannot decrement char '{}'", *c);
123    } else {
124        *c = contiguous_range_to_char(char_to_contiguous_range(*c) - 1).unwrap();
125    }
126}