Skip to content

Commit

Permalink
[yaml] Add a ScalarTraits for mapping endian aware types.
Browse files Browse the repository at this point in the history
This allows mapping of any endian-aware type whose underlying
type (e.g. uint32_t) provides a ScalarTraits specialization.

Reviewed by: majnemer
Differential Revision: http://reviews.llvm.org/D21057

llvm-svn: 272049
  • Loading branch information
Zachary Turner committed Jun 7, 2016
1 parent 8b61759 commit 4fbf61d
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 0 deletions.
27 changes: 27 additions & 0 deletions llvm/include/llvm/Support/YAMLTraits.h
Expand Up @@ -17,6 +17,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
Expand Down Expand Up @@ -856,6 +857,32 @@ struct ScalarTraits<double> {
static bool mustQuote(StringRef) { return false; }
};

// 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.
template <typename value_type, support::endianness endian, size_t alignment>
struct ScalarTraits<support::detail::packed_endian_specific_integral<
value_type, endian, alignment>> {
typedef support::detail::packed_endian_specific_integral<value_type, endian,
alignment>
endian_type;

static void output(const endian_type &E, void *Ctx,
llvm::raw_ostream &Stream) {
ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream);
}
static StringRef input(StringRef Str, void *Ctx, endian_type &E) {
value_type V;
auto R = ScalarTraits<value_type>::input(Str, Ctx, V);
E = static_cast<endian_type>(V);
return R;
}

static bool mustQuote(StringRef Str) {
return ScalarTraits<value_type>::mustQuote(Str);
}
};

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

#include "llvm/ADT/Twine.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/YAMLTraits.h"
#include "gtest/gtest.h"
Expand Down Expand Up @@ -388,6 +389,111 @@ TEST(YAMLIO, TestReadWriteBuiltInTypes) {
}
}

//===----------------------------------------------------------------------===//
// Test endian-aware types
//===----------------------------------------------------------------------===//

struct EndianTypes {
typedef llvm::support::detail::packed_endian_specific_integral<
float, llvm::support::little, llvm::support::unaligned>
ulittle_float;
typedef llvm::support::detail::packed_endian_specific_integral<
double, llvm::support::little, llvm::support::unaligned>
ulittle_double;

llvm::support::ulittle64_t u64;
llvm::support::ulittle32_t u32;
llvm::support::ulittle16_t u16;
llvm::support::little64_t s64;
llvm::support::little32_t s32;
llvm::support::little16_t s16;
ulittle_float f;
ulittle_double d;
};

namespace llvm {
namespace yaml {
template <> struct MappingTraits<EndianTypes> {
static void mapping(IO &io, EndianTypes &et) {
io.mapRequired("u64", et.u64);
io.mapRequired("u32", et.u32);
io.mapRequired("u16", et.u16);
io.mapRequired("s64", et.s64);
io.mapRequired("s32", et.s32);
io.mapRequired("s16", et.s16);
io.mapRequired("f", et.f);
io.mapRequired("d", et.d);
}
};
}
}

//
// Test the reading of all endian scalar conversions
//
TEST(YAMLIO, TestReadEndianTypes) {
EndianTypes map;
Input yin("---\n"
"u64: 5000000000\n"
"u32: 4000000000\n"
"u16: 65000\n"
"s64: -5000000000\n"
"s32: -2000000000\n"
"s16: -32000\n"
"f: 3.25\n"
"d: -2.8625\n"
"...\n");
yin >> map;

EXPECT_FALSE(yin.error());
EXPECT_EQ(map.u64, 5000000000ULL);
EXPECT_EQ(map.u32, 4000000000U);
EXPECT_EQ(map.u16, 65000);
EXPECT_EQ(map.s64, -5000000000LL);
EXPECT_EQ(map.s32, -2000000000L);
EXPECT_EQ(map.s16, -32000);
EXPECT_EQ(map.f, 3.25f);
EXPECT_EQ(map.d, -2.8625);
}

//
// Test writing then reading back all endian-aware scalar types
//
TEST(YAMLIO, TestReadWriteEndianTypes) {
std::string intermediate;
{
EndianTypes map;
map.u64 = 6000000000ULL;
map.u32 = 3000000000U;
map.u16 = 50000;
map.s64 = -6000000000LL;
map.s32 = -2000000000;
map.s16 = -32000;
map.f = 3.25f;
map.d = -2.8625;

llvm::raw_string_ostream ostr(intermediate);
Output yout(ostr);
yout << map;
}

{
Input yin(intermediate);
EndianTypes map;
yin >> map;

EXPECT_FALSE(yin.error());
EXPECT_EQ(map.u64, 6000000000ULL);
EXPECT_EQ(map.u32, 3000000000U);
EXPECT_EQ(map.u16, 50000);
EXPECT_EQ(map.s64, -6000000000LL);
EXPECT_EQ(map.s32, -2000000000L);
EXPECT_EQ(map.s16, -32000);
EXPECT_EQ(map.f, 3.25f);
EXPECT_EQ(map.d, -2.8625);
}
}

struct StringTypes {
llvm::StringRef str1;
llvm::StringRef str2;
Expand Down

0 comments on commit 4fbf61d

Please sign in to comment.