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
 * Contains some contributions under the Thrift Software License.
20
 * Please see doc/old-thrift-license.txt in the Thrift distribution for
21
 * details.
22
 */
23
 
24
#include <cassert>
25
 
26
#include <fstream>
27
#include <iostream>
28
#include <sstream>
29
#include <string>
30
#include <vector>
31
 
32
#include <sys/stat.h>
33
 
34
#include "platform.h"
35
#include "t_oop_generator.h"
36
using namespace std;
37
 
38
 
39
/**
40
 * C++ code generator. This is legitimacy incarnate.
41
 *
42
 */
43
class t_cpp_generator : public t_oop_generator {
44
 public:
45
  t_cpp_generator(
46
      t_program* program,
47
      const std::map<std::string, std::string>& parsed_options,
48
      const std::string& option_string)
49
    : t_oop_generator(program)
50
  {
51
    std::map<std::string, std::string>::const_iterator iter;
52
 
53
    iter = parsed_options.find("dense");
54
    gen_dense_ = (iter != parsed_options.end());
55
 
56
    iter = parsed_options.find("include_prefix");
57
    use_include_prefix_ = (iter != parsed_options.end());
58
 
59
    out_dir_base_ = "gen-cpp";
60
  }
61
 
62
  /**
63
   * Init and close methods
64
   */
65
 
66
  void init_generator();
67
  void close_generator();
68
 
69
  void generate_consts(std::vector<t_const*> consts);
70
 
71
  /**
72
   * Program-level generation functions
73
   */
74
 
75
  void generate_typedef(t_typedef* ttypedef);
76
  void generate_enum(t_enum* tenum);
77
  void generate_struct(t_struct* tstruct) {
78
    generate_cpp_struct(tstruct, false);
79
  }
80
  void generate_xception(t_struct* txception) {
81
    generate_cpp_struct(txception, true);
82
  }
83
  void generate_cpp_struct(t_struct* tstruct, bool is_exception);
84
 
85
  void generate_service(t_service* tservice);
86
 
87
  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
88
  std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
89
 
90
  void generate_struct_definition    (std::ofstream& out, t_struct* tstruct, bool is_exception=false, bool pointers=false, bool read=true, bool write=true);
91
  void generate_struct_fingerprint   (std::ofstream& out, t_struct* tstruct, bool is_definition);
92
  void generate_struct_reader        (std::ofstream& out, t_struct* tstruct, bool pointers=false);
93
  void generate_struct_writer        (std::ofstream& out, t_struct* tstruct, bool pointers=false);
94
  void generate_struct_result_writer (std::ofstream& out, t_struct* tstruct, bool pointers=false);
95
 
96
  /**
97
   * Service-level generation functions
98
   */
99
 
100
  void generate_service_interface (t_service* tservice);
101
  void generate_service_null      (t_service* tservice);
102
  void generate_service_multiface (t_service* tservice);
103
  void generate_service_helpers   (t_service* tservice);
104
  void generate_service_client    (t_service* tservice);
105
  void generate_service_processor (t_service* tservice);
106
  void generate_service_skeleton  (t_service* tservice);
107
  void generate_process_function  (t_service* tservice, t_function* tfunction);
108
  void generate_function_helpers  (t_service* tservice, t_function* tfunction);
109
 
110
  /**
111
   * Serialization constructs
112
   */
113
 
114
  void generate_deserialize_field        (std::ofstream& out,
115
                                          t_field*    tfield,
116
                                          std::string prefix="",
117
                                          std::string suffix="");
118
 
119
  void generate_deserialize_struct       (std::ofstream& out,
120
                                          t_struct*   tstruct,
121
                                          std::string prefix="");
122
 
123
  void generate_deserialize_container    (std::ofstream& out,
124
                                          t_type*     ttype,
125
                                          std::string prefix="");
126
 
127
  void generate_deserialize_set_element  (std::ofstream& out,
128
                                          t_set*      tset,
129
                                          std::string prefix="");
130
 
131
  void generate_deserialize_map_element  (std::ofstream& out,
132
                                          t_map*      tmap,
133
                                          std::string prefix="");
134
 
135
  void generate_deserialize_list_element (std::ofstream& out,
136
                                          t_list*     tlist,
137
                                          std::string prefix,
138
                                          bool push_back,
139
                                          std::string index);
140
 
141
  void generate_serialize_field          (std::ofstream& out,
142
                                          t_field*    tfield,
143
                                          std::string prefix="",
144
                                          std::string suffix="");
145
 
146
  void generate_serialize_struct         (std::ofstream& out,
147
                                          t_struct*   tstruct,
148
                                          std::string prefix="");
149
 
150
  void generate_serialize_container      (std::ofstream& out,
151
                                          t_type*     ttype,
152
                                          std::string prefix="");
153
 
154
  void generate_serialize_map_element    (std::ofstream& out,
155
                                          t_map*      tmap,
156
                                          std::string iter);
157
 
158
  void generate_serialize_set_element    (std::ofstream& out,
159
                                          t_set*      tmap,
160
                                          std::string iter);
161
 
162
  void generate_serialize_list_element   (std::ofstream& out,
163
                                          t_list*     tlist,
164
                                          std::string iter);
165
 
166
  /**
167
   * Helper rendering functions
168
   */
169
 
170
  std::string namespace_prefix(std::string ns);
171
  std::string namespace_open(std::string ns);
172
  std::string namespace_close(std::string ns);
173
  std::string type_name(t_type* ttype, bool in_typedef=false, bool arg=false);
174
  std::string base_type_name(t_base_type::t_base tbase);
175
  std::string declare_field(t_field* tfield, bool init=false, bool pointer=false, bool constant=false, bool reference=false);
176
  std::string function_signature(t_function* tfunction, std::string prefix="", bool name_params=true);
177
  std::string argument_list(t_struct* tstruct, bool name_params=true);
178
  std::string type_to_enum(t_type* ttype);
179
  std::string local_reflection_name(const char*, t_type* ttype, bool external=false);
180
 
181
  // These handles checking gen_dense_ and checking for duplicates.
182
  void generate_local_reflection(std::ofstream& out, t_type* ttype, bool is_definition);
183
  void generate_local_reflection_pointer(std::ofstream& out, t_type* ttype);
184
 
185
  bool is_complex_type(t_type* ttype) {
186
    ttype = get_true_type(ttype);
187
 
188
    return
189
      ttype->is_container() ||
190
      ttype->is_struct() ||
191
      ttype->is_xception() ||
192
      (ttype->is_base_type() && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING));
193
  }
194
 
195
  void set_use_include_prefix(bool use_include_prefix) {
196
    use_include_prefix_ = use_include_prefix;
197
  }
198
 
199
 private:
200
  /**
201
   * Returns the include prefix to use for a file generated by program, or the
202
   * empty string if no include prefix should be used.
203
   */
204
  std::string get_include_prefix(const t_program& program) const;
205
 
206
  /**
207
   * True iff we should generate local reflection metadata for TDenseProtocol.
208
   */
209
  bool gen_dense_;
210
 
211
  /**
212
   * True iff we should use a path prefix in our #include statements for other
213
   * thrift-generated header files.
214
   */
215
  bool use_include_prefix_;
216
 
217
  /**
218
   * Strings for namespace, computed once up front then used directly
219
   */
220
 
221
  std::string ns_open_;
222
  std::string ns_close_;
223
 
224
  /**
225
   * File streams, stored here to avoid passing them as parameters to every
226
   * function.
227
   */
228
 
229
  std::ofstream f_types_;
230
  std::ofstream f_types_impl_;
231
  std::ofstream f_header_;
232
  std::ofstream f_service_;
233
 
234
  /**
235
   * When generating local reflections, make sure we don't generate duplicates.
236
   */
237
  std::set<std::string> reflected_fingerprints_;
238
};
239
 
240
 
241
/**
242
 * Prepares for file generation by opening up the necessary file output
243
 * streams.
244
 *
245
 * @param tprogram The program to generate
246
 */
247
void t_cpp_generator::init_generator() {
248
  // Make output directory
249
  MKDIR(get_out_dir().c_str());
250
 
251
  // Make output file
252
  string f_types_name = get_out_dir()+program_name_+"_types.h";
253
  f_types_.open(f_types_name.c_str());
254
 
255
  string f_types_impl_name = get_out_dir()+program_name_+"_types.cpp";
256
  f_types_impl_.open(f_types_impl_name.c_str());
257
 
258
  // Print header
259
  f_types_ <<
260
    autogen_comment();
261
  f_types_impl_ <<
262
    autogen_comment();
263
 
264
  // Start ifndef
265
  f_types_ <<
266
    "#ifndef " << program_name_ << "_TYPES_H" << endl <<
267
    "#define " << program_name_ << "_TYPES_H" << endl <<
268
    endl;
269
 
270
  // Include base types
271
  f_types_ <<
272
    "#include <Thrift.h>" << endl <<
273
    "#include <protocol/TProtocol.h>" << endl <<
274
    "#include <transport/TTransport.h>" << endl <<
275
    endl;
276
 
277
  // Include other Thrift includes
278
  const vector<t_program*>& includes = program_->get_includes();
279
  for (size_t i = 0; i < includes.size(); ++i) {
280
    f_types_ <<
281
      "#include \"" << get_include_prefix(*(includes[i])) <<
282
      includes[i]->get_name() << "_types.h\"" << endl;
283
  }
284
  f_types_ << endl;
285
 
286
  // Include custom headers
287
  const vector<string>& cpp_includes = program_->get_cpp_includes();
288
  for (size_t i = 0; i < cpp_includes.size(); ++i) {
289
    if (cpp_includes[i][0] == '<') {
290
      f_types_ <<
291
        "#include " << cpp_includes[i] << endl;
292
    } else {
293
      f_types_ <<
294
        "#include \"" << cpp_includes[i] << "\"" << endl;
295
    }
296
  }
297
  f_types_ <<
298
    endl;
299
 
300
  // Include the types file
301
  f_types_impl_ <<
302
    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
303
    "_types.h\"" << endl <<
304
    endl;
305
 
306
  // If we are generating local reflection metadata, we need to include
307
  // the definition of TypeSpec.
308
  if (gen_dense_) {
309
    f_types_impl_ <<
310
      "#include <TReflectionLocal.h>" << endl <<
311
      endl;
312
  }
313
 
314
  // Open namespace
315
  ns_open_ = namespace_open(program_->get_namespace("cpp"));
316
  ns_close_ = namespace_close(program_->get_namespace("cpp"));
317
 
318
  f_types_ <<
319
    ns_open_ << endl <<
320
    endl;
321
 
322
  f_types_impl_ <<
323
    ns_open_ << endl <<
324
    endl;
325
}
326
 
327
/**
328
 * Closes the output files.
329
 */
330
void t_cpp_generator::close_generator() {
331
  // Close namespace
332
  f_types_ <<
333
    ns_close_ << endl <<
334
    endl;
335
  f_types_impl_ <<
336
    ns_close_ << endl;
337
 
338
  // Close ifndef
339
  f_types_ <<
340
    "#endif" << endl;
341
 
342
  // Close output file
343
  f_types_.close();
344
  f_types_impl_.close();
345
}
346
 
347
/**
348
 * Generates a typedef. This is just a simple 1-liner in C++
349
 *
350
 * @param ttypedef The type definition
351
 */
352
void t_cpp_generator::generate_typedef(t_typedef* ttypedef) {
353
  f_types_ <<
354
    indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << ttypedef->get_symbolic() << ";" << endl <<
355
    endl;
356
}
357
 
358
/**
359
 * Generates code for an enumerated type. In C++, this is essentially the same
360
 * as the thrift definition itself, using the enum keyword in C++.
361
 *
362
 * @param tenum The enumeration
363
 */
364
void t_cpp_generator::generate_enum(t_enum* tenum) {
365
  f_types_ <<
366
    indent() << "enum " << tenum->get_name() << " {" << endl;
367
  indent_up();
368
 
369
  vector<t_enum_value*> constants = tenum->get_constants();
370
  vector<t_enum_value*>::iterator c_iter;
371
  bool first = true;
372
  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
373
    if (first) {
374
      first = false;
375
    } else {
376
      f_types_ <<
377
        "," << endl;
378
    }
379
    f_types_ <<
380
      indent() << (*c_iter)->get_name();
381
    if ((*c_iter)->has_value()) {
382
      f_types_ <<
383
        " = " << (*c_iter)->get_value();
384
    }
385
  }
386
 
387
  indent_down();
388
  f_types_ <<
389
    endl <<
390
    "};" << endl <<
391
    endl;
392
 
393
  generate_local_reflection(f_types_, tenum, false);
394
  generate_local_reflection(f_types_impl_, tenum, true);
395
}
396
 
397
/**
398
 * Generates a class that holds all the constants.
399
 */
400
void t_cpp_generator::generate_consts(std::vector<t_const*> consts) {
401
  string f_consts_name = get_out_dir()+program_name_+"_constants.h";
402
  ofstream f_consts;
403
  f_consts.open(f_consts_name.c_str());
404
 
405
  string f_consts_impl_name = get_out_dir()+program_name_+"_constants.cpp";
406
  ofstream f_consts_impl;
407
  f_consts_impl.open(f_consts_impl_name.c_str());
408
 
409
  // Print header
410
  f_consts <<
411
    autogen_comment();
412
  f_consts_impl <<
413
    autogen_comment();
414
 
415
  // Start ifndef
416
  f_consts <<
417
    "#ifndef " << program_name_ << "_CONSTANTS_H" << endl <<
418
    "#define " << program_name_ << "_CONSTANTS_H" << endl <<
419
    endl <<
420
    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
421
    "_types.h\"" << endl <<
422
    endl <<
423
    ns_open_ << endl <<
424
    endl;
425
 
426
  f_consts_impl <<
427
    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
428
    "_constants.h\"" << endl <<
429
    endl <<
430
    ns_open_ << endl <<
431
    endl;
432
 
433
  f_consts <<
434
    "class " << program_name_ << "Constants {" << endl <<
435
    " public:" << endl <<
436
    "  " << program_name_ << "Constants();" << endl <<
437
    endl;
438
  indent_up();
439
  vector<t_const*>::iterator c_iter;
440
  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
441
    string name = (*c_iter)->get_name();
442
    t_type* type = (*c_iter)->get_type();
443
    f_consts <<
444
      indent() << type_name(type) << " " << name << ";" << endl;
445
  }
