OR-Tools  9.6
filelineiter.h
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 // Allows to read a text file line by line with:
15 // for (const std::string& line : FileLines("myfile.txt")) { ... }
16 //
17 // More details:
18 // * The lines are separated by '\n' (which is removed by default) and have no
19 // size limits.
20 // * Consecutive '\n' result in empty lines being produced.
21 // * If not empty, the string after the last '\n' is produced as the last line.
22 // * Options are available to keep the trailing '\n' for each line, to remove
23 // carriage-return characters ('\r'), and to remove blank lines.
24 //
25 #ifndef OR_TOOLS_UTIL_FILELINEITER_H_
26 #define OR_TOOLS_UTIL_FILELINEITER_H_
27 
28 #include <algorithm>
29 #include <memory>
30 #include <string>
31 
32 #include "absl/status/statusor.h"
33 #include "absl/strings/match.h"
34 #include "ortools/base/file.h"
35 #include "ortools/base/logging.h"
37 
38 // Implements the minimum interface for a range-based for loop iterator.
40  public:
41  enum {
42  DEFAULT = 0x0000,
44  KEEP_LINEFEED = 0x0001, // Terminating \n in result.
45  REMOVE_INLINE_CR = 0x0002, // Remove \r characters.
46  REMOVE_BLANK_LINES = 0x0004, // Remove empty or \n-only lines.
47  };
48 
49  FileLineIterator(File* file, int options)
50  : next_position_after_eol_(0),
51  buffer_size_(0),
52  file_(file),
53  options_(options) {
54  ReadNextLine();
55  }
56  const std::string& operator*() const { return line_; }
57  bool operator!=(const FileLineIterator& other) const {
58  return file_ != other.file_;
59  }
60  void operator++() { ReadNextLine(); }
61 
62  private:
63  bool HasOption(int option) const { return options_ & option; }
64 
65  void ReadNextLine() {
66  line_.clear();
67  if (file_ == nullptr) return;
68  do {
69  while (true) {
70  int i = next_position_after_eol_;
71  for (; i < buffer_size_; ++i) {
72  if (buffer_[i] == '\n') break;
73  }
74  if (i == buffer_size_) {
75  line_.append(&buffer_[next_position_after_eol_],
76  i - next_position_after_eol_);
77  buffer_size_ = file_->Read(&buffer_, kBufferSize);
78  if (buffer_size_ < 0) {
79  LOG(WARNING) << "Error while reading file.";
80  file_ = nullptr;
81  break;
82  }
83  next_position_after_eol_ = 0;
84  if (buffer_size_ == 0) {
85  if (line_.empty()) {
86  file_ = nullptr;
87  }
88  break;
89  }
90  } else {
91  line_.append(&buffer_[next_position_after_eol_],
92  i - next_position_after_eol_ + 1);
93  next_position_after_eol_ = i + 1;
94  break;
95  }
96  }
97  PostProcessLine();
98  } while (file_ != nullptr && HasOption(REMOVE_BLANK_LINES) &&
99  (line_.empty() || line_ == "\n"));
100  }
101 
102  void PostProcessLine() {
103  if (HasOption(REMOVE_INLINE_CR)) {
104  line_.erase(std::remove(line_.begin(), line_.end(), '\r'), line_.end());
105  }
106  const auto eol = std::find(line_.begin(), line_.end(), '\n');
107  if (!HasOption(KEEP_LINEFEED) && eol != line_.end()) {
108  line_.erase(eol);
109  }
110  }
111 
112  static constexpr int kBufferSize = 5 * 1024;
113  char buffer_[kBufferSize];
114  int next_position_after_eol_;
115  int64_t buffer_size_;
116  File* file_;
117  std::string line_;
118  const int options_;
119 };
120 
121 class FileLines {
122  public:
123  // Initializes with a provided file, taking ownership of it.
124  //
125  // If file is nullptr, this class behaves as if the file was empty.
126  //
127  // Usage:
128  //
129  // File* file = nullptr;
130  // RETURN_IF_ERROR(file::Open(filename, "r", &file, file::Defaults()));
131  // for (const absl::string_view line : FileLines(filename, file)) {
132  // ...
133  // }
134  //
135  FileLines(const std::string& filename, File* const file,
136  const int options = FileLineIterator::DEFAULT)
137  : file_(file), options_(options) {
138  if (!file_) {
139  return;
140  }
141  }
142 
143  // Initializes the FileLines ignoring errors.
144  //
145  // Please prefer the other constructor combined with file::Open() in new code
146  // so that missing files are properly detected. This version would only print
147  // a warning and act as if the file was empty.
148  explicit FileLines(const std::string& filename,
149  int options = FileLineIterator::DEFAULT)
150  : FileLines(
151  filename,
152  [&]() {
153  File* file = nullptr;
154  if (!file::Open(filename, "r", &file, file::Defaults()).ok()) {
155  LOG(WARNING) << "Could not open: " << filename;
156  }
157  return file;
158  }(),
159  options) {}
160 
161  FileLines(const FileLines&) = delete;
162  FileLines& operator=(const FileLines&) = delete;
163 
165  if (file_ != nullptr) file_->Close(file::Defaults()).IgnoreError();
166  }
167 
168  FileLineIterator begin() { return FileLineIterator(file_, options_); }
169 
170  FileLineIterator end() const { return FileLineIterator(nullptr, options_); }
171 
172  private:
173  // Can be nullptr when the FileLines() constructor is used instead of
174  // FileLines::New().
175  File* file_;
176  const int options_;
177 };
178 
179 #endif // OR_TOOLS_UTIL_FILELINEITER_H_
Definition: base/file.h:33
size_t Read(void *const buff, size_t size)
Definition: base/file.cc:71
bool Close()
Definition: base/file.cc:49
bool operator!=(const FileLineIterator &other) const
Definition: filelineiter.h:57
FileLineIterator(File *file, int options)
Definition: filelineiter.h:49
const std::string & operator*() const
Definition: filelineiter.h:56
FileLineIterator end() const
Definition: filelineiter.h:170
FileLineIterator begin()
Definition: filelineiter.h:168
FileLines(const std::string &filename, File *const file, const int options=FileLineIterator::DEFAULT)
Definition: filelineiter.h:135
FileLines & operator=(const FileLines &)=delete
FileLines(const FileLines &)=delete
FileLines(const std::string &filename, int options=FileLineIterator::DEFAULT)
Definition: filelineiter.h:148
Options Defaults()
Definition: base/file.h:123
absl::Status Open(const absl::string_view &filename, const absl::string_view &mode, File **f, int flags)
Definition: base/file.cc:143