Skip to content

Commit

Permalink
YAMLIO: Improve endian type support
Browse files Browse the repository at this point in the history
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
  • Loading branch information
labath committed Mar 15, 2019
1 parent 70ec64c commit 230837c
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 12 deletions.
55 changes: 43 additions & 12 deletions llvm/include/llvm/Support/YAMLTraits.h
Expand Up @@ -101,8 +101,7 @@ template <class T, class Context> struct MappingContextTraits {
/// io.enumCase(value, "green", cGreen);
/// }
/// };
template<typename T>
struct ScalarEnumerationTraits {
template <typename T, typename Enable = void> struct ScalarEnumerationTraits {
// Must provide:
// static void enumeration(IO &io, T &value);
};
Expand All @@ -118,8 +117,7 @@ struct ScalarEnumerationTraits {
/// io.bitSetCase(value, "round", flagRound);
/// }
/// };
template<typename T>
struct ScalarBitSetTraits {
template <typename T, typename Enable = void> struct ScalarBitSetTraits {
// Must provide:
// static void bitset(IO &io, T &value);
};
Expand All @@ -145,8 +143,7 @@ enum class QuotingType { None, Single, Double };
/// }
/// static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
/// };
template<typename T>
struct ScalarTraits {
template <typename T, typename Enable = void> struct ScalarTraits {
// Must provide:
//
// Function to write the value as a string:
Expand Down Expand Up @@ -980,7 +977,7 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
bool DoClear;
if ( io.beginBitSetScalar(DoClear) ) {
if ( DoClear )
Val = static_cast<T>(0);
Val = T();
ScalarBitSetTraits<T>::bitset(io, Val);
io.endBitSetScalar();
}
Expand Down Expand Up @@ -1245,12 +1242,14 @@ struct ScalarTraits<double> {
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 <typename value_type, support::endianness endian, size_t alignment>
struct ScalarTraits<support::detail::packed_endian_specific_integral<
value_type, endian, alignment>> {
struct ScalarTraits<
support::detail::packed_endian_specific_integral<value_type, endian,
alignment>,
typename std::enable_if<has_ScalarTraits<value_type>::value>::type> {
using endian_type =
support::detail::packed_endian_specific_integral<value_type, endian,
alignment>;
Expand All @@ -1271,6 +1270,38 @@ struct ScalarTraits<support::detail::packed_endian_specific_integral<
}
};

template <typename value_type, support::endianness endian, size_t alignment>
struct ScalarEnumerationTraits<
support::detail::packed_endian_specific_integral<value_type, endian,
alignment>,
typename std::enable_if<
has_ScalarEnumerationTraits<value_type>::value>::type> {
using endian_type =
support::detail::packed_endian_specific_integral<value_type, endian,
alignment>;

static void enumeration(IO &io, endian_type &E) {
value_type V = E;
ScalarEnumerationTraits<value_type>::enumeration(io, V);
E = V;
}
};

template <typename value_type, support::endianness endian, size_t alignment>
struct ScalarBitSetTraits<
support::detail::packed_endian_specific_integral<value_type, endian,
alignment>,
typename std::enable_if<has_ScalarBitSetTraits<value_type>::value>::type> {
using endian_type =
support::detail::packed_endian_specific_integral<value_type, endian,
alignment>;
static void bitset(IO &io, endian_type &E) {
value_type V = E;
ScalarBitSetTraits<value_type>::bitset(io, V);
E = V;
}
};

// Utility for use within MappingTraits<>::mapping() method
// to [de]normalize an object for use with YAML conversion.
template <typename TNorm, typename TFinal>
Expand Down
85 changes: 85 additions & 0 deletions llvm/unittests/Support/YAMLIOTest.cpp
Expand Up @@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
Expand Down Expand Up @@ -579,6 +580,90 @@ TEST(YAMLIO, TestReadWriteEndianTypes) {
}
}

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<Enum> LittleEnum;
llvm::support::big_t<Enum> BigEnum;
llvm::support::little_t<BitsetEnum> LittleBitset;
llvm::support::big_t<BitsetEnum> BigBitset;
};
namespace llvm {
namespace yaml {
template <> struct ScalarEnumerationTraits<Enum> {
static void enumeration(IO &io, Enum &E) {
io.enumCase(E, "One", Enum::One);
io.enumCase(E, "Two", Enum::Two);
}
};

template <> struct ScalarBitSetTraits<BitsetEnum> {
static void bitset(IO &io, BitsetEnum &E) {
io.bitSetCase(E, "ZeroOne", BitsetEnum::ZeroOne);
io.bitSetCase(E, "OneZero", BitsetEnum::OneZero);
}
};

template <> struct MappingTraits<EndianEnums> {
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;
Expand Down

0 comments on commit 230837c

Please sign in to comment.