[llvm] r340457 - [BinaryFormat] Add MessagePack reader/writer

Scott Linder via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 22 14:42:50 PDT 2018


Author: scott.linder
Date: Wed Aug 22 14:42:50 2018
New Revision: 340457

URL: http://llvm.org/viewvc/llvm-project?rev=340457&view=rev
Log:
[BinaryFormat] Add MessagePack reader/writer

Add support for reading and writing MessagePack, a binary object serialization
format which aims to be more compact than text formats like JSON or YAML.

The specification can be found at
https://github.com/msgpack/msgpack/blob/master/spec.md

Will be used for encoding metadata in AMDGPU code objects.

Differential Revision: https://reviews.llvm.org/D44429


Added:
    llvm/trunk/include/llvm/BinaryFormat/MsgPack.def
    llvm/trunk/include/llvm/BinaryFormat/MsgPack.h
    llvm/trunk/include/llvm/BinaryFormat/MsgPackReader.h
    llvm/trunk/include/llvm/BinaryFormat/MsgPackWriter.h
    llvm/trunk/lib/BinaryFormat/MsgPackReader.cpp
    llvm/trunk/lib/BinaryFormat/MsgPackWriter.cpp
    llvm/trunk/unittests/BinaryFormat/MsgPackReaderTest.cpp
    llvm/trunk/unittests/BinaryFormat/MsgPackWriterTest.cpp
Modified:
    llvm/trunk/lib/BinaryFormat/CMakeLists.txt
    llvm/trunk/unittests/BinaryFormat/CMakeLists.txt

Added: llvm/trunk/include/llvm/BinaryFormat/MsgPack.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/MsgPack.def?rev=340457&view=auto
==============================================================================
--- llvm/trunk/include/llvm/BinaryFormat/MsgPack.def (added)
+++ llvm/trunk/include/llvm/BinaryFormat/MsgPack.def Wed Aug 22 14:42:50 2018
@@ -0,0 +1,108 @@
+//===- MsgPack.def - MessagePack definitions --------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Macros for running through MessagePack enumerators.
+///
+//===----------------------------------------------------------------------===//
+
+#if !(                                                                         \
+    defined HANDLE_MP_FIRST_BYTE || defined HANDLE_MP_FIX_BITS ||              \
+    defined HANDLE_MP_FIX_BITS_MASK || defined HANDLE_MP_FIX_MAX ||            \
+    defined HANDLE_MP_FIX_LEN || defined HANDLE_MP_FIX_MIN)
+#error "Missing macro definition of HANDLE_MP*"
+#endif
+
+#ifndef HANDLE_MP_FIRST_BYTE
+#define HANDLE_MP_FIRST_BYTE(ID, NAME)
+#endif
+
+#ifndef HANDLE_MP_FIX_BITS
+#define HANDLE_MP_FIX_BITS(ID, NAME)
+#endif
+
+#ifndef HANDLE_MP_FIX_BITS_MASK
+#define HANDLE_MP_FIX_BITS_MASK(ID, NAME)
+#endif
+
+#ifndef HANDLE_MP_FIX_MAX
+#define HANDLE_MP_FIX_MAX(ID, NAME)
+#endif
+
+#ifndef HANDLE_MP_FIX_LEN
+#define HANDLE_MP_FIX_LEN(ID, NAME)
+#endif
+
+#ifndef HANDLE_MP_FIX_MIN
+#define HANDLE_MP_FIX_MIN(ID, NAME)
+#endif
+
+HANDLE_MP_FIRST_BYTE(0xc0, Nil)
+HANDLE_MP_FIRST_BYTE(0xc2, False)
+HANDLE_MP_FIRST_BYTE(0xc3, True)
+HANDLE_MP_FIRST_BYTE(0xc4, Bin8)
+HANDLE_MP_FIRST_BYTE(0xc5, Bin16)
+HANDLE_MP_FIRST_BYTE(0xc6, Bin32)
+HANDLE_MP_FIRST_BYTE(0xc7, Ext8)
+HANDLE_MP_FIRST_BYTE(0xc8, Ext16)
+HANDLE_MP_FIRST_BYTE(0xc9, Ext32)
+HANDLE_MP_FIRST_BYTE(0xca, Float32)
+HANDLE_MP_FIRST_BYTE(0xcb, Float64)
+HANDLE_MP_FIRST_BYTE(0xcc, UInt8)
+HANDLE_MP_FIRST_BYTE(0xcd, UInt16)
+HANDLE_MP_FIRST_BYTE(0xce, UInt32)
+HANDLE_MP_FIRST_BYTE(0xcf, UInt64)
+HANDLE_MP_FIRST_BYTE(0xd0, Int8)
+HANDLE_MP_FIRST_BYTE(0xd1, Int16)
+HANDLE_MP_FIRST_BYTE(0xd2, Int32)
+HANDLE_MP_FIRST_BYTE(0xd3, Int64)
+HANDLE_MP_FIRST_BYTE(0xd4, FixExt1)
+HANDLE_MP_FIRST_BYTE(0xd5, FixExt2)
+HANDLE_MP_FIRST_BYTE(0xd6, FixExt4)
+HANDLE_MP_FIRST_BYTE(0xd7, FixExt8)
+HANDLE_MP_FIRST_BYTE(0xd8, FixExt16)
+HANDLE_MP_FIRST_BYTE(0xd9, Str8)
+HANDLE_MP_FIRST_BYTE(0xda, Str16)
+HANDLE_MP_FIRST_BYTE(0xdb, Str32)
+HANDLE_MP_FIRST_BYTE(0xdc, Array16)
+HANDLE_MP_FIRST_BYTE(0xdd, Array32)
+HANDLE_MP_FIRST_BYTE(0xde, Map16)
+HANDLE_MP_FIRST_BYTE(0xdf, Map32)
+
+HANDLE_MP_FIX_BITS(0x00, PositiveInt)
+HANDLE_MP_FIX_BITS(0x80, Map)
+HANDLE_MP_FIX_BITS(0x90, Array)
+HANDLE_MP_FIX_BITS(0xa0, String)
+HANDLE_MP_FIX_BITS(0xe0, NegativeInt)
+
+HANDLE_MP_FIX_BITS_MASK(0x80, PositiveInt)
+HANDLE_MP_FIX_BITS_MASK(0xf0, Map)
+HANDLE_MP_FIX_BITS_MASK(0xf0, Array)
+HANDLE_MP_FIX_BITS_MASK(0xe0, String)
+HANDLE_MP_FIX_BITS_MASK(0xe0, NegativeInt)
+
+HANDLE_MP_FIX_MAX(0x7f, PositiveInt)
+HANDLE_MP_FIX_MAX(0x0f, Map)
+HANDLE_MP_FIX_MAX(0x0f, Array)
+HANDLE_MP_FIX_MAX(0x1f, String)
+
+HANDLE_MP_FIX_LEN(0x01, Ext1)
+HANDLE_MP_FIX_LEN(0x02, Ext2)
+HANDLE_MP_FIX_LEN(0x04, Ext4)
+HANDLE_MP_FIX_LEN(0x08, Ext8)
+HANDLE_MP_FIX_LEN(0x10, Ext16)
+
+HANDLE_MP_FIX_MIN(-0x20, NegativeInt)
+
+#undef HANDLE_MP_FIRST_BYTE
+#undef HANDLE_MP_FIX_BITS
+#undef HANDLE_MP_FIX_BITS_MASK
+#undef HANDLE_MP_FIX_MAX
+#undef HANDLE_MP_FIX_LEN
+#undef HANDLE_MP_FIX_MIN

