blob: 8e76dc4797386e441484f81061f9d64915bf6319 [file] [log] [blame]
Gavin McDonald0b75e1a2010-10-28 02:12:01 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20/*
21
22IMPLEMENTATION DETAILS
23
24TDenseProtocol was designed to have a smaller serialized form than
25TBinaryProtocol. This is accomplished using two techniques. The first is
26variable-length integer encoding. We use the same technique that the Standard
27MIDI File format uses for "variable-length quantities"
28(http://en.wikipedia.org/wiki/Variable-length_quantity).
29All integers (including i16, but not byte) are first cast to uint64_t,
30then written out as variable-length quantities. This has the unfortunate side
31effect that all negative numbers require 10 bytes, but negative numbers tend
32to be far less common than positive ones.
33
34The second technique eliminating the field ids used by TBinaryProtocol. This
35decision required support from the Thrift compiler and also sacrifices some of
36the backward and forward compatibility of TBinaryProtocol.
37
38We considered implementing this technique by generating separate readers and
39writers for the dense protocol (this is how Pillar, Thrift's predecessor,
40worked), but this idea had a few problems:
41- Our abstractions go out the window.
42- We would have to maintain a second code generator.
43- Preserving compatibility with old versions of the structures would be a
44 nightmare.
45
46Therefore, we chose an alternate implementation that stored the description of
47the data neither in the data itself (like TBinaryProtocol) nor in the
48serialization code (like Pillar), but instead in a separate data structure,
49called a TypeSpec. TypeSpecs are generated by the Thrift compiler
50(specifically in the t_cpp_generator), and their structure should be
51documented there (TODO(dreiss): s/should be/is/).
52
53We maintain a stack of TypeSpecs within the protocol so it knows where the
54generated code is in the reading/writing process. For example, if we are
55writing an i32 contained in a struct bar, contained in a struct foo, then the
56stack would look like: TOP , i32 , struct bar , struct foo , BOTTOM.
57The following invariant: whenever we are about to read/write an object
58(structBegin, containerBegin, or a scalar), the TypeSpec on the top of the
59stack must match the type being read/written. The main reasons that this
60invariant must be maintained is that if we ever start reading a structure, we
61must have its exact TypeSpec in order to pass the right tags to the
62deserializer.
63
64We use the following strategies for maintaining this invariant:
65
66- For structures, we have a separate stack of indexes, one for each structure
67 on the TypeSpec stack. These are indexes into the list of fields in the
68 structure's TypeSpec. When we {read,write}FieldBegin, we push on the
69 TypeSpec for the field.
70- When we begin writing a list or set, we push on the TypeSpec for the
71 element type.
72- For maps, we have a separate stack of booleans, one for each map on the
73 TypeSpec stack. The boolean is true if we are writing the key for that
74 map, and false if we are writing the value. Maps are the trickiest case
75 because the generated code does not call any protocol method between
76 the key and the value. As a result, we potentially have to switch
77 between map key state and map value state after reading/writing any object.
78- This job is handled by the stateTransition method. It is called after
79 reading/writing every object. It pops the current TypeSpec off the stack,
80 then optionally pushes a new one on, depending on what the next TypeSpec is.
81 If it is a struct, the job is left to the next writeFieldBegin. If it is a
82 set or list, the just-popped typespec is pushed back on. If it is a map,
83 the top of the key/value stack is toggled, and the appropriate TypeSpec
84 is pushed.
85
86Optional fields are a little tricky also. We write a zero byte if they are
87absent and prefix them with an 0x01 byte if they are present
88*/
89
90#define __STDC_LIMIT_MACROS
91#include <stdint.h>
92#include "TDenseProtocol.h"
93#include "TReflectionLocal.h"
94
95// Leaving this on for now. Disabling it will turn off asserts, which should
96// give a performance boost. When we have *really* thorough test cases,
97// we should drop this.
98#define DEBUG_TDENSEPROTOCOL
99
100// NOTE: Assertions should *only* be used to detect bugs in code,
101// either in TDenseProtocol itself, or in code using it.
102// (For example, using the wrong TypeSpec.)
103// Invalid data should NEVER cause an assertion failure,
104// no matter how grossly corrupted, nor how ingeniously crafted.
105#ifdef DEBUG_TDENSEPROTOCOL
106#undef NDEBUG
107#else
108#define NDEBUG
109#endif
110#include <cassert>
111
112using std::string;
113
114#ifdef __GNUC__
115#define UNLIKELY(val) (__builtin_expect((val), 0))
116#else
117#define UNLIKELY(val) (val)
118#endif
119
120namespace apache { namespace thrift { namespace protocol {
121
122const int TDenseProtocol::FP_PREFIX_LEN =
123 apache::thrift::reflection::local::FP_PREFIX_LEN;
124
125// Top TypeSpec. TypeSpec of the structure being encoded.
126#define TTS (ts_stack_.back()) // type = TypeSpec*
127// InDeX. Index into TTS of the current/next field to encode.
128#define IDX (idx_stack_.back()) // type = int
129// Field TypeSpec. TypeSpec of the current/next field to encode.
130#define FTS (TTS->tstruct.specs[IDX]) // type = TypeSpec*
131// Field MeTa. Metadata of the current/next field to encode.
132#define FMT (TTS->tstruct.metas[IDX]) // type = FieldMeta
133// SubType 1/2. TypeSpec of the first/second subtype of this container.
134#define ST1 (TTS->tcontainer.subtype1)
135#define ST2 (TTS->tcontainer.subtype2)
136
137
138/**
139 * Checks that @c ttype is indeed the ttype that we should be writing,
140 * according to our typespec. Aborts if the test fails and debugging in on.
141 */
142inline void TDenseProtocol::checkTType(const TType ttype) {
143 assert(!ts_stack_.empty());
144 assert(TTS->ttype == ttype);
145}
146
147/**
148 * Makes sure that the TypeSpec stack is correct for the next object.
149 * See top-of-file comments.
150 */
151inline void TDenseProtocol::stateTransition() {
152 TypeSpec* old_tts = ts_stack_.back();
153 ts_stack_.pop_back();
154
155 // If this is the end of the top-level write, we should have just popped
156 // the TypeSpec passed to the constructor.
157 if (ts_stack_.empty()) {
158 assert(old_tts = type_spec_);
159 return;
160 }
161
162 switch (TTS->ttype) {
163
164 case T_STRUCT:
165 assert(old_tts == FTS);
166 break;
167
168 case T_LIST:
169 case T_SET:
170 assert(old_tts == ST1);
171 ts_stack_.push_back(old_tts);
172 break;
173
174 case T_MAP:
175 assert(old_tts == (mkv_stack_.back() ? ST1 : ST2));
176 mkv_stack_.back() = !mkv_stack_.back();
177 ts_stack_.push_back(mkv_stack_.back() ? ST1 : ST2);
178 break;
179
180 default:
181 assert(!"Invalid TType in stateTransition.");
182 break;
183
184 }
185}
186
187
188/*
189 * Variable-length quantity functions.
190 */
191
192inline uint32_t TDenseProtocol::vlqRead(uint64_t& vlq) {
193 uint32_t used = 0;
194 uint64_t val = 0;
195 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
196 uint32_t buf_size = sizeof(buf);
197 const uint8_t* borrowed = trans_->borrow(buf, &buf_size);
198
199 // Fast path. TODO(dreiss): Make it faster.
200 if (borrowed != NULL) {
201 while (true) {
202 uint8_t byte = borrowed[used];
203 used++;
204 val = (val << 7) | (byte & 0x7f);
205 if (!(byte & 0x80)) {
206 vlq = val;
207 trans_->consume(used);
208 return used;
209 }
210 // Have to check for invalid data so we don't crash.
211 if (UNLIKELY(used == sizeof(buf))) {
212 resetState();
213 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
214 }
215 }
216 }
217
218 // Slow path.
219 else {
220 while (true) {
221 uint8_t byte;
222 used += trans_->readAll(&byte, 1);
223 val = (val << 7) | (byte & 0x7f);
224 if (!(byte & 0x80)) {
225 vlq = val;
226 return used;
227 }
228 // Might as well check for invalid data on the slow path too.
229 if (UNLIKELY(used >= sizeof(buf))) {
230 resetState();
231 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
232 }
233 }
234 }
235}
236
237inline uint32_t TDenseProtocol::vlqWrite(uint64_t vlq) {
238 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
239 int32_t pos = sizeof(buf) - 1;
240
241 // Write the thing from back to front.
242 buf[pos] = vlq & 0x7f;
243 vlq >>= 7;
244 pos--;
245
246 while (vlq > 0) {
247 assert(pos >= 0);
248 buf[pos] = (vlq | 0x80);
249 vlq >>= 7;
250 pos--;
251 }
252
253 // Back up one step before writing.
254 pos++;
255
256 trans_->write(buf+pos, sizeof(buf) - pos);
257 return sizeof(buf) - pos;
258}
259
260
261
262/*
263 * Writing functions.
264 */
265
266uint32_t TDenseProtocol::writeMessageBegin(const std::string& name,
267 const TMessageType messageType,
268 const int32_t seqid) {
269 throw TApplicationException("TDenseProtocol doesn't work with messages (yet).");
270
271 int32_t version = (VERSION_2) | ((int32_t)messageType);
272 uint32_t wsize = 0;
273 wsize += subWriteI32(version);
274 wsize += subWriteString(name);
275 wsize += subWriteI32(seqid);
276 return wsize;
277}
278
279uint32_t TDenseProtocol::writeMessageEnd() {
280 return 0;
281}
282
283uint32_t TDenseProtocol::writeStructBegin(const char* name) {
284 uint32_t xfer = 0;
285
286 // The TypeSpec stack should be empty if this is the top-level read/write.
287 // If it is, we push the TypeSpec passed to the constructor.
288 if (ts_stack_.empty()) {
289 assert(standalone_);
290
291 if (type_spec_ == NULL) {
292 resetState();
293 throw TApplicationException("TDenseProtocol: No type specified.");
294 } else {
295 assert(type_spec_->ttype == T_STRUCT);
296 ts_stack_.push_back(type_spec_);
297 // Write out a prefix of the structure fingerprint.
298 trans_->write(type_spec_->fp_prefix, FP_PREFIX_LEN);
299 xfer += FP_PREFIX_LEN;
300 }
301 }
302
303 // We need a new field index for this structure.
304 idx_stack_.push_back(0);
305 return 0;
306}
307
308uint32_t TDenseProtocol::writeStructEnd() {
309 idx_stack_.pop_back();
310 stateTransition();
311 return 0;
312}
313
314uint32_t TDenseProtocol::writeFieldBegin(const char* name,
315 const TType fieldType,
316 const int16_t fieldId) {
317 uint32_t xfer = 0;
318
319 // Skip over optional fields.
320 while (FMT.tag != fieldId) {
321 // TODO(dreiss): Old meta here.
322 assert(FTS->ttype != T_STOP);
323 assert(FMT.is_optional);
324 // Write a zero byte so the reader can skip it.
325 xfer += subWriteBool(false);
326 // And advance to the next field.
327 IDX++;
328 }
329
330 // TODO(dreiss): give a better exception.
331 assert(FTS->ttype == fieldType);
332
333 if (FMT.is_optional) {
334 subWriteBool(true);
335 xfer += 1;
336 }
337
338 // writeFieldStop shares all lot of logic up to this point.
339 // Instead of replicating it all, we just call this method from that one
340 // and use a gross special case here.
341 if (UNLIKELY(FTS->ttype != T_STOP)) {
342 // For normal fields, push the TypeSpec that we're about to use.
343 ts_stack_.push_back(FTS);
344 }
345 return xfer;
346}
347
348uint32_t TDenseProtocol::writeFieldEnd() {
349 // Just move on to the next field.
350 IDX++;
351 return 0;
352}
353
354uint32_t TDenseProtocol::writeFieldStop() {
355 return TDenseProtocol::writeFieldBegin("", T_STOP, 0);
356}
357
358uint32_t TDenseProtocol::writeMapBegin(const TType keyType,
359 const TType valType,
360 const uint32_t size) {
361 checkTType(T_MAP);
362
363 assert(keyType == ST1->ttype);
364 assert(valType == ST2->ttype);
365
366 ts_stack_.push_back(ST1);
367 mkv_stack_.push_back(true);
368
369 return subWriteI32((int32_t)size);
370}
371
372uint32_t TDenseProtocol::writeMapEnd() {
373 // Pop off the value type, as well as our entry in the map key/value stack.
374 // stateTransition takes care of popping off our TypeSpec.
375 ts_stack_.pop_back();
376 mkv_stack_.pop_back();
377 stateTransition();
378 return 0;
379}
380
381uint32_t TDenseProtocol::writeListBegin(const TType elemType,
382 const uint32_t size) {
383 checkTType(T_LIST);
384
385 assert(elemType == ST1->ttype);
386 ts_stack_.push_back(ST1);
387 return subWriteI32((int32_t)size);
388}
389
390uint32_t TDenseProtocol::writeListEnd() {
391 // Pop off the element type. stateTransition takes care of popping off ours.
392 ts_stack_.pop_back();
393 stateTransition();
394 return 0;
395}
396
397uint32_t TDenseProtocol::writeSetBegin(const TType elemType,
398 const uint32_t size) {
399 checkTType(T_SET);
400
401 assert(elemType == ST1->ttype);
402 ts_stack_.push_back(ST1);
403 return subWriteI32((int32_t)size);
404}
405
406uint32_t TDenseProtocol::writeSetEnd() {
407 // Pop off the element type. stateTransition takes care of popping off ours.
408 ts_stack_.pop_back();
409 stateTransition();
410 return 0;
411}
412
413uint32_t TDenseProtocol::writeBool(const bool value) {
414 checkTType(T_BOOL);
415 stateTransition();
416 return TBinaryProtocol::writeBool(value);
417}
418
419uint32_t TDenseProtocol::writeByte(const int8_t byte) {
420 checkTType(T_BYTE);
421 stateTransition();
422 return TBinaryProtocol::writeByte(byte);
423}
424
425uint32_t TDenseProtocol::writeI16(const int16_t i16) {
426 checkTType(T_I16);
427 stateTransition();
428 return vlqWrite(i16);
429}
430
431uint32_t TDenseProtocol::writeI32(const int32_t i32) {
432 checkTType(T_I32);
433 stateTransition();
434 return vlqWrite(i32);
435}
436
437uint32_t TDenseProtocol::writeI64(const int64_t i64) {
438 checkTType(T_I64);
439 stateTransition();
440 return vlqWrite(i64);
441}
442
443uint32_t TDenseProtocol::writeDouble(const double dub) {
444 checkTType(T_DOUBLE);
445 stateTransition();
446 return TBinaryProtocol::writeDouble(dub);
447}
448
449uint32_t TDenseProtocol::writeString(const std::string& str) {
450 checkTType(T_STRING);
451 stateTransition();
452 return subWriteString(str);
453}
454
455uint32_t TDenseProtocol::writeBinary(const std::string& str) {
456 return TDenseProtocol::writeString(str);
457}
458
459inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
460 return vlqWrite(i32);
461}
462
463uint32_t TDenseProtocol::subWriteString(const std::string& str) {
464 uint32_t size = str.size();
465 uint32_t xfer = subWriteI32((int32_t)size);
466 if (size > 0) {
467 trans_->write((uint8_t*)str.data(), size);
468 }
469 return xfer + size;
470}
471
472
473
474/*
475 * Reading functions
476 *
477 * These have a lot of the same logic as the writing functions, so if
478 * something is confusing, look for comments in the corresponding writer.
479 */
480
481uint32_t TDenseProtocol::readMessageBegin(std::string& name,
482 TMessageType& messageType,
483 int32_t& seqid) {
484 throw TApplicationException("TDenseProtocol doesn't work with messages (yet).");
485
486 uint32_t xfer = 0;
487 int32_t sz;
488 xfer += subReadI32(sz);
489
490 if (sz < 0) {
491 // Check for correct version number
492 int32_t version = sz & VERSION_MASK;
493 if (version != VERSION_2) {
494 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
495 }
496 messageType = (TMessageType)(sz & 0x000000ff);
497 xfer += subReadString(name);
498 xfer += subReadI32(seqid);
499 } else {
500 throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
501 }
502 return xfer;
503}
504
505uint32_t TDenseProtocol::readMessageEnd() {
506 return 0;
507}
508
509uint32_t TDenseProtocol::readStructBegin(string& name) {
510 uint32_t xfer = 0;
511
512 if (ts_stack_.empty()) {
513 assert(standalone_);
514
515 if (type_spec_ == NULL) {
516 resetState();
517 throw TApplicationException("TDenseProtocol: No type specified.");
518 } else {
519 assert(type_spec_->ttype == T_STRUCT);
520 ts_stack_.push_back(type_spec_);
521
522 // Check the fingerprint prefix.
523 uint8_t buf[FP_PREFIX_LEN];
524 xfer += trans_->read(buf, FP_PREFIX_LEN);
525 if (std::memcmp(buf, type_spec_->fp_prefix, FP_PREFIX_LEN) != 0) {
526 resetState();
527 throw TProtocolException(TProtocolException::INVALID_DATA,
528 "Fingerprint in data does not match type_spec.");
529 }
530 }
531 }
532
533 // We need a new field index for this structure.
534 idx_stack_.push_back(0);
535 return 0;
536}
537
538uint32_t TDenseProtocol::readStructEnd() {
539 idx_stack_.pop_back();
540 stateTransition();
541 return 0;
542}
543
544uint32_t TDenseProtocol::readFieldBegin(string& name,
545 TType& fieldType,
546 int16_t& fieldId) {
547 uint32_t xfer = 0;
548
549 // For optional fields, check to see if they are there.
550 while (FMT.is_optional) {
551 bool is_present;
552 xfer += subReadBool(is_present);
553 if (is_present) {
554 break;
555 }
556 IDX++;
557 }
558
559 // Once we hit a mandatory field, or an optional field that is present,
560 // we know that FMT and FTS point to the appropriate field.
561
562 fieldId = FMT.tag;
563 fieldType = FTS->ttype;
564
565 // Normally, we push the TypeSpec that we are about to read,
566 // but no reading is done for T_STOP.
567 if (FTS->ttype != T_STOP) {
568 ts_stack_.push_back(FTS);
569 }
570 return xfer;
571}
572
573uint32_t TDenseProtocol::readFieldEnd() {
574 IDX++;
575 return 0;
576}
577
578uint32_t TDenseProtocol::readMapBegin(TType& keyType,
579 TType& valType,
580 uint32_t& size) {
581 checkTType(T_MAP);
582
583 uint32_t xfer = 0;
584 int32_t sizei;
585 xfer += subReadI32(sizei);
586 if (sizei < 0) {
587 resetState();
588 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
589 } else if (container_limit_ && sizei > container_limit_) {
590 resetState();
591 throw TProtocolException(TProtocolException::SIZE_LIMIT);
592 }
593 size = (uint32_t)sizei;
594
595 keyType = ST1->ttype;
596 valType = ST2->ttype;
597
598 ts_stack_.push_back(ST1);
599 mkv_stack_.push_back(true);
600
601 return xfer;
602}
603
604uint32_t TDenseProtocol::readMapEnd() {
605 ts_stack_.pop_back();
606 mkv_stack_.pop_back();
607 stateTransition();
608 return 0;
609}
610
611uint32_t TDenseProtocol::readListBegin(TType& elemType,
612 uint32_t& size) {
613 checkTType(T_LIST);
614
615 uint32_t xfer = 0;
616 int32_t sizei;
617 xfer += subReadI32(sizei);
618 if (sizei < 0) {
619 resetState();
620 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
621 } else if (container_limit_ && sizei > container_limit_) {
622 resetState();
623 throw TProtocolException(TProtocolException::SIZE_LIMIT);
624 }
625 size = (uint32_t)sizei;
626
627 elemType = ST1->ttype;
628
629 ts_stack_.push_back(ST1);
630
631 return xfer;
632}
633
634uint32_t TDenseProtocol::readListEnd() {
635 ts_stack_.pop_back();
636 stateTransition();
637 return 0;
638}
639
640uint32_t TDenseProtocol::readSetBegin(TType& elemType,
641 uint32_t& size) {
642 checkTType(T_SET);
643
644 uint32_t xfer = 0;
645 int32_t sizei;
646 xfer += subReadI32(sizei);
647 if (sizei < 0) {
648 resetState();
649 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
650 } else if (container_limit_ && sizei > container_limit_) {
651 resetState();
652 throw TProtocolException(TProtocolException::SIZE_LIMIT);
653 }
654 size = (uint32_t)sizei;
655
656 elemType = ST1->ttype;
657
658 ts_stack_.push_back(ST1);
659
660 return xfer;
661}
662
663uint32_t TDenseProtocol::readSetEnd() {
664 ts_stack_.pop_back();
665 stateTransition();
666 return 0;
667}
668
669uint32_t TDenseProtocol::readBool(bool& value) {
670 checkTType(T_BOOL);
671 stateTransition();
672 return TBinaryProtocol::readBool(value);
673}
674
675uint32_t TDenseProtocol::readByte(int8_t& byte) {
676 checkTType(T_BYTE);
677 stateTransition();
678 return TBinaryProtocol::readByte(byte);
679}
680
681uint32_t TDenseProtocol::readI16(int16_t& i16) {
682 checkTType(T_I16);
683 stateTransition();
684 uint64_t u64;
685 uint32_t rv = vlqRead(u64);
686 int64_t val = (int64_t)u64;
687 if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) {
688 resetState();
689 throw TProtocolException(TProtocolException::INVALID_DATA,
690 "i16 out of range.");
691 }
692 i16 = (int16_t)val;
693 return rv;
694}
695
696uint32_t TDenseProtocol::readI32(int32_t& i32) {
697 checkTType(T_I32);
698 stateTransition();
699 uint64_t u64;
700 uint32_t rv = vlqRead(u64);
701 int64_t val = (int64_t)u64;
702 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
703 resetState();
704 throw TProtocolException(TProtocolException::INVALID_DATA,
705 "i32 out of range.");
706 }
707 i32 = (int32_t)val;
708 return rv;
709}
710
711uint32_t TDenseProtocol::readI64(int64_t& i64) {
712 checkTType(T_I64);
713 stateTransition();
714 uint64_t u64;
715 uint32_t rv = vlqRead(u64);
716 int64_t val = (int64_t)u64;
717 if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) {
718 resetState();
719 throw TProtocolException(TProtocolException::INVALID_DATA,
720 "i64 out of range.");
721 }
722 i64 = (int64_t)val;
723 return rv;
724}
725
726uint32_t TDenseProtocol::readDouble(double& dub) {
727 checkTType(T_DOUBLE);
728 stateTransition();
729 return TBinaryProtocol::readDouble(dub);
730}
731
732uint32_t TDenseProtocol::readString(std::string& str) {
733 checkTType(T_STRING);
734 stateTransition();
735 return subReadString(str);
736}
737
738uint32_t TDenseProtocol::readBinary(std::string& str) {
739 return TDenseProtocol::readString(str);
740}
741
742uint32_t TDenseProtocol::subReadI32(int32_t& i32) {
743 uint64_t u64;
744 uint32_t rv = vlqRead(u64);
745 int64_t val = (int64_t)u64;
746 if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
747 resetState();
748 throw TProtocolException(TProtocolException::INVALID_DATA,
749 "i32 out of range.");
750 }
751 i32 = (int32_t)val;
752 return rv;
753}
754
755uint32_t TDenseProtocol::subReadString(std::string& str) {
756 uint32_t xfer;
757 int32_t size;
758 xfer = subReadI32(size);
759 return xfer + readStringBody(str, size);
760}
761
762}}} // apache::thrift::protocol