| ... | ... | @@ -12,7 +12,7 @@ const std = @import("std"); |
| 12 | 12 | |
| 13 | 13 | /// The C0 control codes of the ASCII encoding. |
| 14 | 14 | /// |
| 15 | | /// See also: https://en.wikipedia.org/wiki/C0_and_C1_control_codes and `isControl`. |
| 15 | /// See also: https://en.wikipedia.org/wiki/C0_and_C1_control_codes and `isControl` |
| 16 | 16 | pub const control_code = struct { |
| 17 | 17 | /// Null. |
| 18 | 18 | pub const nul = 0x00; |
| ... | ... | @@ -88,188 +88,63 @@ pub const control_code = struct { |
| 88 | 88 | pub const xoff = dc3; |
| 89 | 89 | }; |
| 90 | 90 | |
| 91 | | const tIndex = enum(u3) { |
| 92 | | Alpha, |
| 93 | | Hex, |
| 94 | | Space, |
| 95 | | Digit, |
| 96 | | Lower, |
| 97 | | Upper, |
| 98 | | // Ctrl, < 0x20 || == DEL |
| 99 | | // Print, = Graph || == ' '. NOT '\t' et cetera |
| 100 | | Punct, |
| 101 | | Graph, |
| 102 | | //ASCII, | ~0b01111111 |
| 103 | | //isBlank, == ' ' || == '\x09' |
| 104 | | }; |
| 105 | | |
| 106 | | const combinedTable = init: { |
| 107 | | comptime var table: [256]u8 = undefined; |
| 108 | | |
| 109 | | const mem = std.mem; |
| 110 | | |
| 111 | | const alpha = [_]u1{ |
| 112 | | // 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,10,11,12,13,14,15 |
| 113 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 114 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 115 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 116 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 117 | | |
| 118 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 119 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, |
| 120 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 121 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, |
| 122 | | }; |
| 123 | | const lower = [_]u1{ |
| 124 | | // 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,10,11,12,13,14,15 |
| 125 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 126 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 127 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 128 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 129 | | |
| 130 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 131 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 132 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 133 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, |
| 134 | | }; |
| 135 | | const upper = [_]u1{ |
| 136 | | // 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,10,11,12,13,14,15 |
| 137 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 138 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 139 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 140 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 141 | | |
| 142 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 143 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, |
| 144 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 145 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 146 | | }; |
| 147 | | const digit = [_]u1{ |
| 148 | | // 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,10,11,12,13,14,15 |
| 149 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 150 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 151 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 152 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, |
| 153 | | |
| 154 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 155 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 156 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 157 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 158 | | }; |
| 159 | | const hex = [_]u1{ |
| 160 | | // 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,10,11,12,13,14,15 |
| 161 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 162 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 163 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 164 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, |
| 165 | | |
| 166 | | 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 167 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 168 | | 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 169 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 170 | | }; |
| 171 | | const space = [_]u1{ |
| 172 | | // 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,10,11,12,13,14,15 |
| 173 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, |
| 174 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 175 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 176 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 177 | | |
| 178 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 179 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 180 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 181 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 182 | | }; |
| 183 | | const punct = [_]u1{ |
| 184 | | // 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,10,11,12,13,14,15 |
| 185 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 186 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 187 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 188 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, |
| 189 | | |
| 190 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 191 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, |
| 192 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 193 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, |
| 194 | | }; |
| 195 | | const graph = [_]u1{ |
| 196 | | // 0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,10,11,12,13,14,15 |
| 197 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 198 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 199 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 200 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 201 | | |
| 202 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 203 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 204 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 205 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, |
| 206 | | }; |
| 207 | | |
| 208 | | comptime var i = 0; |
| 209 | | inline while (i < 128) : (i += 1) { |
| 210 | | table[i] = |
| 211 | | @as(u8, alpha[i]) << @enumToInt(tIndex.Alpha) | |
| 212 | | @as(u8, hex[i]) << @enumToInt(tIndex.Hex) | |
| 213 | | @as(u8, space[i]) << @enumToInt(tIndex.Space) | |
| 214 | | @as(u8, digit[i]) << @enumToInt(tIndex.Digit) | |
| 215 | | @as(u8, lower[i]) << @enumToInt(tIndex.Lower) | |
| 216 | | @as(u8, upper[i]) << @enumToInt(tIndex.Upper) | |
| 217 | | @as(u8, punct[i]) << @enumToInt(tIndex.Punct) | |
| 218 | | @as(u8, graph[i]) << @enumToInt(tIndex.Graph); |
| 219 | | } |
| 220 | | mem.set(u8, table[128..256], 0); |
| 221 | | break :init table; |
| 222 | | }; |
| 223 | | |
| 224 | | fn inTable(c: u8, t: tIndex) bool { |
| 225 | | return (combinedTable[c] & (@as(u8, 1) << @enumToInt(t))) != 0; |
| 226 | | } |
| 227 | | |
| 228 | | /// Returns whether the character is alphanumeric. |
| 91 | /// Returns whether the character is alphanumeric: A-Z, a-z, or 0-9. |
| 229 | 92 | pub fn isAlphanumeric(c: u8) bool { |
| 230 | | return (combinedTable[c] & ((@as(u8, 1) << @enumToInt(tIndex.Alpha)) | |
| 231 | | @as(u8, 1) << @enumToInt(tIndex.Digit))) != 0; |
| 93 | return switch (c) { |
| 94 | 'A'...'Z', 'a'...'z', '0'...'9' => true, |
| 95 | else => false, |
| 96 | }; |
| 232 | 97 | } |
| 233 | 98 | |
| 234 | | /// Returns whether the character is alphabetic. |
| 99 | /// Returns whether the character is alphabetic: A-Z or a-z. |
| 235 | 100 | pub fn isAlphabetic(c: u8) bool { |
| 236 | | return inTable(c, tIndex.Alpha); |
| 101 | return switch (c) { |
| 102 | 'A'...'Z', 'a'...'z' => true, |
| 103 | else => false, |
| 104 | }; |
| 237 | 105 | } |
| 238 | 106 | |
| 239 | 107 | /// Returns whether the character is a control character. |
| 240 | | /// This is the same as `!isPrint(c)`. |
| 241 | 108 | /// |
| 242 | | /// See also: `control_code`. |
| 109 | /// See also: `control_code` |
| 243 | 110 | pub fn isControl(c: u8) bool { |
| 244 | 111 | return c <= control_code.us or c == control_code.del; |
| 245 | 112 | } |
| 246 | 113 | |
| 247 | 114 | /// Returns whether the character is a digit. |
| 248 | 115 | pub fn isDigit(c: u8) bool { |
| 249 | | return inTable(c, tIndex.Digit); |
| 116 | return switch (c) { |
| 117 | '0'...'9' => true, |
| 118 | else => false, |
| 119 | }; |
| 250 | 120 | } |
| 251 | 121 | |
| 252 | | /// Returns whether the character is a lowercased letter. |
| 122 | /// Returns whether the character is a lowercase letter. |
| 253 | 123 | pub fn isLower(c: u8) bool { |
| 254 | | return inTable(c, tIndex.Lower); |
| 124 | return switch (c) { |
| 125 | 'a'...'z' => true, |
| 126 | else => false, |
| 127 | }; |
| 255 | 128 | } |
| 256 | 129 | |
| 257 | | /// Returns whether the character is printable and has some graphical representation. |
| 258 | | /// This also returns `true` for the space character. |
| 259 | | /// This is the same as `!isControl(c)`. |
| 130 | /// Returns whether the character is printable and has some graphical representation, |
| 131 | /// including the space character. |
| 260 | 132 | pub fn isPrint(c: u8) bool { |
| 261 | | return inTable(c, tIndex.Graph) or c == ' '; |
| 133 | return isASCII(c) and !isControl(c); |
| 262 | 134 | } |
| 263 | 135 | |
| 264 | 136 | /// Returns whether this character is included in `whitespace`. |
| 265 | 137 | pub fn isWhitespace(c: u8) bool { |
| 266 | | return inTable(c, tIndex.Space); |
| 138 | return for (whitespace) |other| { |
| 139 | if (c == other) |
| 140 | break true; |
| 141 | } else false; |
| 267 | 142 | } |
| 268 | 143 | |
| 269 | 144 | /// Whitespace for general use. |
| 270 | 145 | /// This may be used with e.g. `std.mem.trim` to trim whitespace. |
| 271 | 146 | /// |
| 272 | | /// See also: `isWhitespace`. |
| 147 | /// See also: `isWhitespace` |
| 273 | 148 | pub const whitespace = [_]u8{ ' ', '\t', '\n', '\r', control_code.vt, control_code.ff }; |
| 274 | 149 | |
| 275 | 150 | test "whitespace" { |
| ... | ... | @@ -281,14 +156,20 @@ test "whitespace" { |
| 281 | 156 | } |
| 282 | 157 | } |
| 283 | 158 | |
| 284 | | /// Returns whether the character is an uppercased letter. |
| 159 | /// Returns whether the character is an uppercase letter. |
| 285 | 160 | pub fn isUpper(c: u8) bool { |
| 286 | | return inTable(c, tIndex.Upper); |
| 161 | return switch (c) { |
| 162 | 'A'...'Z' => true, |
| 163 | else => false, |
| 164 | }; |
| 287 | 165 | } |
| 288 | 166 | |
| 289 | | /// Returns whether the character is a hexadecimal digit. Case-insensitive. |
| 167 | /// Returns whether the character is a hexadecimal digit: A-F, a-f, or 0-9. |
| 290 | 168 | pub fn isHex(c: u8) bool { |
| 291 | | return inTable(c, tIndex.Hex); |
| 169 | return switch (c) { |
| 170 | 'A'...'F', 'a'...'f', '0'...'9' => true, |
| 171 | else => false, |
| 172 | }; |
| 292 | 173 | } |
| 293 | 174 | |
| 294 | 175 | /// Returns whether the character is a 7-bit ASCII character. |
| ... | ... | @@ -322,6 +203,8 @@ test "ASCII character classes" { |
| 322 | 203 | try testing.expect(isControl(control_code.nul)); |
| 323 | 204 | try testing.expect(isControl(control_code.ff)); |
| 324 | 205 | try testing.expect(isControl(control_code.us)); |
| 206 | try testing.expect(!isControl(0x80)); |
| 207 | try testing.expect(!isControl(0xff)); |
| 325 | 208 | |
| 326 | 209 | try testing.expect('C' == toUpper('c')); |
| 327 | 210 | try testing.expect(':' == toUpper(':')); |
| ... | ... | @@ -351,6 +234,7 @@ test "ASCII character classes" { |
| 351 | 234 | |
| 352 | 235 | try testing.expect(!isHex('g')); |
| 353 | 236 | try testing.expect(isHex('b')); |
| 237 | try testing.expect(isHex('F')); |
| 354 | 238 | try testing.expect(isHex('9')); |
| 355 | 239 | |
| 356 | 240 | try testing.expect(!isDigit('~')); |
| ... | ... | @@ -361,6 +245,8 @@ test "ASCII character classes" { |
| 361 | 245 | try testing.expect(isPrint('@')); |
| 362 | 246 | try testing.expect(isPrint('~')); |
| 363 | 247 | try testing.expect(!isPrint(control_code.esc)); |
| 248 | try testing.expect(!isPrint(0x80)); |
| 249 | try testing.expect(!isPrint(0xff)); |
| 364 | 250 | } |
| 365 | 251 | |
| 366 | 252 | /// Writes a lower case copy of `ascii_string` to `output`. |