malachite_base/chars/exhaustive.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::CharType;
10use crate::chars::crement::increment_char;
11use core::ops::RangeInclusive;
12
13/// Generates all ASCII [`char`]s, in ascending order.
14///
15/// For a friendlier order (_e.g_. nonprintable [`char`]s coming last), try
16/// [`exhaustive_ascii_chars`].
17///
18/// The output length is 128.
19///
20/// # Complexity per iteration
21/// Constant time and additional memory.
22///
23/// # Examples
24/// ```
25/// use malachite_base::chars::exhaustive::ascii_chars_increasing;
26///
27/// assert_eq!(
28/// ascii_chars_increasing().collect::<String>(),
29/// "\u{0}\u{1}\u{2}\u{3}\u{4}\u{5}\u{6}\u{7}\u{8}\t\n\u{b}\u{c}\r\u{e}\u{f}\u{10}\u{11}\u{12}\
30/// \u{13}\u{14}\u{15}\u{16}\u{17}\u{18}\u{19}\u{1a}\u{1b}\u{1c}\u{1d}\u{1e}\u{1f} !\"#$%&\'()*\
31/// +,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u{7f}"
32/// );
33/// ```
34pub const fn ascii_chars_increasing() -> RangeInclusive<char> {
35 char::MIN..='\u{7f}'
36}
37
38/// Generates all [`char`]s, in ascending order.
39///
40/// For a friendlier order (_e.g_. nonprintable [`char`]s coming last), try [`exhaustive_chars`].
41///
42/// The output length is 1,112,064.
43///
44/// # Complexity per iteration
45/// Constant time and additional memory.
46///
47/// # Examples
48/// ```
49/// use malachite_base::chars::exhaustive::chars_increasing;
50///
51/// assert_eq!(
52/// chars_increasing().take(200).collect::<String>(),
53/// "\u{0}\u{1}\u{2}\u{3}\u{4}\u{5}\u{6}\u{7}\u{8}\t\n\u{b}\u{c}\r\u{e}\u{f}\u{10}\u{11}\u{12}\
54/// \u{13}\u{14}\u{15}\u{16}\u{17}\u{18}\u{19}\u{1a}\u{1b}\u{1c}\u{1d}\u{1e}\u{1f} !\"#$%&\'()*\
55/// +,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u{7f}\
56/// \u{80}\u{81}\u{82}\u{83}\u{84}\u{85}\u{86}\u{87}\u{88}\u{89}\u{8a}\u{8b}\u{8c}\u{8d}\u{8e}\
57/// \u{8f}\u{90}\u{91}\u{92}\u{93}\u{94}\u{95}\u{96}\u{97}\u{98}\u{99}\u{9a}\u{9b}\u{9c}\u{9d}\
58/// \u{9e}\u{9f}\u{a0}¡¢£¤¥¦§¨©ª«¬\u{ad}®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇ"
59/// );
60/// ```
61pub const fn chars_increasing() -> RangeInclusive<char> {
62 char::MIN..=char::MAX
63}
64
65/// Generates all [`char`]s, in a friendly order, so that more familiar [`char`] come first.
66///
67/// The order is
68/// - Lowercase ASCII letters,
69/// - Uppercase ASCII letters,
70/// - ASCII digits,
71/// - Graphic ASCII [`char`]s (not alphanumeric and not control), including `' '` but no other
72/// whitespace,
73/// - (only if `ascii_only` is false) Graphic Non-ASCII [`char`]s; all non-ASCII [`char`]s whose
74/// [`Debug`](std::fmt::Debug) representations don't start with `'\'`,
75/// - All remaining [`char`]s.
76///
77/// This `struct` is created by [`exhaustive_chars`] and [`exhaustive_ascii_chars`]; see their
78/// documentation for more.
79#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
80pub struct ExhaustiveChars {
81 ascii_only: bool,
82 first: bool,
83 c: char,
84 current_type: CharType,
85}
86
87impl Iterator for ExhaustiveChars {
88 type Item = char;
89
90 fn next(&mut self) -> Option<char> {
91 if self.first {
92 self.first = false;
93 } else {
94 match self.current_type {
95 CharType::AsciiLower => {
96 if self.c == 'z' {
97 self.current_type = CharType::AsciiUpper;
98 self.c = 'A';
99 } else {
100 increment_char(&mut self.c);
101 }
102 }
103 CharType::AsciiUpper => {
104 if self.c == 'Z' {
105 self.current_type = CharType::AsciiNumeric;
106 self.c = '0';
107 } else {
108 increment_char(&mut self.c);
109 }
110 }
111 CharType::AsciiNumeric => {
112 if self.c == '9' {
113 self.current_type = CharType::AsciiNonAlphanumericGraphic;
114 self.c = ' ';
115 } else {
116 increment_char(&mut self.c);
117 }
118 }
119 CharType::AsciiNonAlphanumericGraphic => {
120 if self.c == '~' {
121 if self.ascii_only {
122 self.current_type = CharType::NonGraphic;
123 self.c = '\0';
124 } else {
125 self.current_type = CharType::NonAsciiGraphic;
126 self.c = '\u{a1}';
127 };
128 } else {
129 increment_char(&mut self.c);
130 // No control chars between ' ' and '~'
131 while self.c.is_ascii_alphanumeric() {
132 increment_char(&mut self.c);
133 }
134 }
135 }
136 CharType::NonAsciiGraphic => {
137 if self.c == '\u{323af}' {
138 self.current_type = CharType::NonGraphic;
139 self.c = '\0';
140 } else {
141 increment_char(&mut self.c);
142 while !CharType::NonAsciiGraphic.contains(self.c) {
143 increment_char(&mut self.c);
144 }
145 }
146 }
147 CharType::NonGraphic => {
148 let limit = if self.ascii_only { '\u{7f}' } else { char::MAX };
149 if self.c == limit {
150 return None;
151 }
152 increment_char(&mut self.c);
153 while !self.c.is_ascii_control()
154 && (self.c.is_ascii() || CharType::NonAsciiGraphic.contains(self.c))
155 {
156 increment_char(&mut self.c);
157 }
158 }
159 }
160 }
161 Some(self.c)
162 }
163}
164
165/// Generates all ASCII [`char`]s, in a friendly order, so that more familiar [`char`]s come first.
166///
167/// The order is
168/// - Lowercase ASCII letters,
169/// - Uppercase ASCII letters,
170/// - ASCII digits,
171/// - Graphic ASCII [`char`]s (not alphanumeric and not control), including `' '` but no other
172/// whitespace,
173/// - All remaining ASCII [`char`]s.
174///
175/// Within each group, the [`char`]s are ordered according to their usual order.
176///
177/// If you want to generate ASCII [`char`]s in their usual order, try [`ascii_chars_increasing`].
178///
179/// The output length is 128.
180///
181/// # Complexity per iteration
182/// Constant time and additional memory.
183///
184/// # Examples
185/// ```
186/// use malachite_base::chars::exhaustive::exhaustive_ascii_chars;
187///
188/// assert_eq!(
189/// exhaustive_ascii_chars().collect::<String>(),
190/// "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !\"#$%&\'()*+,-./:;<=>?@[\\\
191/// ]^_`{|}~\u{0}\u{1}\u{2}\u{3}\u{4}\u{5}\u{6}\u{7}\u{8}\t\n\u{b}\u{c}\r\u{e}\u{f}\u{10}\u{11}\
192/// \u{12}\u{13}\u{14}\u{15}\u{16}\u{17}\u{18}\u{19}\u{1a}\u{1b}\u{1c}\u{1d}\u{1e}\u{1f}\u{7f}"
193/// );
194/// ```
195pub const fn exhaustive_ascii_chars() -> ExhaustiveChars {
196 ExhaustiveChars {
197 ascii_only: true,
198 first: true,
199 c: 'a',
200 current_type: CharType::AsciiLower,
201 }
202}
203
204/// Generates all [`char`]s, in a friendly order, so that more familiar [`char`]s come first.
205///
206/// The order is
207/// - Lowercase ASCII letters,
208/// - Uppercase ASCII letters,
209/// - ASCII digits,
210/// - Graphic ASCII [`char`] (not alphanumeric and not control), including `' '` but no other
211/// whitespace,
212/// - Graphic Non-ASCII [`char`]s; all non-ASCII [`char`]s whose [`Debug`](std::fmt::Debug)
213/// representations don't start with `'\'`,
214/// - All remaining [`char`]s.
215///
216/// Within each group, the [`char`]s are ordered according to their usual order.
217///
218/// If you want to generate [`char`]s in their usual order, try [`chars_increasing`].
219///
220/// The output length is 1,112,064.
221///
222/// # Complexity per iteration
223/// Constant time and additional memory.
224///
225/// # Examples
226/// ```
227/// use malachite_base::chars::exhaustive::exhaustive_chars;
228///
229/// assert_eq!(
230/// exhaustive_chars().take(200).collect::<String>(),
231/// "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !\"#$%&\'()*+,-./:;<=>?@[\\\
232/// ]^_`{|}~¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóô\
233/// õö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊ"
234/// );
235/// ```
236pub const fn exhaustive_chars() -> ExhaustiveChars {
237 ExhaustiveChars {
238 ascii_only: false,
239 first: true,
240 c: 'a',
241 current_type: CharType::AsciiLower,
242 }
243}