446
  indent_down();
447
  f_consts <<
448
    "};" << endl;
449
 
450
  f_consts_impl <<
451
    "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
452
    endl <<
453
    program_name_ << "Constants::" << program_name_ << "Constants() {" << endl;
454
  indent_up();
455
  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
456
    print_const_value(f_consts_impl,
457
                      (*c_iter)->get_name(),
458
                      (*c_iter)->get_type(),
459
                      (*c_iter)->get_value());
460
  }
461
  indent_down();
462
  indent(f_consts_impl) <<
463
    "}" << endl;
464
 
465
  f_consts <<
466
    endl <<
467
    "extern const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
468
    endl <<
469
    ns_close_ << endl <<
470
    endl <<
471
    "#endif" << endl;
472
  f_consts.close();
473
 
474
  f_consts_impl <<
475
    endl <<
476
    ns_close_ << endl <<
477
    endl;
478
}
479
 
480
/**
481
 * Prints the value of a constant with the given type. Note that type checking
482
 * is NOT performed in this function as it is always run beforehand using the
483
 * validate_types method in main.cc
484
 */
485
void t_cpp_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
486
  type = get_true_type(type);
487
  if (type->is_base_type()) {
488
    string v2 = render_const_value(out, name, type, value);
489
    indent(out) << name << " = " << v2 << ";" << endl <<
490
      endl;
491
  } else if (type->is_enum()) {
492
    indent(out) << name << " = (" << type_name(type) << ")" << value->get_integer() << ";" << endl <<
493
      endl;
494
  } else if (type->is_struct() || type->is_xception()) {
495
    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
496
    vector<t_field*>::const_iterator f_iter;
497
    const map<t_const_value*, t_const_value*>& val = value->get_map();
498
    map<t_const_value*, t_const_value*>::const_iterator v_iter;
499
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
500
      t_type* field_type = NULL;
501
      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
502
        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
503
          field_type = (*f_iter)->get_type();
504
        }
505
      }
506
      if (field_type == NULL) {
507
        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
508
      }
509
      string val = render_const_value(out, name, field_type, v_iter->second);
510
      indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
511
      indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
512
    }
513
    out << endl;
514
  } else if (type->is_map()) {
515
    t_type* ktype = ((t_map*)type)->get_key_type();
516
    t_type* vtype = ((t_map*)type)->get_val_type();
517
    const map<t_const_value*, t_const_value*>& val = value->get_map();
518
    map<t_const_value*, t_const_value*>::const_iterator v_iter;
519
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
520
      string key = render_const_value(out, name, ktype, v_iter->first);
521
      string val = render_const_value(out, name, vtype, v_iter->second);
522
      indent(out) << name << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
523
    }
524
    out << endl;
525
  } else if (type->is_list()) {
526
    t_type* etype = ((t_list*)type)->get_elem_type();
527
    const vector<t_const_value*>& val = value->get_list();
528
    vector<t_const_value*>::const_iterator v_iter;
529
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
530
      string val = render_const_value(out, name, etype, *v_iter);
531
      indent(out) << name << ".push_back(" << val << ");" << endl;
532
    }
533
    out << endl;
534
  } else if (type->is_set()) {
535
    t_type* etype = ((t_set*)type)->get_elem_type();
536
    const vector<t_const_value*>& val = value->get_list();
537
    vector<t_const_value*>::const_iterator v_iter;
538
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
539
      string val = render_const_value(out, name, etype, *v_iter);
540
      indent(out) << name << ".insert(" << val << ");" << endl;
541
    }
542
    out << endl;
543
  } else {
544
    throw "INVALID TYPE IN print_const_value: " + type->get_name();
545
  }
546
}
547
 
548
/**
549
 *
550
 */
551
string t_cpp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
552
  std::ostringstream render;
553
 
554
  if (type->is_base_type()) {
555
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
556
    switch (tbase) {
557
    case t_base_type::TYPE_STRING:
558
      render << '"' << get_escaped_string(value) << '"';
559
      break;
560
    case t_base_type::TYPE_BOOL:
561
      render << ((value->get_integer() > 0) ? "true" : "false");
562
      break;
563
    case t_base_type::TYPE_BYTE:
564
    case t_base_type::TYPE_I16:
565
    case t_base_type::TYPE_I32:
566
      render << value->get_integer();
567
      break;
568
    case t_base_type::TYPE_I64:
569
      render << value->get_integer() << "LL";
570
      break;
571
    case t_base_type::TYPE_DOUBLE:
572
      if (value->get_type() == t_const_value::CV_INTEGER) {
573
        render << value->get_integer();
574
      } else {
575
        render << value->get_double();
576
      }
577
      break;
578
    default:
579
      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
580
    }
581
  } else if (type->is_enum()) {
582
    render << "(" << type_name(type) << ")" << value->get_integer();
583
  } else {
584
    string t = tmp("tmp");
585
    indent(out) << type_name(type) << " " << t << ";" << endl;
586
    print_const_value(out, t, type, value);
587
    render << t;
588
  }
589
 
590
  return render.str();
591
}
592
 
593
/**
594
 * Generates a struct definition for a thrift data type. This is a class
595
 * with data members and a read/write() function, plus a mirroring isset
596
 * inner class.
597
 *
598
 * @param tstruct The struct definition
599
 */
600
void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) {
601
  generate_struct_definition(f_types_, tstruct, is_exception);
602
  generate_struct_fingerprint(f_types_impl_, tstruct, true);
603
  generate_local_reflection(f_types_, tstruct, false);
604
  generate_local_reflection(f_types_impl_, tstruct, true);
605
  generate_local_reflection_pointer(f_types_impl_, tstruct);
606
  generate_struct_reader(f_types_impl_, tstruct);
607
  generate_struct_writer(f_types_impl_, tstruct);
608
}
609
 
610
/**
611
 * Writes the struct definition into the header file
612
 *
613
 * @param out Output stream
614
 * @param tstruct The struct
615
 */
616
void t_cpp_generator::generate_struct_definition(ofstream& out,
617
                                                 t_struct* tstruct,
618
                                                 bool is_exception,
619
                                                 bool pointers,
620
                                                 bool read,
621
                                                 bool write) {
622
  string extends = "";
623
  if (is_exception) {
624
    extends = " : public ::apache::thrift::TException";
625
  }
626
 
627
  // Open struct def
628
  out <<
629
    indent() << "class " << tstruct->get_name() << extends << " {" << endl <<
630
    indent() << " public:" << endl <<
631
    endl;
632
  indent_up();
633
 
634
  // Put the fingerprint up top for all to see.
635
  generate_struct_fingerprint(out, tstruct, false);
636
 
637
  // Get members
638
  vector<t_field*>::const_iterator m_iter;
639
  const vector<t_field*>& members = tstruct->get_members();
640
 
641
  if (!pointers) {
642
    // Default constructor
643
    indent(out) <<
644
      tstruct->get_name() << "()";
645
 
646
    bool init_ctor = false;
647
 
648
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
649
      t_type* t = get_true_type((*m_iter)->get_type());
650
      if (t->is_base_type()) {
651
        string dval;
652
        if (t->is_enum()) {
653
          dval += "(" + type_name(t) + ")";
654
        }
655
        dval += t->is_string() ? "\"\"" : "0";
656
        t_const_value* cv = (*m_iter)->get_value();
657
        if (cv != NULL) {
658
          dval = render_const_value(out, (*m_iter)->get_name(), t, cv);
659
        }
660
        if (!init_ctor) {
661
          init_ctor = true;
662
          out << " : ";
663
          out << (*m_iter)->get_name() << "(" << dval << ")";
664
        } else {
665
          out << ", " << (*m_iter)->get_name() << "(" << dval << ")";
666
        }
667
      }
668
    }
669
    out << " {" << endl;
670
    indent_up();
671
    // TODO(dreiss): When everything else in Thrift is perfect,
672
    // do more of these in the initializer list.
673
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
674
      t_type* t = get_true_type((*m_iter)->get_type());
675
 
676
      if (!t->is_base_type()) {
677
        t_const_value* cv = (*m_iter)->get_value();
678
        if (cv != NULL) {
679
          print_const_value(out, (*m_iter)->get_name(), t, cv);
680
        }
681
      }
682
    }
683
    scope_down(out);
684
  }
685
 
686
  if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) {
687
    out <<
688
      endl <<
689
      indent() << "virtual ~" << tstruct->get_name() << "() throw() {}" << endl << endl;
690
  }
691
 
692
  // Pointer to this structure's reflection local typespec.
693
  if (gen_dense_) {
694
    indent(out) <<
695
      "static ::apache::thrift::reflection::local::TypeSpec* local_reflection;" <<
696
      endl << endl;
697
  }
698
 
699
  // Declare all fields
700
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
701
    indent(out) <<
702
      declare_field(*m_iter, false, pointers && !(*m_iter)->get_type()->is_xception(), !read) << endl;
703
  }
704
 
705
  // Isset struct has boolean fields, but only for non-required fields.
706
  bool has_nonrequired_fields = false;
707
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
708
    if ((*m_iter)->get_req() != t_field::T_REQUIRED)
709
      has_nonrequired_fields = true;
710
  }
711
 
712
  if (has_nonrequired_fields && (!pointers || read)) {
713
    out <<
714
      endl <<
715
      indent() << "struct __isset {" << endl;
716
    indent_up();
717
 
718
      indent(out) <<
719
        "__isset() : ";
720
      bool first = true;
721
      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
722
        if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
723
          continue;
724
        }
725
        if (first) {
726
          first = false;
727
          out <<
728
            (*m_iter)->get_name() << "(false)";
729
        } else {
730
          out <<
731
            ", " << (*m_iter)->get_name() << "(false)";
732
        }
733
      }
734
      out << " {}" << endl;
735
 
736
      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
737
        if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
738
          indent(out) <<
739
            "bool " << (*m_iter)->get_name() << ";" << endl;
740
        }
741
      }
742
 
743
    indent_down();
744
    indent(out) <<
745
      "} __isset;" << endl;
746
  }
747
 
748
  out << endl;
749
 
750
  if (!pointers) {
751
    // Generate an equality testing operator.  Make it inline since the compiler
752
    // will do a better job than we would when deciding whether to inline it.
753
    out <<
754
      indent() << "bool operator == (const " << tstruct->get_name() << " & " <<
755
      (members.size() > 0 ? "rhs" : "/* rhs */") << ") const" << endl;
756
    scope_up(out);
757
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
758
      // Most existing Thrift code does not use isset or optional/required,
759
      // so we treat "default" fields as required.
760
      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
761
        out <<
762
          indent() << "if (!(" << (*m_iter)->get_name()
763
                   << " == rhs." << (*m_iter)->get_name() << "))" << endl <<
764
          indent() << "  return false;" << endl;
765
      } else {
766
        out <<
767
          indent() << "if (__isset." << (*m_iter)->get_name()
768
                   << " != rhs.__isset." << (*m_iter)->get_name() << ")" << endl <<
769
          indent() << "  return false;" << endl <<
770
          indent() << "else if (__isset." << (*m_iter)->get_name() << " && !("
771
                   << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name()
772
                   << "))" << endl <<
773
          indent() << "  return false;" << endl;
774
      }
775
    }
776
    indent(out) << "return true;" << endl;
777
    scope_down(out);
778
    out <<
779
      indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" << endl <<
780
      indent() << "  return !(*this == rhs);" << endl <<
781
      indent() << "}" << endl << endl;
782
 
783
    // Generate the declaration of a less-than operator.  This must be
784
    // implemented by the application developer if they wish to use it.  (They
785
    // will get a link error if they try to use it without an implementation.)
786
    out <<
787
      indent() << "bool operator < (const "
788
               << tstruct->get_name() << " & ) const;" << endl << endl;
789
  }
790
  if (read) {
791
    out <<
792
      indent() << "uint32_t read(::apache::thrift::protocol::TProtocol* iprot);" << endl;
793
  }
794
  if (write) {
795
    out <<
796
      indent() << "uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;" << endl;
797
  }
798
  out << endl;
799
 
800
  indent_down();
801
  indent(out) <<
802
    "};" << endl <<
803
    endl;
804
}
805
 
806
/**
807
 * Writes the fingerprint of a struct to either the header or implementation.
808
 *
809
 * @param out Output stream
810
 * @param tstruct The struct
811
 */
812
void t_cpp_generator::generate_struct_fingerprint(ofstream& out,
813
                                                  t_struct* tstruct,
814
                                                  bool is_definition) {
815
  string stat, nspace, comment;
816
  if (is_definition) {
817
    stat = "";
818
    nspace = tstruct->get_name() + "::";
819
    comment = " ";
820
  } else {
821
    stat = "static ";
822
    nspace = "";
823
    comment = "; // ";
824
  }
825
 
826
  if (tstruct->has_fingerprint()) {
827
    out <<
828
      indent() << stat << "const char* " << nspace
829
        << "ascii_fingerprint" << comment << "= \"" <<
830
        tstruct->get_ascii_fingerprint() << "\";" << endl <<
831
      indent() << stat << "const uint8_t " << nspace <<
832
        "binary_fingerprint[" << t_type::fingerprint_len << "]" << comment << "= {";
833
    const char* comma = "";
834
    for (int i = 0; i < t_type::fingerprint_len; i++) {
835
      out << comma << "0x" << t_struct::byte_to_hex(tstruct->get_binary_fingerprint()[i]);
836
      comma = ",";
837
    }
838
    out << "};" << endl << endl;
839
  }
840
}
841
 
