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