Skip to content

Commit

Permalink
refactor(lsp): prefer Vector over std::vector
Browse files Browse the repository at this point in the history
Reduce our use of std::vector to reduce binary bloat:
#689
  • Loading branch information
strager committed Nov 6, 2023
1 parent 7ee7681 commit 99feaff
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 35 deletions.
13 changes: 13 additions & 0 deletions src/quick-lint-js/container/vector-profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,14 @@ class Instrumented_Vector {
return Span<const value_type>(this->data_);
}

void swap(Instrumented_Vector &other) {
this->data_.swap(other.data_);
std::swap(this->debug_owner_, other.debug_owner_);
// TODO(strager): Add instrumentation specific to swapping.
this->add_instrumentation_entry(Vector_Instrumentation::Event::resize);
other.add_instrumentation_entry(Vector_Instrumentation::Event::resize);
}

private:
QLJS_FORCE_INLINE void add_instrumentation_entry(
Vector_Instrumentation::Event event) {
Expand All @@ -370,6 +378,11 @@ class Instrumented_Vector {
Vector data_;
const char *debug_owner_;
};

template <class V>
void swap(Instrumented_Vector<V> &lhs, Instrumented_Vector<V> &rhs) {
lhs.swap(rhs);
}
#endif
}

Expand Down
25 changes: 25 additions & 0 deletions src/quick-lint-js/container/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,17 @@ class Uninstrumented_Vector : private Vector {
using Vector::release_to_span;
using Vector::release_to_string_view;
using Vector::to_string_view;

void swap(Uninstrumented_Vector &other) {
static_cast<Vector &>(*this).swap(static_cast<Vector &>(other));
}
};

template <class V>
void swap(Uninstrumented_Vector<V> &lhs, Uninstrumented_Vector<V> &rhs) {
lhs.swap(rhs);
}

using Vector_Size = std::ptrdiff_t;