842
/**
843
 * Writes the local reflection of a type (either declaration or definition).
844
 */
845
void t_cpp_generator::generate_local_reflection(std::ofstream& out,
846
                                                t_type* ttype,
847
                                                bool is_definition) {
848
  if (!gen_dense_) {
849
    return;
850
  }
851
  ttype = get_true_type(ttype);
852
  assert(ttype->has_fingerprint());
853
  string key = ttype->get_ascii_fingerprint() + (is_definition ? "-defn" : "-decl");
854
  // Note that we have generated this fingerprint.  If we already did, bail out.
855
  if (!reflected_fingerprints_.insert(key).second) {
856
    return;
857
  }
858
  // Let each program handle its own structures.
859
  if (ttype->get_program() != NULL && ttype->get_program() != program_) {
860
    return;
861
  }
862
 
863
  // Do dependencies.
864
  if (ttype->is_list()) {
865
    generate_local_reflection(out, ((t_list*)ttype)->get_elem_type(), is_definition);
866
  } else if (ttype->is_set()) {
867
    generate_local_reflection(out, ((t_set*)ttype)->get_elem_type(), is_definition);
868
  } else if (ttype->is_map()) {
869
    generate_local_reflection(out, ((t_map*)ttype)->get_key_type(), is_definition);
870
    generate_local_reflection(out, ((t_map*)ttype)->get_val_type(), is_definition);
871
  } else if (ttype->is_struct() || ttype->is_xception()) {
872
    // Hacky hacky.  For efficiency and convenience, we need a dummy "T_STOP"
873
    // type at the end of our typespec array.  Unfortunately, there is no
874
    // T_STOP type, so we use the global void type, and special case it when
875
    // generating its typespec.
876
 
877
    const vector<t_field*>& members = ((t_struct*)ttype)->get_sorted_members();
878
    vector<t_field*>::const_iterator m_iter;
879
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
880
      generate_local_reflection(out, (**m_iter).get_type(), is_definition);
881
    }
882
    generate_local_reflection(out, g_type_void, is_definition);
883
 
884
    // For definitions of structures, do the arrays of metas and field specs also.
885
    if (is_definition) {
886
      out <<
887
        indent() << "::apache::thrift::reflection::local::FieldMeta" << endl <<
888
        indent() << local_reflection_name("metas", ttype) <<"[] = {" << endl;
889
      indent_up();
890
      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
891
        indent(out) << "{ " << (*m_iter)->get_key() << ", " <<
892
          (((*m_iter)->get_req() == t_field::T_OPTIONAL) ? "true" : "false") <<
893
          " }," << endl;
894
      }
895
      // Zero for the T_STOP marker.
896
      indent(out) << "{ 0, false }" << endl << "};" << endl;
897
      indent_down();
898
 
899
      out <<
900
        indent() << "::apache::thrift::reflection::local::TypeSpec*" << endl <<
901
        indent() << local_reflection_name("specs", ttype) <<"[] = {" << endl;
902
      indent_up();
903
      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
904
        indent(out) << "&" <<
905
          local_reflection_name("typespec", (*m_iter)->get_type(), true) << "," << endl;
906
      }
907
      indent(out) << "&" <<
908
        local_reflection_name("typespec", g_type_void) << "," << endl;
909
      indent_down();
910
      indent(out) << "};" << endl;
911
    }
912
  }
913
 
914
  out <<
915
    indent() << "// " << ttype->get_fingerprint_material() << endl <<
916
    indent() << (is_definition ? "" : "extern ") <<
917
      "::apache::thrift::reflection::local::TypeSpec" << endl <<
918
      local_reflection_name("typespec", ttype) <<
919
      (is_definition ? "(" : ";") << endl;
920
 
921
  if (!is_definition) {
922
    out << endl;
923
    return;
924
  }
925
 
926
  indent_up();
927
 
928
  if (ttype->is_void()) {
929
    indent(out) << "::apache::thrift::protocol::T_STOP";
930
  } else {
931
    indent(out) << type_to_enum(ttype);
932
  }
933
 
934
  if (ttype->is_struct()) {
935
    out << "," << endl <<
936
      indent() << type_name(ttype) << "::binary_fingerprint," << endl <<
937
      indent() << local_reflection_name("metas", ttype) << "," << endl <<
938
      indent() << local_reflection_name("specs", ttype);
939
  } else if (ttype->is_list()) {
940
    out << "," << endl <<
941
      indent() << "&" << local_reflection_name("typespec", ((t_list*)ttype)->get_elem_type()) << "," << endl <<
942
      indent() << "NULL";
943
  } else if (ttype->is_set()) {
944
    out << "," << endl <<
945
      indent() << "&" << local_reflection_name("typespec", ((t_set*)ttype)->get_elem_type()) << "," << endl <<
946
      indent() << "NULL";
947
  } else if (ttype->is_map()) {
948
    out << "," << endl <<
949
      indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_key_type()) << "," << endl <<
950
      indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_val_type());
951
  }
952
 
953
  out << ");" << endl << endl;
954
 
955
  indent_down();
956
}
957
 
958
/**
959
 * Writes the structure's static pointer to its local reflection typespec
960
 * into the implementation file.
961
 */
962
void t_cpp_generator::generate_local_reflection_pointer(std::ofstream& out,
963
                                                        t_type* ttype) {
964
  if (!gen_dense_) {
965
    return;
966
  }
967
  indent(out) <<
968
    "::apache::thrift::reflection::local::TypeSpec* " <<
969
      ttype->get_name() << "::local_reflection = " << endl <<
970
    indent() << "  &" << local_reflection_name("typespec", ttype) << ";" <<
971
    endl << endl;
972
}
973
 
974
/**
975
 * Makes a helper function to gen a struct reader.
976
 *
977
 * @param out Stream to write to
978
 * @param tstruct The struct
979
 */
980
void t_cpp_generator::generate_struct_reader(ofstream& out,
981
                                             t_struct* tstruct,
982
                                             bool pointers) {
983
  indent(out) <<
984
    "uint32_t " << tstruct->get_name() << "::read(::apache::thrift::protocol::TProtocol* iprot) {" << endl;
985
  indent_up();
986
 
987
  const vector<t_field*>& fields = tstruct->get_members();
988
  vector<t_field*>::const_iterator f_iter;
989
 
990
  // Declare stack tmp variables
991
  out <<
992
    endl <<
993
    indent() << "uint32_t xfer = 0;" << endl <<
994
    indent() << "std::string fname;" << endl <<
995
    indent() << "::apache::thrift::protocol::TType ftype;" << endl <<
996
    indent() << "int16_t fid;" << endl <<
997
    endl <<
998
    indent() << "xfer += iprot->readStructBegin(fname);" << endl <<
999
    endl <<
1000
    indent() << "using ::apache::thrift::protocol::TProtocolException;" << endl <<
1001
    endl;
1002
 
1003
  // Required variables aren't in __isset, so we need tmp vars to check them.
1004
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1005
    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
1006
      indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
1007
  }
1008
  out << endl;
1009
 
1010
 
1011
  // Loop over reading in fields
1012
  indent(out) <<
1013
    "while (true)" << endl;
1014
    scope_up(out);
1015
 
1016
    // Read beginning field marker
1017
    indent(out) <<
1018
      "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
1019
 
1020
    // Check for field STOP marker
1021
    out <<
1022
      indent() << "if (ftype == ::apache::thrift::protocol::T_STOP) {" << endl <<
1023
      indent() << "  break;" << endl <<
1024
      indent() << "}" << endl;
1025
 
1026
    // Switch statement on the field we are reading
1027
    indent(out) <<
1028
      "switch (fid)" << endl;
1029
 
1030
      scope_up(out);
1031
 
1032
      // Generate deserialization code for known cases
1033
      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1034
        indent(out) <<
1035
          "case " << (*f_iter)->get_key() << ":" << endl;
1036
        indent_up();
1037
        indent(out) <<
1038
          "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
1039
        indent_up();
1040
 
1041
        const char *isset_prefix =
1042
          ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset." : "isset_";
1043
 
1044
#if 0
1045
        // This code throws an exception if the same field is encountered twice.
1046
        // We've decided to leave it out for performance reasons.
1047
        // TODO(dreiss): Generate this code and "if" it out to make it easier
1048
        // for people recompiling thrift to include it.
1049
        out <<
1050
          indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl <<
1051
          indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
1052
#endif
1053
 
1054
        if (pointers && !(*f_iter)->get_type()->is_xception()) {
1055
          generate_deserialize_field(out, *f_iter, "(*(this->", "))");
1056
        } else {
1057
          generate_deserialize_field(out, *f_iter, "this->");
1058
        }
1059
        out <<
1060
          indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl;
1061
        indent_down();
1062
        out <<
1063
          indent() << "} else {" << endl <<
1064
          indent() << "  xfer += iprot->skip(ftype);" << endl <<
1065
          // TODO(dreiss): Make this an option when thrift structs
1066
          // have a common base class.
1067
          // indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl <<
1068
          indent() << "}" << endl <<
1069
          indent() << "break;" << endl;
1070
        indent_down();
1071
      }
1072
 
1073
      // In the default case we skip the field
1074
      out <<
1075
        indent() << "default:" << endl <<
1076
        indent() << "  xfer += iprot->skip(ftype);" << endl <<
1077
        indent() << "  break;" << endl;
1078
 
1079
      scope_down(out);
1080
 
1081
    // Read field end marker
1082
    indent(out) <<
1083
      "xfer += iprot->readFieldEnd();" << endl;
1084
 
1085
    scope_down(out);
1086
 
1087
  out <<
1088
    endl <<
1089
    indent() << "xfer += iprot->readStructEnd();" << endl;
1090
 
1091
  // Throw if any required fields are missing.
1092
  // We do this after reading the struct end so that
1093
  // there might possibly be a chance of continuing.
1094
  out << endl;
1095
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1096
    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
1097
      out <<
1098
        indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl <<
1099
        indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
1100
  }
1101
 
1102
  indent(out) << "return xfer;" << endl;
1103
 
1104
  indent_down();
1105
  indent(out) <<
1106
    "}" << endl << endl;
1107
}
1108
 
1109
/**
1110
 * Generates the write function.
1111
 *
1112
 * @param out Stream to write to
1113
 * @param tstruct The struct
1114
 */
1115
void t_cpp_generator::generate_struct_writer(ofstream& out,
1116
                                             t_struct* tstruct,
1117
                                             bool pointers) {
1118
  string name = tstruct->get_name();
1119
  const vector<t_field*>& fields = tstruct->get_sorted_members();
1120
  vector<t_field*>::const_iterator f_iter;
1121
 
1122
  indent(out) <<
1123
    "uint32_t " << tstruct->get_name() << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
1124
  indent_up();
1125
 
1126
  out <<
1127
    indent() << "uint32_t xfer = 0;" << endl;
1128
 
1129
  indent(out) <<
1130
    "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
1131
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1132
    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
1133
      indent(out) << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
1134
      indent_up();
1135
    }
1136
    // Write field header
1137
    out <<
1138
      indent() << "xfer += oprot->writeFieldBegin(" <<
1139
      "\"" << (*f_iter)->get_name() << "\", " <<
1140
      type_to_enum((*f_iter)->get_type()) << ", " <<
1141
      (*f_iter)->get_key() << ");" << endl;
1142
    // Write field contents
1143
    if (pointers) {
1144
      generate_serialize_field(out, *f_iter, "(*(this->", "))");
1145
    } else {
1146
      generate_serialize_field(out, *f_iter, "this->");
1147
    }
1148
    // Write field closer
1149
    indent(out) <<
1150
      "xfer += oprot->writeFieldEnd();" << endl;
1151
    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
1152
      indent_down();
1153
      indent(out) << '}' << endl;
1154
    }
1155
  }
1156
 
1157
  // Write the struct map
1158
  out <<
1159
    indent() << "xfer += oprot->writeFieldStop();" << endl <<
1160
    indent() << "xfer += oprot->writeStructEnd();" << endl <<
1161
    indent() << "return xfer;" << endl;
1162
 
1163
  indent_down();
1164
  indent(out) <<
1165
    "}" << endl <<
1166
    endl;
1167
}
1168
 
1169
/**
1170
 * Struct writer for result of a function, which can have only one of its
1171
 * fields set and does a conditional if else look up into the __isset field
1172
 * of the struct.
1173
 *
1174
 * @param out Output stream
1175
 * @param tstruct The result struct
1176
 */
