From 3c1a325b6f7c67c530d99aaaedf5f8c96f2b2de6 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 10 Mar 2015 19:33:46 +0000 Subject: [PATCH] Refactor String, use a common StringOps interface, hide std::string --- src/buffer_utils.cc | 4 +- src/client.cc | 5 + src/client.hh | 1 + src/command_manager.cc | 4 +- src/commands.cc | 31 ++-- src/display_buffer.cc | 4 +- src/file.cc | 14 +- src/highlighters.cc | 9 +- src/hook_manager.cc | 2 +- src/id_map.hh | 2 +- src/input_handler.cc | 18 +-- src/insert_completer.cc | 15 +- src/keys.cc | 6 +- src/main.cc | 24 ++-- src/ncurses_ui.cc | 2 +- src/normal.cc | 12 +- src/option_types.hh | 4 +- src/parameters_parser.cc | 8 +- src/regex.cc | 3 +- src/regex.hh | 16 ++- src/register_manager.cc | 2 +- src/shell_manager.cc | 4 +- src/string.cc | 5 - src/string.hh | 298 +++++++++++++++++---------------------- 24 files changed, 236 insertions(+), 257 deletions(-) diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 88f7d4f8..eda4d9d4 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -53,7 +53,7 @@ Buffer* create_buffer_from_data(StringView data, StringView name, const char* pos = data.begin(); if (data.length() >= 3 and - data[0] == '\xEF' and data[1] == '\xBB' and data[2] == '\xBF') + data[0_byte] == '\xEF' and data[1_byte] == '\xBB' and data[2_byte] == '\xBF') { bom = true; pos = data.begin() + 3; @@ -81,7 +81,7 @@ Buffer* create_buffer_from_data(StringView data, StringView name, if (buffer) buffer->reload(std::move(lines), fs_timestamp); else - buffer = new Buffer{name, flags, std::move(lines), fs_timestamp}; + buffer = new Buffer{name.str(), flags, std::move(lines), fs_timestamp}; OptionManager& options = buffer->options(); options.get_local_option("eolformat").set(crlf ? "crlf" : "lf"); diff --git a/src/client.cc b/src/client.cc index 74a9aff2..ae18ebe4 100644 --- a/src/client.cc +++ b/src/client.cc @@ -257,6 +257,11 @@ StringView Client::get_env_var(const String& name) const return it->second; } +StringView Client::get_env_var(StringView name) const +{ + return get_env_var(name.str()); +} + void Client::on_option_changed(const Option& option) { if (option.name() == "ui_options") diff --git a/src/client.hh b/src/client.hh index 0f7eeb40..8a8c309f 100644 --- a/src/client.hh +++ b/src/client.hh @@ -51,6 +51,7 @@ public: void change_buffer(Buffer& buffer); StringView get_env_var(const String& name) const; + StringView get_env_var(StringView name) const; private: void on_option_changed(const Option& option) override; diff --git a/src/command_manager.cc b/src/command_manager.cc index 67e33c1e..459fcc22 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -119,7 +119,7 @@ String get_until_delimiter(StringView base, ByteCount& pos, } ++pos; } - return base.substr(start, pos - start); + return base.substr(start, pos - start).str(); } struct unknown_expand : parse_error @@ -313,7 +313,7 @@ String eval_token(const Token& token, Context& context, return ShellManager::instance().eval(content, context, shell_params, env_vars); case Token::Type::RegisterExpand: - return context.main_sel_register_value(content); + return context.main_sel_register_value(content).str(); case Token::Type::OptionExpand: return context.options()[content].get_as_string(); case Token::Type::ValExpand: diff --git a/src/commands.cc b/src/commands.cc index 08a9e3a6..97e19bd8 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -47,7 +47,7 @@ Buffer* open_fifo(StringView name, StringView filename, bool scroll) if (fd < 0) throw runtime_error("unable to open " + filename); - return create_fifo_buffer(name, fd, scroll); + return create_fifo_buffer(name.str(), fd, scroll); } const PerArgumentCommandCompleter filename_completer({ @@ -69,9 +69,9 @@ static CandidateList complete_buffer_name(StringView prefix, ByteCount cursor_po StringView match_name = name; if (not include_dirs and buffer->flags() & Buffer::Flags::File) { - ByteCount pos = name.find_last_of('/'); - if (pos != (int)String::npos) - match_name = name.substr(pos+1); + auto it = find(reversed(name), '/'); + if (it != name.rend()) + match_name = StringView{it.base() + 2, name.end()}; } if (prefix_match(match_name, prefix)) prefix_result.push_back(name); @@ -434,7 +434,7 @@ const CommandDesc namebuf_cmd = { Completions complete_highlighter(const Context& context, StringView arg, ByteCount pos_in_token, bool only_group) { - const bool shared = not arg.empty() and arg[0] == '/'; + const bool shared = not arg.empty() and arg[0_byte] == '/'; if (shared) { auto& group = DefinedHighlighters::instance(); @@ -480,7 +480,7 @@ Highlighter& get_highlighter(const Context& context, StringView path) throw runtime_error("group path should not be empty"); Highlighter* root = nullptr; - if (path[0] == '/') + if (path[0_byte] == '/') { root = &DefinedHighlighters::instance(); path = path.substr(1_byte); @@ -603,12 +603,12 @@ const CommandDesc add_hook_cmd = { if (regex_match(param.begin(), param.end(), regex)) CommandManager::instance().execute(command, context, {}, - { { "hook_param", param } }); + { { "hook_param", param.str() } }); }; StringView group; if (parser.has_option("group")) group = parser.option_value("group"); - get_scope(parser[0], context).hooks().add_hook(parser[1], group, hook_func); + get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), hook_func); } }; @@ -866,7 +866,7 @@ const CommandDesc debug_cmd = { { size_t count = domain_allocated_bytes[domain]; total += count; - write_debug(" "_sv + domain_name((MemoryDomain)domain) + ": " + to_string(count)); + write_debug(" "_str + domain_name((MemoryDomain)domain) + ": " + to_string(count)); } write_debug(" Total: " + to_string(total)); #if defined(__GLIBC__) || defined(__CYGWIN__) @@ -1254,7 +1254,7 @@ const CommandDesc prompt_cmd = { { if (params[1].length() != 1) throw runtime_error("register name should be a single character"); - const char reg = params[1][0]; + const char reg = params[1][0_byte]; const String& command = params[2]; String initstr; @@ -1267,7 +1267,7 @@ const CommandDesc prompt_cmd = { { if (event != PromptEvent::Validate) return; - RegisterManager::instance()[reg] = ConstArrayView(str); + RegisterManager::instance()[reg] = ConstArrayView(str.str()); CommandManager::instance().execute(command, context); }); @@ -1344,12 +1344,11 @@ const CommandDesc info_cmd = { if (parser.has_option("anchor")) { auto anchor = parser.option_value("anchor"); - size_t dot = anchor.find_first_of('.'); - if (dot == String::npos) + auto dot = find(anchor, '.'); + if (dot == anchor.end()) throw runtime_error("expected . for anchor"); - ByteCount dotb = (int)dot; - ByteCoord coord{str_to_int(anchor.substr(0, dotb))-1, - str_to_int(anchor.substr(dotb+1))-1}; + ByteCoord coord{str_to_int({anchor.begin(), dot})-1, + str_to_int({dot+1, anchor.end()})-1}; pos = context.window().display_position(coord); style = InfoStyle::Inline; if (parser.has_option("placement")) diff --git a/src/display_buffer.cc b/src/display_buffer.cc index a56fe612..3bcf37b2 100644 --- a/src/display_buffer.cc +++ b/src/display_buffer.cc @@ -49,7 +49,7 @@ void DisplayAtom::trim_begin(CharCount count) m_begin = utf8::advance(m_buffer->iterator_at(m_begin), m_buffer->iterator_at(m_end), count).coord(); else - m_text = m_text.substr(count); + m_text = m_text.substr(count).str(); check_invariant(); } @@ -59,7 +59,7 @@ void DisplayAtom::trim_end(CharCount count) m_end = utf8::advance(m_buffer->iterator_at(m_end), m_buffer->iterator_at(m_begin), -count).coord(); else - m_text = m_text.substr(0, m_text.char_length() - count); + m_text = m_text.substr(0, m_text.char_length() - count).str(); check_invariant(); } diff --git a/src/file.cc b/src/file.cc index a12b40ce..ec409df8 100644 --- a/src/file.cc +++ b/src/file.cc @@ -26,8 +26,8 @@ namespace Kakoune String parse_filename(StringView filename) { - if (filename.length() >= 1 and filename[0] == '~' and - (filename.length() == 1 or filename[1] == '/')) + if (filename.length() >= 1 and filename[0_byte] == '~' and + (filename.length() == 1 or filename[1_byte] == '/')) return parse_filename("$HOME"_str + filename.substr(1_byte)); ByteCount pos = 0; @@ -90,7 +90,7 @@ String real_path(StringView filename) auto it = find(existing.rbegin(), existing.rend(), '/'); if (it == existing.rend()) - return filename; + return filename.str(); existing = StringView{existing.begin(), it.base()-1}; non_existing = StringView{it.base(), filename.end()}; @@ -105,7 +105,7 @@ String compact_path(StringView filename) getcwd(cwd, 1024); String real_cwd = real_path(cwd) + "/"; if (prefix_match(real_filename, real_cwd)) - return real_filename.substr(real_cwd.length()); + return real_filename.substr(real_cwd.length()).str(); const char* home = getenv("HOME"); if (home) @@ -258,14 +258,14 @@ void write_buffer_to_backup_file(Buffer& buffer) String find_file(StringView filename, ConstArrayView paths) { struct stat buf; - if (filename.length() > 1 and filename[0] == '/') + if (filename.length() > 1 and filename[0_byte] == '/') { if (stat(filename.zstr(), &buf) == 0 and S_ISREG(buf.st_mode)) return filename.str(); return ""; } if (filename.length() > 2 and - filename[0] == '~' and filename[1] == '/') + filename[0_byte] == '~' and filename[1_byte] == '/') { String candidate = getenv("HOME") + filename.substr(1_byte).str(); if (stat(candidate.c_str(), &buf) == 0 and S_ISREG(buf.st_mode)) @@ -386,7 +386,7 @@ Vector complete_command(StringView prefix, ByteCount cursor_pos) Vector res; for (auto dir : split(getenv("PATH"), ':')) { - String dirname = dir; + String dirname = dir.str(); if (not dirname.empty() and dirname.back() != '/') dirname += '/'; diff --git a/src/highlighters.cc b/src/highlighters.cc index 3cd00a75..900835cf 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -264,9 +264,9 @@ public: if (not regex_match(it->begin(), it->end(), res, face_spec_ex)) throw runtime_error("wrong face spec: '" + *it + "' expected :"); - get_face(res[2].str()); // throw if wrong face spec - int capture = str_to_int(res[1].str()); - faces.emplace_back(capture, res[2].str()); + get_face({res[2].first, res[2].second}); // throw if wrong face spec + int capture = str_to_int({res[1].first, res[1].second}); + faces.emplace_back(capture, String{res[2].first, res[2].second}); } String id = "hlregex'" + params[0] + "'"; @@ -711,7 +711,8 @@ void expand_unprintable(const Context& context, HighlightFlags flags, DisplayBuf { std::ostringstream oss; oss << "U+" << std::hex << cp; - String str = oss.str(); + const auto& stdstr = oss.str(); + String str{stdstr.begin(), stdstr.end()}; if (it.coord() != atom_it->begin()) atom_it = ++line.split(atom_it, it.coord()); if (next.coord() < atom_it->end()) diff --git a/src/hook_manager.cc b/src/hook_manager.cc index cc4c1ec6..d7879c61 100644 --- a/src/hook_manager.cc +++ b/src/hook_manager.cc @@ -51,7 +51,7 @@ void HookManager::run_hook(StringView hook_name, for (auto& hook : hook_list_it->second) { if (not hook.first.empty() and not disabled_hooks.empty() and - regex_match(hook.first, disabled_hooks)) + regex_match(hook.first.begin(), hook.first.end(), disabled_hooks)) continue; try diff --git a/src/id_map.hh b/src/id_map.hh index e6f2f7b0..72d1c2f0 100644 --- a/src/id_map.hh +++ b/src/id_map.hh @@ -65,7 +65,7 @@ public: if (it != m_content.end()) return it->second; - append({ id, Value{} }); + append({ id.str(), Value{} }); return (m_content.end()-1)->second; } diff --git a/src/input_handler.cc b/src/input_handler.cc index 23717f88..1e6d0cad 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -154,7 +154,7 @@ public: if (m_params.reg != '"') { atoms.push_back({ "; reg=", Face(Colors::Yellow) }); - atoms.push_back({ StringView(m_params.reg), Face(Colors::Green) }); + atoms.push_back({ StringView(m_params.reg).str(), Face(Colors::Green) }); } return atoms; } @@ -325,12 +325,12 @@ public: m_display_pos = m_cursor_pos + 1 - width; if (m_cursor_pos == m_line.char_length()) - return DisplayLine{{ {m_line.substr(m_display_pos, width-1), get_face("StatusLine")}, + return DisplayLine{{ {m_line.substr(m_display_pos, width-1).str(), get_face("StatusLine")}, {" "_str, get_face("StatusCursor")} }}; else - return DisplayLine({ { m_line.substr(m_display_pos, m_cursor_pos - m_display_pos), get_face("StatusLine") }, - { m_line.substr(m_cursor_pos,1), get_face("StatusCursor") }, - { m_line.substr(m_cursor_pos+1, width - m_cursor_pos + m_display_pos - 1), get_face("StatusLine") } }); + return DisplayLine({ { m_line.substr(m_display_pos, m_cursor_pos - m_display_pos).str(), get_face("StatusLine") }, + { m_line.substr(m_cursor_pos,1).str(), get_face("StatusCursor") }, + { m_line.substr(m_cursor_pos+1, width - m_cursor_pos + m_display_pos - 1).str(), get_face("StatusLine") } }); } private: CharCount m_cursor_pos = 0; @@ -473,7 +473,7 @@ String common_prefix(ConstArrayView strings) while (common_len < len and str[common_len] == res[common_len]) ++common_len; if (common_len != res.length()) - res = res.substr(0, common_len); + res = res.substr(0, common_len).str(); } return res; } @@ -484,7 +484,7 @@ public: Prompt(InputHandler& input_handler, StringView prompt, String initstr, Face face, Completer completer, PromptCallback callback) - : InputMode(input_handler), m_prompt(prompt), m_prompt_face(face), + : InputMode(input_handler), m_prompt(prompt.str()), m_prompt_face(face), m_completer(completer), m_callback(callback), m_autoshowcompl{context().options()["autoshowcompl"].get()} { @@ -600,7 +600,7 @@ public: String prefix = common_prefix(candidates); if (m_completions.end - m_completions.start > prefix.length()) prefix = line.substr(m_completions.start, - m_completions.end - m_completions.start); + m_completions.end - m_completions.start).str(); if (not prefix.empty()) { @@ -742,7 +742,7 @@ private: History::iterator it; while ((it = find(history, entry)) != history.end()) history.erase(it); - history.push_back(entry); + history.push_back(entry.str()); } }; UnorderedMap Prompt::ms_history; diff --git a/src/insert_completer.cc b/src/insert_completer.cc index 45f9681f..5d76023d 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -119,7 +119,7 @@ InsertCompletion complete_word(const Buffer& buffer, ByteCoord cursor_pos) ComplAndDescList result; result.reserve(matches.size()); for (auto& m : matches) - result.emplace_back(m, ""); + result.emplace_back(m.str(), ""); return { begin.coord(), cursor_pos, std::move(result), buffer.timestamp() }; } @@ -158,7 +158,7 @@ InsertCompletion complete_filename(const Buffer& buffer, ByteCoord cursor_pos, if (not dir.empty() and dir.back() != '/') dir += '/'; for (auto& filename : Kakoune::complete_filename(dir + prefix, Regex{})) - res.emplace_back(filename.substr(dir.length()), ""); + res.emplace_back(filename.substr(dir.length()).str(), ""); } } if (res.empty()) @@ -178,16 +178,17 @@ InsertCompletion complete_option(const Buffer& buffer, ByteCoord cursor_pos, MatchResults match; if (regex_match(desc.begin(), desc.end(), match, re)) { - ByteCoord coord{ str_to_int(match[1].str()) - 1, str_to_int(match[2].str()) - 1 }; + ByteCoord coord{ str_to_int({match[1].first, match[1].second}) - 1, + str_to_int({match[2].first, match[2].second}) - 1 }; if (not buffer.is_valid(coord)) return {}; auto end = coord; if (match[3].matched) { - ByteCount len = str_to_int(match[3].str()); + ByteCount len = str_to_int({match[3].first, match[3].second}); end = buffer.advance(coord, len); } - size_t timestamp = (size_t)str_to_int(match[4].str()); + size_t timestamp = (size_t)str_to_int({match[4].first, match[4].second}); auto changes = buffer.changes_since(timestamp); if (find_if(changes, [&](const Buffer::Change& change){ return change.begin < coord; @@ -204,7 +205,7 @@ InsertCompletion complete_option(const Buffer& buffer, ByteCoord cursor_pos, { auto splitted = split(*it, '@'); if (not splitted.empty() and prefix_match(splitted[0], prefix)) - res.emplace_back(splitted[0], splitted.size() > 1 ? splitted[1] : ""); + res.emplace_back(splitted[0].str(), splitted.size() > 1 ? splitted[1].str() : ""); } return { coord, end, std::move(res), timestamp }; } @@ -222,7 +223,7 @@ InsertCompletion complete_line(const Buffer& buffer, ByteCoord cursor_pos) continue; ByteCount len = buffer[l].length(); if (len > cursor_pos.column and std::equal(prefix.begin(), prefix.end(), buffer[l].begin())) - res.emplace_back(buffer[l].substr(0_byte, len-1), ""); + res.emplace_back(buffer[l].substr(0_byte, len-1).str(), ""); } if (res.empty()) return {}; diff --git a/src/keys.cc b/src/keys.cc index b328252c..7dd45383 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -64,9 +64,9 @@ KeyList parse_keys(StringView str) Key::Modifiers modifier = Key::Modifiers::None; StringView desc{it.base()+1, end_it.base()}; - if (desc.length() > 2 and desc[1] == '-') + if (desc.length() > 2 and desc[1_byte] == '-') { - switch(tolower(desc[0])) + switch(tolower(desc[0_byte])) { case 'c': modifier = Key::Modifiers::Control; break; case 'a': modifier = Key::Modifiers::Alt; break; @@ -82,7 +82,7 @@ KeyList parse_keys(StringView str) result.push_back(canonicalize_ifn({ modifier, name_it->key })); else if (desc.char_length() == 1) result.push_back(Key{ modifier, desc[0_char] }); - else if (tolower(desc[0]) == 'f' and desc.length() <= 3) + else if (tolower(desc[0_byte]) == 'f' and desc.length() <= 3) { int val = str_to_int(desc.substr(1_byte)); if (val >= 1 and val <= 12) diff --git a/src/main.cc b/src/main.cc index af77ba44..f022361d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -37,10 +37,10 @@ void run_unit_tests(); String runtime_directory() { String bin_path = get_kak_binary_path(); - size_t last_slash = bin_path.find_last_of('/'); - if (last_slash == String::npos) + auto it = find(reversed(bin_path), '/'); + if (it == bin_path.rend()) throw runtime_error("unable to determine runtime directory"); - return bin_path.substr(0_byte, (int)last_slash) + "/../share/kak"; + return StringView{bin_path.begin(), it.base()-1} + "/../share/kak"; } void register_env_vars() @@ -54,7 +54,7 @@ void register_env_vars() { return context.buffer().display_name(); } }, { "buffile", - [](StringView name, const Context& context) -> String + [](StringView name, const Context& context) { return context.buffer().name(); } }, { "buflist", @@ -85,19 +85,19 @@ void register_env_vars() { return context.options()[name.substr(4_byte)].get_as_string(); } }, { "reg_.+", - [](StringView name, const Context& context) -> String - { return context.main_sel_register_value(name.substr(4_byte)); } + [](StringView name, const Context& context) + { return context.main_sel_register_value(name.substr(4_byte)).str(); } }, { "client_env_.+", - [](StringView name, const Context& context) -> String - { return context.client().get_env_var(name.substr(11_byte)); } + [](StringView name, const Context& context) + { return context.client().get_env_var(name.substr(11_byte)).str(); } }, { "session", - [](StringView name, const Context& context) -> String + [](StringView name, const Context& context) { return Server::instance().session(); } }, { "client", - [](StringView name, const Context& context) -> String + [](StringView name, const Context& context) { return context.name(); } }, { "cursor_line", @@ -356,7 +356,7 @@ int run_server(StringView session, StringView init_command, write_debug("*** This is the debug buffer, where debug info will be written ***"); - Server server(session.empty() ? to_string(getpid()) : String{session}); + Server server(session.empty() ? to_string(getpid()) : session.str()); if (not ignore_kakrc) try { @@ -385,7 +385,7 @@ int run_server(StringView session, StringView init_command, for (auto& file : reversed(files)) { if (not create_buffer_from_file(file)) - new Buffer(file, Buffer::Flags::New | Buffer::Flags::File); + new Buffer(file.str(), Buffer::Flags::New | Buffer::Flags::File); } } catch (Kakoune::runtime_error& error) diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index 9e401985..13de9fd2 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -591,7 +591,7 @@ void NCursesUI::menu_show(ConstArrayView items, const CharCount maxlen = min((int)maxsize.column-2, 200); for (auto& item : items) { - m_items.push_back(item.substr(0_char, maxlen)); + m_items.push_back(item.substr(0_char, maxlen).str()); longest = max(longest, m_items.back().char_length()); } longest += 1; diff --git a/src/normal.cc b/src/normal.cc index 8893b8f5..4d16bad0 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -375,7 +375,7 @@ void pipe(Context& context, NormalParams) real_cmd = context.main_sel_register_value("|"); else { - RegisterManager::instance()['|'] = String{cmdline}; + RegisterManager::instance()['|'] = cmdline.str(); real_cmd = cmdline; } @@ -397,7 +397,7 @@ void pipe(Context& context, NormalParams) {}, EnvVarMap{}); if ((insert_eol or sel.max() == buffer.back_coord()) and str.back() == '\n') - str = str.substr(0, str.length()-1); + str = str.substr(0, str.length()-1).str(); strings.push_back(std::move(str)); } ScopedEdition edition(context); @@ -428,7 +428,7 @@ void insert_output(Context& context, NormalParams) real_cmd = context.main_sel_register_value("|"); else { - RegisterManager::instance()['|'] = String{cmdline}; + RegisterManager::instance()['|'] = cmdline.str(); real_cmd = cmdline; } @@ -617,7 +617,7 @@ void search(Context& context, NormalParams) if (ex.empty()) ex = Regex{context.main_sel_register_value("/").str()}; else if (event == PromptEvent::Validate) - RegisterManager::instance()['/'] = String{ex.str()}; + RegisterManager::instance()['/'] = ex.str(); if (not ex.empty() and not ex.str().empty()) select_next_match(context.buffer(), context.selections(), ex); }); @@ -674,7 +674,7 @@ void select_regex(Context& context, NormalParams) if (ex.empty()) ex = Regex{context.main_sel_register_value("/").str()}; else if (event == PromptEvent::Validate) - RegisterManager::instance()['/'] = String{ex.str()}; + RegisterManager::instance()['/'] = ex.str(); if (not ex.empty() and not ex.str().empty()) select_all_matches(context.selections(), ex); }); @@ -686,7 +686,7 @@ void split_regex(Context& context, NormalParams) if (ex.empty()) ex = Regex{context.main_sel_register_value("/").str()}; else if (event == PromptEvent::Validate) - RegisterManager::instance()['/'] = String{ex.str()}; + RegisterManager::instance()['/'] = ex.str(); if (not ex.empty() and not ex.str().empty()) split_selections(context.selections(), ex); }); diff --git a/src/option_types.hh b/src/option_types.hh index ef611ae4..0f204b70 100644 --- a/src/option_types.hh +++ b/src/option_types.hh @@ -14,8 +14,8 @@ namespace Kakoune { -inline String option_to_string(StringView opt) { return opt; } -inline void option_from_string(StringView str, String& opt) { opt = str; } +inline String option_to_string(StringView opt) { return opt.str(); } +inline void option_from_string(StringView str, String& opt) { opt = str.str(); } inline String option_to_string(int opt) { return to_string(opt); } inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); } diff --git a/src/parameters_parser.cc b/src/parameters_parser.cc index 06c081e0..e86d7101 100644 --- a/src/parameters_parser.cc +++ b/src/parameters_parser.cc @@ -21,7 +21,7 @@ ParametersParser::ParametersParser(ParameterList params, { if (not only_pos and params[i] == "--") only_pos = true; - else if (not only_pos and params[i][0] == '-') + else if (not only_pos and params[i][0_byte] == '-') { auto it = m_desc.switches.find(params[i].substr(1_byte)); if (it == m_desc.switches.end()) @@ -30,7 +30,7 @@ ParametersParser::ParametersParser(ParameterList params, if (it->second.takes_arg) { ++i; - if (i == params.size() or params[i][0] == '-') + if (i == params.size() or params[i][0_byte] == '-') throw missing_option_value(it->first); } } @@ -51,7 +51,7 @@ bool ParametersParser::has_option(const String& name) const kak_assert(m_desc.switches.find(name) != m_desc.switches.end()); for (auto& param : m_params) { - if (param[0] == '-' and param.substr(1_byte) == name) + if (param[0_byte] == '-' and param.substr(1_byte) == name) return true; if (param == "--") @@ -70,7 +70,7 @@ const String& ParametersParser::option_value(const String& name) const for (size_t i = 0; i < m_params.size(); ++i) { - if (m_params[i][0] == '-' and m_params[i].substr(1_byte) == name) + if (m_params[i][0_byte] == '-' and m_params[i].substr(1_byte) == name) return m_params[i+1]; if (m_params[i] == "--") diff --git a/src/regex.cc b/src/regex.cc index d2c8f615..23916036 100644 --- a/src/regex.cc +++ b/src/regex.cc @@ -7,7 +7,8 @@ namespace Kakoune String option_to_string(const Regex& re) { - return String{re.str()}; + const auto& str = re.str(); + return String{str.begin(), str.end()}; } void option_from_string(StringView str, Regex& re) diff --git a/src/regex.hh b/src/regex.hh index aa71f669..8d87427e 100644 --- a/src/regex.hh +++ b/src/regex.hh @@ -29,15 +29,27 @@ struct Regex : std::regex bool operator==(const Regex& other) { return m_str == other.m_str; } bool operator!=(const Regex& other) { return m_str != other.m_str; } - StringView str() const { return m_str; } + const String& str() const { return m_str; } private: String m_str; }; namespace regex_ns = std; #else +struct Regex : boost::regex +{ + Regex() = default; + + explicit Regex(StringView re, flag_type flags = ECMAScript) + : boost::regex(re.begin(), re.end(), flags) {} + + template + Regex(Iterator begin, Iterator end, flag_type flags = ECMAScript) + : boost::regex(begin, end, flags) {} + + String str() const { auto s = boost::regex::str(); return {s.begin(), s.end()}; } +}; namespace regex_ns = boost; -using Regex = boost::regex; #endif template diff --git a/src/register_manager.cc b/src/register_manager.cc index 7a071ae3..7990c13b 100644 --- a/src/register_manager.cc +++ b/src/register_manager.cc @@ -59,7 +59,7 @@ private: Register& RegisterManager::operator[](StringView reg) { if (reg.length() == 1) - return (*this)[reg[0]]; + return (*this)[reg[0_byte]]; static const IdMap reg_names = { { "slash", '/' }, diff --git a/src/shell_manager.cc b/src/shell_manager.cc index d10c4ad5..6b82ba91 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -23,7 +23,7 @@ ShellManager::ShellManager() new_path = path + ":"_str; String kak_path = get_kak_binary_path(); - StringView kak_dir = kak_path.substr(0_byte, (int)kak_path.find_last_of('/')); + StringView kak_dir{kak_path.begin(), find(reversed(kak_path), '/').base()-1}; new_path += kak_dir; setenv("PATH", new_path.c_str(), 1); } @@ -111,7 +111,7 @@ String ShellManager::pipe(StringView input, StringView name = StringView(match[1].first, match[1].second); kak_assert(name.length() > 0); - auto local_var = env_vars.find(name); + auto local_var = env_vars.find(name.str()); if (local_var != env_vars.end()) setenv(("kak_" + name).c_str(), local_var->second.c_str(), 1); else diff --git a/src/string.cc b/src/string.cc index beeb4a74..5da03901 100644 --- a/src/string.cc +++ b/src/string.cc @@ -9,11 +9,6 @@ namespace Kakoune { -bool operator<(StringView lhs, StringView rhs) -{ - return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); -} - Vector split(StringView str, char separator, char escape) { Vector res; diff --git a/src/string.hh b/src/string.hh index 74df3fd7..4fb24c1e 100644 --- a/src/string.hh +++ b/src/string.hh @@ -14,56 +14,133 @@ namespace Kakoune class StringView; -using StringBase = std::basic_string, - Allocator>; - -constexpr ByteCount strlen(const char* s) -{ - return *s == 0 ? 0 : strlen(s+1) + 1; -} - -class String : public StringBase +template +class StringOps { public: + using value_type = CharType; + + friend bool operator==(const Type& lhs, const Type& rhs) + { + return lhs.length() == rhs.length() and + std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + friend bool operator!=(const Type& lhs, const Type& rhs) + { + return lhs.length() != rhs.length() or + not std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + friend bool operator<(const Type& lhs, const Type& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end()); + } + + friend inline size_t hash_value(const Type& str) + { + return hash_data(str.data(), (int)str.length()); + } + + using iterator = CharType*; + using const_iterator = const CharType*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + [[gnu::always_inline]] + iterator begin() { return type().data(); } + + [[gnu::always_inline]] + const_iterator begin() const { return type().data(); } + + [[gnu::always_inline]] + iterator end() { return type().data() + (int)type().length(); } + + [[gnu::always_inline]] + const_iterator end() const { return type().data() + (int)type().length(); } + + reverse_iterator rbegin() { return reverse_iterator{end()}; } + const_reverse_iterator rbegin() const { return const_reverse_iterator{end()}; } + + reverse_iterator rend() { return reverse_iterator{begin()}; } + const_reverse_iterator rend() const { return const_reverse_iterator{begin()}; } + + CharType& front() { return *type().data(); } + const CharType& front() const { return *type().data(); } + CharType& back() { return type().data()[(int)type().length() - 1]; } + const CharType& back() const { return type().data()[(int)type().length() - 1]; } + + [[gnu::always_inline]] + CharType& operator[](ByteCount pos) { return type().data()[(int)pos]; } + + [[gnu::always_inline]] + const CharType& operator[](ByteCount pos) const + { return type().data()[(int)pos]; } + + Codepoint operator[](CharCount pos) const + { return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); } + + CharCount char_length() const { return utf8::distance(begin(), end()); } + + [[gnu::always_inline]] + bool empty() const { return type().length() == 0_byte; } + + ByteCount byte_count_to(CharCount count) const + { return utf8::advance(begin(), end(), (int)count) - begin(); } + + CharCount char_count_to(ByteCount count) const + { return utf8::distance(begin(), begin() + (int)count); } + + StringView substr(ByteCount from, ByteCount length = INT_MAX) const; + StringView substr(CharCount from, CharCount length = INT_MAX) const; + +private: + Type& type() { return *static_cast(this); } + const Type& type() const { return *static_cast(this); } +}; + +class String : public StringOps +{ +public: + using Content = std::basic_string, + Allocator>; + String() {} - String(const char* content) : StringBase(content) {} - String(StringBase content) : StringBase(std::move(content)) {} - template - String(const std::basic_string& content) : StringBase(content.begin(), content.end()) {} - explicit String(char content, CharCount count = 1) : StringBase((size_t)(int)count, content) {} + String(const char* content) : m_data(content) {} + String(Content content) : m_data(std::move(content)) {} + explicit String(char content, CharCount count = 1) : m_data((size_t)(int)count, content) {} explicit String(Codepoint cp, CharCount count = 1) { while (count-- > 0) - utf8::dump(back_inserter(*this), cp); + utf8::dump(std::back_inserter(*this), cp); } template - String(Iterator begin, Iterator end) : StringBase(begin, end) {} - - StringBase& stdstr() { return *this; } - const StringBase& stdstr() const { return *this; } + String(Iterator begin, Iterator end) : m_data(begin, end) {} [[gnu::always_inline]] - char operator[](ByteCount pos) const { return StringBase::operator[]((int)pos); } - [[gnu::always_inline]] - char& operator[](ByteCount pos) { return StringBase::operator[]((int)pos); } - Codepoint operator[](CharCount pos) { return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); } + char* data() { return &m_data[0]; } [[gnu::always_inline]] - ByteCount length() const { return ByteCount{(int)StringBase::length()}; } - CharCount char_length() const { return utf8::distance(begin(), end()); } - ByteCount byte_count_to(CharCount count) const { return utf8::advance(begin(), end(), (int)count) - begin(); } - CharCount char_count_to(ByteCount count) const { return utf8::distance(begin(), begin() + (int)count); } + const char* data() const { return m_data.data(); } - String& operator+=(const String& other) { StringBase::operator+=(other); return *this; } - String& operator+=(const char* other) { StringBase::operator+=(other); return *this; } - String& operator+=(char other) { StringBase::operator+=(other); return *this; } - String& operator+=(Codepoint cp) { utf8::dump(back_inserter(*this), cp); return *this; } + [[gnu::always_inline]] + ByteCount length() const { return ByteCount{(int)m_data.length()}; } - StringView substr(ByteCount pos, ByteCount length = INT_MAX) const; - StringView substr(CharCount pos, CharCount length = INT_MAX) const; + [[gnu::always_inline]] + const char* c_str() const { return m_data.c_str(); } + + void append(const char* data, ByteCount count) { m_data.append(data, (size_t)(int)count); } + + void push_back(char c) { m_data.push_back(c); } + void resize(ByteCount size) { m_data.resize((size_t)(int)size); } + void reserve(ByteCount size) { m_data.reserve((size_t)(int)size); } + +private: + Content m_data; }; -class StringView +class StringView : public StringOps { public: constexpr StringView() : m_data{nullptr}, m_length{0} {} @@ -71,50 +148,17 @@ public: : m_data{data}, m_length{length} {} constexpr StringView(const char* data) : m_data{data}, m_length{strlen(data)} {} constexpr StringView(const char* begin, const char* end) : m_data{begin}, m_length{(int)(end - begin)} {} - template - StringView(const std::basic_string& str) : m_data{str.data()}, m_length{(int)str.length()} {} + StringView(const String& str) : m_data{str.data()}, m_length{(int)str.length()} {} StringView(const char& c) : m_data(&c), m_length(1) {} - friend bool operator==(StringView lhs, StringView rhs); - [[gnu::always_inline]] const char* data() const { return m_data; } - using iterator = const char*; - using reverse_iterator = std::reverse_iterator; - - [[gnu::always_inline]] - iterator begin() const { return m_data; } - [[gnu::always_inline]] - iterator end() const { return m_data + (int)m_length; } - - reverse_iterator rbegin() const { return reverse_iterator{m_data + (int)m_length}; } - reverse_iterator rend() const { return reverse_iterator{m_data}; } - - char front() const { return *m_data; } - char back() const { return m_data[(int)m_length - 1]; } - - [[gnu::always_inline]] - char operator[](ByteCount pos) const { return m_data[(int)pos]; } - Codepoint operator[](CharCount pos) { return utf8::codepoint(utf8::advance(begin(), end(), pos), end()); } - [[gnu::always_inline]] ByteCount length() const { return m_length; } - CharCount char_length() const { return utf8::distance(begin(), end()); } - - [[gnu::always_inline]] - bool empty() { return m_length == 0_byte; } - - ByteCount byte_count_to(CharCount count) const; - CharCount char_count_to(ByteCount count) const; - - StringView substr(ByteCount from, ByteCount length = INT_MAX) const; - StringView substr(CharCount from, CharCount length = INT_MAX) const; String str() const { return String{begin(), end()}; } - operator String() const { return str(); } // to remove - struct ZeroTerminatedString { ZeroTerminatedString(const char* begin, const char* end) @@ -122,53 +166,37 @@ public: if (*end == '\0') unowned = begin; else - owned = StringBase(begin, end); + owned = String::Content(begin, end); } operator const char*() const { return unowned ? unowned : owned.c_str(); } private: - StringBase owned; + String::Content owned; const char* unowned = nullptr; }; ZeroTerminatedString zstr() const { return ZeroTerminatedString{begin(), end()}; } private: + static constexpr ByteCount strlen(const char* s) + { + return *s == 0 ? 0 : strlen(s+1) + 1; + } + const char* m_data; ByteCount m_length; }; -inline bool operator==(StringView lhs, StringView rhs) -{ - return lhs.m_length == rhs.m_length and - std::equal(lhs.begin(), lhs.end(), rhs.begin()); -} - -inline bool operator!=(StringView lhs, StringView rhs) -{ - return not (lhs == rhs); -} - -bool operator<(StringView lhs, StringView rhs); - -inline ByteCount StringView::byte_count_to(CharCount count) const -{ - return utf8::advance(begin(), end(), (int)count) - begin(); -} - -inline CharCount StringView::char_count_to(ByteCount count) const -{ - return utf8::distance(begin(), begin() + (int)count); -} - -inline StringView StringView::substr(ByteCount from, ByteCount length) const +template +inline StringView StringOps::substr(ByteCount from, ByteCount length) const { if (length < 0) length = INT_MAX; - return StringView{ m_data + (int)from, std::min(m_length - from, length) }; + return StringView{ type().data() + (int)from, std::min(type().length() - from, length) }; } -inline StringView StringView::substr(CharCount from, CharCount length) const +template +inline StringView StringOps::substr(CharCount from, CharCount length) const { if (length < 0) length = INT_MAX; @@ -176,70 +204,21 @@ inline StringView StringView::substr(CharCount from, CharCount length) const return StringView{ beg, utf8::advance(beg, end(), length) }; } -inline StringView String::substr(ByteCount pos, ByteCount length) const -{ - return StringView{*this}.substr(pos, length); -} - -inline StringView String::substr(CharCount pos, CharCount length) const -{ - return StringView{*this}.substr(pos, length); -} - inline String& operator+=(String& lhs, StringView rhs) { - lhs.append(rhs.data(), (size_t)(int)rhs.length()); + lhs.append(rhs.data(), rhs.length()); return lhs; } -inline String operator+(const String& lhs, const String& rhs) -{ - String res = lhs; - res += rhs; - return res; -} - inline String operator+(StringView lhs, StringView rhs) { - String res{lhs.begin(), lhs.end()}; + String res; + res.reserve((int)(lhs.length() + rhs.length())); + res += lhs; res += rhs; return res; } -inline String operator+(const String& lhs, StringView rhs) -{ - String res = lhs; - res += rhs; - return res; -} - -inline String operator+(StringView lhs, const String& rhs) -{ - String res{lhs.begin(), lhs.end()}; - res.append(rhs); - return res; -} - -inline String operator+(const char* lhs, StringView rhs) -{ - return StringView{lhs} + rhs; -} - -inline String operator+(StringView lhs, const char* rhs) -{ - return lhs + StringView{rhs}; -} - -inline String operator+(const char* lhs, const String& rhs) -{ - return StringView{lhs} + rhs; -} - -inline String operator+(const String& lhs, const char* rhs) -{ - return lhs + StringView{rhs}; -} - Vector split(StringView str, char separator, char escape); Vector split(StringView str, char separator); @@ -266,16 +245,11 @@ inline String operator"" _str(const char* str, size_t) return String(str); } -inline StringView operator"" _sv(const char* str, size_t len) -{ - return StringView(str, (int)len); -} - inline String codepoint_to_str(Codepoint cp) { - StringBase str; - utf8::dump(back_inserter(str), cp); - return String(str); + String str; + utf8::dump(std::back_inserter(str), cp); + return str; } int str_to_int(StringView str); @@ -301,16 +275,6 @@ String expand_tabs(StringView line, CharCount tabstop, CharCount col = 0); Vector wrap_lines(StringView text, CharCount max_width); -inline size_t hash_value(const Kakoune::String& str) -{ - return hash_data(str.data(), (int)str.length()); -} - -inline size_t hash_value(const Kakoune::StringView& str) -{ - return hash_data(str.data(), (int)str.length()); -} - } #endif // string_hh_INCLUDED