FLANG

io-stmt.h
1 //===-- runtime/io-stmt.h ---------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // Representations of the state of an I/O statement in progress
10
11 #ifndef FORTRAN_RUNTIME_IO_STMT_H_
12 #define FORTRAN_RUNTIME_IO_STMT_H_
13
14 #include "connection.h"
15 #include "descriptor.h"
16 #include "file.h"
17 #include "format.h"
18 #include "internal-unit.h"
19 #include "io-error.h"
20 #include <functional>
21 #include <type_traits>
22 #include <variant>
23
24 namespace Fortran::runtime::io {
25
26 class ExternalFileUnit;
27
28 class OpenStatementState;
29 class CloseStatementState;
30 class NoopCloseStatementState;
31
32 template <Direction, typename CHAR = char>
33 class InternalFormattedIoStatementState;
34 template <Direction, typename CHAR = char> class InternalListIoStatementState;
35 template <Direction, typename CHAR = char>
36 class ExternalFormattedIoStatementState;
37 template <Direction> class ExternalListIoStatementState;
38 template <Direction> class UnformattedIoStatementState;
39 class ExternalMiscIoStatementState;
40
41 // The Cookie type in the I/O API is a pointer (for C) to this class.
42 class IoStatementState {
43 public:
44 template <typename A> explicit IoStatementState(A &x) : u_{x} {}
45
46 // These member functions each project themselves into the active alternative.
47 // They're used by per-data-item routines in the I/O API (e.g., OutputReal64)
48 // to interact with the state of the I/O statement in progress.
49 // This design avoids virtual member functions and function pointers,
50 // which may not have good support in some runtime environments.
51 std::optional<DataEdit> GetNextDataEdit(int = 1);
52 bool Emit(const char *, std::size_t);
53 std::optional<char32_t> GetCurrentChar(); // vacant after end of record
54 bool AdvanceRecord(int = 1);
55 void BackspaceRecord();
56 void HandleRelativePosition(std::int64_t);
57 int EndIoStatement();
58 ConnectionState &GetConnectionState();
59 IoErrorHandler &GetIoErrorHandler() const;
60 ExternalFileUnit *GetExternalFileUnit() const; // null if internal unit
61 MutableModes &mutableModes();
62
63 // N.B.: this also works with base classes
64 template <typename A> A *get_if() const {
65 return std::visit(
66 [](auto &x) -> A * {
67 if constexpr (std::is_convertible_v<decltype(x.get()), A &>) {
68 return &x.get();
69 }
70 return nullptr;
71 },
72 u_);
73 }
74
75 bool EmitRepeated(char, std::size_t);
76 bool EmitField(const char *, std::size_t length, std::size_t width);
77
78 std::optional<char32_t> SkipSpaces(std::optional<int> &remaining);
79 std::optional<char32_t> NextInField(std::optional<int> &remaining);
80 std::optional<char32_t> GetNextNonBlank(); // can advance record
81
82 private:
83 std::variant<std::reference_wrapper<OpenStatementState>,
84 std::reference_wrapper<CloseStatementState>,
85 std::reference_wrapper<NoopCloseStatementState>,
86 std::reference_wrapper<
87 InternalFormattedIoStatementState<Direction::Output>>,
88 std::reference_wrapper<
89 InternalFormattedIoStatementState<Direction::Input>>,
90 std::reference_wrapper<InternalListIoStatementState<Direction::Output>>,
91 std::reference_wrapper<InternalListIoStatementState<Direction::Input>>,
92 std::reference_wrapper<
93 ExternalFormattedIoStatementState<Direction::Output>>,
94 std::reference_wrapper<
95 ExternalFormattedIoStatementState<Direction::Input>>,
96 std::reference_wrapper<ExternalListIoStatementState<Direction::Output>>,
97 std::reference_wrapper<ExternalListIoStatementState<Direction::Input>>,
98 std::reference_wrapper<UnformattedIoStatementState<Direction::Output>>,
99 std::reference_wrapper<UnformattedIoStatementState<Direction::Input>>,
100 std::reference_wrapper<ExternalMiscIoStatementState>>
101 u_;
102 };
103
104 // Base class for all per-I/O statement state classes.
105 // Inherits IoErrorHandler from its base.
106 struct IoStatementBase : public DefaultFormatControlCallbacks {
107 using DefaultFormatControlCallbacks::DefaultFormatControlCallbacks;
108 int EndIoStatement();
109 std::optional<DataEdit> GetNextDataEdit(IoStatementState &, int = 1);
110 ExternalFileUnit *GetExternalFileUnit() const { return nullptr; }
111 };
112
113 struct InputStatementState {};
114 struct OutputStatementState {};
115 template <Direction D>
116 using IoDirectionState = std::conditional_t<D == Direction::Input,
117 InputStatementState, OutputStatementState>;
118
119 struct FormattedStatementState {};
120
121 // Common state for list-directed internal & external I/O
122 template <Direction> struct ListDirectedStatementState {};
123 template <> struct ListDirectedStatementState<Direction::Output> {
124 static std::size_t RemainingSpaceInRecord(const ConnectionState &);
125 bool NeedAdvance(const ConnectionState &, std::size_t) const;
126 bool EmitLeadingSpaceOrAdvance(
127 IoStatementState &, std::size_t, bool isCharacter = false);
128 std::optional<DataEdit> GetNextDataEdit(
129 IoStatementState &, int maxRepeat = 1);
130 bool lastWasUndelimitedCharacter{false};
131 };
132 template <> class ListDirectedStatementState<Direction::Input> {
133 public:
134 // Skips value separators, handles repetition and null values.
135 // Vacant when '/' appears; present with descriptor == ListDirectedNullValue
136 // when a null value appears.
137 std::optional<DataEdit> GetNextDataEdit(
138 IoStatementState &, int maxRepeat = 1);
139
140 private:
141 int remaining_{0}; // for "r*" repetition
142 std::int64_t initialRecordNumber_;
143 std::int64_t initialPositionInRecord_;
144 bool isFirstItem_{true}; // leading separator implies null first item
145 bool hitSlash_{false}; // once '/' is seen, nullify further items
146 bool realPart_{false};
147 bool imaginaryPart_{false};
148 };
149
150 template <Direction DIR, typename CHAR = char>
151 class InternalIoStatementState : public IoStatementBase,
152 public IoDirectionState<DIR> {
153 public:
154 using CharType = CHAR;
155 using Buffer =
156 std::conditional_t<DIR == Direction::Input, const CharType *, CharType *>;
157 InternalIoStatementState(Buffer, std::size_t,
158 const char *sourceFile = nullptr, int sourceLine = 0);
159 InternalIoStatementState(
160 const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
161 int EndIoStatement();
162 bool Emit(const CharType *, std::size_t chars /* not bytes */);
163 std::optional<char32_t> GetCurrentChar();
164 bool AdvanceRecord(int = 1);
165 void BackspaceRecord();
166 ConnectionState &GetConnectionState() { return unit_; }
167 MutableModes &mutableModes() { return unit_.modes; }
168 void HandleRelativePosition(std::int64_t);
169 void HandleAbsolutePosition(std::int64_t);
170
171 protected:
172 bool free_{true};
173 InternalDescriptorUnit<DIR> unit_;
174 };
175
176 template <Direction DIR, typename CHAR>
177 class InternalFormattedIoStatementState
178 : public InternalIoStatementState<DIR, CHAR>,
179 public FormattedStatementState {
180 public:
181 using CharType = CHAR;
182 using typename InternalIoStatementState<DIR, CharType>::Buffer;
183 InternalFormattedIoStatementState(Buffer internal, std::size_t internalLength,
184 const CharType *format, std::size_t formatLength,
185 const char *sourceFile = nullptr, int sourceLine = 0);
186 InternalFormattedIoStatementState(const Descriptor &, const CharType *format,
187 std::size_t formatLength, const char *sourceFile = nullptr,
188 int sourceLine = 0);
189 IoStatementState &ioStatementState() { return ioStatementState_; }
190 int EndIoStatement();
191 std::optional<DataEdit> GetNextDataEdit(
192 IoStatementState &, int maxRepeat = 1) {
193 return format_.GetNextDataEdit(*this, maxRepeat);
194 }
195
196 private:
197 IoStatementState ioStatementState_; // points to *this
198 using InternalIoStatementState<DIR, CharType>::unit_;
199 // format_ *must* be last; it may be partial someday
200 FormatControl<InternalFormattedIoStatementState> format_;
201 };
202
203 template <Direction DIR, typename CHAR>
204 class InternalListIoStatementState : public InternalIoStatementState<DIR, CHAR>,
205 public ListDirectedStatementState<DIR> {
206 public:
207 using CharType = CHAR;
208 using typename InternalIoStatementState<DIR, CharType>::Buffer;
209 InternalListIoStatementState(Buffer internal, std::size_t internalLength,
210 const char *sourceFile = nullptr, int sourceLine = 0);
211 InternalListIoStatementState(
212 const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
213 IoStatementState &ioStatementState() { return ioStatementState_; }
214 using ListDirectedStatementState<DIR>::GetNextDataEdit;
215
216 private:
217 IoStatementState ioStatementState_; // points to *this
218 using InternalIoStatementState<DIR, CharType>::unit_;
219 };
220
221 class ExternalIoStatementBase : public IoStatementBase {
222 public:
223 ExternalIoStatementBase(
224 ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
225 ExternalFileUnit &unit() { return unit_; }
226 MutableModes &mutableModes();
227 ConnectionState &GetConnectionState();
228 int EndIoStatement();
229 ExternalFileUnit *GetExternalFileUnit() { return &unit_; }
230
231 private:
232 ExternalFileUnit &unit_;
233 };
234
235 template <Direction DIR>
236 class ExternalIoStatementState : public ExternalIoStatementBase,
237 public IoDirectionState<DIR> {
238 public:
239 using ExternalIoStatementBase::ExternalIoStatementBase;
240 int EndIoStatement();
241 bool Emit(const char *, std::size_t);
242 bool Emit(const char16_t *, std::size_t chars /* not bytes */);
243 bool Emit(const char32_t *, std::size_t chars /* not bytes */);
244 std::optional<char32_t> GetCurrentChar();
245 bool AdvanceRecord(int = 1);
246 void BackspaceRecord();
247 void HandleRelativePosition(std::int64_t);
248 void HandleAbsolutePosition(std::int64_t);
249 };
250
251 template <Direction DIR, typename CHAR>
252 class ExternalFormattedIoStatementState : public ExternalIoStatementState<DIR>,
253 public FormattedStatementState {
254 public:
255 using CharType = CHAR;
256 ExternalFormattedIoStatementState(ExternalFileUnit &, const CharType *format,
257 std::size_t formatLength, const char *sourceFile = nullptr,
258 int sourceLine = 0);
259 MutableModes &mutableModes() { return mutableModes_; }
260 int EndIoStatement();
261 std::optional<DataEdit> GetNextDataEdit(
262 IoStatementState &, int maxRepeat = 1) {
263 return format_.GetNextDataEdit(*this, maxRepeat);
264 }
265
266 private:
267 // These are forked from ConnectionState's modes at the beginning
268 // of each formatted I/O statement so they may be overridden by control
269 // edit descriptors during the statement.
270 MutableModes mutableModes_;
271 FormatControl<ExternalFormattedIoStatementState> format_;
272 };
273
274 template <Direction DIR>
275 class ExternalListIoStatementState : public ExternalIoStatementState<DIR>,
276 public ListDirectedStatementState<DIR> {
277 public:
278 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
279 using ListDirectedStatementState<DIR>::GetNextDataEdit;
280 };
281
282 template <Direction DIR>
283 class UnformattedIoStatementState : public ExternalIoStatementState<DIR> {
284 public:
285 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
286 bool Receive(char *, std::size_t);
287 int EndIoStatement();
288 };
289
290 class OpenStatementState : public ExternalIoStatementBase {
291 public:
292 OpenStatementState(ExternalFileUnit &unit, bool wasExtant,
293 const char *sourceFile = nullptr, int sourceLine = 0)
294 : ExternalIoStatementBase{unit, sourceFile, sourceLine}, wasExtant_{
295 wasExtant} {}
296 bool wasExtant() const { return wasExtant_; }
297 void set_status(OpenStatus status) { status_ = status; }
298 void set_path(const char *, std::size_t, int kind); // FILE=
299 void set_position(Position position) { position_ = position; } // POSITION=
300 int EndIoStatement();
301
302 private:
303 bool wasExtant_;
304 OpenStatus status_{OpenStatus::Unknown};
305 Position position_{Position::AsIs};
306 OwningPtr<char> path_;
307 std::size_t pathLength_;
308 };
309
310 class CloseStatementState : public ExternalIoStatementBase {
311 public:
312 CloseStatementState(ExternalFileUnit &unit, const char *sourceFile = nullptr,
313 int sourceLine = 0)
314 : ExternalIoStatementBase{unit, sourceFile, sourceLine} {}
315 void set_status(CloseStatus status) { status_ = status; }
316 int EndIoStatement();
317
318 private:
319 CloseStatus status_{CloseStatus::Keep};
320 };
321
322 class NoopCloseStatementState : public IoStatementBase {
323 public:
324 NoopCloseStatementState(const char *sourceFile, int sourceLine)
325 : IoStatementBase{sourceFile, sourceLine}, ioStatementState_{*this} {}
326 IoStatementState &ioStatementState() { return ioStatementState_; }
327 void set_status(CloseStatus) {} // discards
328 MutableModes &mutableModes() { return connection_.modes; }
329 ConnectionState &GetConnectionState() { return connection_; }
330 int EndIoStatement();
331
332 private:
333 IoStatementState ioStatementState_; // points to *this
334 ConnectionState connection_;
335 };
336
337 extern template class InternalIoStatementState<Direction::Output>;
338 extern template class InternalIoStatementState<Direction::Input>;
339 extern template class InternalFormattedIoStatementState<Direction::Output>;
340 extern template class InternalFormattedIoStatementState<Direction::Input>;
341 extern template class InternalListIoStatementState<Direction::Output>;
342 extern template class InternalListIoStatementState<Direction::Input>;
343 extern template class ExternalIoStatementState<Direction::Output>;
344 extern template class ExternalIoStatementState<Direction::Input>;
345 extern template class ExternalFormattedIoStatementState<Direction::Output>;
346 extern template class ExternalFormattedIoStatementState<Direction::Input>;
347 extern template class ExternalListIoStatementState<Direction::Output>;
348 extern template class ExternalListIoStatementState<Direction::Input>;
349 extern template class UnformattedIoStatementState<Direction::Output>;
350 extern template class UnformattedIoStatementState<Direction::Input>;
351 extern template class FormatControl<
352 InternalFormattedIoStatementState<Direction::Output>>;
353 extern template class FormatControl<
354 InternalFormattedIoStatementState<Direction::Input>>;
355 extern template class FormatControl<
356 ExternalFormattedIoStatementState<Direction::Output>>;
357 extern template class FormatControl<
358 ExternalFormattedIoStatementState<Direction::Input>>;
359
360 class ExternalMiscIoStatementState : public ExternalIoStatementBase {
361 public:
362 enum Which { Flush, Backspace, Endfile, Rewind };
363 ExternalMiscIoStatementState(ExternalFileUnit &unit, Which which,
364 const char *sourceFile = nullptr, int sourceLine = 0)
365 : ExternalIoStatementBase{unit, sourceFile, sourceLine}, which_{which} {}
366 int EndIoStatement();
367
368 private:
369 Which which_;
370 };
371
372 } // namespace Fortran::runtime::io
373 #endif // FORTRAN_RUNTIME_IO_STMT_H_
Fortran::runtime::io::NoopCloseStatementState
Definition: io-stmt.h:322
Fortran::runtime::io::ExternalFormattedIoStatementState
Definition: io-stmt.h:36
Fortran::runtime::io::ExternalIoStatementBase
Definition: io-stmt.h:221
Fortran::runtime::io::ListDirectedStatementState
Definition: io-stmt.h:122
Fortran::runtime::io::UnformattedIoStatementState
Definition: io-stmt.h:38
Fortran::runtime::io::CloseStatementState
Definition: io-stmt.h:310
Fortran::runtime::io::FormattedStatementState
Definition: io-stmt.h:119
Fortran::runtime::io::IoStatementState
Definition: io-stmt.h:42
Fortran::runtime::io::InternalIoStatementState
Definition: io-stmt.h:151
Fortran::runtime::io::InputStatementState
Definition: io-stmt.h:113
Fortran::runtime::io::InternalFormattedIoStatementState
Definition: io-stmt.h:33
Fortran::runtime::io::IoErrorHandler
Definition: io-error.h:26
Fortran::runtime::io::ExternalMiscIoStatementState
Definition: io-stmt.h:360
Fortran::runtime::io::ExternalFileUnit
Definition: unit.h:32
Fortran::runtime::Descriptor
Definition: descriptor.h:109
Fortran::runtime::io::ExternalListIoStatementState
Definition: io-stmt.h:37
Fortran::runtime::io::InternalListIoStatementState
Definition: io-stmt.h:34
Fortran::runtime::io::MutableModes
Definition: format.h:29
Fortran::runtime::io::ExternalIoStatementState
Definition: io-stmt.h:236
Fortran::runtime::io::InternalDescriptorUnit
Definition: internal-unit.h:25
Fortran::runtime::io::IoStatementBase
Definition: io-stmt.h:106
Fortran::runtime::io::ConnectionState
Definition: connection.h:35
Fortran::runtime::io::OpenStatementState
Definition: io-stmt.h:290
Fortran::runtime::io::OutputStatementState
Definition: io-stmt.h:114
Fortran::runtime::io::DefaultFormatControlCallbacks
Definition: format.h:63
Fortran::runtime::io::FormatControl
Definition: format.h:79