Skip to content

Commit

Permalink
Add an RAII namespace printer helper for C++ codegen.
Browse files Browse the repository at this point in the history
This can be used to open and close namespace automatically within generated C++ code.

PiperOrigin-RevId: 618930720
  • Loading branch information
protobuf-github-bot authored and Copybara-Service committed Mar 25, 2024
1 parent 6f1ef6f commit 8599ab5
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/google/protobuf/compiler/cpp/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ cc_library(
"generator.cc",
"ifndef_guard.cc",
"message.cc",
"namespace_printer.cc",
"padding_optimizer.cc",
"parse_function_generator.cc",
"service.cc",
Expand All @@ -86,6 +87,7 @@ cc_library(
"ifndef_guard.h",
"message.h",
"message_layout_helper.h",
"namespace_printer.h",
"padding_optimizer.h",
"parse_function_generator.h",
"service.h",
Expand Down Expand Up @@ -359,6 +361,22 @@ cc_test(
],
)

cc_test(
name = "namespace_printer_unittest",
srcs = ["namespace_printer_unittest.cc"],
deps = [
":cpp",
"//:protobuf",
"//src/google/protobuf/io",
"//src/google/protobuf/io:printer",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/types:optional",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)

################################################################################
# Distribution packaging
################################################################################
Expand Down
37 changes: 37 additions & 0 deletions src/google/protobuf/compiler/cpp/namespace_printer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "google/protobuf/compiler/cpp/namespace_printer.h"

#include <string>
#include <utility>
#include <vector>

#include "absl/log/die_if_null.h"
#include "absl/strings/substitute.h"
#include "google/protobuf/io/printer.h"

namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {

NamespacePrinter::NamespacePrinter(
google::protobuf::io::Printer* const p, std::vector<std::string> namespace_components)
: p_(ABSL_DIE_IF_NULL(p)),
namespace_components_(std::move(namespace_components)) {
// Open the namespace.
for (const std::string& ns : namespace_components_) {
p_->Print(absl::Substitute("namespace $0 {\n", ns));
}
p_->Print("\n");
}

NamespacePrinter::~NamespacePrinter() {
// Close the namespace.
for (const std::string& ns : namespace_components_) {
p_->Print(absl::Substitute("} // namespace $0\n", ns));
}
}

} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
58 changes: 58 additions & 0 deletions src/google/protobuf/compiler/cpp/namespace_printer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

// An RAII type for printing a namespace.
//
// Example:
// {
// Printer printer(output_stream.get(), '$');
// const NamespacePrinter namespace_printer(&printer, {"a", "b", "c"});
// // namespace opening will be opened here
// ...
// // namespace closing will be emitted here
// }
//
// By default, the filename will be converted to a macro by substituting '/' and
// '.' characters with '_'. If a different transformation is required, an
// optional transformation function can be provided.

#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_NAMESPACE_PRINTER_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_NAMESPACE_PRINTER_H__

#include <string>
#include <vector>

#include "google/protobuf/io/printer.h"

// Must be included last.
#include "google/protobuf/port_def.inc"

namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {

// An RAII type for printing a namespace.
class PROTOC_EXPORT NamespacePrinter final {
public:
explicit NamespacePrinter(google::protobuf::io::Printer* p,
std::vector<std::string> namespace_components);
~NamespacePrinter();

private:
google::protobuf::io::Printer* const p_;
const std::vector<std::string> namespace_components_;
};

#include "google/protobuf/port_undef.inc"

} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

#endif // GOOGLE_PROTOBUF_COMPILER_CPP_NAMESPACE_PRINTER_H__
78 changes: 78 additions & 0 deletions src/google/protobuf/compiler/cpp/namespace_printer_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "google/protobuf/compiler/cpp/namespace_printer.h"

#include <string>

#include <gtest/gtest.h>
#include "absl/log/absl_check.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"

namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {

namespace {

class NamespacePrinterTest : public testing::Test {
protected:
io::ZeroCopyOutputStream* output() {
ABSL_CHECK(stream_.has_value());
return &*stream_;
}
absl::string_view written() {
stream_.reset();
return out_;
}

std::string out_;
absl::optional<io::StringOutputStream> stream_{&out_};
};

TEST_F(NamespacePrinterTest, Basic) {
{
io::Printer printer(output(), '$');

const NamespacePrinter namespace_printer(&printer, {"A", "B", "E"});

EXPECT_FALSE(printer.failed());
}

EXPECT_EQ(written(),
"namespace A {\n"
"namespace B {\n"
"namespace E {\n"
"\n"
"} // namespace A\n"
"} // namespace B\n"
"} // namespace E\n");
}

TEST_F(NamespacePrinterTest, DifferentDelim) {
{
io::Printer printer(output(), '\0');

const NamespacePrinter namespace_printer(&printer, {"A", "B", "E"});

EXPECT_FALSE(printer.failed());
}

EXPECT_EQ(written(),
"namespace A {\n"
"namespace B {\n"
"namespace E {\n"
"\n"
"} // namespace A\n"
"} // namespace B\n"
"} // namespace E\n");
}

} // namespace

} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

0 comments on commit 8599ab5

Please sign in to comment.