[debt] more tech debt

This commit is contained in:
Timothy Stack 2020-11-12 21:58:40 -08:00
parent cb7a8904c1
commit 9d87cfa2f0
26 changed files with 216 additions and 162 deletions

2
NEWS
View File

@ -15,6 +15,8 @@ lnav v0.9.1:
pressing 'f' in the filter editor UI; executing the ':toggle-filtering'
command; or by doing an UPDATE on the "filtering" column of the
"lnav_views" SQLite table.
* Themes can now include definitions for text highlights under:
/ui/theme-defs/<theme_name>/highlights
Interface Changes:
* When copying log lines, the file name and time offset will be included

View File

@ -124,8 +124,8 @@ inline ssize_t utf8_char_to_byte_index(const std::string &str, ssize_t ch_index)
while (ch_index > 0) {
auto ch_len = ww898::utf::utf8::char_size([&str, retval]() {
return str[retval];
});
return std::make_pair(str[retval], str.length() - retval - 1);
}).unwrapOr(1);
retval += ch_len;
ch_index -= 1;

View File

@ -58,8 +58,6 @@ public:
bottom_status_source();
virtual ~bottom_status_source() = default;
lv_functor_t line_number_wire;
lv_functor_t percent_wire;
lv_functor_t marks_wire;
@ -71,12 +69,12 @@ public:
this->bss_prompt.set_value(prompt);
};
void grep_error(std::string msg)
void grep_error(const std::string& msg) override
{
this->bss_error.set_value(msg);
};
size_t statusview_fields()
size_t statusview_fields() override
{
size_t retval;
@ -90,7 +88,7 @@ public:
return retval;
};
status_field &statusview_value_for_field(int field)
status_field &statusview_value_for_field(int field) override
{
if (!this->bss_error.empty()) {
return this->bss_error;

View File

@ -32,8 +32,6 @@
#include <stdio.h>
#include "spookyhash/SpookyV2.h"
#include <list>
#include <stack>
#include <vector>

View File

@ -74,11 +74,11 @@ void db_label_source::text_attrs_for_line(textview_curses &tc, int row,
}
for (size_t lpc = 0; lpc < this->dls_headers.size() - 1; lpc++) {
if (row % 2 == 0) {
sa.push_back(string_attr(lr2, &view_curses::VC_STYLE, A_BOLD));
sa.emplace_back(lr2, &view_curses::VC_STYLE, A_BOLD);
}
lr.lr_start += this->dls_headers[lpc].hm_column_size - 1;
lr.lr_end = lr.lr_start + 1;
sa.push_back(string_attr(lr, &view_curses::VC_GRAPHIC, ACS_VLINE));
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, ACS_VLINE);
lr.lr_start += 1;
}
@ -268,10 +268,10 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
string_attrs_t &sa = this->dos_lines.back().get_attrs();
struct line_range lr(1, 2);
sa.push_back(string_attr(lr, &view_curses::VC_GRAPHIC, ACS_LTEE));
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, ACS_LTEE);
lr.lr_start = 3 + jpw_value.wt_ptr.size() + 3;
lr.lr_end = -1;
sa.push_back(string_attr(lr, &view_curses::VC_STYLE, A_BOLD));
sa.emplace_back(lr, &view_curses::VC_STYLE, A_BOLD);
double num_value = 0.0;
@ -309,10 +309,10 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
string_attrs_t &sa = this->dos_lines.back().get_attrs();
struct line_range lr(1, 2);
sa.push_back(string_attr(lr, &view_curses::VC_GRAPHIC, ACS_LLCORNER));
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, ACS_LLCORNER);
lr.lr_start = 2;
lr.lr_end = -1;
sa.push_back(string_attr(lr, &view_curses::VC_GRAPHIC, ACS_HLINE));
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, ACS_HLINE);
retval += 1;
}
@ -348,8 +348,7 @@ bool db_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
if (!this->dos_labels->dls_headers[lpc].hm_graphable) {
attrs = A_UNDERLINE;
}
sa.push_back(string_attr(header_range, &view_curses::VC_STYLE,
attrs));
sa.emplace_back(header_range, &view_curses::VC_STYLE, attrs);
before = total_fill / 2;
total_fill -= before;
@ -360,8 +359,7 @@ bool db_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
struct line_range lr(0);
sa.push_back(string_attr(lr, &view_curses::VC_STYLE,
A_BOLD | A_UNDERLINE));
sa.emplace_back(lr, &view_curses::VC_STYLE, A_BOLD | A_UNDERLINE);
return true;
}
else if (this->dos_active && y >= 2 && ((size_t) y) < (this->dos_lines.size() + 2)) {

View File

@ -80,13 +80,6 @@ filter_status_source::filter_status_source()
this->tss_fields[TSF_HELP].set_width(20);
this->tss_fields[TSF_HELP].set_value(TOGGLE_MSG);
this->tss_fields[TSF_HELP].set_left_pad(1);
this->tss_prompt.set_left_pad(1);
this->tss_prompt.set_min_width(35);
this->tss_prompt.set_share(1);
this->tss_error.set_left_pad(1);
this->tss_error.set_min_width(35);
this->tss_error.set_share(1);
}
size_t filter_status_source::statusview_fields()
@ -142,54 +135,38 @@ size_t filter_status_source::statusview_fields()
view_colors::VCR_STATUS_STITCH_NORMAL_TO_TITLE);
}
if (this->tss_prompt.empty() && this->tss_error.empty()) {
lnav_data.ld_view_stack.top() | [this] (auto tc) {
text_sub_source *tss = tc->get_sub_source();
if (tss == nullptr) {
return;
lnav_data.ld_view_stack.top() | [this](auto tc) {
text_sub_source *tss = tc->get_sub_source();
if (tss == nullptr) {
return;
}
filter_stack &fs = tss->get_filters();
auto enabled_count = 0, filter_count = 0;
for (const auto &tf : fs) {
if (tf->is_enabled()) {
enabled_count += 1;
}
filter_count += 1;
}
if (filter_count == 0) {
this->tss_fields[TSF_COUNT].set_value("");
} else {
this->tss_fields[TSF_COUNT].set_value(
" " ANSI_BOLD("%d")
" of " ANSI_BOLD("%d")
" enabled ",
enabled_count,
filter_count);
}
};
filter_stack &fs = tss->get_filters();
auto enabled_count = 0, filter_count = 0;
for (const auto &tf : fs) {
if (tf->is_enabled()) {
enabled_count += 1;
}
filter_count += 1;
}
if (filter_count == 0) {
this->tss_fields[TSF_COUNT].set_value("");
} else {
this->tss_fields[TSF_COUNT].set_value(
" " ANSI_BOLD("%d")
" of " ANSI_BOLD("%d")
" enabled ",
enabled_count,
filter_count);
}
};
return TSF__MAX;
}
return 3;
return TSF__MAX;
}
status_field &filter_status_source::statusview_value_for_field(int field)
{
if (field <= 1) {
return this->tss_fields[field];
}
if (!this->tss_error.empty()) {
return this->tss_error;
}
if (!this->tss_prompt.empty()) {
return this->tss_prompt;
}
return this->tss_fields[field];
}
@ -231,6 +208,12 @@ filter_help_status_source::filter_help_status_source()
{
this->fss_help.set_min_width(10);
this->fss_help.set_share(1);
this->fss_prompt.set_left_pad(1);
this->fss_prompt.set_min_width(35);
this->fss_prompt.set_share(1);
this->fss_error.set_left_pad(22);
this->fss_error.set_min_width(35);
this->fss_error.set_share(1);
}
size_t filter_help_status_source::statusview_fields()
@ -311,5 +294,13 @@ size_t filter_help_status_source::statusview_fields()
status_field &filter_help_status_source::statusview_value_for_field(int field)
{
if (!this->fss_error.empty()) {
return this->fss_error;
}
if (!this->fss_prompt.empty()) {
return this->fss_prompt;
}
return this->fss_help;
}

