File indexing completed on 2024-05-12 17:16:09
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/svnqttypes.h" 0024 #include "svnqt/status.h" 0025 0026 // std::map 'cause QMap isn't usable, it don't work with with the typenames in class 0027 #include <map> 0028 #include <algorithm> 0029 #include <QString> 0030 #include <QStringList> 0031 #include <QReadWriteLock> 0032 #include <QReadLocker> 0033 #include <QWriteLocker> 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> class cacheEntry 0044 { 0045 public: 0046 typedef cacheEntry<C> cache_type; 0047 typedef typename std::map<QString, cache_type> cache_map_type; 0048 typedef typename cache_map_type::const_iterator citer; 0049 typedef typename cache_map_type::iterator iter; 0050 0051 protected: 0052 QString m_key; 0053 bool m_isValid; 0054 C m_content; 0055 cache_map_type m_subMap; 0056 0057 public: 0058 cacheEntry(); 0059 cacheEntry(const QString &key); 0060 cacheEntry(const cacheEntry<C> &other); 0061 0062 virtual ~cacheEntry() {}; 0063 0064 virtual bool find(QStringList &, QList<C> &)const; 0065 //! Checks if cache contains a specific item 0066 /*! 0067 * the keylist will manipulated - so copy-operations aren't needed. 0068 * \param what Stringlist containing the components to search for 0069 * \return true if found (may or may not valid!) otherwise false 0070 */ 0071 virtual bool find(QStringList &what)const; 0072 //! Checks if cache contains a specific valid item 0073 /*! 0074 * if yes, the content will stored in st 0075 * \param what the keylist to search for 0076 * \param st target status to store content if found 0077 * \return true if found 0078 */ 0079 virtual bool findSingleValid(QStringList &what, C &st)const; 0080 //! Checks if cache contains a specific valid item 0081 /*! 0082 * in difference to virtual bool find(QStringList&,svn::StatusEntries&)const no copy operations 0083 * are made inside so it works much faster for simple find. 0084 * \param what the keylist to search for 0085 * \param check_valid_subs if true, return true if a subitem is valid even the item isn't valid 0086 * \return true if found 0087 */ 0088 virtual bool findSingleValid(QStringList &what, bool check_valid_subs)const; 0089 template<class T> 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 std::map<QString, cacheEntry>::const_iterator it; 0126 for (it = m_subMap.begin(); it != m_subMap.end(); ++it) { 0127 std::cout << pre.latin1() << it->first.latin1() << " (" << it->second.m_key.latin1() << ")" << std::endl; 0128 it->second.dump_tree(level + 1); 0129 } 0130 } 0131 #endif 0132 }; 0133 0134 typedef cacheEntry<svn::StatusPtr> statusEntry; 0135 0136 template<class C> inline cacheEntry<C>::cacheEntry() 0137 : m_key(), m_isValid(false), m_content() 0138 { 0139 } 0140 0141 template<class C> inline cacheEntry<C>::cacheEntry(const QString &key) 0142 : m_key(key), m_isValid(false), m_content() 0143 { 0144 } 0145 0146 template<class C> inline cacheEntry<C>::cacheEntry(const cacheEntry<C> &other) 0147 : m_key(other.m_key), m_isValid(other.m_isValid), 0148 m_content(other.m_content), m_subMap(other.m_subMap) 0149 { 0150 } 0151 0152 template<class C> inline cacheEntry<C> &cacheEntry<C>::operator=(const cacheEntry<C> &other) 0153 { 0154 m_key = other.m_key; 0155 m_isValid = other.m_isValid; 0156 m_content = other.m_content; 0157 m_subMap = other.m_subMap; 0158 return *this; 0159 } 0160 0161 template<class C> inline bool cacheEntry<C>::find(QStringList &what, QList<C> &t)const 0162 { 0163 if (what.empty()) { 0164 return false; 0165 } 0166 citer it = m_subMap.find(what.at(0)); 0167 if (it == m_subMap.end()) { 0168 return false; 0169 } 0170 if (what.count() == 1) { 0171 if (it->second.isValid()) { 0172 t.append(it->second.content()); 0173 } 0174 it->second.appendValidSub(t); 0175 return true; 0176 } 0177 what.erase(what.begin()); 0178 return it->second.find(what, t); 0179 } 0180 0181 template<class C> inline bool cacheEntry<C>::find(QStringList &what)const 0182 { 0183 if (what.isEmpty()) { 0184 return false; 0185 } 0186 citer it = m_subMap.find(what.at(0)); 0187 if (it == m_subMap.end()) { 0188 return false; 0189 } 0190 if (what.count() == 1) { 0191 return true; 0192 } 0193 what.erase(what.begin()); 0194 return it->second.find(what); 0195 } 0196 0197 template<class C> inline bool cacheEntry<C>::findSingleValid(QStringList &what, C &t)const 0198 { 0199 if (what.isEmpty()) { 0200 return false; 0201 } 0202 citer it = m_subMap.find(what.at(0)); 0203 if (it == m_subMap.end()) { 0204 return false; 0205 } 0206 if (what.count() == 1) { 0207 t = it->second.content(); 0208 return it->second.isValid(); 0209 } 0210 what.erase(what.begin()); 0211 return it->second.findSingleValid(what, t); 0212 } 0213 0214 template<class C> inline bool cacheEntry<C>::findSingleValid(QStringList &what, bool check_valid_subs)const 0215 { 0216 if (what.isEmpty()) { 0217 return false; 0218 } 0219 citer it = m_subMap.find(what.at(0)); 0220 if (it == m_subMap.end()) { 0221 return false; 0222 } 0223 if (what.count() == 1) { 0224 return it->second.isValid() || (check_valid_subs && it->second.hasValidSubs()); 0225 } 0226 what.erase(what.begin()); 0227 return it->second.findSingleValid(what, check_valid_subs); 0228 } 0229 0230 template<class C> inline void cacheEntry<C>::appendValidSub(QList<C> &t)const 0231 { 0232 citer it; 0233 for (it = m_subMap.begin(); it != m_subMap.end(); ++it) { 0234 if (it->second.isValid()) { 0235 t.append(it->second.content()); 0236 } 0237 it->second.appendValidSub(t); 0238 } 0239 } 0240 0241 template<class C> inline bool cacheEntry<C>::deleteKey(QStringList &what, bool exact) 0242 { 0243 if (what.isEmpty()) { 0244 return true; 0245 } 0246 iter it = m_subMap.find(what.at(0)); 0247 if (it == m_subMap.end()) { 0248 return true; 0249 } 0250 bool caller_must_check = false; 0251 /* first stage - we are the one holding the right key */ 0252 if (what.count() == 1) { 0253 if (!exact || !it->second.hasValidSubs()) { 0254 m_subMap.erase(it); 0255 caller_must_check = true; 0256 } else { 0257 it->second.markInvalid(); 0258 } 0259 } else { 0260 /* otherwise go trough tree */ 0261 what.erase(what.begin()); 0262 bool b = it->second.deleteKey(what, exact); 0263 if (b && !it->second.hasValidSubs()) { 0264 m_subMap.erase(it); 0265 caller_must_check = true; 0266 } 0267 } 0268 return caller_must_check; 0269 } 0270 0271 template<class C> inline bool cacheEntry<C>::hasValidSubs()const 0272 { 0273 citer it; 0274 for (it = m_subMap.begin(); it != m_subMap.end(); ++it) { 0275 if (it->second.isValid() || it->second.hasValidSubs()) { 0276 return true; 0277 } 0278 } 0279 return false; 0280 } 0281 0282 template<class C> inline void cacheEntry<C>::insertKey(QStringList &what, const C &st) 0283 { 0284 if (what.isEmpty()) { 0285 return; 0286 } 0287 const QString m = what.at(0); 0288 0289 if (m_subMap.find(m) == m_subMap.end()) { 0290 m_subMap[m].m_key = m; 0291 } 0292 if (what.count() == 1) { 0293 m_subMap[m].setValidContent(m, st); 0294 return; 0295 } 0296 what.erase(what.begin()); 0297 m_subMap[m].insertKey(what, st); 0298 } 0299 0300 template<class C> template<class T> inline void cacheEntry<C>::listsubs_if(QStringList &what, T &oper)const 0301 { 0302 if (what.isEmpty()) { 0303 /* we are the one to get the list for*/ 0304 oper = for_each(m_subMap.begin(), m_subMap.end(), oper); 0305 return; 0306 } 0307 /* otherwise find next */ 0308 citer it = m_subMap.find(what.at(0)); 0309 if (it == m_subMap.end()) { 0310 /* not found */ 0311 return; 0312 } 0313 what.erase(what.begin()); 0314 it->second.listsubs_if(what, oper); 0315 } 0316 0317 template<class C> class itemCache 0318 { 0319 public: 0320 typedef cacheEntry<C> cache_type; 0321 typedef typename std::map<QString, cache_type> cache_map_type; 0322 typedef typename cache_map_type::const_iterator citer; 0323 typedef typename cache_map_type::iterator iter; 0324 0325 protected: 0326 cache_map_type m_contentMap; 0327 0328 mutable QReadWriteLock m_RWLock; 0329 0330 public: 0331 itemCache(): m_contentMap(), m_RWLock() {} 0332 virtual ~itemCache() {} 0333 0334 void clear() 0335 { 0336 QWriteLocker locker(&m_RWLock); 0337 m_contentMap.clear(); 0338 } 0339 //! Checks if cache contains a specific item 0340 /*! 0341 * the keylist will manipulated - so copy-operations aren't needed. 0342 * \param what Stringlist containing the components to search for 0343 * \return true if found (may or may not valid!) otherwise false 0344 */ 0345 virtual bool find(const QString &what)const; 0346 0347 virtual void deleteKey(const QString &what, bool exact); 0348 virtual void insertKey(const C &, const QString &path); 0349 virtual bool findSingleValid(const QString &what, C &)const; 0350 virtual bool findSingleValid(const QString &what, bool check_valid_subs)const; 0351 0352 template<class T>void listsubs_if(const QString &what, T &oper)const; 0353 0354 void dump_tree(); 0355 }; 0356 0357 0358 template<class C> inline void itemCache<C>::insertKey(const C &st, const QString &path) 0359 { 0360 QStringList _keys = path.split(QLatin1Char('/')); 0361 if (_keys.isEmpty()) { 0362 return; 0363 } 0364 QWriteLocker locker(&m_RWLock); 0365 0366 const QString m = _keys.at(0); 0367 citer it = m_contentMap.find(m); 0368 0369 if (it == m_contentMap.end()) { 0370 m_contentMap[m] = cache_type(m); 0371 } 0372 if (_keys.count() == 1) { 0373 m_contentMap[m].setValidContent(m, st); 0374 } else { 0375 _keys.erase(_keys.begin()); 0376 m_contentMap[m].insertKey(_keys, st); 0377 } 0378 } 0379 0380 template<class C> inline bool itemCache<C>::find(const QString &what)const 0381 { 0382 QReadLocker locker(&m_RWLock); 0383 0384 if (m_contentMap.empty()) { 0385 return false; 0386 } 0387 QStringList _keys = what.split(QLatin1Char('/')); 0388 if (_keys.isEmpty()) { 0389 return false; 0390 } 0391 citer it = m_contentMap.find(_keys.at(0)); 0392 if (it == m_contentMap.end()) { 0393 return false; 0394 } 0395 if (_keys.count() == 1) { 0396 return true; 0397 } 0398 _keys.erase(_keys.begin()); 0399 return it->second.find(_keys); 0400 } 0401 0402 template<class C> inline void itemCache<C>::deleteKey(const QString &_what, bool exact) 0403 { 0404 QWriteLocker locker(&m_RWLock); 0405 0406 if (m_contentMap.empty()) { 0407 return; 0408 } 0409 QStringList what = _what.split(QLatin1Char('/')); 0410 if (what.isEmpty()) { 0411 return; 0412 } 0413 iter it = m_contentMap.find(what.at(0)); 0414 if (it == m_contentMap.end()) { 0415 return; 0416 } 0417 /* first stage - we are the one holding the right key */ 0418 if (what.count() == 1) { 0419 if (!exact || !it->second.hasValidSubs()) { 0420 /* if it has no valid subs delete it */ 0421 m_contentMap.erase(it); 0422 } else { 0423 /* otherwise mark as invalid */ 0424 it->second.markInvalid(); 0425 } 0426 return; 0427 } else { 0428 /* otherwise go trough tree */ 0429 what.erase(what.begin()); 0430 bool b = it->second.deleteKey(what, exact); 0431 if (b && !it->second.hasValidSubs()) { 0432 m_contentMap.erase(it); 0433 } 0434 } 0435 } 0436 0437 template<class C> inline void itemCache<C>::dump_tree() 0438 { 0439 QReadLocker locker(&m_RWLock); 0440 citer it; 0441 for (it = m_contentMap.begin(); it != m_contentMap.end(); ++it) { 0442 // std::cout<<it->first.latin1() << " (" << it->second.key().latin1() << ")"<<std::endl; 0443 // it->second.dump_tree(1); 0444 } 0445 } 0446 0447 template<class C> inline bool itemCache<C>::findSingleValid(const QString &_what, C &st)const 0448 { 0449 QReadLocker locker(&m_RWLock); 0450 0451 if (m_contentMap.empty()) { 0452 return false; 0453 } 0454 QStringList what = _what.split(QLatin1Char('/')); 0455 if (what.isEmpty()) { 0456 return false; 0457 } 0458 citer it = m_contentMap.find(what.at(0)); 0459 if (it == m_contentMap.end()) { 0460 return false; 0461 } 0462 if (what.count() == 1) { 0463 if (it->second.isValid()) { 0464 st = it->second.content(); 0465 return true; 0466 } 0467 return false; 0468 } 0469 what.erase(what.begin()); 0470 return it->second.findSingleValid(what, st); 0471 } 0472 0473 template<class C> inline bool itemCache<C>::findSingleValid(const QString &_what, bool check_valid_subs)const 0474 { 0475 QReadLocker locker(&m_RWLock); 0476 0477 if (m_contentMap.empty()) { 0478 return false; 0479 } 0480 QStringList what = _what.split(QLatin1Char('/')); 0481 if (what.isEmpty()) { 0482 return false; 0483 } 0484 citer it = m_contentMap.find(what.at(0)); 0485 if (it == m_contentMap.end()) { 0486 return false; 0487 } 0488 if (what.count() == 1) { 0489 return it->second.isValid() || (check_valid_subs && it->second.hasValidSubs()); 0490 } 0491 what.erase(what.begin()); 0492 return it->second.findSingleValid(what, check_valid_subs); 0493 } 0494 0495 template<class C> template<class T> inline void itemCache<C>::listsubs_if(const QString &_what, T &oper)const 0496 { 0497 QReadLocker locker(&m_RWLock); 0498 0499 if (m_contentMap.empty()) { 0500 return; 0501 } 0502 QStringList what = _what.split(QLatin1Char('/')); 0503 if (what.isEmpty()) { 0504 return; 0505 } 0506 citer it = m_contentMap.find(what.at(0)); 0507 0508 if (it == m_contentMap.end()) { 0509 return; 0510 } 0511 if (what.count() == 1) { 0512 oper = for_each(m_contentMap.begin(), m_contentMap.end(), oper); 0513 return; 0514 } 0515 what.erase(what.begin()); 0516 it->second.listsubs_if(what, oper); 0517 } 0518 0519 typedef cacheEntry<svn::StatusPtr> ptrEntry; 0520 typedef itemCache<svn::StatusPtr> statusCache; 0521 0522 class ValidRemoteOnly 0523 { 0524 svn::StatusEntries m_List; 0525 public: 0526 ValidRemoteOnly(): m_List() {} 0527 void operator()(const std::pair<QString, helpers::ptrEntry> &_data) 0528 { 0529 if (_data.second.isValid() && _data.second.content()->validReposStatus() && !_data.second.content()->validLocalStatus()) { 0530 m_List.push_back(_data.second.content()); 0531 } 0532 } 0533 const svn::StatusEntries &liste()const 0534 { 0535 return m_List; 0536 } 0537 }; 0538 0539 } 0540 0541 #endif