Explorar o código

LibLine: Remove duplicate members in `CompletionSuggestion`

Previously, we stored two representations of the same string in
`CompletionSuggestion` object: one for the bytes and the other for the
code points corresponding to those bytes. To minimize duplication, this
patch combine both representations into a single UTF-8 string, which is
already supported by our new String class.

Following this update, we successfully reduce the size of each object
from 376 bytes to 256 bytes
hanaa12G hai 1 ano
pai
achega
19f137c1e6

+ 1 - 1
Userland/Libraries/LibCodeComprehension/Shell/ShellComprehensionEngine.cpp

@@ -150,7 +150,7 @@ Vector<CodeComprehension::AutocompleteResultEntry> ShellComprehensionEngine::get
     auto completions = const_cast<::Shell::AST::Node*>(document.node.ptr())->complete_for_editor(shell(), offset_in_file, hit_test).release_value_but_fixme_should_propagate_errors();
     auto completions = const_cast<::Shell::AST::Node*>(document.node.ptr())->complete_for_editor(shell(), offset_in_file, hit_test).release_value_but_fixme_should_propagate_errors();
     Vector<CodeComprehension::AutocompleteResultEntry> entries;
     Vector<CodeComprehension::AutocompleteResultEntry> entries;
     for (auto& completion : completions)
     for (auto& completion : completions)
-        entries.append({ completion.text_string, completion.input_offset });
+        entries.append({ completion.text_string(), completion.input_offset });
 
 
     return entries;
     return entries;
 }
 }

+ 1 - 1
Userland/Libraries/LibLine/Editor.cpp

@@ -1176,7 +1176,7 @@ ErrorOr<void> Editor::handle_read_event()
             m_chars_touched_in_the_middle++;
             m_chars_touched_in_the_middle++;
 
 
             for (auto& view : completion_result.insert)
             for (auto& view : completion_result.insert)
-                insert(view);
+                insert(view.as_string());
 
 
             auto stderr_stream = TRY(Core::File::standard_error());
             auto stderr_stream = TRY(Core::File::standard_error());
             TRY(reposition_cursor(*stderr_stream));
             TRY(reposition_cursor(*stderr_stream));

+ 27 - 38
Userland/Libraries/LibLine/SuggestionManager.cpp

