[libc++][Android] Allow testing libc++ with clang-r536225 (#116149)
[llvm-project.git] / flang / runtime / internal-unit.cpp
blobf28700ee015815db1f88b3dbff5971607c50349c
1 //===-- runtime/internal-unit.cpp -----------------------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "internal-unit.h"
10 #include "io-error.h"
11 #include "flang/Runtime/descriptor.h"
12 #include "flang/Runtime/freestanding-tools.h"
13 #include <algorithm>
14 #include <type_traits>
16 namespace Fortran::runtime::io {
17 RT_OFFLOAD_API_GROUP_BEGIN
19 template <Direction DIR>
20 RT_API_ATTRS InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
21 Scalar scalar, std::size_t length, int kind) {
22 internalIoCharKind = kind;
23 recordLength = length;
24 endfileRecordNumber = 2;
25 void *pointer{reinterpret_cast<void *>(const_cast<char *>(scalar))};
26 descriptor().Establish(TypeCode{TypeCategory::Character, kind}, length * kind,
27 pointer, 0, nullptr, CFI_attribute_pointer);
30 template <Direction DIR>
31 RT_API_ATTRS InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
32 const Descriptor &that, const Terminator &terminator) {
33 auto thatType{that.type().GetCategoryAndKind()};
34 RUNTIME_CHECK(terminator, thatType.has_value());
35 RUNTIME_CHECK(terminator, thatType->first == TypeCategory::Character);
36 Descriptor &d{descriptor()};
37 RUNTIME_CHECK(
38 terminator, that.SizeInBytes() <= d.SizeInBytes(maxRank, true, 0));
39 new (&d) Descriptor{that};
40 d.Check();
41 internalIoCharKind = thatType->second;
42 recordLength = d.ElementBytes();
43 endfileRecordNumber = d.Elements() + 1;
46 template <Direction DIR>
47 RT_API_ATTRS bool InternalDescriptorUnit<DIR>::Emit(
48 const char *data, std::size_t bytes, IoErrorHandler &handler) {
49 if constexpr (DIR == Direction::Input) {
50 handler.Crash("InternalDescriptorUnit<Direction::Input>::Emit() called");
51 return false && data[bytes] != 0; // bogus compare silences GCC warning
52 } else {
53 if (bytes <= 0) {
54 return true;
56 char *record{CurrentRecord()};
57 if (!record) {
58 handler.SignalError(IostatInternalWriteOverrun);
59 return false;
61 auto furthestAfter{std::max(furthestPositionInRecord,
62 positionInRecord + static_cast<std::int64_t>(bytes))};
63 bool ok{true};
64 if (furthestAfter > static_cast<std::int64_t>(recordLength.value_or(0))) {
65 handler.SignalError(IostatRecordWriteOverrun);
66 furthestAfter = recordLength.value_or(0);
67 bytes = std::max(std::int64_t{0}, furthestAfter - positionInRecord);
68 ok = false;
69 } else if (positionInRecord > furthestPositionInRecord) {
70 BlankFill(record + furthestPositionInRecord,
71 positionInRecord - furthestPositionInRecord);
73 std::memcpy(record + positionInRecord, data, bytes);
74 positionInRecord += bytes;
75 furthestPositionInRecord = furthestAfter;
76 return ok;
80 template <Direction DIR>
81 RT_API_ATTRS std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes(
82 const char *&p, IoErrorHandler &handler) {
83 p = nullptr;
84 if constexpr (DIR == Direction::Output) {
85 handler.Crash("InternalDescriptorUnit<Direction::Output>::"
86 "GetNextInputBytes() called");
87 return 0;
88 } else {
89 const char *record{CurrentRecord()};
90 if (!record) {
91 handler.SignalEnd();
92 return 0;
93 } else if (positionInRecord >= recordLength.value_or(positionInRecord)) {
94 return 0;
95 } else {
96 p = &record[positionInRecord];
97 return *recordLength - positionInRecord;
102 template <Direction DIR>
103 RT_API_ATTRS std::size_t InternalDescriptorUnit<DIR>::ViewBytesInRecord(
104 const char *&p, bool forward) const {
105 p = nullptr;
106 auto recl{recordLength.value_or(positionInRecord)};
107 const char *record{CurrentRecord()};
108 if (forward) {
109 if (positionInRecord < recl) {
110 if (record) {
111 p = &record[positionInRecord];
113 return recl - positionInRecord;
115 } else {
116 if (record && positionInRecord <= recl) {
117 p = &record[positionInRecord];
119 return positionInRecord - leftTabLimit.value_or(0);
121 return 0;
124 template <Direction DIR>
125 RT_API_ATTRS bool InternalDescriptorUnit<DIR>::AdvanceRecord(
126 IoErrorHandler &handler) {
127 if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
128 if constexpr (DIR == Direction::Input) {
129 handler.SignalEnd();
130 } else {
131 handler.SignalError(IostatInternalWriteOverrun);
133 return false;
135 if constexpr (DIR == Direction::Output) {
136 BlankFillOutputRecord();
138 ++currentRecordNumber;
139 BeginRecord();
140 return true;
143 template <Direction DIR>
144 RT_API_ATTRS void InternalDescriptorUnit<DIR>::BlankFill(
145 char *at, std::size_t bytes) {
146 switch (internalIoCharKind) {
147 case 2:
148 Fortran::runtime::fill_n(reinterpret_cast<char16_t *>(at), bytes / 2,
149 static_cast<char16_t>(' '));
150 break;
151 case 4:
152 Fortran::runtime::fill_n(reinterpret_cast<char32_t *>(at), bytes / 4,
153 static_cast<char32_t>(' '));
154 break;
155 default:
156 Fortran::runtime::fill_n(at, bytes, ' ');
157 break;
161 template <Direction DIR>
162 RT_API_ATTRS void InternalDescriptorUnit<DIR>::BlankFillOutputRecord() {
163 if constexpr (DIR == Direction::Output) {
164 if (furthestPositionInRecord <
165 recordLength.value_or(furthestPositionInRecord)) {
166 BlankFill(CurrentRecord() + furthestPositionInRecord,
167 *recordLength - furthestPositionInRecord);
172 template <Direction DIR>
173 RT_API_ATTRS void InternalDescriptorUnit<DIR>::BackspaceRecord(
174 IoErrorHandler &handler) {
175 RUNTIME_CHECK(handler, currentRecordNumber > 1);
176 --currentRecordNumber;
177 BeginRecord();
180 template <Direction DIR>
181 RT_API_ATTRS std::int64_t InternalDescriptorUnit<DIR>::InquirePos() {
182 return (currentRecordNumber - 1) * recordLength.value_or(0) +
183 positionInRecord + 1;
186 template class InternalDescriptorUnit<Direction::Output>;
187 template class InternalDescriptorUnit<Direction::Input>;
189 RT_OFFLOAD_API_GROUP_END
190 } // namespace Fortran::runtime::io