File indexing completed on 2024-04-28 05:41:59
0001 /*************************************************************************** 0002 * Copyright (C) 2005-2009 by Rajko Albrecht * 0003 * ral@alwins-world.de * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0019 ***************************************************************************/ 0020 #ifndef HELPERSCACHEENTRY_H 0021 #define HELPERSCACHEENTRY_H 0022 0023 #include "svnqt/status.h" 0024 #include "svnqt/svnqttypes.h" 0025 0026 // std::map 'cause QMap isn't usable, it don't work with with the typenames in class 0027 #include <QReadLocker> 0028 #include <QReadWriteLock> 0029 #include <QString> 0030 #include <QStringList> 0031 #include <QWriteLocker> 0032 #include <algorithm> 0033 #include <map> 0034 0035 namespace helpers 0036 { 0037 0038 /** 0039 Class for fast search of path based items. 0040 0041 @author Rajko Albrecht <ral@alwins-world.de> 0042 */ 0043 template<class C> 0044 class cacheEntry 0045 { 0046 public: 0047 typedef cacheEntry<C> cache_type; 0048 typedef typename std::map<QString, cache_type> cache_map_type; 0049 0050 protected: 0051 QString m_key; 0052 bool m_isValid; 0053 C m_content; 0054 cache_map_type m_subMap; 0055 0056 public: 0057 cacheEntry(); 0058 cacheEntry(const QString &key); 0059 cacheEntry(const cacheEntry<C> &other); 0060 0061 virtual ~cacheEntry() = default; 0062 0063 virtual bool find(QStringList &, QList<C> &) const; 0064 //! Checks if cache contains a specific item 0065 /*! 0066 * the keylist will manipulated - so copy-operations aren't needed. 0067 * \param what Stringlist containing the components to search for 0068 * \return true if found (may or may not valid!) otherwise false 0069 */ 0070 virtual bool find(QStringList &what) const; 0071 //! Checks if cache contains a specific valid item 0072 /*! 0073 * if yes, the content will stored in st 0074 * \param what the keylist to search for 0075 * \param st target status to store content if found 0076 * \return true if found 0077 */ 0078 virtual bool findSingleValid(QStringList &what, C &st) const; 0079 //! Checks if cache contains a specific valid item 0080 /*! 0081 * in difference to virtual bool find(QStringList&,svn::StatusEntries&)const no copy operations 0082 * are made inside so it works much faster for simple find. 0083 * \param what the keylist to search for 0084 * \param check_valid_subs if true, return true if a subitem is valid even the item isn't valid 0085 * \return true if found 0086 */ 0087 virtual bool findSingleValid(QStringList &what, bool check_valid_subs) const; 0088 template<class T> 0089 void listsubs_if(QStringList &_what, T &oper) const; 0090 0091 virtual void appendValidSub(QList<C> &) const; 0092 virtual bool isValid() const 0093 { 0094 return m_isValid; 0095 } 0096 virtual const C &content() const 0097 { 0098 return m_content; 0099 } 0100 virtual bool deleteKey(QStringList &, bool exact); 0101 virtual void insertKey(QStringList &, const C &); 0102 virtual void setValidContent(const QString &key, const C &st) 0103 { 0104 m_key = key; 0105 m_isValid = true; 0106 m_content = st; 0107 } 0108 virtual bool hasValidSubs() const; 0109 virtual void markInvalid() 0110 { 0111 m_content = C(); 0112 m_isValid = false; 0113 } 0114 const QString &key() const 0115 { 0116 return m_key; 0117 } 0118 0119 cacheEntry<C> &operator=(const cacheEntry<C> &other); 0120 #if 0 0121 void dump_tree(int level = 0)const 0122 { 0123 QString pre; 0124 pre.fill('-', level); 0125 for (auto it = m_subMap.begin(); it != m_subMap.end(); ++it) { 0126 std::cout << pre.latin1() << it->first.latin1() << " (" << it->second.m_key.latin1() << ")" << std::endl; 0127 it->second.dump_tree(level + 1); 0128 } 0129 } 0130 #endif 0131 }; 0132 0133 typedef cacheEntry<svn::StatusPtr> statusEntry; 0134 0135 template<class C> 0136 inline cacheEntry<C>::cacheEntry() 0137 : m_key() 0138 , m_isValid(false) 0139 , m_content() 0140 { 0141 } 0142 0143 template<class C> 0144 inline cacheEntry<C>::cacheEntry(const QString &key) 0145 : m_key(key) 0146 , m_isValid(false) 0147 , m_content() 0148 { 0149 } 0150 0151 template<class C> 0152 inline cacheEntry<C>::cacheEntry(const cacheEntry<C> &other) 0153 : m_key(other.m_key) 0154 , m_isValid(other.m_isValid) 0155 , m_content(other.m_content) 0156 , m_subMap(other.m_subMap) 0157 { 0158 } 0159 0160 template<class C> 0161 inline cacheEntry<C> &cacheEntry<C>::operator=(const cacheEntry<C> &other) 0162 { 0163 m_key = other.m_key; 0164 m_isValid = other.m_isValid; 0165 m_content = other.m_content; 0166 m_subMap = other.m_subMap; 0167 return *this; 0168 } 0169 0170 template<class C> 0171 inline bool cacheEntry<C>::find(QStringList &what, QList<C> &t) const 0172 { 0173 if (what.empty()) { 0174 return false; 0175 } 0176 const auto it = m_subMap.find(what.at(0)); 0177 if (it == m_subMap.end()) { 0178 return false; 0179 } 0180 if (what.count() == 1) { 0181 if (it->second.isValid()) { 0182 t.append(it->second.content()); 0183 } 0184 it->second.appendValidSub(t); 0185 return true; 0186 } 0187 what.erase(what.begin()); 0188 return it->second.find(what, t); 0189 } 0190 0191 template<class C> 0192 inline bool cacheEntry<C>::find(QStringList &what) const 0193 { 0194 if (what.isEmpty()) { 0195 return false; 0196 } 0197 const auto it = m_subMap.find(what.at(0)); 0198 if (it == m_subMap.end()) { 0199 return false; 0200 } 0201 if (what.count() == 1) { 0202 return true; 0203 } 0204 what.erase(what.begin()); 0205 return it->second.find(what); 0206 } 0207 0208 template<class C> 0209 inline bool cacheEntry<C>::findSingleValid(QStringList &what, C &t) const 0210 { 0211 if (what.isEmpty()) { 0212 return false; 0213 } 0214 const auto it = m_subMap.find(what.at(0)); 0215 if (it == m_subMap.end()) { 0216 return false; 0217 } 0218 if (what.count() == 1) { 0219 t = it->second.content(); 0220 return it->second.isValid(); 0221 } 0222 what.erase(what.begin()); 0223 return it->second.findSingleValid(what, t); 0224 } 0225 0226 template<class C> 0227 inline bool cacheEntry<C>::findSingleValid(QStringList &what, bool check_valid_subs) const 0228 { 0229 if (what.isEmpty()) { 0230 return false; 0231 } 0232 const auto it = m_subMap.find(what.at(0)); 0233 if (it == m_subMap.end()) { 0234 return false; 0235 } 0236 if (what.count() == 1) { 0237 return it->second.isValid() || (check_valid_subs && it->second.hasValidSubs()); 0238 } 0239 what.erase(what.begin()); 0240 return it->second.findSingleValid(what, check_valid_subs); 0241 } 0242 0243 template<class C> 0244 inline void cacheEntry<C>::appendValidSub(QList<C> &t) const 0245 { 0246 for (const auto &it : m_subMap) { 0247 if (it.second.isValid()) { 0248 t.append(it.second.content()); 0249 } 0250 it.second.appendValidSub(t); 0251 } 0252 } 0253 0254 template<class C> 0255 inline bool cacheEntry<C>::deleteKey(QStringList &what, bool exact) 0256 { 0257 if (what.isEmpty()) { 0258 return true; 0259 } 0260 const auto it = m_subMap.find(what.at(0)); 0261 if (it == m_subMap.end()) { 0262 return true; 0263 } 0264 bool caller_must_check = false; 0265 /* first stage - we are the one holding the right key */ 0266 if (what.count() == 1) { 0267 if (!exact || !it->second.hasValidSubs()) { 0268 m_subMap.erase(it); 0269 caller_must_check = true; 0270 } else { 0271 it->second.markInvalid(); 0272 } 0273 } else { 0274 /* otherwise go trough tree */ 0275 what.erase(what.begin()); 0276 bool b = it->second.deleteKey(what, exact); 0277 if (b && !it->second.hasValidSubs()) { 0278 m_subMap.erase(it); 0279 caller_must_check = true; 0280 } 0281 } 0282 return caller_must_check; 0283 } 0284 0285 template<class C> 0286 inline bool cacheEntry<C>::hasValidSubs() const 0287 { 0288 for (const auto &it : m_subMap) { 0289 if (it.second.isValid() || it.second.hasValidSubs()) { 0290 return true; 0291 } 0292 } 0293 return false; 0294 } 0295 0296 template<class C> 0297 inline void cacheEntry<C>::insertKey(QStringList &what, const C &st) 0298 { 0299 if (what.isEmpty()) { 0300 return; 0301 } 0302 const QString m = what.at(0); 0303 0304 if (m_subMap.find(m) == m_subMap.end()) { 0305 m_subMap[m].m_key = m; 0306 } 0307 if (what.count() == 1) { 0308 m_subMap[m].setValidContent(m, st); 0309 return; 0310 } 0311 what.erase(what.begin()); 0312 m_subMap[m].insertKey(what, st); 0313 } 0314 0315 template<class C> 0316 template<class T> 0317 inline void cacheEntry<C>::listsubs_if(QStringList &what, T &oper) const 0318 { 0319 if (what.isEmpty()) { 0320 /* we are the one to get the list for*/ 0321 oper = for_each(m_subMap.begin(), m_subMap.end(), oper); 0322 return; 0323 } 0324 /* otherwise find next */ 0325 const auto it = m_subMap.find(what.at(0)); 0326 if (it == m_subMap.end()) { 0327 /* not found */ 0328 return; 0329 } 0330 what.erase(what.begin()); 0331 it->second.listsubs_if(what, oper); 0332 } 0333 0334 template<class C> 0335 class itemCache 0336 { 0337 public: 0338 typedef cacheEntry<C> cache_type; 0339 typedef typename std::map<QString, cache_type> cache_map_type; 0340 0341 protected: 0342 cache_map_type m_contentMap; 0343 0344 mutable QReadWriteLock m_RWLock; 0345 0346 public: 0347 itemCache() = default; 0348 virtual ~itemCache() = default; 0349 0350 void clear() 0351 { 0352 QWriteLocker locker(&m_RWLock); 0353 m_contentMap.clear(); 0354 } 0355 //! Checks if cache contains a specific item 0356 /*! 0357 * the keylist will manipulated - so copy-operations aren't needed. 0358 * \param what Stringlist containing the components to search for 0359 * \return true if found (may or may not valid!) otherwise false 0360 */ 0361 virtual bool find(const QString &what) const; 0362 0363 virtual void deleteKey(const QString &what, bool exact); 0364 virtual void insertKey(const C &, const QString &path); 0365 virtual bool findSingleValid(const QString &what, C &) const; 0366 virtual bool findSingleValid(const QString &what, bool check_valid_subs) const; 0367 0368 template<class T> 0369 void listsubs_if(const QString &what, T &oper) const; 0370 0371 void dump_tree(); 0372 }; 0373 0374 template<class C> 0375 inline void itemCache<C>::insertKey(const C &st, const QString &path) 0376 { 0377 QStringList _keys = path.split(QLatin1Char('/')); 0378 if (_keys.isEmpty()) { 0379 return; 0380 } 0381 QWriteLocker locker(&m_RWLock); 0382 0383 const QString m = _keys.at(0); 0384 const auto it = m_contentMap.find(m); 0385 0386 if (it == m_contentMap.end()) { 0387 m_contentMap[m] = cache_type(m); 0388 } 0389 if (_keys.count() == 1) { 0390 m_contentMap[m].setValidContent(m, st); 0391 } else { 0392 _keys.erase(_keys.begin()); 0393 m_contentMap[m].insertKey(_keys, st); 0394 } 0395 } 0396 0397 template<class C> 0398 inline bool itemCache<C>::find(const QString &what) const 0399 { 0400 QReadLocker locker(&m_RWLock); 0401 0402 if (m_contentMap.empty()) { 0403 return false; 0404 } 0405 QStringList _keys = what.split(QLatin1Char('/')); 0406 if (_keys.isEmpty()) { 0407 return false; 0408 } 0409 const auto it = m_contentMap.find(_keys.at(0)); 0410 if (it == m_contentMap.end()) { 0411 return false; 0412 } 0413 if (_keys.count() == 1) { 0414 return true; 0415 } 0416 _keys.erase(_keys.begin()); 0417 return it->second.find(_keys); 0418 } 0419 0420 template<class C> 0421 inline void itemCache<C>::deleteKey(const QString &_what, bool exact) 0422 { 0423 QWriteLocker locker(&m_RWLock); 0424 0425 if (m_contentMap.empty()) { 0426 return; 0427 } 0428 QStringList what = _what.split(QLatin1Char('/')); 0429 if (what.isEmpty()) { 0430 return; 0431 } 0432 const auto it = m_contentMap.find(what.at(0)); 0433 if (it == m_contentMap.end()) { 0434 return; 0435 } 0436 /* first stage - we are the one holding the right key */ 0437 if (what.count() == 1) { 0438 if (!exact || !it->second.hasValidSubs()) { 0439 /* if it has no valid subs delete it */ 0440 m_contentMap.erase(it); 0441 } else { 0442 /* otherwise mark as invalid */ 0443 it->second.markInvalid(); 0444 } 0445 return; 0446 } else { 0447 /* otherwise go trough tree */ 0448 what.erase(what.begin()); 0449 bool b = it->second.deleteKey(what, exact); 0450 if (b && !it->second.hasValidSubs()) { 0451 m_contentMap.erase(it); 0452 } 0453 } 0454 } 0455 0456 template<class C> 0457 inline void itemCache<C>::dump_tree() 0458 { 0459 QReadLocker locker(&m_RWLock); 0460 for (auto it = m_contentMap.begin(); it != m_contentMap.end(); ++it) { 0461 // std::cout<<it->first.latin1() << " (" << it->second.key().latin1() << ")"<<std::endl; 0462 // it->second.dump_tree(1); 0463 } 0464 } 0465 0466 template<class C> 0467 inline bool itemCache<C>::findSingleValid(const QString &_what, C &st) const 0468 { 0469 QReadLocker locker(&m_RWLock); 0470 0471 if (m_contentMap.empty()) { 0472 return false; 0473 } 0474 QStringList what = _what.split(QLatin1Char('/')); 0475 if (what.isEmpty()) { 0476 return false; 0477 } 0478 const auto it = m_contentMap.find(what.at(0)); 0479 if (it == m_contentMap.end()) { 0480 return false; 0481 } 0482 if (what.count() == 1) { 0483 if (it->second.isValid()) { 0484 st = it->second.content(); 0485 return true; 0486 } 0487 return false; 0488 } 0489 what.erase(what.begin()); 0490 return it->second.findSingleValid(what, st); 0491 } 0492 0493 template<class C> 0494 inline bool itemCache<C>::findSingleValid(const QString &_what, bool check_valid_subs) const 0495 { 0496 QReadLocker locker(&m_RWLock); 0497 0498 if (m_contentMap.empty()) { 0499 return false; 0500 } 0501 QStringList what = _what.split(QLatin1Char('/')); 0502 if (what.isEmpty()) { 0503 return false; 0504 } 0505 const auto it = m_contentMap.find(what.at(0)); 0506 if (it == m_contentMap.end()) { 0507 return false; 0508 } 0509 if (what.count() == 1) { 0510 return it->second.isValid() || (check_valid_subs && it->second.hasValidSubs()); 0511 } 0512 what.erase(what.begin()); 0513 return it->second.findSingleValid(what, check_valid_subs); 0514 } 0515 0516 template<class C> 0517 template<class T> 0518 inline void itemCache<C>::listsubs_if(const QString &_what, T &oper) const 0519 { 0520 QReadLocker locker(&m_RWLock); 0521 0522 if (m_contentMap.empty()) { 0523 return; 0524 } 0525 QStringList what = _what.split(QLatin1Char('/')); 0526 if (what.isEmpty()) { 0527 return; 0528 } 0529 const auto it = m_contentMap.find(what.at(0)); 0530 if (it == m_contentMap.end()) { 0531 return; 0532 } 0533 if (what.count() == 1) { 0534 oper = for_each(m_contentMap.begin(), m_contentMap.end(), oper); 0535 return; 0536 } 0537 what.erase(what.begin()); 0538 it->second.listsubs_if(what, oper); 0539 } 0540 0541 typedef cacheEntry<svn::StatusPtr> ptrEntry; 0542 typedef itemCache<svn::StatusPtr> statusCache; 0543 0544 class ValidRemoteOnly 0545 { 0546 svn::StatusEntries m_List; 0547 0548 public: 0549 ValidRemoteOnly() 0550 : m_List() 0551 { 0552 } 0553 void operator()(const std::pair<QString, helpers::ptrEntry> &_data) 0554 { 0555 if (_data.second.isValid() && _data.second.content()->validReposStatus() && !_data.second.content()->validLocalStatus()) { 0556 m_List.push_back(_data.second.content()); 0557 } 0558 } 0559 const svn::StatusEntries &liste() const 0560 { 0561 return m_List; 0562 } 0563 }; 0564 0565 } 0566 0567 #endif