Refactor ui::tagged_text to use allocated strings instead of string_views

This commit is contained in:
Nikita Lisitsa 2022-05-28 20:08:52 +03:00
parent b0fd3562cf
commit 2a2a97f0f8
5 changed files with 39 additions and 44 deletions

View file

@ -102,17 +102,17 @@ namespace psemek::ui
struct text_chunk struct text_chunk
{ {
std::string_view text; std::string text;
text_style style; // to be OR'd with base style text_style style; // to be OR'd with base style
std::optional<gfx::color_rgba> color; std::optional<gfx::color_rgba> color;
std::optional<std::string_view> link; std::optional<std::string> link;
}; };
struct image_chunk struct image_chunk
{ {
std::string_view id; std::string id;
std::optional<gfx::color_rgba> color; std::optional<gfx::color_rgba> color;
std::optional<std::string_view> link; std::optional<std::string> link;
}; };
using chunk = std::variant<text_chunk, image_chunk>; using chunk = std::variant<text_chunk, image_chunk>;
@ -139,12 +139,12 @@ namespace psemek::ui
std::vector<batch> batches; std::vector<batch> batches;
geom::vector<float, 2> size{0.f, 0.f}; geom::vector<float, 2> size{0.f, 0.f};
std::vector<std::pair<geom::box<float, 2>, std::string_view>> link_bboxes; std::vector<std::pair<geom::box<float, 2>, std::string>> link_bboxes;
}; };
mutable std::optional<cached_state> cached_state_; mutable std::optional<cached_state> cached_state_;
mutable std::optional<cached_state> cached_state_inf_; mutable std::optional<cached_state> cached_state_inf_;
std::optional<std::string_view> selected_link_; std::optional<std::string> selected_link_;
bool mouse_down_ = false; bool mouse_down_ = false;
void update_cached_state() const; void update_cached_state() const;

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <optional> #include <optional>
#include <string_view> #include <string>
#include <variant> #include <variant>
#include <vector> #include <vector>
#include <stdexcept> #include <stdexcept>
@ -16,16 +16,16 @@ namespace psemek::ui
{ {
struct opening_tag struct opening_tag
{ {
std::string_view type; std::string type;
std::optional<std::string_view> attribute; std::optional<std::string> attribute;
}; };
struct closing_tag struct closing_tag
{ {
std::string_view type; std::string type;
}; };
using token = std::variant<std::string_view, opening_tag, closing_tag>; using token = std::variant<std::string, opening_tag, closing_tag>;
std::vector<token> tokens; std::vector<token> tokens;

View file

@ -35,7 +35,7 @@ namespace psemek::ui
"link", "link",
}; };
void check_attribute(std::string_view tag, std::optional<std::string_view> const & attribute) void check_attribute(std::string const & tag, std::optional<std::string> const & attribute)
{ {
if (tag == "bold" || tag == "uline" || tag == "strike") if (tag == "bold" || tag == "uline" || tag == "strike")
{ {
@ -65,11 +65,11 @@ namespace psemek::ui
auto parse_result = tagged_text::parse(text_); auto parse_result = tagged_text::parse(text_);
std::unordered_map<std::string_view, std::vector<std::optional<std::string_view>>> tags_stack; std::unordered_map<std::string, std::vector<std::optional<std::string>>> tags_stack;
for (auto const & token : parse_result.tokens) for (auto const & token : parse_result.tokens)
{ {
if (auto text = std::get_if<std::string_view>(&token)) if (auto text = std::get_if<std::string>(&token))
{ {
text_chunk chunk; text_chunk chunk;
if (!tags_stack["bold"].empty()) if (!tags_stack["bold"].empty())
@ -174,7 +174,7 @@ namespace psemek::ui
{ {
if (cached_state_) if (cached_state_)
{ {
std::optional<std::string_view> new_selected_link; std::optional<std::string> new_selected_link;
auto const p = geom::cast<float>(e.position); auto const p = geom::cast<float>(e.position);
for (auto const & b : cached_state_->link_bboxes) for (auto const & b : cached_state_->link_bboxes)
{ {
@ -341,7 +341,7 @@ namespace psemek::ui
text_style style; text_style style;
gfx::color_rgba color; gfx::color_rgba color;
gfx::texture_view_2d image; gfx::texture_view_2d image;
std::optional<std::string_view> link; std::optional<std::string> link;
}; };
std::vector<item> items; std::vector<item> items;

View file

@ -56,12 +56,9 @@ namespace psemek::ui
} }
else else
{ {
auto append = [&](std::string_view & target) auto append = [&](std::string & target)
{ {
if (target.empty()) target.push_back(*current);
target = {current, current + 1};
else
target = {target.data(), current + 1};
}; };
if (in_tag) if (in_tag)
@ -83,17 +80,17 @@ namespace psemek::ui
++current; ++current;
if (current < text.end()) if (current < text.end())
{ {
result.tokens.push_back(std::string_view{}); result.tokens.push_back(std::string{});
append(std::get<std::string_view>(result.tokens.back())); append(std::get<std::string>(result.tokens.back()));
} }
else else
--current; --current;
} }
else else
{ {
if (result.tokens.empty() || !std::get_if<std::string_view>(&result.tokens.back())) if (result.tokens.empty() || !std::get_if<std::string>(&result.tokens.back()))
result.tokens.push_back(std::string_view{}); result.tokens.push_back(std::string{});
append(std::get<std::string_view>(result.tokens.back())); append(std::get<std::string>(result.tokens.back()));
} }
} }
} }

View file

@ -14,9 +14,9 @@ static void compare(tagged_text const & result, tagged_text const & expected)
for (std::size_t i = 0; i < result.tokens.size(); ++i) for (std::size_t i = 0; i < result.tokens.size(); ++i)
{ {
expect_equal(result.tokens[i].index(), expected.tokens[i].index()); expect_equal(result.tokens[i].index(), expected.tokens[i].index());
if (auto token = std::get_if<std::string_view>(&result.tokens[i])) if (auto token = std::get_if<std::string>(&result.tokens[i]))
{ {
expect_equal(*token, std::get<std::string_view>(expected.tokens[i])); expect_equal(*token, std::get<std::string>(expected.tokens[i]));
} }
else if (auto token = std::get_if<tagged_text::opening_tag>(&result.tokens[i])) else if (auto token = std::get_if<tagged_text::opening_tag>(&result.tokens[i]))
{ {
@ -116,14 +116,12 @@ test_case(ui_tagged__text_random)
generator rng; generator rng;
std::vector<std::unique_ptr<std::string>> string_pool; auto random_string = [&rng]() -> std::string {
std::string result;
auto random_string = [&rng, &string_pool]() -> std::string const & { result.resize(uniform<int>(rng, 1, 10));
auto & result = string_pool.emplace_back(std::make_unique<std::string>()); for (char & c : result)
result->resize(uniform<int>(rng, 1, 10));
for (char & c : *result)
c = uniform<char>(rng, 'a', 'z'); c = uniform<char>(rng, 'a', 'z');
return *result; return result;
}; };
std::string text; std::string text;
@ -133,14 +131,14 @@ test_case(ui_tagged__text_random)
{ {
auto roll = uniform<int>(rng, 0, 2); auto roll = uniform<int>(rng, 0, 2);
if (!expected.tokens.empty() && std::get_if<std::string_view>(&expected.tokens.back()) && roll == 0) if (!expected.tokens.empty() && std::get_if<std::string>(&expected.tokens.back()) && roll == 0)
roll = uniform<int>(rng, 1, 2); roll = uniform<int>(rng, 1, 2);
if (roll == 0) if (roll == 0)
{ {
auto const & str = random_string(); auto str = random_string();
text += str; text += str;
expected.tokens.push_back(std::string_view{str}); expected.tokens.push_back(std::move(str));
} }
else if (roll == 1) else if (roll == 1)
{ {
@ -148,16 +146,16 @@ test_case(ui_tagged__text_random)
tagged_text::opening_tag token; tagged_text::opening_tag token;
auto const & tag_str = random_string(); auto tag_str = random_string();
text += "[" + tag_str; text += "[" + tag_str;
token.type = tag_str; token.type = std::move(tag_str);
if (has_attr) if (has_attr)
{ {
auto const & attr_str = random_string(); auto attr_str = random_string();
text += ":" + attr_str; text += ":" + attr_str;
token.attribute = std::string_view{attr_str}; token.attribute = std::move(attr_str);
} }
text += "]"; text += "]";
@ -168,10 +166,10 @@ test_case(ui_tagged__text_random)
{ {
tagged_text::closing_tag token; tagged_text::closing_tag token;
auto const & tag_str = random_string(); auto tag_str = random_string();
text += "[/" + tag_str + "]"; text += "[/" + tag_str + "]";
token.type = tag_str; token.type = std::move(tag_str);
expected.tokens.push_back(token); expected.tokens.push_back(token);
} }