From 2481190d9c9f25fac2f97708c752990f873f44f0 Mon Sep 17 00:00:00 2001 From: 12xx12 <44411062+12xx12@users.noreply.github.com> Date: Fri, 5 Feb 2021 02:05:14 +0000 Subject: [PATCH] CompositeChat: use variants --- src/CompositeChat.cpp | 249 ++++++---------------- src/CompositeChat.h | 121 +++-------- src/Globals.h | 20 ++ tests/CompositeChat/CompositeChatTest.cpp | 82 ++++--- 4 files changed, 156 insertions(+), 316 deletions(-) diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp index 7def15550..46712a0f5 100644 --- a/src/CompositeChat.cpp +++ b/src/CompositeChat.cpp @@ -34,15 +34,6 @@ cCompositeChat::cCompositeChat(const AString & a_ParseText, eMessageType a_Messa -cCompositeChat::~cCompositeChat() -{ - Clear(); -} - - - - - void cCompositeChat::Clear(void) { m_Parts.clear(); @@ -54,7 +45,7 @@ void cCompositeChat::Clear(void) void cCompositeChat::AddTextPart(const AString & a_Message, const AString & a_Style) { - m_Parts.emplace_back(std::make_unique(a_Message, a_Style)); + m_Parts.push_back(TextPart{{ a_Message, a_Style, {} } }); } @@ -63,7 +54,7 @@ void cCompositeChat::AddTextPart(const AString & a_Message, const AString & a_St void cCompositeChat::AddClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style) { - m_Parts.emplace_back(std::make_unique(a_TranslationID, a_Parameters, a_Style)); + m_Parts.push_back(ClientTranslatedPart{{ a_TranslationID, a_Style, {} }, a_Parameters }); } @@ -72,7 +63,7 @@ void cCompositeChat::AddClientTranslatedPart(const AString & a_TranslationID, co void cCompositeChat::AddUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style) { - m_Parts.emplace_back(std::make_unique(a_Text, a_Url, a_Style)); + m_Parts.push_back(UrlPart{{ a_Text, a_Style, {} }, a_Url }); } @@ -81,7 +72,7 @@ void cCompositeChat::AddUrlPart(const AString & a_Text, const AString & a_Url, c void cCompositeChat::AddRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style) { - m_Parts.emplace_back(std::make_unique(a_Text, a_Command, a_Style)); + m_Parts.push_back(RunCommandPart{{{ a_Text, a_Style, {} }, a_Command } }); } @@ -90,7 +81,7 @@ void cCompositeChat::AddRunCommandPart(const AString & a_Text, const AString & a void cCompositeChat::AddSuggestCommandPart(const AString & a_Text, const AString & a_SuggestedCommand, const AString & a_Style) { - m_Parts.emplace_back(std::make_unique(a_Text, a_SuggestedCommand, a_Style)); + m_Parts.push_back(SuggestCommandPart{{{ a_Text, a_Style, {} }, a_SuggestedCommand } }); } @@ -99,7 +90,7 @@ void cCompositeChat::AddSuggestCommandPart(const AString & a_Text, const AString void cCompositeChat::AddShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style) { - m_Parts.emplace_back(std::make_unique(a_PlayerName, a_Achievement, a_Style)); + m_Parts.push_back(ShowAchievementPart{{ a_Achievement, a_Style, {} }, a_PlayerName }); } @@ -145,7 +136,7 @@ void cCompositeChat::ParseText(const AString & a_ParseText) } if (!CurrentText.empty()) { - m_Parts.emplace_back(std::make_unique(CurrentText, CurrentStyle)); + AddTextPart(CurrentText, CurrentStyle); CurrentText.clear(); } AddStyle(CurrentStyle, a_ParseText.substr(i - 1, 2)); @@ -223,10 +214,15 @@ void cCompositeChat::UnderlineUrls(void) { for (auto & Part : m_Parts) { - if (Part->m_PartType == ptUrl) + std::visit(OverloadedVariantAccess { - Part->m_Style.append("u"); - } + [](TextPart & a_Part) { }, + [](ClientTranslatedPart & a_Part) { }, + [](UrlPart & a_Part) { a_Part.Style += 'u'; }, + [](RunCommandPart & a_Part) { }, + [](SuggestCommandPart & a_Part) { }, + [](ShowAchievementPart & a_Part) { }, + }, Part); } } @@ -239,27 +235,16 @@ AString cCompositeChat::ExtractText(void) const AString Msg; for (const auto & Part : m_Parts) { - switch (Part->m_PartType) + std::visit(OverloadedVariantAccess { - case ptText: - case ptClientTranslated: - case ptRunCommand: - case ptSuggestCommand: - { - Msg.append(Part->m_Text); - break; - } - case ptUrl: - { - Msg.append(static_cast(Part.get())->m_Url); - break; - } - case ptShowAchievement: - { - break; - } - } // switch (PartType) - } // for itr - m_Parts[] + [&Msg](const TextPart & a_Part) { Msg.append(a_Part.Text); }, + [&Msg](const ClientTranslatedPart & a_Part) { Msg.append(a_Part.Text); }, + [&Msg](const UrlPart & a_Part) { Msg.append(a_Part.Url); }, + [&Msg](const RunCommandPart & a_Part) { Msg.append(a_Part.Text); }, + [&Msg](const SuggestCommandPart & a_Part) { Msg.append(a_Part.Text); }, + [ ](const ShowAchievementPart & a_Part) { }, + }, Part); + } return Msg; } @@ -321,86 +306,81 @@ AString cCompositeChat::CreateJsonString(bool a_ShouldUseChatPrefixes) const for (const auto & Part : m_Parts) { Json::Value JsonPart; - switch (Part->m_PartType) + std::visit(OverloadedVariantAccess { - case cCompositeChat::ptText: + [this, &JsonPart](const TextPart & a_Part) { - JsonPart["text"] = Part->m_Text; - AddChatPartStyle(JsonPart, Part->m_Style); - break; - } - - case cCompositeChat::ptClientTranslated: + JsonPart["text"] = a_Part.Text; + AddChatPartStyle(JsonPart, a_Part.Style); + }, + [this, &JsonPart](const ClientTranslatedPart & a_Part) { - const auto TranslatedPart = static_cast(Part.get()); - JsonPart["translate"] = TranslatedPart->m_Text; + JsonPart["translate"] = a_Part.Text; Json::Value With; - for (const auto & Parameter : TranslatedPart->m_Parameters) + for (const auto & Parameter : a_Part.Parameters) { With.append(Parameter); } - if (!TranslatedPart->m_Parameters.empty()) + if (!a_Part.Parameters.empty()) { JsonPart["with"] = With; } - AddChatPartStyle(JsonPart, TranslatedPart->m_Style); - break; - } - - case cCompositeChat::ptUrl: + AddChatPartStyle(JsonPart, a_Part.Style); + }, + [this, &JsonPart](const UrlPart & a_Part) { - const auto UrlPart = static_cast(Part.get()); - JsonPart["text"] = UrlPart->m_Text; + JsonPart["text"] = a_Part.Text; Json::Value Url; Url["action"] = "open_url"; - Url["value"] = UrlPart->m_Url; + Url["value"] = a_Part.Url; JsonPart["clickEvent"] = Url; - AddChatPartStyle(JsonPart, UrlPart->m_Style); - break; - } - - case cCompositeChat::ptSuggestCommand: - case cCompositeChat::ptRunCommand: + AddChatPartStyle(JsonPart, a_Part.Style); + }, + [this, &JsonPart](const RunCommandPart & a_Part) { - const auto CommandPart = static_cast(Part.get()); - JsonPart["text"] = CommandPart->m_Text; + JsonPart["text"] = a_Part.Text; Json::Value Cmd; - Cmd["action"] = (CommandPart->m_PartType == cCompositeChat::ptRunCommand) ? "run_command" : "suggest_command"; - Cmd["value"] = CommandPart->m_Command; + Cmd["action"] = "run_command"; + Cmd["value"] = a_Part.Command; JsonPart["clickEvent"] = Cmd; - AddChatPartStyle(JsonPart, CommandPart->m_Style); - break; - } - - case cCompositeChat::ptShowAchievement: + AddChatPartStyle(JsonPart, a_Part.Style); + }, + [this, &JsonPart](const SuggestCommandPart & a_Part) + { + JsonPart["text"] = a_Part.Text; + Json::Value Cmd; + Cmd["action"] = "suggest_command"; + Cmd["value"] = a_Part.Command; + JsonPart["clickEvent"] = Cmd; + AddChatPartStyle(JsonPart, a_Part.Style); + }, + [this, &JsonPart](const ShowAchievementPart & a_Part) { - const auto AchievementPart = static_cast(Part.get()); JsonPart["translate"] = "chat.type.achievement"; Json::Value Ach; Ach["action"] = "show_achievement"; - Ach["value"] = AchievementPart->m_Text; + Ach["value"] = a_Part.Text; Json::Value AchColourAndName; AchColourAndName["color"] = "green"; - AchColourAndName["translate"] = AchievementPart->m_Text; + AchColourAndName["translate"] = a_Part.Text; AchColourAndName["hoverEvent"] = Ach; Json::Value Extra; Extra.append(AchColourAndName); Json::Value Name; - Name["text"] = AchievementPart->m_PlayerName; + Name["text"] = a_Part.PlayerName; Json::Value With; With.append(Name); With.append(Extra); JsonPart["with"] = With; - AddChatPartStyle(JsonPart, AchievementPart->m_Style); - break; - } - } + AddChatPartStyle(JsonPart, a_Part.Style); + }, + }, Part); Message["extra"].append(JsonPart); } // for itr - Parts[] @@ -491,108 +471,3 @@ void cCompositeChat::AddChatPartStyle(Json::Value & a_Value, const AString & a_P } // switch (Style[i]) } // for i - a_PartStyle[] } - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cCompositeChat::cBasePart: - -cCompositeChat::cBasePart::cBasePart(cCompositeChat::ePartType a_PartType, const AString & a_Text, const AString & a_Style) : - m_PartType(a_PartType), - m_Text(a_Text), - m_Style(a_Style) -{ -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cCompositeChat::cTextPart: - -cCompositeChat::cTextPart::cTextPart(const AString & a_Text, const AString &a_Style) : - Super(ptText, a_Text, a_Style) -{ -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cCompositeChat::cClientTranslatedPart: - -cCompositeChat::cClientTranslatedPart::cClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style) : - Super(ptClientTranslated, a_TranslationID, a_Style), - m_Parameters(a_Parameters) -{ -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cCompositeChat::cUrlPart: - -cCompositeChat::cUrlPart::cUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style) : - Super(ptUrl, a_Text, a_Style), - m_Url(a_Url) -{ -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cCompositeChat::cCommandPart: - -cCompositeChat::cCommandPart::cCommandPart(ePartType a_PartType, const AString & a_Text, const AString & a_Command, const AString & a_Style) : - Super(a_PartType, a_Text, a_Style), - m_Command(a_Command) -{ -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cCompositeChat::cRunCommandPart: - -cCompositeChat::cRunCommandPart::cRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style) : - Super(ptRunCommand, a_Text, a_Command, a_Style) -{ -} - - - - -//////////////////////////////////////////////////////////////////////////////// -// cCompositeChat::cSuggestCommandPart: - -cCompositeChat::cSuggestCommandPart::cSuggestCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style) : - Super(ptSuggestCommand, a_Text, a_Command, a_Style) -{ -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cCompositeChat::cShowAchievementPart: - -cCompositeChat::cShowAchievementPart::cShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style) : - Super(ptShowAchievement, a_Achievement, a_Style), - m_PlayerName(a_PlayerName) -{ -} - - - - diff --git a/src/CompositeChat.h b/src/CompositeChat.h index b52b76bc5..78c8e0c9b 100644 --- a/src/CompositeChat.h +++ b/src/CompositeChat.h @@ -34,127 +34,69 @@ class cCompositeChat public: // tolua_end - enum ePartType + + struct BasePart { - ptText, - ptClientTranslated, - ptUrl, - ptRunCommand, - ptSuggestCommand, - ptShowAchievement, + AString Text; + AString Style; + AString AdditionalStyleData; } ; - class cBasePart + struct TextPart: + public BasePart { - public: - ePartType m_PartType; - AString m_Text; - AString m_Style; - AString m_AdditionalStyleData; - - cBasePart(ePartType a_PartType, const AString & a_Text, const AString & a_Style = ""); - - // Force a virtual destructor in descendants - virtual ~cBasePart() {} } ; - class cTextPart: - public cBasePart + struct ClientTranslatedPart: + public BasePart { - using Super = cBasePart; - - public: - - cTextPart(const AString & a_Text, const AString & a_Style = ""); + AStringVector Parameters; } ; - class cClientTranslatedPart: - public cBasePart + struct UrlPart: + public BasePart { - using Super = cBasePart; - - public: - - AStringVector m_Parameters; - - cClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style = ""); + AString Url; } ; - class cUrlPart: - public cBasePart + struct CommandPart: + public BasePart { - using Super = cBasePart; - - public: - - AString m_Url; - - cUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style = ""); + AString Command; } ; - class cCommandPart: - public cBasePart + struct RunCommandPart: + public CommandPart { - using Super = cBasePart; - - public: - - AString m_Command; - - cCommandPart(ePartType a_PartType, const AString & a_Text, const AString & a_Command, const AString & a_Style = ""); } ; - class cRunCommandPart: - public cCommandPart + struct SuggestCommandPart: + public CommandPart { - using Super = cCommandPart; - - public: - - cRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = ""); } ; - class cSuggestCommandPart: - public cCommandPart + struct ShowAchievementPart: + public BasePart { - using Super = cCommandPart; - - public: - - cSuggestCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = ""); + AString PlayerName; } ; - class cShowAchievementPart: - public cBasePart - { - using Super = cBasePart; - - public: - - AString m_PlayerName; - cShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style = ""); - } ; - - - /** the parts have to be allocated with new else the part specific parts are not saved (only the cBasePart members). */ - using cParts = std::vector>; - /** Creates a new empty chat message. Exported manually due to the other overload needing a manual export. */ cCompositeChat(void); @@ -165,14 +107,6 @@ public: Exported manually due to ToLua++ generating extra output parameter. */ cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType = mtCustom); - cCompositeChat(cCompositeChat && a_Other) = default; - - /** Copy constructor is explicitly deleted because m_Parts is not copyable. */ - cCompositeChat(cCompositeChat & a_Other) = delete; - cCompositeChat(const cCompositeChat & a_Other) = delete; - - ~cCompositeChat(); // tolua_export - // The following are exported in ManualBindings in order to support chaining - they return "self" in Lua (#755) /** Removes all parts from the object. */ @@ -231,7 +165,7 @@ public: // tolua_end - const cParts & GetParts(void) const { return m_Parts; } + const auto & GetParts(void) const { return m_Parts; } /** Converts the MessageType to a LogLevel value. Used by the logging bindings when logging a cCompositeChat object. */ @@ -241,8 +175,9 @@ public: void AddChatPartStyle(Json::Value & a_Value, const AString & a_PartStyle) const; protected: + /** All the parts that */ - cParts m_Parts; + std::vector> m_Parts; /** The message type, as indicated by prefixes. */ eMessageType m_MessageType; @@ -255,7 +190,3 @@ protected: If the style already contains something that a_AddStyle overrides, it is erased first. */ void AddStyle(AString & a_Style, const AString & a_AddStyle); } ; // tolua_export - - - - diff --git a/src/Globals.h b/src/Globals.h index 7b488326f..bb512d89d 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -317,6 +317,26 @@ namespace cpp20 +/** +You can use this struct to use in std::visit +example: +std::visit( + OverloadedVariantAccess + { + [&] (cFirstType & a_FirstTypeObject) { // Your code to handle cFirstType }, + [&] (cSecondType & a_SecondTypeObject) { // YourCode to handle cSecondType }, + ... + } +, YourVariant); +You can use constant references if you want to. +*/ +template struct OverloadedVariantAccess : Ts... { using Ts::operator()...; }; +template OverloadedVariantAccess(Ts...)->OverloadedVariantAccess; + + + + + /** Clamp X to the specified range. */ template T Clamp(T a_Value, T a_Min, T a_Max) diff --git a/tests/CompositeChat/CompositeChatTest.cpp b/tests/CompositeChat/CompositeChatTest.cpp index 08733d661..636a5c95a 100644 --- a/tests/CompositeChat/CompositeChatTest.cpp +++ b/tests/CompositeChat/CompositeChatTest.cpp @@ -15,16 +15,20 @@ static void TestParser1(void) { cCompositeChat Msg; Msg.ParseText("Testing @2color codes and http://links parser"); - const cCompositeChat::cParts & Parts = Msg.GetParts(); + const auto & Parts = Msg.GetParts(); TEST_EQUAL(Parts.size(), 4); - TEST_EQUAL(Parts[0]->m_PartType, cCompositeChat::ptText); - TEST_EQUAL(Parts[1]->m_PartType, cCompositeChat::ptText); - TEST_EQUAL(Parts[2]->m_PartType, cCompositeChat::ptUrl); - TEST_EQUAL(Parts[3]->m_PartType, cCompositeChat::ptText); - TEST_EQUAL(Parts[0]->m_Style, ""); - TEST_EQUAL(Parts[1]->m_Style, "@2"); - TEST_EQUAL(Parts[2]->m_Style, "@2"); - TEST_EQUAL(Parts[3]->m_Style, "@2"); + + TEST_TRUE(std::holds_alternative(Parts[0])); + TEST_EQUAL(std::get(Parts[0]).Style, ""); + + TEST_TRUE(std::holds_alternative(Parts[1])); + TEST_EQUAL(std::get(Parts[1]).Style, "@2"); + + TEST_TRUE(std::holds_alternative(Parts[2])); + TEST_EQUAL(std::get(Parts[2]).Style, "@2"); + + TEST_TRUE(std::holds_alternative(Parts[3])); + TEST_EQUAL(std::get(Parts[3]).Style, "@2"); } @@ -35,16 +39,20 @@ static void TestParser2(void) { cCompositeChat Msg; Msg.ParseText("@3Advanced stuff: @5overriding color codes and http://links.with/@4color-in-them handling"); - const cCompositeChat::cParts & Parts = Msg.GetParts(); + const auto & Parts = Msg.GetParts(); TEST_EQUAL(Parts.size(), 4); - TEST_EQUAL(Parts[0]->m_PartType, cCompositeChat::ptText); - TEST_EQUAL(Parts[1]->m_PartType, cCompositeChat::ptText); - TEST_EQUAL(Parts[2]->m_PartType, cCompositeChat::ptUrl); - TEST_EQUAL(Parts[3]->m_PartType, cCompositeChat::ptText); - TEST_EQUAL(Parts[0]->m_Style, "@3"); - TEST_EQUAL(Parts[1]->m_Style, "@5"); - TEST_EQUAL(Parts[2]->m_Style, "@5"); - TEST_EQUAL(Parts[3]->m_Style, "@5"); + + TEST_TRUE(std::holds_alternative(Parts[0])); + TEST_EQUAL(std::get(Parts[0]).Style, "@3"); + + TEST_TRUE(std::holds_alternative(Parts[1])); + TEST_EQUAL(std::get(Parts[1]).Style, "@5"); + + TEST_TRUE(std::holds_alternative(Parts[2])); + TEST_EQUAL(std::get(Parts[2]).Style, "@5"); + + TEST_TRUE(std::holds_alternative(Parts[3])); + TEST_EQUAL(std::get(Parts[3]).Style, "@5"); } @@ -55,12 +63,14 @@ static void TestParser3(void) { cCompositeChat Msg; Msg.ParseText("http://links.starting the text"); - const cCompositeChat::cParts & Parts = Msg.GetParts(); + const auto & Parts = Msg.GetParts(); TEST_EQUAL(Parts.size(), 2); - TEST_EQUAL(Parts[0]->m_PartType, cCompositeChat::ptUrl); - TEST_EQUAL(Parts[1]->m_PartType, cCompositeChat::ptText); - TEST_EQUAL(Parts[0]->m_Style, ""); - TEST_EQUAL(Parts[1]->m_Style, ""); + + TEST_TRUE(std::holds_alternative(Parts[0])); + TEST_EQUAL(std::get(Parts[0]).Style, ""); + + TEST_TRUE(std::holds_alternative(Parts[1])); + TEST_EQUAL(std::get(Parts[1]).Style, ""); } @@ -71,12 +81,14 @@ static void TestParser4(void) { cCompositeChat Msg; Msg.ParseText("links finishing the text: http://some.server"); - const cCompositeChat::cParts & Parts = Msg.GetParts(); + const auto & Parts = Msg.GetParts(); TEST_EQUAL(Parts.size(), 2); - TEST_EQUAL(Parts[0]->m_PartType, cCompositeChat::ptText); - TEST_EQUAL(Parts[1]->m_PartType, cCompositeChat::ptUrl); - TEST_EQUAL(Parts[0]->m_Style, ""); - TEST_EQUAL(Parts[1]->m_Style, ""); + + TEST_TRUE(std::holds_alternative(Parts[0])); + TEST_EQUAL(std::get(Parts[0]).Style, ""); + + TEST_TRUE(std::holds_alternative(Parts[1])); + TEST_EQUAL(std::get(Parts[1]).Style, ""); } @@ -87,10 +99,11 @@ static void TestParser5(void) { cCompositeChat Msg; Msg.ParseText("http://only.links"); - const cCompositeChat::cParts & Parts = Msg.GetParts(); + const auto & Parts = Msg.GetParts(); TEST_EQUAL(Parts.size(), 1); - TEST_EQUAL(Parts[0]->m_PartType, cCompositeChat::ptUrl); - TEST_EQUAL(Parts[0]->m_Style, ""); + + TEST_TRUE(std::holds_alternative(Parts[0])); + TEST_EQUAL(std::get(Parts[0]).Style, ""); } @@ -100,10 +113,11 @@ static void TestParser6(void) { cCompositeChat Msg; Msg.ParseText("Hello World"); - const cCompositeChat::cParts & Parts = Msg.GetParts(); + const auto & Parts = Msg.GetParts(); TEST_EQUAL(Parts.size(), 1); - TEST_EQUAL(Parts[0]->m_PartType, cCompositeChat::ptText); - TEST_EQUAL(Parts[0]->m_Style, ""); + + TEST_TRUE(std::holds_alternative(Parts[0])); + TEST_EQUAL(std::get(Parts[0]).Style, ""); }