xref: /llvm-project/flang/runtime/internal-unit.cpp (revision c91ba04328e1ded6f284469a7828d181324d4e30)
1651f58bfSDiana Picus //===-- runtime/internal-unit.cpp -----------------------------------------===//
295696d56Speter klausler //
395696d56Speter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
495696d56Speter klausler // See https://llvm.org/LICENSE.txt for license information.
595696d56Speter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
695696d56Speter klausler //
795696d56Speter klausler //===----------------------------------------------------------------------===//
895696d56Speter klausler 
995696d56Speter klausler #include "internal-unit.h"
1095696d56Speter klausler #include "io-error.h"
11830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h"
123b337242SSlava Zakharin #include "flang/Runtime/freestanding-tools.h"
1395696d56Speter klausler #include <algorithm>
1495696d56Speter klausler #include <type_traits>
1595696d56Speter klausler 
1695696d56Speter klausler namespace Fortran::runtime::io {
178ebf7411SSlava Zakharin RT_OFFLOAD_API_GROUP_BEGIN
1895696d56Speter klausler 
193b635714Speter klausler template <Direction DIR>
208ebf7411SSlava Zakharin RT_API_ATTRS InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
21bad52055SPeter Klausler     Scalar scalar, std::size_t length, int kind) {
22bad52055SPeter Klausler   internalIoCharKind = kind;
2395696d56Speter klausler   recordLength = length;
2495696d56Speter klausler   endfileRecordNumber = 2;
2595696d56Speter klausler   void *pointer{reinterpret_cast<void *>(const_cast<char *>(scalar))};
26bad52055SPeter Klausler   descriptor().Establish(TypeCode{TypeCategory::Character, kind}, length * kind,
27bad52055SPeter Klausler       pointer, 0, nullptr, CFI_attribute_pointer);
2895696d56Speter klausler }
2995696d56Speter klausler 
303b635714Speter klausler template <Direction DIR>
318ebf7411SSlava Zakharin RT_API_ATTRS InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
3295696d56Speter klausler     const Descriptor &that, const Terminator &terminator) {
33bad52055SPeter Klausler   auto thatType{that.type().GetCategoryAndKind()};
34bad52055SPeter Klausler   RUNTIME_CHECK(terminator, thatType.has_value());
35bad52055SPeter Klausler   RUNTIME_CHECK(terminator, thatType->first == TypeCategory::Character);
3695696d56Speter klausler   Descriptor &d{descriptor()};
3795696d56Speter klausler   RUNTIME_CHECK(
3895696d56Speter klausler       terminator, that.SizeInBytes() <= d.SizeInBytes(maxRank, true, 0));
39*c91ba043SMichael Kruse   RUNTIME_CHECK(terminator,
40*c91ba043SMichael Kruse       that.SizeInBytes() <= MaxDescriptorSizeInBytes(maxRank, true, 0));
4195696d56Speter klausler   new (&d) Descriptor{that};
4295696d56Speter klausler   d.Check();
43bad52055SPeter Klausler   internalIoCharKind = thatType->second;
4495696d56Speter klausler   recordLength = d.ElementBytes();
4595696d56Speter klausler   endfileRecordNumber = d.Elements() + 1;
4695696d56Speter klausler }
4795696d56Speter klausler 
483b635714Speter klausler template <Direction DIR>
498ebf7411SSlava Zakharin RT_API_ATTRS bool InternalDescriptorUnit<DIR>::Emit(
5095696d56Speter klausler     const char *data, std::size_t bytes, IoErrorHandler &handler) {
513b635714Speter klausler   if constexpr (DIR == Direction::Input) {
523b635714Speter klausler     handler.Crash("InternalDescriptorUnit<Direction::Input>::Emit() called");
533b635714Speter klausler     return false && data[bytes] != 0; // bogus compare silences GCC warning
543b635714Speter klausler   } else {
553b635714Speter klausler     if (bytes <= 0) {
563b635714Speter klausler       return true;
573b635714Speter klausler     }
583b635714Speter klausler     char *record{CurrentRecord()};
593b635714Speter klausler     if (!record) {
603b635714Speter klausler       handler.SignalError(IostatInternalWriteOverrun);
6195696d56Speter klausler       return false;
6295696d56Speter klausler     }
6395696d56Speter klausler     auto furthestAfter{std::max(furthestPositionInRecord,
6495696d56Speter klausler         positionInRecord + static_cast<std::int64_t>(bytes))};
6595696d56Speter klausler     bool ok{true};
6695696d56Speter klausler     if (furthestAfter > static_cast<std::int64_t>(recordLength.value_or(0))) {
673b635714Speter klausler       handler.SignalError(IostatRecordWriteOverrun);
6895696d56Speter klausler       furthestAfter = recordLength.value_or(0);
6995696d56Speter klausler       bytes = std::max(std::int64_t{0}, furthestAfter - positionInRecord);
7095696d56Speter klausler       ok = false;
713b635714Speter klausler     } else if (positionInRecord > furthestPositionInRecord) {
72bad52055SPeter Klausler       BlankFill(record + furthestPositionInRecord,
73bad52055SPeter Klausler           positionInRecord - furthestPositionInRecord);
7495696d56Speter klausler     }
7595696d56Speter klausler     std::memcpy(record + positionInRecord, data, bytes);
7695696d56Speter klausler     positionInRecord += bytes;
7795696d56Speter klausler     furthestPositionInRecord = furthestAfter;
7895696d56Speter klausler     return ok;
7995696d56Speter klausler   }
803b635714Speter klausler }
8195696d56Speter klausler 
823b635714Speter klausler template <Direction DIR>
838ebf7411SSlava Zakharin RT_API_ATTRS std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes(
84da25f968SPeter Klausler     const char *&p, IoErrorHandler &handler) {
85c2a95ad2SPeter Klausler   p = nullptr;
863b635714Speter klausler   if constexpr (DIR == Direction::Output) {
87da25f968SPeter Klausler     handler.Crash("InternalDescriptorUnit<Direction::Output>::"
88da25f968SPeter Klausler                   "GetNextInputBytes() called");
89da25f968SPeter Klausler     return 0;
90da25f968SPeter Klausler   } else {
913b635714Speter klausler     const char *record{CurrentRecord()};
923b635714Speter klausler     if (!record) {
933b635714Speter klausler       handler.SignalEnd();
94da25f968SPeter Klausler       return 0;
95da25f968SPeter Klausler     } else if (positionInRecord >= recordLength.value_or(positionInRecord)) {
96da25f968SPeter Klausler       return 0;
97da25f968SPeter Klausler     } else {
98da25f968SPeter Klausler       p = &record[positionInRecord];
99da25f968SPeter Klausler       return *recordLength - positionInRecord;
1003b635714Speter klausler     }
1013b635714Speter klausler   }
102da25f968SPeter Klausler }
103da25f968SPeter Klausler 
104da25f968SPeter Klausler template <Direction DIR>
105c2a95ad2SPeter Klausler RT_API_ATTRS std::size_t InternalDescriptorUnit<DIR>::ViewBytesInRecord(
106c2a95ad2SPeter Klausler     const char *&p, bool forward) const {
107c2a95ad2SPeter Klausler   p = nullptr;
108c2a95ad2SPeter Klausler   auto recl{recordLength.value_or(positionInRecord)};
109c2a95ad2SPeter Klausler   const char *record{CurrentRecord()};
110c2a95ad2SPeter Klausler   if (forward) {
111c2a95ad2SPeter Klausler     if (positionInRecord < recl) {
112c2a95ad2SPeter Klausler       if (record) {
113c2a95ad2SPeter Klausler         p = &record[positionInRecord];
114c2a95ad2SPeter Klausler       }
115c2a95ad2SPeter Klausler       return recl - positionInRecord;
116c2a95ad2SPeter Klausler     }
117c2a95ad2SPeter Klausler   } else {
118c2a95ad2SPeter Klausler     if (record && positionInRecord <= recl) {
119c2a95ad2SPeter Klausler       p = &record[positionInRecord];
120c2a95ad2SPeter Klausler     }
121c2a95ad2SPeter Klausler     return positionInRecord - leftTabLimit.value_or(0);
122c2a95ad2SPeter Klausler   }
123c2a95ad2SPeter Klausler   return 0;
124c2a95ad2SPeter Klausler }
125c2a95ad2SPeter Klausler 
126c2a95ad2SPeter Klausler template <Direction DIR>
1278ebf7411SSlava Zakharin RT_API_ATTRS bool InternalDescriptorUnit<DIR>::AdvanceRecord(
1288ebf7411SSlava Zakharin     IoErrorHandler &handler) {
12995696d56Speter klausler   if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
130fc71a49eSPeter Klausler     if constexpr (DIR == Direction::Input) {
13195696d56Speter klausler       handler.SignalEnd();
132fc71a49eSPeter Klausler     } else {
133fc71a49eSPeter Klausler       handler.SignalError(IostatInternalWriteOverrun);
134fc71a49eSPeter Klausler     }
13595696d56Speter klausler     return false;
13695696d56Speter klausler   }
137b77fd01aSPeter Klausler   if constexpr (DIR == Direction::Output) {
138b77fd01aSPeter Klausler     BlankFillOutputRecord();
13995696d56Speter klausler   }
14095696d56Speter klausler   ++currentRecordNumber;
14137f98f6fSpeter klausler   BeginRecord();
14295696d56Speter klausler   return true;
14395696d56Speter klausler }
14495696d56Speter klausler 
1453b635714Speter klausler template <Direction DIR>
1468ebf7411SSlava Zakharin RT_API_ATTRS void InternalDescriptorUnit<DIR>::BlankFill(
1478ebf7411SSlava Zakharin     char *at, std::size_t bytes) {
148bad52055SPeter Klausler   switch (internalIoCharKind) {
149bad52055SPeter Klausler   case 2:
1508ebf7411SSlava Zakharin     Fortran::runtime::fill_n(reinterpret_cast<char16_t *>(at), bytes / 2,
151bad52055SPeter Klausler         static_cast<char16_t>(' '));
152bad52055SPeter Klausler     break;
153bad52055SPeter Klausler   case 4:
1548ebf7411SSlava Zakharin     Fortran::runtime::fill_n(reinterpret_cast<char32_t *>(at), bytes / 4,
155bad52055SPeter Klausler         static_cast<char32_t>(' '));
156bad52055SPeter Klausler     break;
157bad52055SPeter Klausler   default:
1588ebf7411SSlava Zakharin     Fortran::runtime::fill_n(at, bytes, ' ');
159bad52055SPeter Klausler     break;
160bad52055SPeter Klausler   }
161bad52055SPeter Klausler }
162bad52055SPeter Klausler 
163bad52055SPeter Klausler template <Direction DIR>
1648ebf7411SSlava Zakharin RT_API_ATTRS void InternalDescriptorUnit<DIR>::BlankFillOutputRecord() {
165b77fd01aSPeter Klausler   if constexpr (DIR == Direction::Output) {
166b77fd01aSPeter Klausler     if (furthestPositionInRecord <
167b77fd01aSPeter Klausler         recordLength.value_or(furthestPositionInRecord)) {
168bad52055SPeter Klausler       BlankFill(CurrentRecord() + furthestPositionInRecord,
169bad52055SPeter Klausler           *recordLength - furthestPositionInRecord);
170b77fd01aSPeter Klausler     }
171b77fd01aSPeter Klausler   }
172b77fd01aSPeter Klausler }
173b77fd01aSPeter Klausler 
174b77fd01aSPeter Klausler template <Direction DIR>
1758ebf7411SSlava Zakharin RT_API_ATTRS void InternalDescriptorUnit<DIR>::BackspaceRecord(
1768ebf7411SSlava Zakharin     IoErrorHandler &handler) {
1773b635714Speter klausler   RUNTIME_CHECK(handler, currentRecordNumber > 1);
1783b635714Speter klausler   --currentRecordNumber;
17937f98f6fSpeter klausler   BeginRecord();
18095696d56Speter klausler }
18195696d56Speter klausler 
1824180b29dSPeter Klausler template <Direction DIR>
1838ebf7411SSlava Zakharin RT_API_ATTRS std::int64_t InternalDescriptorUnit<DIR>::InquirePos() {
1844180b29dSPeter Klausler   return (currentRecordNumber - 1) * recordLength.value_or(0) +
1854180b29dSPeter Klausler       positionInRecord + 1;
1864180b29dSPeter Klausler }
1874180b29dSPeter Klausler 
1883b635714Speter klausler template class InternalDescriptorUnit<Direction::Output>;
1893b635714Speter klausler template class InternalDescriptorUnit<Direction::Input>;
1908ebf7411SSlava Zakharin 
1918ebf7411SSlava Zakharin RT_OFFLOAD_API_GROUP_END
1921f879005STim Keith } // namespace Fortran::runtime::io
193