// Like std::pmr::vector. Some differences:
Expand Down Expand Up @@ -344,6 +353,17 @@ class Raw_Vector {

void erase(value_type *item) { erase(item, item + 1); }

// Swap capacity pointers and sizes between *this and other. All items of
// *this and other are untouched.
//
// Precondition: this->get_allocator() == other.get_allocator()
void swap(Raw_Vector &other) {
QLJS_ALWAYS_ASSERT(this->get_allocator() == other.get_allocator());
std::swap(this->data_, other.data_);
std::swap(this->data_end_, other.data_end_);
std::swap(this->capacity_end_, other.capacity_end_);
}

// If new_size > this->size(): default-construct new items at the end.
// If new_size < this->size(): destruct items at the end.
//
Expand Down Expand Up @@ -415,6 +435,11 @@ class Raw_Vector {
Memory_Resource *allocator_;
};

template <class T>
void swap(Raw_Vector<T> &lhs, Raw_Vector<T> &rhs) {
lhs.swap(rhs);
}

#if QLJS_FEATURE_VECTOR_PROFILING
template <class T>
using Vector = Instrumented_Vector<Raw_Vector<T>>;
Expand Down
46 changes: 19 additions & 27 deletions src/quick-lint-js/lsp/lsp-location.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ namespace {
template <class Input_It, class Output, class Transformer>
void insert_back_transform(Input_It input_begin, Input_It input_end,
Output &output, Transformer &&transformer) {
using Difference_Type = typename Output::difference_type;
std::size_t original_size = output.size();
std::size_t final_size =
original_size + narrow_cast<std::size_t>(input_end - input_begin);
Vector_Size original_size = output.size();
Vector_Size final_size = original_size + input_end - input_begin;
output.resize(final_size);
auto output_it = output.begin() + narrow_cast<Difference_Type>(original_size);
auto output_it = output.begin() + original_size;
output_it = std::transform(input_begin, input_end, output_it, transformer);
QLJS_ASSERT(output_it == output.end());
}
Expand Down Expand Up @@ -66,9 +64,8 @@ const Char8 *LSP_Locator::from_position(LSP_Position position) const {
return this->input_.null_terminator();
}

Offset_Type line_begin_offset =
this->offset_of_lines_[narrow_cast<std::size_t>(line)];
bool line_is_ascii = this->line_is_ascii_[narrow_cast<std::size_t>(line)];
Offset_Type line_begin_offset = this->offset_of_lines_[line];
bool line_is_ascii = this->line_is_ascii_[line];
bool is_last_line = line == number_of_lines - 1;
if (is_last_line) {
// TODO(strager): Get rid of this narrow_cast.
Expand All @@ -86,8 +83,7 @@ const Char8 *LSP_Locator::from_position(LSP_Position position) const {
return advance_lsp_characters_in_utf_8(line_string, character);
}
} else {
Offset_Type line_end_offset =
this->offset_of_lines_[narrow_cast<std::size_t>(line + 1)];
Offset_Type line_end_offset = this->offset_of_lines_[line + 1];
Offset_Type line_length_including_terminator =
line_end_offset - line_begin_offset;
if (line_is_ascii) {
Expand Down Expand Up @@ -139,24 +135,24 @@ void LSP_Locator::replace_text(LSP_Range range, String8_View replacement_text,
narrow_cast<Offset_Type>(replacement_text.size());

QLJS_ASSERT(!this->offset_of_lines_.empty());
std::size_t start_line = narrow_cast<std::size_t>(range.start.line);
std::size_t end_line = std::min(this->offset_of_lines_.size() - 1,
narrow_cast<std::size_t>(range.end.line));
Vector_Size start_line = narrow_cast<Vector_Size>(range.start.line);
Vector_Size end_line = std::min(this->offset_of_lines_.size() - 1,
narrow_cast<Vector_Size>(range.end.line));

this->input_ = new_input;
std::swap(this->old_offset_of_lines_, this->offset_of_lines_);
std::swap(this->old_line_is_ascii_, this->line_is_ascii_);
swap(this->old_offset_of_lines_, this->offset_of_lines_);
swap(this->old_line_is_ascii_, this->line_is_ascii_);
this->offset_of_lines_.reserve(this->old_offset_of_lines_.size());
this->offset_of_lines_.clear();
this->line_is_ascii_.reserve(this->old_line_is_ascii_.size());
this->line_is_ascii_.clear();

// Offsets before replacement: do not adjust.
this->offset_of_lines_.insert(
this->offset_of_lines_.end(), this->old_offset_of_lines_.begin(),
this->offset_of_lines_.append(
this->old_offset_of_lines_.begin(),
this->old_offset_of_lines_.begin() + range.start.line + 1);
this->line_is_ascii_.insert(
this->line_is_ascii_.end(), this->old_line_is_ascii_.begin(),
this->line_is_ascii_.append(
this->old_line_is_ascii_.begin(),
this->old_line_is_ascii_.begin() + range.start.line);

// Offsets within replacement: re-parse newlines.
Expand All @@ -183,8 +179,7 @@ void LSP_Locator::replace_text(LSP_Range range, String8_View replacement_text,
[&](Offset_Type offset) -> Offset_Type {
return offset + net_bytes_added;
});
this->line_is_ascii_.insert(this->line_is_ascii_.end(),
this->old_line_is_ascii_.begin() +
this->line_is_ascii_.append(this->old_line_is_ascii_.begin() +
narrow_cast<std::ptrdiff_t>(end_line) + 1,
this->old_line_is_ascii_.end());

Expand Down Expand Up @@ -216,8 +211,7 @@ void LSP_Locator::cache_offsets_of_lines() {
QLJS_ASSERT(this->line_is_ascii_.empty());

constexpr int estimated_bytes_per_line = 64;
std::size_t estimated_lines =
narrow_cast<std::size_t>(this->input_.size() / estimated_bytes_per_line);
Vector_Size estimated_lines = this->input_.size() / estimated_bytes_per_line;
this->offset_of_lines_.reserve(estimated_lines);
this->line_is_ascii_.reserve(estimated_lines);

Expand Down Expand Up @@ -275,10 +269,8 @@ LSP_Locator::Offset_Type LSP_Locator::offset(const Char8 *source) const {
}

LSP_Position LSP_Locator::position(int line_number, Offset_Type offset) const {
Offset_Type beginning_of_line_offset =
this->offset_of_lines_[narrow_cast<std::size_t>(line_number)];
bool line_is_ascii =
this->line_is_ascii_[narrow_cast<std::size_t>(line_number)];
Offset_Type beginning_of_line_offset = this->offset_of_lines_[line_number];
bool line_is_ascii = this->line_is_ascii_[line_number];

int character;
if (line_is_ascii) {
Expand Down
13 changes: 9 additions & 4 deletions src/quick-lint-js/lsp/lsp-location.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <cstddef>
#include <iosfwd>
#include <quick-lint-js/container/padded-string.h>
#include <quick-lint-js/container/vector.h>
#include <quick-lint-js/fe/source-code-span.h>
#include <quick-lint-js/port/char8.h>
#include <vector>
Expand Down Expand Up @@ -58,13 +59,17 @@ class LSP_Locator {
LSP_Position position(int line_number, Offset_Type offset) const;

Padded_String_View input_;
std::vector<Offset_Type> offset_of_lines_;
std::vector<unsigned char> line_is_ascii_;
Vector<Offset_Type> offset_of_lines_{"LSP_Locator::offset_of_lines_",
new_delete_resource()};
Vector<unsigned char> line_is_ascii_{"LSP_Locator::line_is_ascii_",
new_delete_resource()};

// old_offset_of_lines_ and old_line_is_ascii_ are used for double buffering
// of offset_of_lines_ and line_is_ascii_. This reduces allocations.
std::vector<Offset_Type> old_offset_of_lines_;
std::vector<unsigned char> old_line_is_ascii_;
Vector<Offset_Type> old_offset_of_lines_{"LSP_Locator::old_offset_of_lines_",
new_delete_resource()};
Vector<unsigned char> old_line_is_ascii_{"LSP_Locator::old_line_is_ascii_",
new_delete_resource()};
};
}

Expand Down
7 changes: 4 additions & 3 deletions src/quick-lint-js/lsp/lsp-message-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <cstddef>
#include <optional>
#include <quick-lint-js/container/string-view.h>
#include <quick-lint-js/container/vector.h>
#include <quick-lint-js/port/char8.h>
#include <quick-lint-js/util/cast.h>
#include <quick-lint-js/util/integer.h>
Expand Down Expand Up @@ -37,7 +38,8 @@ class LSP_Message_Parser_Base {
static bool header_is(String8_View header_name,
String8_View expected_header_name);

std::vector<Char8> buffer_;
Vector<Char8> buffer_{"LSP_Message_Parser_Base::buffer_",
new_delete_resource()};

// If !pending_message_content_length_.has_value(), buffer_ contains message
// headers (and possibly message content and other messages afterwards).
Expand All @@ -63,8 +65,7 @@ template <class Derived>
class LSP_Message_Parser : private LSP_Message_Parser_Base {
public:
void append(String8_View data) {
this->buffer_.insert(this->buffer_.end(), data.data(),
data.data() + data.size());
this->buffer_ += data;
this->parse();
}

Expand Down
4 changes: 3 additions & 1 deletion src/quick-lint-js/lsp/outgoing-json-rpc-message-queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#else

#include <quick-lint-js/container/byte-buffer.h>
#include <quick-lint-js/container/vector.h>
#include <vector>

namespace quick_lint_js {
Expand All @@ -30,7 +31,8 @@ class Outgoing_JSON_RPC_Message_Queue {
void send(LSP_Endpoint_Remote&);

private:
std::vector<Byte_Buffer> messages_;
Vector<Byte_Buffer> messages_{"Outgoing_JSON_RPC_Message_Queue::messages_",
new_delete_resource()};
};
}

Expand Down

0 comments on commit 99feaff

Please sign in to comment.