Skip to content

Commit

Permalink
Do not use std::visit() for std::variant
Browse files Browse the repository at this point in the history
It is not supported for macOS 10.13 and earlier, see
https://stackoverflow.com/questions/53946674/noexcept-visitation-for-stdvariant.
  • Loading branch information
ufleisch committed Dec 27, 2023
1 parent bd4c9cb commit 7725993
Showing 1 changed file with 111 additions and 105 deletions.
216 changes: 111 additions & 105 deletions taglib/toolkit/tvariant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,125 +70,131 @@ T getVariantValue(StdVariantType *v, bool *ok)
return {};
}

// Visitor to print a possibly recursive Variant to an ostream.
// The representation is JSON with hex strings for ByteVector.
class OStreamVisitor {
public:
OStreamVisitor(std::ostream &os) : s(os)
{
}

void operator()(std::monostate v)
{
s << "null";
}

void operator()(bool v)
{
s << (v ? "true" : "false");
}

void operator()(int v)
{
s << v;
}

void operator()(unsigned int v)
{
s << v;
}

void operator()(long long v)
{
s << v;
}

void operator()(unsigned long long v)
{
s << v;
void printStringToStream(std::ostream &s, const String &v)
{
s << '"';
for(char c : v.to8Bit(true)) {
if(c == '"') {
s << "\\\"";
}
else {
s << c;
}
}
s << '"';
}

void operator()(double v)
{
s << v;
void printByteVectorToStream(std::ostream &s, const String &v)
{
s << '"';
for(char c : v) {
s << "\\x" << std::setfill('0') << std::setw(2) << std::right << std::hex
<< (static_cast<int>(c) & 0xff);
}
s << std::dec << '"';
}

void operator()(const TagLib::String &v)
{
s << '"';
for (char c : v.to8Bit(true)) {
if(c == '"') {
s << "\\\"";
}
else {
s << c;
}
// Print a possibly recursive Variant to an ostream.
// The representation is JSON with hex strings for ByteVector.
void printVariantToStream(std::ostream &s, const StdVariantType &v)
{
switch (v.index()) {
case Variant::Void:
s << "null";
break;
case Variant::Bool:
if(const auto valPtr = std::get_if<Variant::Bool>(&v)) {
s << (*valPtr ? "true" : "false");
}
s << '"';
}

void operator()(const TagLib::StringList &v)
{
s << '[';
for(auto it = v.cbegin(); it != v.cend(); ++it) {
if(it != v.cbegin()) {
s << ", ";
break;
case Variant::Int:
if(const auto valPtr = std::get_if<Variant::Int>(&v)) {
s << *valPtr;
}
break;
case Variant::UInt:
if(const auto valPtr = std::get_if<Variant::UInt>(&v)) {
s << *valPtr;
}
break;
case Variant::LongLong:
if(const auto valPtr = std::get_if<Variant::LongLong>(&v)) {
s << *valPtr;
}
break;
case Variant::ULongLong:
if(const auto valPtr = std::get_if<Variant::ULongLong>(&v)) {
s << *valPtr;
}
break;
case Variant::Double:
if(const auto valPtr = std::get_if<Variant::Double>(&v)) {
s << *valPtr;
}
break;
case Variant::String:
if(const auto valPtr = std::get_if<Variant::String>(&v)) {
printStringToStream(s, *valPtr);
}
break;
case Variant::StringList:
if(const auto valPtr = std::get_if<Variant::StringList>(&v)) {
const auto v = *valPtr;
s << '[';
for(auto it = valPtr->cbegin(); it != valPtr->cend(); ++it) {
if(it != valPtr->cbegin()) {
s << ", ";
}
printStringToStream(s, *it);
}
operator()(*it);
s << ']';
}
s << ']';
}

void operator()(const TagLib::ByteVector &v)
{
s << '"';
for(char c : v) {
s << "\\x" << std::setfill('0') << std::setw(2) << std::right << std::hex
<< (static_cast<int>(c) & 0xff);
break;
case Variant::ByteVector:
if(const auto valPtr = std::get_if<Variant::ByteVector>(&v)) {
printByteVectorToStream(s, *valPtr);
}
s << std::dec << '"';
}

void operator()(const TagLib::ByteVectorList &v)
{
s << '[';
for(auto it = v.cbegin(); it != v.cend(); ++it) {
if(it != v.cbegin()) {
s << ", ";
break;
case Variant::ByteVectorList:
if(const auto valPtr = std::get_if<Variant::ByteVectorList>(&v)) {
s << '[';
for(auto it = valPtr->cbegin(); it != valPtr->cend(); ++it) {
if(it != valPtr->cbegin()) {
s << ", ";
}
printByteVectorToStream(s, *it);
}
operator()(*it);
s << ']';
}
s << ']';
}

void operator()(const List<TagLib::Variant> &v) {
s << '[';
for(auto it = v.cbegin(); it != v.cend(); ++it) {
if(it != v.cbegin()) {
s << ", ";
break;
case Variant::VariantList:
if(const auto valPtr = std::get_if<Variant::VariantList>(&v)) {
s << '[';
for(auto it = valPtr->cbegin(); it != valPtr->cend(); ++it) {
if(it != valPtr->cbegin()) {
s << ", ";
}
s << *it;
}
s << *it;
s << ']';
}
s << ']';
}

void operator()(const Map<TagLib::String, TagLib::Variant> &v)
{
s << '{';
for(auto it = v.cbegin(); it != v.cend(); ++it) {
if(it != v.cbegin()) {
s << ", ";
break;
case Variant::VariantMap:
if(const auto valPtr = std::get_if<Variant::VariantMap>(&v)) {
s << '{';
for(auto it = valPtr->cbegin(); it != valPtr->cend(); ++it) {
if(it != valPtr->cbegin()) {
s << ", ";
}
printStringToStream(s, it->first);
s << ": ";
s << it->second;
}
operator()(it->first);
s << ": ";
s << it->second;
s << '}';
}
s << '}';
break;
}

private:
std::ostream &s;
};
}

} // namespace

Expand Down Expand Up @@ -386,6 +392,6 @@ Variant &Variant::operator=(const Variant &) = default;

std::ostream &operator<<(std::ostream &s, const TagLib::Variant &v)
{
std::visit(OStreamVisitor(s), v.d->data);
printVariantToStream(s, v.d->data);
return s;
}

0 comments on commit 7725993

Please sign in to comment.