Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(831)

Side by Side Diff: third_party/protobuf/src/google/protobuf/util/internal/protostream_objectsource.cc

Issue 2495533002: third_party/protobuf: Update to HEAD (83d681ee2c) (Closed)
Patch Set: Make chrome settings proto generated file a component Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Protocol Buffers - Google's data interchange format 1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved. 2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/ 3 // https://developers.google.com/protocol-buffers/
4 // 4 //
5 // Redistribution and use in source and binary forms, with or without 5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are 6 // modification, are permitted provided that the following conditions are
7 // met: 7 // met:
8 // 8 //
9 // * Redistributions of source code must retain the above copyright 9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer. 10 // notice, this list of conditions and the following disclaimer.
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 const google::protobuf::Type& type, int number); 78 const google::protobuf::Type& type, int number);
79 79
80 // Returns true if the field is packable. 80 // Returns true if the field is packable.
81 bool IsPackable(const google::protobuf::Field& field); 81 bool IsPackable(const google::protobuf::Field& field);
82 82
83 // Finds an enum value with the given number. NULL if none found. 83 // Finds an enum value with the given number. NULL if none found.
84 const google::protobuf::EnumValue* FindEnumValueByNumber( 84 const google::protobuf::EnumValue* FindEnumValueByNumber(
85 const google::protobuf::Enum& tech_enum, int number); 85 const google::protobuf::Enum& tech_enum, int number);
86 86
87 // Utility function to format nanos. 87 // Utility function to format nanos.
88 const string FormatNanos(uint32 nanos); 88 const string FormatNanos(uint32 nanos, bool with_trailing_zeros);
89 89
90 StatusOr<string> MapKeyDefaultValueAsString( 90 StatusOr<string> MapKeyDefaultValueAsString(
91 const google::protobuf::Field& field) { 91 const google::protobuf::Field& field) {
92 switch (field.kind()) { 92 switch (field.kind()) {
93 case google::protobuf::Field_Kind_TYPE_BOOL: 93 case google::protobuf::Field_Kind_TYPE_BOOL:
94 return string("false"); 94 return string("false");
95 case google::protobuf::Field_Kind_TYPE_INT32: 95 case google::protobuf::Field_Kind_TYPE_INT32:
96 case google::protobuf::Field_Kind_TYPE_INT64: 96 case google::protobuf::Field_Kind_TYPE_INT64:
97 case google::protobuf::Field_Kind_TYPE_UINT32: 97 case google::protobuf::Field_Kind_TYPE_UINT32:
98 case google::protobuf::Field_Kind_TYPE_UINT64: 98 case google::protobuf::Field_Kind_TYPE_UINT64:
(...skipping 15 matching lines...) Expand all
114 114
115 ProtoStreamObjectSource::ProtoStreamObjectSource( 115 ProtoStreamObjectSource::ProtoStreamObjectSource(
116 google::protobuf::io::CodedInputStream* stream, TypeResolver* type_resolver, 116 google::protobuf::io::CodedInputStream* stream, TypeResolver* type_resolver,
117 const google::protobuf::Type& type) 117 const google::protobuf::Type& type)
118 : stream_(stream), 118 : stream_(stream),
119 typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), 119 typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
120 own_typeinfo_(true), 120 own_typeinfo_(true),
121 type_(type), 121 type_(type),
122 use_lower_camel_for_enums_(false), 122 use_lower_camel_for_enums_(false),
123 recursion_depth_(0), 123 recursion_depth_(0),
124 max_recursion_depth_(kDefaultMaxRecursionDepth) { 124 max_recursion_depth_(kDefaultMaxRecursionDepth),
125 render_unknown_fields_(false),
126 add_trailing_zeros_for_timestamp_and_duration_(false) {
125 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; 127 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
126 } 128 }
127 129
128 ProtoStreamObjectSource::ProtoStreamObjectSource( 130 ProtoStreamObjectSource::ProtoStreamObjectSource(
129 google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo, 131 google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo,
130 const google::protobuf::Type& type) 132 const google::protobuf::Type& type)
131 : stream_(stream), 133 : stream_(stream),
132 typeinfo_(typeinfo), 134 typeinfo_(typeinfo),
133 own_typeinfo_(false), 135 own_typeinfo_(false),
134 type_(type), 136 type_(type),
135 use_lower_camel_for_enums_(false), 137 use_lower_camel_for_enums_(false),
136 recursion_depth_(0), 138 recursion_depth_(0),
137 max_recursion_depth_(kDefaultMaxRecursionDepth) { 139 max_recursion_depth_(kDefaultMaxRecursionDepth),
140 render_unknown_fields_(false),
141 add_trailing_zeros_for_timestamp_and_duration_(false) {
138 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; 142 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
139 } 143 }
140 144
141 ProtoStreamObjectSource::~ProtoStreamObjectSource() { 145 ProtoStreamObjectSource::~ProtoStreamObjectSource() {
142 if (own_typeinfo_) { 146 if (own_typeinfo_) {
143 delete typeinfo_; 147 delete typeinfo_;
144 } 148 }
145 } 149 }
146 150
147 Status ProtoStreamObjectSource::NamedWriteTo(StringPiece name, 151 Status ProtoStreamObjectSource::NamedWriteTo(StringPiece name,
(...skipping 29 matching lines...) Expand all
177 181
178 const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); 182 const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
179 if (type_renderer != NULL) { 183 if (type_renderer != NULL) {
180 return (*type_renderer)(this, type, name, ow); 184 return (*type_renderer)(this, type, name, ow);
181 } 185 }
182 186
183 const google::protobuf::Field* field = NULL; 187 const google::protobuf::Field* field = NULL;
184 string field_name; 188 string field_name;
185 // last_tag set to dummy value that is different from tag. 189 // last_tag set to dummy value that is different from tag.
186 uint32 tag = stream_->ReadTag(), last_tag = tag + 1; 190 uint32 tag = stream_->ReadTag(), last_tag = tag + 1;
191 google::protobuf::UnknownFieldSet unknown_fields;
187 192
188 if (include_start_and_end) { 193 if (include_start_and_end) {
189 ow->StartObject(name); 194 ow->StartObject(name);
190 } 195 }
191 while (tag != end_tag) { 196 while (tag != end_tag) {
192 if (tag != last_tag) { // Update field only if tag is changed. 197 if (tag != last_tag) { // Update field only if tag is changed.
193 last_tag = tag; 198 last_tag = tag;
194 field = FindAndVerifyField(type, tag); 199 field = FindAndVerifyField(type, tag);
195 if (field != NULL) { 200 if (field != NULL) {
196 field_name = field->json_name(); 201 field_name = field->json_name();
197 } 202 }
198 } 203 }
199 if (field == NULL) { 204 if (field == NULL) {
200 // If we didn't find a field, skip this unknown tag. 205 // If we didn't find a field, skip this unknown tag.
201 // TODO(wpoon): Check return boolean value. 206 // TODO(wpoon): Check return boolean value.
202 WireFormat::SkipField(stream_, tag, NULL); 207 WireFormat::SkipField(stream_, tag,
208 render_unknown_fields_ ? &unknown_fields : NULL);
203 tag = stream_->ReadTag(); 209 tag = stream_->ReadTag();
204 continue; 210 continue;
205 } 211 }
206 212
207 if (field->cardinality() == 213 if (field->cardinality() ==
208 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { 214 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
209 bool check_maps = true; 215 bool check_maps = true;
210 216
211 if (check_maps && IsMap(*field)) { 217 if (check_maps && IsMap(*field)) {
212 ow->StartObject(field_name); 218 ow->StartObject(field_name);
213 ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow)); 219 ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow));
214 ow->EndObject(); 220 ow->EndObject();
215 } else { 221 } else {
216 ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow)); 222 ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow));
217 } 223 }
218 } else { 224 } else {
219 // Render the field. 225 // Render the field.
220 RETURN_IF_ERROR(RenderField(field, field_name, ow)); 226 RETURN_IF_ERROR(RenderField(field, field_name, ow));
221 tag = stream_->ReadTag(); 227 tag = stream_->ReadTag();
222 } 228 }
223 } 229 }
230
231
224 if (include_start_and_end) { 232 if (include_start_and_end) {
225 ow->EndObject(); 233 ow->EndObject();
226 } 234 }
227 return Status::OK; 235 return Status::OK;
228 } 236 }
229 237
230 StatusOr<uint32> ProtoStreamObjectSource::RenderList( 238 StatusOr<uint32> ProtoStreamObjectSource::RenderList(
231 const google::protobuf::Field* field, StringPiece name, uint32 list_tag, 239 const google::protobuf::Field* field, StringPiece name, uint32 list_tag,
232 ObjectWriter* ow) const { 240 ObjectWriter* ow) const {
233 uint32 tag_to_return = 0; 241 uint32 tag_to_return = 0;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 if (map_key.empty()) { 283 if (map_key.empty()) {
276 // An absent map key is treated as the default. 284 // An absent map key is treated as the default.
277 const google::protobuf::Field* key_field = 285 const google::protobuf::Field* key_field =
278 FindFieldByNumber(*field_type, 1); 286 FindFieldByNumber(*field_type, 1);
279 if (key_field == NULL) { 287 if (key_field == NULL) {
280 // The Type info for this map entry is incorrect. It should always 288 // The Type info for this map entry is incorrect. It should always
281 // have a field named "key" and with field number 1. 289 // have a field named "key" and with field number 1.
282 return Status(util::error::INTERNAL, "Invalid map entry."); 290 return Status(util::error::INTERNAL, "Invalid map entry.");
283 } 291 }
284 ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field)); 292 ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field));
293 // Key is empty, force it to render as empty (for string values).
294 ow->empty_name_ok_for_next_key();
285 } 295 }
286 RETURN_IF_ERROR(RenderField(field, map_key, ow)); 296 RETURN_IF_ERROR(RenderField(field, map_key, ow));
287 } else { 297 } else {
288 // The Type info for this map entry is incorrect. It should contain 298 // The Type info for this map entry is incorrect. It should contain
289 // exactly two fields with field number 1 and 2. 299 // exactly two fields with field number 1 and 2.
290 return Status(util::error::INTERNAL, "Invalid map entry."); 300 return Status(util::error::INTERNAL, "Invalid map entry.");
291 } 301 }
292 } 302 }
293 stream_->PopLimit(old_limit); 303 stream_->PopLimit(old_limit);
294 } while ((tag_to_return = stream_->ReadTag()) == list_tag); 304 } while ((tag_to_return = stream_->ReadTag()) == list_tag);
295 return tag_to_return; 305 return tag_to_return;
296 } 306 }
297 307
298 Status ProtoStreamObjectSource::RenderPacked( 308 Status ProtoStreamObjectSource::RenderPacked(
299 const google::protobuf::Field* field, ObjectWriter* ow) const { 309 const google::protobuf::Field* field, ObjectWriter* ow) const {
300 uint32 length; 310 uint32 length;
301 stream_->ReadVarint32(&length); 311 stream_->ReadVarint32(&length);
302 int old_limit = stream_->PushLimit(length); 312 int old_limit = stream_->PushLimit(length);
303 while (stream_->BytesUntilLimit() > 0) { 313 while (stream_->BytesUntilLimit() > 0) {
304 RETURN_IF_ERROR(RenderField(field, StringPiece(), ow)); 314 RETURN_IF_ERROR(RenderField(field, StringPiece(), ow));
305 } 315 }
306 stream_->PopLimit(old_limit); 316 stream_->PopLimit(old_limit);
307 return Status::OK; 317 return Status::OK;
308 } 318 }
309 319
310 Status ProtoStreamObjectSource::RenderTimestamp( 320 Status ProtoStreamObjectSource::RenderTimestamp(
311 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, 321 const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
312 StringPiece field_name, ObjectWriter* ow) { 322 StringPiece field_name, ObjectWriter* ow) {
313 pair<int64, int32> p = os->ReadSecondsAndNanos(type); 323 std::pair<int64, int32> p = os->ReadSecondsAndNanos(type);
314 int64 seconds = p.first; 324 int64 seconds = p.first;
315 int32 nanos = p.second; 325 int32 nanos = p.second;
316 if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) { 326 if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) {
317 return Status( 327 return Status(
318 util::error::INTERNAL, 328 util::error::INTERNAL,
319 StrCat("Timestamp seconds exceeds limit for field: ", field_name)); 329 StrCat("Timestamp seconds exceeds limit for field: ", field_name));
320 } 330 }
321 331
322 if (nanos < 0 || nanos >= kNanosPerSecond) { 332 if (nanos < 0 || nanos >= kNanosPerSecond) {
323 return Status( 333 return Status(
324 util::error::INTERNAL, 334 util::error::INTERNAL,
325 StrCat("Timestamp nanos exceeds limit for field: ", field_name)); 335 StrCat("Timestamp nanos exceeds limit for field: ", field_name));
326 } 336 }
327 337
328 ow->RenderString(field_name, 338 ow->RenderString(field_name,
329 ::google::protobuf::internal::FormatTime(seconds, nanos)); 339 ::google::protobuf::internal::FormatTime(seconds, nanos));
330 340
331 return Status::OK; 341 return Status::OK;
332 } 342 }
333 343
334 Status ProtoStreamObjectSource::RenderDuration( 344 Status ProtoStreamObjectSource::RenderDuration(
335 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, 345 const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
336 StringPiece field_name, ObjectWriter* ow) { 346 StringPiece field_name, ObjectWriter* ow) {
337 pair<int64, int32> p = os->ReadSecondsAndNanos(type); 347 std::pair<int64, int32> p = os->ReadSecondsAndNanos(type);
338 int64 seconds = p.first; 348 int64 seconds = p.first;
339 int32 nanos = p.second; 349 int32 nanos = p.second;
340 if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) { 350 if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) {
341 return Status( 351 return Status(
342 util::error::INTERNAL, 352 util::error::INTERNAL,
343 StrCat("Duration seconds exceeds limit for field: ", field_name)); 353 StrCat("Duration seconds exceeds limit for field: ", field_name));
344 } 354 }
345 355
346 if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { 356 if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
347 return Status( 357 return Status(
348 util::error::INTERNAL, 358 util::error::INTERNAL,
349 StrCat("Duration nanos exceeds limit for field: ", field_name)); 359 StrCat("Duration nanos exceeds limit for field: ", field_name));
350 } 360 }
351 361
352 string sign = ""; 362 string sign = "";
353 if (seconds < 0) { 363 if (seconds < 0) {
354 if (nanos > 0) { 364 if (nanos > 0) {
355 return Status(util::error::INTERNAL, 365 return Status(util::error::INTERNAL,
356 StrCat("Duration nanos is non-negative, but seconds is " 366 StrCat("Duration nanos is non-negative, but seconds is "
357 "negative for field: ", 367 "negative for field: ",
358 field_name)); 368 field_name));
359 } 369 }
360 sign = "-"; 370 sign = "-";
361 seconds = -seconds; 371 seconds = -seconds;
362 nanos = -nanos; 372 nanos = -nanos;
363 } else if (seconds == 0 && nanos < 0) { 373 } else if (seconds == 0 && nanos < 0) {
364 sign = "-"; 374 sign = "-";
365 nanos = -nanos; 375 nanos = -nanos;
366 } 376 }
367 string formatted_duration = StringPrintf("%s%lld%ss", sign.c_str(), seconds, 377 string formatted_duration = StringPrintf(
368 FormatNanos(nanos).c_str()); 378 "%s%lld%ss", sign.c_str(), seconds,
379 FormatNanos(nanos, os->add_trailing_zeros_for_timestamp_and_duration_)
380 .c_str());
369 ow->RenderString(field_name, formatted_duration); 381 ow->RenderString(field_name, formatted_duration);
370 return Status::OK; 382 return Status::OK;
371 } 383 }
372 384
373 Status ProtoStreamObjectSource::RenderDouble(const ProtoStreamObjectSource* os, 385 Status ProtoStreamObjectSource::RenderDouble(const ProtoStreamObjectSource* os,
374 const google::protobuf::Type& type, 386 const google::protobuf::Type& type,
375 StringPiece field_name, 387 StringPiece field_name,
376 ObjectWriter* ow) { 388 ObjectWriter* ow) {
377 uint32 tag = os->stream_->ReadTag(); 389 uint32 tag = os->stream_->ReadTag();
378 uint64 buffer64 = 0; // default value of Double wrapper value 390 uint64 buffer64 = 0; // default value of Double wrapper value
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after
844 if (field->type_url() == kStructNullValueTypeUrl) { 856 if (field->type_url() == kStructNullValueTypeUrl) {
845 ow->RenderNull(field_name); 857 ow->RenderNull(field_name);
846 break; 858 break;
847 } 859 }
848 860
849 // Get the nested enum type for this field. 861 // Get the nested enum type for this field.
850 // TODO(skarvaje): Avoid string manipulation. Find ways to speed this 862 // TODO(skarvaje): Avoid string manipulation. Find ways to speed this
851 // up. 863 // up.
852 const google::protobuf::Enum* en = 864 const google::protobuf::Enum* en =
853 typeinfo_->GetEnumByTypeUrl(field->type_url()); 865 typeinfo_->GetEnumByTypeUrl(field->type_url());
854 // Lookup the name of the enum, and render that. Skips unknown enums. 866 // Lookup the name of the enum, and render that. Unknown enum values
867 // are printed as integers.
855 if (en != NULL) { 868 if (en != NULL) {
856 const google::protobuf::EnumValue* enum_value = 869 const google::protobuf::EnumValue* enum_value =
857 FindEnumValueByNumber(*en, buffer32); 870 FindEnumValueByNumber(*en, buffer32);
858 if (enum_value != NULL) { 871 if (enum_value != NULL) {
859 if (use_lower_camel_for_enums_) 872 if (use_lower_camel_for_enums_)
860 ow->RenderString(field_name, ToCamelCase(enum_value->name())); 873 ow->RenderString(field_name, ToCamelCase(enum_value->name()));
861 else 874 else
862 ow->RenderString(field_name, enum_value->name()); 875 ow->RenderString(field_name, enum_value->name());
876 } else {
877 ow->RenderInt32(field_name, buffer32);
863 } 878 }
864 } else { 879 } else {
865 GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url(); 880 ow->RenderInt32(field_name, buffer32);
866 } 881 }
867 break; 882 break;
868 } 883 }
869 case google::protobuf::Field_Kind_TYPE_STRING: { 884 case google::protobuf::Field_Kind_TYPE_STRING: {
870 stream_->ReadVarint32(&buffer32); // string size. 885 stream_->ReadVarint32(&buffer32); // string size.
871 stream_->ReadString(&strbuffer, buffer32); 886 stream_->ReadString(&strbuffer, buffer32);
872 ow->RenderString(field_name, strbuffer); 887 ow->RenderString(field_name, strbuffer);
873 break; 888 break;
874 } 889 }
875 case google::protobuf::Field_Kind_TYPE_BYTES: { 890 case google::protobuf::Field_Kind_TYPE_BYTES: {
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1006 // Field is a map if it is a repeated message and it has an option "map_type". 1021 // Field is a map if it is a repeated message and it has an option "map_type".
1007 // TODO(skarvaje): Consider pre-computing the IsMap() into Field directly. 1022 // TODO(skarvaje): Consider pre-computing the IsMap() into Field directly.
1008 bool ProtoStreamObjectSource::IsMap( 1023 bool ProtoStreamObjectSource::IsMap(
1009 const google::protobuf::Field& field) const { 1024 const google::protobuf::Field& field) const {
1010 const google::protobuf::Type* field_type = 1025 const google::protobuf::Type* field_type =
1011 typeinfo_->GetTypeByTypeUrl(field.type_url()); 1026 typeinfo_->GetTypeByTypeUrl(field.type_url());
1012 1027
1013 // TODO(xiaofeng): Unify option names. 1028 // TODO(xiaofeng): Unify option names.
1014 return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE && 1029 return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE &&
1015 (GetBoolOptionOrDefault(field_type->options(), 1030 (GetBoolOptionOrDefault(field_type->options(),
1016 "google.protobuf.MessageOptions.map_entry", fal se) || 1031 "google.protobuf.MessageOptions.map_entry",
1017 GetBoolOptionOrDefault(field_type->options(), "map_entry", false)); 1032 false) ||
1033 GetBoolOptionOrDefault(field_type->options(), "map_entry", false) ||
1034 GetBoolOptionOrDefault(field_type->options(),
1035 "proto2.MessageOptions.map_entry", false));
1018 } 1036 }
1019 1037
1020 std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos( 1038 std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos(
1021 const google::protobuf::Type& type) const { 1039 const google::protobuf::Type& type) const {
1022 uint64 seconds = 0; 1040 uint64 seconds = 0;
1023 uint32 nanos = 0; 1041 uint32 nanos = 0;
1024 uint32 tag = 0; 1042 uint32 tag = 0;
1025 int64 signed_seconds = 0; 1043 int64 signed_seconds = 0;
1026 int32 signed_nanos = 0; 1044 int32 signed_nanos = 0;
1027 1045
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1085 const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i); 1103 const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i);
1086 if (ev.number() == number) { 1104 if (ev.number() == number) {
1087 return &ev; 1105 return &ev;
1088 } 1106 }
1089 } 1107 }
1090 return NULL; 1108 return NULL;
1091 } 1109 }
1092 1110
1093 // TODO(skarvaje): Look into optimizing this by not doing computation on 1111 // TODO(skarvaje): Look into optimizing this by not doing computation on
1094 // double. 1112 // double.
1095 const string FormatNanos(uint32 nanos) { 1113 const string FormatNanos(uint32 nanos, bool with_trailing_zeros) {
1114 if (nanos == 0) {
1115 return with_trailing_zeros ? ".000" : "";
1116 }
1117
1096 const char* format = 1118 const char* format =
1097 (nanos % 1000 != 0) ? "%.9f" : (nanos % 1000000 != 0) ? "%.6f" : "%.3f"; 1119 (nanos % 1000 != 0) ? "%.9f" : (nanos % 1000000 != 0) ? "%.6f" : "%.3f";
1098 string formatted = 1120 string formatted =
1099 StringPrintf(format, static_cast<double>(nanos) / kNanosPerSecond); 1121 StringPrintf(format, static_cast<double>(nanos) / kNanosPerSecond);
1100 // remove the leading 0 before decimal. 1122 // remove the leading 0 before decimal.
1101 return formatted.substr(1); 1123 return formatted.substr(1);
1102 } 1124 }
1103 } // namespace 1125 } // namespace
1104 1126
1105 } // namespace converter 1127 } // namespace converter
1106 } // namespace util 1128 } // namespace util
1107 } // namespace protobuf 1129 } // namespace protobuf
1108 } // namespace google 1130 } // namespace google
1131
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698