• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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