@@ -4,61 +4,50 @@
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
+#include <AK/Assertions.h>
 #include <AK/Function.h>
 #include <AK/Function.h>
 #include <LibLine/SuggestionManager.h>
 #include <LibLine/SuggestionManager.h>
 
 
 namespace Line {
 namespace Line {
 
 
 CompletionSuggestion::CompletionSuggestion(StringView completion, StringView trailing_trivia, StringView display_trivia, Style style)
 CompletionSuggestion::CompletionSuggestion(StringView completion, StringView trailing_trivia, StringView display_trivia, Style style)
-    : style(style)
-    , text_string(completion)
-    , display_trivia_string(display_trivia)
+    : text(MUST(String::from_utf8(completion)))
+    , trailing_trivia(MUST(String::from_utf8(trailing_trivia)))
+    , display_trivia(MUST(String::from_utf8(display_trivia)))
+    , style(style)
     , is_valid(true)
     , is_valid(true)
 {
 {
-    Utf8View text_u8 { completion };
-    Utf8View trivia_u8 { trailing_trivia };
-    Utf8View display_u8 { display_trivia };
-
-    for (auto cp : text_u8)
-        text.append(cp);
-
-    for (auto cp : trivia_u8)
-        this->trailing_trivia.append(cp);
-
-    for (auto cp : display_u8)
-        this->display_trivia.append(cp);
-
-    text_view = Utf32View { text.data(), text.size() };
-    trivia_view = Utf32View { this->trailing_trivia.data(), this->trailing_trivia.size() };
-    display_trivia_view = Utf32View { this->display_trivia.data(), this->display_trivia.size() };
 }
 }
 
 
 void SuggestionManager::set_suggestions(Vector<CompletionSuggestion>&& suggestions)
 void SuggestionManager::set_suggestions(Vector<CompletionSuggestion>&& suggestions)
 {
 {
-    m_suggestions = move(suggestions);
+    auto code_point_at = [](Utf8View view, size_t index) {
+        size_t count = 0;
+        for (auto cp : view) {
+            if (count == index) {
+                return cp;
+            }
+            count++;
+        }
+        VERIFY_NOT_REACHED();
+    };
 
 
-    // Set the views and make sure we were not given invalid suggestions
-    for (auto& suggestion : m_suggestions) {
-        VERIFY(suggestion.is_valid);
-        suggestion.text_view = { suggestion.text.data(), suggestion.text.size() };
-        suggestion.trivia_view = { suggestion.trailing_trivia.data(), suggestion.trailing_trivia.size() };
-        suggestion.display_trivia_view = { suggestion.display_trivia.data(), suggestion.display_trivia.size() };
-    }
+    m_suggestions = move(suggestions);
 
 
     size_t common_suggestion_prefix { 0 };
     size_t common_suggestion_prefix { 0 };
     if (m_suggestions.size() == 1) {
     if (m_suggestions.size() == 1) {
-        m_largest_common_suggestion_prefix_length = m_suggestions[0].text_view.length();
+        m_largest_common_suggestion_prefix_length = m_suggestions[0].text_view().length();
     } else if (m_suggestions.size()) {
     } else if (m_suggestions.size()) {
         u32 last_valid_suggestion_code_point;
         u32 last_valid_suggestion_code_point;
 
 
         for (;; ++common_suggestion_prefix) {
         for (;; ++common_suggestion_prefix) {
-            if (m_suggestions[0].text_view.length() <= common_suggestion_prefix)
+            if (m_suggestions[0].text_view().length() <= common_suggestion_prefix)
                 goto no_more_commons;
                 goto no_more_commons;
 
 
-            last_valid_suggestion_code_point = m_suggestions[0].text_view.code_points()[common_suggestion_prefix];
+            last_valid_suggestion_code_point = code_point_at(m_suggestions[0].text_view(), common_suggestion_prefix);
 
 
             for (auto& suggestion : m_suggestions) {
             for (auto& suggestion : m_suggestions) {
-                if (suggestion.text_view.length() <= common_suggestion_prefix || suggestion.text_view.code_points()[common_suggestion_prefix] != last_valid_suggestion_code_point) {
+                if (suggestion.text_view().length() <= common_suggestion_prefix || code_point_at(suggestion.text_view(), common_suggestion_prefix) != last_valid_suggestion_code_point) {
                     goto no_more_commons;
                     goto no_more_commons;
                 }
                 }
             }
             }
@@ -101,7 +90,7 @@ void SuggestionManager::set_current_suggestion_initiation_index(size_t index)
     else
     else
         m_last_shown_suggestion.start_index = index - suggestion.static_offset - suggestion.invariant_offset;
         m_last_shown_suggestion.start_index = index - suggestion.static_offset - suggestion.invariant_offset;
 
 
-    m_last_shown_suggestion_display_length = m_last_shown_suggestion.text_view.length();
+    m_last_shown_suggestion_display_length = m_last_shown_suggestion.text_view().length();
     m_last_shown_suggestion_was_complete = true;
     m_last_shown_suggestion_was_complete = true;
 }
 }
 
 
@@ -131,7 +120,7 @@ SuggestionManager::CompletionAttemptResult SuggestionManager::attempt_completion
         case ShowSuggestions:
         case ShowSuggestions:
             actual_offset = 0 - m_largest_common_suggestion_prefix_length + next_suggestion.invariant_offset;
             actual_offset = 0 - m_largest_common_suggestion_prefix_length + next_suggestion.invariant_offset;
             if (can_complete && next_suggestion.allow_commit_without_listing)
             if (can_complete && next_suggestion.allow_commit_without_listing)
-                shown_length = m_largest_common_suggestion_prefix_length + m_last_shown_suggestion.trivia_view.length();
+                shown_length = m_largest_common_suggestion_prefix_length + m_last_shown_suggestion.trivia_view().length();
             break;
             break;
         default:
         default:
             if (m_last_shown_suggestion_display_length == 0)
             if (m_last_shown_suggestion_display_length == 0)
@@ -151,14 +140,14 @@ SuggestionManager::CompletionAttemptResult SuggestionManager::attempt_completion
         if (mode == CompletePrefix) {
         if (mode == CompletePrefix) {
             // Only auto-complete *if possible*.
             // Only auto-complete *if possible*.
             if (can_complete) {
             if (can_complete) {
-                result.insert.append(suggestion.text_view.substring_view(suggestion.invariant_offset, m_largest_common_suggestion_prefix_length - suggestion.invariant_offset));
+                result.insert.append(suggestion.text_view().substring_view(suggestion.invariant_offset, m_largest_common_suggestion_prefix_length - suggestion.invariant_offset));
                 m_last_shown_suggestion_display_length = m_largest_common_suggestion_prefix_length;
                 m_last_shown_suggestion_display_length = m_largest_common_suggestion_prefix_length;
                 // Do not increment the suggestion index, as the first tab should only be a *peek*.
                 // Do not increment the suggestion index, as the first tab should only be a *peek*.
                 if (m_suggestions.size() == 1) {
                 if (m_suggestions.size() == 1) {
                     // If there's one suggestion, commit and forget.
                     // If there's one suggestion, commit and forget.
                     result.new_completion_mode = DontComplete;
                     result.new_completion_mode = DontComplete;
                     // Add in the trivia of the last selected suggestion.
                     // Add in the trivia of the last selected suggestion.
-                    result.insert.append(suggestion.trivia_view);
+                    result.insert.append(suggestion.trivia_view());
                     m_last_shown_suggestion_display_length = 0;
                     m_last_shown_suggestion_display_length = 0;
                     result.style_to_apply = suggestion.style;
                     result.style_to_apply = suggestion.style;
                     m_last_shown_suggestion_was_complete = true;
                     m_last_shown_suggestion_was_complete = true;
@@ -171,10 +160,10 @@ SuggestionManager::CompletionAttemptResult SuggestionManager::attempt_completion
             m_last_shown_suggestion_was_complete = false;
             m_last_shown_suggestion_was_complete = false;
             m_last_shown_suggestion = DeprecatedString::empty();
             m_last_shown_suggestion = DeprecatedString::empty();
         } else {
         } else {
-            result.insert.append(suggestion.text_view.substring_view(suggestion.invariant_offset, suggestion.text_view.length() - suggestion.invariant_offset));
+            result.insert.append(suggestion.text_view().substring_view(suggestion.invariant_offset, suggestion.text_view().length() - suggestion.invariant_offset));
             // Add in the trivia of the last selected suggestion.
             // Add in the trivia of the last selected suggestion.
-            result.insert.append(suggestion.trivia_view);
-            m_last_shown_suggestion_display_length += suggestion.trivia_view.length();
+            result.insert.append(suggestion.trivia_view());
+            m_last_shown_suggestion_display_length += suggestion.trivia_view().length();
         }
         }
     } else {
     } else {
         m_next_suggestion_index = 0;
         m_next_suggestion_index = 0;

+ 13 - 14
Userland/Libraries/LibLine/SuggestionManager.h

@@ -8,14 +8,13 @@
 
 
 #include <AK/DeprecatedString.h>
 #include <AK/DeprecatedString.h>
 #include <AK/Forward.h>
 #include <AK/Forward.h>
+#include <AK/String.h>
 #include <AK/Utf32View.h>
 #include <AK/Utf32View.h>
 #include <AK/Utf8View.h>
 #include <AK/Utf8View.h>
 #include <LibLine/Style.h>
 #include <LibLine/Style.h>
 
 
 namespace Line {
 namespace Line {
 
 
-// FIXME: These objects are pretty heavy since they store two copies of text
-//        somehow get rid of one.
 struct CompletionSuggestion {
 struct CompletionSuggestion {
 private:
 private:
     struct ForSearchTag {
     struct ForSearchTag {
@@ -30,8 +29,8 @@ public:
     {
     {
     }
     }
 
 
-    CompletionSuggestion(DeprecatedString const& completion, ForSearchTag)
-        : text_string(completion)
+    CompletionSuggestion(StringView completion, ForSearchTag)
+        : text(MUST(String::from_utf8(completion)))
     {
     {
     }
     }
 
 
@@ -44,12 +43,12 @@ public:
 
 
     bool operator==(CompletionSuggestion const& suggestion) const
     bool operator==(CompletionSuggestion const& suggestion) const
     {
     {
-        return suggestion.text_string == text_string;
+        return suggestion.text == text;
     }
     }
 
 
-    Vector<u32> text;
-    Vector<u32> trailing_trivia;
-    Vector<u32> display_trivia;
+    String text;
+    String trailing_trivia;
+    String display_trivia;
     Style style;
     Style style;
     size_t start_index { 0 };
     size_t start_index { 0 };
     size_t input_offset { 0 };
     size_t input_offset { 0 };
@@ -57,11 +56,11 @@ public:
     size_t invariant_offset { 0 };
     size_t invariant_offset { 0 };
     bool allow_commit_without_listing { true };
     bool allow_commit_without_listing { true };
 
 
-    Utf32View text_view;
-    Utf32View trivia_view;
-    Utf32View display_trivia_view;
-    DeprecatedString text_string;
-    DeprecatedString display_trivia_string;
+    Utf8View text_view() const { return text.code_points(); }
+    Utf8View trivia_view() const { return trailing_trivia.code_points(); }
+    Utf8View display_trivia_view() const { return display_trivia.code_points(); }
+    StringView text_string() const { return text.bytes_as_string_view(); }
+    StringView display_trivia_string() const { return display_trivia.bytes_as_string_view(); }
     bool is_valid { false };
     bool is_valid { false };
 };
 };
 
 
@@ -101,7 +100,7 @@ public:
         // This bit of data will be removed, but restored if the suggestion is rejected.
         // This bit of data will be removed, but restored if the suggestion is rejected.
         size_t static_offset_from_cursor { 0 };
         size_t static_offset_from_cursor { 0 };
 
 
-        Vector<Utf32View> insert {};
+        Vector<Utf8View> insert {};
 
 
         Optional<Style> style_to_apply {};
         Optional<Style> style_to_apply {};
 
 

+ 10 - 10
Userland/Libraries/LibLine/XtermSuggestionDisplay.cpp

@@ -26,9 +26,9 @@ ErrorOr<void> XtermSuggestionDisplay::display(SuggestionManager const& manager)
 
 
     manager.set_start_index(0);
     manager.set_start_index(0);
     TRY(manager.for_each_suggestion([&](auto& suggestion, auto) {
     TRY(manager.for_each_suggestion([&](auto& suggestion, auto) {
-        longest_suggestion_length = max(longest_suggestion_length, suggestion.text_view.length() + suggestion.display_trivia_view.length());
-        longest_suggestion_byte_length = max(longest_suggestion_byte_length, suggestion.text_string.length() + suggestion.display_trivia_string.length());
-        longest_suggestion_byte_length_without_trivia = max(longest_suggestion_byte_length_without_trivia, suggestion.text_string.length());
+        longest_suggestion_length = max(longest_suggestion_length, suggestion.text_view().length() + suggestion.display_trivia_view().length());
+        longest_suggestion_byte_length = max(longest_suggestion_byte_length, suggestion.text_string().length() + suggestion.display_trivia_string().length());
+        longest_suggestion_byte_length_without_trivia = max(longest_suggestion_byte_length_without_trivia, suggestion.text_string().length());
         return IterationDecision::Continue;
         return IterationDecision::Continue;
     }));
     }));
 
 
@@ -65,9 +65,9 @@ ErrorOr<void> XtermSuggestionDisplay::display(SuggestionManager const& manager)
         manager.set_start_index(0);
         manager.set_start_index(0);
         size_t page_start = 0;
         size_t page_start = 0;
         TRY(manager.for_each_suggestion([&](auto& suggestion, auto index) {
         TRY(manager.for_each_suggestion([&](auto& suggestion, auto index) {
-            size_t next_column = num_printed + suggestion.text_view.length() + longest_suggestion_length + 2;
+            size_t next_column = num_printed + suggestion.text_view().length() + longest_suggestion_length + 2;
             if (next_column > m_num_columns) {
             if (next_column > m_num_columns) {
-                auto lines = (suggestion.text_view.length() + m_num_columns - 1) / m_num_columns;
+                auto lines = (suggestion.text_view().length() + m_num_columns - 1) / m_num_columns;
                 lines_used += lines;
                 lines_used += lines;
                 num_printed = 0;
                 num_printed = 0;
             }
             }
@@ -94,10 +94,10 @@ ErrorOr<void> XtermSuggestionDisplay::display(SuggestionManager const& manager)
 
 
     manager.set_start_index(m_pages[page_index].start);
     manager.set_start_index(m_pages[page_index].start);
     TRY(manager.for_each_suggestion([&](auto& suggestion, auto index) -> ErrorOr<IterationDecision> {
     TRY(manager.for_each_suggestion([&](auto& suggestion, auto index) -> ErrorOr<IterationDecision> {
-        size_t next_column = num_printed + suggestion.text_view.length() + longest_suggestion_length + 2;
+        size_t next_column = num_printed + suggestion.text_view().length() + longest_suggestion_length + 2;
 
 
         if (next_column > m_num_columns) {
         if (next_column > m_num_columns) {
-            auto lines = (suggestion.text_view.length() + m_num_columns - 1) / m_num_columns;
+            auto lines = (suggestion.text_view().length() + m_num_columns - 1) / m_num_columns;
             lines_used += lines;
             lines_used += lines;
             TRY(stderr_stream->write_until_depleted("\n"sv.bytes()));
             TRY(stderr_stream->write_until_depleted("\n"sv.bytes()));
             num_printed = 0;
             num_printed = 0;
@@ -115,10 +115,10 @@ ErrorOr<void> XtermSuggestionDisplay::display(SuggestionManager const& manager)
 
 
         if (spans_entire_line) {
         if (spans_entire_line) {
             num_printed += m_num_columns;
             num_printed += m_num_columns;
-            TRY(stderr_stream->write_until_depleted(suggestion.text_string.bytes()));
-            TRY(stderr_stream->write_until_depleted(suggestion.display_trivia_string.bytes()));
+            TRY(stderr_stream->write_until_depleted(suggestion.text_string().bytes()));
+            TRY(stderr_stream->write_until_depleted(suggestion.display_trivia_string().bytes()));
         } else {
         } else {
-            auto field = DeprecatedString::formatted("{: <{}}  {}", suggestion.text_string, longest_suggestion_byte_length_without_trivia, suggestion.display_trivia_string);
+            auto field = DeprecatedString::formatted("{: <{}}  {}", suggestion.text_string(), longest_suggestion_byte_length_without_trivia, suggestion.display_trivia_string());
             TRY(stderr_stream->write_until_depleted(DeprecatedString::formatted("{: <{}}", field, longest_suggestion_byte_length + 2).bytes()));
             TRY(stderr_stream->write_until_depleted(DeprecatedString::formatted("{: <{}}", field, longest_suggestion_byte_length + 2).bytes()));
             num_printed += longest_suggestion_length + 2;
             num_printed += longest_suggestion_length + 2;
         }
         }

+ 1 - 1
Userland/Shell/AST.cpp

@@ -349,7 +349,7 @@ ErrorOr<Vector<Line::CompletionSuggestion>> Node::complete_for_editor(Shell& she
         auto set_results_trivia = [enclosure_type](Vector<Line::CompletionSuggestion>&& suggestions) {
         auto set_results_trivia = [enclosure_type](Vector<Line::CompletionSuggestion>&& suggestions) {
             if (enclosure_type != StringLiteral::EnclosureType::None) {
             if (enclosure_type != StringLiteral::EnclosureType::None) {
                 for (auto& entry : suggestions)
                 for (auto& entry : suggestions)
-                    entry.trailing_trivia = { static_cast<u32>(enclosure_type == StringLiteral::EnclosureType::SingleQuotes ? '\'' : '"') };
+                    entry.trailing_trivia = String::from_code_point(static_cast<u32>(enclosure_type == StringLiteral::EnclosureType::SingleQuotes ? '\'' : '"'));
             }
             }
             return suggestions;
             return suggestions;
         };
         };

+ 1 - 1
Userland/Shell/Shell.cpp

@@ -1657,7 +1657,7 @@ Vector<Line::CompletionSuggestion> Shell::complete_path(StringView base, StringV
 
 
     // The results of DirIterator are in the order they appear on-disk.
     // The results of DirIterator are in the order they appear on-disk.
     // Instead, return suggestions in lexicographical order.
     // Instead, return suggestions in lexicographical order.
-    quick_sort(suggestions, [](auto& a, auto& b) { return a.text_string < b.text_string; });
+    quick_sort(suggestions, [](auto& a, auto& b) { return a.text_string() < b.text_string(); });
 
 
     return suggestions;
     return suggestions;
 }
 }