1 // Copyright (c) 2018-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_PARSER_CHAR_BLOCK_H_ 16 #define FORTRAN_PARSER_CHAR_BLOCK_H_ 17 18 // Describes a contiguous block of characters; does not own their storage. 19 20 #include "../common/interval.h" 21 #include <algorithm> 22 #include <cstddef> 23 #include <cstring> 24 #include <iosfwd> 25 #include <string> 26 #include <utility> 27 28 namespace Fortran::parser { 29 30 class CharBlock { 31 public: CharBlock()32 constexpr CharBlock() {} 33 constexpr CharBlock(const char *x, std::size_t n = 1) : interval_{x, n} {} CharBlock(const char * b,const char * ep1)34 constexpr CharBlock(const char *b, const char *ep1) 35 : interval_{b, static_cast<std::size_t>(ep1 - b)} {} CharBlock(const std::string & s)36 CharBlock(const std::string &s) : interval_{s.data(), s.size()} {} 37 constexpr CharBlock(const CharBlock &) = default; 38 constexpr CharBlock(CharBlock &&) = default; 39 constexpr CharBlock &operator=(const CharBlock &) = default; 40 constexpr CharBlock &operator=(CharBlock &&) = default; 41 empty()42 constexpr bool empty() const { return interval_.empty(); } size()43 constexpr std::size_t size() const { return interval_.size(); } begin()44 constexpr const char *begin() const { return interval_.start(); } end()45 constexpr const char *end() const { 46 return interval_.start() + interval_.size(); 47 } 48 constexpr const char &operator[](std::size_t j) const { 49 return interval_.start()[j]; 50 } 51 Contains(const CharBlock & that)52 bool Contains(const CharBlock &that) const { 53 return interval_.Contains(that.interval_); 54 } 55 ExtendToCover(const CharBlock & that)56 void ExtendToCover(const CharBlock &that) { 57 interval_.ExtendToCover(that.interval_); 58 } 59 FirstNonBlank()60 char FirstNonBlank() const { 61 for (char ch : *this) { 62 if (ch != ' ' && ch != '\t') { 63 return ch; 64 } 65 } 66 return ' '; // non no-blank character 67 } 68 IsBlank()69 bool IsBlank() const { return FirstNonBlank() == ' '; } 70 ToString()71 std::string ToString() const { 72 return std::string{interval_.start(), interval_.size()}; 73 } 74 75 // Convert to string, stopping early at any embedded '\0'. NULTerminatedToString()76 std::string NULTerminatedToString() const { 77 return std::string{interval_.start(), 78 /*not in std::*/ strnlen(interval_.start(), interval_.size())}; 79 } 80 81 bool operator<(const CharBlock &that) const { return Compare(that) < 0; } 82 bool operator<=(const CharBlock &that) const { return Compare(that) <= 0; } 83 bool operator==(const CharBlock &that) const { return Compare(that) == 0; } 84 bool operator!=(const CharBlock &that) const { return Compare(that) != 0; } 85 bool operator>=(const CharBlock &that) const { return Compare(that) >= 0; } 86 bool operator>(const CharBlock &that) const { return Compare(that) > 0; } 87 88 bool operator<(const char *that) const { return Compare(that) < 0; } 89 bool operator<=(const char *that) const { return Compare(that) <= 0; } 90 bool operator==(const char *that) const { return Compare(that) == 0; } 91 bool operator!=(const char *that) const { return Compare(that) != 0; } 92 bool operator>=(const char *that) const { return Compare(that) >= 0; } 93 bool operator>(const char *that) const { return Compare(that) > 0; } 94 95 friend bool operator<(const char *, const CharBlock &); 96 friend bool operator<=(const char *, const CharBlock &); 97 friend bool operator==(const char *, const CharBlock &); 98 friend bool operator!=(const char *, const CharBlock &); 99 friend bool operator>=(const char *, const CharBlock &); 100 friend bool operator>(const char *, const CharBlock &); 101 102 private: Compare(const CharBlock & that)103 int Compare(const CharBlock &that) const { 104 std::size_t bytes{std::min(size(), that.size())}; 105 int cmp{std::memcmp(static_cast<const void *>(begin()), 106 static_cast<const void *>(that.begin()), bytes)}; 107 if (cmp != 0) { 108 return cmp; 109 } 110 return size() < that.size() ? -1 : size() > that.size(); 111 } 112 Compare(const char * that)113 int Compare(const char *that) const { 114 std::size_t bytes{size()}; 115 if (int cmp{std::strncmp(begin(), that, bytes)}) { 116 return cmp; 117 } 118 return that[bytes] == '\0' ? 0 : -1; 119 } 120 121 common::Interval<const char *> interval_{nullptr, 0}; 122 }; 123 124 inline bool operator<(const char *left, const CharBlock &right) { 125 return right > left; 126 } 127 inline bool operator<=(const char *left, const CharBlock &right) { 128 return right >= left; 129 } 130 inline bool operator==(const char *left, const CharBlock &right) { 131 return right == left; 132 } 133 inline bool operator!=(const char *left, const CharBlock &right) { 134 return right != left; 135 } 136 inline bool operator>=(const char *left, const CharBlock &right) { 137 return right <= left; 138 } 139 inline bool operator>(const char *left, const CharBlock &right) { 140 return right < left; 141 } 142 143 inline std::ostream &operator<<(std::ostream &os, const CharBlock &x) { 144 return os << x.ToString(); 145 } 146 147 } 148 149 // Specializations to enable std::unordered_map<CharBlock, ...> &c. 150 template<> struct std::hash<Fortran::parser::CharBlock> { 151 std::size_t operator()(const Fortran::parser::CharBlock &x) const { 152 std::size_t hash{0}, bytes{x.size()}; 153 for (std::size_t j{0}; j < bytes; ++j) { 154 hash = (hash * 31) ^ x[j]; 155 } 156 return hash; 157 } 158 }; 159 #endif // FORTRAN_PARSER_CHAR_BLOCK_H_ 160