Subversion Repositories SmartDukaan

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 ashish 1
/*
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
 
22
IMPLEMENTATION DETAILS
23
 
24
TDenseProtocol was designed to have a smaller serialized form than
25
TBinaryProtocol.  This is accomplished using two techniques.  The first is
26
variable-length integer encoding.  We use the same technique that the Standard
27
MIDI File format uses for "variable-length quantities"
28
(http://en.wikipedia.org/wiki/Variable-length_quantity).
29
All integers (including i16, but not byte) are first cast to uint64_t,
30
then written out as variable-length quantities.  This has the unfortunate side
31
effect that all negative numbers require 10 bytes, but negative numbers tend
32
to be far less common than positive ones.
33
 
34
The second technique eliminating the field ids used by TBinaryProtocol.  This
35
decision required support from the Thrift compiler and also sacrifices some of
36
the backward and forward compatibility of TBinaryProtocol.
37
 
38
We considered implementing this technique by generating separate readers and
39
writers for the dense protocol (this is how Pillar, Thrift's predecessor,
40
worked), 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
 
46
Therefore, we chose an alternate implementation that stored the description of
47
the data neither in the data itself (like TBinaryProtocol) nor in the
48
serialization code (like Pillar), but instead in a separate data structure,
49
called a TypeSpec.  TypeSpecs are generated by the Thrift compiler
50
(specifically in the t_cpp_generator), and their structure should be
51
documented there (TODO(dreiss): s/should be/is/).
52
 
53
We maintain a stack of TypeSpecs within the protocol so it knows where the
54
generated code is in the reading/writing process.  For example, if we are
55
writing an i32 contained in a struct bar, contained in a struct foo, then the
56
stack would look like: TOP , i32 , struct bar , struct foo , BOTTOM.
57
The following invariant: whenever we are about to read/write an object
58
(structBegin, containerBegin, or a scalar), the TypeSpec on the top of the
59
stack must match the type being read/written.  The main reasons that this
60
invariant must be maintained is that if we ever start reading a structure, we
61
must have its exact TypeSpec in order to pass the right tags to the
62
deserializer.
63
 
64
We 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
 
86
Optional fields are a little tricky also.  We write a zero byte if they are
87
absent 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
 
112
using std::string;
113
 
114
#ifdef __GNUC__
115
#define UNLIKELY(val) (__builtin_expect((val), 0))
116
#else
117
#define UNLIKELY(val) (val)
118
#endif
119
 
120
namespace apache { namespace thrift { namespace protocol {
121
 
122
const 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
 */
142
inline 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
 */
151
inline 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
 
192
inline 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
 
237
inline 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
 
266
uint32_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
 
279
uint32_t TDenseProtocol::writeMessageEnd() {
280
  return 0;
281
}
282
 
283
uint32_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
 
308
uint32_t TDenseProtocol::writeStructEnd() {
309
  idx_stack_.pop_back();
310
  stateTransition();
311
  return 0;
312
}
313
 
314
uint32_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
 
348
uint32_t TDenseProtocol::writeFieldEnd() {
349
  // Just move on to the next field.
350
  IDX++;
351
  return 0;
352
}
353
 
354
uint32_t TDenseProtocol::writeFieldStop() {
355
  return TDenseProtocol::writeFieldBegin("", T_STOP, 0);
356
}
357
 
358
uint32_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
 
372
uint32_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
 
381
uint32_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
 
390
uint32_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
 
397
uint32_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
 
406
uint32_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
 
413
uint32_t TDenseProtocol::writeBool(const bool value) {
414
  checkTType(T_BOOL);
415
  stateTransition();
416
  return TBinaryProtocol::writeBool(value);
417
}
418
 
419
uint32_t TDenseProtocol::writeByte(const int8_t byte) {
420
  checkTType(T_BYTE);
421
  stateTransition();
422
  return TBinaryProtocol::writeByte(byte);
423
}
424
 
425
uint32_t TDenseProtocol::writeI16(const int16_t i16) {
426
  checkTType(T_I16);
427
  stateTransition();
428
  return vlqWrite(i16);
429
}
430
 
431
uint32_t TDenseProtocol::writeI32(const int32_t i32) {
432
  checkTType(T_I32);
433
  stateTransition();
434
  return vlqWrite(i32);
435
}
436
 
437
uint32_t TDenseProtocol::writeI64(const int64_t i64) {
438
  checkTType(T_I64);
439
  stateTransition();
440
  return vlqWrite(i64);
441
}
442
 
443
uint32_t TDenseProtocol::writeDouble(const double dub) {
444
  checkTType(T_DOUBLE);
445
  stateTransition();
446
  return TBinaryProtocol::writeDouble(dub);
447
}
448
 
449
uint32_t TDenseProtocol::writeString(const std::string& str) {
450
  checkTType(T_STRING);
451
  stateTransition();
452
  return subWriteString(str);
453
}
454
 
455
uint32_t TDenseProtocol::writeBinary(const std::string& str) {
456
  return TDenseProtocol::writeString(str);
457
}
458
 
459
inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
460
  return vlqWrite(i32);
461
}
462
 
463
uint32_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
 
481
uint32_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
 
505
uint32_t TDenseProtocol::readMessageEnd() {
506
  return 0;
507
}
508
 
509
uint32_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
 
538
uint32_t TDenseProtocol::readStructEnd() {
539
  idx_stack_.pop_back();
540
  stateTransition();
541
  return 0;
542
}
543
 
544
uint32_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
 
573
uint32_t TDenseProtocol::readFieldEnd() {
574
  IDX++;
575
  return 0;
576
}
577
 
578
uint32_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
 
604
uint32_t TDenseProtocol::readMapEnd() {
605
  ts_stack_.pop_back();
606
  mkv_stack_.pop_back();
607
  stateTransition();
608
  return 0;
609
}
610
 
611
uint32_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
 
634
uint32_t TDenseProtocol::readListEnd() {
635
  ts_stack_.pop_back();
636
  stateTransition();
637
  return 0;
638
}
639
 
640
uint32_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
 
663
uint32_t TDenseProtocol::readSetEnd() {
664
  ts_stack_.pop_back();
665
  stateTransition();
666
  return 0;
667
}
668
 
669
uint32_t TDenseProtocol::readBool(bool& value) {
670
  checkTType(T_BOOL);
671
  stateTransition();
672
  return TBinaryProtocol::readBool(value);
673
}
674
 
675
uint32_t TDenseProtocol::readByte(int8_t& byte) {
676
  checkTType(T_BYTE);
677
  stateTransition();
678
  return TBinaryProtocol::readByte(byte);
679
}
680
 
681
uint32_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
 
696
uint32_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
 
711
uint32_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
 
726
uint32_t TDenseProtocol::readDouble(double& dub) {
727
  checkTType(T_DOUBLE);
728
  stateTransition();
729
  return TBinaryProtocol::readDouble(dub);
730
}
731
 
732
uint32_t TDenseProtocol::readString(std::string& str) {
733
  checkTType(T_STRING);
734
  stateTransition();
735
  return subReadString(str);
736
}
737
 
738
uint32_t TDenseProtocol::readBinary(std::string& str) {
739
  return TDenseProtocol::readString(str);
740
}
741
 
742
uint32_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
 
755
uint32_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