1177
void t_cpp_generator::generate_struct_result_writer(ofstream& out,
1178
                                                    t_struct* tstruct,
1179
                                                    bool pointers) {
1180
  string name = tstruct->get_name();
1181
  const vector<t_field*>& fields = tstruct->get_sorted_members();
1182
  vector<t_field*>::const_iterator f_iter;
1183
 
1184
  indent(out) <<
1185
    "uint32_t " << tstruct->get_name() << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
1186
  indent_up();
1187
 
1188
  out <<
1189
    endl <<
1190
    indent() << "uint32_t xfer = 0;" << endl <<
1191
    endl;
1192
 
1193
  indent(out) <<
1194
    "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
1195
 
1196
  bool first = true;
1197
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1198
    if (first) {
1199
      first = false;
1200
      out <<
1201
        endl <<
1202
        indent() << "if ";
1203
    } else {
1204
      out <<
1205
        " else if ";
1206
    }
1207
 
1208
    out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
1209
 
1210
    indent_up();
1211
 
1212
    // Write field header
1213
    out <<
1214
      indent() << "xfer += oprot->writeFieldBegin(" <<
1215
      "\"" << (*f_iter)->get_name() << "\", " <<
1216
      type_to_enum((*f_iter)->get_type()) << ", " <<
1217
      (*f_iter)->get_key() << ");" << endl;
1218
    // Write field contents
1219
    if (pointers) {
1220
      generate_serialize_field(out, *f_iter, "(*(this->", "))");
1221
    } else {
1222
      generate_serialize_field(out, *f_iter, "this->");
1223
    }
1224
    // Write field closer
1225
    indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
1226
 
1227
    indent_down();
1228
    indent(out) << "}";
1229
  }
1230
 
1231
  // Write the struct map
1232
  out <<
1233
    endl <<
1234
    indent() << "xfer += oprot->writeFieldStop();" << endl <<
1235
    indent() << "xfer += oprot->writeStructEnd();" << endl <<
1236
    indent() << "return xfer;" << endl;
1237
 
1238
  indent_down();
1239
  indent(out) <<
1240
    "}" << endl <<
1241
    endl;
1242
}
1243
 
1244
/**
1245
 * Generates a thrift service. In C++, this comprises an entirely separate
1246
 * header and source file. The header file defines the methods and includes
1247
 * the data types defined in the main header file, and the implementation
1248
 * file contains implementations of the basic printer and default interfaces.
1249
 *
1250
 * @param tservice The service definition
1251
 */
1252
void t_cpp_generator::generate_service(t_service* tservice) {
1253
  string svcname = tservice->get_name();
1254
 
1255
  // Make output files
1256
  string f_header_name = get_out_dir()+svcname+".h";
1257
  f_header_.open(f_header_name.c_str());
1258
 
1259
  // Print header file includes
1260
  f_header_ <<
1261
    autogen_comment();
1262
  f_header_ <<
1263
    "#ifndef " << svcname << "_H" << endl <<
1264
    "#define " << svcname << "_H" << endl <<
1265
    endl <<
1266
    "#include <TProcessor.h>" << endl <<
1267
    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
1268
    "_types.h\"" << endl;
1269
 
1270
  t_service* extends_service = tservice->get_extends();
1271
  if (extends_service != NULL) {
1272
    f_header_ <<
1273
      "#include \"" << get_include_prefix(*(extends_service->get_program())) <<
1274
      extends_service->get_name() << ".h\"" << endl;
1275
  }
1276
 
1277
  f_header_ <<
1278
    endl <<
1279
    ns_open_ << endl <<
1280
    endl;
1281
 
1282
  // Service implementation file includes
1283
  string f_service_name = get_out_dir()+svcname+".cpp";
1284
  f_service_.open(f_service_name.c_str());
1285
  f_service_ <<
1286
    autogen_comment();
1287
  f_service_ <<
1288
    "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" <<
1289
    endl <<
1290
    endl <<
1291
    ns_open_ << endl <<
1292
    endl;
1293
 
1294
  // Generate all the components
1295
  generate_service_interface(tservice);
1296
  generate_service_null(tservice);
1297
  generate_service_helpers(tservice);
1298
  generate_service_client(tservice);
1299
  generate_service_processor(tservice);
1300
  generate_service_multiface(tservice);
1301
  generate_service_skeleton(tservice);
1302
 
1303
  // Close the namespace
1304
  f_service_ <<
1305
    ns_close_ << endl <<
1306
    endl;
1307
  f_header_ <<
1308
    ns_close_ << endl <<
1309
    endl;
1310
  f_header_ <<
1311
    "#endif" << endl;
1312
 
1313
  // Close the files
1314
  f_service_.close();
1315
  f_header_.close();
1316
}
1317
 
1318
/**
1319
 * Generates helper functions for a service. Basically, this generates types
1320
 * for all the arguments and results to functions.
1321
 *
1322
 * @param tservice The service to generate a header definition for
1323
 */
1324
void t_cpp_generator::generate_service_helpers(t_service* tservice) {
1325
  vector<t_function*> functions = tservice->get_functions();
1326
  vector<t_function*>::iterator f_iter;
1327
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1328
    t_struct* ts = (*f_iter)->get_arglist();
1329
    string name_orig = ts->get_name();
1330
 
1331
    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
1332
    generate_struct_definition(f_header_, ts, false);
1333
    generate_struct_reader(f_service_, ts);
1334
    generate_struct_writer(f_service_, ts);
1335
    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
1336
    generate_struct_definition(f_header_, ts, false, true, false, true);
1337
    generate_struct_writer(f_service_, ts, true);
1338
    ts->set_name(name_orig);
1339
 
1340
    generate_function_helpers(tservice, *f_iter);
1341
  }
1342
}
1343
 
1344
/**
1345
 * Generates a service interface definition.
1346
 *
1347
 * @param tservice The service to generate a header definition for
1348
 */
1349
void t_cpp_generator::generate_service_interface(t_service* tservice) {
1350
  string extends = "";
1351
  if (tservice->get_extends() != NULL) {
1352
    extends = " : virtual public " + type_name(tservice->get_extends()) + "If";
1353
  }
1354
  f_header_ <<
1355
    "class " << service_name_ << "If" << extends << " {" << endl <<
1356
    " public:" << endl;
1357
  indent_up();
1358
  f_header_ <<
1359
    indent() << "virtual ~" << service_name_ << "If() {}" << endl;
1360
 
1361
  vector<t_function*> functions = tservice->get_functions();
1362
  vector<t_function*>::iterator f_iter;
1363
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1364
    f_header_ <<
1365
      indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
1366
  }
1367
  indent_down();
1368
  f_header_ <<
1369
    "};" << endl << endl;
1370
}
1371
 
1372
/**
1373
 * Generates a null implementation of the service.
1374
 *
1375
 * @param tservice The service to generate a header definition for
1376
 */
1377
void t_cpp_generator::generate_service_null(t_service* tservice) {
1378
  string extends = "";
1379
  if (tservice->get_extends() != NULL) {
1380
    extends = " , virtual public " + type_name(tservice->get_extends()) + "Null";
1381
  }
1382
  f_header_ <<
1383
    "class " << service_name_ << "Null : virtual public " << service_name_ << "If" << extends << " {" << endl <<
1384
    " public:" << endl;
1385
  indent_up();
1386
  f_header_ <<
1387
    indent() << "virtual ~" << service_name_ << "Null() {}" << endl;
1388
  vector<t_function*> functions = tservice->get_functions();
1389
  vector<t_function*>::iterator f_iter;
1390
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1391
    f_header_ <<
1392
      indent() << function_signature(*f_iter, "", false) << " {" << endl;
1393
    indent_up();
1394
    t_type* returntype = (*f_iter)->get_returntype();
1395
    if (returntype->is_void()) {
1396
      f_header_ <<
1397
        indent() << "return;" << endl;
1398
    } else if (is_complex_type(returntype)) {
1399
      f_header_ <<
1400
        indent() << "return;" << endl;
1401
    } else {
1402
      t_field returnfield(returntype, "_return");
1403
      f_header_ <<
1404
        indent() << declare_field(&returnfield, true) << endl <<
1405
        indent() << "return _return;" << endl;
1406
    }
1407
    indent_down();
1408
    f_header_ <<
1409
      indent() << "}" << endl;
1410
  }
1411
  indent_down();
1412
  f_header_ <<
1413
    "};" << endl << endl;
1414
}
1415
 
1416
 
1417
/**
1418
 * Generates a multiface, which is a single server that just takes a set
1419
 * of objects implementing the interface and calls them all, returning the
1420
 * value of the last one to be called.
1421
 *
1422
 * @param tservice The service to generate a multiserver for.
1423
 */
1424
void t_cpp_generator::generate_service_multiface(t_service* tservice) {
1425
  // Generate the dispatch methods
1426
  vector<t_function*> functions = tservice->get_functions();
1427
  vector<t_function*>::iterator f_iter;
1428
 
1429
  string extends = "";
1430
  string extends_multiface = "";
1431
  if (tservice->get_extends() != NULL) {
1432
    extends = type_name(tservice->get_extends());
1433
    extends_multiface = ", public " + extends + "Multiface";
1434
  }
1435
 
1436
  string list_type = string("std::vector<boost::shared_ptr<") + service_name_ + "If> >";
1437
 
1438
  // Generate the header portion
1439
  f_header_ <<
1440
    "class " << service_name_ << "Multiface : " <<
1441
    "virtual public " << service_name_ << "If" <<
1442
    extends_multiface << " {" << endl <<
1443
    " public:" << endl;
1444
  indent_up();
1445
  f_header_ <<
1446
    indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl;
1447
  if (!extends.empty()) {
1448
    f_header_ <<
1449
      indent() << "  std::vector<boost::shared_ptr<" + service_name_ + "If> >::iterator iter;" << endl <<
1450
      indent() << "  for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl <<
1451
      indent() << "    " << extends << "Multiface::add(*iter);" << endl <<
1452
      indent() << "  }" << endl;
1453
  }
1454
  f_header_ <<
1455
    indent() << "}" << endl <<
1456
    indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl;
1457
  indent_down();
1458
 
1459
  // Protected data members
1460
  f_header_ <<
1461
    " protected:" << endl;
1462
  indent_up();
1463
  f_header_ <<
1464
    indent() << list_type << " ifaces_;" << endl <<
1465
    indent() << service_name_ << "Multiface() {}" << endl <<
1466
    indent() << "void add(boost::shared_ptr<" << service_name_ << "If> iface) {" << endl;
1467
  if (!extends.empty()) {
1468
    f_header_ <<
1469
      indent() << "  " << extends << "Multiface::add(iface);" << endl;
1470
  }
1471
  f_header_ <<
1472
    indent() << "  ifaces_.push_back(iface);" << endl <<
1473
    indent() << "}" << endl;
1474
  indent_down();
1475
 
1476
  f_header_ <<
1477
    indent() << " public:" << endl;
1478
  indent_up();
1479
 
1480
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1481
    t_struct* arglist = (*f_iter)->get_arglist();
1482
    const vector<t_field*>& args = arglist->get_members();
1483
    vector<t_field*>::const_iterator a_iter;
1484
 
1485
    string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "(";
1486
    bool first = true;
1487
    if (is_complex_type((*f_iter)->get_returntype())) {
1488
      call += "_return";
1489
      first = false;
1490
    }
1491
    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
1492
      if (first) {
1493
        first = false;
1494
      } else {
1495
        call += ", ";
1496
      }
1497
      call += (*a_iter)->get_name();
1498
    }
1499
    call += ")";
1500
 
1501
    f_header_ <<
1502
      indent() << function_signature(*f_iter) << " {" << endl;
1503
    indent_up();
1504
    f_header_ <<
1505
      indent() << "uint32_t sz = ifaces_.size();" << endl <<
1506
      indent() << "for (uint32_t i = 0; i < sz; ++i) {" << endl;
1507
    if (!(*f_iter)->get_returntype()->is_void()) {
1508
      f_header_ <<
1509
        indent() << "  if (i == sz - 1) {" << endl;
1510
      if (is_complex_type((*f_iter)->get_returntype())) {
1511
        f_header_ <<
1512
          indent() << "    " << call << ";" << endl <<
1513
          indent() << "    return;" << endl;
1514
      } else {
1515
        f_header_ <<
1516
          indent() << "    return " << call << ";" << endl;
1517
      }
1518
      f_header_ <<
1519
        indent() << "  } else {" << endl <<
1520
        indent() << "    " << call << ";" << endl <<
1521
        indent() << "  }" << endl;
1522
    } else {
1523
      f_header_ <<
1524
        indent() << "  " << call << ";" << endl;
1525
    }
1526
 
1527
    f_header_ <<
1528
      indent() << "}" << endl;
1529
 
1530
    indent_down();
1531
    f_header_ <<
1532
      indent() << "}" << endl <<
1533
      endl;
1534
  }
1535
 
1536
  indent_down();
1537
  f_header_ <<
1538
    indent() << "};" << endl <<
1539
    endl;
1540
}
1541
 
1542
/**
1543
 * Generates a service client definition.
1544
 *
1545
 * @param tservice The service to generate a server for.
1546
 */