View File

@ -58,8 +58,6 @@ public:
void update_filtered(text_sub_source *tss);
status_field tss_error{1024, view_colors::VCR_ALERT_STATUS};
status_field tss_prompt{1024, view_colors::VCR_STATUS};
private:
status_field tss_fields[TSF__MAX];
int bss_last_filtered_count{0};
@ -74,6 +72,9 @@ public:
size_t statusview_fields() override;
status_field &statusview_value_for_field(int field) override;
status_field fss_prompt{1024, view_colors::VCR_STATUS};
status_field fss_error{1024, view_colors::VCR_ALERT_STATUS};
private:
status_field fss_help;
};

View File

@ -136,12 +136,15 @@ bool filter_sub_source::list_input_handle_key(listview_curses &lv, int ch)
textview_curses *top_view = *lnav_data.ld_view_stack.top();
text_sub_source *tss = top_view->get_sub_source();
filter_stack &fs = tss->get_filters();
auto filter_index = fs.next_index();
if (fs.full()) {
if (!filter_index) {
lnav_data.ld_filter_help_status_source.fss_error
.set_value("error: too many filters");
return true;
}
auto ef = make_shared<empty_filter>(text_filter::type_t::INCLUDE, fs.next_index());
auto ef = make_shared<empty_filter>(text_filter::type_t::INCLUDE, *filter_index);
fs.add_filter(ef);
lv.set_selection(vis_line_t(fs.size() - 1));
lv.reload_data();
@ -163,12 +166,15 @@ bool filter_sub_source::list_input_handle_key(listview_curses &lv, int ch)
textview_curses *top_view = *lnav_data.ld_view_stack.top();
text_sub_source *tss = top_view->get_sub_source();
filter_stack &fs = tss->get_filters();
auto filter_index = fs.next_index();
if (fs.full()) {
if (!filter_index) {
lnav_data.ld_filter_help_status_source.fss_error
.set_value("error: too many filters");
return true;
}
auto ef = make_shared<empty_filter>(text_filter::type_t::EXCLUDE, fs.next_index());
auto ef = make_shared<empty_filter>(text_filter::type_t::EXCLUDE, *filter_index);
fs.add_filter(ef);
lv.set_selection(vis_line_t(fs.size() - 1));
lv.reload_data();
@ -362,7 +368,7 @@ void filter_sub_source::rl_change(readline_curses *rc)
&errptr,
&eoff,
nullptr)) == nullptr) {
lnav_data.ld_filter_status_source.tss_error
lnav_data.ld_filter_help_status_source.fss_error
.set_value("error: %s", errptr);
} else {
textview_curses::highlight_map_t &hm = top_view->get_highlights();
@ -379,7 +385,7 @@ void filter_sub_source::rl_change(readline_curses *rc)
hm[{highlight_source_t::PREVIEW, "preview"}] = hl;
top_view->set_needs_update();
lnav_data.ld_filter_status_source.tss_error.clear();
lnav_data.ld_filter_help_status_source.fss_error.clear();
}
}
@ -414,7 +420,7 @@ void filter_sub_source::rl_perform(readline_curses *rc)
tss->text_filters_changed();
}
lnav_data.ld_filter_status_source.tss_prompt.clear();
lnav_data.ld_filter_help_status_source.fss_prompt.clear();
this->fss_editing = false;
this->fss_editor.set_visible(false);
this->tss_view->reload_data();
@ -428,8 +434,8 @@ void filter_sub_source::rl_abort(readline_curses *rc)
auto iter = fs.begin() + this->tss_view->get_selection();
shared_ptr<text_filter> tf = *iter;
lnav_data.ld_filter_status_source.tss_prompt.clear();
lnav_data.ld_filter_status_source.tss_error.clear();
lnav_data.ld_filter_help_status_source.fss_prompt.clear();
lnav_data.ld_filter_help_status_source.fss_error.clear();
top_view->get_highlights().erase({highlight_source_t::PREVIEW, "preview"});
top_view->reload_data();
fs.delete_filter("");

