File indexing completed on 2024-04-21 05:38:46
0001 /* 0002 SPDX-FileCopyrightText: 2016 Sergio Martins <smartins@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef CLAZY_STL_H 0008 #define CLAZY_STL_H 0009 0010 #include <clang/AST/Stmt.h> 0011 0012 #include <algorithm> 0013 #include <cctype> 0014 #include <sstream> 0015 #include <string_view> 0016 0017 namespace clazy 0018 { 0019 // Don't use .begin() or cend(), clang's ranges don't have them 0020 // Don't use .size(), clang's ranges doesn't have it 0021 0022 template<typename C> 0023 bool contains(const C &container, const typename C::value_type &value) 0024 { 0025 return std::find(container.begin(), container.end(), value) != container.end(); 0026 } 0027 0028 inline bool contains(const std::string &haystack, const std::string &needle) 0029 { 0030 return haystack.find(needle) != std::string::npos; 0031 } 0032 0033 template<typename C> 0034 typename C::iterator find(C &container, const typename C::value_type &value) 0035 { 0036 return std::find(container.begin(), container.end(), value); 0037 } 0038 0039 template<typename C> 0040 typename C::const_iterator find(const C &container, const typename C::value_type &value) 0041 { 0042 return std::find(container.begin(), container.end(), value); 0043 } 0044 0045 template<typename C, typename Pred> 0046 typename C::iterator find_if(C &container, Pred pred) 0047 { 0048 return std::find_if(container.begin(), container.end(), pred); 0049 } 0050 0051 template<typename C, typename Pred> 0052 typename C::const_iterator find_if(const C &container, Pred pred) 0053 { 0054 return std::find_if(container.begin(), container.end(), pred); 0055 } 0056 0057 template<typename Range, typename Pred> 0058 bool any_of(const Range &r, Pred pred) 0059 { 0060 return std::any_of(r.begin(), r.end(), pred); 0061 } 0062 0063 template<typename Range, typename Pred> 0064 bool all_of(const Range &r, Pred pred) 0065 { 0066 return std::all_of(r.begin(), r.end(), pred); 0067 } 0068 0069 template<typename Range> 0070 size_t count(const Range &r) 0071 { 0072 return std::distance(r.begin(), r.end()); 0073 } 0074 0075 template<typename SrcContainer, typename DstContainer> 0076 void append(const SrcContainer &src, DstContainer &dst) 0077 { 0078 dst.reserve(clazy::count(dst) + clazy::count(src)); 0079 std::copy(src.begin(), src.end(), std::back_inserter(dst)); 0080 } 0081 0082 template<typename SrcContainer, typename DstContainer, typename Pred> 0083 void append_if(const SrcContainer &src, DstContainer &dst, Pred pred) 0084 { 0085 dst.reserve(clazy::count(dst) + clazy::count(src)); 0086 std::copy_if(src.begin(), src.end(), std::back_inserter(dst), pred); 0087 } 0088 0089 template<typename Range> 0090 bool isEmpty(const Range &r) 0091 { 0092 return r.begin() == r.end(); 0093 } 0094 0095 inline bool hasChildren(clang::Stmt *s) 0096 { 0097 return s && !clazy::isEmpty(s->children()); 0098 } 0099 0100 inline clang::Stmt *childAt(clang::Stmt *s, int index) 0101 { 0102 int count = s ? std::distance(s->child_begin(), s->child_end()) : 0; 0103 if (count > index) { 0104 auto it = s->child_begin(); 0105 while (index > 0) { 0106 ++it; 0107 --index; 0108 } 0109 return *it; 0110 } 0111 0112 return nullptr; 0113 } 0114 0115 /** 0116 * Returns true if the string target starts with maybeBeginning 0117 */ 0118 inline bool startsWith(std::string_view target, std::string_view maybeBeginning) 0119 { 0120 return target.compare(0, maybeBeginning.length(), maybeBeginning) == 0; 0121 } 0122 0123 /** 0124 * Returns true if the string target starts with any of the strings in beginningCandidates 0125 */ 0126 inline bool startsWithAny(std::string_view target, const std::vector<std::string> &beginningCandidates) 0127 { 0128 return clazy::any_of(beginningCandidates, [target](const std::string &maybeBeginning) { 0129 return clazy::startsWith(target, maybeBeginning); 0130 }); 0131 } 0132 0133 /** 0134 * Returns true if the target equals any of the candidate strings 0135 */ 0136 inline bool equalsAny(const std::string &target, const std::vector<std::string> &candidates) 0137 { 0138 return clazy::any_of(candidates, [target](const std::string &candidate) { 0139 return candidate == target; 0140 }); 0141 } 0142 0143 /** 0144 * Returns true if the string target ends with maybeEnding 0145 */ 0146 inline bool endsWith(std::string_view target, std::string_view maybeEnding) 0147 { 0148 return target.size() >= maybeEnding.size() && target.compare(target.size() - maybeEnding.size(), maybeEnding.size(), maybeEnding) == 0; 0149 } 0150 0151 /** 0152 * Returns true if the string target ends with any of the strings in endingCandidates 0153 */ 0154 inline bool endsWithAny(const std::string &target, const std::vector<std::string> &endingCandidates) 0155 { 0156 return clazy::any_of(endingCandidates, [target](const std::string &maybeEnding) { 0157 return clazy::endsWith(target, maybeEnding); 0158 }); 0159 } 0160 0161 inline std::string toLower(const std::string &s) 0162 { 0163 std::string result(s.size(), 0); 0164 std::transform(s.begin(), s.end(), result.begin(), ::tolower); 0165 return result; 0166 } 0167 0168 inline void rtrim(std::string &s) 0169 { 0170 while (!s.empty() && std::isspace(s.back())) { 0171 s.pop_back(); 0172 } 0173 } 0174 0175 inline std::vector<std::string_view> splitStringBySpaces(std::string_view str) 0176 { 0177 auto nextWord = [str](decltype(str)::const_iterator i) { 0178 auto isSpace = [](char c) { 0179 return std::isspace(c); 0180 }; 0181 auto first = std::find_if_not(i, str.cend(), isSpace); 0182 return std::make_pair(first, std::find_if(first, str.cend(), isSpace)); 0183 }; 0184 0185 std::vector<std::string_view> result; 0186 for (auto w = nextWord(str.cbegin()); w.first != str.cend(); w = nextWord(w.second)) { 0187 // TODO[C++20] Use string_view(begin, end) constructor instead 0188 result.emplace_back(std::addressof(*w.first), std::distance(w.first, w.second)); 0189 } 0190 return result; 0191 } 0192 0193 inline std::vector<std::string> splitString(const std::string &str, char separator) 0194 { 0195 std::string token; 0196 std::vector<std::string> result; 0197 std::istringstream istream(str); 0198 while (std::getline(istream, token, separator)) { 0199 result.push_back(token); 0200 } 0201 0202 return result; 0203 } 0204 0205 inline std::vector<std::string> splitString(const char *str, char separator) 0206 { 0207 if (!str) { 0208 return {}; 0209 } 0210 0211 return clazy::splitString(std::string(str), separator); 0212 } 0213 0214 template<typename Container, typename LessThan> 0215 void sort(Container &c, LessThan lessThan) 0216 { 0217 std::sort(c.begin(), c.end(), lessThan); 0218 } 0219 0220 template<typename Container, typename LessThan> 0221 void sort_and_remove_dups(Container &c, LessThan lessThan) 0222 { 0223 std::sort(c.begin(), c.end(), lessThan); 0224 c.erase(std::unique(c.begin(), c.end()), c.end()); 0225 } 0226 0227 inline std::string unquoteString(const std::string &str) 0228 { 0229 // If first and last are ", return what's in between quotes: 0230 if (str.size() >= 3 && str[0] == '"' && str.at(str.size() - 1) == '"') { 0231 return str.substr(1, str.size() - 2); 0232 } 0233 0234 return str; 0235 } 0236 0237 } 0238 0239 #endif