1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
//===-- runtime/internal-unit.cpp -------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "internal-unit.h"
#include "descriptor.h"
#include "io-error.h"
#include <algorithm>
#include <type_traits>
namespace Fortran::runtime::io {
template<bool isInput>
InternalDescriptorUnit<isInput>::InternalDescriptorUnit(
Scalar scalar, std::size_t length) {
recordLength = length;
endfileRecordNumber = 2;
void *pointer{reinterpret_cast<void *>(const_cast<char *>(scalar))};
descriptor().Establish(TypeCode{CFI_type_char}, length, pointer, 0, nullptr,
CFI_attribute_pointer);
}
template<bool isInput>
InternalDescriptorUnit<isInput>::InternalDescriptorUnit(
const Descriptor &that, const Terminator &terminator) {
RUNTIME_CHECK(terminator, that.type().IsCharacter());
Descriptor &d{descriptor()};
RUNTIME_CHECK(
terminator, that.SizeInBytes() <= d.SizeInBytes(maxRank, true, 0));
new (&d) Descriptor{that};
d.Check();
recordLength = d.ElementBytes();
endfileRecordNumber = d.Elements() + 1;
d.GetLowerBounds(at_);
}
template<bool isInput> void InternalDescriptorUnit<isInput>::EndIoStatement() {
if constexpr (!isInput) {
// blank fill
while (currentRecordNumber < endfileRecordNumber.value_or(0)) {
char *record{descriptor().template Element<char>(at_)};
std::fill_n(record + furthestPositionInRecord,
recordLength.value_or(0) - furthestPositionInRecord, ' ');
furthestPositionInRecord = 0;
++currentRecordNumber;
descriptor().IncrementSubscripts(at_);
}
}
}
template<bool isInput>
bool InternalDescriptorUnit<isInput>::Emit(
const char *data, std::size_t bytes, IoErrorHandler &handler) {
if constexpr (isInput) {
handler.Crash(
"InternalDescriptorUnit<true>::Emit() called for an input statement");
return false;
}
if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
handler.SignalEnd();
return false;
}
char *record{descriptor().template Element<char>(at_)};
auto furthestAfter{std::max(furthestPositionInRecord,
positionInRecord + static_cast<std::int64_t>(bytes))};
bool ok{true};
if (furthestAfter > static_cast<std::int64_t>(recordLength.value_or(0))) {
handler.SignalEor();
furthestAfter = recordLength.value_or(0);
bytes = std::max(std::int64_t{0}, furthestAfter - positionInRecord);
ok = false;
}
std::memcpy(record + positionInRecord, data, bytes);
positionInRecord += bytes;
furthestPositionInRecord = furthestAfter;
return ok;
}
template<bool isInput>
bool InternalDescriptorUnit<isInput>::AdvanceRecord(IoErrorHandler &handler) {
if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
handler.SignalEnd();
return false;
}
if (!HandleAbsolutePosition(recordLength.value_or(0), handler)) {
return false;
}
++currentRecordNumber;
descriptor().IncrementSubscripts(at_);
positionInRecord = 0;
furthestPositionInRecord = 0;
return true;
}
template<bool isInput>
bool InternalDescriptorUnit<isInput>::HandleAbsolutePosition(
std::int64_t n, IoErrorHandler &handler) {
n = std::max<std::int64_t>(0, n);
bool ok{true};
if (n > static_cast<std::int64_t>(recordLength.value_or(n))) {
handler.SignalEor();
n = *recordLength;
ok = false;
}
if (n > furthestPositionInRecord && ok) {
if constexpr (!isInput) {
char *record{descriptor().template Element<char>(at_)};
std::fill_n(
record + furthestPositionInRecord, n - furthestPositionInRecord, ' ');
}
furthestPositionInRecord = n;
}
positionInRecord = n;
return ok;
}
template<bool isInput>
bool InternalDescriptorUnit<isInput>::HandleRelativePosition(
std::int64_t n, IoErrorHandler &handler) {
return HandleAbsolutePosition(positionInRecord + n, handler);
}
template class InternalDescriptorUnit<false>;
template class InternalDescriptorUnit<true>;
}
|