diff options
author | 2016-04-14 19:15:20 -0800 | |
---|---|---|
committer | 2016-04-14 20:22:35 -0700 | |
commit | df15baa9b10a0b2d194181dff7ee14bff70d9b8f (patch) | |
tree | a66e1fcb309a7404a2749140d8bac991a6524ac0 /tensorflow/core/lib/strings/proto_text_util.h | |
parent | 104fe2822b419c4154d11c401ffd4a3a6e8f24c6 (diff) |
Add tools/proto_text for generating ProtoDebugString,
ProtoShortDebugString, and ProtoParseFromString methods from protos. This will
allow changing code used on mobile to use the proto LITE_RUNTIME, to reduce
code size.
This change is only for the tool itself. A future change will add a better
genrule and use it the generated code in tensorflow.
Change: 119919087
Diffstat (limited to 'tensorflow/core/lib/strings/proto_text_util.h')
-rw-r--r-- | tensorflow/core/lib/strings/proto_text_util.h | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/tensorflow/core/lib/strings/proto_text_util.h b/tensorflow/core/lib/strings/proto_text_util.h new file mode 100644 index 0000000000..35040a9408 --- /dev/null +++ b/tensorflow/core/lib/strings/proto_text_util.h @@ -0,0 +1,191 @@ +/* Copyright 2016 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_STRINGS_PROTO_TEXT_UTIL_H_ +#define THIRD_PARTY_TENSORFLOW_CORE_LIB_STRINGS_PROTO_TEXT_UTIL_H_ + +#include "tensorflow/core/lib/strings/numbers.h" +#include "tensorflow/core/lib/strings/scanner.h" +#include "tensorflow/core/lib/strings/str_util.h" +#include "tensorflow/core/lib/strings/strcat.h" +#include "tensorflow/core/platform/macros.h" +#include "tensorflow/core/platform/protobuf.h" + +namespace tensorflow { +namespace strings { + +static constexpr char kColonSeparator[] = ": "; + +// Helper functions for writing proto-text output. +// Used by the code generated from tools/proto_text/gen_proto_text_lib.cc. +class ProtoTextOutput { + public: + // Construct a ProtoTextOutput that writes to <output> If short_debug is true, + // outputs text to match proto.ShortDebugString(); else matches + // proto.DebugString(). + ProtoTextOutput(string* output, bool short_debug) + : output_(output), + short_debug_(short_debug), + field_separator_(short_debug ? " " : "\n") {} + + // Writes opening of nested message and increases indent level. + void OpenNestedMessage(const char field_name[]) { + StrAppend(output_, level_empty_ ? "" : field_separator_, indent_, + field_name, " {", field_separator_); + if (!short_debug_) StrAppend(&indent_, " "); + level_empty_ = true; + } + + // Writes close of nested message and decreases indent level. + void CloseNestedMessage() { + if (!short_debug_) indent_.resize(indent_.size() - 2); + StrAppend(output_, level_empty_ ? "" : field_separator_, indent_, "}"); + level_empty_ = false; + } + + // Print the close of the top-level message that was printed. + void CloseTopMessage() { + if (!short_debug_ && !level_empty_) StrAppend(output_, "\n"); + } + + // Appends a numeric value, like my_field: 123 + template <typename T> + void AppendNumeric(const char field_name[], T value) { + AppendFieldAndValue(field_name, StrCat(value)); + } + + // Appends a numeric value, like my_field: 123, but only if value != 0. + template <typename T> + void AppendNumericIfNotZero(const char field_name[], T value) { + if (value != 0) AppendNumeric(field_name, value); + } + + // Appends a bool value, either my_field: true or my_field: false. + void AppendBool(const char field_name[], bool value) { + AppendFieldAndValue(field_name, value ? "true" : "false"); + } + + // Appends a bool value, as my_field: true, only if value is true. + void AppendBoolIfTrue(const char field_name[], bool value) { + if (value) AppendBool(field_name, value); + } + + // Appends a string value, like my_field: "abc123". + void AppendString(const char field_name[], const string& value) { + AppendFieldAndValue( + field_name, StrCat("\"", ::tensorflow::str_util::CEscape(value), "\"")); + } + + // Appends a string value, like my_field: "abc123", but only if value is not + // empty. + void AppendStringIfNotEmpty(const char field_name[], const string& value) { + if (!value.empty()) AppendString(field_name, value); + } + + // Appends the string name of an enum, like my_field: FIRST_ENUM. + void AppendEnumName(const char field_name[], const string& name) { + AppendFieldAndValue(field_name, name); + } + + private: + void AppendFieldAndValue(const char field_name[], const string& value_text) { + StrAppend(output_, level_empty_ ? "" : field_separator_, indent_, + field_name, kColonSeparator, value_text); + level_empty_ = false; + } + + string* const output_; + const bool short_debug_; + const string field_separator_; + string indent_; + + // False when at least one field has been output for the message at the + // current deepest level of nesting. + bool level_empty_ = true; + + TF_DISALLOW_COPY_AND_ASSIGN(ProtoTextOutput); +}; + +inline bool ProtoParseNumeric(StringPiece s, int32* value) { + return ::tensorflow::strings::safe_strto32(s, value); +} + +inline bool ProtoParseNumeric(StringPiece s, uint32* value) { + return ::tensorflow::strings::safe_strtou32(s, value); +} + +inline bool ProtoParseNumeric(StringPiece s, int64* value) { + return ::tensorflow::strings::safe_strto64(s, value); +} + +inline bool ProtoParseNumeric(StringPiece s, uint64* value) { + return ::tensorflow::strings::safe_strtou64(s, value); +} + +inline bool ProtoParseNumeric(StringPiece s, float* value) { + return ::tensorflow::strings::safe_strtof(s.ToString().c_str(), value); +} + +inline bool ProtoParseNumeric(StringPiece s, double* value) { + return ::tensorflow::strings::safe_strtod(s.ToString().c_str(), value); +} + +inline void ProtoSpaceAndComments(Scanner* scanner) { + for (;;) { + scanner->AnySpace(); + if (scanner->Peek() != '#') return; + // Skip until newline. + while (scanner->Peek('\n') != '\n') scanner->One(Scanner::ALL); + } +} + +// Parse the next numeric value from <scanner>, returning false if parsing +// failed. +template <typename T> +bool ProtoParseNumericFromScanner(Scanner* scanner, T* value) { + StringPiece numeric_str; + scanner->RestartCapture(); + if (!scanner->Many(Scanner::LETTER_DIGIT_DOT_PLUS_MINUS) + .GetResult(nullptr, &numeric_str)) { + return false; + } + + // Special case to disallow multiple leading zeroes, to match proto parsing. + int leading_zero = 0; + for (int i = 0; i < numeric_str.size(); ++i) { + const char ch = numeric_str[i]; + if (ch == '0') { + if (++leading_zero > 1) return false; + } else if (ch != '-') { + break; + } + } + + ProtoSpaceAndComments(scanner); + return ProtoParseNumeric(numeric_str, value); +} + +// Parse the next boolean value from <scanner>, returning false if parsing +// failed. +bool ProtoParseBoolFromScanner(Scanner* scanner, bool* value); + +// Parse the next string literal from <scanner>, returning false if parsing +// failed. +bool ProtoParseStringLiteralFromScanner(Scanner* scanner, string* value); + +} // namespace strings +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_STRINGS_PROTO_TEXT_UTIL_H_ |