11#ifndef FORTRAN_RUNTIME_BUFFER_H_
12#define FORTRAN_RUNTIME_BUFFER_H_
15#include "flang/Runtime/freestanding-tools.h"
16#include "flang/Runtime/memory.h"
21namespace Fortran::runtime::io {
23RT_API_ATTRS
void LeftShiftBufferCircularly(
24 char *, std::size_t bytes, std::size_t shift);
49template <
typename STORE, std::
size_t minBuffer = 65536>
class FileFrame {
51 using FileOffset = std::int64_t;
53 RT_API_ATTRS
~FileFrame() { FreeMemoryAndNullify(buffer_); }
60 RT_API_ATTRS FileOffset FrameAt()
const {
return fileOffset_ + frame_; }
61 RT_API_ATTRS
char *Frame()
const {
return buffer_ + start_ + frame_; }
62 RT_API_ATTRS std::size_t FrameLength()
const {
63 return std::min<std::size_t>(length_ - frame_, size_ - (start_ + frame_));
65 RT_API_ATTRS std::size_t BytesBufferedBeforeFrame()
const {
66 return frame_ - start_;
70 RT_API_ATTRS std::size_t ReadFrame(
73 Reallocate(bytes, handler);
74 std::int64_t newFrame{at - fileOffset_};
75 if (newFrame < 0 || newFrame > length_) {
80 RUNTIME_CHECK(handler, at == fileOffset_ + frame_);
81 if (
static_cast<std::int64_t
>(start_ + frame_ + bytes) > size_) {
82 DiscardLeadingBytes(frame_, handler);
83 MakeDataContiguous(handler, bytes);
84 RUNTIME_CHECK(handler, at == fileOffset_ + frame_);
86 if (FrameLength() < bytes) {
87 auto next{start_ + length_};
88 RUNTIME_CHECK(handler, next < size_);
89 auto minBytes{bytes - FrameLength()};
90 auto maxBytes{size_ - next};
91 auto got{Store().Read(
92 fileOffset_ + length_, buffer_ + next, minBytes, maxBytes, handler)};
94 RUNTIME_CHECK(handler, length_ <= size_);
99 RT_API_ATTRS
void WriteFrame(
101 Reallocate(bytes, handler);
102 std::int64_t newFrame{at - fileOffset_};
103 if (!dirty_ || newFrame < 0 || newFrame > length_) {
106 }
else if (start_ + newFrame +
static_cast<std::int64_t
>(bytes) > size_) {
108 Flush(handler, length_ - newFrame);
109 MakeDataContiguous(handler, bytes);
113 RUNTIME_CHECK(handler, at == fileOffset_ + frame_);
115 length_ = std::max<std::int64_t>(length_, frame_ + bytes);
118 RT_API_ATTRS
void Flush(
IoErrorHandler &handler, std::int64_t keep = 0) {
120 while (length_ > keep) {
122 std::min<std::size_t>(length_ - keep, size_ - start_)};
124 Store().Write(fileOffset_, buffer_ + start_, chunk, handler)};
125 DiscardLeadingBytes(put, handler);
136 RT_API_ATTRS
void TruncateFrame(std::int64_t at,
IoErrorHandler &handler) {
137 RUNTIME_CHECK(handler, !dirty_);
138 if (at <= fileOffset_) {
140 }
else if (at < fileOffset_ + length_) {
141 length_ = at - fileOffset_;
146 RT_API_ATTRS STORE &Store() {
return static_cast<STORE &
>(*this); }
148 RT_API_ATTRS
void Reallocate(
149 std::int64_t bytes,
const Terminator &terminator) {
153 size_ = std::max<std::int64_t>(bytes, size_ + minBuffer);
155 reinterpret_cast<char *
>(AllocateMemoryOrCrash(terminator, size_));
156 auto chunk{std::min<std::int64_t>(length_, oldSize - start_)};
160 if (old !=
nullptr) {
161 std::memcpy(buffer_, old + start_, chunk);
162 std::memcpy(buffer_ + chunk, old, length_ - chunk);
169 RT_API_ATTRS
void Reset(FileOffset at) {
170 start_ = length_ = frame_ = 0;
175 RT_API_ATTRS
void DiscardLeadingBytes(
176 std::int64_t n,
const Terminator &terminator) {
177 RUNTIME_CHECK(terminator, length_ >= n);
183 if (start_ >= size_) {
195 RT_API_ATTRS
void MakeDataContiguous(
197 if (
static_cast<std::int64_t
>(start_ + bytes) > size_) {
200 RUNTIME_CHECK(handler, length_ < size_);
201 if (start_ + length_ <= size_) {
203 runtime::memmove(buffer_, buffer_ + start_, length_);
206 auto n{start_ + length_ - size_};
207 RUNTIME_CHECK(handler, length_ >= n);
208 runtime::memmove(buffer_ + n, buffer_ + start_, length_ - n);
209 LeftShiftBufferCircularly(buffer_, length_, n);
215 char *buffer_{
nullptr};
216 std::int64_t size_{0};
217 FileOffset fileOffset_{0};
218 std::int64_t start_{0};
219 std::int64_t length_{0};
220 std::int64_t frame_{0};
Definition: terminator.h:23
Definition: io-error.h:26