Core/ChatCommands: Move Trinity::ChatCommands::Variant from boost::variant to std::variant, which means we no longer need visitors

This commit is contained in:
Treeston
2020-08-17 00:48:53 +02:00
parent 30a825e2ac
commit f9e7dbd8b4
5 changed files with 364 additions and 366 deletions

View File

@@ -31,9 +31,9 @@ struct AchievementVisitor
}; };
char const* Trinity::ChatCommands::ArgInfo<AchievementEntry const*>::TryConsume(AchievementEntry const*& data, char const* args) char const* Trinity::ChatCommands::ArgInfo<AchievementEntry const*>::TryConsume(AchievementEntry const*& data, char const* args)
{ {
Variant <Hyperlink<achievement>, uint32> val; Variant<Hyperlink<achievement>, uint32> val;
if ((args = CommandArgsConsumerSingle<decltype(val)>::TryConsumeTo(val, args))) if ((args = CommandArgsConsumerSingle<decltype(val)>::TryConsumeTo(val, args)))
data = boost::apply_visitor(AchievementVisitor(), val); data = val.visit(AchievementVisitor());
return args; return args;
} }
@@ -47,7 +47,7 @@ char const* Trinity::ChatCommands::ArgInfo<GameTele const*>::TryConsume(GameTele
{ {
Variant<Hyperlink<tele>, std::string> val; Variant<Hyperlink<tele>, std::string> val;
if ((args = CommandArgsConsumerSingle<decltype(val)>::TryConsumeTo(val, args))) if ((args = CommandArgsConsumerSingle<decltype(val)>::TryConsumeTo(val, args)))
data = boost::apply_visitor(GameTeleVisitor(), val); data = val.visit(GameTeleVisitor());
return args; return args;
} }
@@ -61,21 +61,22 @@ char const* Trinity::ChatCommands::ArgInfo<SpellInfo const*>::TryConsume(SpellIn
{ {
Variant<Hyperlink<spell>, uint32> val; Variant<Hyperlink<spell>, uint32> val;
if ((args = CommandArgsConsumerSingle<decltype(val)>::TryConsumeTo(val, args))) if ((args = CommandArgsConsumerSingle<decltype(val)>::TryConsumeTo(val, args)))
data = boost::apply_visitor(SpellInfoVisitor(), val); data = val.visit(SpellInfoVisitor());
return args; return args;
} }
struct BoolVisitor
{
using value_type = bool;
value_type operator()(uint32 i) const { return !!i; }
value_type operator()(ExactSequence<'o', 'n'>) const { return true; }
value_type operator()(ExactSequence<'o', 'f', 'f'>) const { return false; }
};
char const* Trinity::ChatCommands::ArgInfo<bool>::TryConsume(bool& data, char const* args) char const* Trinity::ChatCommands::ArgInfo<bool>::TryConsume(bool& data, char const* args)
{ {
Variant<uint32, ExactSequence<'o', 'n'>, ExactSequence<'o', 'f', 'f'>> val; std::string val;
if ((args = CommandArgsConsumerSingle<decltype(val)>::TryConsumeTo(val, args))) if ((args = CommandArgsConsumerSingle<std::string>::TryConsumeTo(val, args)))
data = boost::apply_visitor(BoolVisitor(), val); {
strToLower(val);
if (val == "on" || val == "yes" || val == "true" || val == "1" || val == "y")
data = true;
else if (val == "off" || val == "no" || val == "false" || val == "0" || val == "n")
data = false;
else
return nullptr;
}
return args; return args;
} }

View File

@@ -50,7 +50,7 @@ struct ArgInfo<T, std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>>
static char const* TryConsume(T& val, char const* args) static char const* TryConsume(T& val, char const* args)
{ {
char const* next = args; char const* next = args;
std::string token(args, tokenize(next)); std::string token(args, Trinity::Impl::ChatCommands::tokenize(next));
try try
{ {
size_t processedChars = 0; size_t processedChars = 0;
@@ -70,7 +70,7 @@ struct ArgInfo<T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T
static char const* TryConsume(T& val, char const* args) static char const* TryConsume(T& val, char const* args)
{ {
char const* next = args; char const* next = args;
std::string token(args, tokenize(next)); std::string token(args, Trinity::Impl::ChatCommands::tokenize(next));
try try
{ {
size_t processedChars = 0; size_t processedChars = 0;
@@ -90,7 +90,7 @@ struct ArgInfo<T, std::enable_if_t<std::is_floating_point_v<T>>>
static char const* TryConsume(T& val, char const* args) static char const* TryConsume(T& val, char const* args)
{ {
char const* next = args; char const* next = args;
std::string token(args, tokenize(next)); std::string token(args, Trinity::Impl::ChatCommands::tokenize(next));
try try
{ {
size_t processedChars = 0; size_t processedChars = 0;
@@ -110,7 +110,7 @@ struct ArgInfo<std::string, void>
static char const* TryConsume(std::string& val, char const* args) static char const* TryConsume(std::string& val, char const* args)
{ {
char const* next = args; char const* next = args;
if (size_t len = tokenize(next)) if (size_t len = Trinity::Impl::ChatCommands::tokenize(next))
{ {
val.assign(args, len); val.assign(args, len);
return next; return next;

View File

@@ -20,58 +20,50 @@
#include <type_traits> #include <type_traits>
namespace Trinity namespace Trinity::ChatCommands
{
namespace ChatCommands
{ {
static constexpr char COMMAND_DELIMITER = ' ';
static constexpr char COMMAND_DELIMITER = ' '; template <typename T, typename = void>
struct tag_base
{
using type = T;
};
/***************** HELPERS *************************\ template <typename T>
|* These really aren't for outside use... *| using tag_base_t = typename tag_base<T>::type;
\***************************************************/
inline std::size_t tokenize(char const*& end)
{
std::size_t len = 0;
for (; *end && *end != COMMAND_DELIMITER; ++end, ++len);
for (; *end && *end == COMMAND_DELIMITER; ++end);
return len;
} }
template <typename T, typename = void> namespace Trinity::Impl::ChatCommands
struct tag_base
{ {
using type = T; /***************** HELPERS *************************\
}; |* These really aren't for outside use... *|
\***************************************************/
inline std::size_t tokenize(char const*& end)
{
std::size_t len = 0;
for (; *end && *end != Trinity::ChatCommands::COMMAND_DELIMITER; ++end, ++len);
for (; *end && *end == Trinity::ChatCommands::COMMAND_DELIMITER; ++end);
return len;
}
template <typename T> template <typename T, typename... Ts>
using tag_base_t = typename tag_base<T>::type; struct are_all_assignable
{
static constexpr bool value = (std::is_assignable_v<T&, Ts> && ...);
};
template <typename...> template <std::size_t index, typename T1, typename... Ts>
struct are_all_assignable struct get_nth : get_nth<index-1, Ts...> { };
{
static constexpr bool value = true;
};
template <typename T1, typename T2, typename... Ts> template <typename T1, typename... Ts>
struct are_all_assignable<T1, T2, Ts...> struct get_nth<0, T1, Ts...>
{ {
static constexpr bool value = std::is_assignable_v<T1&, T2> && are_all_assignable<T1, Ts...>::value; using type = T1;
}; };
template <std::size_t index, typename T1, typename... Ts> template <std::size_t index, typename... Ts>
struct get_nth : get_nth<index-1, Ts...> { }; using get_nth_t = typename get_nth<index, Ts...>::type;
template <typename T1, typename... Ts>
struct get_nth<0, T1, Ts...>
{
using type = T1;
};
template <std::size_t index, typename... Ts>
using get_nth_t = typename get_nth<index, Ts...>::type;
}
} }
#endif #endif

View File

@@ -22,150 +22,158 @@
#include "ChatCommandHelpers.h" #include "ChatCommandHelpers.h"
#include "Hyperlinks.h" #include "Hyperlinks.h"
#include "Optional.h" #include "Optional.h"
#include <boost/variant.hpp>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <iostream>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <variant>
namespace Trinity namespace Trinity::ChatCommands
{ {
namespace ChatCommands /************************** CONTAINER TAGS **********************************************\
{ |* Simple holder classes to differentiate between extraction methods *|
/************************** CONTAINER TAGS **********************************************\ |* Should inherit from ContainerTag for template identification *|
|* Simple holder classes to differentiate between extraction methods *| |* Must implement the following: *|
|* Should inherit from ContainerTag for template identification *| |* - TryConsume: char const* -> char const* *|
|* Must implement the following: *| |* returns nullptr if no match, otherwise pointer to first character of next token *|
|* - TryConsume: char const* -> char const* *| |* - typedef value_type of type that is contained within the tag *|
|* returns nullptr if no match, otherwise pointer to first character of next token *| |* - cast operator to value_type *|
|* - typedef value_type of type that is contained within the tag *| |* *|
|* - cast operator to value_type *| \****************************************************************************************/
|* *| struct ContainerTag {};
\****************************************************************************************/ template <typename T>
struct ContainerTag {}; struct tag_base<T, std::enable_if_t<std::is_base_of_v<ContainerTag, T>>>
template <typename T>
struct tag_base<T, std::enable_if_t<std::is_base_of_v<ContainerTag, T>>>
{
using type = typename T::value_type;
};
template <char c1, char... chars>
struct ExactSequence : public ContainerTag
{
using value_type = void;
static constexpr bool isSingleChar = !sizeof...(chars);
template <bool C = isSingleChar>
static typename std::enable_if_t<!C, char const*> _TryConsume(char const* pos)
{ {
if (*(pos++) == c1) using type = typename T::value_type;
return ExactSequence<chars...>::_TryConsume(pos); };
else
return nullptr;
}
template <bool C = isSingleChar> template <char c1, char... chars>
static typename std::enable_if_t<C, char const*> _TryConsume(char const* pos) struct ExactSequence : public ContainerTag
{ {
if (*(pos++) != c1) using value_type = void;
return nullptr;
// if more of string is left, tokenize should return 0 (otherwise we didn't reach end of token yet)
return *pos && tokenize(pos) ? nullptr : pos;
}
char const* TryConsume(char const* pos) const { return ExactSequence::_TryConsume(pos); } static char const* _TryConsume(char const* pos)
};
template <typename linktag>
struct Hyperlink : public ContainerTag
{
typedef typename linktag::value_type value_type;
typedef advstd::remove_cvref_t<value_type> storage_type;
public:
operator value_type() const { return val; }
value_type operator*() const { return val; }
storage_type const* operator->() const { return &val; }
char const* TryConsume(char const* pos)
{ {
Trinity::Hyperlinks::HyperlinkInfo info = Trinity::Hyperlinks::ParseHyperlink(pos); if (*(pos++) == c1)
// invalid hyperlinks cannot be consumed {
if (!info) if constexpr (sizeof...(chars))
return ExactSequence<chars...>::_TryConsume(pos);
else if (Trinity::Impl::ChatCommands::tokenize(pos)) /* we did not consume the entire token */
return nullptr;
else
return pos;
}
else
return nullptr; return nullptr;
// check if we got the right tag
if (info.tag.second != strlen(linktag::tag()))
return nullptr;
if (strncmp(info.tag.first, linktag::tag(), strlen(linktag::tag())) != 0)
return nullptr;
// store value
if (!linktag::StoreTo(val, info.data.first, info.data.second))
return nullptr;
// finally, skip to end of token
pos = info.next;
tokenize(pos);
// return final pos
return pos;
} }
private: char const* TryConsume(char const* pos) const { return ExactSequence::_TryConsume(pos); }
storage_type val; };
};
// pull in link tags for user convenience template <typename linktag>
using namespace ::Trinity::Hyperlinks::LinkTags; struct Hyperlink : public ContainerTag
{
using value_type = typename linktag::value_type;
using storage_type = typedef advstd::remove_cvref_t<value_type>;
public:
operator value_type() const { return val; }
value_type operator*() const { return val; }
storage_type const* operator->() const { return &val; }
char const* TryConsume(char const* pos)
{
Trinity::Hyperlinks::HyperlinkInfo info = Trinity::Hyperlinks::ParseHyperlink(pos);
// invalid hyperlinks cannot be consumed
if (!info)
return nullptr;
// check if we got the right tag
if (info.tag.second != strlen(linktag::tag()))
return nullptr;
if (strncmp(info.tag.first, linktag::tag(), strlen(linktag::tag())) != 0)
return nullptr;
// store value
if (!linktag::StoreTo(val, info.data.first, info.data.second))
return nullptr;
// finally, skip to end of token
pos = info.next;
Trinity::Impl::ChatCommands::tokenize(pos);
// return final pos
return pos;
}
private:
storage_type val;
};
// pull in link tags for user convenience
using namespace ::Trinity::Hyperlinks::LinkTags;
}
/************************** VARIANT TAG LOGIC *********************************\ /************************** VARIANT TAG LOGIC *********************************\
|* This has some special handling over in ChatCommand.h *| |* This has some special handling over in ChatCommand.h *|
\******************************************************************************/ \******************************************************************************/
template <typename T> namespace Trinity::Impl
struct CastToVisitor {
using result_type = T;
template <typename U>
T operator()(U const& v) const { return v; }
};
template <typename T1, typename... Ts>
struct Variant : public boost::variant<T1, Ts...>
{ {
using first_type = tag_base_t<T1>;
static constexpr bool have_operators = are_all_assignable<first_type, tag_base_t<Ts>...>::value;
template <bool C = have_operators>
operator std::enable_if_t<C, first_type>()
{
return operator*();
}
template <bool C = have_operators>
std::enable_if_t<C, first_type> operator*()
{
return boost::apply_visitor(CastToVisitor<first_type>(), *this);
}
template <bool C = have_operators>
std::enable_if_t<C, first_type const&> operator*() const
{
return boost::apply_visitor(CastToVisitor<first_type const&>(), *this);
}
template <typename T> template <typename T>
Variant& operator=(T&& arg) { boost::variant<T1, Ts...>::operator=(std::forward<T>(arg)); return *this; } struct CastToVisitor {
template <typename U>
template <size_t index> T operator()(U const& v) const { return v; }
decltype(auto) get() const { return boost::get<get_nth_t<index, T1, Ts...>>(*this); } };
};
} }
namespace Trinity::ChatCommands
{
template <typename T1, typename... Ts>
struct Variant : public std::variant<T1, Ts...>
{
using first_type = tag_base_t<T1>;
static constexpr bool have_operators = Trinity::Impl::ChatCommands::are_all_assignable<first_type, tag_base_t<Ts>...>::value;
template <bool C = have_operators>
std::enable_if_t<C, first_type> operator*() const
{
return visit(Trinity::Impl::CastToVisitor<first_type>());
}
template <bool C = have_operators>
operator std::enable_if_t<C, first_type>() const
{
return operator*();
}
template <typename T>
Variant& operator=(T&& arg) { std::variant<T1, Ts...>::operator=(std::forward<T>(arg)); return *this; }
template <size_t index>
constexpr decltype(auto) get() { return std::get<index>(*this); }
template <size_t index>
constexpr decltype(auto) get() const { return std::get<index>(*this); }
template <typename T>
constexpr decltype(auto) visit(T&& arg) const { return std::visit(std::forward<T>(arg), *this); }
template <typename T>
constexpr bool holds_alternative() const { return std::holds_alternative<T>(*this); }
};
}
/* make the correct operator<< to use explicit, because otherwise the compiler gets confused with the implicit std::variant conversion */
namespace std
{
template <typename... Ts>
auto operator<<(std::ostream& os, Trinity::ChatCommands::Variant<Ts...> const& v) -> std::enable_if_t<Trinity::ChatCommands::Variant<Ts...>::have_operators, std::ostream&>
{
return (os << *v);
}
} }
#endif #endif

View File

@@ -31,212 +31,209 @@ class SpellInfo;
class Quest; class Quest;
struct TalentEntry; struct TalentEntry;
namespace Trinity namespace Trinity::Hyperlinks
{
namespace Hyperlinks
{ {
struct AchievementLinkData struct AchievementLinkData
{
AchievementEntry const* Achievement;
ObjectGuid::LowType CharacterId;
bool IsFinished;
uint16 Year;
uint8 Month;
uint8 Day;
uint32 Criteria[4];
};
struct GlyphLinkData
{
GlyphPropertiesEntry const* Glyph;
GlyphSlotEntry const* Slot;
};
struct ItemLinkData
{
ItemTemplate const* Item;
uint32 EnchantId;
uint32 GemEnchantId[3];
int32 RandomPropertyId;
int32 RandomPropertySeed;
uint8 RenderLevel;
};
struct QuestLinkData
{
::Quest const* Quest;
uint8 QuestLevel;
};
struct TalentLinkData
{
TalentEntry const* Talent;
uint8 Rank;
};
struct TradeskillLinkData
{
SpellInfo const* Spell;
uint16 CurValue;
uint16 MaxValue;
ObjectGuid Owner;
std::string KnownRecipes;
};
namespace LinkTags {
/************************** LINK TAGS ***************************************************\
|* Link tags must abide by the following: *|
|* - MUST expose ::value_type typedef *|
|* - storage type is remove_cvref_t<value_type> *|
|* - MUST expose static ::tag method, void -> const char* *|
|* - this method SHOULD be constexpr *|
|* - returns identifier string for the link ("creature", "creature_entry", "item") *|
|* - MUST expose static ::StoreTo method, (storage&, char const*, size_t) *|
|* - assign value_type& based on content of std::string(char const*, size_t) *|
|* - return value indicates success/failure *|
|* - for integral/string types this can be achieved by extending base_tag *|
\****************************************************************************************/
struct base_tag
{ {
static bool StoreTo(std::string& val, char const* pos, size_t len) AchievementEntry const* Achievement;
ObjectGuid::LowType CharacterId;
bool IsFinished;
uint16 Year;
uint8 Month;
uint8 Day;
uint32 Criteria[4];
};
struct GlyphLinkData
{
GlyphPropertiesEntry const* Glyph;
GlyphSlotEntry const* Slot;
};
struct ItemLinkData
{
ItemTemplate const* Item;
uint32 EnchantId;
uint32 GemEnchantId[3];
int32 RandomPropertyId;
int32 RandomPropertySeed;
uint8 RenderLevel;
};
struct QuestLinkData
{
::Quest const* Quest;
uint8 QuestLevel;
};
struct TalentLinkData
{
TalentEntry const* Talent;
uint8 Rank;
};
struct TradeskillLinkData
{
SpellInfo const* Spell;
uint16 CurValue;
uint16 MaxValue;
ObjectGuid Owner;
std::string KnownRecipes;
};
namespace LinkTags {
/************************** LINK TAGS ***************************************************\
|* Link tags must abide by the following: *|
|* - MUST expose ::value_type typedef *|
|* - storage type is remove_cvref_t<value_type> *|
|* - MUST expose static ::tag method, void -> const char* *|
|* - this method SHOULD be constexpr *|
|* - returns identifier string for the link ("creature", "creature_entry", "item") *|
|* - MUST expose static ::StoreTo method, (storage&, char const*, size_t) *|
|* - assign value_type& based on content of std::string(char const*, size_t) *|
|* - return value indicates success/failure *|
|* - for integral/string types this can be achieved by extending base_tag *|
\****************************************************************************************/
struct base_tag
{ {
val.assign(pos, len); static bool StoreTo(std::string& val, char const* pos, size_t len)
return true; {
} val.assign(pos, len);
return true;
}
template <typename T> template <typename T>
static std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>, bool> StoreTo(T& val, char const* pos, size_t len) static std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>, bool> StoreTo(T& val, char const* pos, size_t len)
{
try { val = std::stoull(std::string(pos, len)); }
catch (...) { return false; }
return true;
}
template <typename T>
static std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>, bool> StoreTo(T& val, char const* pos, size_t len)
{
try { val = std::stoll(std::string(pos, len)); }
catch (...) { return false; }
return true;
}
static bool StoreTo(ObjectGuid& val, char const* pos, size_t len)
{
try { val.Set(std::stoul(std::string(pos, len), nullptr, 16)); }
catch (...) { return false; }
return true;
}
};
#define make_base_tag(ltag, type) struct ltag : public base_tag { using value_type = type; static constexpr char const* tag() { return #ltag; } }
make_base_tag(area, uint32);
make_base_tag(areatrigger, uint32);
make_base_tag(creature, ObjectGuid::LowType);
make_base_tag(creature_entry, uint32);
make_base_tag(gameevent, uint32);
make_base_tag(gameobject, ObjectGuid::LowType);
make_base_tag(gameobject_entry, uint32);
make_base_tag(itemset, uint32);
make_base_tag(player, std::string const&);
make_base_tag(skill, uint32);
make_base_tag(taxinode, uint32);
make_base_tag(tele, uint32);
make_base_tag(title, uint32);
#undef make_base_tag
struct TC_GAME_API achievement
{ {
try { val = std::stoull(std::string(pos, len)); } using value_type = AchievementLinkData const&;
catch (...) { return false; } static constexpr char const* tag() { return "achievement"; }
return true; static bool StoreTo(AchievementLinkData& val, char const* pos, size_t len);
} };
template <typename T> struct TC_GAME_API enchant
static std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>, bool> StoreTo(T& val, char const* pos, size_t len)
{ {
try { val = std::stoll(std::string(pos, len)); } using value_type = SpellInfo const*;
catch (...) { return false; } static constexpr char const* tag() { return "enchant"; }
return true; static bool StoreTo(SpellInfo const*& val, char const* pos, size_t len);
} };
static bool StoreTo(ObjectGuid& val, char const* pos, size_t len) struct TC_GAME_API glyph
{ {
try { val.Set(std::stoul(std::string(pos, len), nullptr, 16)); } using value_type = GlyphLinkData const&;
catch (...) { return false; } static constexpr char const* tag() { return "glyph"; };
return true; static bool StoreTo(GlyphLinkData& val, char const* pos, size_t len);
} };
};
#define make_base_tag(ltag, type) struct ltag : public base_tag { using value_type = type; static constexpr char const* tag() { return #ltag; } } struct TC_GAME_API item
make_base_tag(area, uint32); {
make_base_tag(areatrigger, uint32); using value_type = ItemLinkData const&;
make_base_tag(creature, ObjectGuid::LowType); static constexpr char const* tag() { return "item"; }
make_base_tag(creature_entry, uint32); static bool StoreTo(ItemLinkData& val, char const* pos, size_t len);
make_base_tag(gameevent, uint32); };
make_base_tag(gameobject, ObjectGuid::LowType);
make_base_tag(gameobject_entry, uint32);
make_base_tag(itemset, uint32);
make_base_tag(player, std::string const&);
make_base_tag(skill, uint32);
make_base_tag(taxinode, uint32);
make_base_tag(tele, uint32);
make_base_tag(title, uint32);
#undef make_base_tag
struct TC_GAME_API achievement struct TC_GAME_API quest
{ {
using value_type = AchievementLinkData const&; using value_type = QuestLinkData const&;
static constexpr char const* tag() { return "achievement"; } static constexpr char const* tag() { return "quest"; }
static bool StoreTo(AchievementLinkData& val, char const* pos, size_t len); static bool StoreTo(QuestLinkData& val, char const* pos, size_t len);
}; };
struct TC_GAME_API enchant struct TC_GAME_API spell
{ {
using value_type = SpellInfo const*; using value_type = SpellInfo const*;
static constexpr char const* tag() { return "enchant"; } static constexpr char const* tag() { return "spell"; }
static bool StoreTo(SpellInfo const*& val, char const* pos, size_t len); static bool StoreTo(SpellInfo const*& val, char const* pos, size_t len);
}; };
struct TC_GAME_API glyph struct TC_GAME_API talent
{ {
using value_type = GlyphLinkData const&; using value_type = TalentLinkData const&;
static constexpr char const* tag() { return "glyph"; }; static constexpr char const* tag() { return "talent"; }
static bool StoreTo(GlyphLinkData& val, char const* pos, size_t len); static bool StoreTo(TalentLinkData& val, char const* pos, size_t len);
}; };
struct TC_GAME_API item struct TC_GAME_API trade
{ {
using value_type = ItemLinkData const&; using value_type = TradeskillLinkData const&;
static constexpr char const* tag() { return "item"; } static constexpr char const* tag() { return "trade"; }
static bool StoreTo(ItemLinkData& val, char const* pos, size_t len); static bool StoreTo(TradeskillLinkData& val, char const* pos, size_t len);
}; };
struct TC_GAME_API quest
{
using value_type = QuestLinkData const&;
static constexpr char const* tag() { return "quest"; }
static bool StoreTo(QuestLinkData& val, char const* pos, size_t len);
};
struct TC_GAME_API spell
{
using value_type = SpellInfo const*;
static constexpr char const* tag() { return "spell"; }
static bool StoreTo(SpellInfo const*& val, char const* pos, size_t len);
};
struct TC_GAME_API talent
{
using value_type = TalentLinkData const&;
static constexpr char const* tag() { return "talent"; }
static bool StoreTo(TalentLinkData& val, char const* pos, size_t len);
};
struct TC_GAME_API trade
{
using value_type = TradeskillLinkData const&;
static constexpr char const* tag() { return "trade"; }
static bool StoreTo(TradeskillLinkData& val, char const* pos, size_t len);
};
}
struct HyperlinkColor
{
HyperlinkColor(uint32 c) : r(c >> 16), g(c >> 8), b(c), a(c >> 24) {}
uint8 r, g, b, a;
bool operator==(uint32 c) const
{
if ((c & 0xff) ^ b)
return false;
if (((c >>= 8) & 0xff) ^ g)
return false;
if (((c >>= 8) & 0xff) ^ r)
return false;
if ((c >>= 8) ^ a)
return false;
return true;
} }
};
struct HyperlinkInfo struct HyperlinkColor
{ {
HyperlinkInfo(char const* n = nullptr, uint32 c = 0, char const* tS = nullptr, size_t tL = 0, char const* dS = nullptr, size_t dL = 0, char const* cS = nullptr, size_t cL = 0) : HyperlinkColor(uint32 c) : r(c >> 16), g(c >> 8), b(c), a(c >> 24) {}
next(n), color(c), tag(tS, tL), data(dS, dL), text(cS, cL) {} uint8 r, g, b, a;
bool operator==(uint32 c) const
{
if ((c & 0xff) ^ b)
return false;
if (((c >>= 8) & 0xff) ^ g)
return false;
if (((c >>= 8) & 0xff) ^ r)
return false;
if ((c >>= 8) ^ a)
return false;
return true;
}
};
explicit operator bool() { return next; } struct HyperlinkInfo
char const* const next; {
HyperlinkColor const color; HyperlinkInfo(char const* n = nullptr, uint32 c = 0, char const* tS = nullptr, size_t tL = 0, char const* dS = nullptr, size_t dL = 0, char const* cS = nullptr, size_t cL = 0) :
std::pair<char const*, size_t> const tag; next(n), color(c), tag(tS, tL), data(dS, dL), text(cS, cL) {}
std::pair<char const*, size_t> const data;
std::pair<char const*, size_t> const text; explicit operator bool() { return next; }
}; char const* const next;
HyperlinkInfo TC_GAME_API ParseHyperlink(char const* pos); HyperlinkColor const color;
bool TC_GAME_API CheckAllLinks(std::string const&); std::pair<char const*, size_t> const tag;
std::pair<char const*, size_t> const data;
std::pair<char const*, size_t> const text;
};
HyperlinkInfo TC_GAME_API ParseHyperlink(char const* pos);
bool TC_GAME_API CheckAllLinks(std::string const&);
}
} }
#endif #endif