Index: llvm/trunk/include/llvm/Support/YAMLTraits.h =================================================================== --- llvm/trunk/include/llvm/Support/YAMLTraits.h +++ llvm/trunk/include/llvm/Support/YAMLTraits.h @@ -101,8 +101,7 @@ /// io.enumCase(value, "green", cGreen); /// } /// }; -template -struct ScalarEnumerationTraits { +template struct ScalarEnumerationTraits { // Must provide: // static void enumeration(IO &io, T &value); }; @@ -118,8 +117,7 @@ /// io.bitSetCase(value, "round", flagRound); /// } /// }; -template -struct ScalarBitSetTraits { +template struct ScalarBitSetTraits { // Must provide: // static void bitset(IO &io, T &value); }; @@ -145,8 +143,7 @@ /// } /// static QuotingType mustQuote(StringRef) { return QuotingType::Single; } /// }; -template -struct ScalarTraits { +template struct ScalarTraits { // Must provide: // // Function to write the value as a string: @@ -980,7 +977,7 @@ bool DoClear; if ( io.beginBitSetScalar(DoClear) ) { if ( DoClear ) - Val = static_cast(0); + Val = T(); ScalarBitSetTraits::bitset(io, Val); io.endBitSetScalar(); } @@ -1245,12 +1242,14 @@ static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; -// For endian types, we just use the existing ScalarTraits for the underlying -// type. This way endian aware types are supported whenever a ScalarTraits -// is defined for the underlying type. +// For endian types, we use existing scalar Traits class for the underlying +// type. This way endian aware types are supported whenever the traits are +// defined for the underlying type. template -struct ScalarTraits> { +struct ScalarTraits< + support::detail::packed_endian_specific_integral, + typename std::enable_if::value>::type> { using endian_type = support::detail::packed_endian_specific_integral; @@ -1271,6 +1270,38 @@ } }; +template +struct ScalarEnumerationTraits< + support::detail::packed_endian_specific_integral, + typename std::enable_if< + has_ScalarEnumerationTraits::value>::type> { + using endian_type = + support::detail::packed_endian_specific_integral; + + static void enumeration(IO &io, endian_type &E) { + value_type V = E; + ScalarEnumerationTraits::enumeration(io, V); + E = V; + } +}; + +template +struct ScalarBitSetTraits< + support::detail::packed_endian_specific_integral, + typename std::enable_if::value>::type> { + using endian_type = + support::detail::packed_endian_specific_integral; + static void bitset(IO &io, endian_type &E) { + value_type V = E; + ScalarBitSetTraits::bitset(io, V); + E = V; + } +}; + // Utility for use within MappingTraits<>::mapping() method // to [de]normalize an object for use with YAML conversion. template Index: llvm/trunk/unittests/Support/YAMLIOTest.cpp =================================================================== --- llvm/trunk/unittests/Support/YAMLIOTest.cpp +++ llvm/trunk/unittests/Support/YAMLIOTest.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -579,6 +580,90 @@ } } +enum class Enum : uint16_t { One, Two }; +enum class BitsetEnum : uint16_t { + ZeroOne = 0x01, + OneZero = 0x10, + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ OneZero), +}; +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); +struct EndianEnums { + llvm::support::little_t LittleEnum; + llvm::support::big_t BigEnum; + llvm::support::little_t LittleBitset; + llvm::support::big_t BigBitset; +}; +namespace llvm { +namespace yaml { +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, Enum &E) { + io.enumCase(E, "One", Enum::One); + io.enumCase(E, "Two", Enum::Two); + } +}; + +template <> struct ScalarBitSetTraits { + static void bitset(IO &io, BitsetEnum &E) { + io.bitSetCase(E, "ZeroOne", BitsetEnum::ZeroOne); + io.bitSetCase(E, "OneZero", BitsetEnum::OneZero); + } +}; + +template <> struct MappingTraits { + static void mapping(IO &io, EndianEnums &EE) { + io.mapRequired("LittleEnum", EE.LittleEnum); + io.mapRequired("BigEnum", EE.BigEnum); + io.mapRequired("LittleBitset", EE.LittleBitset); + io.mapRequired("BigBitset", EE.BigBitset); + } +}; +} // namespace yaml +} // namespace llvm + +TEST(YAMLIO, TestReadEndianEnums) { + EndianEnums map; + Input yin("---\n" + "LittleEnum: One\n" + "BigEnum: Two\n" + "LittleBitset: [ ZeroOne ]\n" + "BigBitset: [ ZeroOne, OneZero ]\n" + "...\n"); + yin >> map; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(Enum::One, map.LittleEnum); + EXPECT_EQ(Enum::Two, map.BigEnum); + EXPECT_EQ(BitsetEnum::ZeroOne, map.LittleBitset); + EXPECT_EQ(BitsetEnum::ZeroOne | BitsetEnum::OneZero, map.BigBitset); +} + +TEST(YAMLIO, TestReadWriteEndianEnums) { + std::string intermediate; + { + EndianEnums map; + map.LittleEnum = Enum::Two; + map.BigEnum = Enum::One; + map.LittleBitset = BitsetEnum::OneZero | BitsetEnum::ZeroOne; + map.BigBitset = BitsetEnum::OneZero; + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << map; + } + + { + Input yin(intermediate); + EndianEnums map; + yin >> map; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(Enum::Two, map.LittleEnum); + EXPECT_EQ(Enum::One, map.BigEnum); + EXPECT_EQ(BitsetEnum::OneZero | BitsetEnum::ZeroOne, map.LittleBitset); + EXPECT_EQ(BitsetEnum::OneZero, map.BigBitset); + } +} + struct StringTypes { llvm::StringRef str1; llvm::StringRef str2;