1#pragma once
2
3#include <stdio.h>
4#include <fstream>
5#include <memory>
6#include <string>
7#include "absl/strings/string_view.h"
8#include "muduo/base/Logging.h"  // CHECK_NOTNULL
9
10const int kBufferSize = 1024 * 1024;
11
12// Wrappers FILE* from stdio.
13class File
14{
15 public:
16  int64_t tell() const
17  {
18    return ::ftell(file_);
19  }
20
21  void close()
22  {
23    if (file_)
24      ::fclose(file_);
25    file_ = nullptr;
26    buffer_.reset();
27  }
28
29  const std::string& filename() const
30  {
31    return filename_;
32  }
33
34  // https://github.com/coreutils/coreutils/blob/master/src/ioblksize.h
35  /* As of May 2014, 128KiB is determined to be the minimium
36   * blksize to best minimize system call overhead.
37   */
38
39 protected:
40  File(const std::string& filename, const char* mode, int bufsize=kBufferSize)
41    : filename_(filename),
42      file_(CHECK_NOTNULL(::fopen(filename.c_str(), mode))),
43      buffer_(CHECK_NOTNULL(new char[bufsize]))
44  {
45    ::setbuffer(file_, buffer_.get(), bufsize);
46  }
47
48  virtual ~File()
49  {
50    close();
51  }
52
53 protected:
54  std::string filename_;
55  FILE* file_ = nullptr;
56
57 private:
58  std::unique_ptr<char[]> buffer_;
59
60  File(const File&) = delete;
61  void operator=(const File&) = delete;
62};
63
64class InputFile : public File
65{
66 public:
67  explicit InputFile(const char* filename, int bufsize=kBufferSize)
68    : File(filename, "r", bufsize)
69  {
70  }
71
72  bool getline(std::string* output)
73  {
74    char buf[1024];  // ="" will slow down by 50%!!!
75    if (::fgets(buf, sizeof buf, file_))
76    {
77      *output = buf;
78      if (!output->empty() && output->back() == '\n')
79      {
80        output->resize(output->size()-1);
81      }
82      return true;
83    }
84    return false;
85  }
86};
87
88/*
89class InputFile2
90{
91 public:
92  explicit InputFile2(const char* filename, int bufsize=kBufferSize)
93    : filename_(filename),
94      in_(filename)
95  {
96    // FIXME: bufsize
97  }
98
99  bool getline(std::string* output)
100  {
101    return static_cast<bool>(std::getline(in_, *output));
102  }
103
104  const std::string& filename() const
105  {
106    return filename_;
107  }
108
109 private:
110  std::string filename_;
111  std::ifstream in_;
112};
113*/
114
115class OutputFile : public File
116{
117 public:
118  explicit OutputFile(const std::string& filename)
119    : File(filename, "w")
120  {
121  }
122
123  void write(absl::string_view s)
124  {
125    ::fwrite(s.data(), 1, s.size(), file_);
126  }
127
128  void writeWord(int64_t count, absl::string_view word)
129  {
130    ::fprintf(file_, "%ld\t", count);
131    ::fwrite(word.data(), 1, word.size(), file_);
132    ::fwrite("\n", 1, 1, file_);
133  }
134
135  void appendRecord(absl::string_view s)
136  {
137    assert(s.size() < 255);
138    uint8_t len = s.size();
139    ::fwrite(&len, 1, sizeof len, file_);
140    ::fwrite(s.data(), 1, len, file_);
141    ++items_;
142  }
143
144  size_t items()
145  {
146    return items_;
147  }
148
149 private:
150  size_t items_ = 0;
151};
152
153