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