blob: 2338860ed5190f160d7ba1d1810ecad3e85fc5c4 [file] [log] [blame]
// Copyright 2020 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 <array>
#include <memory>
#include <streambuf>
#include <string>
#include <string_view>
#include <vector>
namespace base {
class FilePath;
} // namespace base
class Err;
// 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
// a 139 MiB project.json file for the Fuchsia build).
// Usage is the following:
// 1) Create instance.
// 2) Use operator<<, or Append() to append data to the instance.
// 3) Alternatively, create an std::ostream that takes its address as
// argument, then use the output stream as usual to append data to it.
// StringOutputBuffer storage;
// std::ostream out(&storage);
// out << "Hello world!";
// 4) Use ContentsEqual() to compare the instance's content with that of a
// given file.
// 5) Use WriteToFile() to write the content to a given file.
class StringOutputBuffer : public std::streambuf {
StringOutputBuffer() = default;
// Convert content to single std::string instance. Useful for unit-testing.
std::string str() const;
// Return the number of characters stored in this instance.
size_t size() const { return (pages_.size() - 1u) * kPageSize + pos_; }
// Append string to this instance.
void Append(const char* str, size_t len);
void Append(std::string_view str);
void Append(char c);
StringOutputBuffer& operator<<(std::string_view str) {
return *this;
// Compare the content of this instance with that of the file at |file_path|.
bool ContentsEqual(const base::FilePath& file_path) const;
// Write the contents of this instance to a file at |file_path|.
bool WriteToFile(const base::FilePath& file_path, Err* err) const;
// Write the contents of this instance to a file at |file_path| unless the
// file already exists and the contents are equal.
bool WriteToFileIfChanged(const base::FilePath& file_path, Err* err) const;
static size_t GetPageSizeForTesting() { return kPageSize; }
// 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 {
return 1;
// Return the number of free bytes in the current page.
size_t page_free_size() const { return kPageSize - pos_; }
static constexpr size_t kPageSize = 65536;
using Page = std::array<char, kPageSize>;
size_t pos_ = kPageSize;
std::vector<std::unique_ptr<Page>> pages_;