From d464a071dabdfafdd7bfc5a70c3419dbe749b84e Mon Sep 17 00:00:00 2001
From: Herman Semenov <GermanAizek@yandex.ru>
Date: Wed, 31 May 2023 20:24:08 +0300
Subject: [PATCH] Optimize inserts in vector and refactor const reference
 objects (#659)

Signed-off-by: German Semenov <GermanAizek@yandex.ru>
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
---
 src/ftxui/component/container.cpp | 2 ++
 src/ftxui/component/input.cpp     | 3 ++-
 src/ftxui/component/menu.cpp      | 8 ++++++--
 src/ftxui/component/radiobox.cpp  | 1 +
 src/ftxui/dom/flexbox.cpp         | 1 +
 src/ftxui/dom/flexbox_helper.cpp  | 3 +++
 src/ftxui/dom/gridbox.cpp         | 2 ++
 src/ftxui/dom/linear_gradient.cpp | 2 +-
 src/ftxui/dom/table.cpp           | 2 ++
 src/ftxui/dom/util.cpp            | 1 +
 10 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/src/ftxui/component/container.cpp b/src/ftxui/component/container.cpp
index 3bd72c88..b2dc6029 100644
--- a/src/ftxui/component/container.cpp
+++ b/src/ftxui/component/container.cpp
@@ -98,6 +98,7 @@ class VerticalContainer : public ContainerBase {
 
   Element Render() override {
     Elements elements;
+    elements.reserve(children_.size());
     for (auto& it : children_) {
       elements.push_back(it->Render());
     }
@@ -180,6 +181,7 @@ class HorizontalContainer : public ContainerBase {
 
   Element Render() override {
     Elements elements;
+    elements.reserve(children_.size());
     for (auto& it : children_) {
       elements.push_back(it->Render());
     }
diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp
index 7275b122..a854614e 100644
--- a/src/ftxui/component/input.cpp
+++ b/src/ftxui/component/input.cpp
@@ -117,7 +117,7 @@ class InputBase : public ComponentBase {
     }
 
     Elements elements;
-    std::vector<std::string> lines = Split(*content_);
+    const std::vector<std::string> lines = Split(*content_);
 
     int& cursor_position = option_->cursor_position();
     cursor_position = util::clamp(cursor_position, 0, (int)content_->size());
@@ -138,6 +138,7 @@ class InputBase : public ComponentBase {
       elements.push_back(text("") | focused);
     }
 
+    elements.reserve(lines.size());
     for (size_t i = 0; i < lines.size(); ++i) {
       const std::string& line = lines[i];
 
diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp
index 03495bbc..1b693b42 100644
--- a/src/ftxui/component/menu.cpp
+++ b/src/ftxui/component/menu.cpp
@@ -27,7 +27,7 @@ namespace {
 
 Element DefaultOptionTransform(const EntryState& state) {
   std::string label = (state.active ? "> " : "  ") + state.label;  // NOLINT
-  Element e = text(label);
+  Element e = text(std::move(label));
   if (state.focused) {
     e = e | inverted;
   }
@@ -114,6 +114,7 @@ class MenuBase : public ComponentBase {
     if (option_->elements_prefix) {
       elements.push_back(option_->elements_prefix());
     }
+    elements.reserve(size());
     for (int i = 0; i < size(); ++i) {
       if (i != 0 && option_->elements_infix) {
         elements.push_back(option_->elements_infix());
@@ -362,7 +363,10 @@ class MenuBase : public ComponentBase {
       animator_background_.clear();
       animator_foreground_.clear();
 
-      for (int i = 0; i < size(); ++i) {
+      const int len = size();
+      animator_background_.reserve(len);
+      animator_foreground_.reserve(len);
+      for (int i = 0; i < len; ++i) {
         animation_background_[i] = 0.F;
         animation_foreground_[i] = 0.F;
         animator_background_.emplace_back(&animation_background_[i], 0.F,
diff --git a/src/ftxui/component/radiobox.cpp b/src/ftxui/component/radiobox.cpp
index 94f81572..10f4bf05 100644
--- a/src/ftxui/component/radiobox.cpp
+++ b/src/ftxui/component/radiobox.cpp
@@ -33,6 +33,7 @@ class RadioboxBase : public ComponentBase {
     Clamp();
     Elements elements;
     const bool is_menu_focused = Focused();
+    elements.reserve(size());
     for (int i = 0; i < size(); ++i) {
       const bool is_focused = (focused_entry() == i) && is_menu_focused;
       const bool is_selected = (hovered_ == i);
diff --git a/src/ftxui/dom/flexbox.cpp b/src/ftxui/dom/flexbox.cpp
index 9a276739..8c1ce2c6 100644
--- a/src/ftxui/dom/flexbox.cpp
+++ b/src/ftxui/dom/flexbox.cpp
@@ -68,6 +68,7 @@ class Flexbox : public Node {
 
   void Layout(flexbox_helper::Global& global,
               bool compute_requirement = false) {
+    global.blocks.reserve(children_.size());
     for (auto& child : children_) {
       flexbox_helper::Block block;
       block.min_size_x = child->requirement().min_x;
diff --git a/src/ftxui/dom/flexbox_helper.cpp b/src/ftxui/dom/flexbox_helper.cpp
index bb55726e..37cd2b7b 100644
--- a/src/ftxui/dom/flexbox_helper.cpp
+++ b/src/ftxui/dom/flexbox_helper.cpp
@@ -88,6 +88,7 @@ struct Line {
 void SetX(Global& global, std::vector<Line> lines) {
   for (auto& line : lines) {
     std::vector<box_helper::Element> elements;
+    elements.reserve(line.blocks.size());
     for (auto* block : line.blocks) {
       box_helper::Element element;
       element.min_size = block->min_size_x;
@@ -117,6 +118,7 @@ void SetX(Global& global, std::vector<Line> lines) {
 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
 void SetY(Global& g, std::vector<Line> lines) {
   std::vector<box_helper::Element> elements;
+  elements.reserve(lines.size());
   for (auto& line : lines) {
     box_helper::Element element;
     element.flex_shrink = line.blocks.front()->flex_shrink_y;
@@ -317,6 +319,7 @@ void Compute3(Global& global) {
   {
     Line line;
     int x = 0;
+    line.blocks.reserve(global.blocks.size());
     for (auto& block : global.blocks) {
       // Does it fit the end of the row?
       // No? Then we need to start a new one:
diff --git a/src/ftxui/dom/gridbox.cpp b/src/ftxui/dom/gridbox.cpp
index 7acbc636..46d21cb4 100644
--- a/src/ftxui/dom/gridbox.cpp
+++ b/src/ftxui/dom/gridbox.cpp
@@ -37,6 +37,8 @@ class GridBox : public Node {
     for (const auto& line : lines_) {
       x_size = std::max(x_size, int(line.size()));
     }
+
+    // Fill in empty cells, in case the user did not used the API correctly:
     for (auto& line : lines_) {
       while (line.size() < size_t(x_size)) {
         line.push_back(filler());
diff --git a/src/ftxui/dom/linear_gradient.cpp b/src/ftxui/dom/linear_gradient.cpp
index 45b27ce3..031228f4 100644
--- a/src/ftxui/dom/linear_gradient.cpp
+++ b/src/ftxui/dom/linear_gradient.cpp
@@ -78,7 +78,7 @@ LinearGradientNormalized Normalize(LinearGradient gradient) {
   LinearGradientNormalized normalized;
   // NOLINTNEXTLINE
   normalized.angle = std::fmod(std::fmod(gradient.angle, 360.f) + 360.f, 360.f);
-  for (auto& stop : gradient.stops) {
+  for (const auto& stop : gradient.stops) {
     normalized.colors.push_back(stop.color);
     normalized.positions.push_back(stop.position.value());  // NOLINT
   }
diff --git a/src/ftxui/dom/table.cpp b/src/ftxui/dom/table.cpp
index e6b77d2e..43974770 100644
--- a/src/ftxui/dom/table.cpp
+++ b/src/ftxui/dom/table.cpp
@@ -44,9 +44,11 @@ Table::Table() {
 
 Table::Table(std::vector<std::vector<std::string>> input) {
   std::vector<std::vector<Element>> output;
+  output.reserve(input.size());
   for (auto& row : input) {
     output.emplace_back();
     auto& output_row = output.back();
+    output_row.reserve(row.size());
     for (auto& cell : row) {
       output_row.push_back(text(std::move(cell)));
     }
diff --git a/src/ftxui/dom/util.cpp b/src/ftxui/dom/util.cpp
index 90c311a2..e5856311 100644
--- a/src/ftxui/dom/util.cpp
+++ b/src/ftxui/dom/util.cpp
@@ -46,6 +46,7 @@ Decorator operator|(Decorator a, Decorator b) {
 /// @ingroup dom
 Elements operator|(Elements elements, Decorator decorator) {  // NOLINT
   Elements output;
+  output.reserve(elements.size());
   for (auto& it : elements) {
     output.push_back(std::move(it) | decorator);
   }
-- 
GitLab