File indexing completed on 2024-04-28 15:30:45

0001 /*
0002     SPDX-FileCopyrightText: 2009 Michel Ludwig <michel.ludwig@kdemail.net>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "prefixstore.h"
0008 
0009 #include "katepartdebug.h"
0010 
0011 void KatePrefixStore::addPrefix(const QString &prefix)
0012 {
0013     if (prefix.isEmpty()) {
0014         return;
0015     }
0016     if (m_prefixSet.contains(prefix)) {
0017         return;
0018     }
0019     unsigned long long state = 0;
0020     for (int i = 0; i < prefix.length(); ++i) {
0021         QChar c = prefix.at(i);
0022 
0023         CharToOccurrenceStateHash &hash = m_transitionFunction[state];
0024         CharToOccurrenceStateHash::iterator it = hash.find(c.unicode());
0025         if (it == hash.end()) {
0026             state = nextFreeState();
0027             hash[c.unicode()] = QPair<unsigned int, unsigned long long>(1, state);
0028             continue;
0029         }
0030 
0031         ++(*it).first;
0032         state = (*it).second;
0033     }
0034     // add the last state as accepting state
0035     m_acceptingStates.insert(state);
0036 
0037     m_prefixSet.insert(prefix);
0038 
0039     if (prefix.length() > m_longestPrefixLength) {
0040         m_longestPrefixLength = prefix.length();
0041     }
0042 }
0043 
0044 void KatePrefixStore::removePrefix(const QString &prefix)
0045 {
0046     if (prefix.isEmpty()) {
0047         return;
0048     }
0049     if (!m_prefixSet.contains(prefix)) {
0050         return;
0051     }
0052     m_prefixSet.remove(prefix);
0053 
0054     unsigned long long state = 0;
0055     for (int i = 0; i < prefix.length(); ++i) {
0056         QChar c = prefix.at(i);
0057 
0058         CharToOccurrenceStateHash &hash = m_transitionFunction[state];
0059         CharToOccurrenceStateHash::iterator it = hash.find(c.unicode());
0060         if (it == hash.end()) {
0061             continue;
0062         }
0063 
0064         state = (*it).second;
0065         if (m_acceptingStates.contains(state) && i == prefix.length() - 1) {
0066             m_acceptingStates.remove(state);
0067         }
0068 
0069         if ((*it).first <= 1) {
0070             hash.erase(it);
0071             m_stateFreeList.push_back(state);
0072         } else {
0073             --(*it).first;
0074         }
0075     }
0076 
0077     if (prefix.length() == m_longestPrefixLength) {
0078         m_longestPrefixLength = computeLongestPrefixLength();
0079     }
0080 }
0081 
0082 void KatePrefixStore::dump()
0083 {
0084     for (unsigned long long i = 0; i < m_lastAssignedState; ++i) {
0085         CharToOccurrenceStateHash &hash = m_transitionFunction[i];
0086         for (CharToOccurrenceStateHash::iterator it = hash.begin(); it != hash.end(); ++it) {
0087             qCDebug(LOG_KTE) << i << "x" << QChar(it.key()) << "->" << it.value().first << "x" << it.value().second;
0088         }
0089     }
0090     qCDebug(LOG_KTE) << "Accepting states" << m_acceptingStates;
0091 }
0092 
0093 QString KatePrefixStore::findPrefix(const QString &s, int start) const
0094 {
0095     unsigned long long state = 0;
0096     for (int i = start; i < s.length(); ++i) {
0097         QChar c = s.at(i);
0098         const CharToOccurrenceStateHash &hash = m_transitionFunction[state];
0099         CharToOccurrenceStateHash::const_iterator it = hash.find(c.unicode());
0100         if (it == hash.end()) {
0101             return QString();
0102         }
0103 
0104         state = (*it).second;
0105         if (m_acceptingStates.contains(state)) {
0106             return s.mid(start, i + 1 - start);
0107         }
0108     }
0109     return QString();
0110 }
0111 
0112 QString KatePrefixStore::findPrefix(const Kate::TextLine &line, int start) const
0113 {
0114     unsigned long long state = 0;
0115     for (int i = start; i < line->length(); ++i) {
0116         QChar c = line->at(i);
0117         const CharToOccurrenceStateHash &hash = m_transitionFunction[state];
0118         CharToOccurrenceStateHash::const_iterator it = hash.find(c.unicode());
0119         if (it == hash.end()) {
0120             return QString();
0121         }
0122 
0123         state = (*it).second;
0124         if (m_acceptingStates.contains(state)) {
0125             return line->string(start, i + 1 - start);
0126         }
0127     }
0128     return QString();
0129 }
0130 
0131 int KatePrefixStore::longestPrefixLength() const
0132 {
0133     return m_longestPrefixLength;
0134 }
0135 
0136 void KatePrefixStore::clear()
0137 {
0138     m_longestPrefixLength = 0;
0139     m_prefixSet.clear();
0140     m_transitionFunction.clear();
0141     m_acceptingStates.clear();
0142     m_stateFreeList.clear();
0143     m_lastAssignedState = 0;
0144 }
0145 
0146 int KatePrefixStore::computeLongestPrefixLength()
0147 {
0148     int toReturn = 0;
0149     for (QSet<QString>::const_iterator i = m_prefixSet.cbegin(); i != m_prefixSet.cend(); ++i) {
0150         qCDebug(LOG_KTE) << "length" << (*i).length();
0151         toReturn = qMax(toReturn, (*i).length());
0152     }
0153     return toReturn;
0154 }
0155 
0156 unsigned long long KatePrefixStore::nextFreeState()
0157 {
0158     if (!m_stateFreeList.isEmpty()) {
0159         return m_stateFreeList.takeFirst();
0160     }
0161     return ++m_lastAssignedState;
0162 }