template <typename InputIterator>
char32_t next_codepoint(InputIterator first, InputIterator last) {
std::array<char,4> units;
int i = 0;
assert(first != last); // replace with an actual throw if you want
while(should_read_one_more(*first)) {
units[i++] = *first;
++first;
assert(first != last);
}
return codepoint_from(units);
}
class istream_unicode_iterator
: boost::iterator_facade<
istream_unicode_iterator,
char32_t,
std::input_iterator_tag> {
istream_unicode_iterator() = default;
istream_unicode_iterator(std::istream& is) : is(&is) {
++*this;
}
char32_t const& dereference() const {
return codepoint;
}
void increment() {
if(*is) {
codepoint = next_codepoint(std::istream_iterator{*is}, std::istream_iterator{});
} else {
is = nullptr;
}
}
bool equal(istream_unicode_iterator const& that) const {
return is == nullptr && that.is == nullptr;
}
private:
std::istream* is = nullptr;
char32_t codepoint;
};
CnRlbXBsYXRlIDx0eXBlbmFtZSBJbnB1dEl0ZXJhdG9yPgpjaGFyMzJfdCBuZXh0X2NvZGVwb2ludChJbnB1dEl0ZXJhdG9yIGZpcnN0LCBJbnB1dEl0ZXJhdG9yIGxhc3QpIHsKICAgIHN0ZDo6YXJyYXk8Y2hhciw0PiB1bml0czsKICAgIGludCBpID0gMDsKICAgIGFzc2VydChmaXJzdCAhPSBsYXN0KTsgLy8gcmVwbGFjZSB3aXRoIGFuIGFjdHVhbCB0aHJvdyBpZiB5b3Ugd2FudAogICAgd2hpbGUoc2hvdWxkX3JlYWRfb25lX21vcmUoKmZpcnN0KSkgewogICAgICAgIHVuaXRzW2krK10gPSAqZmlyc3Q7CiAgICAgICAgKytmaXJzdDsKICAgICAgICBhc3NlcnQoZmlyc3QgIT0gbGFzdCk7CiAgICB9CiAgICByZXR1cm4gY29kZXBvaW50X2Zyb20odW5pdHMpOwp9CgpjbGFzcyBpc3RyZWFtX3VuaWNvZGVfaXRlcmF0b3IKOiBib29zdDo6aXRlcmF0b3JfZmFjYWRlPAogICAgaXN0cmVhbV91bmljb2RlX2l0ZXJhdG9yLAogICAgY2hhcjMyX3QsCiAgICBzdGQ6OmlucHV0X2l0ZXJhdG9yX3RhZz4gewogICAgaXN0cmVhbV91bmljb2RlX2l0ZXJhdG9yKCkgPSBkZWZhdWx0OwogICAgaXN0cmVhbV91bmljb2RlX2l0ZXJhdG9yKHN0ZDo6aXN0cmVhbSYgaXMpIDogaXMoJmlzKSB7CiAgICAgICAgKysqdGhpczsKICAgIH0KCiAgICBjaGFyMzJfdCBjb25zdCYgZGVyZWZlcmVuY2UoKSBjb25zdCB7CiAgICAgICAgcmV0dXJuIGNvZGVwb2ludDsKICAgIH0KCiAgICB2b2lkIGluY3JlbWVudCgpIHsKICAgICAgICBpZigqaXMpIHsKICAgICAgICAgICAgY29kZXBvaW50ID0gbmV4dF9jb2RlcG9pbnQoc3RkOjppc3RyZWFtX2l0ZXJhdG9yeyppc30sIHN0ZDo6aXN0cmVhbV9pdGVyYXRvcnt9KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBpcyA9IG51bGxwdHI7CiAgICAgICAgfQogICAgfQogICAgCiAgICBib29sIGVxdWFsKGlzdHJlYW1fdW5pY29kZV9pdGVyYXRvciBjb25zdCYgdGhhdCkgY29uc3QgewogICAgICAgIHJldHVybiBpcyA9PSBudWxscHRyICYmIHRoYXQuaXMgPT0gbnVsbHB0cjsKICAgIH0KCnByaXZhdGU6CiAgICBzdGQ6OmlzdHJlYW0qIGlzID0gbnVsbHB0cjsKICAgIGNoYXIzMl90IGNvZGVwb2ludDsKfTsK