1//===-- runtime/emit-encoded.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// Templates for emitting CHARACTER values with conversion
10
11#ifndef FORTRAN_RUNTIME_EMIT_ENCODED_H_
12#define FORTRAN_RUNTIME_EMIT_ENCODED_H_
13
14#include "connection.h"
15#include "environment.h"
16#include "tools.h"
17#include "utf.h"
18
19namespace Fortran::runtime::io {
20
21template <typename CONTEXT, typename CHAR>
22bool EmitEncoded(CONTEXT &to, const CHAR *data, std::size_t chars) {
23 ConnectionState &connection{to.GetConnectionState()};
24 if (connection.access == Access::Stream &&
25 connection.internalIoCharKind == 0) {
26 // Stream output: treat newlines as record advancements so that the left tab
27 // limit is correctly managed
28 while (const CHAR * nl{FindCharacter(data, CHAR{'\n'}, chars)}) {
29 auto pos{static_cast<std::size_t>(nl - data)};
30 if (!EmitEncoded(to, data, pos)) {
31 return false;
32 }
33 data += pos + 1;
34 chars -= pos + 1;
35 to.AdvanceRecord();
36 }
37 }
38 if (connection.useUTF8<CHAR>()) {
39 using UnsignedChar = std::make_unsigned_t<CHAR>;
40 const UnsignedChar *uData{reinterpret_cast<const UnsignedChar *>(data)};
41 char buffer[256];
42 std::size_t at{0};
43 while (chars-- > 0) {
44 auto len{EncodeUTF8(buffer + at, *uData++)};
45 at += len;
46 if (at + maxUTF8Bytes > sizeof buffer) {
47 if (!to.Emit(buffer, at)) {
48 return false;
49 }
50 at = 0;
51 }
52 }
53 return at == 0 || to.Emit(buffer, at);
54 } else {
55 std::size_t internalKind = connection.internalIoCharKind;
56 if (internalKind == 0 || internalKind == sizeof(CHAR)) {
57 const char *rawData{reinterpret_cast<const char *>(data)};
58 return to.Emit(rawData, chars * sizeof(CHAR), sizeof(CHAR));
59 } else {
60 // CHARACTER kind conversion for internal output
61 while (chars-- > 0) {
62 char32_t buffer = *data++;
63 char *p{reinterpret_cast<char *>(&buffer)};
64 if constexpr (!isHostLittleEndian) {
65 p += sizeof(buffer) - internalKind;
66 }
67 if (!to.Emit(p, internalKind)) {
68 return false;
69 }
70 }
71 return true;
72 }
73 }
74}
75
76template <typename CONTEXT>
77bool EmitAscii(CONTEXT &to, const char *data, std::size_t chars) {
78 ConnectionState &connection{to.GetConnectionState()};
79 if (connection.internalIoCharKind <= 1 &&
80 connection.access != Access::Stream) {
81 return to.Emit(data, chars);
82 } else {
83 return EmitEncoded(to, data, chars);
84 }
85}
86
87template <typename CONTEXT>
88bool EmitRepeated(CONTEXT &to, char ch, std::size_t n) {
89 if (n <= 0) {
90 return true;
91 }
92 ConnectionState &connection{to.GetConnectionState()};
93 if (connection.internalIoCharKind <= 1 &&
94 connection.access != Access::Stream) {
95 // faster path, no encoding needed
96 while (n-- > 0) {
97 if (!to.Emit(&ch, 1)) {
98 return false;
99 }
100 }
101 } else {
102 while (n-- > 0) {
103 if (!EmitEncoded(to, &ch, 1)) {
104 return false;
105 }
106 }
107 }
108 return true;
109}
110
111} // namespace Fortran::runtime::io
112#endif // FORTRAN_RUNTIME_EMIT_ENCODED_H_
113

source code of flang/runtime/emit-encoded.h