1343171Sdim//===- MsgPackWriter.cpp - Simple MsgPack writer ----------------*- C++ -*-===//
2343171Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6343171Sdim//
7343171Sdim//===----------------------------------------------------------------------===//
8343171Sdim///
9343171Sdim///  \file
10343171Sdim///  This file implements a MessagePack writer.
11343171Sdim///
12343171Sdim//===----------------------------------------------------------------------===//
13343171Sdim
14343171Sdim#include "llvm/BinaryFormat/MsgPackWriter.h"
15343171Sdim#include "llvm/BinaryFormat/MsgPack.h"
16343171Sdim
17343171Sdimusing namespace llvm;
18343171Sdimusing namespace msgpack;
19343171Sdim
20343171SdimWriter::Writer(raw_ostream &OS, bool Compatible)
21343171Sdim    : EW(OS, Endianness), Compatible(Compatible) {}
22343171Sdim
23343171Sdimvoid Writer::writeNil() { EW.write(FirstByte::Nil); }
24343171Sdim
25343171Sdimvoid Writer::write(bool b) { EW.write(b ? FirstByte::True : FirstByte::False); }
26343171Sdim
27343171Sdimvoid Writer::write(int64_t i) {
28343171Sdim  if (i >= 0) {
29343171Sdim    write(static_cast<uint64_t>(i));
30343171Sdim    return;
31343171Sdim  }
32343171Sdim
33343171Sdim  if (i >= FixMin::NegativeInt) {
34343171Sdim    EW.write(static_cast<int8_t>(i));
35343171Sdim    return;
36343171Sdim  }
37343171Sdim
38343171Sdim  if (i >= INT8_MIN) {
39343171Sdim    EW.write(FirstByte::Int8);
40343171Sdim    EW.write(static_cast<int8_t>(i));
41343171Sdim    return;
42343171Sdim  }
43343171Sdim
44343171Sdim  if (i >= INT16_MIN) {
45343171Sdim    EW.write(FirstByte::Int16);
46343171Sdim    EW.write(static_cast<int16_t>(i));
47343171Sdim    return;
48343171Sdim  }
49343171Sdim
50343171Sdim  if (i >= INT32_MIN) {
51343171Sdim    EW.write(FirstByte::Int32);
52343171Sdim    EW.write(static_cast<int32_t>(i));
53343171Sdim    return;
54343171Sdim  }
55343171Sdim
56343171Sdim  EW.write(FirstByte::Int64);
57343171Sdim  EW.write(i);
58343171Sdim}
59343171Sdim
60343171Sdimvoid Writer::write(uint64_t u) {
61343171Sdim  if (u <= FixMax::PositiveInt) {
62343171Sdim    EW.write(static_cast<uint8_t>(u));
63343171Sdim    return;
64343171Sdim  }
65343171Sdim
66343171Sdim  if (u <= UINT8_MAX) {
67343171Sdim    EW.write(FirstByte::UInt8);
68343171Sdim    EW.write(static_cast<uint8_t>(u));
69343171Sdim    return;
70343171Sdim  }
71343171Sdim
72343171Sdim  if (u <= UINT16_MAX) {
73343171Sdim    EW.write(FirstByte::UInt16);
74343171Sdim    EW.write(static_cast<uint16_t>(u));
75343171Sdim    return;
76343171Sdim  }
77343171Sdim
78343171Sdim  if (u <= UINT32_MAX) {
79343171Sdim    EW.write(FirstByte::UInt32);
80343171Sdim    EW.write(static_cast<uint32_t>(u));
81343171Sdim    return;
82343171Sdim  }
83343171Sdim
84343171Sdim  EW.write(FirstByte::UInt64);
85343171Sdim  EW.write(u);
86343171Sdim}
87343171Sdim
88343171Sdimvoid Writer::write(double d) {
89343171Sdim  // If no loss of precision, encode as a Float32.
90343171Sdim  double a = std::fabs(d);
91343171Sdim  if (a >= std::numeric_limits<float>::min() &&
92343171Sdim      a <= std::numeric_limits<float>::max()) {
93343171Sdim    EW.write(FirstByte::Float32);
94343171Sdim    EW.write(static_cast<float>(d));
95343171Sdim  } else {
96343171Sdim    EW.write(FirstByte::Float64);
97343171Sdim    EW.write(d);
98343171Sdim  }
99343171Sdim}
100343171Sdim
101343171Sdimvoid Writer::write(StringRef s) {
102343171Sdim  size_t Size = s.size();
103343171Sdim
104343171Sdim  if (Size <= FixMax::String)
105343171Sdim    EW.write(static_cast<uint8_t>(FixBits::String | Size));
106343171Sdim  else if (!Compatible && Size <= UINT8_MAX) {
107343171Sdim    EW.write(FirstByte::Str8);
108343171Sdim    EW.write(static_cast<uint8_t>(Size));
109343171Sdim  } else if (Size <= UINT16_MAX) {
110343171Sdim    EW.write(FirstByte::Str16);
111343171Sdim    EW.write(static_cast<uint16_t>(Size));
112343171Sdim  } else {
113343171Sdim    assert(Size <= UINT32_MAX && "String object too long to be encoded");
114343171Sdim    EW.write(FirstByte::Str32);
115343171Sdim    EW.write(static_cast<uint32_t>(Size));
116343171Sdim  }
117343171Sdim
118343171Sdim  EW.OS << s;
119343171Sdim}
120343171Sdim
121343171Sdimvoid Writer::write(MemoryBufferRef Buffer) {
122343171Sdim  assert(!Compatible && "Attempt to write Bin format in compatible mode");
123343171Sdim
124343171Sdim  size_t Size = Buffer.getBufferSize();
125343171Sdim
126343171Sdim  if (Size <= UINT8_MAX) {
127343171Sdim    EW.write(FirstByte::Bin8);
128343171Sdim    EW.write(static_cast<uint8_t>(Size));
129343171Sdim  } else if (Size <= UINT16_MAX) {
130343171Sdim    EW.write(FirstByte::Bin16);
131343171Sdim    EW.write(static_cast<uint16_t>(Size));
132343171Sdim  } else {
133343171Sdim    assert(Size <= UINT32_MAX && "Binary object too long to be encoded");
134343171Sdim    EW.write(FirstByte::Bin32);
135343171Sdim    EW.write(static_cast<uint32_t>(Size));
136343171Sdim  }
137343171Sdim
138343171Sdim  EW.OS.write(Buffer.getBufferStart(), Size);
139343171Sdim}
140343171Sdim
141343171Sdimvoid Writer::writeArraySize(uint32_t Size) {
142343171Sdim  if (Size <= FixMax::Array) {
143343171Sdim    EW.write(static_cast<uint8_t>(FixBits::Array | Size));
144343171Sdim    return;
145343171Sdim  }
146343171Sdim
147343171Sdim  if (Size <= UINT16_MAX) {
148343171Sdim    EW.write(FirstByte::Array16);
149343171Sdim    EW.write(static_cast<uint16_t>(Size));
150343171Sdim    return;
151343171Sdim  }
152343171Sdim
153343171Sdim  EW.write(FirstByte::Array32);
154343171Sdim  EW.write(Size);
155343171Sdim}
156343171Sdim
157343171Sdimvoid Writer::writeMapSize(uint32_t Size) {
158343171Sdim  if (Size <= FixMax::Map) {
159343171Sdim    EW.write(static_cast<uint8_t>(FixBits::Map | Size));
160343171Sdim    return;
161343171Sdim  }
162343171Sdim
163343171Sdim  if (Size <= UINT16_MAX) {
164343171Sdim    EW.write(FirstByte::Map16);
165343171Sdim    EW.write(static_cast<uint16_t>(Size));
166343171Sdim    return;
167343171Sdim  }
168343171Sdim
169343171Sdim  EW.write(FirstByte::Map32);
170343171Sdim  EW.write(Size);
171343171Sdim}
172343171Sdim
173343171Sdimvoid Writer::writeExt(int8_t Type, MemoryBufferRef Buffer) {
174343171Sdim  size_t Size = Buffer.getBufferSize();
175343171Sdim
176343171Sdim  switch (Size) {
177343171Sdim  case FixLen::Ext1:
178343171Sdim    EW.write(FirstByte::FixExt1);
179343171Sdim    break;
180343171Sdim  case FixLen::Ext2:
181343171Sdim    EW.write(FirstByte::FixExt2);
182343171Sdim    break;
183343171Sdim  case FixLen::Ext4:
184343171Sdim    EW.write(FirstByte::FixExt4);
185343171Sdim    break;
186343171Sdim  case FixLen::Ext8:
187343171Sdim    EW.write(FirstByte::FixExt8);
188343171Sdim    break;
189343171Sdim  case FixLen::Ext16:
190343171Sdim    EW.write(FirstByte::FixExt16);
191343171Sdim    break;
192343171Sdim  default:
193343171Sdim    if (Size <= UINT8_MAX) {
194343171Sdim      EW.write(FirstByte::Ext8);
195343171Sdim      EW.write(static_cast<uint8_t>(Size));
196343171Sdim    } else if (Size <= UINT16_MAX) {
197343171Sdim      EW.write(FirstByte::Ext16);
198343171Sdim      EW.write(static_cast<uint16_t>(Size));
199343171Sdim    } else {
200343171Sdim      assert(Size <= UINT32_MAX && "Ext size too large to be encoded");
201343171Sdim      EW.write(FirstByte::Ext32);
202343171Sdim      EW.write(static_cast<uint32_t>(Size));
203343171Sdim    }
204343171Sdim  }
205343171Sdim
206343171Sdim  EW.write(Type);
207343171Sdim  EW.OS.write(Buffer.getBufferStart(), Size);
208343171Sdim}
209