aboutsummaryrefslogtreecommitdiff
path: root/src/google
diff options
context:
space:
mode:
Diffstat (limited to 'src/google')
-rw-r--r--src/google/protobuf/arena.h2
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc9
-rw-r--r--src/google/protobuf/compiler/command_line_interface_unittest.cc22
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_service.cc8
-rwxr-xr-xsrc/google/protobuf/compiler/js/js_generator.cc17
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_file.cc331
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_file.h5
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_generator.cc41
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers.cc319
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_helpers.h36
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_message.cc16
-rw-r--r--src/google/protobuf/compiler/objectivec/objectivec_message.h3
-rw-r--r--src/google/protobuf/generated_message_util.h2
-rw-r--r--src/google/protobuf/map.h15
-rw-r--r--[-rwxr-xr-x]src/google/protobuf/stubs/hash.h58
-rw-r--r--src/google/protobuf/text_format_unittest.cc2
18 files changed, 699 insertions, 191 deletions
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index b3d66d91..cf07b9fc 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -213,7 +213,7 @@ struct ArenaOptions {
// well as RepeatedPtrField.
#if __cplusplus >= 201103L
-class Arena final {
+class LIBPROTOBUF_EXPORT Arena final {
#else
class LIBPROTOBUF_EXPORT Arena {
#endif
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index fcad6b61..c1a6c15d 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -1136,8 +1136,13 @@ CommandLineInterface::InterpretArgument(const string& name,
// Make sure disk path exists, warn otherwise.
if (access(disk_path.c_str(), F_OK) < 0) {
- std::cerr << disk_path << ": warning: directory does not exist."
- << std::endl;
+ // Try the original path; it may have just happed to have a '=' in it.
+ if (access(parts[i].c_str(), F_OK) < 0) {
+ cerr << disk_path << ": warning: directory does not exist." << endl;
+ } else {
+ virtual_path = "";
+ disk_path = parts[i];
+ }
}
// Don't use make_pair as the old/default standard library on Solaris
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index ae2900b1..0ebf9b6a 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -65,13 +65,14 @@
#include <gtest/gtest.h>
-// Disable the whole test when we use tcmalloc for "draconian" heap checks, in
-// which case tcmalloc will print warnings that fail the plugin tests.
-#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
namespace google {
namespace protobuf {
namespace compiler {
+// Disable the whole test when we use tcmalloc for "draconian" heap checks, in
+// which case tcmalloc will print warnings that fail the plugin tests.
+#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+
#if defined(_WIN32)
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
@@ -785,6 +786,21 @@ TEST_F(CommandLineInterfaceTest, NonRootMapping) {
ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo");
}
+TEST_F(CommandLineInterfaceTest, PathWithEqualsSign) {
+ // Test setting up a search path which happens to have '=' in it.
+
+ CreateTempDir("with=sign");
+ CreateTempFile("with=sign/foo.proto",
+ "syntax = \"proto2\";\n"
+ "message Foo {}\n");
+
+ Run("protocol_compiler --test_out=$tmpdir "
+ "--proto_path=$tmpdir/with=sign foo.proto");
+
+ ExpectNoErrors();
+ ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
TEST_F(CommandLineInterfaceTest, MultipleGenerators) {
// Test that we can have multiple generators and use both in one invocation,
// each with a different output directory.
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index c81c5982..62b7ed4e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -189,7 +189,7 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
for (int j = 0; j < descriptor_->value_count(); j++) {
vars["tag"] = EnumValueName(descriptor_->value(j));
vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ?
- "PROTOBUF_DEPRECATED_ATTR " : "";
+ "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : "";
printer->Print(vars,
"$deprecated_attr$static $constexpr$const $nested_name$ $tag$ =\n"
" $classname$_$tag$;\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index b3ba3a2e..e2033c1a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -78,7 +78,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
(*variables)["deprecation"] = descriptor->options().deprecated()
? " PROTOBUF_DEPRECATED" : "";
(*variables)["deprecated_attr"] = descriptor->options().deprecated()
- ? "PROTOBUF_DEPRECATED_ATTR " : "";
+ ? "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : "";
(*variables)["cppget"] = "Get";
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc
index 226c2aa0..6030f7ce 100644
--- a/src/google/protobuf/compiler/cpp/cpp_service.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_service.cc
@@ -298,13 +298,15 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
" return $type$::default_instance();\n");
}
- printer->Print(vars_,
+ printer->Print(
" default:\n"
" GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
- " return *static_cast< ::google::protobuf::Message*>(NULL);\n"
+ " return *::google::protobuf::MessageFactory::generated_factory()\n"
+ " ->GetPrototype(method->$input_or_output$_type());\n"
" }\n"
"}\n"
- "\n");
+ "\n",
+ "input_or_output", which == REQUEST ? "input" : "output");
}
void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 3de61e80..8fb24bed 100755
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -28,7 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "google/protobuf/compiler/js/js_generator.h"
+#include <google/protobuf/compiler/js/js_generator.h>
#include <assert.h>
#include <algorithm>
@@ -159,8 +159,16 @@ string GetJSFilename(const string& filename) {
// Given a filename like foo/bar/baz.proto, returns the root directory
// path ../../
-string GetRootPath(const string& filename) {
- size_t slashes = std::count(filename.begin(), filename.end(), '/');
+string GetRootPath(const string& from_filename, const string& to_filename) {
+ if (to_filename.find("google/protobuf") == 0) {
+ // Well-known types (.proto files in the google/protobuf directory) are
+ // assumed to come from the 'google-protobuf' npm package. We may want to
+ // generalize this exception later by letting others put generated code in
+ // their own npm packages.
+ return "google-protobuf/";
+ }
+
+ size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/');
if (slashes == 0) {
return "./";
}
@@ -489,6 +497,7 @@ string JSByteGetterSuffix(BytesMode bytes_mode) {
default:
assert(false);
}
+ return "";
}
// Returns the field name as a capitalized portion of a getter/setter method
@@ -2837,7 +2846,7 @@ void Generator::GenerateFile(const GeneratorOptions& options,
printer->Print(
"var $alias$ = require('$file$');\n",
"alias", ModuleAlias(name),
- "file", GetRootPath(file->name()) + GetJSFilename(name));
+ "file", GetRootPath(file->name(), name) + GetJSFilename(name));
}
}
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
index ed4fc6a3..cf8c34e1 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -37,8 +37,12 @@
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/strutil.h>
+#include <iostream>
#include <sstream>
+// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+// error cases, so it seems to be ok to use as a back door for errors.
+
namespace google {
namespace protobuf {
@@ -50,6 +54,205 @@ const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001;
namespace compiler {
namespace objectivec {
+namespace {
+
+class ImportWriter {
+ public:
+ ImportWriter(const Options& options)
+ : options_(options),
+ need_to_parse_mapping_file_(true) {}
+
+ void AddFile(const FileGenerator* file);
+ void Print(io::Printer *printer) const;
+
+ private:
+ class ProtoFrameworkCollector : public LineConsumer {
+ public:
+ ProtoFrameworkCollector(map<string, string>* inout_proto_file_to_framework_name)
+ : map_(inout_proto_file_to_framework_name) {}
+
+ virtual bool ConsumeLine(const StringPiece& line, string* out_error);
+
+ private:
+ map<string, string>* map_;
+ };
+
+ void ParseFrameworkMappings();
+
+ const Options options_;
+ map<string, string> proto_file_to_framework_name_;
+ bool need_to_parse_mapping_file_;
+
+ vector<string> protobuf_framework_imports_;
+ vector<string> protobuf_non_framework_imports_;
+ vector<string> other_framework_imports_;
+ vector<string> other_imports_;
+};
+
+void ImportWriter::AddFile(const FileGenerator* file) {
+ const FileDescriptor* file_descriptor = file->Descriptor();
+ const string extension(".pbobjc.h");
+
+ if (IsProtobufLibraryBundledProtoFile(file_descriptor)) {
+ protobuf_framework_imports_.push_back(
+ FilePathBasename(file_descriptor) + extension);
+ protobuf_non_framework_imports_.push_back(file->Path() + extension);
+ return;
+ }
+
+ // Lazy parse any mappings.
+ if (need_to_parse_mapping_file_) {
+ ParseFrameworkMappings();
+ }
+
+ map<string, string>::iterator proto_lookup =
+ proto_file_to_framework_name_.find(file_descriptor->name());
+ if (proto_lookup != proto_file_to_framework_name_.end()) {
+ other_framework_imports_.push_back(
+ proto_lookup->second + "/" +
+ FilePathBasename(file_descriptor) + extension);
+ return;
+ }
+
+ if (!options_.generate_for_named_framework.empty()) {
+ other_framework_imports_.push_back(
+ options_.generate_for_named_framework + "/" +
+ FilePathBasename(file_descriptor) + extension);
+ return;
+ }
+
+ other_imports_.push_back(file->Path() + extension);
+}
+
+void ImportWriter::Print(io::Printer* printer) const {
+ assert(protobuf_non_framework_imports_.size() ==
+ protobuf_framework_imports_.size());
+
+ bool add_blank_line = false;
+
+ if (protobuf_framework_imports_.size() > 0) {
+ const string framework_name(ProtobufLibraryFrameworkName);
+ const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
+
+ printer->Print(
+ "#if $cpp_symbol$\n",
+ "cpp_symbol", cpp_symbol);
+ for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin();
+ iter != protobuf_framework_imports_.end(); ++iter) {
+ printer->Print(
+ " #import <$framework_name$/$header$>\n",
+ "framework_name", framework_name,
+ "header", *iter);
+ }
+ printer->Print(
+ "#else\n");
+ for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin();
+ iter != protobuf_non_framework_imports_.end(); ++iter) {
+ printer->Print(
+ " #import \"$header$\"\n",
+ "header", *iter);
+ }
+ printer->Print(
+ "#endif\n");
+
+ add_blank_line = true;
+ }
+
+ if (other_framework_imports_.size() > 0) {
+ if (add_blank_line) {
+ printer->Print("\n");
+ }
+
+ for (vector<string>::const_iterator iter = other_framework_imports_.begin();
+ iter != other_framework_imports_.end(); ++iter) {
+ printer->Print(
+ " #import <$header$>\n",
+ "header", *iter);
+ }
+
+ add_blank_line = true;
+ }
+
+ if (other_imports_.size() > 0) {
+ if (add_blank_line) {
+ printer->Print("\n");
+ }
+
+ for (vector<string>::const_iterator iter = other_imports_.begin();
+ iter != other_imports_.end(); ++iter) {
+ printer->Print(
+ " #import \"$header$\"\n",
+ "header", *iter);
+ }
+ }
+}
+
+void ImportWriter::ParseFrameworkMappings() {
+ need_to_parse_mapping_file_ = false;
+ if (options_.named_framework_to_proto_path_mappings_path.empty()) {
+ return; // Nothing to do.
+ }
+
+ ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
+ string parse_error;
+ if (!ParseSimpleFile(options_.named_framework_to_proto_path_mappings_path,
+ &collector, &parse_error)) {
+ cerr << "error parsing " << options_.named_framework_to_proto_path_mappings_path
+ << " : " << parse_error << endl;
+ cerr.flush();
+ }
+}
+
+bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
+ const StringPiece& line, string* out_error) {
+ int offset = line.find(':');
+ if (offset == StringPiece::npos) {
+ *out_error =
+ string("Framework/proto file mapping line without colon sign: '") +
+ line.ToString() + "'.";
+ return false;
+ }
+ StringPiece framework_name(line, 0, offset);
+ StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1);
+ StringPieceTrimWhitespace(&framework_name);
+
+ int start = 0;
+ while (start < proto_file_list.length()) {
+ offset = proto_file_list.find(',', start);
+ if (offset == StringPiece::npos) {
+ offset = proto_file_list.length();
+ }
+
+ StringPiece proto_file(proto_file_list, start, offset);
+ StringPieceTrimWhitespace(&proto_file);
+ if (proto_file.size() != 0) {
+ map<string, string>::iterator existing_entry =
+ map_->find(proto_file.ToString());
+ if (existing_entry != map_->end()) {
+ cerr << "warning: duplicate proto file reference, replacing framework entry for '"
+ << proto_file.ToString() << "' with '" << framework_name.ToString()
+ << "' (was '" << existing_entry->second << "')." << endl;
+ cerr.flush();
+ }
+
+ if (proto_file.find(' ') != StringPiece::npos) {
+ cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '"
+ << proto_file.ToString() << "'" << endl;
+ cerr.flush();
+ }
+
+ (*map_)[proto_file.ToString()] = framework_name.ToString();
+ }
+
+ start = offset + 1;
+ }
+
+ return true;
+}
+
+} // namespace
+
+
FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
: file_(file),
root_class_name_(FileClassName(file)),
@@ -82,15 +285,7 @@ FileGenerator::~FileGenerator() {
}
void FileGenerator::GenerateHeader(io::Printer *printer) {
- printer->Print(
- "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
- "// source: $filename$\n"
- "\n",
- "filename", file_->name());
-
- printer->Print(
- "#import \"GPBProtocolBuffers.h\"\n"
- "\n");
+ PrintFileRuntimePreamble(printer, "GPBProtocolBuffers.h");
// Add some verification that the generated code matches the source the
// code is being compiled with.
@@ -102,16 +297,24 @@ void FileGenerator::GenerateHeader(io::Printer *printer) {
"protoc_gen_objc_version",
SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION));
- const vector<FileGenerator *> &dependency_generators = DependencyGenerators();
- for (vector<FileGenerator *>::const_iterator iter =
- dependency_generators.begin();
- iter != dependency_generators.end(); ++iter) {
- if ((*iter)->IsPublicDependency()) {
- printer->Print("#import \"$header$.pbobjc.h\"\n",
- "header", (*iter)->Path());
+ // #import any headers for "public imports" in the proto file.
+ {
+ ImportWriter import_writer(options_);
+ const vector<FileGenerator *> &dependency_generators = DependencyGenerators();
+ for (vector<FileGenerator *>::const_iterator iter =
+ dependency_generators.begin();
+ iter != dependency_generators.end(); ++iter) {
+ if ((*iter)->IsPublicDependency()) {
+ import_writer.AddFile(*iter);
+ }
}
+ import_writer.Print(printer);
}
+ // Note:
+ // deprecated-declarations suppression is only needed if some place in this
+ // proto file is something deprecated or if it references something from
+ // another file that is deprecated.
printer->Print(
"// @@protoc_insertion_point(imports)\n"
"\n"
@@ -198,35 +401,58 @@ void FileGenerator::GenerateHeader(io::Printer *printer) {
}
void FileGenerator::GenerateSource(io::Printer *printer) {
- printer->Print(
- "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
- "// source: $filename$\n"
- "\n",
- "filename", file_->name());
+ // #import the runtime support.
+ PrintFileRuntimePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h");
- string header_file = Path() + ".pbobjc.h";
- printer->Print(
- "#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n"
- "#import \"$header_file$\"\n",
- "header_file", header_file);
- const vector<FileGenerator *> &dependency_generators =
- DependencyGenerators();
- for (vector<FileGenerator *>::const_iterator iter =
- dependency_generators.begin();
- iter != dependency_generators.end(); ++iter) {
- if (!(*iter)->IsPublicDependency()) {
- printer->Print("#import \"$header$.pbobjc.h\"\n",
- "header", (*iter)->Path());
+ {
+ ImportWriter import_writer(options_);
+
+ // #import the header for this proto file.
+ import_writer.AddFile(this);
+
+ // #import the headers for anything that a plain dependency of this proto
+ // file (that means they were just an include, not a "public" include).
+ const vector<FileGenerator *> &dependency_generators =
+ DependencyGenerators();
+ for (vector<FileGenerator *>::const_iterator iter =
+ dependency_generators.begin();
+ iter != dependency_generators.end(); ++iter) {
+ if (!(*iter)->IsPublicDependency()) {
+ import_writer.AddFile(*iter);
+ }
+ }
+
+ import_writer.Print(printer);
+ }
+
+ bool includes_oneof = false;
+ for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+ iter != message_generators_.end(); ++iter) {
+ if ((*iter)->IncludesOneOfDefinition()) {
+ includes_oneof = true;
+ break;
}
}
+
+ // Note:
+ // deprecated-declarations suppression is only needed if some place in this
+ // proto file is something deprecated or if it references something from
+ // another file that is deprecated.
printer->Print(
"// @@protoc_insertion_point(imports)\n"
"\n"
"#pragma clang diagnostic push\n"
- "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"
- "\n");
+ "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n");
+ if (includes_oneof) {
+ // The generated code for oneof's uses direct ivar access, suppress the
+ // warning incase developer turn that on in the context they compile the
+ // generated code.
+ printer->Print(
+ "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n");
+ }
printer->Print(
+ "\n"
"#pragma mark - $root_class_name$\n"
"\n"
"@implementation $root_class_name$\n\n",
@@ -356,8 +582,6 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
"// @@protoc_insertion_point(global_scope)\n");
}
-const string FileGenerator::Path() const { return FilePath(file_); }
-
const vector<FileGenerator *> &FileGenerator::DependencyGenerators() {
if (file_->dependency_count() != dependency_generators_.size()) {
set<string> public_import_names;
@@ -376,6 +600,37 @@ const vector<FileGenerator *> &FileGenerator::DependencyGenerators() {
return dependency_generators_;
}
+// Helper to print the import of the runtime support at the top of generated
+// files. This currently only supports the runtime coming from a framework
+// as defined by the official CocoaPod.
+void FileGenerator::PrintFileRuntimePreamble(
+ io::Printer* printer, const string& header_to_import) const {
+ printer->Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
+ "\n",
+ "filename", file_->name());
+
+ const string framework_name(ProtobufLibraryFrameworkName);
+ const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
+ printer->Print(
+ "// This CPP symbol can be defined to use imports that match up to the framework\n"
+ "// imports needed when using CocoaPods.\n"
+ "#if !defined($cpp_symbol$)\n"
+ " #define $cpp_symbol$ 0\n"
+ "#endif\n"
+ "\n"
+ "#if $cpp_symbol$\n"
+ " #import <$framework_name$/$header$>\n"
+ "#else\n"
+ " #import \"$header$\"\n"
+ "#endif\n"
+ "\n",
+ "cpp_symbol", cpp_symbol,
+ "header", header_to_import,
+ "framework_name", framework_name);
+}
+
} // namespace objectivec
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h
index 4c0fcd3f..8e4388d8 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h
@@ -62,7 +62,8 @@ class FileGenerator {
void GenerateHeader(io::Printer* printer);
const string& RootClassName() const { return root_class_name_; }
- const string Path() const;
+ const string Path() const { return FilePath(file_); }
+ const FileDescriptor* Descriptor() const { return file_; }
bool IsPublicDependency() const { return is_public_dep_; }
@@ -87,6 +88,8 @@ class FileGenerator {
const Options options_;
const vector<FileGenerator*>& DependencyGenerators();
+ void PrintFileRuntimePreamble(
+ io::Printer* printer, const string& header_to_import) const;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
};
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
index 72e295de..29a8765c 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -58,7 +58,48 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file,
ParseGeneratorParameter(parameter, &options);
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "expected_prefixes_path") {
+ // Path to find a file containing the expected prefixes
+ // (objc_class_prefix "PREFIX") for proto packages (package NAME). The
+ // generator will then issue warnings/errors if in the proto files being
+ // generated the option is not listed/wrong/etc in the file.
+ //
+ // The format of the file is:
+ // - An entry is a line of "package=prefix".
+ // - Comments start with "#".
+ // - A comment can go on a line after a expected package/prefix pair.
+ // (i.e. - "package=prefix # comment")
+ //
+ // There is no validation that the prefixes are good prefixes, it is
+ // assume they are when you create the file.
generation_options.expected_prefixes_path = options[i].second;
+ } else if (options[i].first == "generate_for_named_framework") {
+ // The name of the framework that protos are being generated for. This
+ // will cause the #import statements to be framework based using this
+ // name (i.e. - "#import <NAME/proto.pbobjc.h>).
+ //
+ // NOTE: If this option is used with
+ // named_framework_to_proto_path_mappings_path, then this is effectively
+ // the "default" to use for everything that wasn't mapped by the other.
+ generation_options.named_framework_to_proto_path_mappings_path = options[i].second;
+ } else if (options[i].first == "named_framework_to_proto_path_mappings_path") {
+ // Path to find a file containing the listing of framework names and
+ // proto files. The generator uses this to decide if another proto file
+ // referenced should use a framework style import vs. a user level import
+ // (#import <FRAMEWORK/file.pbobjc.h> vs #import "dir/file.pbobjc.h").
+ //
+ // The format of the file is:
+ // - An entry is a line of "frameworkName: file.proto, dir/file2.proto".
+ // - Comments start with "#".
+ // - A comment can go on a line after a expected package/prefix pair.
+ // (i.e. - "frameworkName: file.proto # comment")
+ //
+ // Any number of files can be listed for a framework, just separate them
+ // with commas.
+ //
+ // There can be multiple lines listing the same frameworkName incase it
+ // has a lot of proto files included in it; and having multiple lines
+ // makes things easier to read.
+ generation_options.named_framework_to_proto_path_mappings_path = options[i].second;
} else {
*error = "error: Unknown generator option: " + options[i].first;
return false;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index 196b39dd..311bf35d 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -81,6 +81,10 @@ const char* const kUpperSegmentsList[] = {"url", "http", "https"};
hash_set<string> kUpperSegments =
MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList));
+bool ascii_isnewline(char c) {
+ return c == '\n' || c == '\r';
+}
+
// Internal helper for name handing.
// Do not expose this outside of helpers, stick to having functions for specific
// cases (ClassName(), FieldName()), so there is always consistent suffix rules.
@@ -272,6 +276,16 @@ string StripProto(const string& filename) {
}
}
+void StringPieceTrimWhitespace(StringPiece* input) {
+ while (!input->empty() && ascii_isspace(*input->data())) {
+ input->remove_prefix(1);
+ }
+ while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) {
+ input->remove_suffix(1);
+ }
+}
+
+
bool IsRetainedName(const string& name) {
// List of prefixes from
// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
@@ -293,13 +307,6 @@ string BaseFileName(const FileDescriptor* file) {
return basename;
}
-string FileName(const FileDescriptor* file) {
- string path = FilePath(file);
- string basename;
- PathSplit(path, NULL, &basename);
- return basename;
-}
-
string FilePath(const FileDescriptor* file) {
string output;
string basename;
@@ -317,6 +324,19 @@ string FilePath(const FileDescriptor* file) {
return output;
}
+string FilePathBasename(const FileDescriptor* file) {
+ string output;
+ string basename;
+ string directory;
+ PathSplit(file->name(), &directory, &basename);
+ basename = StripProto(basename);
+
+ // CamelCase to be more ObjC friendly.
+ output = UnderscoresToCamelCase(basename, true);
+
+ return output;
+}
+
string FileClassPrefix(const FileDescriptor* file) {
// Default is empty string, no need to check has_objc_class_prefix.
string result = file->options().objc_class_prefix();
@@ -831,65 +851,40 @@ string BuildCommentsString(const SourceLocation& location) {
return final_comments;
}
-namespace {
-
-// Internal helper class that parses the expected package to prefix mappings
-// file.
-class Parser {
- public:
- Parser(map<string, string>* inout_package_to_prefix_map)
- : prefix_map_(inout_package_to_prefix_map), line_(0) {}
-
- // Parses a check of input, returning success/failure.
- bool ParseChunk(StringPiece chunk);
-
- // Should be called to finish parsing (after all input has been provided via
- // ParseChunk()). Returns success/failure.
- bool Finish();
-
- int last_line() const { return line_; }
- string error_str() const { return error_str_; }
-
- private:
- bool ParseLoop();
-
- map<string, string>* prefix_map_;
- int line_;
- string error_str_;
- StringPiece p_;
- string leftover_;
-};
-
-bool Parser::ParseChunk(StringPiece chunk) {
- if (!leftover_.empty()) {
- chunk.AppendToString(&leftover_);
- p_ = StringPiece(leftover_);
- } else {
- p_ = chunk;
- }
- bool result = ParseLoop();
- if (p_.empty()) {
- leftover_.clear();
- } else {
- leftover_ = p_.ToString();
- }
+// Making these a generator option for folks that don't use CocoaPods, but do
+// want to put the library in a framework is an interesting question. The
+// problem is it means changing sources shipped with the library to actually
+// use a different value; so it isn't as simple as a option.
+const char* const ProtobufLibraryFrameworkName = "Protobuf";
+
+string ProtobufFrameworkImportSymbol(const string& framework_name) {
+ // GPB_USE_[framework_name]_FRAMEWORK_IMPORTS
+ string result = string("GPB_USE_");
+ result += ToUpper(framework_name);
+ result += "_FRAMEWORK_IMPORTS";
return result;
}
-bool Parser::Finish() {
- if (leftover_.empty()) {
+bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) {
+ // We don't check the name prefix or proto package because some files
+ // (descriptor.proto), aren't shipped generated by the library, so this
+ // seems to be the safest way to only catch the ones shipped.
+ const string name = file->name();
+ if (name == "google/protobuf/any.proto" ||
+ name == "google/protobuf/api.proto" ||
+ name == "google/protobuf/duration.proto" ||
+ name == "google/protobuf/empty.proto" ||
+ name == "google/protobuf/field_mask.proto" ||
+ name == "google/protobuf/source_context.proto" ||
+ name == "google/protobuf/struct.proto" ||
+ name == "google/protobuf/timestamp.proto" ||
+ name == "google/protobuf/type.proto" ||
+ name == "google/protobuf/wrappers.proto") {
return true;
}
- // Force a newline onto the end to finish parsing.
- p_ = StringPiece(leftover_ + "\n");
- if (!ParseLoop()) {
- return false;
- }
- return p_.empty(); // Everything used?
+ return false;
}
-static bool ascii_isnewline(char c) { return c == '\n' || c == '\r'; }
-
bool ReadLine(StringPiece* input, StringPiece* line) {
for (int len = 0; len < input->size(); ++len) {
if (ascii_isnewline((*input)[len])) {
@@ -902,15 +897,6 @@ bool ReadLine(StringPiece* input, StringPiece* line) {
return false; // Ran out of input with no newline.
}
-void TrimWhitespace(StringPiece* input) {
- while (!input->empty() && ascii_isspace(*input->data())) {
- input->remove_prefix(1);
- }
- while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) {
- input->remove_suffix(1);
- }
-}
-
void RemoveComment(StringPiece* input) {
int offset = input->find('#');
if (offset != StringPiece::npos) {
@@ -918,29 +904,35 @@ void RemoveComment(StringPiece* input) {
}
}
-bool Parser::ParseLoop() {
- StringPiece line;
- while (ReadLine(&p_, &line)) {
- ++line_;
- RemoveComment(&line);
- TrimWhitespace(&line);
- if (line.size() == 0) {
- continue; // Blank line.
- }
- int offset = line.find('=');
- if (offset == StringPiece::npos) {
- error_str_ =
- string("Line without equal sign: '") + line.ToString() + "'.";
- return false;
- }
- StringPiece package(line, 0, offset);
- StringPiece prefix(line, offset + 1, line.length() - offset - 1);
- TrimWhitespace(&package);
- TrimWhitespace(&prefix);
- // Don't really worry about error checking the package/prefix for
- // being valid. Assume the file is validated when it is created/edited.
- (*prefix_map_)[package.ToString()] = prefix.ToString();
+namespace {
+
+class ExpectedPrefixesCollector : public LineConsumer {
+ public:
+ ExpectedPrefixesCollector(map<string, string>* inout_package_to_prefix_map)
+ : prefix_map_(inout_package_to_prefix_map) {}
+
+ virtual bool ConsumeLine(const StringPiece& line, string* out_error);
+
+ private:
+ map<string, string>* prefix_map_;
+};
+
+bool ExpectedPrefixesCollector::ConsumeLine(
+ const StringPiece& line, string* out_error) {
+ int offset = line.find('=');
+ if (offset == StringPiece::npos) {
+ *out_error =
+ string("Expected prefixes file line without equal sign: '") +
+ line.ToString() + "'.";
+ return false;
}
+ StringPiece package(line, 0, offset);
+ StringPiece prefix(line, offset + 1, line.length() - offset - 1);
+ StringPieceTrimWhitespace(&package);
+ StringPieceTrimWhitespace(&prefix);
+ // Don't really worry about error checking the package/prefix for
+ // being valid. Assume the file is validated when it is created/edited.
+ (*prefix_map_)[package.ToString()] = prefix.ToString();
return true;
}
@@ -951,36 +943,9 @@ bool LoadExpectedPackagePrefixes(const Options &generation_options,
return true;
}
- int fd;
- do {
- fd = open(generation_options.expected_prefixes_path.c_str(), O_RDONLY);
- } while (fd < 0 && errno == EINTR);
- if (fd < 0) {
- *out_error =
- string("error: Unable to open \"") +
- generation_options.expected_prefixes_path +
- "\", " + strerror(errno);
- return false;
- }
- io::FileInputStream file_stream(fd);
- file_stream.SetCloseOnDelete(true);
-
- Parser parser(prefix_map);
- const void* buf;
- int buf_len;
- while (file_stream.Next(&buf, &buf_len)) {
- if (buf_len == 0) {
- continue;
- }
-
- if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) {
- *out_error =
- string("error: ") + generation_options.expected_prefixes_path +
- " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str();
- return false;
- }
- }
- return parser.Finish();
+ ExpectedPrefixesCollector collector(prefix_map);
+ return ParseSimpleFile(
+ generation_options.expected_prefixes_path, &collector, out_error);
}
} // namespace
@@ -1081,6 +1046,10 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file,
return true;
}
+TextFormatDecodeData::TextFormatDecodeData() { }
+
+TextFormatDecodeData::~TextFormatDecodeData() { }
+
void TextFormatDecodeData::AddString(int32 key,
const string& input_for_decode,
const string& desired_output) {
@@ -1289,6 +1258,116 @@ string TextFormatDecodeData::DecodeDataForString(const string& input_for_decode,
return builder.Finish() + (char)'\0';
}
+namespace {
+
+class Parser {
+ public:
+ Parser(LineConsumer* line_consumer)
+ : line_consumer_(line_consumer), line_(0) {}
+
+ // Parses a check of input, returning success/failure.
+ bool ParseChunk(StringPiece chunk);
+
+ // Should be called to finish parsing (after all input has been provided via
+ // ParseChunk()). Returns success/failure.
+ bool Finish();
+
+ int last_line() const { return line_; }
+ string error_str() const { return error_str_; }
+
+ private:
+ bool ParseLoop();
+
+ LineConsumer* line_consumer_;
+ int line_;
+ string error_str_;
+ StringPiece p_;
+ string leftover_;
+};
+
+bool Parser::ParseChunk(StringPiece chunk) {
+ if (!leftover_.empty()) {
+ chunk.AppendToString(&leftover_);
+ p_ = StringPiece(leftover_);
+ } else {
+ p_ = chunk;
+ }
+ bool result = ParseLoop();
+ if (p_.empty()) {
+ leftover_.clear();
+ } else {
+ leftover_ = p_.ToString();
+ }
+ return result;
+}
+
+bool Parser::Finish() {
+ if (leftover_.empty()) {
+ return true;
+ }
+ // Force a newline onto the end to finish parsing.
+ p_ = StringPiece(leftover_ + "\n");
+ if (!ParseLoop()) {
+ return false;
+ }
+ return p_.empty(); // Everything used?
+}
+
+bool Parser::ParseLoop() {
+ StringPiece line;
+ while (ReadLine(&p_, &line)) {
+ ++line_;
+ RemoveComment(&line);
+ StringPieceTrimWhitespace(&line);
+ if (line.size() == 0) {
+ continue; // Blank line.
+ }
+ if (!line_consumer_->ConsumeLine(line, &error_str_)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+LineConsumer::LineConsumer() {}
+
+LineConsumer::~LineConsumer() {}
+
+bool ParseSimpleFile(
+ const string& path, LineConsumer* line_consumer, string* out_error) {
+ int fd;
+ do {
+ fd = open(path.c_str(), O_RDONLY);
+ } while (fd < 0 && errno == EINTR);
+ if (fd < 0) {
+ *out_error =
+ string("error: Unable to open \"") + path + "\", " + strerror(errno);
+ return false;
+ }
+ io::FileInputStream file_stream(fd);
+ file_stream.SetCloseOnDelete(true);
+
+ Parser parser(line_consumer);
+ const void* buf;
+ int buf_len;
+ while (file_stream.Next(&buf, &buf_len)) {
+ if (buf_len == 0) {
+ continue;
+ }
+
+ if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) {
+ *out_error =
+ string("error: ") + path +
+ " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str();
+ return false;
+ }
+ }
+ return parser.Finish();
+}
+
+
} // namespace objectivec
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
index 3f56d94b..be20beee 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -46,6 +46,8 @@ namespace objectivec {
struct Options {
Options();
string expected_prefixes_path;
+ string generate_for_named_framework;
+ string named_framework_to_proto_path_mappings_path;
};
// Escape C++ trigraphs by escaping question marks to "\?".
@@ -54,6 +56,9 @@ string EscapeTrigraphs(const string& to_escape);
// Strips ".proto" or ".protodevel" from the end of a filename.
string StripProto(const string& filename);
+// Remove white space from either end of a StringPiece.
+void StringPieceTrimWhitespace(StringPiece* input);
+
// Returns true if the name requires a ns_returns_not_retained attribute applied
// to it.
bool IsRetainedName(const string& name);
@@ -62,15 +67,14 @@ bool IsRetainedName(const string& name);
// handling under ARC.
bool IsInitName(const string& name);
-// Gets the name of the file we're going to generate (sans the .pb.h
-// extension). This does not include the path to that file.
-string FileName(const FileDescriptor* file);
-
// Gets the path of the file we're going to generate (sans the .pb.h
// extension). The path will be dependent on the objectivec package
// declared in the proto package.
string FilePath(const FileDescriptor* file);
+// Just like FilePath(), but without the directory part.
+string FilePathBasename(const FileDescriptor* file);
+
// Gets the name of the root class we'll generate in the file. This class
// is not meant for external consumption, but instead contains helpers that
// the rest of the classes need
@@ -169,6 +173,16 @@ string BuildFlagsString(const vector<string>& strings);
// Builds a HeaderDoc style comment out of the comments in the .proto file.
string BuildCommentsString(const SourceLocation& location);
+// The name the commonly used by the library when built as a framework.
+// This lines up to the name used in the CocoaPod.
+extern const char* const ProtobufLibraryFrameworkName;
+// Returns the CPP symbol name to use as the gate for framework style imports
+// for the given framework name to use.
+string ProtobufFrameworkImportSymbol(const string& framework_name);
+
+// Checks if the file is one of the proto's bundled with the library.
+bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file);
+
// Checks the prefix for a given file and outputs any warnings needed, if
// there are flat out errors, then out_error is filled in and the result is
// false.
@@ -180,7 +194,8 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file,
// the input into the expected output.
class LIBPROTOC_EXPORT TextFormatDecodeData {
public:
- TextFormatDecodeData() {}
+ TextFormatDecodeData();
+ ~TextFormatDecodeData();
void AddString(int32 key, const string& input_for_decode,
const string& desired_output);
@@ -197,6 +212,17 @@ class LIBPROTOC_EXPORT TextFormatDecodeData {
vector<DataEntry> entries_;
};
+// Helper for parsing simple files.
+class LIBPROTOC_EXPORT LineConsumer {
+ public:
+ LineConsumer();
+ virtual ~LineConsumer();
+ virtual bool ConsumeLine(const StringPiece& line, string* out_error) = 0;
+};
+
+bool ParseSimpleFile(
+ const string& path, LineConsumer* line_consumer, string* out_error);
+
} // namespace objectivec
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
index bf272596..e1a78619 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -246,6 +246,22 @@ void MessageGenerator::DetermineForwardDeclarations(set<string>* fwd_decls) {
}
}
+bool MessageGenerator::IncludesOneOfDefinition() const {
+ if (!oneof_generators_.empty()) {
+ return true;
+ }
+
+ for (vector<MessageGenerator*>::const_iterator iter =
+ nested_message_generators_.begin();
+ iter != nested_message_generators_.end(); ++iter) {
+ if ((*iter)->IncludesOneOfDefinition()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void MessageGenerator::GenerateEnumHeader(io::Printer* printer) {
for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
iter != enum_generators_.end(); ++iter) {
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h
index 8565e76f..910535ac 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h
@@ -66,6 +66,9 @@ class MessageGenerator {
void GenerateExtensionRegistrationSource(io::Printer* printer);
void DetermineForwardDeclarations(set<string>* fwd_decls);
+ // Checks if the message or a nested message includes a oneof definition.
+ bool IncludesOneOfDefinition() const;
+
private:
void GenerateParseFromMethodsHeader(io::Printer* printer);
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 4475556a..56f5afd2 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -63,7 +63,7 @@ namespace internal {
#undef DEPRECATED_PROTOBUF_FIELD
#define PROTOBUF_DEPRECATED
-#define PROTOBUF_DEPRECATED_ATTR
+#define GOOGLE_PROTOBUF_DEPRECATED_ATTR
// Constants for special floating point values.
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index bb0b14f9..31593c1a 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -504,9 +504,7 @@ class MapPair {
// assert(m0.begin()->first == m1.begin()->first); // Bug!
//
// Map's interface is similar to std::unordered_map, except that Map is not
-// designed to play well with exceptions. Mutations to a Map do not invalidate
-// a Map's iterators, pointers to elements, or references to elements. Except
-// for erase(iterator), any non-const method can reorder iterators.
+// designed to play well with exceptions.
template <typename Key, typename T>
class Map {
public:
@@ -589,7 +587,7 @@ class Map {
explicit MapAllocator(Arena* arena) : arena_(arena) {}
template <typename X>
MapAllocator(const MapAllocator<X>& allocator)
- : arena_(allocator.arena_) {}
+ : arena_(allocator.arena()) {}
pointer allocate(size_type n, const_pointer hint = 0) {
// If arena is not given, malloc needs to be called which doesn't
@@ -652,12 +650,15 @@ class Map {
return std::numeric_limits<size_type>::max();
}
+ // To support gcc-4.4, which does not properly
+ // support templated friend classes
+ Arena* arena() const {
+ return arena_;
+ }
+
private:
typedef void DestructorSkippable_;
Arena* const arena_;
-
- template <typename X>
- friend class MapAllocator;
};
// InnerMap's key type is Key and its value type is value_type*. We use a
diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h
index bbd8ee65..4eac7d5d 100755..100644
--- a/src/google/protobuf/stubs/hash.h
+++ b/src/google/protobuf/stubs/hash.h
@@ -108,8 +108,13 @@
# define GOOGLE_PROTOBUF_HAS_CXX11_HASH
# define GOOGLE_PROTOBUF_HASH_COMPARE std::hash_compare
# elif _MSC_VER >= 1500 // Since Visual Studio 2008
-# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
-# undef GOOGLE_PROTOBUF_HAVE_HASH_SET
+# define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
+# include <hash_map>
+# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
+# include <hash_set>
+# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
+# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
+# define GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
# elif _MSC_VER >= 1310
# define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
# include <hash_map>
@@ -247,6 +252,52 @@ template <>
struct hash<const char*>
: public GOOGLE_PROTOBUF_HASH_COMPARE<const char*, CstringLess> {};
+#ifdef GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
+
+template <typename Key, typename HashFcn, typename EqualKey>
+struct InternalHashCompare : public GOOGLE_PROTOBUF_HASH_COMPARE<Key> {
+ InternalHashCompare() {}
+ InternalHashCompare(HashFcn hashfcn, EqualKey equalkey)
+ : hashfcn_(hashfcn), equalkey_(equalkey) {}
+ size_t operator()(const Key& key) const { return hashfcn_(key); }
+ bool operator()(const Key& key1, const Key& key2) const {
+ return !equalkey_(key1, key2);
+ }
+ HashFcn hashfcn_;
+ EqualKey equalkey_;
+};
+
+template <typename Key, typename Data,
+ typename HashFcn = hash<Key>,
+ typename EqualKey = std::equal_to<Key>,
+ typename Alloc = std::allocator< std::pair<const Key, Data> > >
+class hash_map
+ : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+ Key, Data, InternalHashCompare<Key, HashFcn, EqualKey>, Alloc> {
+ typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+ Key, Data, InternalHashCompare<Key, HashFcn, EqualKey>, Alloc> BaseClass;
+
+ public:
+ hash_map(int a = 0, const HashFcn& b = HashFcn(),
+ const EqualKey& c = EqualKey(), const Alloc& d = Alloc())
+ : BaseClass(InternalHashCompare<Key, HashFcn, EqualKey>(b, c), d) {}
+
+ HashFcn hash_function() const { return HashFcn(); }
+};
+
+template <typename Key, typename HashFcn = hash<Key>,
+ typename EqualKey = std::equal_to<Key> >
+class hash_set
+ : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
+ Key, InternalHashCompare<Key, HashFcn, EqualKey> > {
+ public:
+ hash_set(int = 0) {}
+
+ HashFcn hash_function() const { return HashFcn(); }
+};
+
+#else // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
+
template <typename Key, typename Data,
typename HashFcn = hash<Key>,
typename EqualKey = std::equal_to<Key>,
@@ -275,8 +326,9 @@ class hash_set
HashFcn hash_function() const { return HashFcn(); }
};
+#endif // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
-#else
+#else // defined(_MSC_VER) && !defined(_STLPORT_VERSION)
template <typename Key>
struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash<Key> {
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 58aa3f8d..410e5480 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -53,11 +53,11 @@
#include <google/protobuf/unittest_mset_wire_format.pb.h>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/mathlimits.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
-#include <google/protobuf/stubs/mathlimits.h>
namespace google {