From 5596b4b2b9dbc56d106f1cd3d3b09ccdcd28ad88 Mon Sep 17 00:00:00 2001 From: geppettodivacin Date: Sat, 25 Jan 2020 20:02:22 -0600 Subject: [PATCH 1/3] Add support for `@` symbols in selection buffer The selection descriptions use the format `@@`. This fails when file paths have `@` symbols in them: the parser splits on `@` symbols and finds more values than it expects. We here modify the behavior to require *at least* two @ symbols, using the last two for `` and `` and leaving the remaining text for the . This should work for any number of `@` symbols, since `` and `` are numbers and should never contain `@` symbols. --- src/normal.cc | 21 ++++++++++++++++----- src/ranges.hh | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/normal.cc b/src/normal.cc index f9b1184f..2c00fb63 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -1,5 +1,7 @@ #include "normal.hh" +#include + #include "buffer.hh" #include "buffer_manager.hh" #include "buffer_utils.hh" @@ -1774,11 +1776,20 @@ SelectionList read_selections_from_register(char reg, Context& context) if (content.size() < 2) throw runtime_error(format("register '{}' does not contain a selections desc", reg)); - struct error : runtime_error { error(size_t) : runtime_error{"expected @@main_index"} {} }; - const auto desc = content[0] | split('@') | static_gather(); - Buffer& buffer = BufferManager::instance().get_buffer(desc[0]); - const size_t timestamp = str_to_int(desc[1]); - size_t main = str_to_int(desc[2]); + // Use the last two values for timestamp and main_index to allow the buffer + // name to have @ symbols + struct error : runtime_error { error() : runtime_error{"expected @@main_index"} {} }; + const auto desc = content[0] | split('@') | gather(); + const size_t desc_size = desc.size(); + if (desc_size < 3) + throw new error; + auto const buffer_name_view = desc | drop(2); + auto const buffer_name_temp = accumulate (buffer_name_view, ""_str, + [](auto str1, auto str2) { return str1 + "@"_str + str2; }); + auto const buffer_name = buffer_name_temp.substr (CharCount (1)); + Buffer& buffer = BufferManager::instance().get_buffer(buffer_name); + const size_t timestamp = str_to_int(desc[desc_size - 2]); + size_t main = str_to_int(desc[desc_size - 1]); return selection_list_from_strings(buffer, ColumnType::Byte, content | skip(1), timestamp, main); } diff --git a/src/ranges.hh b/src/ranges.hh index 4cd85a25..6518e00e 100644 --- a/src/ranges.hh +++ b/src/ranges.hh @@ -73,6 +73,24 @@ inline auto skip(size_t count) }); } +template +struct DropView +{ + auto begin() const { return std::begin(m_range); } + auto end() const { return std::end(m_range) - m_drop_count; } + + Range m_range; + size_t m_drop_count; +}; + +inline auto drop(size_t count) +{ + return make_view_factory([count](auto&& range) { + using Range = decltype(range); + return DropView>{std::forward(range), count}; + }); +} + template struct FilterView { From 39a2ab84fa4b537ed8a54d5a32a0ef158f59003e Mon Sep 17 00:00:00 2001 From: geppettodivacin Date: Sat, 1 Feb 2020 17:24:08 -0600 Subject: [PATCH 2/3] Use ReverseView to perform fewer allocations The first attempt at a bug fix for @ symbols in selection buffer names worked, but it was very inefficient. In particular, it allocated three different vectors, and we really only needed the correct elements. Manipulating iterators to give us the right slices of the existing vector is far more efficient. By reversing the original content and taking the last two, we're able to get the number of selections and main selection without too much hassle. The buffer name is everything from the start of the content to the selection count. This gets us through with only one vector allocation. Credit to @mawww for the optimization idea and for fixing my types. --- src/normal.cc | 19 ++++++++----------- src/ranges.hh | 14 ++++++++++---- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/normal.cc b/src/normal.cc index 2c00fb63..89659c4a 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -1778,18 +1778,15 @@ SelectionList read_selections_from_register(char reg, Context& context) // Use the last two values for timestamp and main_index to allow the buffer // name to have @ symbols - struct error : runtime_error { error() : runtime_error{"expected @@main_index"} {} }; - const auto desc = content[0] | split('@') | gather(); - const size_t desc_size = desc.size(); - if (desc_size < 3) - throw new error; - auto const buffer_name_view = desc | drop(2); - auto const buffer_name_temp = accumulate (buffer_name_view, ""_str, - [](auto str1, auto str2) { return str1 + "@"_str + str2; }); - auto const buffer_name = buffer_name_temp.substr (CharCount (1)); + struct error : runtime_error { error(size_t) : runtime_error{"expected @@main_index"} {} }; + auto end_content = content[0] | reverse() | split('@') | transform([] (auto bounds) { + return StringView{bounds.second.base(), bounds.first.base()}; + }) | static_gather(); + + const size_t main = str_to_int(end_content[0]); + const size_t timestamp = str_to_int(end_content[1]); + const auto buffer_name = StringView{ content[0].begin (), end_content[1].begin () - 1 }; Buffer& buffer = BufferManager::instance().get_buffer(buffer_name); - const size_t timestamp = str_to_int(desc[desc_size - 2]); - size_t main = str_to_int(desc[desc_size - 1]); return selection_list_from_strings(buffer, ColumnType::Byte, content | skip(1), timestamp, main); } diff --git a/src/ranges.hh b/src/ranges.hh index 6518e00e..02757283 100644 --- a/src/ranges.hh +++ b/src/ranges.hh @@ -37,6 +37,12 @@ struct ReverseView { decltype(auto) begin() { return m_range.rbegin(); } decltype(auto) end() { return m_range.rend(); } + decltype(auto) rbegin() { return m_range.begin(); } + decltype(auto) rend() { return m_range.end(); } + decltype(auto) begin() const { return m_range.rbegin(); } + decltype(auto) end() const { return m_range.rend(); } + decltype(auto) rbegin() const { return m_range.begin(); } + decltype(auto) rend() const { return m_range.end(); } Range m_range; }; @@ -495,15 +501,15 @@ auto elements(bool exact_size = false) } template -auto static_gather_impl(std::index_sequence) +auto static_gather_impl(std::index_sequence, bool exact_size) { - return elements(true); + return elements(exact_size); } -template +template auto static_gather() { - return static_gather_impl(std::make_index_sequence()); + return static_gather_impl(std::make_index_sequence(), exact_size); } }