Skip to content

Instantly share code, notes, and snippets.

@leha-bot
Last active October 19, 2018 09:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save leha-bot/5c34d13d8f79b346a11b25112abda63a to your computer and use it in GitHub Desktop.
Save leha-bot/5c34d13d8f79b346a11b25112abda63a to your computer and use it in GitHub Desktop.
class utf8_text_view {
const char *text;
size_t bytes_count;
public:
friend class iterator;
class iterator {
const utf8_text_view &parent;
size_t offset;
public:
iterator(const utf8_text_view &par, size_t init_offset)
: parent(par), offset(init_offset) {}
iterator(const utf8_text_view &par)
: iterator(par, 0) {}
operator const char *()
{
return parent.text + offset;
}
static size_t code_point_size(unsigned char c)
{
// берем крайние 4 бита для проверки на то, является ли
// этот символ первым байтом многобайтового символа
// кодировки UTF-8.
size_t utf8_bits = c >> 4;
// мы утверждаем, что мы не находимся в середине кот-пойнта
assert((utf8_bits & 0xc) != 0x8);
if ((utf8_bits & 0xc) == 0xc) {
// если у нас два старших бита отделены нулем, то самый
// младший бит считать не надо
if ((utf8_bits & 0x2) == 0) {
utf8_bits &= ~1;
}
std::bitset<4> bits_counter(utf8_bits);
return bits_counter.count();
}
// если не совпало с маской, то это символ ASCII.
return 1;
}
iterator &operator ++()
{
assert(offset < parent.bytes_count);
unsigned char first_byte_of_codepoint = parent.text[offset];
offset += code_point_size(first_byte_of_codepoint);
return *this;
}
};
using size_type = std::size_t;
using pointer = iterator*;
// конструкторы
utf8_text_view(const char *str, size_type bytes_count)
: text(str), bytes_count(bytes_count) {}
utf8_text_view(const char *str)
: utf8_text_view(str, strlen(str)) {}
// итераторы
//
iterator begin() const
{
return iterator(*this);
}
iterator end() const
{
return iterator(*this, bytes_count);
}
// сайз и дата, как в векторе
//
size_type size() const
{
auto b = begin();
auto e = end();
size_t count = 0;
for (;b != e; ++b) {
count++;
}
return count;
}
auto c_str()
{
return text;
}
};
auto test_iterators = []()
{
static bool called = false;
if (!called) {
called = true;
} else {
return true;
}
printf("==========================TEST utf8_text_view\n");
struct utf8_test_data {
const char *literal;
size_t expected;
size_t actual;
};
utf8_test_data data[] = {
{"ASCII-HUITA", 11},
{"ХУИТА на UTF-8", 14},
{"ХУИТКА со СМАЙЛАМИ", 18},
{"ОДОЛЖИ 5 € и 10 ¢ ДО ЗАРПЛАТЫ!", 30},
{"ХУИТА СО СМАЙЛАМИ, БЛЯДЬ. РВАНЕТ ЖЕ, КОГДА СОСТАВНЫЕ😡!", 55},
};
for (auto &test : data) {
utf8_text_view utf8_view(test.literal);
test.actual = utf8_view.size();
printf("Expected length: %zu, actual: %zu\n", test.expected, test.actual);
}
};
test_iterators();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment