1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef TOOLS_GN_STRING_OUTPUT_BUFFER_H_ 6 #define TOOLS_GN_STRING_OUTPUT_BUFFER_H_ 7 8 #include <array> 9 #include <memory> 10 #include <streambuf> 11 #include <string> 12 #include <string_view> 13 #include <vector> 14 15 namespace base { 16 class FilePath; 17 } // namespace base 18 19 class Err; 20 21 // An append-only very large storage area for string data. Useful for the parts 22 // of GN that need to generate huge output files (e.g. --ide=json will create 23 // a 139 MiB project.json file for the Fuchsia build). 24 // 25 // Usage is the following: 26 // 27 // 1) Create instance. 28 // 29 // 2) Use operator<<, or Append() to append data to the instance. 30 // 31 // 3) Alternatively, create an std::ostream that takes its address as 32 // argument, then use the output stream as usual to append data to it. 33 // 34 // StringOutputBuffer storage; 35 // std::ostream out(&storage); 36 // out << "Hello world!"; 37 // 38 // 4) Use ContentsEqual() to compare the instance's content with that of a 39 // given file. 40 // 41 // 5) Use WriteToFile() to write the content to a given file. 42 // 43 class StringOutputBuffer : public std::streambuf { 44 public: 45 StringOutputBuffer() = default; 46 47 // Convert content to single std::string instance. Useful for unit-testing. 48 std::string str() const; 49 50 // Return the number of characters stored in this instance. size()51 size_t size() const { return (pages_.size() - 1u) * kPageSize + pos_; } 52 53 // Append string to this instance. 54 void Append(const char* str, size_t len); 55 void Append(std::string_view str); 56 void Append(char c); 57 58 StringOutputBuffer& operator<<(std::string_view str) { 59 Append(str); 60 return *this; 61 } 62 63 // Compare the content of this instance with that of the file at |file_path|. 64 bool ContentsEqual(const base::FilePath& file_path) const; 65 66 // Write the contents of this instance to a file at |file_path|. 67 bool WriteToFile(const base::FilePath& file_path, Err* err) const; 68 69 // Write the contents of this instance to a file at |file_path| unless the 70 // file already exists and the contents are equal. 71 bool WriteToFileIfChanged(const base::FilePath& file_path, Err* err) const; 72 GetPageSizeForTesting()73 static size_t GetPageSizeForTesting() { return kPageSize; } 74 75 protected: 76 // Called by std::ostream to write |n| chars from |s|. xsputn(const char * s,std::streamsize n)77 std::streamsize xsputn(const char* s, std::streamsize n) override { 78 Append(s, static_cast<size_t>(n)); 79 return n; 80 } 81 82 // Called by std::ostream to write a single character. overflow(int_type ch)83 int_type overflow(int_type ch) override { 84 Append(static_cast<char>(ch)); 85 return 1; 86 } 87 88 private: 89 // Return the number of free bytes in the current page. page_free_size()90 size_t page_free_size() const { return kPageSize - pos_; } 91 92 static constexpr size_t kPageSize = 65536; 93 using Page = std::array<char, kPageSize>; 94 95 size_t pos_ = kPageSize; 96 std::vector<std::unique_ptr<Page>> pages_; 97 }; 98 99 #endif // TOOLS_GN_STRING_OUTPUT_BUFFER_H_ 100