2 * Copyright 2017 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #ifndef FOLLY_GEN_FILE_H_
18 #error This file may only be included from folly/gen/File.h
21 #include <system_error>
23 #include <folly/gen/String.h>
29 class FileReader : public GenImpl<ByteRange, FileReader> {
31 FileReader(File file, std::unique_ptr<IOBuf> buffer)
32 : file_(std::move(file)),
33 buffer_(std::move(buffer)) {
38 bool apply(Body&& body) const {
42 n = ::read(file_.fd(), buffer_->writableTail(), buffer_->capacity());
43 } while (n == -1 && errno == EINTR);
45 throw std::system_error(errno, std::system_category(), "read failed");
50 if (!body(ByteRange(buffer_->tail(), size_t(n)))) {
56 // Technically, there could be infinite files (e.g. /dev/random), but people
57 // who open those can do so at their own risk.
58 static constexpr bool infinite = false;
62 std::unique_ptr<IOBuf> buffer_;
65 class FileWriter : public Operator<FileWriter> {
67 FileWriter(File file, std::unique_ptr<IOBuf> buffer)
68 : file_(std::move(file)),
69 buffer_(std::move(buffer)) {
75 template <class Source, class Value>
76 void compose(const GenImpl<Value, Source>& source) const {
77 auto fn = [&](ByteRange v) {
78 if (!this->buffer_ || v.size() >= this->buffer_->capacity()) {
82 if (v.size() > this->buffer_->tailroom()) {
85 memcpy(this->buffer_->writableTail(), v.data(), v.size());
86 this->buffer_->append(v.size());
91 source.foreach(std::move(fn));
98 void write(ByteRange v) const {
102 n = ::write(file_.fd(), v.data(), v.size());
103 } while (n == -1 && errno == EINTR);
105 throw std::system_error(errno, std::system_category(),
108 v.advance(size_t(n));
112 void flushBuffer() const {
113 if (buffer_ && buffer_->length() != 0) {
114 write(ByteRange(buffer_->data(), buffer_->length()));
120 std::unique_ptr<IOBuf> buffer_;
123 inline auto byLineImpl(File file, char delim, bool keepDelimiter)
124 -> decltype(fromFile(std::move(file))
125 | eachAs<StringPiece>()
126 | resplit(delim, keepDelimiter)) {
127 return fromFile(std::move(file))
128 | eachAs<StringPiece>()
129 | resplit(delim, keepDelimiter);
135 * Generator which reads lines from a file.
136 * Note: This produces StringPieces which reference temporary strings which are
137 * only valid during iteration.
139 inline auto byLineFull(File file, char delim = '\n')
140 -> decltype(detail::byLineImpl(std::move(file), delim, true)) {
141 return detail::byLineImpl(std::move(file), delim, true);
144 inline auto byLineFull(int fd, char delim = '\n')
145 -> decltype(byLineFull(File(fd), delim)) {
146 return byLineFull(File(fd), delim);
149 inline auto byLineFull(const char* f, char delim = '\n')
150 -> decltype(byLineFull(File(f), delim)) {
151 return byLineFull(File(f), delim);
154 inline auto byLine(File file, char delim = '\n')
155 -> decltype(detail::byLineImpl(std::move(file), delim, false)) {
156 return detail::byLineImpl(std::move(file), delim, false);
159 inline auto byLine(int fd, char delim = '\n')
160 -> decltype(byLine(File(fd), delim)) { return byLine(File(fd), delim); }
162 inline auto byLine(const char* f, char delim = '\n')
163 -> decltype(byLine(File(f), delim)) { return byLine(File(f), delim); }