/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2016-2019 Danny Robson */ #pragma once #include "annotation.hpp" #include "debug.hpp" #include #include namespace cruft::ascii { /////////////////////////////////////////////////////////////////////////// /// Returns true if the supplied character is an ASCII digit. constexpr inline bool is_digit (char c) noexcept { return c >= '0' && c <= '9'; } ///------------------------------------------------------------------------ /// Converts an ASCII character into a corresponding integer. /// /// Specifically does not convert multiple characters. constexpr inline uint8_t to_integer (char c) { return likely (is_digit (c)) ? c - '0' : throw std::invalid_argument ("character is not a digit"); } ///------------------------------------------------------------------------ /// Returns true if the supplied character is an upper case letter in the /// "C" locale. constexpr inline bool is_upper (char c) noexcept { return c >= 'A' && c <= 'Z'; } ///------------------------------------------------------------------------ /// Returns true if the supplied character is a lower case letter in the /// "C" locale. constexpr inline bool is_lower (char c) noexcept { return c >= 'a' && c <= 'z'; } ///------------------------------------------------------------------------ /// Returns true if the supplied character is an alphabetical character in /// the "C" locale. constexpr inline bool is_alpha (char c) noexcept { return is_lower (c) || is_upper (c); } ///------------------------------------------------------------------------ /// Returns true if the supplied ASCII character is a hexadecimal digit. constexpr inline bool is_hex (const char c) noexcept { switch (c) { case '0'...'9': return true; case 'a'...'f': return true; case 'A'...'F': return true; } return false; } ///------------------------------------------------------------------------ /// Converts a supplied ASCII character from a hexadecimal digit into a /// corresponding integer. /// /// Explicitly does not cover any multi-character case. constexpr inline uint8_t from_hex (char c) { return c >= '0' && c <= '9' ? (c - '0' ) : c >= 'a' && c <= 'f' ? (c - 'a' + 10) : c >= 'A' && c <= 'F' ? (c - 'A' + 10) : throw std::invalid_argument ("character is not hexademical"); } /////////////////////////////////////////////////////////////////////////// /// Converts a lower case ASCII character into an upper case character. /// /// The results are undefined if the character isn't a lowercase /// alphabetical character in the "C" locale. constexpr inline char to_upper (char c) noexcept { CHECK (is_lower (c)); return c - 'a' + 'A'; } ///------------------------------------------------------------------------ /// Convert an ASCII character into a upper case character if it is lower /// case, else return it unchanged. /// /// If you know the character is always lower case then prefer to_upper. constexpr inline char try_upper (char c) noexcept { return is_lower (c) ? to_upper (c) : c; } ///------------------------------------------------------------------------ /// Converts an upper case ASCII character into a lower case character. /// /// The results are undefined if the character isn't an uppercase /// alphabetical character in the "C" locale. constexpr inline char to_lower (char c) noexcept { CHECK (is_upper (c)); return c - 'A' + 'a'; } ///------------------------------------------------------------------------ /// Convert an ASCII character into a lower case character if it is upper /// case, else return it unchanged. /// /// If you know the character is always upper case then prefer to_lower. constexpr inline char try_lower (char c) noexcept { return is_upper (c) ? to_lower (c) : c; } /////////////////////////////////////////////////////////////////////////// /// Returns true if the supplied ASCII character is whitespace. constexpr inline bool is_space (char c) { switch (c) { case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': return true; default: return false; } } } /////////////////////////////////////////////////////////////////////////////// #include "debug.hpp" #include /// Converts a string of ASCII hex digits into a vector of u08 values. /// /// The supplied string must have a length that is a multiple of 2. std::vector inline operator"" _hex2u08 (const char *str, size_t len) { CHECK_MOD (len, 2); std::vector res (len/2); for (size_t i = 0; i < len; i += 2) res[i/2] = cruft::ascii::from_hex (str[i]) << 4 | cruft::ascii::from_hex (str[i+1]); return res; }; /////////////////////////////////////////////////////////////////////////////// /// Converts a string of ASCII hex digits into an array of u08 values. /// /// The supplied string must have a length that is a multiple of 2. template constexpr auto operator"" _hex2array (void) { static_assert (sizeof ...(StrV) % 2 == 0); std::array res {}; constexpr CharT literal[] = { StrV... }; for (size_t i = 0; i < res.size (); ++i) res[i] = cruft::ascii::from_hex (literal[i*2+0]) << 4 | cruft::ascii::from_hex (literal[i*2+1]); return res; }