Added: llvm/trunk/include/llvm/BinaryFormat/MsgPack.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/MsgPack.h?rev=340457&view=auto
==============================================================================
--- llvm/trunk/include/llvm/BinaryFormat/MsgPack.h (added)
+++ llvm/trunk/include/llvm/BinaryFormat/MsgPack.h Wed Aug 22 14:42:50 2018
@@ -0,0 +1,93 @@
+//===-- MsgPack.h - MessagePack Constants -----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains constants used for implementing MessagePack support.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BINARYFORMAT_MSGPACK_H
+#define LLVM_BINARYFORMAT_MSGPACK_H
+
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Endian.h"
+
+namespace llvm {
+namespace msgpack {
+
+/// The endianness of all multi-byte encoded values in MessagePack.
+constexpr support::endianness Endianness = support::big;
+
+/// The first byte identifiers of MessagePack object formats.
+namespace FirstByte {
+#define HANDLE_MP_FIRST_BYTE(ID, NAME) constexpr uint8_t NAME = ID;
+#include "llvm/BinaryFormat/MsgPack.def"
+}
+
+/// Most significant bits used to identify "Fix" variants in MessagePack.
+///
+/// For example, FixStr objects encode their size in the five least significant
+/// bits of their first byte, which is identified by the bit pattern "101" in
+/// the three most significant bits. So FixBits::String contains 0b10100000.
+///
+/// A corresponding mask of the bit pattern is found in \c FixBitsMask.
+namespace FixBits {
+#define HANDLE_MP_FIX_BITS(ID, NAME) constexpr uint8_t NAME = ID;
+#include "llvm/BinaryFormat/MsgPack.def"
+}
+
+/// Mask of bits used to identify "Fix" variants in MessagePack.
+///
+/// For example, FixStr objects encode their size in the five least significant
+/// bits of their first byte, which is identified by the bit pattern "101" in
+/// the three most significant bits. So FixBitsMask::String contains
+/// 0b11100000.
+///
+/// The corresponding bit pattern to mask for is found in FixBits.
+namespace FixBitsMask {
+#define HANDLE_MP_FIX_BITS_MASK(ID, NAME) constexpr uint8_t NAME = ID;
+#include "llvm/BinaryFormat/MsgPack.def"
+}
+
+/// The maximum value or size encodable in "Fix" variants of formats.
+///
+/// For example, FixStr objects encode their size in the five least significant
+/// bits of their first byte, so the largest encodable size is 0b00011111.
+namespace FixMax {
+#define HANDLE_MP_FIX_MAX(ID, NAME) constexpr uint8_t NAME = ID;
+#include "llvm/BinaryFormat/MsgPack.def"
+}
+
+/// The exact size encodable in "Fix" variants of formats.
+///
+/// The only objects for which an exact size makes sense are of Extension type.
+///
+/// For example, FixExt4 stores an extension type containing exactly four bytes.
+namespace FixLen {
+#define HANDLE_MP_FIX_LEN(ID, NAME) constexpr uint8_t NAME = ID;
+#include "llvm/BinaryFormat/MsgPack.def"
+}
+
+/// The minimum value or size encodable in "Fix" variants of formats.
+///
+/// The only object for which a minimum makes sense is a negative FixNum.
+///
+/// Negative FixNum objects encode their signed integer value in one byte, but
+/// they must have the pattern "111" as their three most significant bits. This
+/// means all values are negative, and the smallest representable value is
+/// 0b11100000.
+namespace FixMin {
+#define HANDLE_MP_FIX_MIN(ID, NAME) constexpr int8_t NAME = ID;
+#include "llvm/BinaryFormat/MsgPack.def"
+}
+
+} // end namespace msgpack
+} // end namespace llvm
+
+#endif // LLVM_BINARYFORMAT_MSGPACK_H

Added: llvm/trunk/include/llvm/BinaryFormat/MsgPackReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/MsgPackReader.h?rev=340457&view=auto
==============================================================================
--- llvm/trunk/include/llvm/BinaryFormat/MsgPackReader.h (added)
+++ llvm/trunk/include/llvm/BinaryFormat/MsgPackReader.h Wed Aug 22 14:42:50 2018
@@ -0,0 +1,148 @@
+//===- MsgPackReader.h - Simple MsgPack reader ------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file
+///  This is a MessagePack reader.
+///
+///  See https://github.com/msgpack/msgpack/blob/master/spec.md for the full
+///  standard.
+///
+///  Typical usage:
+///  \code
+///  StringRef input = GetInput();
+///  msgpack::Reader MPReader(input);
+///  msgpack::Object Obj;
+///
+///  while (MPReader.read(Obj)) {
+///    switch (Obj.Kind) {
+///    case msgpack::Type::Int:
+//       // Use Obj.Int
+///      break;
+///    // ...
+///    }
+///  }
+///  \endcode
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MSGPACKREADER_H
+#define LLVM_SUPPORT_MSGPACKREADER_H
+
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+namespace llvm {
+namespace msgpack {
+
+/// MessagePack types as defined in the standard, with the exception of Integer
+/// being divided into a signed Int and unsigned UInt variant in order to map
+/// directly to C++ types.
+///
+/// The types map onto corresponding union members of the \c Object struct.
+enum class Type : uint8_t {
+  Int,
+  UInt,
+  Nil,
+  Boolean,
+  Float,
+  String,
+  Binary,
+  Array,
+  Map,
+  Extension,
+};
+
+/// Extension types are composed of a user-defined type ID and an uninterpreted
+/// sequence of bytes.
+struct ExtensionType {
+  /// User-defined extension type.
+  int8_t Type;
+  /// Raw bytes of the extension object.
+  StringRef Bytes;
+};
+
+/// MessagePack object, represented as a tagged union of C++ types.
+///
+/// All types except \c Type::Nil (which has only one value, and so is
+/// completely represented by the \c Kind itself) map to a exactly one union
+/// member.
+struct Object {
+  Type Kind;
+  union {
+    /// Value for \c Type::Int.
+    int64_t Int;
+    /// Value for \c Type::Uint.
+    uint64_t UInt;
+    /// Value for \c Type::Boolean.
+    bool Bool;
+    /// Value for \c Type::Float.
+    double Float;
+    /// Value for \c Type::String and \c Type::Binary.
+    StringRef Raw;
+    /// Value for \c Type::Array and \c Type::Map.
+    size_t Length;
+    /// Value for \c Type::Extension.
+    ExtensionType Extension;
+  };
+
+  Object() : Kind(Type::Int), Int(0) {}
+};
+
+/// Reads MessagePack objects from memory, one at a time.
+class Reader {
+public:
+  /// Construct a reader, keeping a reference to the \p InputBuffer.
+  Reader(MemoryBufferRef InputBuffer);
+  /// Construct a reader, keeping a reference to the \p Input.
+  Reader(StringRef Input);
+
+  Reader(const Reader &) = delete;
+  Reader &operator=(const Reader &) = delete;
+
+  /// Read one object from the input buffer, advancing past it.
+  ///
+  /// The \p Obj is updated with the kind of the object read, and the
+  /// corresponding union member is updated.
+  ///
+  /// For the collection objects (Array and Map), only the length is read, and
+  /// the caller must make and additional \c N calls (in the case of Array) or
+  /// \c N*2 calls (in the case of Map) to \c Read to retrieve the collection
+  /// elements.
+  ///
+  /// \param [out] Obj filled with next object on success.
+  ///
+  /// \returns true when object successfully read, false when at end of
+  /// input (and so \p Obj was not updated), otherwise an error.
+  Expected<bool> read(Object &Obj);
+
+private:
+  MemoryBufferRef InputBuffer;
+  StringRef::iterator Current;
+  StringRef::iterator End;
+
+  size_t remainingSpace() {
+    // The rest of the code maintains the invariant that End >= Current, so
+    // that this cast is always defined behavior.
+    return static_cast<size_t>(End - Current);
+  }
+
+  template <class T> Expected<bool> readRaw(Object &Obj);
+  template <class T> Expected<bool> readInt(Object &Obj);
+  template <class T> Expected<bool> readUInt(Object &Obj);
+  template <class T> Expected<bool> readLength(Object &Obj);
+  template <class T> Expected<bool> readExt(Object &Obj);
+  Expected<bool> createRaw(Object &Obj, uint32_t Size);
+  Expected<bool> createExt(Object &Obj, uint32_t Size);
+};
+
+} // end namespace msgpack
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_MSGPACKREADER_H

Added: llvm/trunk/include/llvm/BinaryFormat/MsgPackWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/MsgPackWriter.h?rev=340457&view=auto
==============================================================================
--- llvm/trunk/include/llvm/BinaryFormat/MsgPackWriter.h (added)
+++ llvm/trunk/include/llvm/BinaryFormat/MsgPackWriter.h Wed Aug 22 14:42:50 2018
@@ -0,0 +1,131 @@
+//===- MsgPackWriter.h - Simple MsgPack writer ------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file
+///  This file contains a MessagePack writer.
+///
+///  See https://github.com/msgpack/msgpack/blob/master/spec.md for the full
+///  specification.
+///
+///  Typical usage:
+///  \code
+///  raw_ostream output = GetOutputStream();
+///  msgpack::Writer MPWriter(output);
+///  MPWriter.writeNil();
+///  MPWriter.write(false);
+///  MPWriter.write("string");
+///  // ...
+///  \endcode
+///
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MSGPACKPARSER_H
+#define LLVM_SUPPORT_MSGPACKPARSER_H
+
+#include "llvm/BinaryFormat/MsgPack.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace msgpack {
+
+/// Writes MessagePack objects to an output stream, one at a time.
+class Writer {
+public:
+  /// Construct a writer, optionally enabling "Compatibility Mode" as defined
+  /// in the MessagePack specification.
+  ///
+  /// When in \p Compatible mode, the writer will write \c Str16 formats
+  /// instead of \c Str8 formats, and will refuse to write any \c Bin formats.
+  ///
+  /// \param OS stream to output MessagePack objects to.
+  /// \param Compatible when set, write in "Compatibility Mode".
+  Writer(raw_ostream &OS, bool Compatible = false);
+
+  Writer(const Writer &) = delete;
+  Writer &operator=(const Writer &) = delete;
+
+  /// Write a \em Nil to the output stream.
+  ///
+  /// The output will be the \em nil format.
+  void writeNil();
+
+  /// Write a \em Boolean to the output stream.
+  ///
+  /// The output will be a \em bool format.
+  void write(bool b);
+
+  /// Write a signed integer to the output stream.
+  ///
+  /// The output will be in the smallest possible \em int format.
+  ///
+  /// The format chosen may be for an unsigned integer.
+  void write(int64_t i);
+
+  /// Write an unsigned integer to the output stream.
+  ///
+  /// The output will be in the smallest possible \em int format.
+  void write(uint64_t u);
+
+  /// Write a floating point number to the output stream.
+  ///
+  /// The output will be in the smallest possible \em float format.
+  void write(double d);
+
+  /// Write a string to the output stream.
+  ///
+  /// The output will be in the smallest possible \em str format.
+  void write(StringRef s);
+
+  /// Write a memory buffer to the output stream.
+  ///
+  /// The output will be in the smallest possible \em bin format.
+  ///
+  /// \warning Do not use this overload if in \c Compatible mode.
+  void write(MemoryBufferRef Buffer);
+
+  /// Write the header for an \em Array of the given size.
+  ///
+  /// The output will be in the smallest possible \em array format.
+  //
+  /// The header contains an identifier for the \em array format used, as well
+  /// as an encoding of the size of the array.
+  ///
+  /// N.B. The caller must subsequently call \c Write an additional \p Size
+  /// times to complete the array.
+  void writeArraySize(uint32_t Size);
+
+  /// Write the header for a \em Map of the given size.
+  ///
+  /// The output will be in the smallest possible \em map format.
+  //
+  /// The header contains an identifier for the \em map format used, as well
+  /// as an encoding of the size of the map.
+  ///
+  /// N.B. The caller must subsequently call \c Write and additional \c Size*2
+  /// times to complete the map. Each even numbered call to \c Write defines a
+  /// new key, and each odd numbered call defines the previous key's value.
+  void writeMapSize(uint32_t Size);
+
+  /// Write a typed memory buffer (an extension type) to the output stream.
+  ///
+  /// The output will be in the smallest possible \em ext format.
+  void writeExt(int8_t Type, MemoryBufferRef Buffer);
+
+private:
+  support::endian::Writer EW;
+  bool Compatible;
+};
+
+} // end namespace msgpack
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_MSGPACKPARSER_H

