vn-verdnaturachat/ios/Pods/Flipper-Folly/folly/gen/File-inl.h

162 lines
4.1 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOLLY_GEN_FILE_H_
#error This file may only be included from folly/gen/File.h
#endif
#include <system_error>
#include <folly/gen/String.h>
namespace folly {
namespace gen {
namespace detail {
class FileReader : public GenImpl<ByteRange, FileReader> {
public:
FileReader(File file, std::unique_ptr<IOBuf> buffer)
: file_(std::move(file)), buffer_(std::move(buffer)) {
buffer_->clear();
}
template <class Body>
bool apply(Body&& body) const {
for (;;) {
ssize_t n;
do {
n = ::read(file_.fd(), buffer_->writableTail(), buffer_->capacity());
} while (n == -1 && errno == EINTR);
if (n == -1) {
throw std::system_error(errno, std::system_category(), "read failed");
}
if (n == 0) {
return true;
}
if (!body(ByteRange(buffer_->tail(), size_t(n)))) {
return false;
}
}
}
// Technically, there could be infinite files (e.g. /dev/random), but people
// who open those can do so at their own risk.
static constexpr bool infinite = false;
private:
File file_;
std::unique_ptr<IOBuf> buffer_;
};
class FileWriter : public Operator<FileWriter> {
public:
FileWriter(File file, std::unique_ptr<IOBuf> buffer)
: file_(std::move(file)), buffer_(std::move(buffer)) {
if (buffer_) {
buffer_->clear();
}
}
template <class Source, class Value>
void compose(const GenImpl<Value, Source>& source) const {
auto fn = [&](ByteRange v) {
if (!this->buffer_ || v.size() >= this->buffer_->capacity()) {
this->flushBuffer();
this->write(v);
} else {
if (v.size() > this->buffer_->tailroom()) {
this->flushBuffer();
}
memcpy(this->buffer_->writableTail(), v.data(), v.size());
this->buffer_->append(v.size());
}
};
// Iterate
source.foreach(std::move(fn));
flushBuffer();
file_.close();
}
private:
void write(ByteRange v) const {
ssize_t n;
while (!v.empty()) {
do {
n = ::write(file_.fd(), v.data(), v.size());
} while (n == -1 && errno == EINTR);
if (n == -1) {
throw std::system_error(
errno, std::system_category(), "write() failed");
}
v.advance(size_t(n));
}
}
void flushBuffer() const {
if (buffer_ && buffer_->length() != 0) {
write(ByteRange(buffer_->data(), buffer_->length()));
buffer_->clear();
}
}
mutable File file_;
std::unique_ptr<IOBuf> buffer_;
};
inline auto byLineImpl(File file, char delim, bool keepDelimiter) {
// clang-format off
return fromFile(std::move(file))
| eachAs<StringPiece>()
| resplit(delim, keepDelimiter);
// clang-format on
}
} // namespace detail
/**
* Generator which reads lines from a file.
* Note: This produces StringPieces which reference temporary strings which are
* only valid during iteration.
*/
inline auto byLineFull(File file, char delim = '\n') {
return detail::byLineImpl(std::move(file), delim, true);
}
inline auto byLineFull(int fd, char delim = '\n') {
return byLineFull(File(fd), delim);
}
inline auto byLineFull(const char* f, char delim = '\n') {
return byLineFull(File(f), delim);
}
inline auto byLine(File file, char delim = '\n') {
return detail::byLineImpl(std::move(file), delim, false);
}
inline auto byLine(int fd, char delim = '\n') {
return byLine(File(fd), delim);
}
inline auto byLine(const char* f, char delim = '\n') {
return byLine(File(f), delim);
}
} // namespace gen
} // namespace folly