blob: 095dd64f6c7e6ab830ca16fe04bc669fa45698c3 [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
7#include "TDenseProtocol.h"
8#include "TReflectionLocal.h"
9
10// XXX for debugging (duh)
11#define DEBUG_TDENSEPROTOCOL
12
13// The XXX above does not apply to this.
14#ifdef DEBUG_TDENSEPROTOCOL
15#undef NDEBUG
16#endif
17#include <cassert>
18
19using std::string;
20
21namespace facebook { namespace thrift { namespace protocol {
22
23// Top TypeSpec. TypeSpec of the structure being encoded.
24#define TTS (ts_stack_.back()) // type = TypeSpec*
25// InDeX. Index into TTS of the current/next field to encode.
26#define IDX (idx_stack_.back()) // type = int
27// Field TypeSpec. TypeSpec of the current/next field to encode.
28#define FTS (TTS->tstruct.specs[IDX]) // type = TypeSpec*
29// Field MeTa. Metadata of the current/next field to encode.
30#define FMT (TTS->tstruct.metas[IDX]) // type = FieldMeta
31// SubType 1/2. TypeSpec of the first/second subtype of this container.
32#define ST1 (TTS->tcontainer.subtype1)
33#define ST2 (TTS->tcontainer.subtype2)
34
35
36inline void TDenseProtocol::checkTType(const TType ttype) {
37 assert(!ts_stack_.empty());
38 assert(TTS->ttype == ttype);
39}
40
41inline void TDenseProtocol::stateTransition() {
42 TypeSpec* old_tts = ts_stack_.back();
43 ts_stack_.pop_back();
44
45 if (ts_stack_.empty()) {
46 assert(old_tts = type_spec_);
47 return;
48 }
49
50 switch (TTS->ttype) {
51
52 case T_STRUCT:
53 assert(old_tts == FTS);
54 break;
55
56 case T_LIST:
57 case T_SET:
58 assert(old_tts == ST1);
59 ts_stack_.push_back(old_tts);
60 break;
61
62 case T_MAP:
63 assert(old_tts == (mkv_stack_.back() ? ST1 : ST2));
64 mkv_stack_.back() = !mkv_stack_.back();
65 ts_stack_.push_back(mkv_stack_.back() ? ST1 : ST2);
66 break;
67
68 default:
69 assert(!"Invalid TType in stateTransition.");
70 break;
71
72 }
73}
74
75uint32_t TDenseProtocol::writeMessageBegin(const std::string& name,
76 const TMessageType messageType,
77 const int32_t seqid) {
78 int32_t version = (VERSION_2) | ((int32_t)messageType);
79 uint32_t wsize = 0;
80 wsize += subWriteI32(version);
81 wsize += subWriteString(name);
82 wsize += subWriteI32(seqid);
83 return wsize;
84}
85
86uint32_t TDenseProtocol::writeMessageEnd() {
87 return 0;
88}
89
90// Also implements readStructBegin.
91uint32_t TDenseProtocol::writeStructBegin(const string& name) {
92 if (ts_stack_.empty()) {
93 if (type_spec_ == NULL) {
94 throw TApplicationException("TDenseProtocol: No type specified.");
95 } else {
96 ts_stack_.push_back(type_spec_);
97 }
98 }
99
100 idx_stack_.push_back(0);
101 return 0;
102}
103
104uint32_t TDenseProtocol::writeStructEnd() {
105 idx_stack_.pop_back();
106 stateTransition();
107 return 0;
108}
109
110uint32_t TDenseProtocol::writeFieldBegin(const string& name,
111 const TType fieldType,
112 const int16_t fieldId) {
113 uint32_t xfer = 0;
114
115 while (FMT.tag != fieldId) {
116 // TODO(dreiss): Old meta here.
117 assert(FTS->ttype != T_STOP);
118 assert(FMT.is_optional);
119 xfer += subWriteBool(false);
120 IDX++;
121 }
122
123 // TODO(dreiss): give a better exception.
124 assert(FTS->ttype == fieldType);
125
126 if (FMT.is_optional) {
127 subWriteBool(true);
128 xfer += 1;
129 }
130
131 // OMG I'm so gross. XXX
132 if (FTS->ttype != T_STOP) {
133 ts_stack_.push_back(FTS);
134 }
135 return xfer;
136}
137
138uint32_t TDenseProtocol::writeFieldEnd() {
139 IDX++;
140 return 0;
141}
142
143uint32_t TDenseProtocol::writeFieldStop() {
144 return writeFieldBegin("", T_STOP, 0);
145}
146
147uint32_t TDenseProtocol::writeMapBegin(const TType keyType,
148 const TType valType,
149 const uint32_t size) {
150 checkTType(T_MAP);
151
152 assert(keyType == ST1->ttype);
153 assert(valType == ST2->ttype);
154
155 ts_stack_.push_back(ST1);
156 mkv_stack_.push_back(true);
157
158 return subWriteI32((int32_t)size);
159}
160
161uint32_t TDenseProtocol::writeMapEnd() {
162 ts_stack_.pop_back();
163 mkv_stack_.pop_back();
164 stateTransition();
165 return 0;
166}
167
168uint32_t TDenseProtocol::writeListBegin(const TType elemType,
169 const uint32_t size) {
170 checkTType(T_LIST);
171
172 assert(elemType == ST1->ttype);
173 ts_stack_.push_back(ST1);
174 return subWriteI32((int32_t)size);
175}
176
177uint32_t TDenseProtocol::writeListEnd() {
178 ts_stack_.pop_back();
179 stateTransition();
180 return 0;
181}
182
183uint32_t TDenseProtocol::writeSetBegin(const TType elemType,
184 const uint32_t size) {
185 checkTType(T_SET);
186
187 assert(elemType == ST1->ttype);
188 ts_stack_.push_back(ST1);
189 return subWriteI32((int32_t)size);
190}
191
192uint32_t TDenseProtocol::writeSetEnd() {
193 ts_stack_.pop_back();
194 stateTransition();
195 return 0;
196}
197
198uint32_t TDenseProtocol::writeBool(const bool value) {
199 checkTType(T_BOOL);
200 stateTransition();
201 return TBinaryProtocol::writeBool(value);
202}
203
204uint32_t TDenseProtocol::writeByte(const int8_t byte) {
205 checkTType(T_BYTE);
206 stateTransition();
207 return TBinaryProtocol::writeByte(byte);
208}
209
210
211
212// XXX Remove this code for collecting statistics.
213static int vli_size(uint64_t towrite) {
214 int count = 0;
215 while (true) {
216 towrite = towrite >> 7;
217 if (towrite == 0) {
218 return count+1;
219 }
220 }
221}
222
223uint32_t TDenseProtocol::writeI16(const int16_t i16) {
224 vli_save_16 += 2 - vli_size(i16);
225 if (i16 < 0) negs++;
226
227 checkTType(T_I16);
228 stateTransition();
229 return TBinaryProtocol::writeI16(i16);
230}
231
232uint32_t TDenseProtocol::writeI32(const int32_t i32) {
233 vli_save_32 += 4 - vli_size(i32);
234 if (i32 < 0) negs++;
235
236 checkTType(T_I32);
237 stateTransition();
238 return TBinaryProtocol::writeI32(i32);
239}
240
241uint32_t TDenseProtocol::writeI64(const int64_t i64) {
242 vli_save_64 += 8 - vli_size(i64);
243 if (i64 < 0) negs++;
244
245 checkTType(T_I64);
246 stateTransition();
247 return TBinaryProtocol::writeI64(i64);
248}
249
250uint32_t TDenseProtocol::writeDouble(const double dub) {
251 checkTType(T_DOUBLE);
252 stateTransition();
253 return TBinaryProtocol::writeDouble(dub);
254}
255
256uint32_t TDenseProtocol::writeString(const std::string& str) {
257 checkTType(T_STRING);
258 stateTransition();
259 return subWriteString(str);
260}
261
262// XXX this can go into .h when we delete instrumentaion. (See subWritebool)
263inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
264 vli_save_sub += 4 - vli_size(i32);
265 if (i32 < 0) negs++;
266
267 int32_t net = (int32_t)htonl(i32);
268 trans_->write((uint8_t*)&net, 4);
269 return 4;
270}
271
272// XXX Delete when subWriteI32 goes into .h
273uint32_t TDenseProtocol::subWriteString(const std::string& str) {
274 uint32_t size = str.size();
275 uint32_t xfer = subWriteI32((int32_t)size);
276 if (size > 0) {
277 trans_->write((uint8_t*)str.data(), size);
278 }
279 return xfer + size;
280}
281
282
283/**
284 * Reading functions
285 */
286
287uint32_t TDenseProtocol::readMessageBegin(std::string& name,
288 TMessageType& messageType,
289 int32_t& seqid) {
290 uint32_t xfer = 0;
291 int32_t sz;
292 xfer += subReadI32(sz);
293
294 if (sz < 0) {
295 // Check for correct version number
296 int32_t version = sz & VERSION_MASK;
297 if (version != VERSION_2) {
298 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
299 }
300 messageType = (TMessageType)(sz & 0x000000ff);
301 xfer += subReadString(name);
302 xfer += subReadI32(seqid);
303 } else {
304 throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
305 }
306 return xfer;
307}
308
309uint32_t TDenseProtocol::readMessageEnd() {
310 return 0;
311}
312
313uint32_t TDenseProtocol::readStructBegin(string& name) {
314 // TODO(dreiss): Any chance this gets inlined?
315 return TDenseProtocol::writeStructBegin(name);
316}
317
318uint32_t TDenseProtocol::readStructEnd() {
319 idx_stack_.pop_back();
320 stateTransition();
321 return 0;
322}
323
324uint32_t TDenseProtocol::readFieldBegin(string& name,
325 TType& fieldType,
326 int16_t& fieldId) {
327 uint32_t xfer = 0;
328
329 while (FMT.is_optional) {
330 bool is_present;
331 xfer += subReadBool(is_present);
332 if (is_present) {
333 break;
334 }
335 IDX++;
336 }
337
338 fieldId = FMT.tag;
339 fieldType = FTS->ttype;
340
341 // OMG I'm so gross. XXX
342 if (FTS->ttype != T_STOP) {
343 ts_stack_.push_back(FTS);
344 }
345 return xfer;
346}
347
348uint32_t TDenseProtocol::readFieldEnd() {
349 IDX++;
350 return 0;
351}
352
353uint32_t TDenseProtocol::readMapBegin(TType& keyType,
354 TType& valType,
355 uint32_t& size) {
356 checkTType(T_MAP);
357
358 uint32_t xfer = 0;
359 int32_t sizei;
360 xfer += subReadI32(sizei);
361 if (sizei < 0) {
362 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
363 } else if (container_limit_ && sizei > container_limit_) {
364 throw TProtocolException(TProtocolException::SIZE_LIMIT);
365 }
366 size = (uint32_t)sizei;
367
368 keyType = ST1->ttype;
369 valType = ST2->ttype;
370
371 ts_stack_.push_back(ST1);
372 mkv_stack_.push_back(true);
373
374 return xfer;
375}
376
377uint32_t TDenseProtocol::readMapEnd() {
378 ts_stack_.pop_back();
379 mkv_stack_.pop_back();
380 stateTransition();
381 return 0;
382}
383
384uint32_t TDenseProtocol::readListBegin(TType& elemType,
385 uint32_t& size) {
386 checkTType(T_LIST);
387
388 uint32_t xfer = 0;
389 int32_t sizei;
390 xfer += subReadI32(sizei);
391 if (sizei < 0) {
392 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
393 } else if (container_limit_ && sizei > container_limit_) {
394 throw TProtocolException(TProtocolException::SIZE_LIMIT);
395 }
396 size = (uint32_t)sizei;
397
398 elemType = ST1->ttype;
399
400 ts_stack_.push_back(ST1);
401
402 return xfer;
403}
404
405uint32_t TDenseProtocol::readListEnd() {
406 ts_stack_.pop_back();
407 stateTransition();
408 return 0;
409}
410
411uint32_t TDenseProtocol::readSetBegin(TType& elemType,
412 uint32_t& size) {
413 checkTType(T_SET);
414
415 uint32_t xfer = 0;
416 int32_t sizei;
417 xfer += subReadI32(sizei);
418 if (sizei < 0) {
419 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
420 } else if (container_limit_ && sizei > container_limit_) {
421 throw TProtocolException(TProtocolException::SIZE_LIMIT);
422 }
423 size = (uint32_t)sizei;
424
425 elemType = ST1->ttype;
426
427 ts_stack_.push_back(ST1);
428
429 return xfer;
430}
431
432uint32_t TDenseProtocol::readSetEnd() {
433 ts_stack_.pop_back();
434 stateTransition();
435 return 0;
436}
437
438uint32_t TDenseProtocol::readBool(bool& value) {
439 checkTType(T_BOOL);
440 stateTransition();
441 return TBinaryProtocol::readBool(value);
442}
443
444uint32_t TDenseProtocol::readByte(int8_t& byte) {
445 checkTType(T_BYTE);
446 stateTransition();
447 return TBinaryProtocol::readByte(byte);
448}
449
450uint32_t TDenseProtocol::readI16(int16_t& i16) {
451 checkTType(T_I16);
452 stateTransition();
453 return TBinaryProtocol::readI16(i16);
454}
455
456uint32_t TDenseProtocol::readI32(int32_t& i32) {
457 checkTType(T_I32);
458 stateTransition();
459 return TBinaryProtocol::readI32(i32);
460}
461
462uint32_t TDenseProtocol::readI64(int64_t& i64) {
463 checkTType(T_I64);
464 stateTransition();
465 return TBinaryProtocol::readI64(i64);
466}
467
468uint32_t TDenseProtocol::readDouble(double& dub) {
469 checkTType(T_DOUBLE);
470 stateTransition();
471 return TBinaryProtocol::readDouble(dub);
472}
473
474uint32_t TDenseProtocol::readString(std::string& str) {
475 checkTType(T_STRING);
476 stateTransition();
477 return subReadString(str);
478}
479
480}}} // facebook::thrift::protocol