1 //===-- runtime/emit-encoded.h ----------------------------------*- C++ -*-===//
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
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"
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
)) {
43 if (connection
.useUTF8
<CHAR
>()) {
44 using UnsignedChar
= std::make_unsigned_t
<CHAR
>;
45 const UnsignedChar
*uData
{reinterpret_cast<const UnsignedChar
*>(data
)};
49 auto len
{EncodeUTF8(buffer
+ at
, *uData
++)};
51 if (at
+ maxUTF8Bytes
> sizeof buffer
) {
52 if (!to
.Emit(buffer
, at
)) {
58 return at
== 0 || to
.Emit(buffer
, at
);
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
));
65 // CHARACTER kind conversion for internal output
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
)) {
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
);
88 return EmitEncoded(to
, data
, chars
);
92 template <typename CONTEXT
>
93 RT_API_ATTRS
bool EmitRepeated(CONTEXT
&to
, char ch
, std::size_t n
) {
97 ConnectionState
&connection
{to
.GetConnectionState()};
98 if (connection
.internalIoCharKind
<= 1 &&
99 connection
.access
!= Access::Stream
) {
100 // faster path, no encoding needed
102 if (!to
.Emit(&ch
, 1)) {
108 if (!EmitEncoded(to
, &ch
, 1)) {
116 } // namespace Fortran::runtime::io
117 #endif // FORTRAN_RUNTIME_EMIT_ENCODED_H_