File indexing completed on 2024-05-19 09:43:04
0001 /***************************************************************************** 0002 * Copyright 2012 - 2015 Yichao Yu <yyc1992@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU Lesser General Public License as * 0006 * published by the Free Software Foundation; either version 2.1 of the * 0007 * License, or (at your option) version 3, or any later version accepted * 0008 * by the membership of KDE e.V. (or its successor approved by the * 0009 * membership of KDE e.V.), which shall act as a proxy defined in * 0010 * Section 6 of version 3 of the license. * 0011 * * 0012 * This program is distributed in the hope that it will be useful, * 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0015 * Lesser General Public License for more details. * 0016 * * 0017 * You should have received a copy of the GNU Lesser General Public * 0018 * License along with this library. If not, * 0019 * see <http://www.gnu.org/licenses/>. * 0020 *****************************************************************************/ 0021 0022 #ifndef _QTC_UTILS_STRS_H_ 0023 #define _QTC_UTILS_STRS_H_ 0024 0025 #include "utils.h" 0026 #include <stdarg.h> 0027 0028 #include <array> 0029 #include <numeric> 0030 #include <functional> 0031 #include <string> 0032 0033 namespace QtCurve { 0034 0035 class uniqueStr : public uniqueCPtr<char> { 0036 public: 0037 // TODO add back when when we drop gcc 4.7 support. 0038 // using uniqueCPtr<char>::uniqueCPtr; 0039 uniqueStr(char *p) 0040 : uniqueCPtr<char>(p) 0041 { 0042 } 0043 template<typename T, 0044 typename std::enable_if< 0045 std::is_convertible<decltype(std::declval<T>()()), 0046 char*>::value>::type* = nullptr> 0047 uniqueStr(T &&f) 0048 : uniqueStr((char*)f()) 0049 { 0050 } 0051 }; 0052 0053 namespace Str { 0054 0055 QTC_ALWAYS_INLINE static inline bool 0056 startsWith(const char *str, const char *head) 0057 { 0058 return strncmp(str, head, strlen(head)) == 0; 0059 } 0060 0061 QTC_ALWAYS_INLINE static inline bool 0062 endsWith(const char *str, const char *tail) 0063 { 0064 size_t len1 = strlen(str); 0065 size_t len2 = strlen(tail); 0066 if (len2 > len1) { 0067 return false; 0068 } 0069 return memcmp(str + len1 - len2, tail, len2) == 0; 0070 } 0071 0072 QTC_ALWAYS_INLINE static inline char* 0073 dup(char *dest, const char *src, size_t len) 0074 { 0075 dest = (char*)realloc(dest, len + 1); 0076 memcpy(dest, src, len); 0077 dest[len] = '\0'; 0078 return dest; 0079 } 0080 QTC_ALWAYS_INLINE static inline char* 0081 dup(char *dest, const char *src) 0082 { 0083 return dup(dest, src, strlen(src)); 0084 } 0085 QTC_ALWAYS_INLINE static inline char* 0086 dup(const char *src) 0087 { 0088 return strdup(src); 0089 } 0090 0091 template<bool allocated=true> __attribute__((format(printf, 3, 0))) 0092 char *vformat(char *buff, size_t *size, const char *fmt, va_list ap); 0093 0094 #ifndef __QTC_UTILS_STRS_INTERNAL__ 0095 extern template __attribute__((format(printf, 3, 0))) 0096 char *vformat<true>(char *buff, size_t *size, const char *fmt, va_list ap); 0097 extern template __attribute__((format(printf, 3, 0))) 0098 char *vformat<false>(char *buff, size_t *size, const char *fmt, va_list ap); 0099 #endif 0100 0101 template<bool allocated=true> 0102 __attribute__((format(printf, 3, 4))) 0103 static inline char* 0104 format(char *buff, size_t *size, const char *fmt, ...) 0105 { 0106 va_list ap; 0107 va_start(ap, fmt); 0108 char *res = vformat<allocated>(buff, size, fmt, ap); 0109 va_end(ap); 0110 return res; 0111 } 0112 0113 template <typename... ArgTypes> 0114 QTC_ALWAYS_INLINE static inline char* 0115 fill(char *buff, ArgTypes&&...strs) 0116 { 0117 const std::array<const char*, sizeof...(strs)> strs_l{{strs...}}; 0118 const std::array<size_t, sizeof...(strs)> str_lens{{strlen(strs)...}}; 0119 const size_t total_len = std::accumulate(str_lens.begin(), 0120 str_lens.end(), 0); 0121 char *res = (buff ? (char*)realloc(buff, total_len + 1) : 0122 (char*)malloc(total_len + 1)); 0123 char *p = res; 0124 for (size_t i = 0;i < sizeof...(strs);i++) { 0125 memcpy(p, strs_l[i], str_lens[i]); 0126 p += str_lens[i]; 0127 } 0128 res[total_len] = 0; 0129 return res; 0130 } 0131 0132 template <typename... ArgTypes> 0133 QTC_ALWAYS_INLINE static inline char* 0134 cat(ArgTypes&&... strs) 0135 { 0136 return fill(nullptr, std::forward<ArgTypes>(strs)...); 0137 } 0138 0139 template<size_t N> 0140 class Buff : public LocalBuff<char, N> { 0141 public: 0142 Buff(size_t size=N, const char *ary=nullptr) 0143 : LocalBuff<char, N>(size, ary) 0144 {} 0145 Buff(const char *str) 0146 : Buff(str ? strlen(str) + 1 : 0, str) 0147 {} 0148 operator char*() const 0149 { 0150 return this->get(); 0151 } 0152 __attribute__((format(printf, 2, 3))) 0153 char* 0154 printf(const char *fmt, ...) 0155 { 0156 va_list ap; 0157 va_start(ap, fmt); 0158 if (this->is_static()) { 0159 size_t new_size = N; 0160 char *res = vformat<false>(this->m_ptr, &new_size, fmt, ap); 0161 if (res != this->m_ptr) { 0162 this->m_ptr = res; 0163 this->m_size = new_size; 0164 } 0165 } else { 0166 this->m_ptr = vformat(this->m_ptr, &this->m_size, fmt, ap); 0167 } 0168 va_end(ap); 0169 return this->m_ptr; 0170 } 0171 template <typename... ArgTypes> 0172 inline char* 0173 cat(ArgTypes&&... strs) 0174 { 0175 return this->append_from(0, std::forward<ArgTypes>(strs)...); 0176 } 0177 template <typename... ArgTypes> 0178 inline char* 0179 append(ArgTypes&&... strs) 0180 { 0181 return this->append_from(strlen(this->m_ptr), 0182 std::forward<ArgTypes>(strs)...); 0183 } 0184 template <typename... ArgTypes> 0185 inline char* 0186 append_from(size_t orig_len, ArgTypes&&... strs) 0187 { 0188 const std::array<const char*, sizeof...(strs)> strs_l{{strs...}}; 0189 const std::array<size_t, sizeof...(strs)> str_lens{{strlen(strs)...}}; 0190 const size_t total_len = std::accumulate(str_lens.begin(), 0191 str_lens.end(), 0) + orig_len; 0192 this->resize(total_len); 0193 char *p = this->m_ptr + orig_len; 0194 for (size_t i = 0;i < sizeof...(strs);i++) { 0195 memcpy(p, strs_l[i], str_lens[i]); 0196 p += str_lens[i]; 0197 } 0198 this->m_ptr[total_len] = 0; 0199 return this->m_ptr; 0200 } 0201 }; 0202 0203 template<typename T> 0204 T convert(const char*, const T &def=T(), bool *is_def=nullptr); 0205 0206 #ifndef __QTC_UTILS_STRS_INTERNAL__ 0207 extern template double convert<double>(const char*, const double& =0, 0208 bool* =nullptr); 0209 extern template long convert<long>(const char*, const long& =0, bool* =nullptr); 0210 extern template bool convert<bool>(const char*, const bool& =false, 0211 bool* =nullptr); 0212 #endif 0213 0214 template<> 0215 inline std::string 0216 convert<std::string>(const char *str, const std::string&, bool *is_def) 0217 { 0218 qtcAssign(is_def, false); 0219 return std::string(str); 0220 } 0221 0222 template<> 0223 inline char* 0224 convert<char*>(const char *str, char *const&, bool *is_def) 0225 { 0226 qtcAssign(is_def, false); 0227 return strdup(str); 0228 } 0229 0230 } 0231 0232 namespace StrList { 0233 0234 void _forEach(const char *str, char delim, char escape, 0235 const std::function<bool(const char*, size_t)> &func); 0236 0237 template<typename Func, typename... Args> 0238 static inline auto 0239 _forEachCaller(const char *str, size_t len, Func &func, Args&... args) 0240 -> typename std::enable_if<std::is_same<decltype(func(str, len, args...)), 0241 bool>::value, bool>::type 0242 { 0243 return func(str, len, args...); 0244 } 0245 0246 template<typename Func, typename... Args> 0247 static inline auto 0248 _forEachCaller(const char *str, size_t, Func &func, Args&... args) 0249 -> typename std::enable_if<std::is_same<decltype(func(str, args...)), 0250 bool>::value, bool>::type 0251 { 0252 return func(str, args...); 0253 } 0254 0255 template<typename Func, typename... Args> 0256 static inline void 0257 forEach(const char *str, char delim, char escape, Func &&func, Args&&... args) 0258 { 0259 using namespace std::placeholders; 0260 _forEach(str, delim, escape, 0261 std::bind(_forEachCaller<typename std::decay<Func>::type, 0262 typename std::decay<Args>::type...>, _1, _2, 0263 std::forward<Func>(func), std::forward<Args>(args)...)); 0264 } 0265 template<typename Func, typename... Args> 0266 static inline typename std::enable_if<!_isChar<Func>::value>::type 0267 forEach(const char *str, char delim, Func &&func, Args&&... args) 0268 { 0269 forEach(str, delim, '\\', std::forward<Func>(func), 0270 std::forward<Args>(args)...); 0271 } 0272 template<typename Func, typename... Args> 0273 static inline typename std::enable_if<!_isChar<Func>::value>::type 0274 forEach(const char *str, Func &&func, Args&&... args) 0275 { 0276 forEach(str, ',', std::forward<Func>(func), std::forward<Args>(args)...); 0277 } 0278 0279 } 0280 } 0281 0282 typedef bool (*QtcListEleLoader)(void *ele, const char *str, 0283 size_t len, void *data); 0284 0285 void *qtcStrLoadList(const char *str, char delim, char escape, 0286 size_t size, size_t *nele, void *buff, size_t max_len, 0287 QtcListEleLoader loader, void *data=nullptr); 0288 #define qtcStrLoadList(str, delim, escape, size, nele, \ 0289 buff, max_len, loader, data...) \ 0290 qtcStrLoadList(str, QTC_DEFAULT(delim, ','), QTC_DEFAULT(escape, '\\'), \ 0291 size, nele, QTC_DEFAULT(buff, nullptr), \ 0292 QTC_DEFAULT(max_len, 0), loader, ##data) 0293 0294 char **qtcStrLoadStrList(const char *str, char delim, char escape, size_t *nele, 0295 char **buff, size_t max_len, const char *def); 0296 #define qtcStrLoadStrList(str, delim, escape, nele, buff, max_len, def) \ 0297 qtcStrLoadStrList(str, QTC_DEFAULT(delim, ','), \ 0298 QTC_DEFAULT(escape, '\\'), nele, \ 0299 QTC_DEFAULT(buff, nullptr), QTC_DEFAULT(max_len, 0), \ 0300 QTC_DEFAULT(def, nullptr)) 0301 0302 long *qtcStrLoadIntList(const char *str, char delim, char escape, 0303 size_t *nele, long *buff=nullptr, 0304 size_t max_len=0, long def=0); 0305 #define qtcStrLoadIntList(str, delim, escape, nele, extra...) \ 0306 qtcStrLoadIntList(str, QTC_DEFAULT(delim, ','), \ 0307 QTC_DEFAULT(escape, '\\'), nele, ##extra) 0308 0309 double *qtcStrLoadFloatList(const char *str, char delim, char escape, 0310 size_t *nele, double *buff=nullptr, 0311 size_t max_len=0, double def=0); 0312 #define qtcStrLoadFloatList(str, delim, escape, nele, extra...) \ 0313 qtcStrLoadFloatList(str, QTC_DEFAULT(delim, ','), \ 0314 QTC_DEFAULT(escape, '\\'), nele, ##extra) 0315 0316 #endif