123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- #pragma once
- #include <util/system/defaults.h>
- #include <util/system/compat.h>
- #include <util/generic/string.h>
- // ctype.h-like functions, locale-independent:
- // IsAscii{Upper,Lower,Digit,Alpha,Alnum,Space} and
- // AsciiTo{Upper,Lower}
- //
- // standard functions from <ctype.h> are locale dependent,
- // and cause undefined behavior when called on chars outside [0..127] range
- namespace NPrivate {
- enum ECharClass {
- CC_SPACE = 1,
- CC_UPPER = 2,
- CC_LOWER = 4,
- CC_DIGIT = 8,
- CC_ALPHA = 16,
- CC_ALNUM = 32,
- CC_ISHEX = 64,
- CC_PUNCT = 128,
- };
- extern const unsigned char ASCII_CLASS[256];
- extern const unsigned char ASCII_LOWER[256];
- template <class T>
- struct TDereference {
- using type = T;
- };
- #ifndef TSTRING_IS_STD_STRING
- template <class String>
- struct TDereference<TBasicCharRef<String>> {
- using type = typename String::value_type;
- };
- #endif
- template <class T>
- using TDereferenced = typename TDereference<T>::type;
- template <class T>
- bool RangeOk(T c) noexcept {
- static_assert(std::is_integral<T>::value, "Integral type character expected");
- if (sizeof(T) == 1) {
- return true;
- }
- return c >= static_cast<T>(0) && c <= static_cast<T>(127);
- }
- #ifndef TSTRING_IS_STD_STRING
- template <class String>
- bool RangeOk(const TBasicCharRef<String>& c) {
- return RangeOk(static_cast<typename String::value_type>(c));
- }
- #endif
- } // namespace NPrivate
- constexpr bool IsAscii(const int c) noexcept {
- return !(c & ~0x7f);
- }
- inline bool IsAsciiSpace(unsigned char c) {
- return ::NPrivate::ASCII_CLASS[c] & ::NPrivate::CC_SPACE;
- }
- inline bool IsAsciiUpper(unsigned char c) {
- return ::NPrivate::ASCII_CLASS[c] & ::NPrivate::CC_UPPER;
- }
- inline bool IsAsciiLower(unsigned char c) {
- return ::NPrivate::ASCII_CLASS[c] & ::NPrivate::CC_LOWER;
- }
- inline bool IsAsciiDigit(unsigned char c) {
- return ::NPrivate::ASCII_CLASS[c] & ::NPrivate::CC_DIGIT;
- }
- inline bool IsAsciiAlpha(unsigned char c) {
- return ::NPrivate::ASCII_CLASS[c] & ::NPrivate::CC_ALPHA;
- }
- inline bool IsAsciiAlnum(unsigned char c) {
- return ::NPrivate::ASCII_CLASS[c] & ::NPrivate::CC_ALNUM;
- }
- inline bool IsAsciiHex(unsigned char c) {
- return ::NPrivate::ASCII_CLASS[c] & ::NPrivate::CC_ISHEX;
- }
- inline bool IsAsciiPunct(unsigned char c) {
- return ::NPrivate::ASCII_CLASS[c] & ::NPrivate::CC_PUNCT;
- }
- // some overloads
- template <class T>
- inline bool IsAsciiSpace(T c) {
- return ::NPrivate::RangeOk(c) && IsAsciiSpace(static_cast<unsigned char>(c));
- }
- template <class T>
- inline bool IsAsciiUpper(T c) {
- return ::NPrivate::RangeOk(c) && IsAsciiUpper(static_cast<unsigned char>(c));
- }
- template <class T>
- inline bool IsAsciiLower(T c) {
- return ::NPrivate::RangeOk(c) && IsAsciiLower(static_cast<unsigned char>(c));
- }
- template <class T>
- inline bool IsAsciiDigit(T c) {
- return ::NPrivate::RangeOk(c) && IsAsciiDigit(static_cast<unsigned char>(c));
- }
- template <class T>
- inline bool IsAsciiAlpha(T c) {
- return ::NPrivate::RangeOk(c) && IsAsciiAlpha(static_cast<unsigned char>(c));
- }
- template <class T>
- inline bool IsAsciiAlnum(T c) {
- return ::NPrivate::RangeOk(c) && IsAsciiAlnum(static_cast<unsigned char>(c));
- }
- template <class T>
- inline bool IsAsciiHex(T c) {
- return ::NPrivate::RangeOk(c) && IsAsciiHex(static_cast<unsigned char>(c));
- }
- template <class T>
- inline bool IsAsciiPunct(T c) {
- return ::NPrivate::RangeOk(c) && IsAsciiPunct(static_cast<unsigned char>(c));
- }
- // some extra helpers
- inline ui8 AsciiToLower(ui8 c) noexcept {
- return ::NPrivate::ASCII_LOWER[c];
- }
- inline char AsciiToLower(char c) noexcept {
- return (char)AsciiToLower((ui8)c);
- }
- template <class T>
- inline ::NPrivate::TDereferenced<T> AsciiToLower(T c) noexcept {
- return (c >= 0 && c <= 127) ? (::NPrivate::TDereferenced<T>)AsciiToLower((ui8)c) : c;
- }
- template <class T>
- inline ::NPrivate::TDereferenced<T> AsciiToUpper(T c) noexcept {
- return IsAsciiLower(c) ? (c + ('A' - 'a')) : c;
- }
- /**
- * ASCII case-insensitive string comparison (for proper UTF8 strings
- * case-insensitive comparison consider using @c library/cpp/charset).
- *
- * BUGS: Currently will NOT work properly with strings that contain
- * 0-terminator character inside. See IGNIETFERRO-1641 for details.
- *
- * @return true iff @c s1 ans @c s2 are case-insensitively equal.
- */
- static inline bool AsciiEqualsIgnoreCase(const char* s1, const char* s2) noexcept {
- return ::stricmp(s1, s2) == 0;
- }
- /**
- * ASCII case-insensitive string comparison (for proper UTF8 strings
- * case-insensitive comparison consider using @c library/cpp/charset).
- *
- * BUGS: Currently will NOT work properly with strings that contain
- * 0-terminator character inside. See IGNIETFERRO-1641 for details.
- *
- * @return true iff @c s1 ans @c s2 are case-insensitively equal.
- */
- static inline bool AsciiEqualsIgnoreCase(const TStringBuf s1, const TStringBuf s2) noexcept {
- if (s1.size() != s2.size()) {
- return false;
- }
- if (s1.empty()) {
- return true;
- }
- return ::strnicmp(s1.data(), s2.data(), s1.size()) == 0;
- }
- /**
- * ASCII case-insensitive string comparison (for proper UTF8 strings
- * case-insensitive comparison consider using @c library/cpp/charset).
- *
- * BUGS: Currently will NOT work properly with strings that contain
- * 0-terminator character inside. See IGNIETFERRO-1641 for details.
- *
- * @return 0 if strings are equal, negative if @c s1 < @c s2
- * and positive otherwise.
- * (same value as @c stricmp does).
- */
- static inline int AsciiCompareIgnoreCase(const char* s1, const char* s2) noexcept {
- return ::stricmp(s1, s2);
- }
- /**
- * ASCII case-insensitive string comparison (for proper UTF8 strings
- * case-insensitive comparison consider using @c library/cpp/charset).
- *
- * BUGS: Currently will NOT work properly with strings that contain
- * 0-terminator character inside. See IGNIETFERRO-1641 for details.
- *
- * @return
- * - zero if strings are equal
- * - negative if @c s1 < @c s2
- * - positive otherwise,
- * similar to stricmp.
- */
- Y_PURE_FUNCTION int AsciiCompareIgnoreCase(const TStringBuf s1, const TStringBuf s2) noexcept;
- /**
- * ASCII case-sensitive string comparison (for proper UTF8 strings
- * case-sensitive comparison consider using @c library/cpp/charset).
- *
- * BUGS: Currently will NOT work properly with strings that contain
- * 0-terminator character inside. See IGNIETFERRO-1641 for details.
- *
- * @return true iff @c s2 are case-sensitively prefix of @c s1.
- */
- static inline bool AsciiHasPrefix(const TStringBuf s1, const TStringBuf s2) noexcept {
- return (s1.size() >= s2.size()) && memcmp(s1.data(), s2.data(), s2.size()) == 0;
- }
- /**
- * ASCII case-insensitive string comparison (for proper UTF8 strings
- * case-insensitive comparison consider using @c library/cpp/charset).
- *
- * @return true iff @c s2 are case-insensitively prefix of @c s1.
- */
- static inline bool AsciiHasPrefixIgnoreCase(const TStringBuf s1, const TStringBuf s2) noexcept {
- return (s1.size() >= s2.size()) && ::strnicmp(s1.data(), s2.data(), s2.size()) == 0;
- }
- /**
- * ASCII case-insensitive string comparison (for proper UTF8 strings
- * case-insensitive comparison consider using @c library/cpp/charset).
- *
- * @return true iff @c s2 are case-insensitively suffix of @c s1.
- */
- static inline bool AsciiHasSuffixIgnoreCase(const TStringBuf s1, const TStringBuf s2) noexcept {
- return (s1.size() >= s2.size()) && ::strnicmp((s1.data() + (s1.size() - s2.size())), s2.data(), s2.size()) == 0;
- }
|