blob: e79d4f1deb37d7f6bac5027633c69d3982edb649 [file] [log] [blame]
David Reiss4e7530d2007-09-04 21:49:53 +00001// Copyright (c) 2006- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
David Reissce161a92007-09-11 22:09:42 +00007/*
8
9IMPLEMENTATION DETAILS
10
11TDenseProtocol was designed to have a smaller serialized form than
12TBinaryProtocol. This is accomplished using two techniques. The first is
13variable-length integer encoding. We use the same technique that the Standard
14MIDI File format uses for "variable-length quantities"
15(http://en.wikipedia.org/wiki/Variable-length_quantity).
16All integers (including i16, but not byte) are first cast to uint64_t,
17then written out as variable-length quantities. This has the unfortunate side
18effect that all negative numbers require 10 bytes, but negative numbers tend
19to be far less common than positive ones.
20
21The second technique eliminating the field ids used by TBinaryProtocol. This
22decision required support from the Thrift compiler and also sacrifices some of
23the backward and forward compatibility of TBinaryProtocol.
24
25We considered implementing this technique by generating separate readers and
26writers for the dense protocol (this is how Pillar, Thrift's predecessor,
27worked), but this idea had a few problems:
28- Our abstractions go out the window.
29- We would have to maintain a second code generator.
30- Preserving compatibility with old versions of the structures would be a
31 nightmare.
32
33Therefore, we chose an alternate implementation that stored the description of
34the data neither in the data itself (like TBinaryProtocol) nor in the
35serialization code (like Pillar), but instead in a separate data structure,
36called a TypeSpec. TypeSpecs are generated by the Thrift compiler
37(specifically in the t_cpp_generator), and their structure should be
38documented there (TODO(dreiss): s/should be/is/).
39
40We maintain a stack of TypeSpecs within the protocol so it knows where the
41generated code is in the reading/writing process. For example, if we are
42writing an i32 contained in a struct bar, contained in a struct foo, then the
43stack would look like: TOP , i32 , struct bar , struct foo , BOTTOM.
44The following invariant: whenever we are about to read/write an object
45(structBegin, containerBegin, or a scalar), the TypeSpec on the top of the
46stack must match the type being read/written. The main reasons that this
47invariant must be maintained is that if we ever start reading a structure, we
48must have its exact TypeSpec in order to pass the right tags to the
49deserializer.
50
51We use the following strategies for maintaining this invariant:
52
53- For structures, we have a separate stack of indexes, one for each structure
54 on the TypeSpec stack. These are indexes into the list of fields in the
55 structure's TypeSpec. When we {read,write}FieldBegin, we push on the
56 TypeSpec for the field.
57- When we begin writing a list or set, we push on the TypeSpec for the
58 element type.
59- For maps, we have a separate stack of booleans, one for each map on the
60 TypeSpec stack. The boolean is true if we are writing the key for that
61 map, and false if we are writing the value. Maps are the trickiest case
62 because the generated code does not call any protocol method between
63 the key and the value. As a result, we potentially have to switch
64 between map key state and map value state after reading/writing any object.
65- This job is handled by the stateTransition method. It is called after
66 reading/writing every object. It pops the current TypeSpec off the stack,
67 then optionally pushes a new one on, depending on what the next TypeSpec is.
68 If it is a struct, the job is left to the next writeFieldBegin. If it is a
69 set or list, the just-popped typespec is pushed back on. If it is a map,
70 the top of the key/value stack is toggled, and the appropriate TypeSpec
71 is pushed.
72
73Optional fields are a little tricky also. We write a zero byte if they are
74absent and prefix them with an 0x01 byte if they are present
75*/
76
David Reisse67c0e62007-09-07 01:34:12 +000077#define __STDC_LIMIT_MACROS
78#include <stdint.h>
David Reiss4e7530d2007-09-04 21:49:53 +000079#include "TDenseProtocol.h"
80#include "TReflectionLocal.h"
81
David Reissce161a92007-09-11 22:09:42 +000082// Leaving this on for now. Disabling it will turn off asserts, which should
83// give a performance boost. When we have *really* thorough test cases,
84// we should drop this.
David Reiss4e7530d2007-09-04 21:49:53 +000085#define DEBUG_TDENSEPROTOCOL
86
David Reissce161a92007-09-11 22:09:42 +000087// NOTE: Assertions should *only* be used to detect bugs in code,
88// either in TDenseProtocol itself, or in code using it.
89// (For example, using the wrong TypeSpec.)
90// Invalid data should NEVER cause an assertion failure,
91// no matter how grossly corrupted, nor how ingeniously crafted.
David Reiss4e7530d2007-09-04 21:49:53 +000092#ifdef DEBUG_TDENSEPROTOCOL
93#undef NDEBUG
David Reissce161a92007-09-11 22:09:42 +000094#else
95#define NDEBUG
David Reiss4e7530d2007-09-04 21:49:53 +000096#endif
97#include <cassert>
98
99using std::string;
100
David Reisse67c0e62007-09-07 01:34:12 +0000101#ifdef __GNUC__
102#define UNLIKELY(val) (__builtin_expect((val), 0))
103#else
104#define UNLIKELY(val) (val)
105#endif
106
David Reiss4e7530d2007-09-04 21:49:53 +0000107namespace facebook { namespace thrift { namespace protocol {
108
David Reissce161a92007-09-11 22:09:42 +0000109const int TDenseProtocol::FP_PREFIX_LEN =
110 facebook::thrift::reflection::local::FP_PREFIX_LEN;
111
David Reiss4e7530d2007-09-04 21:49:53 +0000112// Top TypeSpec. TypeSpec of the structure being encoded.
113#define TTS (ts_stack_.back()) // type = TypeSpec*
114// InDeX. Index into TTS of the current/next field to encode.
115#define IDX (idx_stack_.back()) // type = int
116// Field TypeSpec. TypeSpec of the current/next field to encode.
117#define FTS (TTS->tstruct.specs[IDX]) // type = TypeSpec*
118// Field MeTa. Metadata of the current/next field to encode.
119#define FMT (TTS->tstruct.metas[IDX]) // type = FieldMeta
120// SubType 1/2. TypeSpec of the first/second subtype of this container.
121#define ST1 (TTS->tcontainer.subtype1)
122#define ST2 (TTS->tcontainer.subtype2)
123
124
David Reissce161a92007-09-11 22:09:42 +0000125/**
126 * Checks that @c ttype is indeed the ttype that we should be writing,
127 * according to our typespec. Aborts if the test fails and debugging in on.
128 */
David Reiss4e7530d2007-09-04 21:49:53 +0000129inline void TDenseProtocol::checkTType(const TType ttype) {
130 assert(!ts_stack_.empty());
131 assert(TTS->ttype == ttype);
132}
133
David Reissce161a92007-09-11 22:09:42 +0000134/**
135 * Makes sure that the TypeSpec stack is correct for the next object.
136 * See top-of-file comments.
137 */
David Reiss4e7530d2007-09-04 21:49:53 +0000138inline void TDenseProtocol::stateTransition() {
139 TypeSpec* old_tts = ts_stack_.back();
140 ts_stack_.pop_back();
141
David Reissce161a92007-09-11 22:09:42 +0000142 // If this is the end of the top-level write, we should have just popped
143 // the TypeSpec passed to the constructor.
David Reiss4e7530d2007-09-04 21:49:53 +0000144 if (ts_stack_.empty()) {
145 assert(old_tts = type_spec_);
146 return;
147 }
148
149 switch (TTS->ttype) {
150
151 case T_STRUCT:
152 assert(old_tts == FTS);
153 break;
154
155 case T_LIST:
156 case T_SET:
157 assert(old_tts == ST1);
158 ts_stack_.push_back(old_tts);
159 break;
160
161 case T_MAP:
162 assert(old_tts == (mkv_stack_.back() ? ST1 : ST2));
163 mkv_stack_.back() = !mkv_stack_.back();
164 ts_stack_.push_back(mkv_stack_.back() ? ST1 : ST2);
165 break;
166
167 default:
168 assert(!"Invalid TType in stateTransition.");
169 break;
170
171 }
172}
173
David Reissce161a92007-09-11 22:09:42 +0000174
175/*
176 * Variable-length quantity functions.
177 */
178
179inline uint32_t TDenseProtocol::vlqRead(uint64_t& vlq) {
180 uint32_t used = 0;
181 uint64_t val = 0;
182 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
183 bool borrowed = trans_->borrow(buf, sizeof(buf));
184
185 // Fast path. TODO(dreiss): Make it faster.
186 if (borrowed) {
187 while (true) {
188 uint8_t byte = buf[used];
189 used++;
190 val = (val << 7) | (byte & 0x7f);
191 if (!(byte & 0x80)) {
192 vlq = val;
193 trans_->consume(used);
194 return used;
195 }
196 // Have to check for invalid data so we don't crash.
197 if (UNLIKELY(used == sizeof(buf))) {
198 resetState();
199 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
200 }
201 }
202 }
203
204 // Slow path.
205 else {
206 while (true) {
207 uint8_t byte;
208 used += trans_->readAll(&byte, 1);
209 val = (val << 7) | (byte & 0x7f);
210 if (!(byte & 0x80)) {
211 vlq = val;
212 return used;
213 }
214 // Might as well check for invalid data on the slow path too.
215 if (UNLIKELY(used >= sizeof(buf))) {
216 resetState();
217 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
218 }
219 }
220 }
221}
222
223inline uint32_t TDenseProtocol::vlqWrite(uint64_t vlq) {
224 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
225 int32_t pos = sizeof(buf) - 1;
226
227 // Write the thing from back to front.
228 buf[pos] = vlq & 0x7f;
229 vlq >>= 7;
230 pos--;
231
232 while (vlq > 0) {
233 assert(pos >= 0);
234 buf[pos] = (vlq | 0x80);
235 vlq >>= 7;
236 pos--;
237 }
238
239 // Back up one step before writing.
240 pos++;
241
242 trans_->write(buf+pos, sizeof(buf) - pos);
243 return sizeof(buf) - pos;
244}
245
246
247
248/*
249 * Writing functions.
250 */
251
David Reiss4e7530d2007-09-04 21:49:53 +0000252uint32_t TDenseProtocol::writeMessageBegin(const std::string& name,
253 const TMessageType messageType,
254 const int32_t seqid) {
David Reisse67c0e62007-09-07 01:34:12 +0000255 throw TApplicationException("TDenseProtocol doesn't work with messages (yet).");
256
David Reiss4e7530d2007-09-04 21:49:53 +0000257 int32_t version = (VERSION_2) | ((int32_t)messageType);
258 uint32_t wsize = 0;
259 wsize += subWriteI32(version);
260 wsize += subWriteString(name);
261 wsize += subWriteI32(seqid);
262 return wsize;
263}
264
265uint32_t TDenseProtocol::writeMessageEnd() {
266 return 0;
267}
268
David Reiss4e7530d2007-09-04 21:49:53 +0000269uint32_t TDenseProtocol::writeStructBegin(const string& name) {
David Reissce161a92007-09-11 22:09:42 +0000270 uint32_t xfer = 0;
271
272 // The TypeSpec stack should be empty if this is the top-level read/write.
273 // If it is, we push the TypeSpec passed to the constructor.
David Reiss4e7530d2007-09-04 21:49:53 +0000274 if (ts_stack_.empty()) {
David Reissce161a92007-09-11 22:09:42 +0000275 assert(standalone_);
276
David Reiss4e7530d2007-09-04 21:49:53 +0000277 if (type_spec_ == NULL) {
David Reissce161a92007-09-11 22:09:42 +0000278 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000279 throw TApplicationException("TDenseProtocol: No type specified.");
280 } else {
David Reissce161a92007-09-11 22:09:42 +0000281 assert(type_spec_->ttype == T_STRUCT);
David Reiss4e7530d2007-09-04 21:49:53 +0000282 ts_stack_.push_back(type_spec_);
David Reissce161a92007-09-11 22:09:42 +0000283 // Write out a prefix of the structure fingerprint.
284 trans_->write(type_spec_->fp_prefix, FP_PREFIX_LEN);
285 xfer += FP_PREFIX_LEN;
David Reiss4e7530d2007-09-04 21:49:53 +0000286 }
287 }
288
David Reissce161a92007-09-11 22:09:42 +0000289 // We need a new field index for this structure.
David Reiss4e7530d2007-09-04 21:49:53 +0000290 idx_stack_.push_back(0);
291 return 0;
292}
293
294uint32_t TDenseProtocol::writeStructEnd() {
295 idx_stack_.pop_back();
296 stateTransition();
297 return 0;
298}
299
300uint32_t TDenseProtocol::writeFieldBegin(const string& name,
301 const TType fieldType,
302 const int16_t fieldId) {
303 uint32_t xfer = 0;
304
David Reissce161a92007-09-11 22:09:42 +0000305 // Skip over optional fields.
David Reiss4e7530d2007-09-04 21:49:53 +0000306 while (FMT.tag != fieldId) {
307 // TODO(dreiss): Old meta here.
308 assert(FTS->ttype != T_STOP);
309 assert(FMT.is_optional);
David Reissce161a92007-09-11 22:09:42 +0000310 // Write a zero byte so the reader can skip it.
David Reiss4e7530d2007-09-04 21:49:53 +0000311 xfer += subWriteBool(false);
David Reissce161a92007-09-11 22:09:42 +0000312 // And advance to the next field.
David Reiss4e7530d2007-09-04 21:49:53 +0000313 IDX++;
314 }
315
316 // TODO(dreiss): give a better exception.
317 assert(FTS->ttype == fieldType);
318
319 if (FMT.is_optional) {
320 subWriteBool(true);
321 xfer += 1;
322 }
323
David Reissce161a92007-09-11 22:09:42 +0000324 // writeFieldStop shares all lot of logic up to this point.
325 // Instead of replicating it all, we just call this method from that one
326 // and use a gross special case here.
327 if (UNLIKELY(FTS->ttype != T_STOP)) {
328 // For normal fields, push the TypeSpec that we're about to use.
David Reiss4e7530d2007-09-04 21:49:53 +0000329 ts_stack_.push_back(FTS);
330 }
331 return xfer;
332}
333
334uint32_t TDenseProtocol::writeFieldEnd() {
David Reissce161a92007-09-11 22:09:42 +0000335 // Just move on to the next field.
David Reiss4e7530d2007-09-04 21:49:53 +0000336 IDX++;
337 return 0;
338}
339
340uint32_t TDenseProtocol::writeFieldStop() {
David Reissce161a92007-09-11 22:09:42 +0000341 return TDenseProtocol::writeFieldBegin("", T_STOP, 0);
David Reiss4e7530d2007-09-04 21:49:53 +0000342}
343
344uint32_t TDenseProtocol::writeMapBegin(const TType keyType,
345 const TType valType,
346 const uint32_t size) {
347 checkTType(T_MAP);
348
349 assert(keyType == ST1->ttype);
350 assert(valType == ST2->ttype);
351
352 ts_stack_.push_back(ST1);
353 mkv_stack_.push_back(true);
354
355 return subWriteI32((int32_t)size);
356}
357
358uint32_t TDenseProtocol::writeMapEnd() {
David Reissce161a92007-09-11 22:09:42 +0000359 // Pop off the value type, as well as our entry in the map key/value stack.
360 // stateTransition takes care of popping off our TypeSpec.
David Reiss4e7530d2007-09-04 21:49:53 +0000361 ts_stack_.pop_back();
362 mkv_stack_.pop_back();
363 stateTransition();
364 return 0;
365}
366
367uint32_t TDenseProtocol::writeListBegin(const TType elemType,
368 const uint32_t size) {
369 checkTType(T_LIST);
370
371 assert(elemType == ST1->ttype);
372 ts_stack_.push_back(ST1);
373 return subWriteI32((int32_t)size);
374}
375
376uint32_t TDenseProtocol::writeListEnd() {
David Reissce161a92007-09-11 22:09:42 +0000377 // Pop off the element type. stateTransition takes care of popping off ours.
David Reiss4e7530d2007-09-04 21:49:53 +0000378 ts_stack_.pop_back();
379 stateTransition();
380 return 0;
381}
382
383uint32_t TDenseProtocol::writeSetBegin(const TType elemType,
384 const uint32_t size) {
385 checkTType(T_SET);
386
387 assert(elemType == ST1->ttype);
388 ts_stack_.push_back(ST1);
389 return subWriteI32((int32_t)size);
390}
391
392uint32_t TDenseProtocol::writeSetEnd() {
David Reissce161a92007-09-11 22:09:42 +0000393 // Pop off the element type. stateTransition takes care of popping off ours.
David Reiss4e7530d2007-09-04 21:49:53 +0000394 ts_stack_.pop_back();
395 stateTransition();
396 return 0;
397}
398
399uint32_t TDenseProtocol::writeBool(const bool value) {
400 checkTType(T_BOOL);
401 stateTransition();
402 return TBinaryProtocol::writeBool(value);
403}
404
405uint32_t TDenseProtocol::writeByte(const int8_t byte) {
406 checkTType(T_BYTE);
407 stateTransition();
408 return TBinaryProtocol::writeByte(byte);
409}
410
David Reiss4e7530d2007-09-04 21:49:53 +0000411uint32_t TDenseProtocol::writeI16(const int16_t i16) {
David Reiss4e7530d2007-09-04 21:49:53 +0000412 checkTType(T_I16);
413 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000414 return vlqWrite(i16);
David Reiss4e7530d2007-09-04 21:49:53 +0000415}
416
417uint32_t TDenseProtocol::writeI32(const int32_t i32) {
David Reiss4e7530d2007-09-04 21:49:53 +0000418 checkTType(T_I32);
419 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000420 return vlqWrite(i32);
David Reiss4e7530d2007-09-04 21:49:53 +0000421}
422
423uint32_t TDenseProtocol::writeI64(const int64_t i64) {
David Reiss4e7530d2007-09-04 21:49:53 +0000424 checkTType(T_I64);
425 stateTransition();
David Reissce161a92007-09-11 22:09:42 +0000426 return vlqWrite(i64);
David Reiss4e7530d2007-09-04 21:49:53 +0000427}
428
429uint32_t TDenseProtocol::writeDouble(const double dub) {
430 checkTType(T_DOUBLE);
431 stateTransition();
432 return TBinaryProtocol::writeDouble(dub);
433}
434
435uint32_t TDenseProtocol::writeString(const std::string& str) {
436 checkTType(T_STRING);
437 stateTransition();
438 return subWriteString(str);
439}
440
David Reiss4e7530d2007-09-04 21:49:53 +0000441inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
David Reissce161a92007-09-11 22:09:42 +0000442 return vlqWrite(i32);
David Reiss4e7530d2007-09-04 21:49:53 +0000443}
444
David Reiss4e7530d2007-09-04 21:49:53 +0000445uint32_t TDenseProtocol::subWriteString(const std::string& str) {
446 uint32_t size = str.size();
447 uint32_t xfer = subWriteI32((int32_t)size);
448 if (size > 0) {
449 trans_->write((uint8_t*)str.data(), size);
450 }
451 return xfer + size;
452}
453
David Reisse67c0e62007-09-07 01:34:12 +0000454
David Reisse67c0e62007-09-07 01:34:12 +0000455
David Reissce161a92007-09-11 22:09:42 +0000456/*
David Reiss4e7530d2007-09-04 21:49:53 +0000457 * Reading functions
David Reissce161a92007-09-11 22:09:42 +0000458 *
459 * These have a lot of the same logic as the writing functions, so if
460 * something is confusing, look for comments in the corresponding writer.
David Reiss4e7530d2007-09-04 21:49:53 +0000461 */
462
463uint32_t TDenseProtocol::readMessageBegin(std::string& name,
464 TMessageType& messageType,
465 int32_t& seqid) {
David Reisse67c0e62007-09-07 01:34:12 +0000466 throw TApplicationException("TDenseProtocol doesn't work with messages (yet).");
467
David Reiss4e7530d2007-09-04 21:49:53 +0000468 uint32_t xfer = 0;
469 int32_t sz;
470 xfer += subReadI32(sz);
471
472 if (sz < 0) {
473 // Check for correct version number
474 int32_t version = sz & VERSION_MASK;
475 if (version != VERSION_2) {
476 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
477 }
478 messageType = (TMessageType)(sz & 0x000000ff);
479 xfer += subReadString(name);
480 xfer += subReadI32(seqid);
481 } else {
482 throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
483 }
484 return xfer;
485}
486
487uint32_t TDenseProtocol::readMessageEnd() {
488 return 0;
489}
490
491uint32_t TDenseProtocol::readStructBegin(string& name) {
David Reissce161a92007-09-11 22:09:42 +0000492 uint32_t xfer = 0;
493
494 if (ts_stack_.empty()) {
495 assert(standalone_);
496
497 if (type_spec_ == NULL) {
498 resetState();
499 throw TApplicationException("TDenseProtocol: No type specified.");
500 } else {
501 assert(type_spec_->ttype == T_STRUCT);
502 ts_stack_.push_back(type_spec_);
503
504 // Check the fingerprint prefix.
505 uint8_t buf[FP_PREFIX_LEN];
506 xfer += trans_->read(buf, FP_PREFIX_LEN);
507 if (std::memcmp(buf, type_spec_->fp_prefix, FP_PREFIX_LEN) != 0) {
508 resetState();
509 throw TProtocolException(TProtocolException::INVALID_DATA,
510 "Fingerprint in data does not match type_spec.");
511 }
512 }
513 }
514
515 // We need a new field index for this structure.
516 idx_stack_.push_back(0);
517 return 0;
David Reiss4e7530d2007-09-04 21:49:53 +0000518}
519
520uint32_t TDenseProtocol::readStructEnd() {
521 idx_stack_.pop_back();
522 stateTransition();
523 return 0;
524}
525
526uint32_t TDenseProtocol::readFieldBegin(string& name,
527 TType& fieldType,
528 int16_t& fieldId) {
529 uint32_t xfer = 0;
530
David Reissce161a92007-09-11 22:09:42 +0000531 // For optional fields, check to see if they are there.
David Reiss4e7530d2007-09-04 21:49:53 +0000532 while (FMT.is_optional) {
533 bool is_present;
534 xfer += subReadBool(is_present);
535 if (is_present) {
536 break;
537 }
538 IDX++;
539 }
540
David Reissce161a92007-09-11 22:09:42 +0000541 // Once we hit a mandatory field, or an optional field that is present,
542 // we know that FMT and FTS point to the appropriate field.
543
David Reiss4e7530d2007-09-04 21:49:53 +0000544 fieldId = FMT.tag;
545 fieldType = FTS->ttype;
546
David Reissce161a92007-09-11 22:09:42 +0000547 // Normally, we push the TypeSpec that we are about to read,
548 // but no reading is done for T_STOP.
David Reiss4e7530d2007-09-04 21:49:53 +0000549 if (FTS->ttype != T_STOP) {
550 ts_stack_.push_back(FTS);
551 }
552 return xfer;
553}
554
555uint32_t TDenseProtocol::readFieldEnd() {
556 IDX++;
557 return 0;
558}
559
560uint32_t TDenseProtocol::readMapBegin(TType& keyType,
561 TType& valType,
562 uint32_t& size) {
563 checkTType(T_MAP);
564
565 uint32_t xfer = 0;
566 int32_t sizei;
567 xfer += subReadI32(sizei);
568 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000569 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000570 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
571 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000572 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000573 throw TProtocolException(TProtocolException::SIZE_LIMIT);
574 }
575 size = (uint32_t)sizei;
576
577 keyType = ST1->ttype;
578 valType = ST2->ttype;
579
580 ts_stack_.push_back(ST1);
581 mkv_stack_.push_back(true);
582
583 return xfer;
584}
585
586uint32_t TDenseProtocol::readMapEnd() {
587 ts_stack_.pop_back();
588 mkv_stack_.pop_back();
589 stateTransition();
590 return 0;
591}
592
593uint32_t TDenseProtocol::readListBegin(TType& elemType,
594 uint32_t& size) {
595 checkTType(T_LIST);
596
597 uint32_t xfer = 0;
598 int32_t sizei;
599 xfer += subReadI32(sizei);
600 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000601 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000602 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
603 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000604 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000605 throw TProtocolException(TProtocolException::SIZE_LIMIT);
606 }
607 size = (uint32_t)sizei;
608
609 elemType = ST1->ttype;
610
611 ts_stack_.push_back(ST1);
612
613 return xfer;
614}
615
616uint32_t TDenseProtocol::readListEnd() {
617 ts_stack_.pop_back();
618 stateTransition();
619 return 0;
620}
621
622uint32_t TDenseProtocol::readSetBegin(TType& elemType,
623 uint32_t& size) {
624 checkTType(T_SET);
625
626 uint32_t xfer = 0;
627 int32_t sizei;
628 xfer += subReadI32(sizei);
629 if (sizei < 0) {
David Reissce161a92007-09-11 22:09:42 +0000630 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000631 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
632 } else if (container_limit_ && sizei > container_limit_) {
David Reissce161a92007-09-11 22:09:42 +0000633 resetState();
David Reiss4e7530d2007-09-04 21:49:53 +0000634 throw TProtocolException(TProtocolException::SIZE_LIMIT);
635 }
636 size = (uint32_t)sizei;
637
638 elemType = ST1->ttype;
639
640 ts_stack_.push_back(ST1);
641
642 return xfer;
643}
644
645uint32_t TDenseProtocol::readSetEnd() {
646 ts_stack_.pop_back();
647 stateTransition();
648 return 0;
649}
650
651uint32_t TDenseProtocol::readBool(bool& value) {
652 checkTType(T_BOOL);
653 stateTransition();
654 return TBinaryProtocol::readBool(value);
655}
656
657uint32_t TDenseProtocol::readByte(int8_t& byte) {
658 checkTType(T_BYTE);
659 stateTransition();
660 return TBinaryProtocol::readByte(byte);
661}
662
663uint32_t TDenseProtocol::readI16(int16_t& i16) {
664 checkTType(T_I16);
665 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000666 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000667 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000668 int64_t val = (int64_t)u64;
669 if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000670 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000671 throw TProtocolException(TProtocolException::INVALID_DATA,
672 "i16 out of range.");
673 }
674 i16 = (int16_t)val;
675 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000676}
677
678uint32_t TDenseProtocol::readI32(int32_t& i32) {
679 checkTType(T_I32);
680 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000681 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000682 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000683 int64_t val = (int64_t)u64;
684 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000685 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000686 throw TProtocolException(TProtocolException::INVALID_DATA,
687 "i32 out of range.");
688 }
689 i32 = (int32_t)val;
690 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000691}
692
693uint32_t TDenseProtocol::readI64(int64_t& i64) {
694 checkTType(T_I64);
695 stateTransition();
David Reisse67c0e62007-09-07 01:34:12 +0000696 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000697 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000698 int64_t val = (int64_t)u64;
699 if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000700 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000701 throw TProtocolException(TProtocolException::INVALID_DATA,
702 "i64 out of range.");
703 }
704 i64 = (int64_t)val;
705 return rv;
David Reiss4e7530d2007-09-04 21:49:53 +0000706}
707
708uint32_t TDenseProtocol::readDouble(double& dub) {
709 checkTType(T_DOUBLE);
710 stateTransition();
711 return TBinaryProtocol::readDouble(dub);
712}
713
714uint32_t TDenseProtocol::readString(std::string& str) {
715 checkTType(T_STRING);
716 stateTransition();
717 return subReadString(str);
718}
719
David Reisse67c0e62007-09-07 01:34:12 +0000720uint32_t TDenseProtocol::subReadI32(int32_t& i32) {
721 uint64_t u64;
David Reissce161a92007-09-11 22:09:42 +0000722 uint32_t rv = vlqRead(u64);
David Reisse67c0e62007-09-07 01:34:12 +0000723 int64_t val = (int64_t)u64;
724 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
David Reissce161a92007-09-11 22:09:42 +0000725 resetState();
David Reisse67c0e62007-09-07 01:34:12 +0000726 throw TProtocolException(TProtocolException::INVALID_DATA,
727 "i32 out of range.");
728 }
729 i32 = (int32_t)val;
730 return rv;
731}
732
733uint32_t TDenseProtocol::subReadString(std::string& str) {
734 uint32_t xfer;
735 int32_t size;
736 xfer = subReadI32(size);
737 return xfer + readStringBody(str, size);
738}
739
David Reiss4e7530d2007-09-04 21:49:53 +0000740}}} // facebook::thrift::protocol