Last active
October 19, 2018 09:11
-
-
Save leha-bot/5c34d13d8f79b346a11b25112abda63a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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