Speed-up GN with custom OutputStream interface. For legacy reasons, std::ostream is a very inefficient interface for appending text to an output stream, something that GN does a lot. This CL speeds GN by: - Introducing a new OutputStream abstract class to replace std::ostream entirely. It provides the same API subset needed by the rest of the code to minimize changes. See gn/output_stream.h. - Adding StringOutputStream, a concrete OutputStream to store the result into an std::stream. This replaces std::ostringstream. See gn/output_stream.h. - Adding FileOutputStream, a concrete OutputStream to store the result into a file. This replaces std::ofstream. See gn/output_stream.h. - Making StringOutputBuffer an OutputStream derived class as well, simplify its use as an output destination for many calls. - Adjusting all call sites appropriately. - Replace `out << std::endl` statements with `out << "\n"` as the type of `std::endl` is unspecified by the standard and hard to guess at compile time for implementing an OutputStream::operator<< overload. - Remove obsolete `#include <sstream>` statements from the sources. Same for `<fstream>`. Benchmarking shows that on Linux, this saves about 6% of `gn gen` time for a small Fuchsia build graph (6.27s -> 5.90s), and that the stripped LTO-optimized executable, is reduced by about 50 kiB. Change-Id: I00c7e1db67c59ab57c64756382683159df0662a6 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/18140 Reviewed-by: Dirk Pranke <dpranke@google.com> Commit-Queue: David Turner <digit@google.com>
diff --git a/build/gen.py b/build/gen.py index d1c649c..e13d194 100755 --- a/build/gen.py +++ b/build/gen.py
@@ -732,6 +732,7 @@ 'src/gn/operators.cc', 'src/gn/output_conversion.cc', 'src/gn/output_file.cc', + 'src/gn/output_stream.cc', 'src/gn/parse_node_value_adapter.cc', 'src/gn/parse_tree.cc', 'src/gn/parser.cc', @@ -857,6 +858,7 @@ 'src/gn/ninja_toolchain_writer_unittest.cc', 'src/gn/operators_unittest.cc', 'src/gn/output_conversion_unittest.cc', + 'src/gn/output_stream_unittest.cc', 'src/gn/parse_tree_unittest.cc', 'src/gn/parser_unittest.cc', 'src/gn/path_output_unittest.cc',
diff --git a/src/gn/command_desc.cc b/src/gn/command_desc.cc index b50d4e9..13a82db 100644 --- a/src/gn/command_desc.cc +++ b/src/gn/command_desc.cc
@@ -7,7 +7,6 @@ #include <algorithm> #include <memory> #include <set> -#include <sstream> #include "base/command_line.h" #include "base/json/json_writer.h"
diff --git a/src/gn/command_format.cc b/src/gn/command_format.cc index 1a6f9ec..75c3741 100644 --- a/src/gn/command_format.cc +++ b/src/gn/command_format.cc
@@ -6,8 +6,6 @@ #include <stddef.h> -#include <sstream> - #include "base/command_line.h" #include "base/files/file_util.h" #include "base/json/json_reader.h" @@ -17,6 +15,7 @@ #include "gn/commands.h" #include "gn/filesystem_utils.h" #include "gn/input_file.h" +#include "gn/output_stream.h" #include "gn/parser.h" #include "gn/scheduler.h" #include "gn/setup.h" @@ -1240,7 +1239,7 @@ std::string* output, std::string* dump_output) { if (dump_tree == TreeDumpMode::kPlainText) { - std::ostringstream os; + StringOutputStream os; RenderToText(root->GetJSONNode(), 0, os); *dump_output = os.str(); } else if (dump_tree == TreeDumpMode::kJSON) {
diff --git a/src/gn/compile_commands_writer.cc b/src/gn/compile_commands_writer.cc index 23d6029..5dd8270 100644 --- a/src/gn/compile_commands_writer.cc +++ b/src/gn/compile_commands_writer.cc
@@ -4,8 +4,6 @@ #include "gn/compile_commands_writer.h" -#include <sstream> - #include "base/json/string_escape.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" @@ -16,6 +14,7 @@ #include "gn/deps_iterator.h" #include "gn/escape.h" #include "gn/ninja_target_command_util.h" +#include "gn/output_stream.h" #include "gn/path_output.h" #include "gn/string_output_buffer.h" #include "gn/substitution_writer.h" @@ -62,7 +61,7 @@ const std::vector<T>& (ConfigValues::*getter)() const, const Writer& writer) { std::string result; - std::ostringstream out; + StringOutputStream out; RecursiveTargetConfigToStream<T>(config, target, getter, writer, out); base::EscapeJSONString(out.str(), false, &result); return result; @@ -102,7 +101,7 @@ const std::vector<std::string>& (ConfigValues::*getter)() const) -> std::string { std::string result; - std::ostringstream out; + StringOutputStream out; WriteOneFlag(config, target, substitution, has_precompiled_headers, tool_name, getter, opts, path_output, out, /*write_substitution=*/false, /*indent=*/false); @@ -133,13 +132,12 @@ void WriteFile(const SourceFile& source, PathOutput& path_output, - std::ostream& out) { - std::ostringstream rel_source_path; + OutputStream& out) { out << " \"file\": \""; path_output.WriteFile(out, source); } -void WriteDirectory(std::string build_dir, std::ostream& out) { +void WriteDirectory(std::string build_dir, OutputStream& out) { out << "\","; out << kPrettyPrintLineEnding; out << " \"directory\": \""; @@ -155,7 +153,7 @@ SourceFile::Type source_type, const char* tool_name, EscapeOptions opts, - std::ostream& out) { + OutputStream& out) { EscapeOptions no_quoting(opts); no_quoting.inhibit_quoting = true; const Tool* tool = target->toolchain()->GetTool(tool_name); @@ -223,7 +221,7 @@ void OutputJSON(const BuildSettings* build_settings, std::vector<const Target*>& all_targets, - std::ostream& out) { + OutputStream& out) { out << '['; out << kPrettyPrintLineEnding; bool first = true; @@ -291,9 +289,8 @@ std::string CompileCommandsWriter::RenderJSON( const BuildSettings* build_settings, std::vector<const Target*>& all_targets) { - StringOutputBuffer json; - std::ostream out(&json); - OutputJSON(build_settings, all_targets, out); + StringOutputStream json; + OutputJSON(build_settings, all_targets, json); return json.str(); } @@ -310,8 +307,7 @@ return false; StringOutputBuffer json; - std::ostream output_to_json(&json); - OutputJSON(build_settings, to_write, output_to_json); + OutputJSON(build_settings, to_write, json); return json.WriteToFileIfChanged(output_path, err); }
diff --git a/src/gn/compile_commands_writer_unittest.cc b/src/gn/compile_commands_writer_unittest.cc index 2f0294c..7e2ca28 100644 --- a/src/gn/compile_commands_writer_unittest.cc +++ b/src/gn/compile_commands_writer_unittest.cc
@@ -5,7 +5,6 @@ #include "gn/compile_commands_writer.h" #include <memory> -#include <sstream> #include <utility> #include "gn/config.h"
diff --git a/src/gn/config_values_extractors.cc b/src/gn/config_values_extractors.cc index a369008..58458ad 100644 --- a/src/gn/config_values_extractors.cc +++ b/src/gn/config_values_extractors.cc
@@ -5,6 +5,7 @@ #include "gn/config_values_extractors.h" #include "gn/escape.h" +#include "gn/output_stream.h" namespace { @@ -13,7 +14,7 @@ explicit EscapedStringWriter(const EscapeOptions& escape_options) : escape_options_(escape_options) {} - void operator()(const std::string& s, std::ostream& out) const { + void operator()(const std::string& s, OutputStream& out) const { out << " "; EscapeStringToStream(out, s, escape_options_); } @@ -29,7 +30,7 @@ const Target* target, const std::vector<std::string>& (ConfigValues::*getter)() const, const EscapeOptions& escape_options, - std::ostream& out) { + OutputStream& out) { RecursiveTargetConfigToStream(config, target, getter, EscapedStringWriter(escape_options), out); }
diff --git a/src/gn/config_values_extractors.h b/src/gn/config_values_extractors.h index 45b1f25..ae4c862 100644 --- a/src/gn/config_values_extractors.h +++ b/src/gn/config_values_extractors.h
@@ -17,6 +17,8 @@ struct EscapeOptions; +class OutputStream; + // Provides a way to iterate through all ConfigValues applying to a given // target. This is more complicated than normal because the target has a list // of configs applying to it, and also config values on the target itself. @@ -87,7 +89,7 @@ const Target* target, const std::vector<T>& (ConfigValues::*getter)() const, const Writer& writer, - std::ostream& out) { + OutputStream& out) { std::set<T> seen; for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) { const std::vector<T>& values = ((iter.cur()).*getter)(); @@ -113,6 +115,6 @@ const Target* target, const std::vector<std::string>& (ConfigValues::*getter)() const, const EscapeOptions& escape_options, - std::ostream& out); + OutputStream& out); #endif // TOOLS_GN_CONFIG_VALUES_EXTRACTORS_H_
diff --git a/src/gn/config_values_extractors_unittest.cc b/src/gn/config_values_extractors_unittest.cc index 3db4bff..c27107d 100644 --- a/src/gn/config_values_extractors_unittest.cc +++ b/src/gn/config_values_extractors_unittest.cc
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <sstream> +#include "gn/config_values_extractors.h" #include "gn/config.h" -#include "gn/config_values_extractors.h" +#include "gn/output_stream.h" #include "gn/target.h" #include "gn/test_with_scope.h" #include "util/test/test.h" @@ -13,13 +13,13 @@ namespace { struct FlagWriter { - void operator()(const std::string& dir, std::ostream& out) const { + void operator()(const std::string& dir, OutputStream& out) const { out << dir << " "; } }; struct IncludeWriter { - void operator()(const SourceDir& dir, std::ostream& out) const { + void operator()(const SourceDir& dir, OutputStream& out) const { out << dir.value() << " "; } }; @@ -128,7 +128,7 @@ ASSERT_TRUE(target.OnResolved(&err)); // Verify cflags by serializing. - std::ostringstream flag_out; + StringOutputStream flag_out; FlagWriter flag_writer; RecursiveTargetConfigToStream<std::string, FlagWriter>( kRecursiveWriterKeepDuplicates, &target, &ConfigValues::cflags, @@ -138,7 +138,7 @@ "--dep1-all --dep1-all-sub --dep2-all --dep2-all --dep1-direct "); // Verify include dirs by serializing. - std::ostringstream include_out; + StringOutputStream include_out; IncludeWriter include_writer; RecursiveTargetConfigToStream<SourceDir, IncludeWriter>( kRecursiveWriterSkipDuplicates, &target, &ConfigValues::include_dirs,
diff --git a/src/gn/eclipse_writer.cc b/src/gn/eclipse_writer.cc index 0067f6d..5da2b12 100644 --- a/src/gn/eclipse_writer.cc +++ b/src/gn/eclipse_writer.cc
@@ -4,7 +4,6 @@ #include "gn/eclipse_writer.h" -#include <fstream> #include <memory> #include "base/files/file_path.h" @@ -12,6 +11,7 @@ #include "gn/config_values_extractors.h" #include "gn/filesystem_utils.h" #include "gn/loader.h" +#include "gn/output_stream.h" #include "gn/xml_element_writer.h" namespace { @@ -37,7 +37,7 @@ EclipseWriter::EclipseWriter(const BuildSettings* build_settings, const Builder& builder, - std::ostream& out) + OutputStream& out) : build_settings_(build_settings), builder_(builder), out_(out) { languages_.push_back("C++ Source File"); languages_.push_back("C Source File"); @@ -55,9 +55,7 @@ Err* err) { base::FilePath file = build_settings->GetFullPath(build_settings->build_dir()) .AppendASCII("eclipse-cdt-settings.xml"); - std::ofstream file_out; - file_out.open(FilePathToUTF8(file).c_str(), - std::ios_base::out | std::ios_base::binary); + FileOutputStream file_out(FilePathToUTF8(file).c_str()); if (file_out.fail()) { *err = Err(Location(), "Couldn't open eclipse-cdt-settings.xml for writing"); @@ -119,7 +117,7 @@ } void EclipseWriter::WriteCDTSettings() { - out_ << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; + out_ << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; XmlElementWriter cdt_properties_element(out_, "cdtprojectproperties", XmlAttributes());
diff --git a/src/gn/eclipse_writer.h b/src/gn/eclipse_writer.h index 6b71a51..17b515f 100644 --- a/src/gn/eclipse_writer.h +++ b/src/gn/eclipse_writer.h
@@ -14,6 +14,7 @@ class BuildSettings; class Builder; class Err; +class OutputStream; class Target; class EclipseWriter { @@ -25,7 +26,7 @@ private: EclipseWriter(const BuildSettings* build_settings, const Builder& builder, - std::ostream& out); + OutputStream& out); ~EclipseWriter(); void Run(); @@ -48,7 +49,7 @@ const Builder& builder_; // The output stream for the settings file. - std::ostream& out_; + OutputStream& out_; // Eclipse languages for which the include dirs and defines apply. std::vector<std::string> languages_;
diff --git a/src/gn/escape.cc b/src/gn/escape.cc index 687c92a..56ae6de 100644 --- a/src/gn/escape.cc +++ b/src/gn/escape.cc
@@ -11,6 +11,7 @@ #include "base/compiler_specific.h" #include "base/json/string_escape.h" #include "base/logging.h" +#include "gn/output_stream.h" #include "util/build_config.h" namespace { @@ -294,14 +295,14 @@ EscapeStringToString(str, options, dest, needed_quoting)); } -void EscapeStringToStream(std::ostream& out, +void EscapeStringToStream(OutputStream& out, std::string_view str, const EscapeOptions& options) { StackOrHeapBuffer dest(str.size() * kMaxEscapedCharsPerChar); out.write(dest, EscapeStringToString(str, options, dest, nullptr)); } -void EscapeJSONStringToStream(std::ostream& out, +void EscapeJSONStringToStream(OutputStream& out, std::string_view str, const EscapeOptions& options) { std::string dest;
diff --git a/src/gn/escape.h b/src/gn/escape.h index c46d42d..1fc87a5 100644 --- a/src/gn/escape.h +++ b/src/gn/escape.h
@@ -5,10 +5,11 @@ #ifndef TOOLS_GN_ESCAPE_H_ #define TOOLS_GN_ESCAPE_H_ -#include <iosfwd> #include <string_view> #include <string> +class OutputStream; + enum EscapingMode { // No escaping. ESCAPE_NONE, @@ -78,13 +79,13 @@ // Same as EscapeString but writes the results to the given stream, saving a // copy. -void EscapeStringToStream(std::ostream& out, +void EscapeStringToStream(OutputStream& out, std::string_view str, const EscapeOptions& options); // Same as EscapeString but escape JSON string and writes the results to the // given stream, saving a copy. -void EscapeJSONStringToStream(std::ostream& out, +void EscapeJSONStringToStream(OutputStream& out, std::string_view str, const EscapeOptions& options);
diff --git a/src/gn/escape_unittest.cc b/src/gn/escape_unittest.cc index 004498e..0f32075 100644 --- a/src/gn/escape_unittest.cc +++ b/src/gn/escape_unittest.cc
@@ -3,7 +3,7 @@ // found in the LICENSE file. #include "gn/escape.h" -#include "gn/string_output_buffer.h" +#include "gn/output_stream.h" #include "util/test/test.h" TEST(Escape, Ninja) { @@ -85,20 +85,17 @@ opts.mode = ESCAPE_NINJA_PREFORMATTED_COMMAND; opts.inhibit_quoting = true; - StringOutputBuffer buffer; - std::ostream out(&buffer); + StringOutputStream buffer; - EscapeJSONStringToStream(out, "foo\\\" bar", opts); + EscapeJSONStringToStream(buffer, "foo\\\" bar", opts); EXPECT_EQ("foo\\\\\\\" bar", buffer.str()); - StringOutputBuffer buffer1; - std::ostream out1(&buffer1); - EscapeJSONStringToStream(out1, "foo bar\\\\", opts); + StringOutputStream buffer1; + EscapeJSONStringToStream(buffer1, "foo bar\\\\", opts); EXPECT_EQ("foo bar\\\\\\\\", buffer1.str()); - StringOutputBuffer buffer2; - std::ostream out2(&buffer2); - EscapeJSONStringToStream(out2, "a: \"$\\b", opts); + StringOutputStream buffer2; + EscapeJSONStringToStream(buffer2, "a: \"$\\b", opts); EXPECT_EQ("a: \\\"$$\\\\b", buffer2.str()); }
diff --git a/src/gn/function_write_file.cc b/src/gn/function_write_file.cc index 709f5fb..d79f4df 100644 --- a/src/gn/function_write_file.cc +++ b/src/gn/function_write_file.cc
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <sstream> - #include "base/files/file_util.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -14,6 +12,7 @@ #include "gn/functions.h" #include "gn/input_file.h" #include "gn/output_conversion.h" +#include "gn/output_stream.h" #include "gn/parse_tree.h" #include "gn/scheduler.h" #include "gn/string_output_buffer.h" @@ -90,8 +89,7 @@ // Compute output. StringOutputBuffer storage; - std::ostream contents(&storage); - ConvertValueToOutput(scope->settings(), args[1], output_conversion, contents, + ConvertValueToOutput(scope->settings(), args[1], output_conversion, storage, err); if (err->has_error()) return Value();
diff --git a/src/gn/header_checker_unittest.cc b/src/gn/header_checker_unittest.cc index 00a82d3..74d99cc 100644 --- a/src/gn/header_checker_unittest.cc +++ b/src/gn/header_checker_unittest.cc
@@ -7,6 +7,7 @@ #include "gn/config.h" #include "gn/header_checker.h" +#include "gn/output_stream.h" #include "gn/scheduler.h" #include "gn/target.h" #include "gn/test_with_scheduler.h" @@ -75,7 +76,7 @@ } // namespace -void PrintTo(const SourceFile& source_file, ::std::ostream* os) { +void PrintTo(const SourceFile& source_file, OutputStream* os) { *os << source_file.value(); }
diff --git a/src/gn/ninja_action_target_writer.cc b/src/gn/ninja_action_target_writer.cc index 0fe0c1b..e479c90 100644 --- a/src/gn/ninja_action_target_writer.cc +++ b/src/gn/ninja_action_target_writer.cc
@@ -10,6 +10,7 @@ #include "gn/deps_iterator.h" #include "gn/err.h" #include "gn/general_tool.h" +#include "gn/output_stream.h" #include "gn/pool.h" #include "gn/settings.h" #include "gn/string_utils.h" @@ -17,7 +18,7 @@ #include "gn/target.h" NinjaActionTargetWriter::NinjaActionTargetWriter(const Target* target, - std::ostream& out) + OutputStream& out) : NinjaTargetWriter(target, out), path_output_no_escaping_( target->settings()->build_settings()->build_dir(), @@ -75,7 +76,7 @@ target_->output_type() == Target::ACTION ? 1u : target_->sources().size(); std::vector<OutputFile> input_deps = WriteInputDepsStampOrPhonyAndGetDep( additional_hard_deps, num_output_uses); - out_ << std::endl; + out_ << "\n"; // Collects all output files for writing below. std::vector<OutputFile> output_files; @@ -108,7 +109,7 @@ path_output_.WriteFiles(out_, order_only_deps); } - out_ << std::endl; + out_ << "\n"; if (target_->action_values().has_depfile()) { WriteDepfile(SourceFile()); } @@ -119,10 +120,10 @@ out_ << " pool = "; out_ << target_->pool().ptr->GetNinjaName( settings_->default_toolchain_label()); - out_ << std::endl; + out_ << "\n"; } } - out_ << std::endl; + out_ << "\n"; // Write the phony, which doesn't need to depend on the data deps because they // have been added as order-only deps of the action output itself. @@ -147,7 +148,7 @@ EscapeOptions args_escape_options; args_escape_options.mode = ESCAPE_NINJA_COMMAND; - out_ << "rule " << custom_rule_name << std::endl; + out_ << "rule " << custom_rule_name << "\n"; if (target_->action_values().uses_rsp_file()) { // Needs a response file. The unique_name part is for action_foreach so @@ -158,7 +159,7 @@ if (!target_->sources().empty()) rspfile += ".$unique_name"; rspfile += ".rsp"; - out_ << " rspfile = " << rspfile << std::endl; + out_ << " rspfile = " << rspfile << "\n"; // Response file contents. out_ << " rspfile_content ="; @@ -168,7 +169,7 @@ SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, out_); } - out_ << std::endl; + out_ << "\n"; } // The command line requires shell escaping to properly handle filenames @@ -185,19 +186,19 @@ out_ << " "; SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, out_); } - out_ << std::endl; + out_ << "\n"; auto mnemonic = target_->action_values().mnemonic(); if (mnemonic.empty()) mnemonic = "ACTION"; - out_ << " description = " << mnemonic << " " << target_label << std::endl; - out_ << " restat = 1" << std::endl; + out_ << " description = " << mnemonic << " " << target_label << "\n"; + out_ << " restat = 1\n"; const Tool* tool = target_->toolchain()->GetTool(GeneralTool::kGeneralToolAction); if (tool && tool->pool().ptr) { out_ << " pool = "; out_ << tool->pool().ptr->GetNinjaName( settings_->default_toolchain_label()); - out_ << std::endl; + out_ << "\n"; } return custom_rule_name; @@ -235,11 +236,11 @@ out_ << " ||"; path_output_.WriteFiles(out_, order_only_deps); } - out_ << std::endl; + out_ << "\n"; // Response files require a unique name be defined. if (target_->action_values().uses_rsp_file()) - out_ << " unique_name = " << i << std::endl; + out_ << " unique_name = " << i << "\n"; // The required types is the union of the args and response file. This // might theoretically duplicate a definition if the same substitution is @@ -263,7 +264,7 @@ out_ << " pool = "; out_ << target_->pool().ptr->GetNinjaName( settings_->default_toolchain_label()); - out_ << std::endl; + out_ << "\n"; } } } @@ -289,14 +290,14 @@ out_, SubstitutionWriter::ApplyPatternToSourceAsOutputFile( target_, settings_, target_->action_values().depfile(), source)); - out_ << std::endl; + out_ << "\n"; // Using "deps = gcc" allows Ninja to read and store the depfile content in // its internal database which improves performance, especially for large // depfiles. The use of this feature with depfiles that contain multiple // outputs require Ninja version 1.9.0 or newer. if (settings_->build_settings()->ninja_required_version() >= Version{1, 9, 0}) { - out_ << " deps = gcc" << std::endl; + out_ << " deps = gcc\n"; } }
diff --git a/src/gn/ninja_action_target_writer.h b/src/gn/ninja_action_target_writer.h index eff087b..fe18f5b 100644 --- a/src/gn/ninja_action_target_writer.h +++ b/src/gn/ninja_action_target_writer.h
@@ -11,11 +11,12 @@ #include "gn/ninja_target_writer.h" class OutputFile; +class OutputStream; // Writes a .ninja file for a action target type. class NinjaActionTargetWriter : public NinjaTargetWriter { public: - NinjaActionTargetWriter(const Target* target, std::ostream& out); + NinjaActionTargetWriter(const Target* target, OutputStream& out); ~NinjaActionTargetWriter() override; void Run() override;
diff --git a/src/gn/ninja_action_target_writer_unittest.cc b/src/gn/ninja_action_target_writer_unittest.cc index 9b7c76f..69035fb 100644 --- a/src/gn/ninja_action_target_writer_unittest.cc +++ b/src/gn/ninja_action_target_writer_unittest.cc
@@ -3,10 +3,10 @@ // found in the LICENSE file. #include <algorithm> -#include <sstream> #include "gn/config.h" #include "gn/ninja_action_target_writer.h" +#include "gn/output_stream.h" #include "gn/pool.h" #include "gn/substitution_list.h" #include "gn/target.h" @@ -27,7 +27,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); SourceFile source("//foo/bar.in"); @@ -57,7 +57,7 @@ setup.build_settings()->set_python_path( base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); writer.Run(); @@ -99,7 +99,7 @@ setup.build_settings()->set_python_path( base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); writer.Run(); @@ -141,7 +141,7 @@ setup.build_settings()->set_python_path( base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); writer.Run(); @@ -198,7 +198,7 @@ setup.build_settings()->set_python_path( base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); writer.Run(); @@ -269,7 +269,7 @@ setup.build_settings()->set_python_path( base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); writer.Run(); @@ -337,7 +337,7 @@ base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); setup.build_settings()->set_ninja_required_version(Version{1, 9, 0}); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); writer.Run(); @@ -394,7 +394,7 @@ setup.build_settings()->set_python_path( base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); writer.Run(); @@ -452,7 +452,7 @@ setup.build_settings()->set_python_path( base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); writer.Run(); @@ -499,7 +499,7 @@ ASSERT_TRUE(foo.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&foo, out); writer.Run(); @@ -528,7 +528,7 @@ ASSERT_TRUE(bar.OnResolved(&err)) << err.message(); { - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&bar, out); writer.Run(); @@ -583,7 +583,7 @@ ASSERT_TRUE(foo.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&foo, out); writer.Run(); @@ -629,7 +629,7 @@ setup.build_settings()->set_python_path( base::FilePath(FILE_PATH_LITERAL("/Program Files/python"))); - std::ostringstream out; + StringOutputStream out; NinjaActionTargetWriter writer(&target, out); writer.Run();
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc index c244c7c..21b10fc 100644 --- a/src/gn/ninja_binary_target_writer.cc +++ b/src/gn/ninja_binary_target_writer.cc
@@ -4,8 +4,6 @@ #include "gn/ninja_binary_target_writer.h" -#include <sstream> - #include "base/strings/string_util.h" #include "gn/builtin_tool.h" #include "gn/config_values_extractors.h" @@ -16,6 +14,7 @@ #include "gn/ninja_rust_binary_target_writer.h" #include "gn/ninja_target_command_util.h" #include "gn/ninja_utils.h" +#include "gn/output_stream.h" #include "gn/pool.h" #include "gn/settings.h" #include "gn/string_utils.h" @@ -35,7 +34,7 @@ } // namespace NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, - std::ostream& out) + OutputStream& out) : NinjaTargetWriter(target, out), rule_prefix_(GetNinjaRulePrefixForToolchain(settings_)) {} @@ -119,7 +118,7 @@ path_output_.WriteFile(out_, *input); } - out_ << std::endl; + out_ << "\n"; return {stamp_or_phony}; } @@ -292,22 +291,22 @@ out_ << " ||"; path_output_.WriteFiles(out_, order_only_deps); } - out_ << std::endl; + out_ << "\n"; if (!sources.empty() && can_write_source_info) { out_ << " " << "source_file_part = " << sources[0].GetName(); - out_ << std::endl; + out_ << "\n"; out_ << " " << "source_name_part = " << FindFilenameNoExtension(&sources[0].value()); - out_ << std::endl; + out_ << "\n"; } if (restat_output_allowed) { - out_ << " restat = 1" << std::endl; + out_ << " restat = 1\n"; } } -void NinjaBinaryTargetWriter::WriteCustomLinkerFlags(std::ostream& out, +void NinjaBinaryTargetWriter::WriteCustomLinkerFlags(OutputStream& out, const Tool* tool) { if (tool->AsC() || (tool->AsRust() && tool->AsRust()->MayLink())) { // First the ldflags from the target and its config. @@ -317,7 +316,7 @@ } } -void NinjaBinaryTargetWriter::WriteLibrarySearchPath(std::ostream& out, +void NinjaBinaryTargetWriter::WriteLibrarySearchPath(OutputStream& out, const Tool* tool) { // Write library search paths that have been recursively pushed // through the dependency tree. @@ -351,7 +350,7 @@ } void NinjaBinaryTargetWriter::WriteLinkerFlags( - std::ostream& out, + OutputStream& out, const Tool* tool, const SourceFile* optional_def_file) { // First any ldflags @@ -365,7 +364,7 @@ } } -void NinjaBinaryTargetWriter::WriteLibs(std::ostream& out, const Tool* tool) { +void NinjaBinaryTargetWriter::WriteLibs(OutputStream& out, const Tool* tool) { // Libraries that have been recursively pushed through the dependency tree. // Since we're passing these on the command line to the linker and not // to Ninja, we need to do shell escaping. @@ -388,7 +387,7 @@ } } -void NinjaBinaryTargetWriter::WriteFrameworks(std::ostream& out, +void NinjaBinaryTargetWriter::WriteFrameworks(OutputStream& out, const Tool* tool) { // Frameworks that have been recursively pushed through the dependency tree. FrameworksWriter writer(tool->framework_switch()); @@ -405,7 +404,7 @@ } void NinjaBinaryTargetWriter::WriteSwiftModules( - std::ostream& out, + OutputStream& out, const Tool* tool, const std::vector<OutputFile>& swiftmodules) { // Since we're passing these on the command line to the linker and not @@ -420,11 +419,11 @@ } } -void NinjaBinaryTargetWriter::WritePool(std::ostream& out) { +void NinjaBinaryTargetWriter::WritePool(OutputStream& out) { if (target_->pool().ptr) { out << " pool = "; out << target_->pool().ptr->GetNinjaName( settings_->default_toolchain_label()); - out << std::endl; + out << "\n"; } }
diff --git a/src/gn/ninja_binary_target_writer.h b/src/gn/ninja_binary_target_writer.h index 29105b4..56a777a 100644 --- a/src/gn/ninja_binary_target_writer.h +++ b/src/gn/ninja_binary_target_writer.h
@@ -11,13 +11,15 @@ #include "gn/toolchain.h" #include "gn/unique_vector.h" +class OutputStream; + struct EscapeOptions; // Writes a .ninja file for a binary target type (an executable, a shared // library, or a static library). class NinjaBinaryTargetWriter : public NinjaTargetWriter { public: - NinjaBinaryTargetWriter(const Target* target, std::ostream& out); + NinjaBinaryTargetWriter(const Target* target, OutputStream& out); ~NinjaBinaryTargetWriter() override; void Run() override; @@ -61,17 +63,17 @@ bool can_write_source_info = true, bool restat_output_allowed = false); - void WriteLinkerFlags(std::ostream& out, + void WriteLinkerFlags(OutputStream& out, const Tool* tool, const SourceFile* optional_def_file); - void WriteCustomLinkerFlags(std::ostream& out, const Tool* tool); - void WriteLibrarySearchPath(std::ostream& out, const Tool* tool); - void WriteLibs(std::ostream& out, const Tool* tool); - void WriteFrameworks(std::ostream& out, const Tool* tool); - void WriteSwiftModules(std::ostream& out, + void WriteCustomLinkerFlags(OutputStream& out, const Tool* tool); + void WriteLibrarySearchPath(OutputStream& out, const Tool* tool); + void WriteLibs(OutputStream& out, const Tool* tool); + void WriteFrameworks(OutputStream& out, const Tool* tool); + void WriteSwiftModules(OutputStream& out, const Tool* tool, const std::vector<OutputFile>& swiftmodules); - void WritePool(std::ostream& out); + void WritePool(OutputStream& out); void AddSourceSetFiles(const Target* source_set, UniqueVector<OutputFile>* obj_files) const;
diff --git a/src/gn/ninja_binary_target_writer_unittest.cc b/src/gn/ninja_binary_target_writer_unittest.cc index 29dfd33..7ef54c6 100644 --- a/src/gn/ninja_binary_target_writer_unittest.cc +++ b/src/gn/ninja_binary_target_writer_unittest.cc
@@ -4,6 +4,7 @@ #include "gn/ninja_binary_target_writer.h" +#include "gn/output_stream.h" #include "gn/test_with_scheduler.h" #include "gn/test_with_scope.h" #include "util/test/test.h" @@ -28,7 +29,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaBinaryTargetWriter writer(&target, out); writer.Run(); @@ -65,7 +66,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaBinaryTargetWriter writer(&target, out); writer.Run(); @@ -92,7 +93,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaBinaryTargetWriter writer(&target, out); writer.Run(); @@ -128,7 +129,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaBinaryTargetWriter writer(&target, out); writer.Run(); @@ -164,7 +165,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaBinaryTargetWriter writer(&target, out); writer.Run();
diff --git a/src/gn/ninja_build_writer.cc b/src/gn/ninja_build_writer.cc index 5349948..de91eaf 100644 --- a/src/gn/ninja_build_writer.cc +++ b/src/gn/ninja_build_writer.cc
@@ -6,10 +6,8 @@ #include <stddef.h> -#include <fstream> #include <map> #include <set> -#include <sstream> #include "base/command_line.h" #include "base/files/file_util.h" @@ -23,6 +21,7 @@ #include "gn/input_file_manager.h" #include "gn/loader.h" #include "gn/ninja_utils.h" +#include "gn/output_stream.h" #include "gn/pool.h" #include "gn/scheduler.h" #include "gn/string_atom.h" @@ -199,8 +198,8 @@ const std::vector<const Target*>& all_targets, const Toolchain* default_toolchain, const std::vector<const Target*>& default_toolchain_targets, - std::ostream& out, - std::ostream& dep_out) + OutputStream& out, + OutputStream& dep_out) : build_settings_(build_settings), used_toolchains_(used_toolchains), all_targets_(all_targets), @@ -254,8 +253,8 @@ } } - std::stringstream file; - std::stringstream depfile; + StringOutputStream file; + StringOutputStream depfile; NinjaBuildWriter gen(build_settings, used_toolchains, all_targets, default_toolchain, default_toolchain_targets, file, depfile); @@ -308,7 +307,7 @@ // static std::string NinjaBuildWriter::ExtractRegenerationCommands( std::istream& build_ninja_in) { - std::ostringstream out; + StringOutputStream out; int num_blank_lines = 0; for (std::string line; std::getline(build_ninja_in, line);) { out << line << '\n'; @@ -380,7 +379,7 @@ sorter.IterateOver(item_callback); - out_ << std::endl; + out_ << "\n"; } void NinjaBuildWriter::WriteAllPools() { @@ -415,9 +414,9 @@ std::string name = pool_name(pool); if (name == "console") continue; - out_ << "pool " << name << std::endl - << " depth = " << pool->depth() << std::endl - << std::endl; + out_ << "pool " << name << "\n" + << " depth = " << pool->depth() << "\n" + << "\n"; } } @@ -453,11 +452,11 @@ out_ << "subninja "; path_output_.WriteFile(out_, subninja); - out_ << std::endl; + out_ << "\n"; previous_subninja = subninja; previous_toolchain = pair.second; } - out_ << std::endl; + out_ << "\n"; return true; } @@ -675,22 +674,22 @@ } } } - out_ << std::endl; + out_ << "\n"; if (default_target) { // Use the short name when available if (written_rules.find(StringAtom("default")) != written_rules.end()) { - out_ << "\ndefault default" << std::endl; + out_ << "\ndefault default\n"; } else if (default_target->has_dependency_output()) { // If the default target does not have a dependency output file or phony, // then the target specified as default is a no-op. We omit the default // statement entirely to avoid ninja runtime failure. out_ << "\ndefault "; path_output_.WriteFile(out_, default_target->dependency_output()); - out_ << std::endl; + out_ << "\n"; } } else if (!default_toolchain_targets_.empty()) { - out_ << "\ndefault all" << std::endl; + out_ << "\ndefault all\n"; } return true; @@ -711,5 +710,5 @@ if (target->has_dependency_output()) { path_output_.WriteFile(out_, target->dependency_output()); } - out_ << std::endl; + out_ << "\n"; }
diff --git a/src/gn/ninja_build_writer.h b/src/gn/ninja_build_writer.h index c21769a..77d891c 100644 --- a/src/gn/ninja_build_writer.h +++ b/src/gn/ninja_build_writer.h
@@ -35,8 +35,8 @@ const std::vector<const Target*>& all_targets, const Toolchain* default_toolchain, const std::vector<const Target*>& default_toolchain_targets, - std::ostream& out, - std::ostream& dep_out); + OutputStream& out, + OutputStream& dep_out); ~NinjaBuildWriter(); // The design of this class is that this static factory function takes the @@ -92,8 +92,8 @@ const Toolchain* default_toolchain_; const std::vector<const Target*>& default_toolchain_targets_; - std::ostream& out_; - std::ostream& dep_out_; + OutputStream& out_; + OutputStream& dep_out_; PathOutput path_output_; NinjaBuildWriter(const NinjaBuildWriter&) = delete;
diff --git a/src/gn/ninja_build_writer_unittest.cc b/src/gn/ninja_build_writer_unittest.cc index 493ba40..5511147 100644 --- a/src/gn/ninja_build_writer_unittest.cc +++ b/src/gn/ninja_build_writer_unittest.cc
@@ -2,12 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <fstream> -#include <sstream> - +#include "gn/ninja_build_writer.h" #include "base/command_line.h" #include "base/files/file_util.h" -#include "gn/ninja_build_writer.h" +#include "gn/output_stream.h" #include "gn/pool.h" #include "gn/scheduler.h" #include "gn/switches.h" @@ -135,8 +133,8 @@ std::vector<const Target*> targets = {&target_foo, &target_bar, &target_baz}; - std::ostringstream ninja_out; - std::ostringstream depfile_out; + StringOutputStream ninja_out; + StringOutputStream depfile_out; NinjaBuildWriter writer(setup.build_settings(), used_toolchains, targets, setup.toolchain(), targets, ninja_out, depfile_out); @@ -211,8 +209,8 @@ std::vector<const Target*> targets = {&target_foo}; - std::stringstream ninja_out; - std::ostringstream depfile_out; + StringOutputStream ninja_out; + StringOutputStream depfile_out; NinjaBuildWriter writer(setup.build_settings(), used_toolchains, targets, setup.toolchain(), targets, ninja_out, depfile_out); @@ -241,8 +239,9 @@ EXPECT_SNIPPET(ninja_out_str, expected_root_target); EXPECT_SNIPPET(ninja_out_str, expected_default); + std::istringstream ninja_in(ninja_out.str()); std::string commands = - NinjaBuildWriter::ExtractRegenerationCommands(ninja_out); + NinjaBuildWriter::ExtractRegenerationCommands(ninja_in); EXPECT_SNIPPET(commands, expected_rule_gn); EXPECT_SNIPPET(commands, expected_build_ninja_stamp); EXPECT_SNIPPET(commands, expected_build_ninja); @@ -255,18 +254,17 @@ } TEST_F(NinjaBuildWriterTest, ExtractRegenerationCommands_DefaultStream) { - std::ifstream ninja_in; + std::istringstream ninja_in; EXPECT_EQ(NinjaBuildWriter::ExtractRegenerationCommands(ninja_in), ""); } TEST_F(NinjaBuildWriterTest, ExtractRegenerationCommands_StreamError) { - std::ifstream ninja_in("/does/not/exist"); + std::istringstream ninja_in("/does/not/exist"); EXPECT_EQ(NinjaBuildWriter::ExtractRegenerationCommands(ninja_in), ""); } TEST_F(NinjaBuildWriterTest, ExtractRegenerationCommands_IncompleteNinja) { - std::stringstream ninja_in; - ninja_in << "foo\nbar\nbaz\nbif\n"; + std::istringstream ninja_in("foo\nbar\nbaz\nbif\n"); EXPECT_EQ(NinjaBuildWriter::ExtractRegenerationCommands(ninja_in), ""); } @@ -287,8 +285,8 @@ std::unordered_map<const Settings*, const Toolchain*> used_toolchains; used_toolchains[setup.settings()] = setup.toolchain(); std::vector<const Target*> targets; - std::ostringstream ninja_out; - std::ostringstream depfile_out; + StringOutputStream ninja_out; + StringOutputStream depfile_out; NinjaBuildWriter writer(setup.build_settings(), used_toolchains, targets, setup.toolchain(), targets, ninja_out, depfile_out); ASSERT_TRUE(writer.Run(&err)); @@ -320,8 +318,8 @@ std::unordered_map<const Settings*, const Toolchain*> used_toolchains; used_toolchains[setup.settings()] = setup.toolchain(); std::vector<const Target*> targets = {&target_foo, &target_bar}; - std::ostringstream ninja_out; - std::ostringstream depfile_out; + StringOutputStream ninja_out; + StringOutputStream depfile_out; NinjaBuildWriter writer(setup.build_settings(), used_toolchains, targets, setup.toolchain(), targets, ninja_out, depfile_out); ASSERT_FALSE(writer.Run(&err));
diff --git a/src/gn/ninja_bundle_data_target_writer.cc b/src/gn/ninja_bundle_data_target_writer.cc index 4ba1733..362344d 100644 --- a/src/gn/ninja_bundle_data_target_writer.cc +++ b/src/gn/ninja_bundle_data_target_writer.cc
@@ -9,7 +9,7 @@ #include "gn/target.h" NinjaBundleDataTargetWriter::NinjaBundleDataTargetWriter(const Target* target, - std::ostream& out) + OutputStream& out) : NinjaTargetWriter(target, out) {} NinjaBundleDataTargetWriter::~NinjaBundleDataTargetWriter() = default;
diff --git a/src/gn/ninja_bundle_data_target_writer.h b/src/gn/ninja_bundle_data_target_writer.h index 720c593..de1e3fc 100644 --- a/src/gn/ninja_bundle_data_target_writer.h +++ b/src/gn/ninja_bundle_data_target_writer.h
@@ -10,7 +10,7 @@ // Writes a .ninja file for a bundle_data target type. class NinjaBundleDataTargetWriter : public NinjaTargetWriter { public: - NinjaBundleDataTargetWriter(const Target* target, std::ostream& out); + NinjaBundleDataTargetWriter(const Target* target, OutputStream& out); ~NinjaBundleDataTargetWriter() override; void Run() override;
diff --git a/src/gn/ninja_bundle_data_target_writer_unittest.cc b/src/gn/ninja_bundle_data_target_writer_unittest.cc index 9f90245..4de32bf 100644 --- a/src/gn/ninja_bundle_data_target_writer_unittest.cc +++ b/src/gn/ninja_bundle_data_target_writer_unittest.cc
@@ -5,8 +5,8 @@ #include "gn/ninja_bundle_data_target_writer.h" #include <algorithm> -#include <sstream> +#include "gn/output_stream.h" #include "gn/target.h" #include "gn/test_with_scope.h" #include "util/test/test.h" @@ -41,7 +41,7 @@ bundle_data.visibility().SetPublic(); ASSERT_TRUE(bundle_data.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaBundleDataTargetWriter writer(&bundle_data, out); writer.Run();
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc index 96907f7..207741a 100644 --- a/src/gn/ninja_c_binary_target_writer.cc +++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -9,7 +9,6 @@ #include <cstring> #include <set> -#include <sstream> #include "base/strings/string_util.h" #include "gn/c_substitution_type.h" @@ -21,6 +20,7 @@ #include "gn/general_tool.h" #include "gn/ninja_target_command_util.h" #include "gn/ninja_utils.h" +#include "gn/output_stream.h" #include "gn/pool.h" #include "gn/scheduler.h" #include "gn/settings.h" @@ -122,7 +122,7 @@ } // namespace NinjaCBinaryTargetWriter::NinjaCBinaryTargetWriter(const Target* target, - std::ostream& out) + OutputStream& out) : NinjaBinaryTargetWriter(target, out), tool_(target->toolchain()->GetToolForTargetFinalOutputAsC(target)) {} @@ -267,7 +267,7 @@ } } - out_ << std::endl; + out_ << "\n"; } } @@ -388,7 +388,7 @@ // Write two blank lines to help separate the PCH build lines from the // regular source build lines. - out_ << std::endl << std::endl; + out_ << "\n\n"; } void NinjaCBinaryTargetWriter::WriteWindowsPCHCommand( @@ -424,7 +424,8 @@ // Write two blank lines to help separate the PCH build lines from the // regular source build lines. - out_ << std::endl << std::endl; + out_ << "\n" + << "\n"; } void NinjaCBinaryTargetWriter::WriteSources( @@ -500,7 +501,7 @@ } } - out_ << std::endl; + out_ << "\n"; } void NinjaCBinaryTargetWriter::WriteSwiftSources( @@ -537,7 +538,7 @@ /*can_write_source_info=*/false, /*restat_output_allowed=*/true); - out_ << std::endl; + out_ << "\n"; } void NinjaCBinaryTargetWriter::WriteSourceSetStamp( @@ -693,7 +694,7 @@ WriteOrderOnlyDependencies(classified_deps.non_linkable_deps); // End of the link "build" line. - out_ << std::endl; + out_ << "\n"; // The remaining things go in the inner scope of the link line. if (target_->output_type() == Target::EXECUTABLE || @@ -701,22 +702,22 @@ target_->output_type() == Target::LOADABLE_MODULE) { out_ << " ldflags ="; WriteLinkerFlags(out_, tool_, optional_def_file); - out_ << std::endl; + out_ << "\n"; out_ << " libs ="; WriteLibs(out_, tool_); - out_ << std::endl; + out_ << "\n"; out_ << " frameworks ="; WriteFrameworks(out_, tool_); - out_ << std::endl; + out_ << "\n"; out_ << " swiftmodules ="; WriteSwiftModules(out_, tool_, swiftmodules); - out_ << std::endl; + out_ << "\n"; } else if (target_->output_type() == Target::STATIC_LIBRARY) { out_ << " arflags ="; RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, target_, &ConfigValues::arflags, GetFlagOptions(), out_); - out_ << std::endl; + out_ << "\n"; } WriteOutputSubstitutions(); WriteLibsList("solibs", solibs); @@ -732,7 +733,7 @@ if (!output_extension.empty()) { out_ << " " << output_extension; } - out_ << std::endl; + out_ << "\n"; const std::string output_dir = SubstitutionWriter::GetLinkerSubstitution( target_, tool_, &SubstitutionOutputDir); @@ -740,7 +741,7 @@ if (!output_dir.empty()) { out_ << " " << output_dir; } - out_ << std::endl; + out_ << "\n"; } void NinjaCBinaryTargetWriter::WriteLibsList( @@ -754,7 +755,7 @@ settings_->build_settings()->root_path_utf8(), ESCAPE_NINJA_COMMAND); output.WriteFiles(out_, libs); - out_ << std::endl; + out_ << "\n"; } void NinjaCBinaryTargetWriter::WriteOrderOnlyDependencies(
diff --git a/src/gn/ninja_c_binary_target_writer.h b/src/gn/ninja_c_binary_target_writer.h index f60790f..6a553fc 100644 --- a/src/gn/ninja_c_binary_target_writer.h +++ b/src/gn/ninja_c_binary_target_writer.h
@@ -10,6 +10,8 @@ #include "gn/toolchain.h" #include "gn/unique_vector.h" +class OutputStream; + struct EscapeOptions; struct ModuleDep; @@ -17,7 +19,7 @@ // library, or a static library). class NinjaCBinaryTargetWriter : public NinjaBinaryTargetWriter { public: - NinjaCBinaryTargetWriter(const Target* target, std::ostream& out); + NinjaCBinaryTargetWriter(const Target* target, OutputStream& out); ~NinjaCBinaryTargetWriter() override; void Run() override;
diff --git a/src/gn/ninja_c_binary_target_writer_unittest.cc b/src/gn/ninja_c_binary_target_writer_unittest.cc index 8d2a388..f8d1130 100644 --- a/src/gn/ninja_c_binary_target_writer_unittest.cc +++ b/src/gn/ninja_c_binary_target_writer_unittest.cc
@@ -5,11 +5,11 @@ #include "gn/ninja_c_binary_target_writer.h" #include <memory> -#include <sstream> #include <utility> #include "gn/config.h" #include "gn/ninja_target_command_util.h" +#include "gn/output_stream.h" #include "gn/pool.h" #include "gn/scheduler.h" #include "gn/target.h" @@ -40,7 +40,7 @@ // Source set itself. { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -75,7 +75,7 @@ ASSERT_TRUE(shlib_target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&shlib_target, out); writer.Run(); @@ -112,7 +112,7 @@ ASSERT_TRUE(stlib_target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&stlib_target, out); writer.Run(); @@ -138,7 +138,7 @@ // Make the static library 'complete', which means it should be linked. stlib_target.set_complete_static_lib(true); { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&stlib_target, out); writer.Run(); @@ -175,7 +175,7 @@ target.config_values().defines().push_back("STR_DEF=\"ABCD-1\""); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -199,7 +199,7 @@ target.config_values().arflags().push_back("--asdf"); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -248,7 +248,7 @@ // should link in the dependent object files as if the dependent target // were a source set. { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -280,7 +280,7 @@ // Dependent complete static libraries should not be linked directly. { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -333,7 +333,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -401,7 +401,7 @@ gen_obj.SetToolchain(setup.toolchain()); ASSERT_TRUE(gen_obj.OnResolved(&err)); - std::ostringstream obj_out; + StringOutputStream obj_out; NinjaCBinaryTargetWriter obj_writer(&gen_obj, obj_out); obj_writer.Run(); @@ -440,7 +440,7 @@ gen_lib.SetToolchain(setup.toolchain()); ASSERT_TRUE(gen_lib.OnResolved(&err)); - std::ostringstream lib_out; + StringOutputStream lib_out; NinjaCBinaryTargetWriter lib_writer(&gen_lib, lib_out); lib_writer.Run(); @@ -479,7 +479,7 @@ executable.SetToolchain(setup.toolchain()); ASSERT_TRUE(executable.OnResolved(&err)) << err.message(); - std::ostringstream final_out; + StringOutputStream final_out; NinjaCBinaryTargetWriter final_writer(&executable, final_out); final_writer.Run(); @@ -527,7 +527,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -598,7 +598,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -642,7 +642,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -698,7 +698,7 @@ ASSERT_TRUE(inter.OnResolved(&err)) << err.message(); // Write out the intermediate target. - std::ostringstream inter_out; + StringOutputStream inter_out; NinjaCBinaryTargetWriter inter_writer(&inter, inter_out); inter_writer.Run(); @@ -732,7 +732,7 @@ exe.source_types_used().Set(SourceFile::SOURCE_CPP); ASSERT_TRUE(exe.OnResolved(&err)); - std::ostringstream final_out; + StringOutputStream final_out; NinjaCBinaryTargetWriter final_writer(&exe, final_out); final_writer.Run(); @@ -779,7 +779,7 @@ shared_lib.source_types_used().Set(SourceFile::SOURCE_DEF); ASSERT_TRUE(shared_lib.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&shared_lib, out); writer.Run(); @@ -819,7 +819,7 @@ loadable_module.source_types_used().Set(SourceFile::SOURCE_CPP); ASSERT_TRUE(loadable_module.OnResolved(&err)) << err.message(); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&loadable_module, out); writer.Run(); @@ -855,7 +855,7 @@ exe.source_types_used().Set(SourceFile::SOURCE_CPP); ASSERT_TRUE(exe.OnResolved(&err)) << err.message(); - std::ostringstream final_out; + StringOutputStream final_out; NinjaCBinaryTargetWriter final_writer(&exe, final_out); final_writer.Run(); @@ -937,7 +937,7 @@ no_pch_target.SetToolchain(&pch_toolchain); ASSERT_TRUE(no_pch_target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&no_pch_target, out); writer.Run(); @@ -979,7 +979,7 @@ pch_target.SetToolchain(&pch_toolchain); ASSERT_TRUE(pch_target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&pch_target, out); writer.Run(); @@ -1083,7 +1083,7 @@ no_pch_target.SetToolchain(&pch_toolchain); ASSERT_TRUE(no_pch_target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&no_pch_target, out); writer.Run(); @@ -1125,7 +1125,7 @@ pch_target.SetToolchain(&pch_toolchain); ASSERT_TRUE(pch_target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&pch_target, out); writer.Run(); @@ -1185,7 +1185,7 @@ scheduler().SuppressOutputForTesting(true); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1213,7 +1213,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1251,7 +1251,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1288,7 +1288,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1343,7 +1343,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1400,7 +1400,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1577,7 +1577,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1745,7 +1745,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1822,7 +1822,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1925,7 +1925,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -2021,7 +2021,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -2119,7 +2119,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -2229,7 +2229,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -2279,7 +2279,7 @@ target.source_types_used().Set(SourceFile::SOURCE_MODULEMAP); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -2326,7 +2326,7 @@ ASSERT_TRUE(foo_target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&foo_target, out); writer.Run(); @@ -2364,7 +2364,7 @@ bar_target.SetToolchain(setup.toolchain()); ASSERT_TRUE(bar_target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&bar_target, out); writer.Run(); @@ -2410,7 +2410,7 @@ bar_target.SetToolchain(setup.toolchain()); ASSERT_TRUE(bar_target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&bar_target, out); writer.Run(); @@ -2445,7 +2445,7 @@ bar_target.SetToolchain(setup.toolchain()); ASSERT_TRUE(bar_target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&bar_target, out); writer.Run(); @@ -2544,7 +2544,7 @@ // The library first. { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -2589,7 +2589,7 @@ // A second library to make sure the depender includes both. { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target2, out); writer.Run(); @@ -2633,7 +2633,7 @@ // A third library that depends on one of the previous static libraries, to // check module_deps_no_self. { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target3, out); writer.Run(); @@ -2674,7 +2674,7 @@ // Then the executable that depends on it. { - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&depender, out); writer.Run(); @@ -2736,7 +2736,7 @@ target.SetToolchain(&toolchain_with_toc); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCBinaryTargetWriter writer(&target, out); writer.Run(); @@ -2786,7 +2786,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaBinaryTargetWriter writer(&target, out); writer.Run();
diff --git a/src/gn/ninja_copy_target_writer.cc b/src/gn/ninja_copy_target_writer.cc index 47657c0..5be189b 100644 --- a/src/gn/ninja_copy_target_writer.cc +++ b/src/gn/ninja_copy_target_writer.cc
@@ -8,6 +8,7 @@ #include "gn/general_tool.h" #include "gn/ninja_utils.h" #include "gn/output_file.h" +#include "gn/output_stream.h" #include "gn/scheduler.h" #include "gn/string_utils.h" #include "gn/substitution_list.h" @@ -16,7 +17,7 @@ #include "gn/toolchain.h" NinjaCopyTargetWriter::NinjaCopyTargetWriter(const Target* target, - std::ostream& out) + OutputStream& out) : NinjaTargetWriter(target, out) {} NinjaCopyTargetWriter::~NinjaCopyTargetWriter() = default; @@ -55,7 +56,7 @@ std::vector<OutputFile> output_files; WriteCopyRules(&output_files); - out_ << std::endl; + out_ << "\n"; WriteStampOrPhonyForTarget(output_files, std::vector<OutputFile>()); } @@ -124,6 +125,6 @@ path_output_.WriteFiles(out_, input_deps); path_output_.WriteFiles(out_, data_outs); } - out_ << std::endl; + out_ << "\n"; } }
diff --git a/src/gn/ninja_copy_target_writer.h b/src/gn/ninja_copy_target_writer.h index 95d50b4..0717fc8 100644 --- a/src/gn/ninja_copy_target_writer.h +++ b/src/gn/ninja_copy_target_writer.h
@@ -7,10 +7,12 @@ #include "gn/ninja_target_writer.h" +class OutputStream; + // Writes a .ninja file for a copy target type. class NinjaCopyTargetWriter : public NinjaTargetWriter { public: - NinjaCopyTargetWriter(const Target* target, std::ostream& out); + NinjaCopyTargetWriter(const Target* target, OutputStream& out); ~NinjaCopyTargetWriter() override; void Run() override;
diff --git a/src/gn/ninja_copy_target_writer_unittest.cc b/src/gn/ninja_copy_target_writer_unittest.cc index 1b5077a..3870ac3 100644 --- a/src/gn/ninja_copy_target_writer_unittest.cc +++ b/src/gn/ninja_copy_target_writer_unittest.cc
@@ -3,9 +3,9 @@ // found in the LICENSE file. #include <algorithm> -#include <sstream> #include "gn/ninja_copy_target_writer.h" +#include "gn/output_stream.h" #include "gn/target.h" #include "gn/test_with_scope.h" #include "util/test/test.h" @@ -27,7 +27,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCopyTargetWriter writer(&target, out); writer.Run(); @@ -56,7 +56,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCopyTargetWriter writer(&target, out); writer.Run(); @@ -81,7 +81,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCopyTargetWriter writer(&target, out); writer.Run(); @@ -113,7 +113,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCopyTargetWriter writer(&target, out); writer.Run();
diff --git a/src/gn/ninja_create_bundle_target_writer.cc b/src/gn/ninja_create_bundle_target_writer.cc index 09299c7..13fb1d8 100644 --- a/src/gn/ninja_create_bundle_target_writer.cc +++ b/src/gn/ninja_create_bundle_target_writer.cc
@@ -12,6 +12,7 @@ #include "gn/general_tool.h" #include "gn/ninja_utils.h" #include "gn/output_file.h" +#include "gn/output_stream.h" #include "gn/scheduler.h" #include "gn/substitution_writer.h" #include "gn/target.h" @@ -68,7 +69,7 @@ NinjaCreateBundleTargetWriter::NinjaCreateBundleTargetWriter( const Target* target, - std::ostream& out) + OutputStream& out) : NinjaTargetWriter(target, out) {} NinjaCreateBundleTargetWriter::~NinjaCreateBundleTargetWriter() = default; @@ -113,7 +114,7 @@ target_->bundle_data().GetBundleRootDirOutput(settings_))); out_ << ": " << BuiltinTool::kBuiltinToolPhony << " "; out_ << target_->dependency_output().value(); - out_ << std::endl; + out_ << "\n"; } std::string NinjaCreateBundleTargetWriter::WritePostProcessingRuleDefinition() { @@ -125,7 +126,7 @@ base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name); custom_rule_name.append("_post_processing_rule"); - out_ << "rule " << custom_rule_name << std::endl; + out_ << "rule " << custom_rule_name << "\n"; out_ << " command = "; path_output_.WriteFile(out_, settings_->build_settings()->python_path()); out_ << " "; @@ -139,10 +140,10 @@ out_ << " "; SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, out_); } - out_ << std::endl; - out_ << " description = POST PROCESSING " << target_label << std::endl; - out_ << " restat = 1" << std::endl; - out_ << std::endl; + out_ << "\n"; + out_ << " description = POST PROCESSING " << target_label << "\n"; + out_ << " restat = 1\n"; + out_ << "\n"; return custom_rule_name; } @@ -183,7 +184,7 @@ path_output_.WriteFiles(out_, order_only_deps); } - out_ << std::endl; + out_ << "\n"; } } @@ -224,7 +225,7 @@ out_ << " ||"; path_output_.WriteFiles(out_, order_only_deps); } - out_ << std::endl; + out_ << "\n"; return; } @@ -261,15 +262,14 @@ path_output_.WriteFiles(out_, order_only_deps); } - out_ << std::endl; + out_ << "\n"; - out_ << " product_type = " << target_->bundle_data().product_type() - << std::endl; + out_ << " product_type = " << target_->bundle_data().product_type() << "\n"; if (partial_info_plist != OutputFile()) { out_ << " partial_info_plist = "; path_output_.WriteFile(out_, partial_info_plist); - out_ << std::endl; + out_ << "\n"; } const std::vector<SubstitutionPattern>& flags = @@ -283,7 +283,7 @@ SubstitutionWriter::WriteWithNinjaVariables(flag, args_escape_options, out_); } - out_ << std::endl; + out_ << "\n"; } } @@ -325,7 +325,7 @@ path_output_.WriteFile(out_, target->dependency_output()); } } - out_ << std::endl; + out_ << "\n"; return xcassets_input_stamp_or_phony; } @@ -355,7 +355,7 @@ out_ << ": " << post_processing_rule_name; out_ << " | "; path_output_.WriteFile(out_, post_processing_input_stamp_file); - out_ << std::endl; + out_ << "\n"; } OutputFile @@ -411,6 +411,6 @@ out_ << " ||"; path_output_.WriteFiles(out_, order_only_deps); } - out_ << std::endl; + out_ << "\n"; return stamp_or_phony; }
diff --git a/src/gn/ninja_create_bundle_target_writer.h b/src/gn/ninja_create_bundle_target_writer.h index ee27557..ce68fa2 100644 --- a/src/gn/ninja_create_bundle_target_writer.h +++ b/src/gn/ninja_create_bundle_target_writer.h
@@ -12,7 +12,7 @@ // Writes a .ninja file for a bundle_data target type. class NinjaCreateBundleTargetWriter : public NinjaTargetWriter { public: - NinjaCreateBundleTargetWriter(const Target* target, std::ostream& out); + NinjaCreateBundleTargetWriter(const Target* target, OutputStream& out); ~NinjaCreateBundleTargetWriter() override; void Run() override;
diff --git a/src/gn/ninja_create_bundle_target_writer_unittest.cc b/src/gn/ninja_create_bundle_target_writer_unittest.cc index d79b719..917f047 100644 --- a/src/gn/ninja_create_bundle_target_writer_unittest.cc +++ b/src/gn/ninja_create_bundle_target_writer_unittest.cc
@@ -6,8 +6,8 @@ #include <algorithm> #include <memory> -#include <sstream> +#include "gn/output_stream.h" #include "gn/target.h" #include "gn/test_with_scope.h" #include "util/test/test.h" @@ -70,7 +70,7 @@ create_bundle.SetToolchain(setup.toolchain()); ASSERT_TRUE(create_bundle.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCreateBundleTargetWriter writer(&create_bundle, out); writer.Run(); @@ -119,7 +119,7 @@ create_bundle.SetToolchain(setup.toolchain()); ASSERT_TRUE(create_bundle.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCreateBundleTargetWriter writer(&create_bundle, out); writer.Run(); @@ -160,7 +160,7 @@ create_bundle.SetToolchain(setup.toolchain()); ASSERT_TRUE(create_bundle.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCreateBundleTargetWriter writer(&create_bundle, out); writer.Run(); @@ -224,7 +224,7 @@ create_bundle.SetToolchain(setup.toolchain()); ASSERT_TRUE(create_bundle.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCreateBundleTargetWriter writer(&create_bundle, out); writer.Run(); @@ -268,7 +268,7 @@ ASSERT_TRUE(create_bundle.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCreateBundleTargetWriter writer(&create_bundle, out); writer.Run(); @@ -388,7 +388,7 @@ create_bundle.SetToolchain(setup.toolchain()); ASSERT_TRUE(create_bundle.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCreateBundleTargetWriter writer(&create_bundle, out); writer.Run(); @@ -470,7 +470,7 @@ create_bundle.SetToolchain(setup.toolchain()); ASSERT_TRUE(create_bundle.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCreateBundleTargetWriter writer(&create_bundle, out); writer.Run(); @@ -553,7 +553,7 @@ create_bundle.SetToolchain(setup.toolchain()); ASSERT_TRUE(create_bundle.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaCreateBundleTargetWriter writer(&create_bundle, out); writer.Run();
diff --git a/src/gn/ninja_generated_file_target_writer.cc b/src/gn/ninja_generated_file_target_writer.cc index 6de8207..81ac730 100644 --- a/src/gn/ninja_generated_file_target_writer.cc +++ b/src/gn/ninja_generated_file_target_writer.cc
@@ -6,6 +6,7 @@ #include "gn/output_conversion.h" #include "gn/output_file.h" +#include "gn/output_stream.h" #include "gn/scheduler.h" #include "gn/settings.h" #include "gn/string_output_buffer.h" @@ -15,7 +16,7 @@ NinjaGeneratedFileTargetWriter::NinjaGeneratedFileTargetWriter( const Target* target, - std::ostream& out) + OutputStream& out) : NinjaTargetWriter(target, out) {} NinjaGeneratedFileTargetWriter::~NinjaGeneratedFileTargetWriter() = default; @@ -89,9 +90,8 @@ // Compute output. StringOutputBuffer storage; - std::ostream out(&storage); - ConvertValueToOutput(settings_, contents, target_->output_conversion(), out, - &err); + ConvertValueToOutput(settings_, contents, target_->output_conversion(), + storage, &err); if (err.has_error()) { g_scheduler->FailWithError(err);
diff --git a/src/gn/ninja_generated_file_target_writer.h b/src/gn/ninja_generated_file_target_writer.h index 3103388..90e64d4 100644 --- a/src/gn/ninja_generated_file_target_writer.h +++ b/src/gn/ninja_generated_file_target_writer.h
@@ -10,7 +10,7 @@ // Writes a .ninja file for a group target type. class NinjaGeneratedFileTargetWriter : public NinjaTargetWriter { public: - NinjaGeneratedFileTargetWriter(const Target* target, std::ostream& out); + NinjaGeneratedFileTargetWriter(const Target* target, OutputStream& out); ~NinjaGeneratedFileTargetWriter() override; void Run() override;
diff --git a/src/gn/ninja_generated_file_target_writer_unittest.cc b/src/gn/ninja_generated_file_target_writer_unittest.cc index 481db80..119f4ea 100644 --- a/src/gn/ninja_generated_file_target_writer_unittest.cc +++ b/src/gn/ninja_generated_file_target_writer_unittest.cc
@@ -4,6 +4,7 @@ #include "gn/ninja_generated_file_target_writer.h" +#include "gn/output_stream.h" #include "gn/source_file.h" #include "gn/target.h" #include "gn/test_with_scheduler.h" @@ -58,7 +59,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)) << err.message(); - std::ostringstream out; + StringOutputStream out; NinjaGeneratedFileTargetWriter writer(&target, out); writer.Run();
diff --git a/src/gn/ninja_group_target_writer.cc b/src/gn/ninja_group_target_writer.cc index 7db1a3a..3dde553 100644 --- a/src/gn/ninja_group_target_writer.cc +++ b/src/gn/ninja_group_target_writer.cc
@@ -11,7 +11,7 @@ #include "gn/target.h" NinjaGroupTargetWriter::NinjaGroupTargetWriter(const Target* target, - std::ostream& out) + OutputStream& out) : NinjaTargetWriter(target, out) {} NinjaGroupTargetWriter::~NinjaGroupTargetWriter() = default;
diff --git a/src/gn/ninja_group_target_writer.h b/src/gn/ninja_group_target_writer.h index 7a3f211..b286bce 100644 --- a/src/gn/ninja_group_target_writer.h +++ b/src/gn/ninja_group_target_writer.h
@@ -10,7 +10,7 @@ // Writes a .ninja file for a group target type. class NinjaGroupTargetWriter : public NinjaTargetWriter { public: - NinjaGroupTargetWriter(const Target* target, std::ostream& out); + NinjaGroupTargetWriter(const Target* target, OutputStream& out); ~NinjaGroupTargetWriter() override; void Run() override;
diff --git a/src/gn/ninja_group_target_writer_unittest.cc b/src/gn/ninja_group_target_writer_unittest.cc index ec9f72d..e61b2f8 100644 --- a/src/gn/ninja_group_target_writer_unittest.cc +++ b/src/gn/ninja_group_target_writer_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "gn/ninja_group_target_writer.h" +#include "gn/output_stream.h" #include "gn/target.h" #include "gn/test_with_scope.h" #include "util/test/test.h" @@ -49,7 +50,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaGroupTargetWriter writer(&target, out); writer.Run();
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc index ba6b416..e4aafe8 100644 --- a/src/gn/ninja_rust_binary_target_writer.cc +++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -4,8 +4,6 @@ #include "gn/ninja_rust_binary_target_writer.h" -#include <sstream> - #include "base/strings/string_util.h" #include "gn/deps_iterator.h" #include "gn/filesystem_utils.h" @@ -29,16 +27,16 @@ void WriteVar(const char* name, const std::string& value, EscapeOptions opts, - std::ostream& out) { + OutputStream& out) { out << name << " = "; EscapeStringToStream(out, value, opts); - out << std::endl; + out << "\n"; } void WriteCrateVars(const Target* target, const Tool* tool, EscapeOptions opts, - std::ostream& out) { + OutputStream& out) { WriteVar(kRustSubstitutionCrateName.ninja_name, target->rust_values().crate_name(), opts, out); @@ -100,7 +98,7 @@ } // namespace NinjaRustBinaryTargetWriter::NinjaRustBinaryTargetWriter(const Target* target, - std::ostream& out) + OutputStream& out) : NinjaBinaryTargetWriter(target, out), tool_(target->toolchain()->GetToolForTargetFinalOutputAsRust(target)) {} @@ -265,7 +263,7 @@ out_ << " "; path_output_.WriteFile(out_, OutputFile(settings_->build_settings(), data)); } - out_ << std::endl; + out_ << "\n"; } void NinjaRustBinaryTargetWriter::WriteExternsAndDeps( @@ -353,7 +351,7 @@ } } - out_ << std::endl; + out_ << "\n"; out_ << " rustdeps ="; for (const SourceDir& dir : private_extern_dirs) { @@ -385,11 +383,11 @@ WriteFrameworks(out_, tool_); WriteSwiftModules(out_, tool_, swiftmodules); - out_ << std::endl; + out_ << "\n"; out_ << " ldflags ="; // If rustc will invoke a linker, linker flags need to be forwarded through to // the linker. WriteCustomLinkerFlags(out_, tool_); - out_ << std::endl; + out_ << "\n"; }
diff --git a/src/gn/ninja_rust_binary_target_writer.h b/src/gn/ninja_rust_binary_target_writer.h index 83e1203..7966fc7 100644 --- a/src/gn/ninja_rust_binary_target_writer.h +++ b/src/gn/ninja_rust_binary_target_writer.h
@@ -14,7 +14,7 @@ // library, or a static library). class NinjaRustBinaryTargetWriter : public NinjaBinaryTargetWriter { public: - NinjaRustBinaryTargetWriter(const Target* target, std::ostream& out); + NinjaRustBinaryTargetWriter(const Target* target, OutputStream& out); ~NinjaRustBinaryTargetWriter() override; void Run() override;
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc index 461cbd8..2497ac6 100644 --- a/src/gn/ninja_rust_binary_target_writer_unittest.cc +++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -6,6 +6,7 @@ #include "gn/config.h" #include "gn/label_ptr.h" +#include "gn/output_stream.h" #include "gn/pool.h" #include "gn/rust_values.h" #include "gn/scheduler.h" @@ -49,7 +50,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -104,7 +105,7 @@ ASSERT_TRUE(private_rlib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&private_rlib, out); writer.Run(); @@ -146,7 +147,7 @@ ASSERT_TRUE(far_public_rlib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&far_public_rlib, out); writer.Run(); @@ -188,7 +189,7 @@ ASSERT_TRUE(public_rlib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&public_rlib, out); writer.Run(); @@ -244,7 +245,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -297,7 +298,7 @@ ASSERT_TRUE(private_inside_dylib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&private_inside_dylib, out); writer.Run(); @@ -338,7 +339,7 @@ ASSERT_TRUE(inside_dylib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&inside_dylib, out); writer.Run(); @@ -382,7 +383,7 @@ ASSERT_TRUE(dylib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&dylib, out); writer.Run(); @@ -455,7 +456,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -507,7 +508,7 @@ ASSERT_TRUE(procmacro.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&procmacro, out); writer.Run(); @@ -563,7 +564,7 @@ ASSERT_TRUE(rlib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&rlib, out); writer.Run(); @@ -610,7 +611,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -702,7 +703,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -805,7 +806,7 @@ ASSERT_TRUE(nonrust.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&nonrust, out); writer.Run(); @@ -852,7 +853,7 @@ ASSERT_TRUE(nonrust_only.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&nonrust_only, out); writer.Run(); @@ -893,7 +894,7 @@ ASSERT_TRUE(rstaticlib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&rstaticlib, out); writer.Run(); @@ -1065,7 +1066,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1131,7 +1132,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1198,7 +1199,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1298,7 +1299,7 @@ ASSERT_TRUE(rlib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&rlib, out); writer.Run(); @@ -1382,7 +1383,7 @@ ASSERT_TRUE(procmacro.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&procmacro, out); writer.Run(); @@ -1429,7 +1430,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1475,7 +1476,7 @@ ASSERT_TRUE(rlib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&rlib, out); writer.Run(); @@ -1524,7 +1525,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1579,7 +1580,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1628,7 +1629,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1676,7 +1677,7 @@ cdylib.SetToolchain(setup.toolchain()); ASSERT_TRUE(cdylib.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&cdylib, out); writer.Run(); const char expected[] = @@ -1716,7 +1717,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1793,7 +1794,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1878,7 +1879,7 @@ ASSERT_TRUE(target.OnResolved(&err)); { - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -1932,7 +1933,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaBinaryTargetWriter writer(&target, out); writer.Run(); @@ -2005,7 +2006,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run(); @@ -2063,7 +2064,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream out; + StringOutputStream out; NinjaRustBinaryTargetWriter writer(&target, out); writer.Run();
diff --git a/src/gn/ninja_target_command_util.cc b/src/gn/ninja_target_command_util.cc index a691ae3..4b78677 100644 --- a/src/gn/ninja_target_command_util.cc +++ b/src/gn/ninja_target_command_util.cc
@@ -50,7 +50,7 @@ const, EscapeOptions flag_escape_options, PathOutput& path_output, - std::ostream& out, + OutputStream& out, bool write_substitution, bool indent) { if (!target->toolchain()->substitution_bits().used.count(subst_enum)) @@ -103,7 +103,7 @@ } if (write_substitution) - out << std::endl; + out << "\n"; } void GetPCHOutputFiles(const Target* target,
diff --git a/src/gn/ninja_target_command_util.h b/src/gn/ninja_target_command_util.h index 93666fb..e754ef7 100644 --- a/src/gn/ninja_target_command_util.h +++ b/src/gn/ninja_target_command_util.h
@@ -12,6 +12,7 @@ #include "gn/escape.h" #include "gn/filesystem_utils.h" #include "gn/frameworks_utils.h" +#include "gn/output_stream.h" #include "gn/path_output.h" #include "gn/target.h" #include "gn/toolchain.h" @@ -21,7 +22,7 @@ DefineWriter() { options.mode = ESCAPE_NINJA_COMMAND; } DefineWriter(EscapingMode mode) { options.mode = mode; } - void operator()(const std::string& s, std::ostream& out) const { + void operator()(const std::string& s, OutputStream& out) const { out << " "; EscapeStringToStream(out, "-D" + s, options); } @@ -35,8 +36,8 @@ ~FrameworkDirsWriter() = default; - void operator()(const SourceDir& d, std::ostream& out) const { - std::ostringstream path_out; + void operator()(const SourceDir& d, OutputStream& out) const { + StringOutputStream path_out; path_output_.WriteDir(path_out, d, PathOutput::DIR_NO_LAST_SLASH); const std::string& path = path_out.str(); if (path[0] == '"') @@ -57,7 +58,7 @@ options_.mode = mode; } - void operator()(const std::string& s, std::ostream& out) const { + void operator()(const std::string& s, OutputStream& out) const { out << " " << tool_switch_; std::string_view framework_name = GetFrameworkName(s); EscapeStringToStream(out, framework_name, options_); @@ -71,8 +72,8 @@ explicit IncludeWriter(PathOutput& path_output) : path_output_(path_output) {} ~IncludeWriter() = default; - void operator()(const SourceDir& d, std::ostream& out) const { - std::ostringstream path_out; + void operator()(const SourceDir& d, OutputStream& out) const { + StringOutputStream path_out; path_output_.WriteDir(path_out, d, PathOutput::DIR_NO_LAST_SLASH); const std::string& path = path_out.str(); if (path[0] == '"') @@ -101,7 +102,7 @@ const, EscapeOptions flag_escape_options, PathOutput& path_output, - std::ostream& out, + OutputStream& out, bool write_substitution = true, bool indent = false);
diff --git a/src/gn/ninja_target_command_util_unittest.cc b/src/gn/ninja_target_command_util_unittest.cc index 8da62d3..6b2a9f2 100644 --- a/src/gn/ninja_target_command_util_unittest.cc +++ b/src/gn/ninja_target_command_util_unittest.cc
@@ -5,8 +5,8 @@ #include "gn/ninja_target_command_util.h" #include <algorithm> -#include <sstream> +#include "gn/output_stream.h" #include "util/build_config.h" #include "util/test/test.h" @@ -16,7 +16,7 @@ // the generated output as a string. template <typename Writer, typename Item> std::string FormatWithWriter(Writer writer, std::vector<Item> items) { - std::ostringstream out; + StringOutputStream out; for (const Item& item : items) { writer(item, out); } @@ -36,7 +36,7 @@ // see the difference in the error message (by default the error message // would just be "formatted == expected"). if (formatted != expected) { - std::ostringstream stream; + StringOutputStream stream; stream << '"' << expected << "\" == \"" << formatted << '"'; std::string message = stream.str();
diff --git a/src/gn/ninja_target_writer.cc b/src/gn/ninja_target_writer.cc index 01a1407..163840f 100644 --- a/src/gn/ninja_target_writer.cc +++ b/src/gn/ninja_target_writer.cc
@@ -4,8 +4,6 @@ #include "gn/ninja_target_writer.h" -#include <sstream> - #include "base/files/file_util.h" #include "base/strings/string_util.h" #include "gn/builtin_tool.h" @@ -25,6 +23,7 @@ #include "gn/ninja_target_command_util.h" #include "gn/ninja_utils.h" #include "gn/output_file.h" +#include "gn/output_stream.h" #include "gn/rust_substitution_type.h" #include "gn/scheduler.h" #include "gn/string_output_buffer.h" @@ -33,7 +32,7 @@ #include "gn/target.h" #include "gn/trace.h" -NinjaTargetWriter::NinjaTargetWriter(const Target* target, std::ostream& out) +NinjaTargetWriter::NinjaTargetWriter(const Target* target, OutputStream& out) : settings_(target->settings()), target_(target), out_(out), @@ -111,8 +110,7 @@ // It's ridiculously faster to write to a string and then write that to // disk in one operation than to use an fstream here. - StringOutputBuffer storage; - std::ostream rules(&storage); + StringOutputBuffer rules; // Call out to the correct sub-type of writer. Binary targets need to be // written to separate files for compiler flag scoping, but other target @@ -176,7 +174,7 @@ SourceFile ninja_file = GetNinjaFileForTarget(target); base::FilePath full_ninja_file = settings->build_settings()->GetFullPath(ninja_file); - storage.WriteToFileIfChanged(full_ninja_file, nullptr); + rules.WriteToFileIfChanged(full_ninja_file, nullptr); EscapeOptions options; options.mode = ESCAPE_NINJA; @@ -191,7 +189,7 @@ } // No separate file required, just return the rules. - return storage.str(); + return rules.str(); } void NinjaTargetWriter::WriteEscapedSubstitution(const Substitution* type) { @@ -201,7 +199,7 @@ out_ << type->ninja_name << " = "; EscapeStringToStream( out_, SubstitutionWriter::GetTargetSubstitution(target_, type), opts); - out_ << std::endl; + out_ << "\n"; } void NinjaTargetWriter::WriteSharedVars(const SubstitutionBits& bits) { @@ -258,7 +256,7 @@ // If we wrote any vars, separate them from the rest of the file that follows // with a blank line. if (written_anything) - out_ << std::endl; + out_ << "\n"; } void NinjaTargetWriter::WriteCCompilerVars(const SubstitutionBits& bits, @@ -272,7 +270,7 @@ RecursiveTargetConfigToStream<std::string>(kRecursiveWriterSkipDuplicates, target_, &ConfigValues::defines, DefineWriter(), out_); - out_ << std::endl; + out_ << "\n"; } // Framework search path. @@ -290,7 +288,7 @@ FrameworkDirsWriter(framework_dirs_output, tool->framework_dir_switch()), out_); - out_ << std::endl; + out_ << "\n"; } // Include directories. @@ -304,7 +302,7 @@ RecursiveTargetConfigToStream<SourceDir>( kRecursiveWriterSkipDuplicates, target_, &ConfigValues::include_dirs, IncludeWriter(include_path_output), out_); - out_ << std::endl; + out_ << "\n"; } bool has_precompiled_headers = @@ -370,7 +368,7 @@ out_ << " "; out_ << CSubstitutionSwiftModuleName.ninja_name << " = "; EscapeStringToStream(out_, target_->swift_values().module_name(), opts); - out_ << std::endl; + out_ << "\n"; } if (bits.used.count(&CSubstitutionSwiftBridgeHeader)) { @@ -382,7 +380,7 @@ } else { out_ << R"("")"; } - out_ << std::endl; + out_ << "\n"; } if (bits.used.count(&CSubstitutionSwiftModuleDirs)) { @@ -402,7 +400,7 @@ for (const SourceDir& swiftmodule_dir : swiftmodule_dirs) { swiftmodule_path_writer(swiftmodule_dir, out_); } - out_ << std::endl; + out_ << "\n"; } WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, @@ -621,5 +619,5 @@ out_ << " ||"; path_output_.WriteFiles(out_, order_only_deps); } - out_ << std::endl; + out_ << "\n"; }
diff --git a/src/gn/ninja_target_writer.h b/src/gn/ninja_target_writer.h index 68bc0a3..4ae2515 100644 --- a/src/gn/ninja_target_writer.h +++ b/src/gn/ninja_target_writer.h
@@ -12,6 +12,7 @@ #include "gn/substitution_type.h" class OutputFile; +class OutputStream; class Settings; class Target; struct SubstitutionBits; @@ -20,7 +21,7 @@ // generated by the NinjaBuildWriter. class NinjaTargetWriter { public: - NinjaTargetWriter(const Target* target, std::ostream& out); + NinjaTargetWriter(const Target* target, OutputStream& out); virtual ~NinjaTargetWriter(); // Returns a ResolvedTargetData that can be used to retrieve information @@ -101,7 +102,7 @@ const Settings* settings_; // Non-owning. const Target* target_; // Non-owning. - std::ostream& out_; + OutputStream& out_; PathOutput path_output_; // Write a Ninja output file to out_, and also add it to |*ninja_outputs_|
diff --git a/src/gn/ninja_target_writer_unittest.cc b/src/gn/ninja_target_writer_unittest.cc index ae691d7..d2472a9 100644 --- a/src/gn/ninja_target_writer_unittest.cc +++ b/src/gn/ninja_target_writer_unittest.cc
@@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <sstream> - -#include "gn/ninja_action_target_writer.h" #include "gn/ninja_target_writer.h" +#include "gn/ninja_action_target_writer.h" +#include "gn/output_stream.h" #include "gn/target.h" #include "gn/test_with_scope.h" #include "util/test/test.h" @@ -16,7 +15,7 @@ public: TestingNinjaTargetWriter(const Target* target, const Toolchain* toolchain, - std::ostream& out) + OutputStream& out) : NinjaTargetWriter(target, out) {} void Run() override {} @@ -44,7 +43,7 @@ base_target.action_values().set_script(SourceFile("//foo/script.py")); ASSERT_TRUE(base_target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; TestingNinjaTargetWriter writer(&base_target, setup.toolchain(), stream); const auto* resolved_ptr = &writer.resolved(); @@ -67,7 +66,7 @@ ASSERT_TRUE(base_target.OnResolved(&err)); ResolvedTargetData resolved; - std::ostringstream stream; + StringOutputStream stream; TestingNinjaTargetWriter writer(&base_target, setup.toolchain(), stream); writer.SetResolvedTargetData(&resolved); @@ -111,7 +110,7 @@ // Input deps for the base (should be only the script itself). { - std::ostringstream stream; + StringOutputStream stream; TestingNinjaTargetWriter writer(&base_target, setup.toolchain(), stream); std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep( std::vector<const Target*>(), 10u); @@ -125,7 +124,7 @@ // Input deps for the target (should depend on the base). { - std::ostringstream stream; + StringOutputStream stream; TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream); std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep( std::vector<const Target*>(), 10u); @@ -137,7 +136,7 @@ } { - std::ostringstream stream; + StringOutputStream stream; NinjaActionTargetWriter writer(&action, stream); writer.Run(); EXPECT_EQ( @@ -156,7 +155,7 @@ // Input deps for action which should depend on the base since its a hard dep // that is a (indirect) dependency, as well as the the action source. { - std::ostringstream stream; + StringOutputStream stream; TestingNinjaTargetWriter writer(&action, setup.toolchain(), stream); std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep( std::vector<const Target*>(), 10u); @@ -208,7 +207,7 @@ // Input deps for the base (should be only the script itself). { - std::ostringstream stream; + StringOutputStream stream; TestingNinjaTargetWriter writer(&base_target, setup.toolchain(), stream); std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep( std::vector<const Target*>(), 10u); @@ -222,7 +221,7 @@ // Input deps for the target (should depend on the base). { - std::ostringstream stream; + StringOutputStream stream; TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream); std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep( std::vector<const Target*>(), 10u); @@ -234,7 +233,7 @@ } { - std::ostringstream stream; + StringOutputStream stream; NinjaActionTargetWriter writer(&action, stream); writer.Run(); EXPECT_EQ( @@ -253,7 +252,7 @@ // Input deps for action which should depend on the base since its a hard dep // that is a (indirect) dependency, as well as the the action source. { - std::ostringstream stream; + StringOutputStream stream; TestingNinjaTargetWriter writer(&action, setup.toolchain(), stream); std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep( std::vector<const Target*>(), 10u); @@ -289,7 +288,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream); std::vector<OutputFile> dep = writer.WriteInputDepsStampOrPhonyAndGetDep( std::vector<const Target*>(), 10u);
diff --git a/src/gn/ninja_toolchain_writer.cc b/src/gn/ninja_toolchain_writer.cc index 917d068..4d68eeb 100644 --- a/src/gn/ninja_toolchain_writer.cc +++ b/src/gn/ninja_toolchain_writer.cc
@@ -4,8 +4,6 @@ #include "gn/ninja_toolchain_writer.h" -#include <fstream> - #include "base/files/file_util.h" #include "base/strings/stringize_macros.h" #include "gn/build_settings.h" @@ -14,6 +12,7 @@ #include "gn/filesystem_utils.h" #include "gn/general_tool.h" #include "gn/ninja_utils.h" +#include "gn/output_stream.h" #include "gn/pool.h" #include "gn/settings.h" #include "gn/substitution_writer.h" @@ -29,7 +28,7 @@ NinjaToolchainWriter::NinjaToolchainWriter(const Settings* settings, const Toolchain* toolchain, - std::ostream& out) + OutputStream& out) : settings_(settings), toolchain_(toolchain), out_(out), @@ -50,7 +49,7 @@ } WriteToolRule(tool.second.get(), rule_prefix); } - out_ << std::endl; + out_ << "\n"; for (const auto& pair : rules) out_ << pair.second; @@ -68,9 +67,7 @@ base::CreateDirectory(ninja_file.DirName()); - std::ofstream file; - file.open(FilePathToUTF8(ninja_file).c_str(), - std::ios_base::out | std::ios_base::binary); + FileOutputStream file(FilePathToUTF8(ninja_file).c_str()); if (file.fail()) return false; @@ -81,7 +78,7 @@ void NinjaToolchainWriter::WriteToolRule(Tool* tool, const std::string& rule_prefix) { - out_ << "rule " << rule_prefix << tool->name() << std::endl; + out_ << "rule " << rule_prefix << tool->name() << "\n"; // Rules explicitly include shell commands, so don't try to escape. EscapeOptions options; @@ -99,26 +96,26 @@ // GCC-style deps require a depfile. if (!c_tool->depfile().empty()) { WriteRulePattern("depfile", tool->depfile(), options); - out_ << kIndent << "deps = gcc" << std::endl; + out_ << kIndent << "deps = gcc\n"; } } else if (c_tool->depsformat() == CTool::DEPS_MSVC) { // MSVC deps don't have a depfile. - out_ << kIndent << "deps = msvc" << std::endl; + out_ << kIndent << "deps = msvc\n"; } } else if (!tool->depfile().empty()) { WriteRulePattern("depfile", tool->depfile(), options); - out_ << kIndent << "deps = gcc" << std::endl; + out_ << kIndent << "deps = gcc\n"; } // Use pool is specified. if (tool->pool().ptr) { std::string pool_name = tool->pool().ptr->GetNinjaName(settings_->default_toolchain_label()); - out_ << kIndent << "pool = " << pool_name << std::endl; + out_ << kIndent << "pool = " << pool_name << "\n"; } if (tool->restat()) - out_ << kIndent << "restat = 1" << std::endl; + out_ << kIndent << "restat = 1\n"; } void NinjaToolchainWriter::WriteRulePattern(const char* name, @@ -128,7 +125,7 @@ return; out_ << kIndent << name << " = "; SubstitutionWriter::WriteWithNinjaVariables(pattern, options, out_); - out_ << std::endl; + out_ << "\n"; } void NinjaToolchainWriter::WriteCommandRulePattern( @@ -141,5 +138,5 @@ if (!launcher.empty()) out_ << launcher << " "; SubstitutionWriter::WriteWithNinjaVariables(command, options, out_); - out_ << std::endl; + out_ << "\n"; }
diff --git a/src/gn/ninja_toolchain_writer.h b/src/gn/ninja_toolchain_writer.h index cbc7c68..b7fd2ee 100644 --- a/src/gn/ninja_toolchain_writer.h +++ b/src/gn/ninja_toolchain_writer.h
@@ -34,7 +34,7 @@ NinjaToolchainWriter(const Settings* settings, const Toolchain* toolchain, - std::ostream& out); + OutputStream& out); ~NinjaToolchainWriter(); void Run(const std::vector<NinjaWriter::TargetRulePair>& extra_rules); @@ -51,7 +51,7 @@ const Settings* settings_; const Toolchain* toolchain_; - std::ostream& out_; + OutputStream& out_; PathOutput path_output_; NinjaToolchainWriter(const NinjaToolchainWriter&) = delete;
diff --git a/src/gn/ninja_toolchain_writer_unittest.cc b/src/gn/ninja_toolchain_writer_unittest.cc index 863c174..56f22db 100644 --- a/src/gn/ninja_toolchain_writer_unittest.cc +++ b/src/gn/ninja_toolchain_writer_unittest.cc
@@ -2,16 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <sstream> - #include "gn/ninja_toolchain_writer.h" +#include "gn/output_stream.h" #include "gn/test_with_scope.h" #include "util/test/test.h" TEST(NinjaToolchainWriter, WriteToolRule) { TestWithScope setup; - std::ostringstream stream; + StringOutputStream stream; NinjaToolchainWriter writer(setup.settings(), setup.toolchain(), stream); writer.WriteToolRule(setup.toolchain()->GetTool(CTool::kCToolCc), std::string("prefix_")); @@ -26,7 +25,7 @@ TEST(NinjaToolchainWriter, WriteToolRuleWithLauncher) { TestWithScope setup; - std::ostringstream stream; + StringOutputStream stream; NinjaToolchainWriter writer(setup.settings(), setup.toolchain(), stream); writer.WriteToolRule(setup.toolchain()->GetTool(CTool::kCToolCxx), std::string("prefix_"));
diff --git a/src/gn/output_conversion.cc b/src/gn/output_conversion.cc index 971e740..10b397c 100644 --- a/src/gn/output_conversion.cc +++ b/src/gn/output_conversion.cc
@@ -4,28 +4,29 @@ #include "gn/output_conversion.h" +#include "gn/output_stream.h" #include "gn/settings.h" #include "gn/value.h" namespace { -void ToString(const Value& output, std::ostream& out) { +void ToString(const Value& output, OutputStream& out) { out << output.ToString(false); } -void ToStringQuoted(const Value& output, std::ostream& out) { +void ToStringQuoted(const Value& output, OutputStream& out) { out << "\"" << output.ToString(false) << "\""; } -void Indent(int indent, std::ostream& out) { +void Indent(int indent, OutputStream& out) { for (int i = 0; i < indent; ++i) out << " "; } // Forward declare so it can be used recursively. -void RenderScopeToJSON(const Value& output, std::ostream& out, int indent); +void RenderScopeToJSON(const Value& output, OutputStream& out, int indent); -void RenderListToJSON(const Value& output, std::ostream& out, int indent) { +void RenderListToJSON(const Value& output, OutputStream& out, int indent) { assert(indent > 0); bool first = true; out << "[\n"; @@ -46,7 +47,7 @@ out << "]"; } -void RenderScopeToJSON(const Value& output, std::ostream& out, int indent) { +void RenderScopeToJSON(const Value& output, OutputStream& out, int indent) { assert(indent > 0); Scope::KeyValueMap scope_values; output.scope_value()->GetCurrentScopeValues(&scope_values); @@ -70,14 +71,14 @@ out << "}"; } -void OutputListLines(const Value& output, std::ostream& out) { +void OutputListLines(const Value& output, OutputStream& out) { assert(output.type() == Value::LIST); const std::vector<Value>& list = output.list_value(); for (const auto& cur : list) out << cur.ToString(false) << "\n"; } -void OutputString(const Value& output, std::ostream& out) { +void OutputString(const Value& output, OutputStream& out) { if (output.type() == Value::NONE) return; if (output.type() == Value::STRING) { @@ -87,7 +88,7 @@ ToStringQuoted(output, out); } -void OutputValue(const Value& output, std::ostream& out) { +void OutputValue(const Value& output, OutputStream& out) { if (output.type() == Value::NONE) return; if (output.type() == Value::STRING) { @@ -99,7 +100,7 @@ // The direct Value::ToString call wraps the scope in '{}', which we don't want // here for the top-level scope being output. -void OutputScope(const Value& output, std::ostream& out) { +void OutputScope(const Value& output, OutputStream& out) { Scope::KeyValueMap scope_values; output.scope_value()->GetCurrentScopeValues(&scope_values); for (const auto& pair : scope_values) { @@ -107,14 +108,14 @@ } } -void OutputDefault(const Value& output, std::ostream& out) { +void OutputDefault(const Value& output, OutputStream& out) { if (output.type() == Value::LIST) OutputListLines(output, out); else ToString(output, out); } -void OutputJSON(const Value& output, std::ostream& out) { +void OutputJSON(const Value& output, OutputStream& out) { if (output.type() == Value::SCOPE) { RenderScopeToJSON(output, out, /*indent=*/1); return; @@ -129,7 +130,7 @@ void DoConvertValueToOutput(const Value& output, const std::string& output_conversion, const Value& original_output_conversion, - std::ostream& out, + OutputStream& out, Err* err) { if (output_conversion == "") { OutputDefault(output, out); @@ -163,7 +164,7 @@ void ConvertValueToOutput(const Settings* settings, const Value& output, const Value& output_conversion, - std::ostream& out, + OutputStream& out, Err* err) { if (output_conversion.type() == Value::NONE) { OutputDefault(output, out);
diff --git a/src/gn/output_conversion.h b/src/gn/output_conversion.h index 09ca254..3e72fe1 100644 --- a/src/gn/output_conversion.h +++ b/src/gn/output_conversion.h
@@ -9,6 +9,7 @@ #include <string> class Err; +class OutputStream; class Settings; class Value; @@ -20,7 +21,7 @@ void ConvertValueToOutput(const Settings* settings, const Value& output, const Value& output_conversion_value, - std::ostream& out, + OutputStream& out, Err* err); #endif // TOOLS_GN_OUTPUT_CONVERSION_H_
diff --git a/src/gn/output_conversion_unittest.cc b/src/gn/output_conversion_unittest.cc index 43fdad5..44fc1da 100644 --- a/src/gn/output_conversion_unittest.cc +++ b/src/gn/output_conversion_unittest.cc
@@ -4,10 +4,9 @@ #include "gn/output_conversion.h" -#include <sstream> - #include "gn/err.h" #include "gn/input_conversion.h" +#include "gn/output_stream.h" #include "gn/scope.h" #include "gn/template.h" #include "gn/test_with_scheduler.h" @@ -38,7 +37,7 @@ output.list_value().push_back(Value(nullptr, "foo")); output.list_value().push_back(Value(nullptr, "")); output.list_value().push_back(Value(nullptr, "bar")); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, "list lines"), result, &err); @@ -49,7 +48,7 @@ TEST_F(OutputConversionTest, String) { Err err; Value output(nullptr, "foo bar"); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, "string"), result, &err); @@ -60,7 +59,7 @@ TEST_F(OutputConversionTest, StringInt) { Err err; Value output(nullptr, int64_t(6)); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, "string"), result, &err); @@ -71,7 +70,7 @@ TEST_F(OutputConversionTest, StringBool) { Err err; Value output(nullptr, true); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, "string"), result, &err); @@ -85,7 +84,7 @@ output.list_value().push_back(Value(nullptr, "foo")); output.list_value().push_back(Value(nullptr, "bar")); output.list_value().push_back(Value(nullptr, int64_t(6))); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, "string"), result, &err); @@ -103,7 +102,7 @@ std::string_view private_var_name("_private"); new_scope->SetValue(private_var_name, value, nullptr); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), Value(nullptr, std::move(new_scope)), Value(nullptr, "string"), result, &err); EXPECT_FALSE(err.has_error()); @@ -113,7 +112,7 @@ TEST_F(OutputConversionTest, ValueString) { Err err; Value output(nullptr, "foo bar"); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, "value"), result, &err); @@ -124,7 +123,7 @@ TEST_F(OutputConversionTest, ValueInt) { Err err; Value output(nullptr, int64_t(6)); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, "value"), result, &err); @@ -135,7 +134,7 @@ TEST_F(OutputConversionTest, ValueBool) { Err err; Value output(nullptr, true); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, "value"), result, &err); @@ -149,7 +148,7 @@ output.list_value().push_back(Value(nullptr, "foo")); output.list_value().push_back(Value(nullptr, "bar")); output.list_value().push_back(Value(nullptr, int64_t(6))); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, "value"), result, &err); @@ -167,7 +166,7 @@ std::string_view private_var_name("_private"); new_scope->SetValue(private_var_name, value, nullptr); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), Value(nullptr, std::move(new_scope)), Value(nullptr, "value"), result, &err); EXPECT_FALSE(err.has_error()); @@ -208,7 +207,7 @@ ] } })*"); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), Value(nullptr, std::move(new_scope)), Value(nullptr, "json"), result, &err); EXPECT_FALSE(err.has_error()); @@ -217,7 +216,7 @@ TEST_F(OutputConversionTest, ValueEmpty) { Err err; - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), Value(), Value(nullptr, ""), result, &err); EXPECT_FALSE(err.has_error()); EXPECT_EQ(result.str(), "<void>"); @@ -226,7 +225,7 @@ TEST_F(OutputConversionTest, DefaultValue) { Err err; Value output(nullptr, "foo bar"); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, ""), result, &err); EXPECT_FALSE(err.has_error()); @@ -240,7 +239,7 @@ output.list_value().push_back(Value(nullptr, "foo")); output.list_value().push_back(Value(nullptr, "")); output.list_value().push_back(Value(nullptr, "bar")); - std::ostringstream result; + StringOutputStream result; ConvertValueToOutput(settings(), output, Value(nullptr, ""), result, &err); EXPECT_FALSE(err.has_error()); @@ -254,7 +253,7 @@ Value(nullptr, "string"), &err); EXPECT_FALSE(err.has_error()); - std::ostringstream reverse; + StringOutputStream reverse; ConvertValueToOutput(settings(), result, Value(nullptr, "string"), reverse, &err); EXPECT_FALSE(err.has_error()); @@ -269,7 +268,7 @@ Value(nullptr, "list lines"), &err); EXPECT_FALSE(err.has_error()); - std::ostringstream reverse; + StringOutputStream reverse; ConvertValueToOutput(settings(), result, Value(nullptr, "list lines"), reverse, &err); EXPECT_FALSE(err.has_error()); @@ -284,7 +283,7 @@ Value(nullptr, "value"), &err); EXPECT_FALSE(err.has_error()); - std::ostringstream reverse; + StringOutputStream reverse; ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse, &err); EXPECT_FALSE(err.has_error()); @@ -299,7 +298,7 @@ Value(nullptr, "value"), &err); EXPECT_FALSE(err.has_error()); - std::ostringstream reverse; + StringOutputStream reverse; ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse, &err); EXPECT_FALSE(err.has_error()); @@ -314,7 +313,7 @@ Value(nullptr, "value"), &err); EXPECT_FALSE(err.has_error()); - std::ostringstream reverse; + StringOutputStream reverse; ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse, &err); EXPECT_FALSE(err.has_error()); @@ -329,7 +328,7 @@ Value(nullptr, "scope"), &err); EXPECT_FALSE(err.has_error()); - std::ostringstream reverse; + StringOutputStream reverse; ConvertValueToOutput(settings(), result, Value(nullptr, "scope"), reverse, &err); EXPECT_FALSE(err.has_error()); @@ -343,7 +342,7 @@ Value(nullptr, "value"), &err); EXPECT_FALSE(err.has_error()); - std::ostringstream reverse; + StringOutputStream reverse; ConvertValueToOutput(settings(), result, Value(nullptr, "value"), reverse, &err); EXPECT_FALSE(err.has_error());
diff --git a/src/gn/output_stream.cc b/src/gn/output_stream.cc new file mode 100644 index 0000000..119aaab --- /dev/null +++ b/src/gn/output_stream.cc
@@ -0,0 +1,82 @@ +// Copyright (c) 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gn/output_stream.h" + +#include <limits.h> + +OutputStream& OutputStream::operator<<(unsigned long long value) { + const size_t buffer_size = 24; + char buffer[buffer_size]; + char* end = buffer + buffer_size; + char* pos = end; + do { + *(--pos) = '0' + static_cast<char>(value % 10); + value /= 10; + } while (value != 0); + write(pos, static_cast<size_t>(end - pos)); + return *this; +} + +OutputStream& OutputStream::operator<<(long long value) { + const size_t buffer_size = 24; + char buffer[buffer_size]; + char* end = buffer + buffer_size; + char* pos = end; + + bool has_sign = (value < 0); + if (has_sign) { + // NOTE: |LLONG_MIN == -LLONG_MIN| must be handled here. + if (value == LLONG_MIN) { + *(--pos) = '8'; + value /= 10; + } + value = -value; + } + + do { + *(--pos) = '0' + static_cast<char>(value % 10); + value /= 10; + } while (value != 0); + if (has_sign) + *(--pos) = '-'; + write(pos, static_cast<size_t>(end - pos)); + return *this; +} + +OutputStream& OutputStream::operator<<(unsigned value) { + return *this << static_cast<unsigned long long>(value); +} + +OutputStream& OutputStream::operator<<(int value) { + return *this << static_cast<long long>(value); +} + +OutputStream& OutputStream::operator<<(unsigned long value) { + return *this << static_cast<unsigned long long>(value); +} + +OutputStream& OutputStream::operator<<(long value) { + return *this << static_cast<long long>(value); +} + +FileOutputStream::FileOutputStream(const char* utf8_path) { + file_ = fopen(utf8_path, "rw"); +} + +FileOutputStream::~FileOutputStream() { + fclose(file_); +} + +bool FileOutputStream::fail() const { + return ferror(file_) != 0; +} + +void FileOutputStream::write(const char* str, size_t len) { + fwrite(str, 1, len, file_); +} + +void FileOutputStream::put(char ch) { + fputc(ch, file_); +}
diff --git a/src/gn/output_stream.h b/src/gn/output_stream.h new file mode 100644 index 0000000..336c56d --- /dev/null +++ b/src/gn/output_stream.h
@@ -0,0 +1,109 @@ +// Copyright (c) 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TOOLS_GN_OUTPUT_STREAM_H_ +#define TOOLS_GN_OUTPUT_STREAM_H_ + +#include <cstdint> +#include <cstdio> +#include <cstring> +#include <string> + +// GN generates a lot of text that it sends to various +// output streams. Initially, this was done using std::ostream +// but this interface (and implementation) is inefficient due +// to legacy feature requirements that GN does not need. +// +// OutputStream is an abstract interface for an output stream +// that provides a subset of the std::ostream API, but performs +// far faster. In practice, using it results in 6% faster +// `gn gen` times for large build plans that generate huge +// Ninja build plans. +class OutputStream { + public: + virtual ~OutputStream() {} + + // Add |len| bytes of data to the output stream. + virtual void write(const char* str, size_t len) = 0; + + // Add a single byte of data to the output stream. + virtual void put(char ch) = 0; + + // Convenience helpers for C literals and standard strings. + void write(const char* str) { write(str, ::strlen(str)); } + void write(const std::string& str) { write(str.data(), str.size()); } + + // Operator << overload for std::ostream compatibility. + OutputStream& operator<<(char ch) { + put(ch); + return *this; + } + OutputStream& operator<<(const char* str) { + write(str); + return *this; + } + OutputStream& operator<<(const std::string& str) { + write(str); + return *this; + } + OutputStream& operator<<(const std::string_view& str) { + write(str.data(), str.size()); + return *this; + } + + // Add decimal representations to the output stream. + OutputStream& operator<<(int value); + OutputStream& operator<<(long value); + OutputStream& operator<<(long long value); + OutputStream& operator<<(unsigned value); + OutputStream& operator<<(unsigned long value); + OutputStream& operator<<(unsigned long long value); +}; + +// A StringOutputStream stores all input into an std::string. +// This is a replacement for std::ostringstream. +class StringOutputStream : public OutputStream { + public: + // Constructor creates empty string. + StringOutputStream() {} + + virtual ~StringOutputStream() {} + + // Retrieve reference to result. + const std::string str() const { return str_; } + + // Move result out of the instance. + std::string release() { return std::move(str_); } + + // OutputStream overrides + void write(const char* str, size_t len) override { str_.append(str, len); } + void put(char ch) override { str_.push_back(ch); } + + protected: + std::string str_; +}; + +// A FileOutputStream writes all input into a file. +class FileOutputStream : public OutputStream { + public: + // Constructor opens a FILE instance in binary mode. + // Use fail() after the call to verify for errors. + FileOutputStream(const char* utf8_path); + + // Destructor closes the FILE instance. + virtual ~FileOutputStream(); + + // Return true if an error occured during construction + // or a write or put call. + bool fail() const; + + // OutputStream overrides. + void write(const char* str, size_t len) override; + void put(char ch) override; + + protected: + FILE* file_ = nullptr; +}; + +#endif // TOOLS_GN_OUTPUT_STREAM_H_
diff --git a/src/gn/output_stream_unittest.cc b/src/gn/output_stream_unittest.cc new file mode 100644 index 0000000..115e9e9 --- /dev/null +++ b/src/gn/output_stream_unittest.cc
@@ -0,0 +1,98 @@ +// Copyright (c) 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gn/output_stream.h" + +#include <limits> + +#include "util/test/test.h" + +TEST(OutputStream, AppendIntDecimals) { + static const int kValues[] = { + 0, 1, -1, 12345678, -12345678, INT_MIN, INT_MAX, + }; + for (const auto value : kValues) { + char expected[20]; + snprintf(expected, sizeof(expected), "%d", value); + + StringOutputStream s; + s << value; + EXPECT_EQ(s.str(), expected) << value; + } +} + +TEST(OutputStream, AppendUIntDecimals) { + static const unsigned kValues[] = { + 0, + 1, + 12345678, + UINT_MAX, + }; + for (const auto value : kValues) { + char expected[20]; + snprintf(expected, sizeof(expected), "%u", value); + + StringOutputStream s; + s << value; + EXPECT_EQ(s.str(), expected) << value; + } +} + +TEST(OutputStream, AppendLongDecimals) { + static const long kValues[] = { + 0, 1, -1, 12345678, -12345678, INT_MIN, INT_MAX, LONG_MIN, LONG_MAX, + }; + for (const auto value : kValues) { + char expected[32]; + snprintf(expected, sizeof(expected), "%ld", value); + + StringOutputStream s; + s << value; + + EXPECT_EQ(s.str(), expected) << value; + } +} + +TEST(OutputStream, AppendULongDecimals) { + static const unsigned long kValues[] = { + 0, 1, 12345678, UINT_MAX, ULONG_MAX, + }; + for (const auto value : kValues) { + char expected[32]; + snprintf(expected, sizeof(expected), "%lu", value); + + StringOutputStream s; + s << value; + EXPECT_EQ(s.str(), expected) << value; + } +} + +TEST(OutputStream, AppendLongLongDecimals) { + static const long long kValues[] = { + 0, 1, -1, 12345678, -12345678, INT_MIN, + INT_MAX, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, + }; + for (const auto value : kValues) { + char expected[48]; + snprintf(expected, sizeof(expected), "%lld", value); + + StringOutputStream s; + s << value; + EXPECT_EQ(s.str(), expected) << value; + } +} + +TEST(OutputStream, AppendULongLongDecimals) { + static const unsigned long long kValues[] = { + 0, 1, 12345678, UINT_MAX, ULONG_MAX, ULLONG_MAX, + }; + for (const auto value : kValues) { + char expected[48]; + snprintf(expected, sizeof(expected), "%llu", value); + + StringOutputStream s; + s << value; + EXPECT_EQ(s.str(), expected) << value; + } +}
diff --git a/src/gn/parser.cc b/src/gn/parser.cc index 96739a5..b05cebb 100644 --- a/src/gn/parser.cc +++ b/src/gn/parser.cc
@@ -10,6 +10,7 @@ #include "base/logging.h" #include "gn/functions.h" #include "gn/operators.h" +#include "gn/output_stream.h" #include "gn/token.h" const char kGrammar_Help[] = @@ -896,23 +897,21 @@ return std::string(value, ' '); } -void RenderToText(const base::Value& node, - int indent_level, - std::ostringstream& os) { +void RenderToText(const base::Value& node, int indent_level, OutputStream& os) { const base::Value* child = node.FindKey(std::string("child")); std::string node_type(node.FindKey("type")->GetString()); if (node_type == "ACCESSOR") { // AccessorNode is a bit special, in that it holds a Token, not a ParseNode // for the base. - os << IndentFor(indent_level) << node_type << std::endl; + os << IndentFor(indent_level) << node_type << "\n"; os << IndentFor(indent_level + 1) << node.FindKey("value")->GetString() - << std::endl; + << "\n"; } else { os << IndentFor(indent_level) << node_type; if (node.FindKey("value")) { os << "(" << node.FindKey("value")->GetString() << ")"; } - os << std::endl; + os << "\n"; } if (node.FindKey(kJsonBeforeComment)) { for (auto& v : node.FindKey(kJsonBeforeComment)->GetList()) {
diff --git a/src/gn/parser.h b/src/gn/parser.h index b323028..f92429c 100644 --- a/src/gn/parser.h +++ b/src/gn/parser.h
@@ -15,6 +15,8 @@ #include "gn/err.h" #include "gn/parse_tree.h" +class OutputStream; + extern const char kGrammar_Help[]; struct ParserHelper; @@ -151,8 +153,6 @@ // Renders parse subtree as a formatted text, indenting by the given number of // spaces. -void RenderToText(const base::Value& node, - int indent_level, - std::ostringstream& os); +void RenderToText(const base::Value& node, int indent_level, OutputStream& os); #endif // TOOLS_GN_PARSER_H_
diff --git a/src/gn/parser_unittest.cc b/src/gn/parser_unittest.cc index 8cfdb8d..d850551 100644 --- a/src/gn/parser_unittest.cc +++ b/src/gn/parser_unittest.cc
@@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <sstream> - -#include "gn/input_file.h" #include "gn/parser.h" +#include "gn/input_file.h" +#include "gn/output_stream.h" #include "gn/tokenizer.h" #include "util/test/test.h" @@ -30,7 +29,7 @@ err.PrintToStdout(); ASSERT_TRUE(result); - std::ostringstream collector; + StringOutputStream collector; RenderToText(result->GetJSONNode(), 0, collector); EXPECT_EQ(expected, collector.str()); @@ -46,7 +45,7 @@ std::unique_ptr<ParseNode> result = Parser::ParseExpression(tokens, &err); ASSERT_TRUE(result); - std::ostringstream collector; + StringOutputStream collector; RenderToText(result->GetJSONNode(), 0, collector); EXPECT_EQ(expected, collector.str());
diff --git a/src/gn/path_output.cc b/src/gn/path_output.cc index 86c92e6..74c336d 100644 --- a/src/gn/path_output.cc +++ b/src/gn/path_output.cc
@@ -7,6 +7,7 @@ #include "base/strings/string_util.h" #include "gn/filesystem_utils.h" #include "gn/output_file.h" +#include "gn/output_stream.h" #include "gn/string_utils.h" #include "util/build_config.h" @@ -22,11 +23,11 @@ PathOutput::~PathOutput() = default; -void PathOutput::WriteFile(std::ostream& out, const SourceFile& file) const { +void PathOutput::WriteFile(OutputStream& out, const SourceFile& file) const { WritePathStr(out, file.value()); } -void PathOutput::WriteDir(std::ostream& out, +void PathOutput::WriteDir(OutputStream& out, const SourceDir& dir, DirSlashEnding slash_ending) const { if (dir.value() == "/") { @@ -69,12 +70,12 @@ } } -void PathOutput::WriteFile(std::ostream& out, const OutputFile& file) const { +void PathOutput::WriteFile(OutputStream& out, const OutputFile& file) const { // Here we assume that the path is already preprocessed. EscapeStringToStream(out, file.value(), options_); } -void PathOutput::WriteFiles(std::ostream& out, +void PathOutput::WriteFiles(OutputStream& out, const std::vector<SourceFile>& files) const { for (const auto& file : files) { out << " "; @@ -82,7 +83,7 @@ } } -void PathOutput::WriteFiles(std::ostream& out, +void PathOutput::WriteFiles(OutputStream& out, const std::vector<OutputFile>& files) const { for (const auto& file : files) { out << " "; @@ -90,7 +91,7 @@ } } -void PathOutput::WriteFiles(std::ostream& out, +void PathOutput::WriteFiles(OutputStream& out, const UniqueVector<OutputFile>& files) const { for (const auto& file : files) { out << " "; @@ -98,7 +99,7 @@ } } -void PathOutput::WriteDir(std::ostream& out, +void PathOutput::WriteDir(OutputStream& out, const OutputFile& file, DirSlashEnding slash_ending) const { DCHECK(file.value().empty() || file.value()[file.value().size() - 1] == '/'); @@ -122,13 +123,13 @@ } } -void PathOutput::WriteFile(std::ostream& out, +void PathOutput::WriteFile(OutputStream& out, const base::FilePath& file) const { // Assume native file paths are always absolute. EscapeStringToStream(out, FilePathToUTF8(file), options_); } -void PathOutput::WriteSourceRelativeString(std::ostream& out, +void PathOutput::WriteSourceRelativeString(OutputStream& out, std::string_view str) const { if (options_.mode == ESCAPE_NINJA_COMMAND) { // Shell escaping needs an intermediate string since it may end up @@ -150,7 +151,7 @@ } } -void PathOutput::WritePathStr(std::ostream& out, std::string_view str) const { +void PathOutput::WritePathStr(OutputStream& out, std::string_view str) const { DCHECK(str.size() > 0 && str[0] == '/'); if (str.substr(0, current_dir_.value().size()) ==
diff --git a/src/gn/path_output.h b/src/gn/path_output.h index 3b973d6..3fced0a 100644 --- a/src/gn/path_output.h +++ b/src/gn/path_output.h
@@ -14,6 +14,7 @@ #include "gn/unique_vector.h" class OutputFile; +class OutputStream; class SourceFile; namespace base { @@ -48,35 +49,35 @@ void set_inhibit_quoting(bool iq) { options_.inhibit_quoting = iq; } void set_escape_platform(EscapingPlatform p) { options_.platform = p; } - void WriteFile(std::ostream& out, const SourceFile& file) const; - void WriteFile(std::ostream& out, const OutputFile& file) const; - void WriteFile(std::ostream& out, const base::FilePath& file) const; + void WriteFile(OutputStream& out, const SourceFile& file) const; + void WriteFile(OutputStream& out, const OutputFile& file) const; + void WriteFile(OutputStream& out, const base::FilePath& file) const; // Writes the given SourceFiles/OutputFiles with spaces separating them. This // will also write an initial space before the first item. - void WriteFiles(std::ostream& out, const std::vector<SourceFile>& file) const; - void WriteFiles(std::ostream& out, + void WriteFiles(OutputStream& out, const std::vector<SourceFile>& file) const; + void WriteFiles(OutputStream& out, const std::vector<OutputFile>& files) const; - void WriteFiles(std::ostream& out, + void WriteFiles(OutputStream& out, const UniqueVector<OutputFile>& files) const; // This variant assumes the dir ends in a trailing slash or is empty. - void WriteDir(std::ostream& out, + void WriteDir(OutputStream& out, const SourceDir& dir, DirSlashEnding slash_ending) const; - void WriteDir(std::ostream& out, + void WriteDir(OutputStream& out, const OutputFile& file, DirSlashEnding slash_ending) const; // Backend for WriteFile and WriteDir. This appends the given file or // directory string to the file. - void WritePathStr(std::ostream& out, std::string_view str) const; + void WritePathStr(OutputStream& out, std::string_view str) const; private: // Takes the given string and writes it out, appending to the inverse // current dir. This assumes leading slashes have been trimmed. - void WriteSourceRelativeString(std::ostream& out, std::string_view str) const; + void WriteSourceRelativeString(OutputStream& out, std::string_view str) const; SourceDir current_dir_;
diff --git a/src/gn/path_output_unittest.cc b/src/gn/path_output_unittest.cc index 1debb64..e137522 100644 --- a/src/gn/path_output_unittest.cc +++ b/src/gn/path_output_unittest.cc
@@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <sstream> - +#include "gn/path_output.h" #include "base/files/file_path.h" #include "gn/output_file.h" -#include "gn/path_output.h" +#include "gn/output_stream.h" #include "gn/source_dir.h" #include "gn/source_file.h" #include "util/build_config.h" @@ -18,19 +17,19 @@ PathOutput writer(build_dir, source_root, ESCAPE_NONE); { // Normal source-root path. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/bar.cc")); EXPECT_EQ("../../foo/bar.cc", out.str()); } { // File in the root dir. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo.cc")); EXPECT_EQ("../../foo.cc", out.str()); } { // Files in the output dir. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//out/Debug/foo.cc")); out << " "; writer.WriteFile(out, SourceFile("//out/Debug/bar/baz.cc")); @@ -39,14 +38,14 @@ #if defined(OS_WIN) { // System-absolute path. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("/C:/foo/bar.cc")); EXPECT_EQ("C:/foo/bar.cc", out.str()); } #else { // System-absolute path. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("/foo/bar.cc")); EXPECT_EQ("/foo/bar.cc", out.str()); } @@ -60,13 +59,13 @@ PathOutput writer(build_dir, source_root, ESCAPE_NONE); { // Normal source-root path. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/bar.cc")); EXPECT_EQ("foo/bar.cc", out.str()); } { // File in the root dir. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo.cc")); EXPECT_EQ("foo.cc", out.str()); } @@ -78,13 +77,13 @@ PathOutput writer(build_dir, source_root, ESCAPE_NINJA); { // Spaces and $ in filenames. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/foo bar$.cc")); EXPECT_EQ("../../foo/foo$ bar$$.cc", out.str()); } { // Not other weird stuff - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/\"foo\".cc")); EXPECT_EQ("../../foo/\"foo\".cc", out.str()); } @@ -98,7 +97,7 @@ // Spaces in filenames should get quoted on Windows. writer.set_escape_platform(ESCAPE_PLATFORM_WIN); { - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/foo bar.cc")); EXPECT_EQ("\"../../foo/foo$ bar.cc\"", out.str()); } @@ -106,7 +105,7 @@ // Spaces in filenames should get escaped on Posix. writer.set_escape_platform(ESCAPE_PLATFORM_POSIX); { - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/foo bar.cc")); EXPECT_EQ("../../foo/foo\\$ bar.cc", out.str()); } @@ -114,7 +113,7 @@ // Quotes should get blackslash-escaped on Windows and Posix. writer.set_escape_platform(ESCAPE_PLATFORM_WIN); { - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/\"foobar\".cc")); // Our Windows code currently quotes the whole thing in this case for // code simplicity, even though it's strictly unnecessary. This might @@ -123,7 +122,7 @@ } writer.set_escape_platform(ESCAPE_PLATFORM_POSIX); { - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/\"foobar\".cc")); EXPECT_EQ("../../foo/\\\"foobar\\\".cc", out.str()); } @@ -131,13 +130,13 @@ // Backslashes should get escaped on non-Windows and preserved on Windows. writer.set_escape_platform(ESCAPE_PLATFORM_WIN); { - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, OutputFile("foo\\bar.cc")); EXPECT_EQ("foo\\bar.cc", out.str()); } writer.set_escape_platform(ESCAPE_PLATFORM_POSIX); { - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, OutputFile("foo\\bar.cc")); EXPECT_EQ("foo\\\\bar.cc", out.str()); } @@ -152,7 +151,7 @@ writer.set_escape_platform(ESCAPE_PLATFORM_WIN); { // We should get unescaped spaces in the output with no quotes. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/foo bar.cc")); EXPECT_EQ("../../foo/foo$ bar.cc", out.str()); } @@ -160,7 +159,7 @@ writer.set_escape_platform(ESCAPE_PLATFORM_POSIX); { // Escapes the space. - std::ostringstream out; + StringOutputStream out; writer.WriteFile(out, SourceFile("//foo/foo bar.cc")); EXPECT_EQ("../../foo/foo\\$ bar.cc", out.str()); } @@ -172,13 +171,13 @@ std::string_view source_root("/source/root"); PathOutput writer(build_dir, source_root, ESCAPE_NINJA); { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("//foo/bar/"), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("../../foo/bar/", out.str()); } { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("//foo/bar/"), PathOutput::DIR_NO_LAST_SLASH); EXPECT_EQ("../../foo/bar", out.str()); @@ -186,54 +185,54 @@ // Output source root dir. { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("//"), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("../../", out.str()); } { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("//"), PathOutput::DIR_NO_LAST_SLASH); EXPECT_EQ("../..", out.str()); } // Output system root dir. { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("/"), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("/", out.str()); } { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("/"), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("/", out.str()); } { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("/"), PathOutput::DIR_NO_LAST_SLASH); EXPECT_EQ("/.", out.str()); } // Output inside current dir. { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("//out/Debug/"), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("./", out.str()); } { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("//out/Debug/"), PathOutput::DIR_NO_LAST_SLASH); EXPECT_EQ(".", out.str()); } { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("//out/Debug/foo/"), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("foo/", out.str()); } { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, SourceDir("//out/Debug/foo/"), PathOutput::DIR_NO_LAST_SLASH); EXPECT_EQ("foo", out.str()); @@ -241,18 +240,18 @@ // WriteDir using an OutputFile. { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, OutputFile("foo/"), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("foo/", out.str()); } { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, OutputFile("foo/"), PathOutput::DIR_NO_LAST_SLASH); EXPECT_EQ("foo", out.str()); } { - std::ostringstream out; + StringOutputStream out; writer.WriteDir(out, OutputFile(), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("", out.str()); } @@ -262,13 +261,13 @@ std::string_view source_root("/source/root"); PathOutput root_writer(SourceDir("//"), source_root, ESCAPE_NINJA); { - std::ostringstream out; + StringOutputStream out; root_writer.WriteDir(out, SourceDir("//"), PathOutput::DIR_INCLUDE_LAST_SLASH); EXPECT_EQ("./", out.str()); } { - std::ostringstream out; + StringOutputStream out; root_writer.WriteDir(out, SourceDir("//"), PathOutput::DIR_NO_LAST_SLASH); EXPECT_EQ(".", out.str()); }
diff --git a/src/gn/pool.cc b/src/gn/pool.cc index 60049a1..740f1d2 100644 --- a/src/gn/pool.cc +++ b/src/gn/pool.cc
@@ -4,9 +4,8 @@ #include "gn/pool.h" -#include <sstream> - #include "base/logging.h" +#include "gn/output_stream.h" Pool::~Pool() = default; @@ -25,7 +24,7 @@ } std::string Pool::GetNinjaName(bool include_toolchain) const { - std::ostringstream buffer; + StringOutputStream buffer; if (include_toolchain) { DCHECK(label().toolchain_dir().is_source_absolute()); std::string toolchain_dir = label().toolchain_dir().value();
diff --git a/src/gn/qt_creator_writer.cc b/src/gn/qt_creator_writer.cc index 94fed8f..2e9ee0b 100644 --- a/src/gn/qt_creator_writer.cc +++ b/src/gn/qt_creator_writer.cc
@@ -6,7 +6,6 @@ #include <optional> #include <set> -#include <sstream> #include <string> #include "base/files/file_path.h" @@ -271,11 +270,10 @@ void QtCreatorWriter::GenerateFile(const base::FilePath::CharType* suffix, const std::set<std::string>& items) { const base::FilePath file_path = project_prefix_.AddExtension(suffix); - StringOutputBuffer storage; - std::ostream output(&storage); + StringOutputBuffer output; for (const std::string& item : items) - output << item << std::endl; - storage.WriteToFileIfChanged(file_path, &err_); + output << item << "\n"; + output.WriteToFileIfChanged(file_path, &err_); } void QtCreatorWriter::Run() {
diff --git a/src/gn/runtime_deps.cc b/src/gn/runtime_deps.cc index 546d63e..e121183 100644 --- a/src/gn/runtime_deps.cc +++ b/src/gn/runtime_deps.cc
@@ -6,7 +6,6 @@ #include <map> #include <set> -#include <sstream> #include "base/command_line.h" #include "base/files/file_util.h" @@ -212,13 +211,12 @@ base::FilePath data_deps_file = target->settings()->build_settings()->GetFullPath(output_as_source); - StringOutputBuffer storage; - std::ostream contents(&storage); + StringOutputBuffer contents; for (const auto& pair : ComputeRuntimeDeps(target)) - contents << pair.first.value() << std::endl; + contents << pair.first.value() << "\n"; ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, output_as_source.value()); - return storage.WriteToFileIfChanged(data_deps_file, err); + return contents.WriteToFileIfChanged(data_deps_file, err); } } // namespace
diff --git a/src/gn/rust_project_writer.cc b/src/gn/rust_project_writer.cc index 6c9aef8..840c211 100644 --- a/src/gn/rust_project_writer.cc +++ b/src/gn/rust_project_writer.cc
@@ -4,9 +4,7 @@ #include "gn/rust_project_writer.h" -#include <fstream> #include <optional> -#include <sstream> #include <tuple> #include "base/json/string_escape.h" @@ -72,9 +70,7 @@ std::vector<const Target*> all_targets = builder.GetAllResolvedTargets(); StringOutputBuffer out_buffer; - std::ostream out(&out_buffer); - - RenderJSON(build_settings, all_targets, out); + RenderJSON(build_settings, all_targets, out_buffer); return out_buffer.WriteToFileIfChanged(output_path, err); } @@ -248,7 +244,7 @@ void WriteCrates(const BuildSettings* build_settings, CrateList& crate_list, std::optional<std::string>& sysroot, - std::ostream& rust_project) { + OutputStream& rust_project) { rust_project << "{" NEWLINE; // If a sysroot was found, then that can be used to tell rust-analyzer where @@ -390,7 +386,7 @@ void RustProjectWriter::RenderJSON(const BuildSettings* build_settings, std::vector<const Target*>& all_targets, - std::ostream& rust_project) { + OutputStream& rust_project) { TargetIndexMap lookup; CrateList crate_list; std::optional<std::string> rust_sysroot;
diff --git a/src/gn/rust_project_writer.h b/src/gn/rust_project_writer.h index 3fbdedb..8af7bf1 100644 --- a/src/gn/rust_project_writer.h +++ b/src/gn/rust_project_writer.h
@@ -10,6 +10,7 @@ class Builder; class BuildSettings; +class OutputStream; // rust-project.json is an output format describing the rust build graph. It is // used by rust-analyzer (a LSP server), similar to compile-commands.json. @@ -27,7 +28,7 @@ Err* err); static void RenderJSON(const BuildSettings* build_settings, std::vector<const Target*>& all_targets, - std::ostream& rust_project); + OutputStream& rust_project); private: // This function visits the deps graph of a target in a DFS fashion.
diff --git a/src/gn/rust_project_writer_helpers.h b/src/gn/rust_project_writer_helpers.h index 3073fd5..864b7d0 100644 --- a/src/gn/rust_project_writer_helpers.h +++ b/src/gn/rust_project_writer_helpers.h
@@ -5,9 +5,7 @@ #ifndef TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_ #define TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_ -#include <fstream> #include <optional> -#include <sstream> #include <string> #include <string_view> #include <tuple> @@ -19,6 +17,8 @@ #include "gn/source_file.h" #include "gn/target.h" +class OutputStream; + // These are internal types and helper functions for RustProjectWriter that have // been extracted for easier testability. @@ -130,7 +130,7 @@ void WriteCrates(const BuildSettings* build_settings, CrateList& crate_list, std::optional<std::string>& sysroot, - std::ostream& rust_project); + OutputStream& rust_project); // Assemble the compiler arguments for the given GN Target. std::vector<std::string> ExtractCompilerArgs(const Target* target);
diff --git a/src/gn/rust_project_writer_helpers_unittest.cc b/src/gn/rust_project_writer_helpers_unittest.cc index 87ccd83..13d6b47 100644 --- a/src/gn/rust_project_writer_helpers_unittest.cc +++ b/src/gn/rust_project_writer_helpers_unittest.cc
@@ -40,7 +40,7 @@ crates.push_back(dep); crates.push_back(target); - std::ostringstream stream; + StringOutputStream stream; WriteCrates(setup.build_settings(), crates, sysroot, stream); std::string out = stream.str(); #if defined(OS_WIN) @@ -101,7 +101,7 @@ std::optional<std::string> sysroot = "sysroot"; CrateList crates; - std::ostringstream stream; + StringOutputStream stream; WriteCrates(setup.build_settings(), crates, sysroot, stream); std::string out = stream.str(); #if defined(OS_WIN)
diff --git a/src/gn/rust_project_writer_unittest.cc b/src/gn/rust_project_writer_unittest.cc index f0b806b..66948e3 100644 --- a/src/gn/rust_project_writer_unittest.cc +++ b/src/gn/rust_project_writer_unittest.cc
@@ -6,6 +6,7 @@ #include "base/files/file_path.h" #include "base/strings/string_util.h" #include "gn/filesystem_utils.h" +#include "gn/output_stream.h" #include "gn/substitution_list.h" #include "gn/target.h" #include "gn/test_with_scheduler.h" @@ -41,7 +42,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; std::vector<const Target*> targets; targets.push_back(&target); RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream); @@ -106,7 +107,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; std::vector<const Target*> targets; targets.push_back(&target); RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream); @@ -204,7 +205,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; std::vector<const Target*> targets; targets.push_back(&target); RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream); @@ -341,7 +342,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; std::vector<const Target*> targets; targets.push_back(&target); RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream); @@ -444,7 +445,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; std::vector<const Target*> targets; targets.push_back(&target); RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream); @@ -499,7 +500,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; std::vector<const Target*> targets; targets.push_back(&target); RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream); @@ -554,7 +555,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; std::vector<const Target*> targets; targets.push_back(&target); RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream); @@ -610,7 +611,7 @@ target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); - std::ostringstream stream; + StringOutputStream stream; std::vector<const Target*> targets; targets.push_back(&target); RustProjectWriter::RenderJSON(setup.build_settings(), targets, stream);
diff --git a/src/gn/setup.cc b/src/gn/setup.cc index 912f378..d907a6c 100644 --- a/src/gn/setup.cc +++ b/src/gn/setup.cc
@@ -8,7 +8,6 @@ #include <algorithm> #include <memory> -#include <sstream> #include <utility> #include "base/command_line.h"
diff --git a/src/gn/string_output_buffer.cc b/src/gn/string_output_buffer.cc index c5d91ff..53af53e 100644 --- a/src/gn/string_output_buffer.cc +++ b/src/gn/string_output_buffer.cc
@@ -4,13 +4,14 @@ #include "gn/string_output_buffer.h" +#include <fstream> + #include "base/files/file_path.h" #include "base/files/file_util.h" #include "gn/err.h" #include "gn/file_writer.h" #include "gn/filesystem_utils.h" - -#include <fstream> +#include "gn/output_stream.h" std::string StringOutputBuffer::str() const { std::string result;
diff --git a/src/gn/string_output_buffer.h b/src/gn/string_output_buffer.h index 2338860..04e27dd 100644 --- a/src/gn/string_output_buffer.h +++ b/src/gn/string_output_buffer.h
@@ -7,16 +7,18 @@ #include <array> #include <memory> -#include <streambuf> #include <string> #include <string_view> #include <vector> +#include "gn/output_stream.h" + namespace base { class FilePath; } // namespace base class Err; +class OutputStream; // An append-only very large storage area for string data. Useful for the parts // of GN that need to generate huge output files (e.g. --ide=json will create @@ -28,11 +30,11 @@ // // 2) Use operator<<, or Append() to append data to the instance. // -// 3) Alternatively, create an std::ostream that takes its address as +// 3) Alternatively, create an OutputStream that takes its address as // argument, then use the output stream as usual to append data to it. // // StringOutputBuffer storage; -// std::ostream out(&storage); +// OutputStream out(&storage); // out << "Hello world!"; // // 4) Use ContentsEqual() to compare the instance's content with that of a @@ -40,7 +42,7 @@ // // 5) Use WriteToFile() to write the content to a given file. // -class StringOutputBuffer : public std::streambuf { +class StringOutputBuffer : public OutputStream { public: StringOutputBuffer() = default; @@ -72,18 +74,9 @@ static size_t GetPageSizeForTesting() { return kPageSize; } - protected: - // Called by std::ostream to write |n| chars from |s|. - std::streamsize xsputn(const char* s, std::streamsize n) override { - Append(s, static_cast<size_t>(n)); - return n; - } - - // Called by std::ostream to write a single character. - int_type overflow(int_type ch) override { - Append(static_cast<char>(ch)); - return 1; - } + // OutputStream overrides + void put(char ch) override { Append(ch); } + void write(const char* str, size_t len) override { Append(str, len); } private: // Return the number of free bytes in the current page.
diff --git a/src/gn/string_output_buffer_unittest.cc b/src/gn/string_output_buffer_unittest.cc index 6dcb741..b80a3be 100644 --- a/src/gn/string_output_buffer_unittest.cc +++ b/src/gn/string_output_buffer_unittest.cc
@@ -69,12 +69,11 @@ const size_t span_size = data_size / num_spans; StringOutputBuffer buffer; - std::ostream out(&buffer); for (size_t n = 0; n < num_spans; ++n) { size_t start_offset = n * span_size; size_t end_offset = std::min(start_offset + span_size, data.size()); - out << std::string_view(&data[start_offset], end_offset - start_offset); + buffer << std::string_view(&data[start_offset], end_offset - start_offset); } EXPECT_EQ(data.size(), buffer.size());
diff --git a/src/gn/substitution_writer.cc b/src/gn/substitution_writer.cc index c9624d7..f49abc4 100644 --- a/src/gn/substitution_writer.cc +++ b/src/gn/substitution_writer.cc
@@ -9,6 +9,7 @@ #include "gn/escape.h" #include "gn/filesystem_utils.h" #include "gn/output_file.h" +#include "gn/output_stream.h" #include "gn/rust_substitution_type.h" #include "gn/rust_tool.h" #include "gn/settings.h" @@ -150,7 +151,7 @@ void SubstitutionWriter::WriteWithNinjaVariables( const SubstitutionPattern& pattern, const EscapeOptions& escape_options, - std::ostream& out) { + OutputStream& out) { // The result needs to be quoted as if it was one string, but the $ for // the inserted Ninja variables can't be escaped. So write to a buffer with // no quoting, and then quote the whole thing if necessary. @@ -322,7 +323,7 @@ const SourceFile& source, const std::vector<const Substitution*>& types, const EscapeOptions& escape_options, - std::ostream& out) { + OutputStream& out) { for (const auto& type : types) { // Don't write SOURCE since that just maps to Ninja's $in variable, which // is implicit in the rule. RESPONSE_FILE_NAME is written separately @@ -335,7 +336,7 @@ GetSourceSubstitution(target, settings, source, type, OUTPUT_RELATIVE, settings->build_settings()->build_dir()), escape_options); - out << std::endl; + out << "\n"; } } }
diff --git a/src/gn/substitution_writer.h b/src/gn/substitution_writer.h index 95e4b94..73f5cda 100644 --- a/src/gn/substitution_writer.h +++ b/src/gn/substitution_writer.h
@@ -13,6 +13,7 @@ struct EscapeOptions; class OutputFile; +class OutputStream; class Settings; class SourceDir; class SourceFile; @@ -62,7 +63,7 @@ // Ninja variables replacing the patterns. static void WriteWithNinjaVariables(const SubstitutionPattern& pattern, const EscapeOptions& escape_options, - std::ostream& out); + OutputStream& out); // NOP substitutions --------------------------------------------------------- @@ -157,7 +158,7 @@ const SourceFile& source, const std::vector<const Substitution*>& types, const EscapeOptions& escape_options, - std::ostream& out); + OutputStream& out); // Extracts the given type of substitution related to a source file from the // given source file. If output_style is OUTPUT_RELATIVE, relative_to
diff --git a/src/gn/substitution_writer_unittest.cc b/src/gn/substitution_writer_unittest.cc index eaa521a..152adb5 100644 --- a/src/gn/substitution_writer_unittest.cc +++ b/src/gn/substitution_writer_unittest.cc
@@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <sstream> - +#include "gn/substitution_writer.h" #include "gn/c_substitution_type.h" #include "gn/err.h" #include "gn/escape.h" +#include "gn/output_stream.h" #include "gn/substitution_list.h" #include "gn/substitution_pattern.h" -#include "gn/substitution_writer.h" #include "gn/target.h" #include "gn/test_with_scope.h" #include "util/build_config.h" @@ -77,7 +76,7 @@ EscapeOptions options; options.mode = ESCAPE_NONE; - std::ostringstream out; + StringOutputStream out; SubstitutionWriter::WriteNinjaVariablesForSource( nullptr, setup.settings(), SourceFile("//foo/bar/baz.txt"), types, options, out); @@ -100,7 +99,7 @@ EscapeOptions options; options.mode = ESCAPE_NONE; - std::ostringstream out; + StringOutputStream out; SubstitutionWriter::WriteWithNinjaVariables(pattern, options, out); EXPECT_EQ("-i ${in} --out=bar\"${source_name_part}\".o", out.str());
diff --git a/src/gn/trace.cc b/src/gn/trace.cc index 5f07353..8a16f14 100644 --- a/src/gn/trace.cc +++ b/src/gn/trace.cc
@@ -9,7 +9,6 @@ #include <algorithm> #include <map> #include <mutex> -#include <sstream> #include <vector> #include "base/command_line.h" @@ -20,6 +19,7 @@ #include "base/strings/stringprintf.h" #include "gn/filesystem_utils.h" #include "gn/label.h" +#include "gn/output_stream.h" namespace { @@ -72,18 +72,18 @@ return a.total_duration > b.total_duration; } -void SummarizeParses(std::vector<const TraceItem*>& loads, std::ostream& out) { +void SummarizeParses(std::vector<const TraceItem*>& loads, OutputStream& out) { out << "File parse times: (time in ms, name)\n"; std::sort(loads.begin(), loads.end(), &DurationGreater); for (auto* load : loads) { out << base::StringPrintf(" %8.2f ", load->delta().InMillisecondsF()); - out << load->name() << std::endl; + out << load->name() << "\n"; } } void SummarizeCoalesced(std::vector<const TraceItem*>& items, - std::ostream& out) { + OutputStream& out) { // Group by file name. std::map<std::string, Coalesced> coalesced; for (auto* item : items) { @@ -101,18 +101,18 @@ for (const auto& cur : sorted) { out << base::StringPrintf(" %8.2f %d ", cur.total_duration, cur.count); - out << *cur.name_ptr << std::endl; + out << *cur.name_ptr << "\n"; } } void SummarizeFileExecs(std::vector<const TraceItem*>& execs, - std::ostream& out) { + OutputStream& out) { out << "File execute times: (total time in ms, # executions, name)\n"; SummarizeCoalesced(execs, out); } void SummarizeScriptExecs(std::vector<const TraceItem*>& execs, - std::ostream& out) { + OutputStream& out) { out << "Script execute times: (total time in ms, # executions, name)\n"; SummarizeCoalesced(execs, out); } @@ -223,13 +223,13 @@ } } - std::ostringstream out; + StringOutputStream out; SummarizeParses(parses, out); - out << std::endl; + out << "\n"; SummarizeFileExecs(file_execs, out); - out << std::endl; + out << "\n"; SummarizeScriptExecs(script_execs, out); - out << std::endl; + out << "\n"; // Generally there will only be one header check, but it's theoretically // possible for more than one to run if more than one build is going in @@ -248,7 +248,7 @@ } void SaveTraces(const base::FilePath& file_name) { - std::ostringstream out; + StringOutputStream out; out << "{\"traceEvents\":[";
diff --git a/src/gn/visual_studio_writer.cc b/src/gn/visual_studio_writer.cc index 243fedd..19e903d 100644 --- a/src/gn/visual_studio_writer.cc +++ b/src/gn/visual_studio_writer.cc
@@ -22,6 +22,7 @@ #include "gn/deps_iterator.h" #include "gn/filesystem_utils.h" #include "gn/label_pattern.h" +#include "gn/output_stream.h" #include "gn/parse_tree.h" #include "gn/path_output.h" #include "gn/standard_out.h" @@ -38,7 +39,7 @@ namespace { struct SemicolonSeparatedWriter { - void operator()(const std::string& value, std::ostream& out) const { + void operator()(const std::string& value, OutputStream& out) const { out << XmlEscape(value) + ';'; } }; @@ -48,7 +49,7 @@ : path_output_(path_output) {} ~IncludeDirWriter() = default; - void operator()(const SourceDir& dir, std::ostream& out) const { + void operator()(const SourceDir& dir, OutputStream& out) const { path_output_.WriteDir(out, dir, PathOutput::DIR_NO_LAST_SLASH); out << ";"; } @@ -61,7 +62,7 @@ : path_output_(path_output), source_file_(source_file) {} ~SourceFileWriter() = default; - void operator()(std::ostream& out) const { + void operator()(OutputStream& out) const { path_output_.WriteFile(out, source_file_); } @@ -428,9 +429,8 @@ project_config_platform)); StringOutputBuffer vcxproj_storage; - std::ostream vcxproj_string_out(&vcxproj_storage); SourceFileCompileTypePairs source_types; - if (!WriteProjectFileContents(vcxproj_string_out, *projects_.back(), target, + if (!WriteProjectFileContents(vcxproj_storage, *projects_.back(), target, ninja_extra_args, ninja_executable, &source_types, err)) { projects_.pop_back(); @@ -446,13 +446,12 @@ base::FilePath filters_path = UTF8ToFilePath(vcxproj_path_str + ".filters"); StringOutputBuffer filters_storage; - std::ostream filters_string_out(&filters_storage); - WriteFiltersFileContents(filters_string_out, target, source_types); + WriteFiltersFileContents(filters_storage, target, source_types); return filters_storage.WriteToFileIfChanged(filters_path, err); } bool VisualStudioWriter::WriteProjectFileContents( - std::ostream& out, + OutputStream& out, const SolutionProject& solution_project, const Target* target, const std::string& ninja_extra_args, @@ -463,7 +462,7 @@ GetBuildDirForTargetAsSourceDir(target, BuildDirType::OBJ), build_settings_->root_path_utf8(), EscapingMode::ESCAPE_NONE); - out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl; + out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; XmlElementWriter project( out, "Project", XmlAttributes("DefaultTargets", "Build") @@ -685,16 +684,16 @@ } void VisualStudioWriter::WriteFiltersFileContents( - std::ostream& out, + OutputStream& out, const Target* target, const SourceFileCompileTypePairs& source_types) { - out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl; + out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; XmlElementWriter project( out, "Project", XmlAttributes("ToolsVersion", "4.0") .add("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003")); - std::ostringstream files_out; + StringOutputStream files_out; { std::unique_ptr<XmlElementWriter> filters_group = @@ -718,7 +717,7 @@ file_and_type.compile_type, "Include", SourceFileWriter(file_path_output, *file_and_type.file)); - std::ostringstream target_relative_out; + StringOutputStream target_relative_out; filter_path_output.WriteFile(target_relative_out, *file_and_type.file); std::string target_relative_path = target_relative_out.str(); ConvertPathToSystem(&target_relative_path); @@ -756,8 +755,7 @@ base::FilePath sln_path = build_settings_->GetFullPath(sln_file); StringOutputBuffer storage; - std::ostream string_out(&storage); - WriteSolutionFileContents(string_out, sln_path.DirName()); + WriteSolutionFileContents(storage, sln_path.DirName()); // Only write the content to the file if it's different. That is // both a performance optimization and more importantly, prevents @@ -766,66 +764,64 @@ } void VisualStudioWriter::WriteSolutionFileContents( - std::ostream& out, + OutputStream& out, const base::FilePath& solution_dir_path) { - out << "Microsoft Visual Studio Solution File, Format Version 12.00" - << std::endl; - out << "# " << version_string_ << std::endl; + out << "Microsoft Visual Studio Solution File, Format Version 12.00\n"; + out << "# " << version_string_ << "\n"; SourceDir solution_dir(FilePathToUTF8(solution_dir_path)); for (const std::unique_ptr<SolutionEntry>& folder : folders_) { out << "Project(\"" << kGuidTypeFolder << "\") = \"(" << folder->name << ")\", \"" << RebasePath(folder->path, solution_dir) << "\", \"" - << folder->guid << "\"" << std::endl; - out << "EndProject" << std::endl; + << folder->guid << "\"\n"; + out << "EndProject\n"; } for (const std::unique_ptr<SolutionProject>& project : projects_) { out << "Project(\"" << kGuidTypeProject << "\") = \"" << project->name << "\", \"" << RebasePath(project->path, solution_dir) << "\", \"" - << project->guid << "\"" << std::endl; - out << "EndProject" << std::endl; + << project->guid << "\"\n"; + out << "EndProject\n"; } - out << "Global" << std::endl; + out << "Global\n"; out << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution" - << std::endl; + << "\n"; const std::string config_mode_prefix = std::string(kConfigurationName) + '|'; const std::string config_mode = config_mode_prefix + config_platform_; - out << "\t\t" << config_mode << " = " << config_mode << std::endl; - out << "\tEndGlobalSection" << std::endl; + out << "\t\t" << config_mode << " = " << config_mode << "\n"; + out << "\tEndGlobalSection\n"; - out << "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution" - << std::endl; + out << "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n"; for (const std::unique_ptr<SolutionProject>& project : projects_) { const std::string project_config_mode = config_mode_prefix + project->config_platform; out << "\t\t" << project->guid << '.' << config_mode - << ".ActiveCfg = " << project_config_mode << std::endl; + << ".ActiveCfg = " << project_config_mode << "\n"; out << "\t\t" << project->guid << '.' << config_mode - << ".Build.0 = " << project_config_mode << std::endl; + << ".Build.0 = " << project_config_mode << "\n"; } - out << "\tEndGlobalSection" << std::endl; + out << "\tEndGlobalSection\n"; - out << "\tGlobalSection(SolutionProperties) = preSolution" << std::endl; - out << "\t\tHideSolutionNode = FALSE" << std::endl; - out << "\tEndGlobalSection" << std::endl; + out << "\tGlobalSection(SolutionProperties) = preSolution\n"; + out << "\t\tHideSolutionNode = FALSE\n"; + out << "\tEndGlobalSection\n"; - out << "\tGlobalSection(NestedProjects) = preSolution" << std::endl; + out << "\tGlobalSection(NestedProjects) = preSolution\n"; for (const std::unique_ptr<SolutionEntry>& folder : folders_) { if (folder->parent_folder) { out << "\t\t" << folder->guid << " = " << folder->parent_folder->guid - << std::endl; + << "\n"; } } for (const std::unique_ptr<SolutionProject>& project : projects_) { out << "\t\t" << project->guid << " = " << project->parent_folder->guid - << std::endl; + << "\n"; } - out << "\tEndGlobalSection" << std::endl; + out << "\tEndGlobalSection\n"; - out << "EndGlobal" << std::endl; + out << "EndGlobal\n"; } void VisualStudioWriter::ResolveSolutionFolders() { @@ -929,7 +925,7 @@ std::pair<std::string, bool> VisualStudioWriter::GetNinjaTarget( const Target* target) { - std::ostringstream ninja_target_out; + StringOutputStream ninja_target_out; bool is_phony = false; OutputFile output_file; if (target->has_dependency_output_file()) {
diff --git a/src/gn/visual_studio_writer.h b/src/gn/visual_studio_writer.h index 7161481..e725744 100644 --- a/src/gn/visual_studio_writer.h +++ b/src/gn/visual_studio_writer.h
@@ -113,18 +113,18 @@ const std::string& ninja_extra_args, const std::string& ninja_executable, Err* err); - bool WriteProjectFileContents(std::ostream& out, + bool WriteProjectFileContents(OutputStream& out, const SolutionProject& solution_project, const Target* target, const std::string& ninja_extra_args, const std::string& ninja_executable, SourceFileCompileTypePairs* source_types, Err* err); - void WriteFiltersFileContents(std::ostream& out, + void WriteFiltersFileContents(OutputStream& out, const Target* target, const SourceFileCompileTypePairs& source_types); bool WriteSolutionFile(const std::string& sln_name, Err* err); - void WriteSolutionFileContents(std::ostream& out, + void WriteSolutionFileContents(OutputStream& out, const base::FilePath& solution_dir_path); // Resolves all solution folders (parent folders for projects) into |folders_|
diff --git a/src/gn/visual_studio_writer_unittest.cc b/src/gn/visual_studio_writer_unittest.cc index 01271a3..b4abaed 100644 --- a/src/gn/visual_studio_writer_unittest.cc +++ b/src/gn/visual_studio_writer_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/strings/string_util.h" +#include "gn/output_stream.h" #include "gn/test_with_scope.h" #include "gn/visual_studio_utils.h" #include "util/test/test.h" @@ -191,7 +192,7 @@ VisualStudioWriter::SourceFileCompileTypePairs source_types; - std::stringstream file_contents; + StringOutputStream file_contents; writer.WriteProjectFileContents(file_contents, *writer.projects_.back(), &target, "", "", &source_types, &err); @@ -226,7 +227,7 @@ VisualStudioWriter::SourceFileCompileTypePairs source_types; - std::stringstream file_contents_without_flag; + StringOutputStream file_contents_without_flag; writer.WriteProjectFileContents(file_contents_without_flag, *writer.projects_.back(), &target, "", "", &source_types, &err); @@ -235,7 +236,7 @@ ASSERT_NE(file_contents_without_flag.str().find("call ninja.exe"), std::string::npos); - std::stringstream file_contents_with_flag; + StringOutputStream file_contents_with_flag; writer.WriteProjectFileContents(file_contents_with_flag, *writer.projects_.back(), &target, "", "ninja_wrapper.exe", &source_types, &err);
diff --git a/src/gn/xcode_object.cc b/src/gn/xcode_object.cc index 4399c55..58543ee 100644 --- a/src/gn/xcode_object.cc +++ b/src/gn/xcode_object.cc
@@ -4,15 +4,15 @@ #include "gn/xcode_object.h" -#include <iomanip> +#include <cstring> #include <iterator> #include <memory> -#include <sstream> #include <utility> #include "base/logging.h" #include "base/strings/string_util.h" #include "gn/filesystem_utils.h" +#include "gn/output_stream.h" // Helper methods ------------------------------------------------------------- @@ -51,7 +51,7 @@ if (!StringNeedEscaping(string)) return string; - std::stringstream buffer; + StringOutputStream buffer; buffer << '"'; for (char c : string) { if (c <= 31) { @@ -75,10 +75,12 @@ case '\f': buffer << "\\f"; break; - default: - buffer << std::hex << std::setw(4) << std::left << "\\U" - << static_cast<unsigned>(c); + default: { + char buff[10]; + ::snprintf(buff, sizeof(buff), "\\U%04x", static_cast<unsigned>(c)); + buffer << buff; break; + } } } else { if (c == '"' || c == '\\') @@ -171,37 +173,37 @@ explicit NoReference(const PBXObject* value) : value(value) {} }; -void PrintValue(std::ostream& out, IndentRules rules, unsigned value) { +void PrintValue(OutputStream& out, IndentRules rules, unsigned value) { out << value; } -void PrintValue(std::ostream& out, IndentRules rules, const char* value) { +void PrintValue(OutputStream& out, IndentRules rules, const char* value) { out << EncodeString(value); } -void PrintValue(std::ostream& out, +void PrintValue(OutputStream& out, IndentRules rules, const std::string& value) { out << EncodeString(value); } -void PrintValue(std::ostream& out, IndentRules rules, const NoReference& obj) { +void PrintValue(OutputStream& out, IndentRules rules, const NoReference& obj) { out << obj.value->id(); } -void PrintValue(std::ostream& out, IndentRules rules, const PBXObject* value) { +void PrintValue(OutputStream& out, IndentRules rules, const PBXObject* value) { out << value->Reference(); } template <typename ObjectClass> -void PrintValue(std::ostream& out, +void PrintValue(OutputStream& out, IndentRules rules, const std::unique_ptr<ObjectClass>& value) { PrintValue(out, rules, value.get()); } template <typename ValueType> -void PrintValue(std::ostream& out, +void PrintValue(OutputStream& out, IndentRules rules, const std::vector<ValueType>& values) { IndentRules sub_rule{rules.one_line, rules.level + 1}; @@ -220,7 +222,7 @@ } template <typename ValueType> -void PrintValue(std::ostream& out, +void PrintValue(OutputStream& out, IndentRules rules, const std::map<std::string, ValueType>& values) { IndentRules sub_rule{rules.one_line, rules.level + 1}; @@ -240,7 +242,7 @@ } template <typename ValueType> -void PrintProperty(std::ostream& out, +void PrintProperty(OutputStream& out, IndentRules rules, const char* name, ValueType&& value) { @@ -443,7 +445,7 @@ return PBXAggregateTargetClass; } -void PBXAggregateTarget::Print(std::ostream& out, unsigned indent) const { +void PBXAggregateTarget::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -475,7 +477,7 @@ return file_reference_->Name() + " in " + build_phase_->Name(); } -void PBXBuildFile::Print(std::ostream& out, unsigned indent) const { +void PBXBuildFile::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {true, 0}; out << indent_str << Reference() << " = {"; @@ -499,7 +501,7 @@ return "PBXContainerItemProxy"; } -void PBXContainerItemProxy::Print(std::ostream& out, unsigned indent) const { +void PBXContainerItemProxy::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -532,7 +534,7 @@ return !name_.empty() ? name_ : path_; } -void PBXFileReference::Print(std::ostream& out, unsigned indent) const { +void PBXFileReference::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {true, 0}; out << indent_str << Reference() << " = {"; @@ -572,7 +574,7 @@ return "Frameworks"; } -void PBXFrameworksBuildPhase::Print(std::ostream& out, unsigned indent) const { +void PBXFrameworksBuildPhase::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -663,7 +665,7 @@ } } -void PBXGroup::Print(std::ostream& out, unsigned indent) const { +void PBXGroup::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -755,7 +757,7 @@ return PBXNativeTargetClass; } -void PBXNativeTarget::Print(std::ostream& out, unsigned indent) const { +void PBXNativeTarget::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -924,7 +926,7 @@ target->Visit(visitor); } } -void PBXProject::Print(std::ostream& out, unsigned indent) const { +void PBXProject::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -958,7 +960,7 @@ return "Resources"; } -void PBXResourcesBuildPhase::Print(std::ostream& out, unsigned indent) const { +void PBXResourcesBuildPhase::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -987,7 +989,7 @@ return name_; } -void PBXShellScriptBuildPhase::Print(std::ostream& out, unsigned indent) const { +void PBXShellScriptBuildPhase::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -1019,7 +1021,7 @@ return "Sources"; } -void PBXSourcesBuildPhase::Print(std::ostream& out, unsigned indent) const { +void PBXSourcesBuildPhase::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -1055,7 +1057,7 @@ container_item_proxy_->Visit(visitor); } -void PBXTargetDependency::Print(std::ostream& out, unsigned indent) const { +void PBXTargetDependency::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -1081,7 +1083,7 @@ return name_; } -void XCBuildConfiguration::Print(std::ostream& out, unsigned indent) const { +void XCBuildConfiguration::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n"; @@ -1133,7 +1135,7 @@ } } -void XCConfigurationList::Print(std::ostream& out, unsigned indent) const { +void XCConfigurationList::Print(OutputStream& out, unsigned indent) const { const std::string indent_str(indent, '\t'); const IndentRules rules = {false, indent + 1}; out << indent_str << Reference() << " = {\n";
diff --git a/src/gn/xcode_object.h b/src/gn/xcode_object.h index 076e993..8bad659 100644 --- a/src/gn/xcode_object.h +++ b/src/gn/xcode_object.h
@@ -45,6 +45,7 @@ // Forward-declarations ------------------------------------------------------- +class OutputStream; class PBXAggregateTarget; class PBXBuildFile; class PBXBuildPhase; @@ -108,7 +109,7 @@ virtual std::string Comment() const; virtual void Visit(PBXObjectVisitor& visitor); virtual void Visit(PBXObjectVisitorConst& visitor) const; - virtual void Print(std::ostream& out, unsigned indent) const = 0; + virtual void Print(OutputStream& out, unsigned indent) const = 0; private: std::string id_; @@ -180,7 +181,7 @@ // PBXObject implementation. PBXObjectClass Class() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: PBXAggregateTarget(const PBXAggregateTarget&) = delete; @@ -198,7 +199,7 @@ // PBXObject implementation. PBXObjectClass Class() const override; std::string Name() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: const PBXFileReference* file_reference_ = nullptr; @@ -217,7 +218,7 @@ // PBXObject implementation. PBXObjectClass Class() const override; std::string Name() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: const PBXProject* project_ = nullptr; @@ -240,7 +241,7 @@ PBXObjectClass Class() const override; std::string Name() const override; std::string Comment() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; const std::string& path() const { return path_; } @@ -263,7 +264,7 @@ // PBXObject implementation. PBXObjectClass Class() const override; std::string Name() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: PBXFrameworksBuildPhase(const PBXFrameworksBuildPhase&) = delete; @@ -295,7 +296,7 @@ std::string Name() const override; void Visit(PBXObjectVisitor& visitor) override; void Visit(PBXObjectVisitorConst& visitor) const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; // Returns whether the current PBXGroup should sort last when sorting // children of a PBXGroup. This should only be used for the "Products" @@ -353,7 +354,7 @@ // PBXObject implementation. PBXObjectClass Class() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: const PBXFileReference* product_reference_ = nullptr; @@ -402,7 +403,7 @@ std::string Comment() const override; void Visit(PBXObjectVisitor& visitor) override; void Visit(PBXObjectVisitorConst& visitor) const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: PBXAttributes attributes_; @@ -431,7 +432,7 @@ // PBXObject implementation. PBXObjectClass Class() const override; std::string Name() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: PBXResourcesBuildPhase(const PBXResourcesBuildPhase&) = delete; @@ -449,7 +450,7 @@ // PBXObject implementation. PBXObjectClass Class() const override; std::string Name() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: std::string name_; @@ -469,7 +470,7 @@ // PBXObject implementation. PBXObjectClass Class() const override; std::string Name() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: PBXSourcesBuildPhase(const PBXSourcesBuildPhase&) = delete; @@ -489,7 +490,7 @@ std::string Name() const override; void Visit(PBXObjectVisitor& visitor) override; void Visit(PBXObjectVisitorConst& visitor) const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: const PBXTarget* target_ = nullptr; @@ -510,7 +511,7 @@ // PBXObject implementation. PBXObjectClass Class() const override; std::string Name() const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: PBXAttributes attributes_; @@ -534,7 +535,7 @@ std::string Name() const override; void Visit(PBXObjectVisitor& visitor) override; void Visit(PBXObjectVisitorConst& visitor) const override; - void Print(std::ostream& out, unsigned indent) const override; + void Print(OutputStream& out, unsigned indent) const override; private: std::vector<std::unique_ptr<XCBuildConfiguration>> configurations_;
diff --git a/src/gn/xcode_writer.cc b/src/gn/xcode_writer.cc index ea84a3d..85b6c08 100644 --- a/src/gn/xcode_writer.cc +++ b/src/gn/xcode_writer.cc
@@ -9,7 +9,6 @@ #include <map> #include <memory> #include <optional> -#include <sstream> #include <string> #include <string_view> #include <utility> @@ -31,6 +30,7 @@ #include "gn/filesystem_utils.h" #include "gn/item.h" #include "gn/loader.h" +#include "gn/output_stream.h" #include "gn/scheduler.h" #include "gn/settings.h" #include "gn/source_file.h" @@ -551,8 +551,7 @@ if (source_file.is_null()) return false; - StringOutputBuffer storage; - std::ostream out(&storage); + StringOutputBuffer out; out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" << "<Workspace\n" << " version = \"1.0\">\n" @@ -561,8 +560,8 @@ << " </FileRef>\n" << "</Workspace>\n"; - return storage.WriteToFileIfChanged(build_settings_->GetFullPath(source_file), - err); + return out.WriteToFileIfChanged(build_settings_->GetFullPath(source_file), + err); } bool XcodeWorkspace::WriteSettingsFile(const std::string& name, @@ -574,8 +573,7 @@ if (source_file.is_null()) return false; - StringOutputBuffer storage; - std::ostream out(&storage); + StringOutputBuffer out; out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" " << "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" @@ -593,8 +591,8 @@ out << "</dict>\n" << "</plist>\n"; - return storage.WriteToFileIfChanged(build_settings_->GetFullPath(source_file), - err); + return out.WriteToFileIfChanged(build_settings_->GetFullPath(source_file), + err); } // Class responsible for constructing and writing the .xcodeproj from the @@ -660,7 +658,7 @@ std::string GetConfigOutputDir(std::string_view output_dir); // Generates the content of the .xcodeproj file into |out|. - void WriteFileContent(std::ostream& out) const; + void WriteFileContent(OutputStream& out) const; // Returns whether the file should be added to the project. bool ShouldIncludeFileInProject(const SourceFile& source) const; @@ -916,12 +914,11 @@ if (pbxproj_file.is_null()) return false; - StringOutputBuffer storage; - std::ostream pbxproj_string_out(&storage); - WriteFileContent(pbxproj_string_out); + StringOutputBuffer pbxproj_out; + WriteFileContent(pbxproj_out); - if (!storage.WriteToFileIfChanged(build_settings_->GetFullPath(pbxproj_file), - err)) { + if (!pbxproj_out.WriteToFileIfChanged( + build_settings_->GetFullPath(pbxproj_file), err)) { return false; } @@ -1062,7 +1059,7 @@ build_settings_->root_path_utf8()); } -void XcodeProject::WriteFileContent(std::ostream& out) const { +void XcodeProject::WriteFileContent(OutputStream& out) const { out << "// !$*UTF8*$!\n" << "{\n" << "\tarchiveVersion = 1;\n"
diff --git a/src/gn/xml_element_writer.cc b/src/gn/xml_element_writer.cc index f888915..4ee5820 100644 --- a/src/gn/xml_element_writer.cc +++ b/src/gn/xml_element_writer.cc
@@ -19,12 +19,12 @@ return *this; } -XmlElementWriter::XmlElementWriter(std::ostream& out, +XmlElementWriter::XmlElementWriter(OutputStream& out, const std::string& tag, const XmlAttributes& attributes) : XmlElementWriter(out, tag, attributes, 0) {} -XmlElementWriter::XmlElementWriter(std::ostream& out, +XmlElementWriter::XmlElementWriter(OutputStream& out, const std::string& tag, const XmlAttributes& attributes, int indent) @@ -42,11 +42,11 @@ if (!opening_tag_finished_) { // The XML spec does not require a space before the closing slash. However, // Eclipse is unable to parse XML settings files if there is no space. - out_ << " />" << std::endl; + out_ << " />\n"; } else { if (!one_line_) out_ << std::string(indent_, ' '); - out_ << "</" << tag_ << '>' << std::endl; + out_ << "</" << tag_ << ">\n"; } } @@ -67,13 +67,13 @@ return std::make_unique<XmlElementWriter>(out_, tag, attributes, indent_ + 2); } -std::ostream& XmlElementWriter::StartContent(bool start_new_line) { +OutputStream& XmlElementWriter::StartContent(bool start_new_line) { if (!opening_tag_finished_) { out_ << '>'; opening_tag_finished_ = true; if (start_new_line && one_line_) { - out_ << std::endl; + out_ << "\n"; one_line_ = false; } }
diff --git a/src/gn/xml_element_writer.h b/src/gn/xml_element_writer.h index 1bf9b46..e23581f 100644 --- a/src/gn/xml_element_writer.h +++ b/src/gn/xml_element_writer.h
@@ -12,6 +12,8 @@ #include <utility> #include <vector> +#include "gn/output_stream.h" + // Vector of XML attribute key-value pairs. class XmlAttributes : public std::vector<std::pair<std::string_view, std::string_view>> { @@ -29,11 +31,11 @@ public: // Starts new XML element. This constructor adds no indentation and is // designed for XML root element. - XmlElementWriter(std::ostream& out, + XmlElementWriter(OutputStream& out, const std::string& tag, const XmlAttributes& attributes); // Starts new XML element with specified indentation. - XmlElementWriter(std::ostream& out, + XmlElementWriter(OutputStream& out, const std::string& tag, const XmlAttributes& attributes, int indent); @@ -41,7 +43,7 @@ // that allows writing XML element with single attribute without copying // attribute value. template <class Writer> - XmlElementWriter(std::ostream& out, + XmlElementWriter(OutputStream& out, const std::string& tag, const std::string& attribute_name, const Writer& attribute_value_writer, @@ -66,12 +68,12 @@ // Finishes opening tag if it isn't finished yet and optionally starts new // document line. Returns the stream where XML element content can be written. // This is an alternative to Text() and SubElement() methods. - std::ostream& StartContent(bool start_new_line); + OutputStream& StartContent(bool start_new_line); private: // Output stream. XmlElementWriter objects for XML element and its // sub-elements share the same output stream. - std::ostream& out_; + OutputStream& out_; // XML element tag name. std::string tag_; @@ -90,7 +92,7 @@ }; template <class Writer> -XmlElementWriter::XmlElementWriter(std::ostream& out, +XmlElementWriter::XmlElementWriter(OutputStream& out, const std::string& tag, const std::string& attribute_name, const Writer& attribute_value_writer,
diff --git a/src/gn/xml_element_writer_unittest.cc b/src/gn/xml_element_writer_unittest.cc index 6a4cfed..9ad9ed3 100644 --- a/src/gn/xml_element_writer_unittest.cc +++ b/src/gn/xml_element_writer_unittest.cc
@@ -4,8 +4,7 @@ #include "gn/xml_element_writer.h" -#include <sstream> - +#include "gn/output_stream.h" #include "util/test/test.h" namespace { @@ -13,7 +12,7 @@ class MockValueWriter { public: explicit MockValueWriter(const std::string& value) : value_(value) {} - void operator()(std::ostream& out) const { out << value_; } + void operator()(OutputStream& out) const { out << value_; } private: std::string value_; @@ -22,24 +21,24 @@ } // namespace TEST(XmlElementWriter, EmptyElement) { - std::ostringstream out; + StringOutputStream out; { XmlElementWriter writer(out, "foo", XmlAttributes()); } EXPECT_EQ("<foo />\n", out.str()); - std::ostringstream out_attr; + StringOutputStream out_attr; { XmlElementWriter writer(out_attr, "foo", XmlAttributes("bar", "abc").add("baz", "123")); } EXPECT_EQ("<foo bar=\"abc\" baz=\"123\" />\n", out_attr.str()); - std::ostringstream out_indent; + StringOutputStream out_indent; { XmlElementWriter writer(out_indent, "foo", XmlAttributes("bar", "baz"), 2); } EXPECT_EQ(" <foo bar=\"baz\" />\n", out_indent.str()); - std::ostringstream out_writer; + StringOutputStream out_writer; { XmlElementWriter writer(out_writer, "foo", "bar", MockValueWriter("baz"), 2); @@ -48,7 +47,7 @@ } TEST(XmlElementWriter, ElementWithText) { - std::ostringstream out; + StringOutputStream out; { XmlElementWriter writer(out, "foo", XmlAttributes("bar", "baz")); writer.Text("Hello world!"); @@ -57,7 +56,7 @@ } TEST(XmlElementWriter, SubElements) { - std::ostringstream out; + StringOutputStream out; { XmlElementWriter writer(out, "root", XmlAttributes("aaa", "000")); writer.SubElement("foo", XmlAttributes()); @@ -77,7 +76,7 @@ } TEST(XmlElementWriter, StartContent) { - std::ostringstream out; + StringOutputStream out; { XmlElementWriter writer(out, "foo", XmlAttributes("bar", "baz")); writer.StartContent(false) << "Hello world!";