#pragma once #include #include #include namespace NPrivate { template struct TCommonCaseInsensitiveCharTraits : private std::char_traits { static bool eq(char c1, char c2) { return TImpl::ToCommonCase(c1) == TImpl::ToCommonCase(c2); } static bool lt(char c1, char c2) { return TImpl::ToCommonCase(c1) < TImpl::ToCommonCase(c2); } static const char* find(const char* s, std::size_t n, char a); using std::char_traits::assign; using std::char_traits::char_type; using std::char_traits::copy; using std::char_traits::length; using std::char_traits::move; }; } // namespace NPrivate struct TCaseInsensitiveCharTraits : public ::NPrivate::TCommonCaseInsensitiveCharTraits { static int compare(const char* s1, const char* s2, std::size_t n); private: friend ::NPrivate::TCommonCaseInsensitiveCharTraits; // XXX return unsigned char. Current impl depends on char signedness, and if char is signed, // TCaseInsensitiveCharTraits::compare returns different result from std::char_traits::compare for non-ascii strings. static char ToCommonCase(char ch) { return std::toupper((unsigned char)ch); } }; struct TCaseInsensitiveAsciiCharTraits : public ::NPrivate::TCommonCaseInsensitiveCharTraits { // WARN: does not work with null bytes (`compare("ab\0c", "ab\0d", 4)` returns 0). static int compare(const char* s1, const char* s2, std::size_t n) { return ::strncasecmp(s1, s2, n); } private: friend ::NPrivate::TCommonCaseInsensitiveCharTraits; static unsigned char ToCommonCase(char ch) { return AsciiToLower(ch); } };