1 // Copyright (c) 2019, NVIDIA CORPORATION.  All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef FORTRAN_EVALUATE_CHARACTER_H_
16 #define FORTRAN_EVALUATE_CHARACTER_H_
17 
18 #include "type.h"
19 #include <string>
20 
21 // Provides implementations of intrinsic functions operating on character
22 // scalars. No assumption is made regarding character encodings other than they
23 // must be compatible with ASCII (else, NEW_LINE, ACHAR and IACHAR need to be
24 // adapted).
25 
26 namespace Fortran::evaluate {
27 
28 template<int KIND> class CharacterUtils {
29   using Character = Scalar<Type<TypeCategory::Character, KIND>>;
30   using CharT = typename Character::value_type;
31 
32 public:
33   // CHAR also implements ACHAR under assumption that character encodings
34   // contain ASCII
CHAR(std::uint64_t code)35   static Character CHAR(std::uint64_t code) {
36     return Character{{static_cast<CharT>(code)}};
37   }
38 
39   // ICHAR also implements IACHAR under assumption that character encodings
40   // contain ASCII
ICHAR(const Character & c)41   static std::int64_t ICHAR(const Character &c) {
42     CHECK(c.length() == 1);
43     if constexpr (std::is_same_v<CharT, char>) {
44       // char may be signed, so cast it first to unsigned to avoid having
45       // ichar(char(128_4)) returning -128
46       return static_cast<unsigned char>(c[0]);
47     } else {
48       return c[0];
49     }
50   }
51 
NEW_LINE()52   static Character NEW_LINE() { return Character{{NewLine()}}; }
53 
ADJUSTL(const Character & str)54   static Character ADJUSTL(const Character &str) {
55     auto pos{str.find_first_not_of(Space())};
56     if (pos != Character::npos && pos != 0) {
57       return Character{str.substr(pos) + Character(pos, Space())};
58     }
59     // else empty or only spaces, or no leading spaces
60     return str;
61   }
62 
ADJUSTR(const Character & str)63   static Character ADJUSTR(const Character &str) {
64     auto pos{str.find_last_not_of(Space())};
65     if (pos != Character::npos && pos != str.length() - 1) {
66       auto delta{str.length() - 1 - pos};
67       return Character{Character(delta, Space()) + str.substr(0, pos + 1)};
68     }
69     // else empty or only spaces, or no trailing spaces
70     return str;
71   }
72 
73 private:
74   // Following helpers assume that character encodings contain ASCII
Space()75   static constexpr CharT Space() { return 0x20; }
NewLine()76   static constexpr CharT NewLine() { return 0x0a; }
77 };
78 
79 }
80 
81 #endif  // FORTRAN_EVALUATE_CHARACTER_H_
82