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