[lldb] Add ability to hide the root name of a value
[llvm-project.git] / flang / runtime / internal-unit.cpp
blobaa7130f3a6a53ddccebd699c95ca368743d61349
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 <algorithm>
13 #include <type_traits>
15 namespace Fortran::runtime::io {
17 template <Direction DIR>
18 InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
19 Scalar scalar, std::size_t length, int kind) {
20 internalIoCharKind = kind;
21 recordLength = length;
22 endfileRecordNumber = 2;
23 void *pointer{reinterpret_cast<void *>(const_cast<char *>(scalar))};
24 descriptor().Establish(TypeCode{TypeCategory::Character, kind}, length * kind,
25 pointer, 0, nullptr, CFI_attribute_pointer);
28 template <Direction DIR>
29 InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
30 const Descriptor &that, const Terminator &terminator) {
31 auto thatType{that.type().GetCategoryAndKind()};
32 RUNTIME_CHECK(terminator, thatType.has_value());
33 RUNTIME_CHECK(terminator, thatType->first == TypeCategory::Character);
34 Descriptor &d{descriptor()};
35 RUNTIME_CHECK(
36 terminator, that.SizeInBytes() <= d.SizeInBytes(maxRank, true, 0));
37 new (&d) Descriptor{that};
38 d.Check();
39 internalIoCharKind = thatType->second;
40 recordLength = d.ElementBytes();
41 endfileRecordNumber = d.Elements() + 1;
44 template <Direction DIR> void InternalDescriptorUnit<DIR>::EndIoStatement() {
45 if constexpr (DIR == Direction::Output) {
46 // Clear the remainder of the current record if anything was written
47 // to it, or if it is the only record.
48 auto end{endfileRecordNumber.value_or(0)};
49 if (currentRecordNumber < end &&
50 (end == 2 || furthestPositionInRecord > 0)) {
51 BlankFillOutputRecord();
56 template <Direction DIR>
57 bool InternalDescriptorUnit<DIR>::Emit(
58 const char *data, std::size_t bytes, IoErrorHandler &handler) {
59 if constexpr (DIR == Direction::Input) {
60 handler.Crash("InternalDescriptorUnit<Direction::Input>::Emit() called");
61 return false && data[bytes] != 0; // bogus compare silences GCC warning
62 } else {
63 if (bytes <= 0) {
64 return true;
66 char *record{CurrentRecord()};
67 if (!record) {
68 handler.SignalError(IostatInternalWriteOverrun);
69 return false;
71 auto furthestAfter{std::max(furthestPositionInRecord,
72 positionInRecord + static_cast<std::int64_t>(bytes))};
73 bool ok{true};
74 if (furthestAfter > static_cast<std::int64_t>(recordLength.value_or(0))) {
75 handler.SignalError(IostatRecordWriteOverrun);
76 furthestAfter = recordLength.value_or(0);
77 bytes = std::max(std::int64_t{0}, furthestAfter - positionInRecord);
78 ok = false;
79 } else if (positionInRecord > furthestPositionInRecord) {
80 BlankFill(record + furthestPositionInRecord,
81 positionInRecord - furthestPositionInRecord);
83 std::memcpy(record + positionInRecord, data, bytes);
84 positionInRecord += bytes;
85 furthestPositionInRecord = furthestAfter;
86 return ok;
90 template <Direction DIR>
91 std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes(
92 const char *&p, IoErrorHandler &handler) {
93 if constexpr (DIR == Direction::Output) {
94 handler.Crash("InternalDescriptorUnit<Direction::Output>::"
95 "GetNextInputBytes() called");
96 return 0;
97 } else {
98 const char *record{CurrentRecord()};
99 if (!record) {
100 handler.SignalEnd();
101 return 0;
102 } else if (positionInRecord >= recordLength.value_or(positionInRecord)) {
103 return 0;
104 } else {
105 p = &record[positionInRecord];
106 return *recordLength - positionInRecord;
111 template <Direction DIR>
112 bool InternalDescriptorUnit<DIR>::AdvanceRecord(IoErrorHandler &handler) {
113 if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
114 handler.SignalEnd();
115 return false;
117 if constexpr (DIR == Direction::Output) {
118 BlankFillOutputRecord();
120 ++currentRecordNumber;
121 BeginRecord();
122 return true;
125 template <Direction DIR>
126 void InternalDescriptorUnit<DIR>::BlankFill(char *at, std::size_t bytes) {
127 switch (internalIoCharKind) {
128 case 2:
129 std::fill_n(reinterpret_cast<char16_t *>(at), bytes / 2,
130 static_cast<char16_t>(' '));
131 break;
132 case 4:
133 std::fill_n(reinterpret_cast<char32_t *>(at), bytes / 4,
134 static_cast<char32_t>(' '));
135 break;
136 default:
137 std::fill_n(at, bytes, ' ');
138 break;
142 template <Direction DIR>
143 void InternalDescriptorUnit<DIR>::BlankFillOutputRecord() {
144 if constexpr (DIR == Direction::Output) {
145 if (furthestPositionInRecord <
146 recordLength.value_or(furthestPositionInRecord)) {
147 BlankFill(CurrentRecord() + furthestPositionInRecord,
148 *recordLength - furthestPositionInRecord);
153 template <Direction DIR>
154 void InternalDescriptorUnit<DIR>::BackspaceRecord(IoErrorHandler &handler) {
155 RUNTIME_CHECK(handler, currentRecordNumber > 1);
156 --currentRecordNumber;
157 BeginRecord();
160 template <Direction DIR>
161 std::int64_t InternalDescriptorUnit<DIR>::InquirePos() {
162 return (currentRecordNumber - 1) * recordLength.value_or(0) +
163 positionInRecord + 1;
166 template class InternalDescriptorUnit<Direction::Output>;
167 template class InternalDescriptorUnit<Direction::Input>;
168 } // namespace Fortran::runtime::io