PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/src/farsounder/protobuf/compiler/matlab/matlab_generator.cc

https://code.google.com/
C++ | 712 lines | 567 code | 67 blank | 78 comment | 44 complexity | 8b6a9bb3c2380db7d3faa73e656efd01 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // protobuf-matlab - FarSounder's Protocol Buffer support for Matlab
  2. // Copyright (c) 2008, FarSounder Inc. All rights reserved.
  3. // http://code.google.com/p/protobuf-matlab/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. //
  11. // * Redistributions in binary form must reproduce the above copyright
  12. // notice, this list of conditions and the following disclaimer in the
  13. // documentation and/or other materials provided with the distribution.
  14. //
  15. // * Neither the name of the FarSounder Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from this
  17. // software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  23. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  27. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29. // POSSIBILITY OF SUCH DAMAGE.
  30. // Author: fedor.labounko@gmail.com (Fedor Labounko)
  31. // Based on Google's C++ Protobuf compiler.
  32. //
  33. // Generates Matlab code for a given .proto file.
  34. #include <farsounder/protobuf/compiler/matlab/matlab_generator.h>
  35. #include <algorithm>
  36. #include <map>
  37. #include <set>
  38. #include <string>
  39. #include <sstream>
  40. #include <utility>
  41. #include <vector>
  42. #include <google/protobuf/io/printer.h>
  43. #include <google/protobuf/io/zero_copy_stream.h>
  44. #include <google/protobuf/descriptor.pb.h>
  45. #include <google/protobuf/stubs/strutil.h>
  46. #include <google/protobuf/wire_format.h>
  47. namespace farsounder {
  48. namespace protobuf {
  49. namespace compiler {
  50. namespace matlab {
  51. using ::google::protobuf::Descriptor;
  52. using ::google::protobuf::FieldDescriptor;
  53. using ::google::protobuf::FieldDescriptor;
  54. using ::google::protobuf::FileDescriptor;
  55. using ::google::protobuf::LowerString;
  56. using ::google::protobuf::SimpleDtoa;
  57. using ::google::protobuf::SimpleFtoa;
  58. using ::google::protobuf::SimpleItoa;
  59. using ::google::protobuf::StringReplace;
  60. using ::google::protobuf::compiler::GeneratorContext;
  61. using ::google::protobuf::internal::MutexLock;
  62. using ::google::protobuf::io::Printer;
  63. using ::std::make_pair;
  64. using ::std::map;
  65. using ::std::max;
  66. using ::std::pair;
  67. using ::std::set;
  68. using ::std::string;
  69. using ::std::stringstream;
  70. using ::std::vector;
  71. namespace {
  72. // CamelToLower taken from Dave Benson's modification for a C implementation
  73. // of Protocol Buffers
  74. string CamelToLower(const string &name) {
  75. string new_name;
  76. if (name.size() < 2) {
  77. new_name = name;
  78. LowerString(&new_name);
  79. return new_name;
  80. }
  81. new_name += tolower(name[0]);
  82. for (int i = 1; i < name.size(); ++i) {
  83. if (isupper(name[i]))
  84. new_name += "_";
  85. new_name += tolower(name[i]);
  86. }
  87. return new_name;
  88. }
  89. } // namespace
  90. // See Type enum in descriptor.h
  91. const MatlabGenerator::MatlabType
  92. MatlabGenerator::kTypeToMatlabTypeMap[FieldDescriptor::MAX_TYPE + 1] = {
  93. static_cast<MatlabGenerator::MatlabType>(-1), //invalid
  94. MATLABTYPE_DOUBLE, // TYPE_DOUBLE
  95. MATLABTYPE_SINGLE, // TYPE_FLOAT
  96. MATLABTYPE_INT64, // TYPE_INT64
  97. MATLABTYPE_UINT64, // TYPE_UINT64
  98. MATLABTYPE_INT32, // TYPE_INT32
  99. MATLABTYPE_UINT64, // TYPE_FIXED64
  100. MATLABTYPE_UINT32, // TYPE_FIXED32
  101. MATLABTYPE_UINT32, // TYPE_BOOL
  102. MATLABTYPE_STRING, // TYPE_STRING
  103. MATLABTYPE_MESSAGE, // TYPE_GROUP
  104. MATLABTYPE_MESSAGE, // TYPE_MESSAGE
  105. MATLABTYPE_BYTES, // TYPE_BYTES
  106. MATLABTYPE_UINT32, // TYPE_UINT32
  107. MATLABTYPE_ENUM, // TYPE_ENUM
  108. MATLABTYPE_INT32, // TYPE_SFIXED32
  109. MATLABTYPE_INT64, // TYPE_SFIXED64
  110. MATLABTYPE_INT32, // TYPE_SINT32
  111. MATLABTYPE_INT64 // TYPE_SINT64
  112. };
  113. const string
  114. MatlabGenerator::kMatlabTypeToString[MatlabGenerator::MAX_MATLABTYPE + 1] = {
  115. "invalid", // invalid index
  116. "int32", // MATLABTYPE_INT32
  117. "int64", // MATLABTYPE_INT64
  118. "uint32", // MATLABTYPE_UINT32
  119. "uint64", // MATLABTYPE_UINT64
  120. "double", // MATLABTYPE_DOUBLE
  121. "single", // MATLABTYPE_SINGLE
  122. "string", // MATLABTYPE_STRING
  123. "uint8 vector", // MATLABTYPE_BYTES
  124. "message", // MATLABTYPE_MESSAGE
  125. "enum", // MATLABTYPE_ENUM
  126. };
  127. MatlabGenerator::MatlabGenerator() {}
  128. MatlabGenerator::~MatlabGenerator() {}
  129. bool MatlabGenerator::Generate(const FileDescriptor* file,
  130. const string& parameter,
  131. GeneratorContext* output_directory,
  132. string* error) const {
  133. MutexLock lock(&mutex_);
  134. file_ = file;
  135. output_directory_ = output_directory;
  136. PrintMessageFunctions();
  137. return true;
  138. }
  139. void MatlabGenerator::PrintMessageFunctions() const {
  140. for (int i = 0; i < file_->message_type_count(); ++i) {
  141. PrintDescriptorFunction(*file_->message_type(i));
  142. PrintReadFunction(*file_->message_type(i));
  143. }
  144. }
  145. void MatlabGenerator::PrintDescriptorFunction(
  146. const Descriptor & descriptor) const {
  147. // Print nested messages
  148. for (int i = 0; i < descriptor.nested_type_count(); ++i) {
  149. PrintDescriptorFunction(*descriptor.nested_type(i));
  150. }
  151. string filename = DescriptorFunctionName(descriptor);
  152. filename += ".m";
  153. google::protobuf::internal::scoped_ptr<
  154. google::protobuf::io::ZeroCopyOutputStream>
  155. output(output_directory_->Open(filename));
  156. Printer printer(output.get(), '$');
  157. PrintDescriptorHeader(printer, descriptor);
  158. PrintDescriptorComment(printer, descriptor);
  159. printer.Indent();
  160. PrintDescriptorBody(printer, descriptor);
  161. printer.Outdent();
  162. }
  163. void MatlabGenerator::PrintDescriptorHeader(
  164. Printer & printer, const Descriptor & descriptor) const {
  165. string function_name = DescriptorFunctionName(descriptor);
  166. printer.Print("function [descriptor] = $function_name$()\n",
  167. "function_name", function_name);
  168. }
  169. void MatlabGenerator::PrintDescriptorComment(
  170. Printer & printer, const Descriptor & descriptor) const {
  171. string name = descriptor.name();
  172. string function_name = DescriptorFunctionName(descriptor);
  173. printer.Print("%$function_name$ Returns the descriptor for message $name$.\n",
  174. "name", name, "function_name", function_name);
  175. printer.Print("% ");
  176. PrintDescriptorHeader(printer, descriptor);
  177. printer.Print("%\n");
  178. printer.Print("% See also $read_function$",
  179. "read_function", ReadFunctionName(descriptor));
  180. printer.Print("\n");
  181. }
  182. void MatlabGenerator::PrintDescriptorBody(
  183. Printer & printer, const Descriptor & descriptor) const {
  184. printer.Print("\n");
  185. printer.Print("descriptor = struct( ...\n");
  186. printer.Indent();
  187. printer.Print("'name', '$name$', ...\n", "name", descriptor.name());
  188. printer.Print("'full_name', '$full_name$', ...\n", "full_name",
  189. descriptor.full_name());
  190. printer.Print("'filename', '$filename$', ...\n", "filename",
  191. descriptor.file()->name());
  192. printer.Print("'containing_type', '$containing_type$', ...\n",
  193. "containing_type",
  194. descriptor.containing_type() == NULL ? "" :
  195. descriptor.containing_type()->full_name());
  196. printer.Print("'fields', [ ...\n");
  197. printer.Indent();
  198. PrintFieldDescriptors(printer, descriptor);
  199. printer.Outdent();
  200. printer.Print("], ...\n");
  201. printer.Print("'extensions', [ ... % Not Implemented\n");
  202. printer.Indent();
  203. // PrintExtensions(printer, descriptor);
  204. printer.Outdent();
  205. printer.Print("], ...\n");
  206. printer.Print("'nested_types', [ ... % Not implemented\n");
  207. printer.Indent();
  208. // PrintNestedTypes(printer, descriptor);
  209. printer.Outdent();
  210. printer.Print("], ...\n");
  211. printer.Print("'enum_types', [ ... % Not Implemented\n");
  212. printer.Indent();
  213. // PrintEnumTypes(printer, descriptor);
  214. printer.Outdent();
  215. printer.Print("], ...\n");
  216. printer.Print("'options', [ ... % Not Implemented\n");
  217. printer.Indent();
  218. // PrintOptions(printer, descriptor);
  219. printer.Outdent();
  220. printer.Print("] ...\n");
  221. printer.Outdent();
  222. printer.Print(");\n\n");
  223. PrintFieldIndecesByNumber(printer, descriptor);
  224. }
  225. void MatlabGenerator::PrintFieldDescriptors(
  226. Printer & printer, const Descriptor & descriptor) const {
  227. vector<pair<int, int> > sorted_fields;
  228. for (int i = 0; i < descriptor.field_count(); ++i) {
  229. sorted_fields.push_back(make_pair(descriptor.field(i)->number(), i));
  230. }
  231. sort(sorted_fields.begin(), sorted_fields.end());
  232. const FieldDescriptor * field;
  233. map<string, string> m;
  234. for (int i = 0; i < descriptor.field_count(); ++i) {
  235. field = descriptor.field(sorted_fields[i].second);
  236. m.clear();
  237. printer.Print("struct( ...\n");
  238. printer.Indent();
  239. m["name"] = field->name();
  240. m["full_name"] = field->full_name();
  241. m["index"] = SimpleItoa(i + 1);
  242. m["number"] = SimpleItoa(field->number());
  243. m["type"] = SimpleItoa(field->type());
  244. m["matlab_type"] = SimpleItoa(kTypeToMatlabTypeMap[field->type()]);
  245. m["wire_type"] = SimpleItoa(
  246. google::protobuf::internal::WireFormat::WireTypeForFieldType(
  247. field->type()));
  248. m["label"] = SimpleItoa(field->label());
  249. m["default_value"] = DefaultValueToString(*field);
  250. m["read_function"] = MakeReadFunctionHandle(*field);
  251. m["write_function"] = MakeWriteFunctionHandle(*field);
  252. if (field->options().packed()) {
  253. m["packed"] = "true";
  254. } else {
  255. m["packed"] = "false";
  256. }
  257. printer.Print(m,
  258. "'name', '$name$', ...\n"
  259. "'full_name', '$full_name$', ...\n"
  260. "'index', $index$, ...\n"
  261. "'number', uint32($number$), ...\n"
  262. "'type', uint32($type$), ...\n"
  263. "'matlab_type', uint32($matlab_type$), ...\n"
  264. "'wire_type', uint32($wire_type$), ...\n"
  265. "'label', uint32($label$), ...\n"
  266. "'default_value', $default_value$, ...\n"
  267. "'read_function', $read_function$, ...\n"
  268. "'write_function', $write_function$, ...\n"
  269. "'options', struct('packed', $packed$) ...\n"
  270. );
  271. printer.Outdent();
  272. if (i != descriptor.field_count() - 1)
  273. printer.Print("), ...\n");
  274. else
  275. printer.Print(") ...\n");
  276. }
  277. }
  278. void MatlabGenerator::PrintFieldIndecesByNumber(
  279. Printer & printer, const Descriptor & descriptor) const {
  280. // Assumes the fields are entered into an array by increasing tag values
  281. printer.Print("descriptor.field_indeces_by_number = java.util.HashMap;\n");
  282. const FieldDescriptor * field;
  283. map<string, string> map_values;
  284. vector<pair<int, int> > sorted_fields;
  285. for (int i = 0; i < descriptor.field_count(); ++i) {
  286. sorted_fields.push_back(make_pair(descriptor.field(i)->number(), i));
  287. }
  288. sort(sorted_fields.begin(), sorted_fields.end());
  289. for (int i = 0; i < descriptor.field_count(); ++i) {
  290. field = descriptor.field(sorted_fields[i].second);
  291. printer.Print("put(descriptor.field_indeces_by_number, uint32($number$), $index$);\n",
  292. "number", SimpleItoa(field->number()),
  293. "index", SimpleItoa(i + 1));
  294. }
  295. printer.Print("\n");
  296. }
  297. void MatlabGenerator::PrintReadFunction(const Descriptor & descriptor) const {
  298. // Print nested messages
  299. for (int i = 0; i < descriptor.nested_type_count(); ++i) {
  300. PrintReadFunction(*descriptor.nested_type(i));
  301. }
  302. string filename = ReadFunctionName(descriptor);
  303. filename += ".m";
  304. google::protobuf::internal::scoped_ptr<
  305. google::protobuf::io::ZeroCopyOutputStream>
  306. output(output_directory_->Open(filename));
  307. Printer printer(output.get(), '$');
  308. PrintReadHeader(printer, descriptor);
  309. PrintReadComment(printer, descriptor);
  310. printer.Indent();
  311. PrintReadBody(printer, descriptor);
  312. printer.Outdent();
  313. }
  314. void MatlabGenerator::PrintReadHeader(Printer & printer,
  315. const Descriptor & descriptor) const {
  316. string name = CamelToLower(descriptor.name());
  317. string function_name = ReadFunctionName(descriptor);
  318. printer.Print("function [$name$] = $function_name$(buffer, buffer_start, buffer_end)\n",
  319. "name", name,
  320. "function_name", function_name);
  321. }
  322. void MatlabGenerator::PrintReadComment(Printer & printer,
  323. const Descriptor & descriptor) const {
  324. string name = descriptor.name();
  325. string function_name = ReadFunctionName(descriptor);
  326. printer.Print("%$function_name$ Reads the protobuf message $name$.\n",
  327. "name", name,
  328. "function_name", function_name);
  329. printer.Print("% ");
  330. PrintReadHeader(printer, descriptor);
  331. printer.Print("%\n");
  332. printer.Print("% INPUTS:\n"
  333. "% buffer : a buffer of uint8's to parse\n"
  334. "% buffer_start : optional starting index to consider of the buffer\n"
  335. "% defaults to 1\n"
  336. "% buffer_end : optional ending index to consider of the buffer\n"
  337. "% defaults to length(buffer)\n"
  338. "%\n"
  339. "% MEMBERS:\n");
  340. for (int i = 0; i < descriptor.field_count(); ++i) {
  341. const FieldDescriptor & field = *descriptor.field(i);
  342. string buffer_space(max(0, static_cast<int>(15 - field.name().size())), ' ');
  343. printer.Print("% $name$$buffer$: ",
  344. "name", field.name(),
  345. "buffer", buffer_space);
  346. switch(field.label()) {
  347. case FieldDescriptor::LABEL_OPTIONAL:
  348. printer.Print("optional ");
  349. break;
  350. case FieldDescriptor::LABEL_REQUIRED:
  351. printer.Print("required ");
  352. break;
  353. case FieldDescriptor::LABEL_REPEATED:
  354. printer.Print("repeated ");
  355. break;
  356. default:
  357. GOOGLE_LOG(FATAL)<<"Unhandled case in print comment.";
  358. }
  359. if (field.type() == FieldDescriptor::TYPE_MESSAGE) {
  360. printer.Print("<a href=\"matlab:help $read_function$\">$type$</a>",
  361. "read_function", ReadFunctionName(*field.message_type()),
  362. "type", field.message_type()->full_name());
  363. } else {
  364. printer.Print("$type$",
  365. "type", kMatlabTypeToString[kTypeToMatlabTypeMap[field.type()]]);
  366. }
  367. printer.Print(", defaults to $default$.\n", "default", DefaultValueToString(field));
  368. }
  369. bool first_to_print = true;
  370. string beginning_string = "%\n% See also";
  371. // Will store all the types we'll print in the See also help string
  372. // Used so we don't print duplicates
  373. int num = 0;
  374. set<const Descriptor *> used_types;
  375. #define PRINT_SEE_ALSO(DESCRIPTOR) \
  376. if (used_types.count(DESCRIPTOR) == 0) { \
  377. if (first_to_print) { \
  378. printer.Print("$beginning$ $function$", \
  379. "beginning", beginning_string, \
  380. "function", ReadFunctionName(*(DESCRIPTOR))); \
  381. first_to_print = false; \
  382. } else { \
  383. printer.Print(", $function$", \
  384. "function", ReadFunctionName(*(DESCRIPTOR))); \
  385. } \
  386. used_types.insert(DESCRIPTOR); \
  387. }
  388. // Add the containing type
  389. if (descriptor.containing_type() != NULL) {
  390. PRINT_SEE_ALSO(descriptor.containing_type());
  391. }
  392. // Add types used as fields in this message
  393. for (int i = 0; i < descriptor.field_count(); ++i) {
  394. if (descriptor.field(i)->type() !=
  395. ::google::protobuf::FieldDescriptor::TYPE_MESSAGE) {
  396. continue;
  397. }
  398. PRINT_SEE_ALSO(descriptor.field(i)->message_type());
  399. }
  400. // Add nested types defined in this message
  401. for (int i = 0; i < descriptor.nested_type_count(); ++i) {
  402. PRINT_SEE_ALSO(descriptor.nested_type(i));
  403. }
  404. // Print other message types defined in the same file
  405. for (int i = 0; i < file_->message_type_count(); ++i) {
  406. if (file_->message_type(i) == &descriptor)
  407. continue;
  408. PRINT_SEE_ALSO(file_->message_type(i));
  409. }
  410. #undef PRINT_SEE_ALSO
  411. if (!first_to_print) {
  412. printer.Print(".\n");
  413. }
  414. }
  415. void MatlabGenerator::PrintReadBody(Printer & printer,
  416. const Descriptor & descriptor) const {
  417. printer.Print("\n");
  418. printer.Print("if (nargin < 1)\n"
  419. " buffer = uint8([]);\n"
  420. "end\n"
  421. "if (nargin < 2)\n"
  422. " buffer_start = 1;\n"
  423. "end\n"
  424. "if (nargin < 3)\n"
  425. " buffer_end = length(buffer);\n"
  426. "end\n"
  427. "\n");
  428. string name = CamelToLower(descriptor.name());
  429. string descriptor_function = DescriptorFunctionName(descriptor);
  430. printer.Print("descriptor = $descriptor_function$();\n",
  431. "descriptor_function", descriptor_function);
  432. printer.Print("$name$ = pblib_generic_parse_from_string(buffer, descriptor, buffer_start, buffer_end);\n",
  433. "name", name);
  434. printer.Print("$name$.descriptor_function = @$descriptor_function$;\n",
  435. "name", name, "descriptor_function", descriptor_function);
  436. }
  437. string MatlabGenerator::DefaultValueToString(
  438. const FieldDescriptor & field) const {
  439. MatlabType type = kTypeToMatlabTypeMap[field.type()];
  440. field.has_default_value();
  441. stringstream s;
  442. if (field.is_repeated()) {
  443. switch(type) {
  444. case MATLABTYPE_INT32:
  445. return "int32([])";
  446. case MATLABTYPE_INT64:
  447. return "int64([])";
  448. case MATLABTYPE_UINT32:
  449. return "uint32([])";
  450. case MATLABTYPE_UINT64:
  451. return "uint64([])";
  452. case MATLABTYPE_DOUBLE:
  453. return "double([])";
  454. case MATLABTYPE_SINGLE:
  455. return "single([])";
  456. case MATLABTYPE_MESSAGE:
  457. return "struct([])";
  458. case MATLABTYPE_ENUM:
  459. return "int32([])";
  460. case MATLABTYPE_STRING:
  461. return "char([])";
  462. case MATLABTYPE_BYTES:
  463. return "uint8([])";
  464. }
  465. } else {
  466. switch(type) {
  467. case MATLABTYPE_INT32:
  468. s << "int32(" << SimpleItoa(field.default_value_int32()) << ")";
  469. return s.str();
  470. case MATLABTYPE_INT64:
  471. s << "int64(" << SimpleItoa(field.default_value_int64()) << ")";
  472. return s.str();
  473. case MATLABTYPE_UINT32:
  474. s << "uint32(";
  475. // This is needed as the default values are in a union and if the bool
  476. // value is set it doesn't set the full 32 bits
  477. if (field.type() == FieldDescriptor::TYPE_BOOL) {
  478. s << SimpleItoa(field.default_value_bool());
  479. } else {
  480. s << SimpleItoa(field.default_value_uint32());
  481. }
  482. s << ")";
  483. return s.str();
  484. case MATLABTYPE_UINT64:
  485. s << "uint64(" << SimpleItoa(field.default_value_uint64()) << ")";
  486. return s.str();
  487. case MATLABTYPE_DOUBLE:
  488. s << "double(" << SimpleDtoa(field.default_value_double()) << ")";
  489. return s.str();
  490. case MATLABTYPE_SINGLE:
  491. s << "single(" << SimpleFtoa(field.default_value_float()) << ")";
  492. return s.str();
  493. case MATLABTYPE_MESSAGE:
  494. return "struct([])";
  495. case MATLABTYPE_ENUM:
  496. s << "int32(" << SimpleItoa(field.default_value_enum()->number())<< ")";
  497. return s.str();
  498. case MATLABTYPE_STRING:
  499. s << "'" << StringReplace(field.default_value_string(), "'", "''", true) << "'";
  500. return s.str();
  501. case MATLABTYPE_BYTES:
  502. s << "uint8('" << StringReplace(field.default_value_string(), "'", "''", true) << "')";
  503. return s.str();
  504. }
  505. }
  506. GOOGLE_LOG(FATAL) << "Not reached.";
  507. return "''";
  508. }
  509. string MatlabGenerator::MakeReadFunctionHandle(
  510. const FieldDescriptor & field) const {
  511. MatlabType type = kTypeToMatlabTypeMap[field.type()];
  512. FieldDescriptor::Type proto_type = field.type();
  513. string function_handle;
  514. switch(type) {
  515. case MATLABTYPE_INT32:
  516. // We must call pblib_helpers_first because the standard varint
  517. // will put the result into a uint64
  518. //
  519. // We must also figure out whether this is encoded using the ZigZag
  520. // encoding, which is the case if its type was specificied as sint32 or
  521. // sint64
  522. if (proto_type == FieldDescriptor::TYPE_SINT32) {
  523. return "@(x) pblib_helpers_first(typecast(pblib_helpers_iff(bitget(x, 1), bitset(bitshift(bitxor(intmax('uint64'), x), -1), 64), bitshift(x, -1)), 'int32'))";
  524. } else {
  525. return "@(x) pblib_helpers_first(typecast(x, 'int32'))";
  526. }
  527. case MATLABTYPE_INT64:
  528. // We must figure out whether this is encoded using the ZigZag encoding,
  529. // which is the case if its type was specificied as sint32 or sint64
  530. if (proto_type == FieldDescriptor::TYPE_SINT64) {
  531. return "@(x) typecast(pblib_helpers_iff(bitget(x, 1), bitset(bitshift(bitxor(intmax('uint64'), x), -1), 64), bitshift(x, -1)), 'int64')";
  532. } else {
  533. return "@(x) typecast(x, 'int64')";
  534. }
  535. case MATLABTYPE_UINT32:
  536. // We must call pblib_helpers_first because the standard varint
  537. // will put the result into a uint64
  538. return "@(x) pblib_helpers_first(typecast(x, 'uint32'))";
  539. case MATLABTYPE_UINT64:
  540. return "@(x) typecast(x, 'uint64')";
  541. case MATLABTYPE_DOUBLE:
  542. return "@(x) typecast(x, 'double')";
  543. case MATLABTYPE_SINGLE:
  544. return "@(x) typecast(x, 'single')";
  545. case MATLABTYPE_STRING:
  546. return "@(x) char(x{1}(x{2} : x{3}))";
  547. case MATLABTYPE_BYTES:
  548. return "@(x) uint8(x{1}(x{2} : x{3}))";
  549. case MATLABTYPE_MESSAGE:
  550. return "@(x) " + ReadFunctionName(*field.message_type()) + "(x{1}, x{2}, x{3})";
  551. case MATLABTYPE_ENUM:
  552. // We must call pblib_helpers_first because the standard varint
  553. // will put the result into a uint64
  554. return "@(x) pblib_helpers_first(typecast(x, 'int32'))";
  555. }
  556. GOOGLE_LOG(FATAL) << "Shouldn't get here since switch should catch all cases.";
  557. return "";
  558. }
  559. string MatlabGenerator::MakeWriteFunctionHandle(const FieldDescriptor & field) const {
  560. // These functions should undo the work done by the read functions so as to
  561. // pass as input to write_varint the same values that read_varint would pass
  562. // back as output. That's why, in particular, we typecast fixed32,
  563. // sfixed32, etc. into uint8 as that's how read_varint would return them to
  564. // us.
  565. MatlabType matlab_type = kTypeToMatlabTypeMap[field.type()];
  566. FieldDescriptor::Type type = field.type();
  567. string function_handle;
  568. switch(matlab_type) {
  569. case MATLABTYPE_INT32:
  570. // We must figure out whether this is encoded using the ZigZag encoding,
  571. // which is the case if its type was specificied as sint32 or sint64 I
  572. // am not able to find an arithmetic shift in Matlab, but if one is
  573. // found we can do the zigzag with (n<<1) ^ (n>>31)
  574. switch (type) {
  575. case FieldDescriptor::TYPE_INT32:
  576. return "@(x) typecast(int32(x), 'uint32')";
  577. case FieldDescriptor::TYPE_SFIXED32:
  578. return "@(x) typecast(int32(x), 'uint8')";
  579. case FieldDescriptor::TYPE_SINT32:
  580. return "@(x) typecast(pblib_helpers_iff(int32(x) < 0, -2 * int32(x) - 1, 2 * int32(x)), 'uint32')";
  581. }
  582. GOOGLE_LOG(DFATAL)<<"Unhandled matlabtype_int32 type "<<type<<" in WriteFunctionHandle.";
  583. break;
  584. case MATLABTYPE_INT64:
  585. // We must figure out whether this is encoded using the ZigZag encoding,
  586. // which is the case if its type was specificied as sint32 or sint64 I
  587. // am not able to find an arithmetic shift in Matlab, but if one is
  588. // found we can do the zigzag with (n<<1) ^ (n>>63)
  589. switch(type) {
  590. case FieldDescriptor::TYPE_INT64:
  591. return "@(x) typecast(int64(x), 'uint64')";
  592. case FieldDescriptor::TYPE_SFIXED64:
  593. return "@(x) typecast(int64(x), 'uint8')";
  594. case FieldDescriptor::TYPE_SINT64:
  595. return "@(x) pblib_helpers_iff(int64(x) < 0, bitxor(bitshift(typecast(int64(x), 'uint64'), 1), intmax('uint64')), bitshift(typecast(int64(x), 'uint64'), 1))";
  596. }
  597. GOOGLE_LOG(DFATAL)<<"Unhandled matlabtype_int32 type "<<type<<" in WriteFunctionHandle.";
  598. break;
  599. case MATLABTYPE_UINT32:
  600. switch(type) {
  601. case FieldDescriptor::TYPE_FIXED32:
  602. return "@(x) typecast(uint32(x), 'uint8')";
  603. case FieldDescriptor::TYPE_BOOL:
  604. case FieldDescriptor::TYPE_UINT32:
  605. return "@(x) typecast(uint32(x), 'uint32')";
  606. }
  607. GOOGLE_LOG(DFATAL)<<"Unhandled matlabtype_uint32 type "<<type<<" in WriteFunctionHandle.";
  608. break;
  609. case MATLABTYPE_UINT64:
  610. switch(type) {
  611. case FieldDescriptor::TYPE_UINT64:
  612. return "@(x) typecast(uint64(x), 'uint64')";
  613. case FieldDescriptor::TYPE_FIXED64:
  614. return "@(x) typecast(uint64(x), 'uint8')";
  615. }
  616. GOOGLE_LOG(DFATAL)<<"Unhandled matlabtype_uint64 type "<<type<<" in WriteFunctionHandle.";
  617. break;
  618. case MATLABTYPE_DOUBLE:
  619. return "@(x) typecast(double(x), 'uint8')";
  620. case MATLABTYPE_SINGLE:
  621. return "@(x) typecast(single(x), 'uint8')";
  622. case MATLABTYPE_STRING:
  623. return "@uint8";
  624. case MATLABTYPE_BYTES:
  625. return "@uint8";
  626. case MATLABTYPE_MESSAGE:
  627. return "@pblib_generic_serialize_to_string";
  628. case MATLABTYPE_ENUM:
  629. // We must call pblib_helpers_first because the standard varint
  630. // will put the result into a uint64
  631. return "@(x) typecast(int32(x), 'uint32')";
  632. }
  633. GOOGLE_LOG(DFATAL) << "Shouldn't get here since switch should catch all cases.";
  634. return "";
  635. }
  636. string MatlabGenerator::DescriptorFunctionName(const Descriptor & descriptor) const {
  637. return "pb_descriptor_" + StringReplace(descriptor.full_name(), ".", "__", true);
  638. }
  639. string MatlabGenerator::ReadFunctionName(const Descriptor & descriptor) const {
  640. return "pb_read_" + StringReplace(descriptor.full_name(), ".", "__", true);
  641. }
  642. } // namespace matlab
  643. } // namespace compiler
  644. } // namespace protobuf
  645. } // namespace google