92 lines
3.1 KiB
C++
92 lines
3.1 KiB
C++
// uchar_string_traits.hpp
|
||
#pragma once
|
||
#include <cstddef>
|
||
#include <cstring>
|
||
#include <string>
|
||
#include <ostream>
|
||
#include <type_traits>
|
||
|
||
static_assert(sizeof(unsigned char) == 1, "Assumes 8-bit unsigned char");
|
||
|
||
namespace std {
|
||
|
||
// Пользовательская специализация char_traits для unsigned char.
|
||
// Разрешено стандартом, т.к. char_traits предназначен для специализации.
|
||
template<>
|
||
struct char_traits<unsigned char> {
|
||
using char_type = unsigned char;
|
||
using int_type = int; // согласовано с базовой специализацией
|
||
using off_type = std::streamoff;
|
||
using pos_type = std::streampos;
|
||
using state_type = std::mbstate_t;
|
||
|
||
static void assign(char_type& r, const char_type& a) noexcept { r = a; }
|
||
static constexpr bool eq(char_type a, char_type b) noexcept { return a == b; }
|
||
static constexpr bool lt(char_type a, char_type b) noexcept { return a < b; }
|
||
|
||
static int compare(const char_type* s1, const char_type* s2, size_t n) noexcept {
|
||
for (size_t i = 0; i < n; ++i) {
|
||
if (lt(s1[i], s2[i])) return -1;
|
||
if (lt(s2[i], s1[i])) return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static size_t length(const char_type* s) noexcept {
|
||
// Ищем нуль-терминатор (0), как в C-строках
|
||
size_t i = 0;
|
||
while (s[i] != 0) ++i;
|
||
return i;
|
||
}
|
||
|
||
static const char_type* find(const char_type* s, size_t n, const char_type& a) noexcept {
|
||
for (size_t i = 0; i < n; ++i)
|
||
if (eq(s[i], a)) return s + i;
|
||
return nullptr;
|
||
}
|
||
|
||
static char_type* move(char_type* s1, const char_type* s2, size_t n) noexcept {
|
||
if (s1 == s2 || n == 0) return s1;
|
||
// корректно обрабатываем перекрытие
|
||
std::memmove(s1, s2, n);
|
||
return s1;
|
||
}
|
||
|
||
static char_type* copy(char_type* s1, const char_type* s2, size_t n) noexcept {
|
||
if (n) std::memcpy(s1, s2, n);
|
||
return s1;
|
||
}
|
||
|
||
static char_type* assign(char_type* s, size_t n, char_type a) noexcept {
|
||
if (n) std::memset(s, a, n);
|
||
return s;
|
||
}
|
||
|
||
static constexpr int_type to_int_type(char_type c) noexcept {
|
||
return static_cast<unsigned int>(c);
|
||
}
|
||
|
||
static constexpr char_type to_char_type(int_type c) noexcept {
|
||
return static_cast<char_type>(static_cast<unsigned int>(c) & 0xFFu);
|
||
}
|
||
|
||
static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept {
|
||
return c1 == c2;
|
||
}
|
||
|
||
static constexpr int_type eof() noexcept {
|
||
return -1;
|
||
}
|
||
|
||
static constexpr int_type not_eof(int_type c) noexcept {
|
||
return (c == eof()) ? 0 : c;
|
||
}
|
||
};
|
||
|
||
} // namespace std
|
||
|
||
// Удобный вывод: печатаем как байты/символы ASCII (без гарантий по локали)
|
||
inline std::ostream& operator<<(std::ostream& os, const std::basic_string<unsigned char>& s) {
|
||
for (unsigned char ch : s) os.put(static_cast<char>(ch));
|
||
return os;
|
||
}
|