View File

@ -103,7 +103,7 @@ public:
virtual ~grep_proc_control() = default;
/** @param msg The error encountered while attempting the grep. */
virtual void grep_error(std::string msg) { };
virtual void grep_error(const std::string& msg) { };
};
/**

View File

@ -36,9 +36,12 @@
#include "attr_line.hh"
using help_example_to_attr_line_fun_t =
std::function<attr_line_t(const help_text &, const help_example &)>;
std::function<attr_line_t(const help_text &, const help_example &)>;
void
format_help_text_for_term(const help_text &ht, size_t width, attr_line_t &out,
bool synopsis_only = false);
void format_help_text_for_term(const help_text &ht, size_t width, attr_line_t &out, bool synopsis_only = false);
void format_example_text_for_term(
const help_text &ht,
help_example_to_attr_line_fun_t eval,

View File

@ -51,6 +51,8 @@ STRONG_INT_TYPE(int, bucket_group);
STRONG_INT_TYPE(int, bucket_type);
struct stacked_bar_chart_base {
virtual ~stacked_bar_chart_base() = default;
struct show_none {};
struct show_all {};
struct show_one {
@ -78,8 +80,6 @@ public:
};
virtual ~stacked_bar_chart() { };
stacked_bar_chart &with_stacking_enabled(bool enabled) {
this->sbc_do_stacking = enabled;
return *this;

View File

@ -113,7 +113,10 @@ void input_dispatcher::new_input(const struct timeval &current_time, int ch)
this->id_escape_index = 0;
}
} else {
auto seq_size = utf::utf8::char_size([ch]() { return ch; });
auto seq_size = utf::utf8::char_size([ch]() {
return std::make_pair(ch, 16);
})
.unwrapOr(size_t{1});
if (seq_size == 1) {
snprintf(keyseq.data(), keyseq.size(), "x%02x", ch & 0xff);

View File

@ -1020,6 +1020,7 @@ static bool handle_config_ui_key(int ch)
{
nonstd::optional<ln_mode_t> new_mode;
lnav_data.ld_filter_help_status_source.fss_error.clear();
if (ch == 'F') {
new_mode = LNM_FILES;
} else if (ch == 'T') {

View File

@ -1317,7 +1317,11 @@ static Result<string, string> com_filter(exec_context &ec, string cmdline, vecto
text_filter::type_t lt = (args[0] == "filter-out") ?
text_filter::EXCLUDE :
text_filter::INCLUDE;
auto pf = make_shared<pcre_filter>(lt, args[1], fs.next_index(), code.release());
auto filter_index = fs.next_index();
if (!filter_index) {
return ec.make_error("too many filters");
}
auto pf = make_shared<pcre_filter>(lt, args[1], *filter_index, code.release());
log_debug("%s [%d] %s", args[0].c_str(), pf->get_index(), args[1].c_str());
fs.add_filter(pf);
@ -2809,7 +2813,7 @@ static Result<string, string> com_add_test(exec_context &ec, string cmdline, vec
snprintf(path, sizeof(path),
"%s/test/log-samples/sample-%s.txt",
getenv("LNAV_SRC"),
hash_string(line).c_str());
hasher().update(line).to_string().c_str());
if ((file = fopen(path, "w")) == nullptr) {
perror("fopen failed");

View File

@ -127,21 +127,42 @@ inline mstime_t getmstime() {
#error "off_t has unhandled size..."
#endif
struct hash_updater {
hash_updater(SpookyHash *context) : su_context(context) { };
void operator()(const std::string &str)
{
this->su_context->Update(str.c_str(), str.length());
class hasher {
public:
hasher() {
this->h_context.Init(0, 0);
}
SpookyHash *su_context;
hasher &update(const std::string &str) {
this->h_context.Update(str.data(), str.length());
return *this;
}
hasher &update(const char *bits, size_t len) {
this->h_context.Update(bits, len);
return *this;
}
template<typename T,
typename = std::enable_if<std::is_arithmetic<T>::value>>
hasher &update(T value) {
this->h_context.Update(&value, sizeof(value));
return *this;
}
std::string to_string() {
byte_array<2, uint64> bits;
this->h_context.Final(bits.out(0), bits.out(1));
return bits.to_string();
}
private:
SpookyHash h_context;
};
std::string hash_string(const std::string &str);
std::string hash_bytes(const char *str1, size_t s1len, ...);
template<typename UnaryFunction, typename Member>
struct object_field_t {
object_field_t(UnaryFunction &func, Member &mem)

View File

@ -190,7 +190,7 @@ class generic_log_format : public log_format {
lr.lr_start = pc[0]->c_begin;
lr.lr_end = pc[0]->c_end;
sa.push_back(string_attr(lr, &logline::L_TIMESTAMP));
sa.emplace_back(lr, &logline::L_TIMESTAMP);
const char *level = &line.get_data()[pc[1]->c_begin];
@ -203,11 +203,11 @@ class generic_log_format : public log_format {
lr.lr_start = 0;
lr.lr_end = prefix_len;
sa.push_back(string_attr(lr, &logline::L_PREFIX));
sa.emplace_back(lr, &logline::L_PREFIX);
lr.lr_start = prefix_len;
lr.lr_end = line.length();
sa.push_back(string_attr(lr, &textview_curses::SA_BODY));
sa.emplace_back(lr, &textview_curses::SA_BODY);
};
unique_ptr<log_format> specialized(int fmt_lock)

View File

@ -98,7 +98,7 @@ logfile::logfile(const string &filename, logfile_open_options &loo)
this->lf_valid_filename = false;
}
this->lf_content_id = hash_string(this->lf_filename);
this->lf_content_id = hasher().update(this->lf_filename).to_string();
this->lf_line_buffer.set_fd(this->lf_options.loo_fd);
this->lf_index.reserve(INDEX_RESERVE_INCREMENT);
@ -187,7 +187,9 @@ bool logfile::process_prefix(shared_buffer_ref &sbr, const line_info &li)
this->lf_format = (*iter)->specialized();
this->set_format_base_time(this->lf_format.get());
this->lf_content_id = hash_string(string(sbr.get_data(), sbr.length()));
this->lf_content_id = hasher()
.update(sbr.get_data(), sbr.length())
.to_string();
/*
* We'll go ahead and assume that any previous lines were

View File

@ -340,7 +340,7 @@ static void rl_search_internal(void *dummy, readline_curses *rc, ln_mode_t mode,
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
lnav_data.ld_bottom_source.
grep_error(string("sql error: ") + string(errmsg));
grep_error(fmt::format("sql error: {}", errmsg));
} else {
lnav_data.ld_bottom_source.grep_error("");
}

View File

@ -36,8 +36,6 @@
#include <fcntl.h>
#include <sys/types.h>
#include "spookyhash/SpookyV2.h"
#include <algorithm>
#include <utility>
#include <yajl/api/yajl_tree.h>
@ -173,9 +171,10 @@ static bool bind_line(sqlite3 *db,
}
auto line_hash = read_result.map([cl](auto sbr) {
return hash_bytes(sbr.get_data(), sbr.length(),
&cl, sizeof(cl),
nullptr);
return hasher()
.update(sbr.get_data(), sbr.length())
.update(cl)
.to_string();
}).unwrap();
return bind_values(stmt,
@ -297,25 +296,21 @@ void init_session()
static nonstd::optional<std::string> compute_session_id()
{
byte_array<2, uint64> hash;
SpookyHash context;
bool has_files = false;
hasher h;
context.Init(0, 0);
hash_updater updater(&context);
for (auto &ld_file_name : lnav_data.ld_active_files.fc_file_names) {
if (!ld_file_name.second.loo_include_in_session) {
continue;
}
has_files = true;
updater(ld_file_name.first);
h.update(ld_file_name.first);
}
if (!has_files) {
return nonstd::nullopt;
}
context.Final(hash.out(0), hash.out(1));
return hash.to_string();
return h.to_string();
}
nonstd::optional<session_pair_t> scan_sessions()
@ -504,9 +499,10 @@ void load_time_bookmarks()
auto sbr = read_result.unwrap();
string line_hash = hash_bytes(sbr.get_data(), sbr.length(),
&cl, sizeof(cl),
nullptr);
string line_hash = hasher()
.update(sbr.get_data(), sbr.length())
.update(cl)
.to_string();
if (line_hash == log_hash) {
content_line_t line_cl = content_line_t(
@ -671,7 +667,9 @@ void load_time_bookmarks()
auto sbr = read_result.unwrap();
string line_hash = hash_bytes(sbr.get_data(), sbr.length(), nullptr);
string line_hash = hasher()
.update(sbr.get_data(), sbr.length())
.to_string();
if (line_hash == log_hash) {
int file_line = std::distance(lf->begin(), line_iter);
content_line_t line_cl = content_line_t(
@ -1241,7 +1239,9 @@ static void save_time_bookmarks()
lf->original_line_time(line_iter),
lf->get_format()->get_name(),
read_result.map([](auto sbr) {
return hash_bytes(sbr.get_data(), sbr.length(), nullptr);
return hasher()
.update(sbr.get_data(), sbr.length())
.to_string();
}).unwrap(),
lnav_data.ld_session_time,
offset.tv_sec,

View File

@ -404,11 +404,11 @@ public:
else {
color = COLOR_RED;
}
value_out.push_back(string_attr(
value_out.emplace_back(
line_range(lpc, lpc + 1),
&view_curses::VC_STYLE,
vc.ansi_color_pair(COLOR_BLACK, color)
));
);
}
};

View File

@ -72,7 +72,7 @@ void textfile_sub_source::text_attrs_for_line(textview_curses &tc, int row,
lr.lr_start = 0;
lr.lr_end = -1;
value_out.push_back(string_attr(lr, &logline::L_FILE, this->current_file().get()));
value_out.emplace_back(lr, &logline::L_FILE, this->current_file().get());
}
size_t textfile_sub_source::text_size_for_line(textview_curses &tc, int line,

View File

@ -203,7 +203,7 @@ public:
return this->fs_filters.size() == logfile_filter_state::MAX_FILTERS;
}
size_t next_index() {
nonstd::optional<size_t> next_index() {
bool used[32];
memset(used, 0, sizeof(used));
@ -223,7 +223,7 @@ public:
return lpc;
}
}
throw "No more filters";
return nonstd::nullopt;
};
void add_filter(const std::shared_ptr<text_filter> &filter) {

View File

@ -319,24 +319,32 @@ void view_curses::mvwattrline(WINDOW *window,
break;
default: {
auto offset = 1 - (int) ww898::utf::utf8::char_size([ch]() {
return ch;
auto size_result = ww898::utf::utf8::char_size([&line, lpc]() {
return std::make_pair(line[lpc], line.length() - lpc - 1);
});
expanded_line[exp_index] = line[lpc];
exp_index += 1;
if (offset) {
if (char_index < lr_chars.lr_start) {
lr_bytes.lr_start += abs(offset);
}
if (char_index < lr_chars.lr_end) {
lr_bytes.lr_end += abs(offset);
}
exp_offset += offset;
utf_adjustments.emplace_back(lpc, offset);
for (; offset && (lpc + 1) < line.size(); lpc++, offset++) {
expanded_line[exp_index] = line[lpc + 1];
exp_index += 1;
if (size_result.isErr()) {
expanded_line[exp_index] = '?';
exp_index += 1;
} else {
auto offset = 1 - (int) size_result.unwrap();
expanded_line[exp_index] = line[lpc];
exp_index += 1;
if (offset) {
if (char_index < lr_chars.lr_start) {
lr_bytes.lr_start += abs(offset);
}
if (char_index < lr_chars.lr_end) {
lr_bytes.lr_end += abs(offset);
}
exp_offset += offset;
utf_adjustments.emplace_back(lpc, offset);
for (; offset &&
(lpc + 1) < line.size(); lpc++, offset++) {
expanded_line[exp_index] = line[lpc + 1];
exp_index += 1;
}
}
}
char_index += 1;

View File

@ -462,10 +462,14 @@ CREATE TABLE lnav_view_filters (
textview_curses &tc = lnav_data.ld_views[view_index];
text_sub_source *tss = tc.get_sub_source();
filter_stack &fs = tss->get_filters();
auto filter_index = fs.next_index();
if (!filter_index) {
throw sqlite_func_error("Too many filters");
}
auto pf = make_shared<pcre_filter>(
type.value_or(text_filter::type_t::EXCLUDE),
pattern.first,
fs.next_index(),
*filter_index,
pattern.second);
fs.add_filter(pf);
if (!enabled.value_or(true)) {

View File

@ -230,8 +230,9 @@ void vt52_curses::map_output(const char *output, int len)
else {
auto next_ch = output[lpc];
auto seq_size = ww898::utf::utf8::char_size([next_ch]() {
return next_ch;
});
return std::make_pair(next_ch, 16);
})
.unwrapOr(size_t{1});
if (seq_size > 1) {
this->vc_escape[0] = next_ch;

View File

@ -25,8 +25,11 @@
#pragma once
#include <cstdint>
#include <utility>
#include <stdexcept>
#include "base/result.h"
namespace ww898 {
namespace utf {
@ -47,24 +50,34 @@ struct utf8 final
using char_type = uint8_t;
template<typename PeekFn>
static size_t char_size(PeekFn && peek_fn)
static Result<size_t, const char *> char_size(PeekFn && peek_fn)
{
char_type const ch0 = std::forward<PeekFn>(peek_fn)();
if (ch0 < 0x80) // 0xxx_xxxx
return 1;
if (ch0 < 0xC0)
throw std::runtime_error("The utf8 first char in sequence is incorrect");
if (ch0 < 0xE0) // 110x_xxxx 10xx_xxxx
return 2;
if (ch0 < 0xF0) // 1110_xxxx 10xx_xxxx 10xx_xxxx
return 3;
if (ch0 < 0xF8) // 1111_0xxx 10xx_xxxx 10xx_xxxx 10xx_xxxx
return 4;
if (ch0 < 0xFC) // 1111_10xx 10xx_xxxx 10xx_xxxx 10xx_xxxx 10xx_xxxx
return 5;
if (ch0 < 0xFE) // 1111_110x 10xx_xxxx 10xx_xxxx 10xx_xxxx 10xx_xxxx 10xx_xxxx
return 6;
throw std::runtime_error("The utf8 first char in sequence is incorrect");
const std::pair<char_type, size_t> peek_res = std::forward<PeekFn>(peek_fn)();
const auto ch0 = peek_res.first;
const auto remaining = peek_res.second;
size_t retval = 0;
if (ch0 < 0x80) { // 0xxx_xxxx
retval = 1;
} else if (ch0 < 0xC0) {
return Err("The utf8 first char in sequence is incorrect");
} else if (ch0 < 0xE0) { // 110x_xxxx 10xx_xxxx
retval = 2;
} else if (ch0 < 0xF0) { // 1110_xxxx 10xx_xxxx 10xx_xxxx
retval = 3;
} else if (ch0 < 0xF8) { // 1111_0xxx 10xx_xxxx 10xx_xxxx 10xx_xxxx
retval = 4;
} else if (ch0 < 0xFC) { // 1111_10xx 10xx_xxxx 10xx_xxxx 10xx_xxxx 10xx_xxxx
retval = 5;
} else if (ch0 < 0xFE) { // 1111_110x 10xx_xxxx 10xx_xxxx 10xx_xxxx 10xx_xxxx 10xx_xxxx
retval = 6;
} else {
return Err("The utf8 first char in sequence is incorrect");
}
if (retval - 1 > remaining) {
return Err("Truncated utf8 sequence");
}
return Ok(retval);
}
template<typename ReadFn>