1547
void t_cpp_generator::generate_service_client(t_service* tservice) {
1548
  string extends = "";
1549
  string extends_client = "";
1550
  if (tservice->get_extends() != NULL) {
1551
    extends = type_name(tservice->get_extends());
1552
    extends_client = ", public " + extends + "Client";
1553
  }
1554
 
1555
  // Generate the header portion
1556
  f_header_ <<
1557
    "class " << service_name_ << "Client : " <<
1558
    "virtual public " << service_name_ << "If" <<
1559
    extends_client << " {" << endl <<
1560
    " public:" << endl;
1561
 
1562
  indent_up();
1563
  f_header_ <<
1564
    indent() << service_name_ << "Client(boost::shared_ptr< ::apache::thrift::protocol::TProtocol> prot) :" << endl;
1565
  if (extends.empty()) {
1566
    f_header_ <<
1567
      indent() << "  piprot_(prot)," << endl <<
1568
      indent() << "  poprot_(prot) {" << endl <<
1569
      indent() << "  iprot_ = prot.get();" << endl <<
1570
      indent() << "  oprot_ = prot.get();" << endl <<
1571
      indent() << "}" << endl;
1572
  } else {
1573
    f_header_ <<
1574
      indent() << "  " << extends << "Client(prot, prot) {}" << endl;
1575
  }
1576
 
1577
  f_header_ <<
1578
    indent() << service_name_ << "Client(boost::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, boost::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot) :" << endl;
1579
  if (extends.empty()) {
1580
    f_header_ <<
1581
      indent() << "  piprot_(iprot)," << endl <<
1582
      indent() << "  poprot_(oprot) {" << endl <<
1583
      indent() << "  iprot_ = iprot.get();" << endl <<
1584
      indent() << "  oprot_ = oprot.get();" << endl <<
1585
      indent() << "}" << endl;
1586
  } else {
1587
    f_header_ <<
1588
      indent() << "  " << extends << "Client(iprot, oprot) {}" << endl;
1589
  }
1590
 
1591
  // Generate getters for the protocols.
1592
  f_header_ <<
1593
    indent() << "boost::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() {" << endl <<
1594
    indent() << "  return piprot_;" << endl <<
1595
    indent() << "}" << endl;
1596
 
1597
  f_header_ <<
1598
    indent() << "boost::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() {" << endl <<
1599
    indent() << "  return poprot_;" << endl <<
1600
    indent() << "}" << endl;
1601
 
1602
  vector<t_function*> functions = tservice->get_functions();
1603
  vector<t_function*>::const_iterator f_iter;
1604
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1605
    t_function send_function(g_type_void,
1606
                             string("send_") + (*f_iter)->get_name(),
1607
                             (*f_iter)->get_arglist());
1608
    indent(f_header_) << function_signature(*f_iter) << ";" << endl;
1609
    indent(f_header_) << function_signature(&send_function) << ";" << endl;
1610
    if (!(*f_iter)->is_oneway()) {
1611
      t_struct noargs(program_);
1612
      t_function recv_function((*f_iter)->get_returntype(),
1613
                               string("recv_") + (*f_iter)->get_name(),
1614
                               &noargs);
1615
      indent(f_header_) << function_signature(&recv_function) << ";" << endl;
1616
    }
1617
  }
1618
  indent_down();
1619
 
1620
  if (extends.empty()) {
1621
    f_header_ <<
1622
      " protected:" << endl;
1623
    indent_up();
1624
    f_header_ <<
1625
      indent() << "boost::shared_ptr< ::apache::thrift::protocol::TProtocol> piprot_;"  << endl <<
1626
      indent() << "boost::shared_ptr< ::apache::thrift::protocol::TProtocol> poprot_;"  << endl <<
1627
      indent() << "::apache::thrift::protocol::TProtocol* iprot_;"  << endl <<
1628
      indent() << "::apache::thrift::protocol::TProtocol* oprot_;"  << endl;
1629
    indent_down();
1630
  }
1631
 
1632
  f_header_ <<
1633
    "};" << endl <<
1634
    endl;
1635
 
1636
  string scope = service_name_ + "Client::";
1637
 
1638
  // Generate client method implementations
1639
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1640
    string funname = (*f_iter)->get_name();
1641
 
1642
    // Open function
1643
    indent(f_service_) <<
1644
      function_signature(*f_iter, scope) << endl;
1645
    scope_up(f_service_);
1646
    indent(f_service_) <<
1647
      "send_" << funname << "(";
1648
 
1649
    // Get the struct of function call params
1650
    t_struct* arg_struct = (*f_iter)->get_arglist();
1651
 
1652
    // Declare the function arguments
1653
    const vector<t_field*>& fields = arg_struct->get_members();
1654
    vector<t_field*>::const_iterator fld_iter;
1655
    bool first = true;
1656
    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1657
      if (first) {
1658
        first = false;
1659
      } else {
1660
        f_service_ << ", ";
1661
      }
1662
      f_service_ << (*fld_iter)->get_name();
1663
    }
1664
    f_service_ << ");" << endl;
1665
 
1666
    if (!(*f_iter)->is_oneway()) {
1667
      f_service_ << indent();
1668
      if (!(*f_iter)->get_returntype()->is_void()) {
1669
        if (is_complex_type((*f_iter)->get_returntype())) {
1670
          f_service_ << "recv_" << funname << "(_return);" << endl;
1671
        } else {
1672
          f_service_ << "return recv_" << funname << "();" << endl;
1673
        }
1674
      } else {
1675
        f_service_ <<
1676
          "recv_" << funname << "();" << endl;
1677
      }
1678
    }
1679
    scope_down(f_service_);
1680
    f_service_ << endl;
1681
 
1682
    // Function for sending
1683
    t_function send_function(g_type_void,
1684
                             string("send_") + (*f_iter)->get_name(),
1685
                             (*f_iter)->get_arglist());
1686
 
1687
    // Open the send function
1688
    indent(f_service_) <<
1689
      function_signature(&send_function, scope) << endl;
1690
    scope_up(f_service_);
1691
 
1692
    // Function arguments and results
1693
    string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs";
1694
    string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult";
1695
 
1696
    // Serialize the request
1697
    f_service_ <<
1698
      indent() << "int32_t cseqid = 0;" << endl <<
1699
      indent() << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", ::apache::thrift::protocol::T_CALL, cseqid);" << endl <<
1700
      endl <<
1701
      indent() << argsname << " args;" << endl;
1702
 
1703
    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1704
      f_service_ <<
1705
        indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() << ";" << endl;
1706
    }
1707
 
1708
    f_service_ <<
1709
      indent() << "args.write(oprot_);" << endl <<
1710
      endl <<
1711
      indent() << "oprot_->writeMessageEnd();" << endl <<
1712
      indent() << "oprot_->getTransport()->flush();" << endl <<
1713
      indent() << "oprot_->getTransport()->writeEnd();" << endl;
1714
 
1715
    scope_down(f_service_);
1716
    f_service_ << endl;
1717
 
1718
    // Generate recv function only if not an oneway function
1719
    if (!(*f_iter)->is_oneway()) {
1720
      t_struct noargs(program_);
1721
      t_function recv_function((*f_iter)->get_returntype(),
1722
                               string("recv_") + (*f_iter)->get_name(),
1723
                               &noargs);
1724
      // Open function
1725
      indent(f_service_) <<
1726
        function_signature(&recv_function, scope) << endl;
1727
      scope_up(f_service_);
1728
 
1729
      f_service_ <<
1730
        endl <<
1731
        indent() << "int32_t rseqid = 0;" << endl <<
1732
        indent() << "std::string fname;" << endl <<
1733
        indent() << "::apache::thrift::protocol::TMessageType mtype;" << endl <<
1734
        endl <<
1735
        indent() << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl <<
1736
        indent() << "if (mtype == ::apache::thrift::protocol::T_EXCEPTION) {" << endl <<
1737
        indent() << "  ::apache::thrift::TApplicationException x;" << endl <<
1738
        indent() << "  x.read(iprot_);" << endl <<
1739
        indent() << "  iprot_->readMessageEnd();" << endl <<
1740
        indent() << "  iprot_->getTransport()->readEnd();" << endl <<
1741
        indent() << "  throw x;" << endl <<
1742
        indent() << "}" << endl <<
1743
        indent() << "if (mtype != ::apache::thrift::protocol::T_REPLY) {" << endl <<
1744
        indent() << "  iprot_->skip(::apache::thrift::protocol::T_STRUCT);" << endl <<
1745
        indent() << "  iprot_->readMessageEnd();" << endl <<
1746
        indent() << "  iprot_->getTransport()->readEnd();" << endl <<
1747
        indent() << "  throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1748
        indent() << "}" << endl <<
1749
        indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl <<
1750
        indent() << "  iprot_->skip(::apache::thrift::protocol::T_STRUCT);" << endl <<
1751
        indent() << "  iprot_->readMessageEnd();" << endl <<
1752
        indent() << "  iprot_->getTransport()->readEnd();" << endl <<
1753
        indent() << "  throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::WRONG_METHOD_NAME);" << endl <<
1754
        indent() << "}" << endl;
1755
 
1756
      if (!(*f_iter)->get_returntype()->is_void() &&
1757
          !is_complex_type((*f_iter)->get_returntype())) {
1758
        t_field returnfield((*f_iter)->get_returntype(), "_return");
1759
        f_service_ <<
1760
          indent() << declare_field(&returnfield) << endl;
1761
      }
1762
 
1763
      f_service_ <<
1764
        indent() << resultname << " result;" << endl;
1765
 
1766
      if (!(*f_iter)->get_returntype()->is_void()) {
1767
        f_service_ <<
1768
          indent() << "result.success = &_return;" << endl;
1769
      }
1770
 
1771
      f_service_ <<
1772
        indent() << "result.read(iprot_);" << endl <<
1773
        indent() << "iprot_->readMessageEnd();" << endl <<
1774
        indent() << "iprot_->getTransport()->readEnd();" << endl <<
1775
        endl;
1776
 
1777
      // Careful, only look for _result if not a void function
1778
      if (!(*f_iter)->get_returntype()->is_void()) {
1779
        if (is_complex_type((*f_iter)->get_returntype())) {
1780
          f_service_ <<
1781
            indent() << "if (result.__isset.success) {" << endl <<
1782
            indent() << "  // _return pointer has now been filled" << endl <<
1783
            indent() << "  return;" << endl <<
1784
            indent() << "}" << endl;
1785
        } else {
1786
          f_service_ <<
1787
            indent() << "if (result.__isset.success) {" << endl <<
1788
            indent() << "  return _return;" << endl <<
1789
            indent() << "}" << endl;
1790
        }
1791
      }
1792
 
1793
      t_struct* xs = (*f_iter)->get_xceptions();
1794
      const std::vector<t_field*>& xceptions = xs->get_members();
1795
      vector<t_field*>::const_iterator x_iter;
1796
      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1797
        f_service_ <<
1798
          indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
1799
          indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl <<
1800
          indent() << "}" << endl;
1801
      }
1802
 
1803
      // We only get here if we are a void function
1804
      if ((*f_iter)->get_returntype()->is_void()) {
1805
        indent(f_service_) <<
1806
          "return;" << endl;
1807
      } else {
1808
        f_service_ <<
1809
          indent() << "throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1810
      }
1811
 
1812
      // Close function
1813
      scope_down(f_service_);
1814
      f_service_ << endl;
1815
    }
1816
  }
1817
}
1818
 
1819
/**
1820
 * Generates a service server definition.
1821
 *
1822
 * @param tservice The service to generate a server for.
1823
 */
1824
void t_cpp_generator::generate_service_processor(t_service* tservice) {
1825
  // Generate the dispatch methods
1826
  vector<t_function*> functions = tservice->get_functions();
1827
  vector<t_function*>::iterator f_iter;
1828
 
1829
  string extends = "";
1830
  string extends_processor = "";
1831
  if (tservice->get_extends() != NULL) {
1832
    extends = type_name(tservice->get_extends());
1833
    extends_processor = ", public " + extends + "Processor";
1834
  }
1835
 
1836
  // Generate the header portion
1837
  f_header_ <<
1838
    "class " << service_name_ << "Processor : " <<
1839
    "virtual public ::apache::thrift::TProcessor" <<
1840
    extends_processor << " {" << endl;
1841
 
1842
  // Protected data members
1843
  f_header_ <<
1844
    " protected:" << endl;
1845
  indent_up();
1846
  f_header_ <<
1847
    indent() << "boost::shared_ptr<" << service_name_ << "If> iface_;" << endl;
1848
  f_header_ <<
1849
    indent() << "virtual bool process_fn(::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid);" << endl;
1850
  indent_down();
1851
 
1852
  // Process function declarations
1853
  f_header_ <<
1854
    " private:" << endl;
1855
  indent_up();
1856
  f_header_ <<
1857
    indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, ::apache::thrift::protocol::TProtocol*, ::apache::thrift::protocol::TProtocol*)> processMap_;" << endl;
1858
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1859
    indent(f_header_) <<
1860
      "void process_" << (*f_iter)->get_name() << "(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot);" << endl;
1861
  }
1862
  indent_down();
1863
 
1864
  indent_up();
1865
  string declare_map = "";
1866
  indent_up();
1867
 
1868
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1869
    declare_map += indent();
1870
    declare_map += "processMap_[\"";
1871
    declare_map += (*f_iter)->get_name();
1872
    declare_map += "\"] = &";
1873
    declare_map += service_name_;
1874
    declare_map += "Processor::process_";
1875
    declare_map += (*f_iter)->get_name();
1876
    declare_map += ";\n";
1877
  }
1878
  indent_down();
1879
 
1880
  f_header_ <<
1881
    " public:" << endl <<
1882
    indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface) :" << endl;
1883
  if (extends.empty()) {
1884
    f_header_ <<
1885
      indent() << "  iface_(iface) {" << endl;
1886
  } else {
1887
    f_header_ <<
1888
      indent() << "  " << extends << "Processor(iface)," << endl <<
1889
      indent() << "  iface_(iface) {" << endl;
1890
  }
1891
  f_header_ <<
1892
    declare_map <<
1893
    indent() << "}" << endl <<
1894
    endl <<
1895
    indent() << "virtual bool process(boost::shared_ptr< ::apache::thrift::protocol::TProtocol> piprot, boost::shared_ptr< ::apache::thrift::protocol::TProtocol> poprot);" << endl <<
1896
    indent() << "virtual ~" << service_name_ << "Processor() {}" << endl;
1897
  indent_down();
1898
  f_header_ <<
1899
    "};" << endl << endl;
1900
 
1901
  // Generate the server implementation
1902
  f_service_ <<
1903
    "bool " << service_name_ << "Processor::process(boost::shared_ptr< ::apache::thrift::protocol::TProtocol> piprot, boost::shared_ptr< ::apache::thrift::protocol::TProtocol> poprot) {" << endl;
1904
  indent_up();
1905
 
1906
  f_service_ <<
