24#ifndef MTCORE_ASCII_HPP
25#define MTCORE_ASCII_HPP
51 inline bool is_digit(
const char c) {
return c >=
'0' && c <=
'9'; }
62 const auto lower = (c | 0b0100000);
63 return lower >=
'a' && lower <=
'f';
79 while (
iter.next().copy_if_present(cur)) {
102 while (
iter.next().copy_if_present(cur)) {
105 if (cur ==
'+' || cur ==
'-') {
132 while (
iter.next().copy_if_present(cur)) {
155 template<
typename Out = i32>
158 if (!parse.
head || !parse.
len) {
168 else if (s[0] ==
'+') {
172 if (negate && !std::numeric_limits<Out>::is_signed) {
180 if (s.size() > 2 && s[0] ==
'0' && s[1] ==
'x') {
183 else if (s.size() > 1 && s[0] ==
'x') {
189 while (it.next().copy_if_present(ch)) {
200 if (res < std::numeric_limits<Out>::min() / 16) {
205 if (res > std::numeric_limits<Out>::max() / 16) {
211 auto addAmt = (
is_digit(ch)) ? ch -
'0' : (ch | 0b0100000) -
'a' + 10;
214 if (res != 0 && std::abs(std::numeric_limits<Out>::min() - res) < addAmt) {
220 else if (std::numeric_limits<Out>::max() - res < addAmt) {
225 if (!negate && old > res) {
228 else if (negate && old < res) {
243 template<
typename Out = i32>
246 if (!parse.
head || !parse.
len) {
256 else if (s[0] ==
'+') {
260 if (negate && !std::numeric_limits<Out>::is_signed) {
270 while (it.next().copy_if_present(ch)) {
281 if (res < std::numeric_limits<Out>::min() / 10) {
286 if (res > std::numeric_limits<Out>::max() / 10) {
292 auto addAmt =
static_cast<Out
>(ch -
'0');
294 if constexpr (std::is_signed_v<Out>) {
296 if (res != 0 && std::abs(std::numeric_limits<Out>::min() - res) < addAmt) {
306 else if (std::numeric_limits<Out>::max() - res < addAmt) {
311 if (!negate && old > res) {
314 else if (negate && old < res) {
348 if (str.
size() == 1) {
349 if (str[0] == escapeChar) {
355 if (str[0] != escapeChar) {
359 char escaped = str[1];
392 auto hex = std::array<char, 2>{
'0',
'0'};
398 if (parseRes.is_success()) {
399 escaped = parseRes.value();
445 template<
typename Writer>
448 using ErrType = std::variant<typename Writer::ErrType, UnescapeError>;
450 for (
size_t i = 0; i < str.
size(); ++i) {
452 if (cur == escapeChar) {
453 if (i + 1 < str.
size()) {
456 char escaped = str[i + 1];
457 switch (str[i + 1]) {
489 auto hex = std::array{
'0',
'0'};
490 if (i + 2 < str.
size() &&
is_hex(str[i + 2])) {
492 if (i + 3 < str.
size() &&
is_hex(str[i + 3])) {
495 if (parseRes.is_success()) {
497 escaped = parseRes.value();
513 escaped = str[i + 1];
516 auto chRes = writer.write(escaped);
517 if (chRes.is_error()) {
518 return error(ErrType{chRes.error().code});
527 auto chRes = writer.write(cur);
528 if (chRes.is_error()) {
529 return error(ErrType{chRes.error().code});
bool is_hex_str(Slice< const char > str)
Checks if a string is composed of only hex characters Will return false if string is empty.
bool is_digit(const char c)
Checks if a character is an ASCII digit (0-9)
bool is_int_str(Slice< const char > str)
Checks if a string is composed of only integer characters Will return false if string is empty.
bool is_hex(const char c)
Checks if a character is an ASCII hex digit (0-9, a-f, A-F)
Result< Out, AsciiNumericParseError > base10_to_int(const Slice< const char > &parse)
Tries to parse an ASCII numeric string into an integer Will return an error if the parsed string does...
bool is_pos_int_str(Slice< const char > str)
Checks if a string is composed of only positive integer characters Will return false if string is emp...
Result< Out, AsciiNumericParseError > hex_to_int(const Slice< const char > &parse)
Tries to parse an ASCII hex string into an integer Will return an error if the parsed string does not...
Result< size_t, std::variant< typename Writer::ErrType, UnescapeError > > write_unescaped(Writer &writer, Slice< const char > str, char escapeChar='\\')
Writes unescaped ASCII characters to a stream Note: This does NOT support writing Unicode escape code...
Result< char, UnescapeError > unescape_char(Slice< const char > str, char escapeChar='\\')
Unescapes the first (potentially) escaped character in a character sequence If the sequence is empty,...
constexpr Slice< const char32_t > slice_from(char32_t *cstr)
Creates a slice from a utf32 string in the form of a c string.
AsciiNumericParseError
Errors when parsing ASCII strings as numbers.
#define unreachable(...)
Marks code as unreachable.
#define mtdefer
Defer statement that will mtdefer execution until the scope is left, at which point the code will run...
Error< Underlying > error(Underlying err)
Creates an error.
ASCII-related methods for parsing and character classification Split into its own namespace to allow ...
Generic iterator defaults built on common contracts Does not guarantee performance of iterators Actua...
Core library for C++ with Zig-related functionality.
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
A Slice which is just a pointer + length Accessing elements through the array operator will do bounds...
constexpr size_t size() const noexcept
Gets the size of a Slice.
constexpr bool empty() const noexcept
Checks if a Slice is empty.
decltype(auto) iter() const noexcept
Error when unescaping characters fails.
bool operator!=(const UnescapeError &o) const
static const UnescapeError INVALID_ESCAPE_SEQUENCE
static const UnescapeError EMPTY_INPUT
bool operator==(const UnescapeError &o) const