Modified: llvm/trunk/lib/BinaryFormat/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/BinaryFormat/CMakeLists.txt?rev=340457&r1=340456&r2=340457&view=diff
==============================================================================
--- llvm/trunk/lib/BinaryFormat/CMakeLists.txt (original)
+++ llvm/trunk/lib/BinaryFormat/CMakeLists.txt Wed Aug 22 14:42:50 2018
@@ -1,6 +1,8 @@
 add_llvm_library(LLVMBinaryFormat
   Dwarf.cpp
   Magic.cpp
+  MsgPackReader.cpp
+  MsgPackWriter.cpp
   Wasm.cpp
 
   ADDITIONAL_HEADER_DIRS

Added: llvm/trunk/lib/BinaryFormat/MsgPackReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/BinaryFormat/MsgPackReader.cpp?rev=340457&view=auto
==============================================================================
--- llvm/trunk/lib/BinaryFormat/MsgPackReader.cpp (added)
+++ llvm/trunk/lib/BinaryFormat/MsgPackReader.cpp Wed Aug 22 14:42:50 2018
@@ -0,0 +1,255 @@
+//===- MsgPackReader.cpp - Simple MsgPack reader ----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file
+///  This file implements a MessagePack reader.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/MsgPackReader.h"
+#include "llvm/BinaryFormat/MsgPack.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support;
+using namespace msgpack;
+
+Reader::Reader(MemoryBufferRef InputBuffer)
+    : InputBuffer(InputBuffer), Current(InputBuffer.getBufferStart()),
+      End(InputBuffer.getBufferEnd()) {}
+
+Reader::Reader(StringRef Input) : Reader({Input, "MsgPack"}) {}
+
+Expected<bool> Reader::read(Object &Obj) {
+  if (Current == End)
+    return false;
+
+  uint8_t FB = static_cast<uint8_t>(*Current++);
+
+  switch (FB) {
+  case FirstByte::Nil:
+    Obj.Kind = Type::Nil;
+    return true;
+  case FirstByte::True:
+    Obj.Kind = Type::Boolean;
+    Obj.Bool = true;
+    return true;
+  case FirstByte::False:
+    Obj.Kind = Type::Boolean;
+    Obj.Bool = false;
+    return true;
+  case FirstByte::Int8:
+    Obj.Kind = Type::Int;
+    return readInt<int8_t>(Obj);
+  case FirstByte::Int16:
+    Obj.Kind = Type::Int;
+    return readInt<int16_t>(Obj);
+  case FirstByte::Int32:
+    Obj.Kind = Type::Int;
+    return readInt<int32_t>(Obj);
+  case FirstByte::Int64:
+    Obj.Kind = Type::Int;
+    return readInt<int64_t>(Obj);
+  case FirstByte::UInt8:
+    Obj.Kind = Type::UInt;
+    return readUInt<uint8_t>(Obj);
+  case FirstByte::UInt16:
+    Obj.Kind = Type::UInt;
+    return readUInt<uint16_t>(Obj);
+  case FirstByte::UInt32:
+    Obj.Kind = Type::UInt;
+    return readUInt<uint32_t>(Obj);
+  case FirstByte::UInt64:
+    Obj.Kind = Type::UInt;
+    return readUInt<uint64_t>(Obj);
+  case FirstByte::Float32:
+    Obj.Kind = Type::Float;
+    if (sizeof(float) > remainingSpace())
+      return make_error<StringError>(
+          "Invalid Float32 with insufficient payload",
+          std::make_error_code(std::errc::invalid_argument));
+    Obj.Float = BitsToFloat(endian::read<uint32_t, Endianness>(Current));
+    Current += sizeof(float);
+    return true;
+  case FirstByte::Float64:
+    Obj.Kind = Type::Float;
+    if (sizeof(double) > remainingSpace())
+      return make_error<StringError>(
+          "Invalid Float64 with insufficient payload",
+          std::make_error_code(std::errc::invalid_argument));
+    Obj.Float = BitsToDouble(endian::read<uint64_t, Endianness>(Current));
+    Current += sizeof(double);
+    return true;
+  case FirstByte::Str8:
+    Obj.Kind = Type::String;
+    return readRaw<uint8_t>(Obj);
+  case FirstByte::Str16:
+    Obj.Kind = Type::String;
+    return readRaw<uint16_t>(Obj);
+  case FirstByte::Str32:
+    Obj.Kind = Type::String;
+    return readRaw<uint32_t>(Obj);
+  case FirstByte::Bin8:
+    Obj.Kind = Type::Binary;
+    return readRaw<uint8_t>(Obj);
+  case FirstByte::Bin16:
+    Obj.Kind = Type::Binary;
+    return readRaw<uint16_t>(Obj);
+  case FirstByte::Bin32:
+    Obj.Kind = Type::Binary;
+    return readRaw<uint32_t>(Obj);
+  case FirstByte::Array16:
+    Obj.Kind = Type::Array;
+    return readLength<uint16_t>(Obj);
+  case FirstByte::Array32:
+    Obj.Kind = Type::Array;
+    return readLength<uint32_t>(Obj);
+  case FirstByte::Map16:
+    Obj.Kind = Type::Map;
+    return readLength<uint16_t>(Obj);
+  case FirstByte::Map32:
+    Obj.Kind = Type::Map;
+    return readLength<uint32_t>(Obj);
+  case FirstByte::FixExt1:
+    Obj.Kind = Type::Extension;
+    return createExt(Obj, FixLen::Ext1);
+  case FirstByte::FixExt2:
+    Obj.Kind = Type::Extension;
+    return createExt(Obj, FixLen::Ext2);
+  case FirstByte::FixExt4:
+    Obj.Kind = Type::Extension;
+    return createExt(Obj, FixLen::Ext4);
+  case FirstByte::FixExt8:
+    Obj.Kind = Type::Extension;
+    return createExt(Obj, FixLen::Ext8);
+  case FirstByte::FixExt16:
+    Obj.Kind = Type::Extension;
+    return createExt(Obj, FixLen::Ext16);
+  case FirstByte::Ext8:
+    Obj.Kind = Type::Extension;
+    return readExt<uint8_t>(Obj);
+  case FirstByte::Ext16:
+    Obj.Kind = Type::Extension;
+    return readExt<uint16_t>(Obj);
+  case FirstByte::Ext32:
+    Obj.Kind = Type::Extension;
+    return readExt<uint32_t>(Obj);
+  }
+
+  if ((FB & FixBitsMask::NegativeInt) == FixBits::NegativeInt) {
+    Obj.Kind = Type::Int;
+    int8_t I;
+    static_assert(sizeof(I) == sizeof(FB), "Unexpected type sizes");
+    memcpy(&I, &FB, sizeof(FB));
+    Obj.Int = I;
+    return true;
+  }
+
+  if ((FB & FixBitsMask::PositiveInt) == FixBits::PositiveInt) {
+    Obj.Kind = Type::UInt;
+    Obj.UInt = FB;
+    return true;
+  }
+
+  if ((FB & FixBitsMask::String) == FixBits::String) {
+    Obj.Kind = Type::String;
+    uint8_t Size = FB & ~FixBitsMask::String;
+    return createRaw(Obj, Size);
+  }
+
+  if ((FB & FixBitsMask::Array) == FixBits::Array) {
+    Obj.Kind = Type::Array;
+    Obj.Length = FB & ~FixBitsMask::Array;
+    return true;
+  }
+
+  if ((FB & FixBitsMask::Map) == FixBits::Map) {
+    Obj.Kind = Type::Map;
+    Obj.Length = FB & ~FixBitsMask::Map;
+    return true;
+  }
+
+  return make_error<StringError>(
+      "Invalid first byte", std::make_error_code(std::errc::invalid_argument));
+}
+
+template <class T> Expected<bool> Reader::readRaw(Object &Obj) {
+  if (sizeof(T) > remainingSpace())
+    return make_error<StringError>(
+        "Invalid Raw with insufficient payload",
+        std::make_error_code(std::errc::invalid_argument));
+  T Size = endian::read<T, Endianness>(Current);
+  Current += sizeof(T);
+  return createRaw(Obj, Size);
+}
+
+template <class T> Expected<bool> Reader::readInt(Object &Obj) {
+  if (sizeof(T) > remainingSpace())
+    return make_error<StringError>(
+        "Invalid Int with insufficient payload",
+        std::make_error_code(std::errc::invalid_argument));
+  Obj.Int = static_cast<int64_t>(endian::read<T, Endianness>(Current));
+  Current += sizeof(T);
+  return true;
+}
+
+template <class T> Expected<bool> Reader::readUInt(Object &Obj) {
+  if (sizeof(T) > remainingSpace())
+    return make_error<StringError>(
+        "Invalid Int with insufficient payload",
+        std::make_error_code(std::errc::invalid_argument));
+  Obj.UInt = static_cast<uint64_t>(endian::read<T, Endianness>(Current));
+  Current += sizeof(T);
+  return true;
+}
+
+template <class T> Expected<bool> Reader::readLength(Object &Obj) {
+  if (sizeof(T) > remainingSpace())
+    return make_error<StringError>(
+        "Invalid Map/Array with invalid length",
+        std::make_error_code(std::errc::invalid_argument));
+  Obj.Length = static_cast<size_t>(endian::read<T, Endianness>(Current));
+  Current += sizeof(T);
+  return true;
+}
+
+template <class T> Expected<bool> Reader::readExt(Object &Obj) {
+  if (sizeof(T) > remainingSpace())
+    return make_error<StringError>(
+        "Invalid Ext with invalid length",
+        std::make_error_code(std::errc::invalid_argument));
+  T Size = endian::read<T, Endianness>(Current);
+  Current += sizeof(T);
+  return createExt(Obj, Size);
+}
+
+Expected<bool> Reader::createRaw(Object &Obj, uint32_t Size) {
+  if (Size > remainingSpace())
+    return make_error<StringError>(
+        "Invalid Raw with insufficient payload",
+        std::make_error_code(std::errc::invalid_argument));
+  Obj.Raw = StringRef(Current, Size);
+  Current += Size;
+  return true;
+}
+
+Expected<bool> Reader::createExt(Object &Obj, uint32_t Size) {
+  if (Current == End)
+    return make_error<StringError>(
+        "Invalid Ext with no type",
+        std::make_error_code(std::errc::invalid_argument));
+  Obj.Extension.Type = *Current++;
+  if (Size > remainingSpace())
+    return make_error<StringError>(
+        "Invalid Ext with insufficient payload",
+        std::make_error_code(std::errc::invalid_argument));
+  Obj.Extension.Bytes = StringRef(Current, Size);
+  Current += Size;
+  return true;
+}

Added: llvm/trunk/lib/BinaryFormat/MsgPackWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/BinaryFormat/MsgPackWriter.cpp?rev=340457&view=auto
==============================================================================
--- llvm/trunk/lib/BinaryFormat/MsgPackWriter.cpp (added)
+++ llvm/trunk/lib/BinaryFormat/MsgPackWriter.cpp Wed Aug 22 14:42:50 2018
@@ -0,0 +1,208 @@
+//===- MsgPackWriter.cpp - Simple MsgPack writer ----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file
+///  This file implements a MessagePack writer.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/MsgPackWriter.h"
+#include "llvm/BinaryFormat/MsgPack.h"
+
+using namespace llvm;
+using namespace msgpack;
+
+Writer::Writer(raw_ostream &OS, bool Compatible)
+    : EW(OS, Endianness), Compatible(Compatible) {}
+
+void Writer::writeNil() { EW.write(FirstByte::Nil); }
+
+void Writer::write(bool b) { EW.write(b ? FirstByte::True : FirstByte::False); }
+
+void Writer::write(int64_t i) {
+  if (i >= 0) {
+    write(static_cast<uint64_t>(i));
+    return;
+  }
+
+  if (i >= FixMin::NegativeInt) {
+    EW.write(static_cast<int8_t>(i));
+    return;
+  }
+
+  if (i >= INT8_MIN) {
+    EW.write(FirstByte::Int8);
+    EW.write(static_cast<int8_t>(i));
+    return;
+  }
+
+  if (i >= INT16_MIN) {
+    EW.write(FirstByte::Int16);
+    EW.write(static_cast<int16_t>(i));
+    return;
+  }
+
+  if (i >= INT32_MIN) {
+    EW.write(FirstByte::Int32);
+    EW.write(static_cast<int32_t>(i));
+    return;
+  }
+
+  EW.write(FirstByte::Int64);
+  EW.write(i);
+}
+
+void Writer::write(uint64_t u) {
+  if (u <= FixMax::PositiveInt) {
+    EW.write(static_cast<uint8_t>(u));
+    return;
+  }
+
+  if (u <= UINT8_MAX) {
+    EW.write(FirstByte::UInt8);
+    EW.write(static_cast<uint8_t>(u));
+    return;
+  }
+
+  if (u <= UINT16_MAX) {
+    EW.write(FirstByte::UInt16);
+    EW.write(static_cast<uint16_t>(u));
+    return;
+  }
+
+  if (u <= UINT32_MAX) {
+    EW.write(FirstByte::UInt32);
+    EW.write(static_cast<uint32_t>(u));
+    return;
+  }
+
+  EW.write(FirstByte::UInt64);
+  EW.write(u);
+}
+
+void Writer::write(double d) {
+  // If no loss of precision, encode as a Float32.
+  float f = static_cast<float>(d);
+  if (static_cast<double>(f) == d) {
+    EW.write(FirstByte::Float32);
+    EW.write(f);
+  } else {
+    EW.write(FirstByte::Float64);
+    EW.write(d);
+  }
+}
+
+void Writer::write(StringRef s) {
+  size_t Size = s.size();
+
+  if (Size <= FixMax::String)
+    EW.write(static_cast<uint8_t>(FixBits::String | Size));
+  else if (!Compatible && Size <= UINT8_MAX) {
+    EW.write(FirstByte::Str8);
+    EW.write(static_cast<uint8_t>(Size));
+  } else if (Size <= UINT16_MAX) {
+    EW.write(FirstByte::Str16);
+    EW.write(static_cast<uint16_t>(Size));
+  } else {
+    assert(Size <= UINT32_MAX && "String object too long to be encoded");
+    EW.write(FirstByte::Str32);
+    EW.write(static_cast<uint32_t>(Size));
+  }
+
+  EW.OS << s;
+}
+
+void Writer::write(MemoryBufferRef Buffer) {
+  assert(!Compatible && "Attempt to write Bin format in compatible mode");
+
+  size_t Size = Buffer.getBufferSize();
+
+  if (Size <= UINT8_MAX) {
+    EW.write(FirstByte::Bin8);
+    EW.write(static_cast<uint8_t>(Size));
+  } else if (Size <= UINT16_MAX) {
+    EW.write(FirstByte::Bin16);
+    EW.write(static_cast<uint16_t>(Size));
+  } else {
+    assert(Size <= UINT32_MAX && "Binary object too long to be encoded");
+    EW.write(FirstByte::Bin32);
+    EW.write(static_cast<uint32_t>(Size));
+  }
+
+  EW.OS.write(Buffer.getBufferStart(), Size);
+}
+
+void Writer::writeArraySize(uint32_t Size) {
+  if (Size <= FixMax::Array) {
+    EW.write(static_cast<uint8_t>(FixBits::Array | Size));
+    return;
+  }
+
+  if (Size <= UINT16_MAX) {
+    EW.write(FirstByte::Array16);
+    EW.write(static_cast<uint16_t>(Size));
+    return;
+  }
+
+  EW.write(FirstByte::Array32);
+  EW.write(Size);
+}
+
+void Writer::writeMapSize(uint32_t Size) {
+  if (Size <= FixMax::Map) {
+    EW.write(static_cast<uint8_t>(FixBits::Map | Size));
+    return;
+  }
+
+  if (Size <= UINT16_MAX) {
+    EW.write(FirstByte::Map16);
+    EW.write(static_cast<uint16_t>(Size));
+    return;
+  }
+
+  EW.write(FirstByte::Map32);
+  EW.write(Size);
+}
+
+void Writer::writeExt(int8_t Type, MemoryBufferRef Buffer) {
+  size_t Size = Buffer.getBufferSize();
+
+  switch (Size) {
+  case FixLen::Ext1:
+    EW.write(FirstByte::FixExt1);
+    break;
+  case FixLen::Ext2:
+    EW.write(FirstByte::FixExt2);
+    break;
+  case FixLen::Ext4:
+    EW.write(FirstByte::FixExt4);
+    break;
+  case FixLen::Ext8:
+    EW.write(FirstByte::FixExt8);
+    break;
+  case FixLen::Ext16:
+    EW.write(FirstByte::FixExt16);
+    break;
+  default:
+    if (Size <= UINT8_MAX) {
+      EW.write(FirstByte::Ext8);
+      EW.write(static_cast<uint8_t>(Size));
+    } else if (Size <= UINT16_MAX) {
+      EW.write(FirstByte::Ext16);
+      EW.write(static_cast<uint16_t>(Size));
+    } else {
+      assert(Size <= UINT32_MAX && "Ext size too large to be encoded");
+      EW.write(FirstByte::Ext32);
+      EW.write(static_cast<uint32_t>(Size));
+    }
+  }
+
+  EW.write(Type);
+  EW.OS.write(Buffer.getBufferStart(), Size);
+}

Modified: llvm/trunk/unittests/BinaryFormat/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/BinaryFormat/CMakeLists.txt?rev=340457&r1=340456&r2=340457&view=diff
==============================================================================
--- llvm/trunk/unittests/BinaryFormat/CMakeLists.txt (original)
+++ llvm/trunk/unittests/BinaryFormat/CMakeLists.txt Wed Aug 22 14:42:50 2018
@@ -5,6 +5,8 @@ set(LLVM_LINK_COMPONENTS
 add_llvm_unittest(BinaryFormatTests
   DwarfTest.cpp
   MachOTest.cpp
+  MsgPackReaderTest.cpp
+  MsgPackWriterTest.cpp
   TestFileMagic.cpp
   )
 

Added: llvm/trunk/unittests/BinaryFormat/MsgPackReaderTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/BinaryFormat/MsgPackReaderTest.cpp?rev=340457&view=auto
==============================================================================
--- llvm/trunk/unittests/BinaryFormat/MsgPackReaderTest.cpp (added)
+++ llvm/trunk/unittests/BinaryFormat/MsgPackReaderTest.cpp Wed Aug 22 14:42:50 2018
@@ -0,0 +1,891 @@
+//===- MsgPackReaderTest.cpp ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/MsgPackReader.h"
+#include "llvm/BinaryFormat/MsgPack.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::msgpack;
+
+struct MsgPackReader : testing::Test {
+  std::string Buffer;
+  Object Obj;
+};
+
+TEST_F(MsgPackReader, TestReadMultiple) {
+  Buffer = "\xc0\xc2";
+  Reader MPReader(Buffer);
+  {
+    auto ContinueOrErr = MPReader.read(Obj);
+    EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+    EXPECT_TRUE(*ContinueOrErr);
+    EXPECT_EQ(Obj.Kind, Type::Nil);
+  }
+  {
+    auto ContinueOrErr = MPReader.read(Obj);
+    EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+    EXPECT_TRUE(*ContinueOrErr);
+    EXPECT_EQ(Obj.Kind, Type::Boolean);
+    EXPECT_EQ(Obj.Bool, false);
+  }
+  {
+    auto ContinueOrErr = MPReader.read(Obj);
+    EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+    EXPECT_FALSE(*ContinueOrErr);
+  }
+}
+
+TEST_F(MsgPackReader, TestReadNil) {
+  Buffer = "\xc0";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Nil);
+}
+
+TEST_F(MsgPackReader, TestReadBoolFalse) {
+  Buffer = "\xc2";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Boolean);
+  EXPECT_EQ(Obj.Bool, false);
+}
+
+TEST_F(MsgPackReader, TestReadBoolTrue) {
+  Buffer = "\xc3";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Boolean);
+  EXPECT_EQ(Obj.Bool, true);
+}
+
+TEST_F(MsgPackReader, TestReadFixNegativeInt) {
+  // Positive values will be written in a UInt form, so max FixNegativeInt is -1
+  //
+  // FixNegativeInt form bitpattern starts with 111, so min FixNegativeInt
+  // is 11100000 = -32
+  for (int8_t i = -1; i >= -32; --i) {
+    Buffer.assign(1, static_cast<char>(i));
+    Reader MPReader(Buffer);
+    auto ContinueOrErr = MPReader.read(Obj);
+    EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+    EXPECT_TRUE(*ContinueOrErr);
+    EXPECT_EQ(Obj.Kind, Type::Int);
+    EXPECT_EQ(Obj.Int, i);
+  }
+}
+
+TEST_F(MsgPackReader, TestReadInt8Max) {
+  Buffer = "\xd0\x7f";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, INT8_MAX);
+}
+
+TEST_F(MsgPackReader, TestReadInt8Zero) {
+  Buffer.assign("\xd0\x00", 2);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, 0);
+}
+
+TEST_F(MsgPackReader, TestReadInt8Min) {
+  Buffer = "\xd0\x80";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, INT8_MIN);
+}
+
+TEST_F(MsgPackReader, TestReadInt16Max) {
+  Buffer = "\xd1\x7f\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, INT16_MAX);
+}
+
+TEST_F(MsgPackReader, TestReadInt16Zero) {
+  Buffer.assign("\xd1\x00\x00", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, 0);
+}
+
+TEST_F(MsgPackReader, TestReadInt16Min) {
+  Buffer.assign("\xd1\x80\x00", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, INT16_MIN);
+}
+
+TEST_F(MsgPackReader, TestReadInt32Max) {
+  Buffer = "\xd2\x7f\xff\xff\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, INT32_MAX);
+}
+
+TEST_F(MsgPackReader, TestReadInt32Zero) {
+  Buffer.assign("\xd2\x00\x00\x00\x00", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, 0);
+}
+
+TEST_F(MsgPackReader, TestReadInt32Min) {
+  Buffer.assign("\xd2\x80\x00\x00\x00", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, INT32_MIN);
+}
+
+TEST_F(MsgPackReader, TestReadInt64Max) {
+  Buffer = "\xd3\x7f\xff\xff\xff\xff\xff\xff\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, INT64_MAX);
+}
+
+TEST_F(MsgPackReader, TestReadInt64Zero) {
+  Buffer.assign("\xd3\x00\x00\x00\x00\x00\x00\x00\x00", 9);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, 0);
+}
+
+TEST_F(MsgPackReader, TestReadInt64Min) {
+  Buffer.assign("\xd3\x80\x00\x00\x00\x00\x00\x00\x00", 9);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Int);
+  EXPECT_EQ(Obj.Int, INT64_MIN);
+}
+
+TEST_F(MsgPackReader, TestReadFixPositiveInt) {
+  // FixPositiveInt form bitpattern starts with 0, so max FixPositiveInt
+  // is 01111111 = 127
+  for (uint64_t u = 0; u <= 127; ++u) {
+    Buffer.assign(1, static_cast<char>(u));
+    Reader MPReader(Buffer);
+    auto ContinueOrErr = MPReader.read(Obj);
+    EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+    EXPECT_TRUE(*ContinueOrErr);
+    EXPECT_EQ(Obj.Kind, Type::UInt);
+    EXPECT_EQ(Obj.UInt, u);
+  }
+}
+
+TEST_F(MsgPackReader, TestReadUInt8Zero) {
+  Buffer.assign("\xcc\x00", 2);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadUInt8One) {
+  Buffer = "\xcc\x01";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadUInt8Max) {
+  Buffer = "\xcc\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, static_cast<uint8_t>(UINT8_MAX));
+}
+
+TEST_F(MsgPackReader, TestReadUInt16Zero) {
+  Buffer.assign("\xcd\x00\x00", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadUInt16One) {
+  Buffer.assign("\xcd\x00\x01", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadUInt16Max) {
+  Buffer = "\xcd\xff\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, static_cast<uint16_t>(UINT16_MAX));
+}
+
+TEST_F(MsgPackReader, TestReadUInt32Zero) {
+  Buffer.assign("\xce\x00\x00\x00\x00", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadUInt32One) {
+  Buffer.assign("\xce\x00\x00\x00\x01", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadUInt32Max) {
+  Buffer = "\xce\xff\xff\xff\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, static_cast<uint32_t>(UINT32_MAX));
+}
+
+TEST_F(MsgPackReader, TestReadUInt64Zero) {
+  Buffer.assign("\xcf\x00\x00\x00\x00\x00\x00\x00\x00", 9);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadUInt64One) {
+  Buffer.assign("\xcf\x00\x00\x00\x00\x00\x00\x00\x01", 9);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadUInt64Max) {
+  Buffer = "\xcf\xff\xff\xff\xff\xff\xff\xff\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::UInt);
+  EXPECT_EQ(Obj.UInt, static_cast<uint64_t>(UINT64_MAX));
+}
+
+TEST_F(MsgPackReader, TestReadFloat32) {
+  Buffer = "\xca\xee\xee\xee\xef";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Float);
+  EXPECT_EQ(Obj.Float, -3.6973142664068907e+28f);
+}
+
+TEST_F(MsgPackReader, TestReadFloat64) {
+  Buffer = "\xcb\xee\xee\xee\xee\xee\xee\xee\xef";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Float);
+  EXPECT_EQ(Obj.Float, -2.2899894549927042e+226);
+}
+
+TEST_F(MsgPackReader, TestReadFixStrZero) {
+  Buffer = "\xa0";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, StringRef());
+}
+
+TEST_F(MsgPackReader, TestReadFixStrOne) {
+  std::string Result(1, 'a');
+  Buffer = std::string("\xa1") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadFixStrMax) {
+  // FixStr format's size is a 5 bit unsigned integer, so max is 11111 = 31
+  std::string Result(31, 'a');
+  Buffer = std::string("\xbf") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadStr8Zero) {
+  Buffer.assign("\xd9\x00", 2);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, StringRef());
+}
+
+TEST_F(MsgPackReader, TestReadStr8One) {
+  std::string Result(1, 'a');
+  Buffer = std::string("\xd9\x01") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadStr8Max) {
+  std::string Result(UINT8_MAX, 'a');
+  Buffer = std::string("\xd9\xff") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadStr16Zero) {
+  Buffer.assign("\xda\x00\x00", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, StringRef());
+}
+
+TEST_F(MsgPackReader, TestReadStr16One) {
+  std::string Result(1, 'a');
+  Buffer = std::string("\xda\x00\x01", 3) + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadStr16Max) {
+  std::string Result(UINT16_MAX, 'a');
+  Buffer = std::string("\xda\xff\xff") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadStr32Zero) {
+  Buffer.assign("\xdb\x00\x00\x00\x00", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, StringRef());
+}
+
+TEST_F(MsgPackReader, TestReadStr32One) {
+  std::string Result(1, 'a');
+  Buffer = std::string("\xdb\x00\x00\x00\x01", 5) + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadStr32Max) {
+  std::string Result(static_cast<uint32_t>(UINT16_MAX) + 1, 'a');
+  Buffer = std::string("\xdb\x00\x01\x00\x00", 5) + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::String);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadBin8Zero) {
+  Buffer.assign("\xc4\x00", 2);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Binary);
+  EXPECT_EQ(Obj.Raw, StringRef());
+}
+
+TEST_F(MsgPackReader, TestReadBin8One) {
+  std::string Result(1, 'a');
+  Buffer = std::string("\xc4\x01") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Binary);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadBin8Max) {
+  std::string Result(UINT8_MAX, 'a');
+  Buffer = std::string("\xc4\xff") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Binary);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadBin16Zero) {
+  Buffer.assign("\xc5\x00\x00", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Binary);
+  EXPECT_EQ(Obj.Raw, StringRef());
+}
+
+TEST_F(MsgPackReader, TestReadBin16One) {
+  std::string Result(1, 'a');
+  Buffer = std::string("\xc5\x00\x01", 3) + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Binary);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadBin16Max) {
+  std::string Result(UINT16_MAX, 'a');
+  Buffer = std::string("\xc5\xff\xff") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Binary);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadBin32Zero) {
+  Buffer.assign("\xc6\x00\x00\x00\x00", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Binary);
+  EXPECT_EQ(Obj.Raw, StringRef());
+}
+
+TEST_F(MsgPackReader, TestReadBin32One) {
+  std::string Result(1, 'a');
+  Buffer = std::string("\xc6\x00\x00\x00\x01", 5) + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Binary);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadBin32Max) {
+  std::string Result(static_cast<uint32_t>(UINT16_MAX) + 1, 'a');
+  Buffer = std::string("\xc6\x00\x01\x00\x00", 5) + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Binary);
+  EXPECT_EQ(Obj.Raw, Result);
+}
+
+TEST_F(MsgPackReader, TestReadFixArrayZero) {
+  Buffer = "\x90";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Array);
+  EXPECT_EQ(Obj.Length, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadFixArrayOne) {
+  Buffer = "\x91";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Array);
+  EXPECT_EQ(Obj.Length, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadFixArrayMax) {
+  Buffer = "\x9f";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Array);
+  // FixArray format's size is a 4 bit unsigned integer, so max is 1111 = 15
+  EXPECT_EQ(Obj.Length, 15u);
+}
+
+TEST_F(MsgPackReader, TestReadArray16Zero) {
+  Buffer.assign("\xdc\x00\x00", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Array);
+  EXPECT_EQ(Obj.Length, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadArray16One) {
+  Buffer.assign("\xdc\x00\x01", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Array);
+  EXPECT_EQ(Obj.Length, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadArray16Max) {
+  Buffer = "\xdc\xff\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Array);
+  EXPECT_EQ(Obj.Length, static_cast<uint16_t>(UINT16_MAX));
+}
+
+TEST_F(MsgPackReader, TestReadArray32Zero) {
+  Buffer.assign("\xdd\x00\x00\x00\x00", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Array);
+  EXPECT_EQ(Obj.Length, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadArray32One) {
+  Buffer.assign("\xdd\x00\x00\x00\x01", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Array);
+  EXPECT_EQ(Obj.Length, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadArray32Max) {
+  Buffer = "\xdd\xff\xff\xff\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Array);
+  EXPECT_EQ(Obj.Length, static_cast<uint32_t>(UINT32_MAX));
+}
+
+TEST_F(MsgPackReader, TestReadFixMapZero) {
+  Buffer = "\x80";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Map);
+  EXPECT_EQ(Obj.Length, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadFixMapOne) {
+  Buffer = "\x81";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Map);
+  EXPECT_EQ(Obj.Length, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadFixMapMax) {
+  Buffer = "\x8f";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Map);
+  // FixMap format's size is a 4 bit unsigned integer, so max is 1111 = 15
+  EXPECT_EQ(Obj.Length, 15u);
+}
+
+TEST_F(MsgPackReader, TestReadMap16Zero) {
+  Buffer.assign("\xde\x00\x00", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Map);
+  EXPECT_EQ(Obj.Length, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadMap16One) {
+  Buffer.assign("\xde\x00\x01", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Map);
+  EXPECT_EQ(Obj.Length, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadMap16Max) {
+  Buffer = "\xde\xff\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Map);
+  EXPECT_EQ(Obj.Length, static_cast<uint16_t>(UINT16_MAX));
+}
+
+TEST_F(MsgPackReader, TestReadMap32Zero) {
+  Buffer.assign("\xdf\x00\x00\x00\x00", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Map);
+  EXPECT_EQ(Obj.Length, 0u);
+}
+
+TEST_F(MsgPackReader, TestReadMap32One) {
+  Buffer.assign("\xdf\x00\x00\x00\x01", 5);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Map);
+  EXPECT_EQ(Obj.Length, 1u);
+}
+
+TEST_F(MsgPackReader, TestReadMap32Max) {
+  Buffer = "\xdf\xff\xff\xff\xff";
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Map);
+  EXPECT_EQ(Obj.Length, static_cast<uint32_t>(UINT32_MAX));
+}
+
+// FixExt formats are only available for these specific lengths: 1, 2, 4, 8, 16
+
+TEST_F(MsgPackReader, TestReadFixExt1) {
+  std::string Result(1, 'a');
+  Buffer = std::string("\xd4\x01") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, Result);
+}
+
+TEST_F(MsgPackReader, TestReadFixExt2) {
+  std::string Result(2, 'a');
+  Buffer = std::string("\xd5\x01") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, Result);
+}
+
+TEST_F(MsgPackReader, TestReadFixExt4) {
+  std::string Result(4, 'a');
+  Buffer = std::string("\xd6\x01") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, Result);
+}
+
+TEST_F(MsgPackReader, TestReadFixExt8) {
+  std::string Result(8, 'a');
+  Buffer = std::string("\xd7\x01") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, Result);
+}
+
+TEST_F(MsgPackReader, TestReadFixExt16) {
+  std::string Result(16, 'a');
+  Buffer = std::string("\xd8\x01") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, Result);
+}
+
+TEST_F(MsgPackReader, TestReadExt8Min) {
+  // There are fix variants for sizes 1 and 2
+  Buffer.assign("\xc7\x00\x01", 3);
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, StringRef());
+}
+
+TEST_F(MsgPackReader, TestReadExt8Max) {
+  std::string Result(UINT8_MAX, 'a');
+  Buffer = std::string("\xc7\xff\x01", 3) + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, Result);
+}
+
+TEST_F(MsgPackReader, TestReadExt16Min) {
+  std::string Result(static_cast<uint16_t>(UINT8_MAX) + 1, 'a');
+  Buffer = std::string("\xc8\x01\x00\x01", 4) + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, Result);
+}
+
+TEST_F(MsgPackReader, TestReadExt16Max) {
+  std::string Result(UINT16_MAX, 'a');
+  Buffer = std::string("\xc8\xff\xff\x01") + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, Result);
+}
+
+TEST_F(MsgPackReader, TestReadExt32Min) {
+  std::string Result(static_cast<uint32_t>(UINT16_MAX) + 1, 'a');
+  Buffer = std::string("\xc9\x00\x01\x00\x00\x01", 6) + Result;
+  Reader MPReader(Buffer);
+  auto ContinueOrErr = MPReader.read(Obj);
+  EXPECT_TRUE(static_cast<bool>(ContinueOrErr));
+  EXPECT_TRUE(*ContinueOrErr);
+  EXPECT_EQ(Obj.Kind, Type::Extension);
+  EXPECT_EQ(Obj.Extension.Type, 0x01);
+  EXPECT_EQ(Obj.Extension.Bytes, Result);
+}