1907
    endl <<
1908
    indent() << "::apache::thrift::protocol::TProtocol* iprot = piprot.get();" << endl <<
1909
    indent() << "::apache::thrift::protocol::TProtocol* oprot = poprot.get();" << endl <<
1910
    indent() << "std::string fname;" << endl <<
1911
    indent() << "::apache::thrift::protocol::TMessageType mtype;" << endl <<
1912
    indent() << "int32_t seqid;" << endl <<
1913
    endl <<
1914
    indent() << "iprot->readMessageBegin(fname, mtype, seqid);" << endl <<
1915
    endl <<
1916
    indent() << "if (mtype != ::apache::thrift::protocol::T_CALL && mtype != ::apache::thrift::protocol::T_ONEWAY) {" << endl <<
1917
    indent() << "  iprot->skip(::apache::thrift::protocol::T_STRUCT);" << endl <<
1918
    indent() << "  iprot->readMessageEnd();" << endl <<
1919
    indent() << "  iprot->getTransport()->readEnd();" << endl <<
1920
    indent() << "  ::apache::thrift::TApplicationException x(::apache::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1921
    indent() << "  oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1922
    indent() << "  x.write(oprot);" << endl <<
1923
    indent() << "  oprot->writeMessageEnd();" << endl <<
1924
    indent() << "  oprot->getTransport()->flush();" << endl <<
1925
    indent() << "  oprot->getTransport()->writeEnd();" << endl <<
1926
    indent() << "  return true;" << endl <<
1927
    indent() << "}" << endl <<
1928
    endl <<
1929
    indent() << "return process_fn(iprot, oprot, fname, seqid);" <<
1930
    endl;
1931
 
1932
  indent_down();
1933
  f_service_ <<
1934
    indent() << "}" << endl <<
1935
    endl;
1936
 
1937
  f_service_ <<
1938
    "bool " << service_name_ << "Processor::process_fn(::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid) {" << endl;
1939
  indent_up();
1940
 
1941
  // HOT: member function pointer map
1942
  f_service_ <<
1943
    indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, ::apache::thrift::protocol::TProtocol*, ::apache::thrift::protocol::TProtocol*)>::iterator pfn;" << endl <<
1944
    indent() << "pfn = processMap_.find(fname);" << endl <<
1945
    indent() << "if (pfn == processMap_.end()) {" << endl;
1946
  if (extends.empty()) {
1947
    f_service_ <<
1948
      indent() << "  iprot->skip(::apache::thrift::protocol::T_STRUCT);" << endl <<
1949
      indent() << "  iprot->readMessageEnd();" << endl <<
1950
      indent() << "  iprot->getTransport()->readEnd();" << endl <<
1951
      indent() << "  ::apache::thrift::TApplicationException x(::apache::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: '\"+fname+\"'\");" << endl <<
1952
      indent() << "  oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1953
      indent() << "  x.write(oprot);" << endl <<
1954
      indent() << "  oprot->writeMessageEnd();" << endl <<
1955
      indent() << "  oprot->getTransport()->flush();" << endl <<
1956
      indent() << "  oprot->getTransport()->writeEnd();" << endl <<
1957
      indent() << "  return true;" << endl;
1958
  } else {
1959
    f_service_ <<
1960
      indent() << "  return " << extends << "Processor::process_fn(iprot, oprot, fname, seqid);" << endl;
1961
  }
1962
  f_service_ <<
1963
    indent() << "}" << endl <<
1964
    indent() << "(this->*(pfn->second))(seqid, iprot, oprot);" << endl <<
1965
    indent() << "return true;" << endl;
1966
 
1967
  indent_down();
1968
  f_service_ <<
1969
    "}" << endl <<
1970
    endl;
1971
 
1972
  // Generate the process subfunctions
1973
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1974
    generate_process_function(tservice, *f_iter);
1975
  }
1976
}
1977
 
1978
/**
1979
 * Generates a struct and helpers for a function.
1980
 *
1981
 * @param tfunction The function
1982
 */
1983
void t_cpp_generator::generate_function_helpers(t_service* tservice,
1984
                                                t_function* tfunction) {
1985
  if (tfunction->is_oneway()) {
1986
    return;
1987
  }
1988
 
1989
  t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result");
1990
  t_field success(tfunction->get_returntype(), "success", 0);
1991
  if (!tfunction->get_returntype()->is_void()) {
1992
    result.append(&success);
1993
  }
1994
 
1995
  t_struct* xs = tfunction->get_xceptions();
1996
  const vector<t_field*>& fields = xs->get_members();
1997
  vector<t_field*>::const_iterator f_iter;
1998
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1999
    result.append(*f_iter);
2000
  }
2001
 
2002
  generate_struct_definition(f_header_, &result, false);
2003
  generate_struct_reader(f_service_, &result);
2004
  generate_struct_result_writer(f_service_, &result);
2005
 
2006
  result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
2007
  generate_struct_definition(f_header_, &result, false, true, true, false);
2008
  generate_struct_reader(f_service_, &result, true);
2009
 
2010
}
2011
 
2012
/**
2013
 * Generates a process function definition.
2014
 *
2015
 * @param tfunction The function to write a dispatcher for
2016
 */
2017
void t_cpp_generator::generate_process_function(t_service* tservice,
2018
                                                t_function* tfunction) {
2019
  // Open function
2020
  f_service_ <<
2021
    "void " << tservice->get_name() << "Processor::" <<
2022
    "process_" << tfunction->get_name() <<
2023
    "(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot)" << endl;
2024
  scope_up(f_service_);
2025
 
2026
  string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args";
2027
  string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result";
2028
 
2029
  f_service_ <<
2030
    indent() << argsname << " args;" << endl <<
2031
    indent() << "args.read(iprot);" << endl <<
2032
    indent() << "iprot->readMessageEnd();" << endl <<
2033
    indent() << "iprot->getTransport()->readEnd();" << endl <<
2034
    endl;
2035
 
2036
  t_struct* xs = tfunction->get_xceptions();
2037
  const std::vector<t_field*>& xceptions = xs->get_members();
2038
  vector<t_field*>::const_iterator x_iter;
2039
 
2040
  // Declare result
2041
  if (!tfunction->is_oneway()) {
2042
    f_service_ <<
2043
      indent() << resultname << " result;" << endl;
2044
  }
2045
 
2046
  // Try block for functions with exceptions
2047
  f_service_ <<
2048
    indent() << "try {" << endl;
2049
  indent_up();
2050
 
2051
  // Generate the function call
2052
  t_struct* arg_struct = tfunction->get_arglist();
2053
  const std::vector<t_field*>& fields = arg_struct->get_members();
2054
  vector<t_field*>::const_iterator f_iter;
2055
 
2056
  bool first = true;
2057
  f_service_ << indent();
2058
  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
2059
    if (is_complex_type(tfunction->get_returntype())) {
2060
      first = false;
2061
      f_service_ << "iface_->" << tfunction->get_name() << "(result.success";
2062
    } else {
2063
      f_service_ << "result.success = iface_->" << tfunction->get_name() << "(";
2064
    }
2065
  } else {
2066
    f_service_ <<
2067
      "iface_->" << tfunction->get_name() << "(";
2068
  }
2069
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2070
    if (first) {
2071
      first = false;
2072
    } else {
2073
      f_service_ << ", ";
2074
    }
2075
    f_service_ << "args." << (*f_iter)->get_name();
2076
  }
2077
  f_service_ << ");" << endl;
2078
 
2079
  // Set isset on success field
2080
  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
2081
    f_service_ <<
2082
      indent() << "result.__isset.success = true;" << endl;
2083
  }
2084
 
2085
  indent_down();
2086
  f_service_ << indent() << "}";
2087
 
2088
  if (!tfunction->is_oneway()) {
2089
    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
2090
      f_service_ << " catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name() << ") {" << endl;
2091
      if (!tfunction->is_oneway()) {
2092
        indent_up();
2093
        f_service_ <<
2094
          indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
2095
          indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
2096
        indent_down();
2097
        f_service_ << indent() << "}";
2098
      } else {
2099
        f_service_ << "}";
2100
      }
2101
    }
2102
  }
2103
 
2104
  f_service_ << " catch (const std::exception& e) {" << endl;
2105
 
2106
  if (!tfunction->is_oneway()) {
2107
    indent_up();
2108
    f_service_ <<
2109
      indent() << "::apache::thrift::TApplicationException x(e.what());" << endl <<
2110
      indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
2111
      indent() << "x.write(oprot);" << endl <<
2112
      indent() << "oprot->writeMessageEnd();" << endl <<
2113
      indent() << "oprot->getTransport()->flush();" << endl <<
2114
      indent() << "oprot->getTransport()->writeEnd();" << endl <<
2115
      indent() << "return;" << endl;
2116
    indent_down();
2117
  }
2118
  f_service_ << indent() << "}" << endl;
2119
 
2120
  // Shortcut out here for oneway functions
2121
  if (tfunction->is_oneway()) {
2122
    f_service_ <<
2123
      indent() << "return;" << endl;
2124
    indent_down();
2125
    f_service_ << "}" << endl <<
2126
      endl;
2127
    return;
2128
  }
2129
 
2130
  // Serialize the result into a struct
2131
  f_service_ <<
2132
    endl <<
2133
    indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl <<
2134
    indent() << "result.write(oprot);" << endl <<
2135
    indent() << "oprot->writeMessageEnd();" << endl <<
2136
    indent() << "oprot->getTransport()->flush();" << endl <<
2137
    indent() << "oprot->getTransport()->writeEnd();" << endl;
2138
 
2139
  // Close function
2140
  scope_down(f_service_);
2141
  f_service_ << endl;
2142
}
2143
 
2144
/**
2145
 * Generates a skeleton file of a server
2146
 *
2147
 * @param tservice The service to generate a server for.
2148
 */
2149
void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
2150
  string svcname = tservice->get_name();
2151
 
2152
  // Service implementation file includes
2153
  string f_skeleton_name = get_out_dir()+svcname+"_server.skeleton.cpp";
2154
 
2155
  string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp"));
2156
 
2157
  ofstream f_skeleton;
2158
  f_skeleton.open(f_skeleton_name.c_str());
2159
  f_skeleton <<
2160
    "// This autogenerated skeleton file illustrates how to build a server." << endl <<
2161
    "// You should copy it to another filename to avoid overwriting it." << endl <<
2162
    endl <<
2163
    "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl <<
2164
    "#include <protocol/TBinaryProtocol.h>" << endl <<
2165
    "#include <server/TSimpleServer.h>" << endl <<
2166
    "#include <transport/TServerSocket.h>" << endl <<
2167
    "#include <transport/TBufferTransports.h>" << endl <<
2168
    endl <<
2169
    "using namespace ::apache::thrift;" << endl <<
2170
    "using namespace ::apache::thrift::protocol;" << endl <<
2171
    "using namespace ::apache::thrift::transport;" << endl <<
2172
    "using namespace ::apache::thrift::server;" << endl <<
2173
    endl <<
2174
    "using boost::shared_ptr;" << endl <<
2175
    endl;
2176
 
2177
  if (!ns.empty()) {
2178
    f_skeleton <<
2179
      "using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
2180
      endl;
2181
  }
2182
 
2183
  f_skeleton <<
2184
    "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl <<
2185
    " public:" << endl;
2186
  indent_up();
2187
  f_skeleton <<
2188
    indent() << svcname << "Handler() {" << endl <<
2189
    indent() << "  // Your initialization goes here" << endl <<
2190
    indent() << "}" << endl <<
2191
    endl;
2192
 
2193
  vector<t_function*> functions = tservice->get_functions();
2194
  vector<t_function*>::iterator f_iter;
2195
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2196
    f_skeleton <<
2197
      indent() << function_signature(*f_iter) << " {" << endl <<
2198
      indent() << "  // Your implementation goes here" << endl <<
2199
      indent() << "  printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl <<
2200
      indent() << "}" << endl <<
2201
      endl;
2202
  }
2203
 
2204
  indent_down();
2205
  f_skeleton <<
2206
    "};" << endl <<
2207
    endl;
2208
 
2209
  f_skeleton <<
2210
    indent() << "int main(int argc, char **argv) {" << endl;
2211
  indent_up();
2212
  f_skeleton <<
2213
    indent() << "int port = 9090;" << endl <<
2214
    indent() << "shared_ptr<" << svcname << "Handler> handler(new " << svcname << "Handler());" << endl <<
2215
    indent() << "shared_ptr<TProcessor> processor(new " << svcname << "Processor(handler));" << endl <<
2216
    indent() << "shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));" << endl <<
2217
    indent() << "shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());" << endl <<
2218
    indent() << "shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());" << endl <<
2219
    endl <<
2220
    indent() << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" << endl <<
2221
    indent() << "server.serve();" << endl <<
2222
    indent() << "return 0;" << endl;
2223
  indent_down();
2224
  f_skeleton <<
2225
    "}" << endl <<
2226
    endl;
2227
 
2228
  // Close the files
2229
  f_skeleton.close();
2230
}
2231
 
2232
/**
2233
 * Deserializes a field of any type.
2234
 */
