[SelectOpt] Support ADD and SUB with zext operands. (#115489)
[llvm-project.git] / flang / runtime / emit-encoded.h
blob4b5e39007883575191a04d06577a8f7b60d52e17
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 //===----------------------------------------------------------------------===//
9 // Templates for emitting CHARACTER values with conversion
11 #ifndef FORTRAN_RUNTIME_EMIT_ENCODED_H_
12 #define FORTRAN_RUNTIME_EMIT_ENCODED_H_
14 #include "connection.h"
15 #include "environment.h"
16 #include "tools.h"
17 #include "utf.h"
19 namespace Fortran::runtime::io {
21 template <typename CONTEXT, typename CHAR, bool NL_ADVANCES_RECORD = true>
22 RT_API_ATTRS bool EmitEncoded(
23 CONTEXT &to, const CHAR *data, std::size_t chars) {
24 ConnectionState &connection{to.GetConnectionState()};
25 if constexpr (NL_ADVANCES_RECORD) {
26 if (connection.access == Access::Stream &&
27 connection.internalIoCharKind == 0) {
28 // Stream output: treat newlines as record advancements so that the left
29 // tab limit is correctly managed
30 while (const CHAR * nl{FindCharacter(data, CHAR{'\n'}, chars)}) {
31 auto pos{static_cast<std::size_t>(nl - data)};
32 // The [data, data + pos) does not contain the newline,
33 // so we can avoid the recursion by calling proper specialization.
34 if (!EmitEncoded<CONTEXT, CHAR, false>(to, data, pos)) {
35 return false;
37 data += pos + 1;
38 chars -= pos + 1;
39 to.AdvanceRecord();
43 if (connection.useUTF8<CHAR>()) {
44 using UnsignedChar = std::make_unsigned_t<CHAR>;
45 const UnsignedChar *uData{reinterpret_cast<const UnsignedChar *>(data)};
46 char buffer[256];
47 std::size_t at{0};
48 while (chars-- > 0) {
49 auto len{EncodeUTF8(buffer + at, *uData++)};
50 at += len;
51 if (at + maxUTF8Bytes > sizeof buffer) {
52 if (!to.Emit(buffer, at)) {
53 return false;
55 at = 0;
58 return at == 0 || to.Emit(buffer, at);
59 } else {
60 std::size_t internalKind = connection.internalIoCharKind;
61 if (internalKind == 0 || internalKind == sizeof(CHAR)) {
62 const char *rawData{reinterpret_cast<const char *>(data)};
63 return to.Emit(rawData, chars * sizeof(CHAR), sizeof(CHAR));
64 } else {
65 // CHARACTER kind conversion for internal output
66 while (chars-- > 0) {
67 char32_t buffer = *data++;
68 char *p{reinterpret_cast<char *>(&buffer)};
69 if constexpr (!isHostLittleEndian) {
70 p += sizeof(buffer) - internalKind;
72 if (!to.Emit(p, internalKind)) {
73 return false;
76 return true;
81 template <typename CONTEXT>
82 RT_API_ATTRS bool EmitAscii(CONTEXT &to, const char *data, std::size_t chars) {
83 ConnectionState &connection{to.GetConnectionState()};
84 if (connection.internalIoCharKind <= 1 &&
85 connection.access != Access::Stream) {
86 return to.Emit(data, chars);
87 } else {
88 return EmitEncoded(to, data, chars);
92 template <typename CONTEXT>
93 RT_API_ATTRS bool EmitRepeated(CONTEXT &to, char ch, std::size_t n) {
94 if (n <= 0) {
95 return true;
97 ConnectionState &connection{to.GetConnectionState()};
98 if (connection.internalIoCharKind <= 1 &&
99 connection.access != Access::Stream) {
100 // faster path, no encoding needed
101 while (n-- > 0) {
102 if (!to.Emit(&ch, 1)) {
103 return false;
106 } else {
107 while (n-- > 0) {
108 if (!EmitEncoded(to, &ch, 1)) {
109 return false;
113 return true;
116 } // namespace Fortran::runtime::io
117 #endif // FORTRAN_RUNTIME_EMIT_ENCODED_H_