Added: llvm/trunk/unittests/BinaryFormat/MsgPackWriterTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/BinaryFormat/MsgPackWriterTest.cpp?rev=340457&view=auto
==============================================================================
--- llvm/trunk/unittests/BinaryFormat/MsgPackWriterTest.cpp (added)
+++ llvm/trunk/unittests/BinaryFormat/MsgPackWriterTest.cpp Wed Aug 22 14:42:50 2018
@@ -0,0 +1,523 @@
+//===- MsgPackWriterTest.cpp ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/MsgPackWriter.h"
+#include "llvm/BinaryFormat/MsgPack.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::msgpack;
+
+struct MsgPackWriter : testing::Test {
+  std::string Buffer;
+  llvm::raw_string_ostream OStream;
+  Writer MPWriter;
+
+  MsgPackWriter() : OStream(Buffer), MPWriter(OStream) {}
+};
+
+TEST_F(MsgPackWriter, TestWriteNil) {
+  MPWriter.writeNil();
+  EXPECT_EQ(OStream.str(), "\xc0");
+}
+
+TEST_F(MsgPackWriter, TestWriteBool) {
+  MPWriter.write(true);
+  MPWriter.write(false);
+  EXPECT_EQ(OStream.str(), "\xc3\xc2");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixPositiveInt) {
+  // FixPositiveInt form bitpattern starts with 0, so max FixPositiveInt
+  // is 01111111 = 127
+  for (uint64_t u = 0; u <= 127; ++u) {
+    Buffer.clear();
+    MPWriter.write(u);
+    std::string Output = OStream.str();
+    EXPECT_EQ(Output.size(), 1u);
+    EXPECT_EQ(Output.data()[0], static_cast<uint8_t>(u));
+  }
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt8Min) {
+  // See TestWriteFixPositiveInt for why 128 is the min non-fix Int8
+  uint64_t u = 128;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), "\xcc\x80");
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt8) {
+  uint64_t u = 221;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), "\xcc\xdd");
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt8Max) {
+  uint64_t u = UINT8_MAX;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), "\xcc\xff");
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt16Min) {
+  uint64_t u = static_cast<uint64_t>(UINT8_MAX) + 1;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), std::string("\xcd\x01\x00", 3));
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt16) {
+  uint64_t u = 43981;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), "\xcd\xab\xcd");
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt16Max) {
+  uint64_t u = UINT16_MAX;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), "\xcd\xff\xff");
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt32Min) {
+  uint64_t u = static_cast<uint64_t>(UINT16_MAX) + 1;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), std::string("\xce\x00\x01\x00\x00", 5));
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt32) {
+  uint64_t u = 2882400186;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), "\xce\xab\xcd\xef\xba");
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt32Max) {
+  uint64_t u = UINT32_MAX;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), "\xce\xff\xff\xff\xff");
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt64Min) {
+  uint64_t u = static_cast<uint64_t>(UINT32_MAX) + 1;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(),
+            std::string("\xcf\x00\x00\x00\x01\x00\x00\x00\x00", 9));
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt64) {
+  uint64_t u = 0x010203040506074a;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), "\xcf\x01\x02\x03\x04\x05\x06\x07\x4a");
+}
+
+TEST_F(MsgPackWriter, TestWriteUInt64Max) {
+  uint64_t u = UINT64_MAX;
+  MPWriter.write(u);
+  EXPECT_EQ(OStream.str(), "\xcf\xff\xff\xff\xff\xff\xff\xff\xff");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixNegativeInt) {
+  // Positive values will be written in a UInt form, so max FixNegativeInt is -1
+  //
+  // FixNegativeInt form bitpattern starts with 111, so min FixNegativeInt
+  // is 11100000 = -32
+  for (int64_t i = -1; i >= -32; --i) {
+    Buffer.clear();
+    MPWriter.write(i);
+    std::string Output = OStream.str();
+    EXPECT_EQ(Output.size(), 1u);
+    EXPECT_EQ(Output.data()[0], static_cast<int8_t>(i));
+  }
+}
+
+TEST_F(MsgPackWriter, TestWriteInt8Max) {
+  // See TestWriteFixNegativeInt for why -33 is the max non-fix Int8
+  int64_t i = -33;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), "\xd0\xdf");
+}
+
+TEST_F(MsgPackWriter, TestWriteInt8) {
+  int64_t i = -40;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), "\xd0\xd8");
+}
+
+TEST_F(MsgPackWriter, TestWriteInt8Min) {
+  int64_t i = INT8_MIN;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), "\xd0\x80");
+}
+
+TEST_F(MsgPackWriter, TestWriteInt16Max) {
+  int64_t i = static_cast<int64_t>(INT8_MIN) - 1;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), "\xd1\xff\x7f");
+}
+
+TEST_F(MsgPackWriter, TestWriteInt16) {
+  int64_t i = -4369;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), "\xd1\xee\xef");
+}
+
+TEST_F(MsgPackWriter, TestWriteInt16Min) {
+  int64_t i = INT16_MIN;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), std::string("\xd1\x80\x00", 3));
+}
+
+TEST_F(MsgPackWriter, TestWriteInt32Max) {
+  int64_t i = static_cast<int64_t>(INT16_MIN) - 1;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), "\xd2\xff\xff\x7f\xff");
+}
+
+TEST_F(MsgPackWriter, TestWriteInt32) {
+  int64_t i = -286331153;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), "\xd2\xee\xee\xee\xef");
+}
+
+TEST_F(MsgPackWriter, TestWriteInt32Min) {
+  int64_t i = INT32_MIN;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), std::string("\xd2\x80\x00\x00\x00", 5));
+}
+
+TEST_F(MsgPackWriter, TestWriteInt64Max) {
+  int64_t i = static_cast<int64_t>(INT32_MIN) - 1;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), "\xd3\xff\xff\xff\xff\x7f\xff\xff\xff");
+}
+
+TEST_F(MsgPackWriter, TestWriteInt64) {
+  int64_t i = -1229782938247303441;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(), "\xd3\xee\xee\xee\xee\xee\xee\xee\xef");
+}
+
+TEST_F(MsgPackWriter, TestWriteInt64Min) {
+  int64_t i = INT64_MIN;
+  MPWriter.write(i);
+  EXPECT_EQ(OStream.str(),
+            std::string("\xd3\x80\x00\x00\x00\x00\x00\x00\x00", 9));
+}
+
+TEST_F(MsgPackWriter, TestWriteFloat32) {
+  float f = -3.6973142664068907e+28;
+  MPWriter.write(f);
+  EXPECT_EQ(OStream.str(), "\xca\xee\xee\xee\xef");
+}
+
+TEST_F(MsgPackWriter, TestWriteFloat64) {
+  double d = -2.2899894549927042e+226;
+  MPWriter.write(d);
+  EXPECT_EQ(OStream.str(), "\xcb\xee\xee\xee\xee\xee\xee\xee\xef");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixStrMin) {
+  std::string s;
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), "\xa0");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixStr) {
+  std::string s = "foo";
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), "\xa3"
+                           "foo");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixStrMax) {
+  // FixStr format's size is a 5 bit unsigned integer, so max is 11111 = 31
+  std::string s(31, 'a');
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xbf") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteStr8Min) {
+  // See TestWriteFixStrMax for why 32 is the min non-fix Str8
+  std::string s(32, 'a');
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xd9\x20") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteStr8) {
+  std::string s(33, 'a');
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xd9\x21") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteStr8Max) {
+  std::string s(UINT8_MAX, 'a');
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xd9\xff") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteStr16Min) {
+  std::string s(static_cast<uint64_t>(UINT8_MAX) + 1, 'a');
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xda\x01\x00", 3) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteStr16) {
+  std::string s(511, 'a');
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xda\x01\xff") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteStr16Max) {
+  std::string s(UINT16_MAX, 'a');
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xda\xff\xff") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteStr32Min) {
+  std::string s(static_cast<uint64_t>(UINT16_MAX) + 1, 'a');
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xdb\x00\x01\x00\x00", 5) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteStr32) {
+  std::string s(131071, 'a');
+  MPWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xdb\x00\x01\xff\xff", 5) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteBin8Min) {
+  std::string s;
+  MPWriter.write(MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc4\x00", 2) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteBin8) {
+  std::string s(5, 'a');
+  MPWriter.write(MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc4\x05") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteBin8Max) {
+  std::string s(UINT8_MAX, 'a');
+  MPWriter.write(MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc4\xff") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteBin16Min) {
+  std::string s(static_cast<uint64_t>(UINT8_MAX) + 1, 'a');
+  MPWriter.write(MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc5\x01\x00", 3) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteBin16) {
+  std::string s(511, 'a');
+  MPWriter.write(MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), "\xc5\x01\xff" + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteBin16Max) {
+  std::string s(UINT16_MAX, 'a');
+  MPWriter.write(MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc5\xff\xff") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteBin32Min) {
+  std::string s(static_cast<uint64_t>(UINT16_MAX) + 1, 'a');
+  MPWriter.write(MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc6\x00\x01\x00\x00", 5) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteBin32) {
+  std::string s(131071, 'a');
+  MPWriter.write(MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc6\x00\x01\xff\xff", 5) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteFixArrayMin) {
+  MPWriter.writeArraySize(0);
+  EXPECT_EQ(OStream.str(), "\x90");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixArray) {
+  MPWriter.writeArraySize(4);
+  EXPECT_EQ(OStream.str(), "\x94");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixArrayMax) {
+  // FixArray format's size is a 4 bit unsigned integer, so max is 1111 = 15
+  MPWriter.writeArraySize(15);
+  EXPECT_EQ(OStream.str(), "\x9f");
+}
+
+TEST_F(MsgPackWriter, TestWriteArray16Min) {
+  // See TestWriteFixArrayMax for why 16 is the min non-fix Array16
+  MPWriter.writeArraySize(16);
+  EXPECT_EQ(OStream.str(), std::string("\xdc\x00\x10", 3));
+}
+
+TEST_F(MsgPackWriter, TestWriteArray16) {
+  MPWriter.writeArraySize(273);
+  EXPECT_EQ(OStream.str(), "\xdc\x01\x11");
+}
+
+TEST_F(MsgPackWriter, TestWriteArray16Max) {
+  MPWriter.writeArraySize(UINT16_MAX);
+  EXPECT_EQ(OStream.str(), "\xdc\xff\xff");
+}
+
+TEST_F(MsgPackWriter, TestWriteArray32Min) {
+  MPWriter.writeArraySize(static_cast<uint64_t>(UINT16_MAX) + 1);
+  EXPECT_EQ(OStream.str(), std::string("\xdd\x00\x01\x00\x00", 5));
+}
+
+TEST_F(MsgPackWriter, TestWriteArray32) {
+  MPWriter.writeArraySize(131071);
+  EXPECT_EQ(OStream.str(), std::string("\xdd\x00\x01\xff\xff", 5));
+}
+
+TEST_F(MsgPackWriter, TestWriteArray32Max) {
+  MPWriter.writeArraySize(UINT32_MAX);
+  EXPECT_EQ(OStream.str(), "\xdd\xff\xff\xff\xff");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixMapMin) {
+  MPWriter.writeMapSize(0);
+  EXPECT_EQ(OStream.str(), "\x80");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixMap) {
+  MPWriter.writeMapSize(4);
+  EXPECT_EQ(OStream.str(), "\x84");
+}
+
+TEST_F(MsgPackWriter, TestWriteFixMapMax) {
+  // FixMap format's size is a 4 bit unsigned integer, so max is 1111 = 15
+  MPWriter.writeMapSize(15);
+  EXPECT_EQ(OStream.str(), "\x8f");
+}
+
+TEST_F(MsgPackWriter, TestWriteMap16Min) {
+  // See TestWriteFixMapMax for why 16 is the min non-fix Map16
+  MPWriter.writeMapSize(16);
+  EXPECT_EQ(OStream.str(), std::string("\xde\x00\x10", 3));
+}
+
+TEST_F(MsgPackWriter, TestWriteMap16) {
+  MPWriter.writeMapSize(273);
+  EXPECT_EQ(OStream.str(), "\xde\x01\x11");
+}
+
+TEST_F(MsgPackWriter, TestWriteMap16Max) {
+  MPWriter.writeMapSize(UINT16_MAX);
+  EXPECT_EQ(OStream.str(), "\xde\xff\xff");
+}
+
+TEST_F(MsgPackWriter, TestWriteMap32Min) {
+  MPWriter.writeMapSize(static_cast<uint64_t>(UINT16_MAX) + 1);
+  EXPECT_EQ(OStream.str(), std::string("\xdf\x00\x01\x00\x00", 5));
+}
+
+TEST_F(MsgPackWriter, TestWriteMap32) {
+  MPWriter.writeMapSize(131071);
+  EXPECT_EQ(OStream.str(), std::string("\xdf\x00\x01\xff\xff", 5));
+}
+
+TEST_F(MsgPackWriter, TestWriteMap32Max) {
+  MPWriter.writeMapSize(UINT32_MAX);
+  EXPECT_EQ(OStream.str(), std::string("\xdf\xff\xff\xff\xff", 5));
+}
+
+// FixExt formats are only available for these specific lengths: 1, 2, 4, 8, 16
+
+TEST_F(MsgPackWriter, TestWriteFixExt1) {
+  std::string s(1, 'a');
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xd4\x01") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteFixExt2) {
+  std::string s(2, 'a');
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xd5\x01") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteFixExt4) {
+  std::string s(4, 'a');
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xd6\x01") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteFixExt8) {
+  std::string s(8, 'a');
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xd7\x01") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteFixExt16) {
+  std::string s(16, 'a');
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xd8\x01") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteExt8Min) {
+  std::string s;
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc7\x00\x01", 3) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteExt8) {
+  std::string s(0x2a, 'a');
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc7\x2a\x01") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteExt8Max) {
+  std::string s(UINT8_MAX, 'a');
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc7\xff\x01") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteExt16Min) {
+  std::string s(static_cast<uint16_t>(UINT8_MAX) + 1, 'a');
+  MPWriter.writeExt(0x02, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc8\x01\x00\x02", 4) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteExt16) {
+  std::string s(273, 'a');
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc8\x01\x11\x01") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteExt16Max) {
+  std::string s(UINT16_MAX, 'a');
+  MPWriter.writeExt(0x01, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc8\xff\xff\x01") + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteExt32Min) {
+  std::string s(static_cast<uint32_t>(UINT16_MAX) + 1, 'a');
+  MPWriter.writeExt(0x02, MemoryBufferRef(s, ""));
+  EXPECT_EQ(OStream.str(), std::string("\xc9\x00\x01\x00\x00\x02", 6) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteCompatibleNoStr8) {
+  Writer CompatWriter(OStream, true);
+  std::string s(32, 'a');
+  CompatWriter.write(s);
+  EXPECT_EQ(OStream.str(), std::string("\xda\x00\x20", 3) + s);
+}
+
+TEST_F(MsgPackWriter, TestWriteCompatibleNoBin) {
+  Writer CompatWriter(OStream, true);
+  std::string s;
+
+#ifdef GTEST_HAS_DEATH_TEST
+#ifndef NDEBUG
+  EXPECT_DEATH(CompatWriter.write(MemoryBufferRef(s, "")), "compatible mode");
+#endif
+#endif
+}




More information about the llvm-commits mailing list