1 //===-- runtime/edit-output.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 #ifndef FORTRAN_RUNTIME_EDIT_OUTPUT_H_
10 #define FORTRAN_RUNTIME_EDIT_OUTPUT_H_
11 
12 // Output data editing templates implementing the FORMAT data editing
13 // descriptors E, EN, ES, EX, D, F, and G for REAL data (and COMPLEX
14 // components, I and G for INTEGER, and B/O/Z for both.
15 // See subclauses in 13.7.2.3 of Fortran 2018 for the
16 // detailed specifications of these descriptors.
17 // List-directed output (13.10.4) for numeric types is also done here.
18 // Drives the same fast binary-to-decimal formatting templates used
19 // in the f18 front-end.
20 
21 #include "format.h"
22 #include "io-stmt.h"
23 #include "flang/Common/uint128.h"
24 #include "flang/Decimal/decimal.h"
25 
26 namespace Fortran::runtime::io {
27 
28 // I, B, O, Z, and G output editing for INTEGER.
29 // The DataEdit reference is const here (and elsewhere in this header) so that
30 // one edit descriptor with a repeat factor may safely serve to edit
31 // multiple elements of an array.
32 template <int KIND>
33 bool EditIntegerOutput(
34     IoStatementState &, const DataEdit &, common::HostSignedIntType<8 * KIND>);
35 
36 // Encapsulates the state of a REAL output conversion.
37 class RealOutputEditingBase {
38 protected:
RealOutputEditingBase(IoStatementState & io)39   explicit RealOutputEditingBase(IoStatementState &io) : io_{io} {}
40 
IsInfOrNaN(const decimal::ConversionToDecimalResult & res)41   static bool IsInfOrNaN(const decimal::ConversionToDecimalResult &res) {
42     const char *p{res.str};
43     if (!p || res.length < 1) {
44       return false;
45     }
46     if (*p == '-' || *p == '+') {
47       if (res.length == 1) {
48         return false;
49       }
50       ++p;
51     }
52     return *p < '0' || *p > '9';
53   }
54 
55   // Returns null when the exponent overflows a fixed-size output field.
56   const char *FormatExponent(int, const DataEdit &edit, int &length);
57   bool EmitPrefix(const DataEdit &, std::size_t length, std::size_t width);
58   bool EmitSuffix(const DataEdit &);
59 
60   IoStatementState &io_;
61   int trailingBlanks_{0}; // created when Gw editing maps to Fw
62   char exponent_[16];
63 };
64 
65 template <int KIND> class RealOutputEditing : public RealOutputEditingBase {
66 public:
67   static constexpr int binaryPrecision{common::PrecisionOfRealKind(KIND)};
68   using BinaryFloatingPoint =
69       decimal::BinaryFloatingPointNumber<binaryPrecision>;
70   template <typename A>
RealOutputEditing(IoStatementState & io,A x)71   RealOutputEditing(IoStatementState &io, A x)
72       : RealOutputEditingBase{io}, x_{x} {}
73   bool Edit(const DataEdit &);
74 
75 private:
76   // The DataEdit arguments here are const references or copies so that
77   // the original DataEdit can safely serve multiple array elements when
78   // it has a repeat count.
79   bool EditEorDOutput(const DataEdit &);
80   bool EditFOutput(const DataEdit &);
81   DataEdit EditForGOutput(DataEdit); // returns an E or F edit
82   bool EditEXOutput(const DataEdit &);
83   bool EditListDirectedOutput(const DataEdit &);
84 
IsZero()85   bool IsZero() const { return x_.IsZero(); }
86 
87   decimal::ConversionToDecimalResult Convert(
88       int significantDigits, enum decimal::FortranRounding, int flags = 0);
89 
90   BinaryFloatingPoint x_;
91   char buffer_[BinaryFloatingPoint::maxDecimalConversionDigits +
92       EXTRA_DECIMAL_CONVERSION_SPACE];
93 };
94 
95 bool ListDirectedLogicalOutput(
96     IoStatementState &, ListDirectedStatementState<Direction::Output> &, bool);
97 bool EditLogicalOutput(IoStatementState &, const DataEdit &, bool);
98 
99 template <typename CHAR>
100 bool ListDirectedCharacterOutput(IoStatementState &,
101     ListDirectedStatementState<Direction::Output> &, const CHAR *,
102     std::size_t chars);
103 extern template bool ListDirectedCharacterOutput(IoStatementState &,
104     ListDirectedStatementState<Direction::Output> &, const char *,
105     std::size_t chars);
106 extern template bool ListDirectedCharacterOutput(IoStatementState &,
107     ListDirectedStatementState<Direction::Output> &, const char16_t *,
108     std::size_t chars);
109 extern template bool ListDirectedCharacterOutput(IoStatementState &,
110     ListDirectedStatementState<Direction::Output> &, const char32_t *,
111     std::size_t chars);
112 
113 template <typename CHAR>
114 bool EditCharacterOutput(
115     IoStatementState &, const DataEdit &, const CHAR *, std::size_t chars);
116 extern template bool EditCharacterOutput(
117     IoStatementState &, const DataEdit &, const char *, std::size_t chars);
118 extern template bool EditCharacterOutput(
119     IoStatementState &, const DataEdit &, const char16_t *, std::size_t chars);
120 extern template bool EditCharacterOutput(
121     IoStatementState &, const DataEdit &, const char32_t *, std::size_t chars);
122 
123 extern template bool EditIntegerOutput<1>(
124     IoStatementState &, const DataEdit &, std::int8_t);
125 extern template bool EditIntegerOutput<2>(
126     IoStatementState &, const DataEdit &, std::int16_t);
127 extern template bool EditIntegerOutput<4>(
128     IoStatementState &, const DataEdit &, std::int32_t);
129 extern template bool EditIntegerOutput<8>(
130     IoStatementState &, const DataEdit &, std::int64_t);
131 extern template bool EditIntegerOutput<16>(
132     IoStatementState &, const DataEdit &, common::int128_t);
133 
134 extern template class RealOutputEditing<2>;
135 extern template class RealOutputEditing<3>;
136 extern template class RealOutputEditing<4>;
137 extern template class RealOutputEditing<8>;
138 extern template class RealOutputEditing<10>;
139 // TODO: double/double
140 extern template class RealOutputEditing<16>;
141 
142 } // namespace Fortran::runtime::io
143 #endif // FORTRAN_RUNTIME_EDIT_OUTPUT_H_
144