File indexing completed on 2024-04-28 03:53:09
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1999 Carsten Pfeiffer <pfeiffer@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef KCOMPTREENODE_P_H 0009 #define KCOMPTREENODE_P_H 0010 0011 #include "kcompletion_export.h" 0012 0013 #include <QSharedPointer> 0014 #include <kzoneallocator_p.h> 0015 0016 class KCompTreeNode; 0017 0018 class KCOMPLETION_EXPORT KCompTreeChildren 0019 { 0020 public: 0021 KCompTreeChildren() 0022 : m_first(nullptr) 0023 , m_last(nullptr) 0024 , m_count(0) 0025 { 0026 } 0027 0028 KCompTreeNode *begin() const 0029 { 0030 return m_first; 0031 } 0032 0033 KCompTreeNode *end() const 0034 { 0035 return m_last; 0036 } 0037 0038 inline KCompTreeNode *at(uint index) const; 0039 inline void append(KCompTreeNode *item); 0040 inline void prepend(KCompTreeNode *item); 0041 inline void insert(KCompTreeNode *after, KCompTreeNode *item); 0042 inline KCompTreeNode *remove(KCompTreeNode *item); 0043 0044 uint count() const 0045 { 0046 return m_count; 0047 } 0048 0049 private: 0050 KCompTreeNode *m_first; 0051 KCompTreeNode *m_last; 0052 uint m_count; 0053 }; 0054 0055 /** 0056 * A helper class for KCompletion. Implements a tree of QChar. 0057 * Every node is a QChar and has a list of children, which are Nodes as well. 0058 * 0059 * QChar( 0x0 ) is used as the delimiter of a string; the last child of each 0060 * inserted string is 0x0. 0061 * 0062 * The tree looks like this (containing the items "kde", "kde-ui", 0063 * "kde-core" and "pfeiffer". Every item is delimited with QChar( 0x0 ) 0064 * 0065 * some_root_node 0066 * / \ 0067 * k p 0068 * | | 0069 * d f 0070 * | | 0071 * e e 0072 * /| | 0073 * 0x0 - i 0074 * / \ | 0075 * u c f 0076 * | | | 0077 * i o f 0078 * | | | 0079 * 0x0 r e 0080 * | | 0081 * e r 0082 * | | 0083 * 0x0 0x0 0084 * 0085 * @author Carsten Pfeiffer <pfeiffer@kde.org> 0086 * @internal 0087 */ 0088 class KCOMPLETION_EXPORT KCompTreeNode : public QChar 0089 { 0090 public: 0091 KCompTreeNode() 0092 : QChar() 0093 , m_next(nullptr) 0094 , m_weight(0) 0095 { 0096 } 0097 0098 explicit KCompTreeNode(const QChar &ch, uint weight = 0) 0099 : QChar(ch) 0100 , m_next(nullptr) 0101 , m_weight(weight) 0102 { 0103 } 0104 0105 ~KCompTreeNode() 0106 { 0107 // delete all children 0108 KCompTreeNode *cur = m_children.begin(); 0109 while (cur) { 0110 KCompTreeNode *next = cur->m_next; 0111 delete m_children.remove(cur); 0112 cur = next; 0113 } 0114 } 0115 0116 KCompTreeNode(const KCompTreeNode &) = delete; 0117 KCompTreeNode &operator=(const KCompTreeNode &) = delete; 0118 0119 void *operator new(size_t s) 0120 { 0121 Q_ASSERT(m_alloc); 0122 return m_alloc->allocate(s); 0123 } 0124 0125 void operator delete(void *s) 0126 { 0127 Q_ASSERT(m_alloc); 0128 m_alloc->deallocate(s); 0129 } 0130 0131 // Returns a child of this node matching ch, if available. 0132 // Otherwise, returns 0L 0133 KCompTreeNode *find(const QChar &ch) const 0134 { 0135 KCompTreeNode *cur = m_children.begin(); 0136 while (cur && (*cur != ch)) { 0137 cur = cur->m_next; 0138 } 0139 return cur; 0140 } 0141 0142 // Adds a child-node "ch" to this node. If such a node is already existent, 0143 // it will not be created. Returns the new/existing node. 0144 inline KCompTreeNode *insert(const QChar &ch, bool sorted); 0145 0146 // Iteratively removes a string from the tree. The nicer recursive 0147 // version apparently was a little memory hungry (see #56757) 0148 inline void remove(const QString &str); 0149 0150 int childrenCount() const 0151 { 0152 return m_children.count(); 0153 } 0154 0155 void confirm() 0156 { 0157 m_weight++; 0158 } 0159 0160 void confirm(uint w) 0161 { 0162 m_weight += w; 0163 } 0164 0165 void decline() 0166 { 0167 m_weight--; 0168 } 0169 0170 uint weight() const 0171 { 0172 return m_weight; 0173 } 0174 0175 const KCompTreeChildren *children() const 0176 { 0177 return &m_children; 0178 } 0179 0180 const KCompTreeNode *childAt(int index) const 0181 { 0182 return m_children.at(index); 0183 } 0184 0185 const KCompTreeNode *firstChild() const 0186 { 0187 return m_children.begin(); 0188 } 0189 0190 const KCompTreeNode *lastChild() const 0191 { 0192 return m_children.end(); 0193 } 0194 0195 /* We want to handle a list of KCompTreeNodes on our own, to not 0196 need to use QValueList<>. And to make it even faster we don't 0197 use an accessor, but just a public member. */ 0198 KCompTreeNode *m_next; 0199 0200 /** 0201 * Custom allocator used for all KCompTreeNode instances 0202 */ 0203 static QSharedPointer<KZoneAllocator> allocator() 0204 { 0205 return m_alloc; 0206 } 0207 0208 private: 0209 uint m_weight; 0210 KCompTreeChildren m_children; 0211 static QSharedPointer<KZoneAllocator> m_alloc; 0212 }; 0213 0214 KCompTreeNode *KCompTreeNode::insert(const QChar &ch, bool sorted) 0215 { 0216 KCompTreeNode *child = find(ch); 0217 if (!child) { 0218 child = new KCompTreeNode(ch); 0219 0220 // FIXME, first (slow) sorted insertion implementation 0221 if (sorted) { 0222 KCompTreeNode *prev = nullptr; 0223 KCompTreeNode *cur = m_children.begin(); 0224 while (cur) { 0225 if (ch > *cur) { 0226 prev = cur; 0227 cur = cur->m_next; 0228 } else { 0229 break; 0230 } 0231 } 0232 if (prev) { 0233 m_children.insert(prev, child); 0234 } else { 0235 m_children.prepend(child); 0236 } 0237 } 0238 0239 else { 0240 m_children.append(child); 0241 } 0242 } 0243 0244 // implicit weighting: the more often an item is inserted, the higher 0245 // priority it gets. 0246 child->confirm(); 0247 0248 return child; 0249 } 0250 0251 void KCompTreeNode::remove(const QString &str) 0252 { 0253 QString string = str; 0254 string += QChar(0x0); 0255 0256 QList<KCompTreeNode *> deletables(string.length() + 1); 0257 0258 KCompTreeNode *child = nullptr; 0259 KCompTreeNode *parent = this; 0260 deletables.replace(0, parent); 0261 0262 int i = 0; 0263 for (; i < string.length(); i++) { 0264 child = parent->find(string.at(i)); 0265 if (child) { 0266 deletables.replace(i + 1, child); 0267 } else { 0268 break; 0269 } 0270 0271 parent = child; 0272 } 0273 0274 for (; i >= 1; i--) { 0275 parent = deletables.at(i - 1); 0276 child = deletables.at(i); 0277 if (child->m_children.count() == 0) { 0278 delete parent->m_children.remove(child); 0279 } 0280 } 0281 } 0282 0283 KCompTreeNode *KCompTreeChildren::at(uint index) const 0284 { 0285 KCompTreeNode *cur = m_first; 0286 while (index-- && cur) { 0287 cur = cur->m_next; 0288 } 0289 return cur; 0290 } 0291 0292 void KCompTreeChildren::append(KCompTreeNode *item) 0293 { 0294 m_count++; 0295 if (!m_last) { 0296 m_last = item; 0297 m_last->m_next = nullptr; 0298 m_first = item; 0299 return; 0300 } 0301 m_last->m_next = item; 0302 item->m_next = nullptr; 0303 m_last = item; 0304 } 0305 0306 void KCompTreeChildren::prepend(KCompTreeNode *item) 0307 { 0308 m_count++; 0309 if (!m_last) { 0310 m_last = item; 0311 m_last->m_next = nullptr; 0312 m_first = item; 0313 return; 0314 } 0315 item->m_next = m_first; 0316 m_first = item; 0317 } 0318 0319 void KCompTreeChildren::insert(KCompTreeNode *after, KCompTreeNode *item) 0320 { 0321 if (!after) { 0322 append(item); 0323 return; 0324 } 0325 0326 m_count++; 0327 0328 item->m_next = after->m_next; 0329 after->m_next = item; 0330 0331 if (after == m_last) { 0332 m_last = item; 0333 } 0334 } 0335 0336 KCompTreeNode *KCompTreeChildren::remove(KCompTreeNode *item) 0337 { 0338 if (!m_first || !item) { 0339 return nullptr; 0340 } 0341 KCompTreeNode *cur = nullptr; 0342 0343 if (item == m_first) { 0344 m_first = m_first->m_next; 0345 } else { 0346 cur = m_first; 0347 while (cur && cur->m_next != item) { 0348 cur = cur->m_next; 0349 } 0350 if (!cur) { 0351 return nullptr; 0352 } 0353 cur->m_next = item->m_next; 0354 } 0355 if (item == m_last) { 0356 m_last = cur; 0357 } 0358 m_count--; 0359 return item; 0360 } 0361 0362 #endif // KCOMPTREENODE_P_H