2235
void t_cpp_generator::generate_deserialize_field(ofstream& out,
2236
                                                 t_field* tfield,
2237
                                                 string prefix,
2238
                                                 string suffix) {
2239
  t_type* type = get_true_type(tfield->get_type());
2240
 
2241
  if (type->is_void()) {
2242
    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
2243
      prefix + tfield->get_name();
2244
  }
2245
 
2246
  string name = prefix + tfield->get_name() + suffix;
2247
 
2248
  if (type->is_struct() || type->is_xception()) {
2249
    generate_deserialize_struct(out, (t_struct*)type, name);
2250
  } else if (type->is_container()) {
2251
    generate_deserialize_container(out, type, name);
2252
  } else if (type->is_base_type()) {
2253
    indent(out) <<
2254
      "xfer += iprot->";
2255
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2256
    switch (tbase) {
2257
    case t_base_type::TYPE_VOID:
2258
      throw "compiler error: cannot serialize void field in a struct: " + name;
2259
      break;
2260
    case t_base_type::TYPE_STRING:
2261
      if (((t_base_type*)type)->is_binary()) {
2262
        out << "readBinary(" << name << ");";
2263
      }
2264
      else {
2265
        out << "readString(" << name << ");";
2266
      }
2267
      break;
2268
    case t_base_type::TYPE_BOOL:
2269
      out << "readBool(" << name << ");";
2270
      break;
2271
    case t_base_type::TYPE_BYTE:
2272
      out << "readByte(" << name << ");";
2273
      break;
2274
    case t_base_type::TYPE_I16:
2275
      out << "readI16(" << name << ");";
2276
      break;
2277
    case t_base_type::TYPE_I32:
2278
      out << "readI32(" << name << ");";
2279
      break;
2280
    case t_base_type::TYPE_I64:
2281
      out << "readI64(" << name << ");";
2282
      break;
2283
    case t_base_type::TYPE_DOUBLE:
2284
      out << "readDouble(" << name << ");";
2285
      break;
2286
    default:
2287
      throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
2288
    }
2289
    out <<
2290
      endl;
2291
  } else if (type->is_enum()) {
2292
    string t = tmp("ecast");
2293
    out <<
2294
      indent() << "int32_t " << t << ";" << endl <<
2295
      indent() << "xfer += iprot->readI32(" << t << ");" << endl <<
2296
      indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl;
2297
  } else {
2298
    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
2299
           tfield->get_name().c_str(), type_name(type).c_str());
2300
  }
2301
}
2302
 
2303
/**
2304
 * Generates an unserializer for a variable. This makes two key assumptions,
2305
 * first that there is a const char* variable named data that points to the
2306
 * buffer for deserialization, and that there is a variable protocol which
2307
 * is a reference to a TProtocol serialization object.
2308
 */
2309
void t_cpp_generator::generate_deserialize_struct(ofstream& out,
2310
                                                  t_struct* tstruct,
2311
                                                  string prefix) {
2312
  indent(out) <<
2313
    "xfer += " << prefix << ".read(iprot);" << endl;
2314
}
2315
 
2316
void t_cpp_generator::generate_deserialize_container(ofstream& out,
2317
                                                     t_type* ttype,
2318
                                                     string prefix) {
2319
  scope_up(out);
2320
 
2321
  string size = tmp("_size");
2322
  string ktype = tmp("_ktype");
2323
  string vtype = tmp("_vtype");
2324
  string etype = tmp("_etype");
2325
 
2326
  t_container* tcontainer = (t_container*)ttype;
2327
  bool use_push = tcontainer->has_cpp_name();
2328
 
2329
  indent(out) <<
2330
    prefix << ".clear();" << endl <<
2331
    indent() << "uint32_t " << size << ";" << endl;
2332
 
2333
  // Declare variables, read header
2334
  if (ttype->is_map()) {
2335
    out <<
2336
      indent() << "::apache::thrift::protocol::TType " << ktype << ";" << endl <<
2337
      indent() << "::apache::thrift::protocol::TType " << vtype << ";" << endl <<
2338
      indent() << "iprot->readMapBegin(" <<
2339
                   ktype << ", " << vtype << ", " << size << ");" << endl;
2340
  } else if (ttype->is_set()) {
2341
    out <<
2342
      indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl <<
2343
      indent() << "iprot->readSetBegin(" <<
2344
                   etype << ", " << size << ");" << endl;
2345
  } else if (ttype->is_list()) {
2346
    out <<
2347
      indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl <<
2348
      indent() << "iprot->readListBegin(" <<
2349
      etype << ", " << size << ");" << endl;
2350
    if (!use_push) {
2351
      indent(out) << prefix << ".resize(" << size << ");" << endl;
2352
    }
2353
  }
2354
 
2355
 
2356
  // For loop iterates over elements
2357
  string i = tmp("_i");
2358
  out <<
2359
    indent() << "uint32_t " << i << ";" << endl <<
2360
    indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
2361
 
2362
    scope_up(out);
2363
 
2364
    if (ttype->is_map()) {
2365
      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
2366
    } else if (ttype->is_set()) {
2367
      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
2368
    } else if (ttype->is_list()) {
2369
      generate_deserialize_list_element(out, (t_list*)ttype, prefix, use_push, i);
2370
    }
2371
 
2372
    scope_down(out);
2373
 
2374
  // Read container end
2375
  if (ttype->is_map()) {
2376
    indent(out) << "iprot->readMapEnd();" << endl;
2377
  } else if (ttype->is_set()) {
2378
    indent(out) << "iprot->readSetEnd();" << endl;
2379
  } else if (ttype->is_list()) {
2380
    indent(out) << "iprot->readListEnd();" << endl;
2381
  }
2382
 
2383
  scope_down(out);
2384
}
2385
 
2386
 
2387
/**
2388
 * Generates code to deserialize a map
2389
 */
2390
void t_cpp_generator::generate_deserialize_map_element(ofstream& out,
2391
                                                       t_map* tmap,
2392
                                                       string prefix) {
2393
  string key = tmp("_key");
2394
  string val = tmp("_val");
2395
  t_field fkey(tmap->get_key_type(), key);
2396
  t_field fval(tmap->get_val_type(), val);
2397
 
2398
  out <<
2399
    indent() << declare_field(&fkey) << endl;
2400
 
2401
  generate_deserialize_field(out, &fkey);
2402
  indent(out) <<
2403
    declare_field(&fval, false, false, false, true) << " = " <<
2404
    prefix << "[" << key << "];" << endl;
2405
 
2406
  generate_deserialize_field(out, &fval);
2407
}
2408
 
2409
void t_cpp_generator::generate_deserialize_set_element(ofstream& out,
2410
                                                       t_set* tset,
2411
                                                       string prefix) {
2412
  string elem = tmp("_elem");
2413
  t_field felem(tset->get_elem_type(), elem);
2414
 
2415
  indent(out) <<
2416
    declare_field(&felem) << endl;
2417
 
2418
  generate_deserialize_field(out, &felem);
2419
 
2420
  indent(out) <<
2421
    prefix << ".insert(" << elem << ");" << endl;
2422
}
2423
 
2424
void t_cpp_generator::generate_deserialize_list_element(ofstream& out,
2425
                                                        t_list* tlist,
2426
                                                        string prefix,
2427
                                                        bool use_push,
2428
                                                        string index) {
2429
  if (use_push) {
2430
    string elem = tmp("_elem");
2431
    t_field felem(tlist->get_elem_type(), elem);
2432
    indent(out) << declare_field(&felem) << endl;
2433
    generate_deserialize_field(out, &felem);
2434
    indent(out) << prefix << ".push_back(" << elem << ");" << endl;
2435
  } else {
2436
    t_field felem(tlist->get_elem_type(), prefix + "[" + index + "]");
2437
    generate_deserialize_field(out, &felem);
2438
  }
2439
}
2440
 
2441
 
2442
/**
2443
 * Serializes a field of any type.
2444
 *
2445
 * @param tfield The field to serialize
2446
 * @param prefix Name to prepend to field name
2447
 */
2448
void t_cpp_generator::generate_serialize_field(ofstream& out,
2449
                                               t_field* tfield,
2450
                                               string prefix,
2451
                                               string suffix) {
2452
  t_type* type = get_true_type(tfield->get_type());
2453
 
2454
  string name = prefix + tfield->get_name() + suffix;
2455
 
2456
  // Do nothing for void types
2457
  if (type->is_void()) {
2458
    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
2459
  }
2460
 
2461
 
2462
 
2463
  if (type->is_struct() || type->is_xception()) {
2464
    generate_serialize_struct(out,
2465
                              (t_struct*)type,
2466
                              name);
2467
  } else if (type->is_container()) {
2468
    generate_serialize_container(out, type, name);
2469
  } else if (type->is_base_type() || type->is_enum()) {
2470
 
2471
    indent(out) <<
2472
      "xfer += oprot->";
2473
 
2474
    if (type->is_base_type()) {
2475
      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2476
      switch (tbase) {
2477
      case t_base_type::TYPE_VOID:
2478
        throw
2479
          "compiler error: cannot serialize void field in a struct: " + name;
2480
        break;
2481
      case t_base_type::TYPE_STRING:
2482
        if (((t_base_type*)type)->is_binary()) {
2483
          out << "writeBinary(" << name << ");";
2484
        }
2485
        else {
2486
          out << "writeString(" << name << ");";
2487
        }
2488
        break;
2489
      case t_base_type::TYPE_BOOL:
2490
        out << "writeBool(" << name << ");";
2491
        break;
2492
      case t_base_type::TYPE_BYTE:
2493
        out << "writeByte(" << name << ");";
2494
        break;
2495
      case t_base_type::TYPE_I16:
2496
        out << "writeI16(" << name << ");";
2497
        break;
2498
      case t_base_type::TYPE_I32:
2499
        out << "writeI32(" << name << ");";
2500
        break;
2501
      case t_base_type::TYPE_I64:
2502
        out << "writeI64(" << name << ");";
2503
        break;
2504
      case t_base_type::TYPE_DOUBLE:
2505
        out << "writeDouble(" << name << ");";
2506
        break;
2507
      default:
2508
        throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase) + name;
2509
      }
2510
    } else if (type->is_enum()) {
2511
      out << "writeI32((int32_t)" << name << ");";
2512
    }
2513
    out << endl;
2514
  } else {
2515
    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
2516
           name.c_str(),
2517
           type_name(type).c_str());
2518
  }
2519
}
2520
 
2521
/**
2522
 * Serializes all the members of a struct.
2523
 *
2524
 * @param tstruct The struct to serialize
2525
 * @param prefix  String prefix to attach to all fields
2526
 */
2527
void t_cpp_generator::generate_serialize_struct(ofstream& out,
2528
                                                t_struct* tstruct,
2529
                                                string prefix) {
2530
  indent(out) <<
2531
    "xfer += " << prefix << ".write(oprot);" << endl;
2532
}
2533
 
2534
void t_cpp_generator::generate_serialize_container(ofstream& out,
2535
                                                   t_type* ttype,
2536
                                                   string prefix) {
2537
  scope_up(out);
2538
 
2539
  if (ttype->is_map()) {
2540
    indent(out) <<
2541
      "xfer += oprot->writeMapBegin(" <<
2542
      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
2543
      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
2544
      prefix << ".size());" << endl;
2545
  } else if (ttype->is_set()) {
2546
    indent(out) <<
2547
      "xfer += oprot->writeSetBegin(" <<
2548
      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
2549
      prefix << ".size());" << endl;
2550
  } else if (ttype->is_list()) {
2551
    indent(out) <<
2552
      "xfer += oprot->writeListBegin(" <<
2553
      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
2554
      prefix << ".size());" << endl;
2555
  }
2556
 
2557
  string iter = tmp("_iter");
2558
  out <<
2559
    indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl <<
2560
    indent() << "for (" << iter << " = " << prefix  << ".begin(); " << iter << " != " << prefix << ".end(); ++" << iter << ")" << endl;
2561
  scope_up(out);
2562
    if (ttype->is_map()) {
2563
      generate_serialize_map_element(out, (t_map*)ttype, iter);
2564
    } else if (ttype->is_set()) {
2565
      generate_serialize_set_element(out, (t_set*)ttype, iter);
2566
    } else if (ttype->is_list()) {
2567
      generate_serialize_list_element(out, (t_list*)ttype, iter);
2568
    }
2569
  scope_down(out);
2570
 
2571
  if (ttype->is_map()) {
2572
    indent(out) <<
2573
      "xfer += oprot->writeMapEnd();" << endl;
2574
  } else if (ttype->is_set()) {
2575
    indent(out) <<
2576
      "xfer += oprot->writeSetEnd();" << endl;
2577
  } else if (ttype->is_list()) {
2578
    indent(out) <<
2579
      "xfer += oprot->writeListEnd();" << endl;
2580
  }
2581
 
2582
  scope_down(out);
2583
}
2584
 
2585
/**
2586
 * Serializes the members of a map.
2587
 *
2588
 */
2589
void t_cpp_generator::generate_serialize_map_element(ofstream& out,
2590
                                                     t_map* tmap,
2591
                                                     string iter) {
2592
  t_field kfield(tmap->get_key_type(), iter + "->first");
2593
  generate_serialize_field(out, &kfield, "");
2594
 
2595
  t_field vfield(tmap->get_val_type(), iter + "->second");
2596
  generate_serialize_field(out, &vfield, "");
2597
}
2598
 
2599
/**
2600
 * Serializes the members of a set.
2601
 */
2602
void t_cpp_generator::generate_serialize_set_element(ofstream& out,
2603
                                                     t_set* tset,
2604
                                                     string iter) {
2605
  t_field efield(tset->get_elem_type(), "(*" + iter + ")");
2606
  generate_serialize_field(out, &efield, "");
2607
}
2608
 
2609
/**
2610
 * Serializes the members of a list.
2611
 */
2612
void t_cpp_generator::generate_serialize_list_element(ofstream& out,
2613
                                                      t_list* tlist,
2614
                                                      string iter) {
2615
  t_field efield(tlist->get_elem_type(), "(*" + iter + ")");
2616
  generate_serialize_field(out, &efield, "");
2617
}
2618
 
2619
/**
2620
 * Makes a :: prefix for a namespace
2621
 *
2622
 * @param ns The namepsace, w/ periods in it
2623
 * @return Namespaces
2624
 */
