From d5446f2f01419684a7cd39880d7830758796a02a Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 14 Aug 2023 15:48:10 +0900 Subject: [PATCH] Use `std::variant` in `StringOrView` We also add a direct string move-assignment (`operator=(std::string &&)`), which results in better codegen. As a consequence, we have to replace `= {}` assignments with `= StringOrView {}` because `= {}` is now ambiguous. --- Source/control.cpp | 4 +-- Source/controls/plrctrls.cpp | 2 +- Source/diablo.cpp | 6 ++-- Source/panels/spell_list.cpp | 2 +- Source/utils/string_or_view.hpp | 61 ++++++++------------------------- 5 files changed, 22 insertions(+), 53 deletions(-) diff --git a/Source/control.cpp b/Source/control.cpp index bfb81cb89..e981609d4 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -883,7 +883,7 @@ void InitControlPan() for (bool &buttonEnabled : chrbtn) buttonEnabled = false; chrbtnactive = false; - InfoString = {}; + InfoString = StringOrView {}; RedrawComponent(PanelDrawComponent::Health); RedrawComponent(PanelDrawComponent::Mana); CloseCharPanel(); @@ -1165,7 +1165,7 @@ void DrawInfoBox(const Surface &out) { DrawPanelBox(out, { 177, 62, 288, 63 }, GetMainPanel().position + Displacement { 177, 46 }); if (!panelflag && !trigflag && pcursinvitem == -1 && pcursstashitem == StashStruct::EmptyCell && !spselflag) { - InfoString = {}; + InfoString = StringOrView {}; InfoColor = UiFlags::ColorWhite; } Player &myPlayer = *MyPlayer; diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 23f5d81ae..fdcb89e91 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -1781,7 +1781,7 @@ void plrctrls_after_check_curs_move() return; } if (!invflag) { - InfoString = {}; + InfoString = StringOrView {}; FindActor(); FindItemOrObject(); FindTrigger(); diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 2bbd4a6d0..7a4434be1 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -1435,7 +1435,7 @@ void TimeoutCursor(bool bTimeout) if (sgnTimeoutCurs == CURSOR_NONE && sgbMouseDown == CLICK_NONE) { sgnTimeoutCurs = pcurs; multi_net_ping(); - InfoString = {}; + InfoString = StringOrView {}; AddPanelString(_("-- Network timeout --")); AddPanelString(_("-- Waiting for players --")); NewCursor(CURSOR_HOURGLASS); @@ -1449,7 +1449,7 @@ void TimeoutCursor(bool bTimeout) if (pcurs == CURSOR_HOURGLASS) NewCursor(sgnTimeoutCurs); sgnTimeoutCurs = CURSOR_NONE; - InfoString = {}; + InfoString = StringOrView {}; RedrawEverything(); } } @@ -1459,7 +1459,7 @@ void HelpKeyPressed() if (HelpFlag) { HelpFlag = false; } else if (stextflag != TalkID::None) { - InfoString = {}; + InfoString = StringOrView {}; AddPanelString(_("No help available")); /// BUGFIX: message isn't displayed AddPanelString(_("while in stores")); LastMouseButtonAction = MouseActionType::None; diff --git a/Source/panels/spell_list.cpp b/Source/panels/spell_list.cpp index f8381119c..3d2972e43 100644 --- a/Source/panels/spell_list.cpp +++ b/Source/panels/spell_list.cpp @@ -114,7 +114,7 @@ void DrawSpell(const Surface &out) void DrawSpellList(const Surface &out) { - InfoString = {}; + InfoString = StringOrView {}; Player &myPlayer = *MyPlayer; diff --git a/Source/utils/string_or_view.hpp b/Source/utils/string_or_view.hpp index 779ad02eb..1d38c75bd 100644 --- a/Source/utils/string_or_view.hpp +++ b/Source/utils/string_or_view.hpp @@ -3,78 +3,51 @@ #include #include #include +#include namespace devilution { class StringOrView { public: StringOrView() - : owned_(false) - , view_() + : rep_ { std::string_view {} } { } + StringOrView(StringOrView &&) noexcept = default; + StringOrView(std::string &&str) - : owned_(true) - , str_(std::move(str)) + : rep_ { std::move(str) } { } StringOrView(std::string_view str) - : owned_(false) - , view_(str) + : rep_ { str } { } - StringOrView(StringOrView &&other) noexcept - : owned_(other.owned_) - { - if (other.owned_) { - new (&str_) std::string(std::move(other.str_)); - } else { - new (&view_) std::string_view(other.view_); - } - } + StringOrView &operator=(StringOrView &&) noexcept = default; - StringOrView &operator=(StringOrView &&other) noexcept + StringOrView &operator=(std::string &&value) noexcept { - if (owned_) { - if (other.owned_) { - str_ = std::move(other.str_); - } else { - str_.~basic_string(); - owned_ = false; - new (&view_) std::string_view(other.view_); - } - } else { - if (other.owned_) { - view_.~basic_string_view(); - owned_ = true; - new (&str_) std::string(std::move(other.str_)); - } else { - view_ = other.view_; - } - } + rep_ = std::move(value); return *this; } - ~StringOrView() + StringOrView &operator=(std::string_view value) noexcept { - if (owned_) { - str_.~basic_string(); - } else { - view_.~basic_string_view(); - } + rep_ = value; + return *this; } bool empty() const { - return owned_ ? str_.empty() : view_.empty(); + return std::visit([](auto &&val) -> bool { return val.empty(); }, rep_); } std::string_view str() const { - return owned_ ? str_ : view_; + return std::visit([](auto &&val) -> std::string_view { return val; }, rep_); } operator std::string_view() const @@ -83,11 +56,7 @@ public: } private: - bool owned_; - union { - std::string str_; - std::string_view view_; - }; + std::variant rep_; }; } // namespace devilution