Skip to content

Commit 230837c

Browse files
committed
YAMLIO: Improve endian type support
Summary: Now that endian types support enumerations (D59141), the existing yaml support for them is somewhat insufficient. The current solution was to define the ScalarTraits class for these types, which always forwards to the ScalarTraits of the underlying type. However, the enum types will usually have ScalarEnumerationTraits of ScalarBitsetTraits. In this patch I add the two extra Traits types to the endian types. In order to properly SFINAE-ize them, I've also added an extra "Enable" template argument to the Traits template classes. Reviewers: zturner, sammccall Subscribers: kristina, Bigcheese, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D59289 llvm-svn: 356269
1 parent 70ec64c commit 230837c

File tree

2 files changed

+128
-12
lines changed

2 files changed

+128
-12
lines changed

llvm/include/llvm/Support/YAMLTraits.h

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ template <class T, class Context> struct MappingContextTraits {
101101
/// io.enumCase(value, "green", cGreen);
102102
/// }
103103
/// };
104-
template<typename T>
105-
struct ScalarEnumerationTraits {
104+
template <typename T, typename Enable = void> struct ScalarEnumerationTraits {
106105
// Must provide:
107106
// static void enumeration(IO &io, T &value);
108107
};
@@ -118,8 +117,7 @@ struct ScalarEnumerationTraits {
118117
/// io.bitSetCase(value, "round", flagRound);
119118
/// }
120119
/// };
121-
template<typename T>
122-
struct ScalarBitSetTraits {
120+
template <typename T, typename Enable = void> struct ScalarBitSetTraits {
123121
// Must provide:
124122
// static void bitset(IO &io, T &value);
125123
};
@@ -145,8 +143,7 @@ enum class QuotingType { None, Single, Double };
145143
/// }
146144
/// static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
147145
/// };
148-
template<typename T>
149-
struct ScalarTraits {
146+
template <typename T, typename Enable = void> struct ScalarTraits {
150147
// Must provide:
151148
//
152149
// Function to write the value as a string:
@@ -980,7 +977,7 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
980977
bool DoClear;
981978
if ( io.beginBitSetScalar(DoClear) ) {
982979
if ( DoClear )
983-
Val = static_cast<T>(0);
980+
Val = T();
984981
ScalarBitSetTraits<T>::bitset(io, Val);
985982
io.endBitSetScalar();
986983
}
@@ -1245,12 +1242,14 @@ struct ScalarTraits<double> {
12451242
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
12461243
};
12471244

1248-
// For endian types, we just use the existing ScalarTraits for the underlying
1249-
// type. This way endian aware types are supported whenever a ScalarTraits
1250-
// is defined for the underlying type.
1245+
// For endian types, we use existing scalar Traits class for the underlying
1246+
// type. This way endian aware types are supported whenever the traits are
1247+
// defined for the underlying type.
12511248
template <typename value_type, support::endianness endian, size_t alignment>
1252-
struct ScalarTraits<support::detail::packed_endian_specific_integral<
1253-
value_type, endian, alignment>> {
1249+
struct ScalarTraits<
1250+
support::detail::packed_endian_specific_integral<value_type, endian,
1251+
alignment>,
1252+
typename std::enable_if<has_ScalarTraits<value_type>::value>::type> {
12541253
using endian_type =
12551254
support::detail::packed_endian_specific_integral<value_type, endian,
12561255
alignment>;
@@ -1271,6 +1270,38 @@ struct ScalarTraits<support::detail::packed_endian_specific_integral<
12711270
}
12721271
};
12731272

1273+
template <typename value_type, support::endianness endian, size_t alignment>
1274+
struct ScalarEnumerationTraits<
1275+
support::detail::packed_endian_specific_integral<value_type, endian,
1276+
alignment>,
1277+
typename std::enable_if<
1278+
has_ScalarEnumerationTraits<value_type>::value>::type> {
1279+
using endian_type =
1280+
support::detail::packed_endian_specific_integral<value_type, endian,
1281+
alignment>;
1282+
1283+
static void enumeration(IO &io, endian_type &E) {
1284+
value_type V = E;
1285+
ScalarEnumerationTraits<value_type>::enumeration(io, V);
1286+
E = V;
1287+
}
1288+
};
1289+
1290+
template <typename value_type, support::endianness endian, size_t alignment>
1291+
struct ScalarBitSetTraits<
1292+
support::detail::packed_endian_specific_integral<value_type, endian,
1293+
alignment>,
1294+
typename std::enable_if<has_ScalarBitSetTraits<value_type>::value>::type> {
1295+
using endian_type =
1296+
support::detail::packed_endian_specific_integral<value_type, endian,
1297+
alignment>;
1298+
static void bitset(IO &io, endian_type &E) {
1299+
value_type V = E;
1300+
ScalarBitSetTraits<value_type>::bitset(io, V);
1301+
E = V;
1302+
}
1303+
};
1304+
12741305
// Utility for use within MappingTraits<>::mapping() method
12751306
// to [de]normalize an object for use with YAML conversion.
12761307
template <typename TNorm, typename TFinal>

llvm/unittests/Support/YAMLIOTest.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "llvm/ADT/BitmaskEnum.h"
910
#include "llvm/ADT/StringMap.h"
1011
#include "llvm/ADT/StringRef.h"
1112
#include "llvm/ADT/Twine.h"
@@ -579,6 +580,90 @@ TEST(YAMLIO, TestReadWriteEndianTypes) {
579580
}
580581
}
581582

583+
enum class Enum : uint16_t { One, Two };
584+
enum class BitsetEnum : uint16_t {
585+
ZeroOne = 0x01,
586+
OneZero = 0x10,
587+
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ OneZero),
588+
};
589+
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
590+
struct EndianEnums {
591+
llvm::support::little_t<Enum> LittleEnum;
592+
llvm::support::big_t<Enum> BigEnum;
593+
llvm::support::little_t<BitsetEnum> LittleBitset;
594+
llvm::support::big_t<BitsetEnum> BigBitset;
595+
};
596+
namespace llvm {
597+
namespace yaml {
598+
template <> struct ScalarEnumerationTraits<Enum> {
599+
static void enumeration(IO &io, Enum &E) {
600+
io.enumCase(E, "One", Enum::One);
601+
io.enumCase(E, "Two", Enum::Two);
602+
}
603+
};
604+
605+
template <> struct ScalarBitSetTraits<BitsetEnum> {
606+
static void bitset(IO &io, BitsetEnum &E) {
607+
io.bitSetCase(E, "ZeroOne", BitsetEnum::ZeroOne);
608+
io.bitSetCase(E, "OneZero", BitsetEnum::OneZero);
609+
}
610+
};
611+
612+
template <> struct MappingTraits<EndianEnums> {
613+
static void mapping(IO &io, EndianEnums &EE) {
614+
io.mapRequired("LittleEnum", EE.LittleEnum);
615+
io.mapRequired("BigEnum", EE.BigEnum);
616+
io.mapRequired("LittleBitset", EE.LittleBitset);
617+
io.mapRequired("BigBitset", EE.BigBitset);
618+
}
619+
};
620+
} // namespace yaml
621+
} // namespace llvm
622+
623+
TEST(YAMLIO, TestReadEndianEnums) {
624+
EndianEnums map;
625+
Input yin("---\n"
626+
"LittleEnum: One\n"
627+
"BigEnum: Two\n"
628+
"LittleBitset: [ ZeroOne ]\n"
629+
"BigBitset: [ ZeroOne, OneZero ]\n"
630+
"...\n");
631+
yin >> map;
632+
633+
EXPECT_FALSE(yin.error());
634+
EXPECT_EQ(Enum::One, map.LittleEnum);
635+
EXPECT_EQ(Enum::Two, map.BigEnum);
636+
EXPECT_EQ(BitsetEnum::ZeroOne, map.LittleBitset);
637+
EXPECT_EQ(BitsetEnum::ZeroOne | BitsetEnum::OneZero, map.BigBitset);
638+
}
639+
640+
TEST(YAMLIO, TestReadWriteEndianEnums) {
641+
std::string intermediate;
642+
{
643+
EndianEnums map;
644+
map.LittleEnum = Enum::Two;
645+
map.BigEnum = Enum::One;
646+
map.LittleBitset = BitsetEnum::OneZero | BitsetEnum::ZeroOne;
647+
map.BigBitset = BitsetEnum::OneZero;
648+
649+
llvm::raw_string_ostream ostr(intermediate);
650+
Output yout(ostr);
651+
yout << map;
652+
}
653+
654+
{
655+
Input yin(intermediate);
656+
EndianEnums map;
657+
yin >> map;
658+
659+
EXPECT_FALSE(yin.error());
660+
EXPECT_EQ(Enum::Two, map.LittleEnum);
661+
EXPECT_EQ(Enum::One, map.BigEnum);
662+
EXPECT_EQ(BitsetEnum::OneZero | BitsetEnum::ZeroOne, map.LittleBitset);
663+
EXPECT_EQ(BitsetEnum::OneZero, map.BigBitset);
664+
}
665+
}
666+
582667
struct StringTypes {
583668
llvm::StringRef str1;
584669
llvm::StringRef str2;

0 commit comments

Comments
 (0)