2625
string t_cpp_generator::namespace_prefix(string ns) {
2626
  if (ns.size() == 0) {
2627
    return "";
2628
  }
2629
  string result = "";
2630
  string::size_type loc;
2631
  while ((loc = ns.find(".")) != string::npos) {
2632
    result += ns.substr(0, loc);
2633
    result += "::";
2634
    ns = ns.substr(loc+1);
2635
  }
2636
  if (ns.size() > 0) {
2637
    result += ns + "::";
2638
  }
2639
  return result;
2640
}
2641
 
2642
/**
2643
 * Opens namespace.
2644
 *
2645
 * @param ns The namepsace, w/ periods in it
2646
 * @return Namespaces
2647
 */
2648
string t_cpp_generator::namespace_open(string ns) {
2649
  if (ns.size() == 0) {
2650
    return "";
2651
  }
2652
  string result = "";
2653
  string separator = "";
2654
  string::size_type loc;
2655
  while ((loc = ns.find(".")) != string::npos) {
2656
    result += separator;
2657
    result += "namespace ";
2658
    result += ns.substr(0, loc);
2659
    result += " {";
2660
    separator = " ";
2661
    ns = ns.substr(loc+1);
2662
  }
2663
  if (ns.size() > 0) {
2664
    result += separator + "namespace " + ns + " {";
2665
  }
2666
  return result;
2667
}
2668
 
2669
/**
2670
 * Closes namespace.
2671
 *
2672
 * @param ns The namepsace, w/ periods in it
2673
 * @return Namespaces
2674
 */
2675
string t_cpp_generator::namespace_close(string ns) {
2676
  if (ns.size() == 0) {
2677
    return "";
2678
  }
2679
  string result = "}";
2680
  string::size_type loc;
2681
  while ((loc = ns.find(".")) != string::npos) {
2682
    result += "}";
2683
    ns = ns.substr(loc+1);
2684
  }
2685
  result += " // namespace";
2686
  return result;
2687
}
2688
 
2689
/**
2690
 * Returns a C++ type name
2691
 *
2692
 * @param ttype The type
2693
 * @return String of the type name, i.e. std::set<type>
2694
 */
2695
string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
2696
  if (ttype->is_base_type()) {
2697
    string bname = base_type_name(((t_base_type*)ttype)->get_base());
2698
    if (!arg) {
2699
      return bname;
2700
    }
2701
 
2702
    if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) {
2703
      return "const " + bname + "&";
2704
    } else {
2705
      return "const " + bname;
2706
    }
2707
  }
2708
 
2709
  // Check for a custom overloaded C++ name
2710
  if (ttype->is_container()) {
2711
    string cname;
2712
 
2713
    t_container* tcontainer = (t_container*) ttype;
2714
    if (tcontainer->has_cpp_name()) {
2715
      cname = tcontainer->get_cpp_name();
2716
    } else if (ttype->is_map()) {
2717
      t_map* tmap = (t_map*) ttype;
2718
      cname = "std::map<" +
2719
        type_name(tmap->get_key_type(), in_typedef) + ", " +
2720
        type_name(tmap->get_val_type(), in_typedef) + "> ";
2721
    } else if (ttype->is_set()) {
2722
      t_set* tset = (t_set*) ttype;
2723
      cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> ";
2724
    } else if (ttype->is_list()) {
2725
      t_list* tlist = (t_list*) ttype;
2726
      cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> ";
2727
    }
2728
 
2729
    if (arg) {
2730
      return "const " + cname + "&";
2731
    } else {
2732
      return cname;
2733
    }
2734
  }
2735
 
2736
  string class_prefix;
2737
  if (in_typedef && (ttype->is_struct() || ttype->is_xception())) {
2738
    class_prefix = "class ";
2739
  }
2740
 
2741
  // Check if it needs to be namespaced
2742
  string pname;
2743
  t_program* program = ttype->get_program();
2744
  if (program != NULL && program != program_) {
2745
    pname =
2746
      class_prefix +
2747
      namespace_prefix(program->get_namespace("cpp")) +
2748
      ttype->get_name();
2749
  } else {
2750
    pname = class_prefix + ttype->get_name();
2751
  }
2752
 
2753
  if (arg) {
2754
    if (is_complex_type(ttype)) {
2755
      return "const " + pname + "&";
2756
    } else {
2757
      return "const " + pname;
2758
    }
2759
  } else {
2760
    return pname;
2761
  }
2762
}
2763
 
2764
/**
2765
 * Returns the C++ type that corresponds to the thrift type.
2766
 *
2767
 * @param tbase The base type
2768
 * @return Explicit C++ type, i.e. "int32_t"
2769
 */
2770
string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
2771
  switch (tbase) {
2772
  case t_base_type::TYPE_VOID:
2773
    return "void";
2774
  case t_base_type::TYPE_STRING:
2775
    return "std::string";
2776
  case t_base_type::TYPE_BOOL:
2777
    return "bool";
2778
  case t_base_type::TYPE_BYTE:
2779
    return "int8_t";
2780
  case t_base_type::TYPE_I16:
2781
    return "int16_t";
2782
  case t_base_type::TYPE_I32:
2783
    return "int32_t";
2784
  case t_base_type::TYPE_I64:
2785
    return "int64_t";
2786
  case t_base_type::TYPE_DOUBLE:
2787
    return "double";
2788
  default:
2789
    throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
2790
  }
2791
}
2792
 
2793
/**
2794
 * Declares a field, which may include initialization as necessary.
2795
 *
2796
 * @param ttype The type
2797
 * @return Field declaration, i.e. int x = 0;
2798
 */
2799
string t_cpp_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant, bool reference) {
2800
  // TODO(mcslee): do we ever need to initialize the field?
2801
  string result = "";
2802
  if (constant) {
2803
    result += "const ";
2804
  }
2805
  result += type_name(tfield->get_type());
2806
  if (pointer) {
2807
    result += "*";
2808
  }
2809
  if (reference) {
2810
    result += "&";
2811
  }
2812
  result += " " + tfield->get_name();
2813
  if (init) {
2814
    t_type* type = get_true_type(tfield->get_type());
2815
 
2816
    if (type->is_base_type()) {
2817
      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2818
      switch (tbase) {
2819
      case t_base_type::TYPE_VOID:
2820
        break;
2821
      case t_base_type::TYPE_STRING:
2822
        result += " = \"\"";
2823
        break;
2824
      case t_base_type::TYPE_BOOL:
2825
        result += " = false";
2826
        break;
2827
      case t_base_type::TYPE_BYTE:
2828
      case t_base_type::TYPE_I16:
2829
      case t_base_type::TYPE_I32:
2830
      case t_base_type::TYPE_I64:
2831
        result += " = 0";
2832
        break;
2833
      case t_base_type::TYPE_DOUBLE:
2834
        result += " = (double)0";
2835
        break;
2836
      default:
2837
        throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase);
2838
      }
2839
    } else if (type->is_enum()) {
2840
      result += " = (" + type_name(type) + ")0";
2841
    }
2842
  }
2843
  if (!reference) {
2844
    result += ";";
2845
  }
2846
  return result;
2847
}
2848
 
2849
/**
2850
 * Renders a function signature of the form 'type name(args)'
2851
 *
2852
 * @param tfunction Function definition
2853
 * @return String of rendered function definition
2854
 */
2855
string t_cpp_generator::function_signature(t_function* tfunction,
2856
                                           string prefix,
2857
                                           bool name_params) {
2858
  t_type* ttype = tfunction->get_returntype();
2859
  t_struct* arglist = tfunction->get_arglist();
2860
 
2861
  if (is_complex_type(ttype)) {
2862
    bool empty = arglist->get_members().size() == 0;
2863
    return
2864
      "void " + prefix + tfunction->get_name() +
2865
      "(" + type_name(ttype) + (name_params ? "& _return" : "& /* _return */") +
2866
      (empty ? "" : (", " + argument_list(arglist, name_params))) + ")";
2867
  } else {
2868
    return
2869
      type_name(ttype) + " " + prefix + tfunction->get_name() +
2870
      "(" + argument_list(arglist, name_params) + ")";
2871
  }
2872
}
2873
 
2874
/**
2875
 * Renders a field list
2876
 *
2877
 * @param tstruct The struct definition
2878
 * @return Comma sepearated list of all field names in that struct
2879
 */
2880
string t_cpp_generator::argument_list(t_struct* tstruct, bool name_params) {
2881
  string result = "";
2882
 
2883
  const vector<t_field*>& fields = tstruct->get_members();
2884
  vector<t_field*>::const_iterator f_iter;
2885
  bool first = true;
2886
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2887
    if (first) {
2888
      first = false;
2889
    } else {
2890
      result += ", ";
2891
    }
2892
    result += type_name((*f_iter)->get_type(), false, true) + " " +
2893
      (name_params ? (*f_iter)->get_name() : "/* " + (*f_iter)->get_name() + " */");
2894
  }
2895
  return result;
2896
}
2897
 
2898
/**
2899
 * Converts the parse type to a C++ enum string for the given type.
2900
 *
2901
 * @param type Thrift Type
2902
 * @return String of C++ code to definition of that type constant
2903
 */
2904
string t_cpp_generator::type_to_enum(t_type* type) {
2905
  type = get_true_type(type);
2906
 
2907
  if (type->is_base_type()) {
2908
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2909
    switch (tbase) {
2910
    case t_base_type::TYPE_VOID:
2911
      throw "NO T_VOID CONSTRUCT";
2912
    case t_base_type::TYPE_STRING:
2913
      return "::apache::thrift::protocol::T_STRING";
2914
    case t_base_type::TYPE_BOOL:
2915
      return "::apache::thrift::protocol::T_BOOL";
2916
    case t_base_type::TYPE_BYTE:
2917
      return "::apache::thrift::protocol::T_BYTE";
2918
    case t_base_type::TYPE_I16:
2919
      return "::apache::thrift::protocol::T_I16";
2920
    case t_base_type::TYPE_I32:
2921
      return "::apache::thrift::protocol::T_I32";
2922
    case t_base_type::TYPE_I64:
2923
      return "::apache::thrift::protocol::T_I64";
2924
    case t_base_type::TYPE_DOUBLE:
2925
      return "::apache::thrift::protocol::T_DOUBLE";
2926
    }
2927
  } else if (type->is_enum()) {
2928
    return "::apache::thrift::protocol::T_I32";
2929
  } else if (type->is_struct()) {
2930
    return "::apache::thrift::protocol::T_STRUCT";
2931
  } else if (type->is_xception()) {
2932
    return "::apache::thrift::protocol::T_STRUCT";
2933
  } else if (type->is_map()) {
2934
    return "::apache::thrift::protocol::T_MAP";
2935
  } else if (type->is_set()) {
2936
    return "::apache::thrift::protocol::T_SET";
2937
  } else if (type->is_list()) {
2938
    return "::apache::thrift::protocol::T_LIST";
2939
  }
2940
 
2941
  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2942
}
2943
 
2944
/**
2945
 * Returns the symbol name of the local reflection of a type.
2946
 */
2947
string t_cpp_generator::local_reflection_name(const char* prefix, t_type* ttype, bool external) {
2948
  ttype = get_true_type(ttype);
2949
 
2950
  // We have to use the program name as part of the identifier because
2951
  // if two thrift "programs" are compiled into one actual program
2952
  // you would get a symbol collison if they both defined list<i32>.
2953
  // trlo = Thrift Reflection LOcal.
2954
  string prog;
2955
  string name;
2956
  string nspace;
2957
 
2958
  // TODO(dreiss): Would it be better to pregenerate the base types
2959
  //               and put them in Thrift.{h,cpp} ?
2960
 
2961
  if (ttype->is_base_type()) {
2962
    prog = program_->get_name();
2963
    name = ttype->get_ascii_fingerprint();
2964
  } else if (ttype->is_enum()) {
2965
    assert(ttype->get_program() != NULL);
2966
    prog = ttype->get_program()->get_name();
2967
    name = ttype->get_ascii_fingerprint();
2968
  } else if (ttype->is_container()) {
2969
    prog = program_->get_name();
2970
    name = ttype->get_ascii_fingerprint();
2971
  } else {
2972
    assert(ttype->is_struct() || ttype->is_xception());
2973
    assert(ttype->get_program() != NULL);
2974
    prog = ttype->get_program()->get_name();
2975
    name = ttype->get_ascii_fingerprint();
2976
  }
2977
 
2978
  if (external &&
2979
      ttype->get_program() != NULL &&
2980
      ttype->get_program() != program_) {
2981
    nspace = namespace_prefix(ttype->get_program()->get_namespace("cpp"));
2982
  }
2983
 
2984
  return nspace + "trlo_" + prefix + "_" + prog + "_" + name;
2985
}
2986
 
2987
string t_cpp_generator::get_include_prefix(const t_program& program) const {
2988
  string include_prefix = program.get_include_prefix();
2989
  if (!use_include_prefix_ ||
2990
      (include_prefix.size() > 0 && include_prefix[0] == '/')) {
2991
    // if flag is turned off or this is absolute path, return empty prefix
2992
    return "";
2993
  }
2994
 
2995
  string::size_type last_slash = string::npos;
2996
  if ((last_slash = include_prefix.rfind("/")) != string::npos) {
2997
    return include_prefix.substr(0, last_slash) + "/" + out_dir_base_ + "/";
2998
  }
2999
 
3000
  return "";
3001
}
3002
 
3003
 
3004
THRIFT_REGISTER_GENERATOR(cpp, "C++",
3005
"    dense:           Generate type specifications for the dense protocol.\n"
3006
"    include_prefix:  Use full include paths in generated files.\n"
3007
);