proxygen
Dump.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <folly/io/Cursor.h>
20 
21 using namespace folly;
24 
25 namespace folly {
26 namespace bser {
27 
28 const uint8_t kMagic[2] = {0, 1};
29 
30 static void bserEncode(
31  dynamic const& dyn,
32  QueueAppender& appender,
33  const serialization_opts& opts);
34 
36  : sort_keys(false), growth_increment(8192) {}
37 
38 static const dynamic* getTemplate(
39  const serialization_opts& opts,
40  dynamic const& dynArray) {
41  if (!opts.templates.hasValue()) {
42  return nullptr;
43  }
44  const auto& templates = opts.templates.value();
45  const auto it = templates.find(&dynArray);
46  if (it == templates.end()) {
47  return nullptr;
48  }
49  return &it->second;
50 }
51 
52 static void bserEncodeInt(int64_t ival, QueueAppender& appender) {
53  /* Return the smallest size int that can store the value */
54  auto size =
55  ((ival == ((int8_t)ival))
56  ? 1
57  : (ival == ((int16_t)ival)) ? 2 : (ival == ((int32_t)ival)) ? 4 : 8);
58 
59  switch (size) {
60  case 1:
61  appender.write((int8_t)BserType::Int8);
62  appender.write(int8_t(ival));
63  return;
64  case 2:
65  appender.write((int8_t)BserType::Int16);
66  appender.write(int16_t(ival));
67  return;
68  case 4:
69  appender.write((int8_t)BserType::Int32);
70  appender.write(int32_t(ival));
71  return;
72  case 8:
73  appender.write((int8_t)BserType::Int64);
74  appender.write(ival);
75  return;
76  default:
77  throw std::runtime_error("impossible integer size");
78  }
79 }
80 
81 static void bserEncodeString(folly::StringPiece str, QueueAppender& appender) {
82  appender.write((int8_t)BserType::String);
83  bserEncodeInt(int64_t(str.size()), appender);
84  appender.push((uint8_t*)str.data(), str.size());
85 }
86 
88  dynamic const& dyn,
89  QueueAppender& appender,
90  const serialization_opts& opts) {
91  appender.write((int8_t)BserType::Array);
92  bserEncodeInt(int64_t(dyn.size()), appender);
93  for (const auto& ele : dyn) {
94  bserEncode(ele, appender, opts);
95  }
96 }
97 
98 static void bserEncodeArray(
99  dynamic const& dyn,
100  QueueAppender& appender,
101  const serialization_opts& opts) {
102  auto templ = getTemplate(opts, dyn);
103  if (UNLIKELY(templ != nullptr)) {
104  appender.write((int8_t)BserType::Template);
105 
106  // Emit the list of property names
107  bserEncodeArraySimple(*templ, appender, opts);
108 
109  // The number of objects in the array
110  bserEncodeInt(int64_t(dyn.size()), appender);
111 
112  // For each object in the array
113  for (const auto& ele : dyn) {
114  // For each key in the template
115  for (const auto& name : *templ) {
116  if (auto found = ele.get_ptr(name)) {
117  if (found->isNull()) {
118  // Prefer to Skip rather than encode a null value for
119  // compatibility with the other bser implementations
120  appender.write((int8_t)BserType::Skip);
121  } else {
122  bserEncode(*found, appender, opts);
123  }
124  } else {
125  appender.write((int8_t)BserType::Skip);
126  }
127  }
128  }
129  return;
130  }
131 
132  bserEncodeArraySimple(dyn, appender, opts);
133 }
134 
135 static void bserEncodeObject(
136  dynamic const& dyn,
137  QueueAppender& appender,
138  const serialization_opts& opts) {
139  appender.write((int8_t)BserType::Object);
140  bserEncodeInt(int64_t(dyn.size()), appender);
141 
142  if (opts.sort_keys) {
143  std::vector<std::pair<dynamic, dynamic>> sorted(
144  dyn.items().begin(), dyn.items().end());
145  std::sort(sorted.begin(), sorted.end());
146  for (const auto& item : sorted) {
147  bserEncode(item.first, appender, opts);
148  bserEncode(item.second, appender, opts);
149  }
150  } else {
151  for (const auto& item : dyn.items()) {
152  bserEncode(item.first, appender, opts);
153  bserEncode(item.second, appender, opts);
154  }
155  }
156 }
157 
158 static void bserEncode(
159  dynamic const& dyn,
160  QueueAppender& appender,
161  const serialization_opts& opts) {
162  switch (dyn.type()) {
163  case dynamic::Type::NULLT:
164  appender.write((int8_t)BserType::Null);
165  return;
166  case dynamic::Type::BOOL:
167  appender.write(
169  return;
170  case dynamic::Type::DOUBLE: {
171  double dval = dyn.getDouble();
172  appender.write((int8_t)BserType::Real);
173  appender.write(dval);
174  return;
175  }
176  case dynamic::Type::INT64:
177  bserEncodeInt(dyn.getInt(), appender);
178  return;
179  case dynamic::Type::OBJECT:
180  bserEncodeObject(dyn, appender, opts);
181  return;
182  case dynamic::Type::ARRAY:
183  bserEncodeArray(dyn, appender, opts);
184  return;
186  bserEncodeString(dyn.getString(), appender);
187  return;
188  }
189 }
190 
191 std::unique_ptr<folly::IOBuf> toBserIOBuf(
192  folly::dynamic const& dyn,
193  const serialization_opts& opts) {
195  uint8_t hdrbuf[sizeof(kMagic) + 1 + sizeof(int64_t)];
196 
197  // Reserve some headroom for the overall PDU size; we'll fill this in
198  // after we've serialized the data and know the length
199  auto firstbuf = IOBuf::create(opts.growth_increment);
200  firstbuf->advance(sizeof(hdrbuf));
201  q.append(std::move(firstbuf));
202 
203  // encode the value
204  QueueAppender appender(&q, opts.growth_increment);
205  bserEncode(dyn, appender, opts);
206 
207  // compute the length
208  auto len = q.chainLength();
210  throw std::range_error(folly::to<std::string>(
211  "serialized data size ", len, " is too large to represent as BSER"));
212  }
213 
214  // This is a bit verbose, but it computes a header that is appropriate
215  // to the size of the serialized data
216 
217  memcpy(hdrbuf, kMagic, sizeof(kMagic));
218  size_t hdrlen = sizeof(kMagic) + 1;
219  auto magicptr = hdrbuf + sizeof(kMagic);
220  auto lenptr = hdrbuf + hdrlen;
221 
223  *magicptr = (int8_t)BserType::Int64;
224  *(int64_t*)lenptr = (int64_t)len;
225  hdrlen += sizeof(int64_t);
226  } else if (len > uint64_t(std::numeric_limits<int16_t>::max())) {
227  *magicptr = (int8_t)BserType::Int32;
228  *(int32_t*)lenptr = (int32_t)len;
229  hdrlen += sizeof(int32_t);
230  } else if (len > uint64_t(std::numeric_limits<int8_t>::max())) {
231  *magicptr = (int8_t)BserType::Int16;
232  *(int16_t*)lenptr = (int16_t)len;
233  hdrlen += sizeof(int16_t);
234  } else {
235  *magicptr = (int8_t)BserType::Int8;
236  *(int8_t*)lenptr = (int8_t)len;
237  hdrlen += sizeof(int8_t);
238  }
239 
240  // and place the data in the headroom
241  q.prepend(hdrbuf, hdrlen);
242 
243  return q.move();
244 }
245 
246 fbstring toBser(dynamic const& dyn, const serialization_opts& opts) {
247  auto buf = toBserIOBuf(dyn, opts);
248  return buf->moveToFbString();
249 }
250 } // namespace bser
251 } // namespace folly
252 
253 /* vim:ts=2:sw=2:et:
254  */
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
size_t chainLength() const
Definition: IOBufQueue.h:492
void prepend(const void *buf, std::size_t n)
Definition: IOBufQueue.cpp:132
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
LogLevel max
Definition: LogLevel.cpp:31
double getDouble() const &
Definition: dynamic-inl.h:534
static void bserEncodeString(folly::StringPiece str, QueueAppender &appender)
Definition: Dump.cpp:81
std::enable_if< std::is_arithmetic< T >::value >::type write(T value)
Definition: Cursor.h:1137
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
constexpr size_type size() const
Definition: Range.h:431
void push(const uint8_t *buf, size_t len)
Definition: Cursor.h:755
const std::string & getString() const &
Definition: dynamic-inl.h:531
std::unique_ptr< folly::IOBuf > move()
Definition: IOBufQueue.h:459
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
#define STRING
static const dynamic * getTemplate(const serialization_opts &opts, dynamic const &dynArray)
Definition: Dump.cpp:38
const char * name
Definition: http_parser.c:437
int64_t getInt() const &
Definition: dynamic-inl.h:537
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
static void bserEncodeInt(int64_t ival, QueueAppender &appender)
Definition: Dump.cpp:52
static Options cacheChainLength()
Definition: IOBufQueue.h:83
constexpr Iter data() const
Definition: Range.h:446
FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept
Definition: Optional.h:300
static void bserEncodeArray(dynamic const &dyn, QueueAppender &appender, const serialization_opts &opts)
Definition: Dump.cpp:98
std::unique_ptr< folly::IOBuf > toBserIOBuf(folly::dynamic const &, const serialization_opts &)
Definition: Dump.cpp:191
static void bserEncodeObject(dynamic const &dyn, QueueAppender &appender, const serialization_opts &opts)
Definition: Dump.cpp:135
static void bserEncode(dynamic const &dyn, QueueAppender &appender, const serialization_opts &opts)
Definition: Dump.cpp:158
IterableProxy< const_item_iterator > items() const
Definition: dynamic-inl.h:476
std::size_t size() const
Definition: dynamic.cpp:275
static void bserEncodeArraySimple(dynamic const &dyn, QueueAppender &appender, const serialization_opts &opts)
Definition: Dump.cpp:87
folly::Optional< TemplateMap > templates
Definition: Bser.h:82
bool getBool() const &
Definition: dynamic-inl.h:540
FOLLY_CPP14_CONSTEXPR const Value & value() const &
Definition: Optional.h:268
Type type() const
Definition: dynamic-inl.h:514
folly::fbstring toBser(folly::dynamic const &, const serialization_opts &)
Definition: Dump.cpp:246
#define UNLIKELY(x)
Definition: Likely.h:48
const uint8_t kMagic[2]
Definition: Dump.cpp:28