| ... | @@ -12,7 +12,7 @@ const std = @import("std"); | ... | @@ -12,7 +12,7 @@ const std = @import("std"); |
| 12 | | 12 | |
| 13 | /// The C0 control codes of the ASCII encoding. | 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 | pub const control_code = struct { | 16 | pub const control_code = struct { |
| 17 | /// Null. | 17 | /// Null. |
| 18 | pub const nul = 0x00; | 18 | pub const nul = 0x00; |
| ... | @@ -88,188 +88,63 @@ pub const control_code = struct { | ... | @@ -88,188 +88,63 @@ pub const control_code = struct { |
| 88 | pub const xoff = dc3; | 88 | pub const xoff = dc3; |
| 89 | }; | 89 | }; |
| 90 | | 90 | |
| 91 | const tIndex = enum(u3) { | 91 | /// Returns whether the character is alphanumeric: A-Z, a-z, or 0-9. |
| 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. | | |
| 229 | pub fn isAlphanumeric(c: u8) bool { | 92 | pub fn isAlphanumeric(c: u8) bool { |
| 230 | return (combinedTable[c] & ((@as(u8, 1) << @enumToInt(tIndex.Alpha)) | | 93 | return switch (c) { |
| 231 | @as(u8, 1) << @enumToInt(tIndex.Digit))) != 0; | 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 | pub fn isAlphabetic(c: u8) bool { | 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 | /// Returns whether the character is a control character. | 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 | pub fn isControl(c: u8) bool { | 110 | pub fn isControl(c: u8) bool { |
| 244 | return c <= control_code.us or c == control_code.del; | 111 | return c <= control_code.us or c == control_code.del; |
| 245 | } | 112 | } |
| 246 | | 113 | |
| 247 | /// Returns whether the character is a digit. | 114 | /// Returns whether the character is a digit. |
| 248 | pub fn isDigit(c: u8) bool { | 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 | pub fn isLower(c: u8) bool { | 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. | 130 | /// Returns whether the character is printable and has some graphical representation, |
| 258 | /// This also returns `true` for the space character. | 131 | /// including the space character. |
| 259 | /// This is the same as `!isControl(c)`. | | |
| 260 | pub fn isPrint(c: u8) bool { | 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 | /// Returns whether this character is included in `whitespace`. | 136 | /// Returns whether this character is included in `whitespace`. |
| 265 | pub fn isWhitespace(c: u8) bool { | 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 | /// Whitespace for general use. | 144 | /// Whitespace for general use. |
| 270 | /// This may be used with e.g. `std.mem.trim` to trim whitespace. | 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 | pub const whitespace = [_]u8{ ' ', '\t', '\n', '\r', control_code.vt, control_code.ff }; | 148 | pub const whitespace = [_]u8{ ' ', '\t', '\n', '\r', control_code.vt, control_code.ff }; |
| 274 | | 149 | |
| 275 | test "whitespace" { | 150 | test "whitespace" { |
| ... | @@ -281,14 +156,20 @@ 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 | pub fn isUpper(c: u8) bool { | 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 | pub fn isHex(c: u8) bool { | 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 | /// Returns whether the character is a 7-bit ASCII character. | 175 | /// Returns whether the character is a 7-bit ASCII character. |
| ... | @@ -322,6 +203,8 @@ test "ASCII character classes" { | ... | @@ -322,6 +203,8 @@ test "ASCII character classes" { |
| 322 | try testing.expect(isControl(control_code.nul)); | 203 | try testing.expect(isControl(control_code.nul)); |
| 323 | try testing.expect(isControl(control_code.ff)); | 204 | try testing.expect(isControl(control_code.ff)); |
| 324 | try testing.expect(isControl(control_code.us)); | 205 | try testing.expect(isControl(control_code.us)); |
| | 206 | try testing.expect(!isControl(0x80)); |
| | 207 | try testing.expect(!isControl(0xff)); |
| 325 | | 208 | |
| 326 | try testing.expect('C' == toUpper('c')); | 209 | try testing.expect('C' == toUpper('c')); |
| 327 | try testing.expect(':' == toUpper(':')); | 210 | try testing.expect(':' == toUpper(':')); |
| ... | @@ -351,6 +234,7 @@ test "ASCII character classes" { | ... | @@ -351,6 +234,7 @@ test "ASCII character classes" { |
| 351 | | 234 | |
| 352 | try testing.expect(!isHex('g')); | 235 | try testing.expect(!isHex('g')); |
| 353 | try testing.expect(isHex('b')); | 236 | try testing.expect(isHex('b')); |
| | 237 | try testing.expect(isHex('F')); |
| 354 | try testing.expect(isHex('9')); | 238 | try testing.expect(isHex('9')); |
| 355 | | 239 | |
| 356 | try testing.expect(!isDigit('~')); | 240 | try testing.expect(!isDigit('~')); |
| ... | @@ -361,6 +245,8 @@ test "ASCII character classes" { | ... | @@ -361,6 +245,8 @@ test "ASCII character classes" { |
| 361 | try testing.expect(isPrint('@')); | 245 | try testing.expect(isPrint('@')); |
| 362 | try testing.expect(isPrint('~')); | 246 | try testing.expect(isPrint('~')); |
| 363 | try testing.expect(!isPrint(control_code.esc)); | 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 | /// Writes a lower case copy of `ascii_string` to `output`. | 252 | /// Writes a lower case copy of `ascii_string` to `output`. |