1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QMLDOM_PATH_H
5#define QMLDOM_PATH_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include "qqmldomconstants_p.h"
19#include "qqmldomstringdumper_p.h"
20#include "qqmldom_global.h"
21
22#include <QtCore/QCoreApplication>
23#include <QtCore/QMetaEnum>
24#include <QtCore/QString>
25#include <QtCore/QStringView>
26#include <QtCore/QStringList>
27#include <QtCore/QVector>
28#include <QtCore/QDebug>
29
30#include <functional>
31#include <iterator>
32
33QT_BEGIN_NAMESPACE
34
35namespace QQmlJS {
36namespace Dom {
37
38class ErrorGroups;
39class ErrorMessage;
40class DomItem;
41class Path;
42
43using ErrorHandler = std::function<void(const ErrorMessage &)> ;
44
45using index_type = qint64;
46
47namespace PathEls {
48
49enum class Kind{
50 Empty,
51 Field,
52 Index,
53 Key,
54 Root,
55 Current,
56 Any,
57 Filter
58};
59
60class TestPaths;
61class Empty;
62class Field;
63class Index;
64class Key;
65class Root;
66class Current;
67class Any;
68class Filter;
69
70class Base {
71public:
72 QStringView stringView() const { return QStringView(); }
73 index_type index(index_type defaultValue = -1) const { return defaultValue; }
74 bool hasSquareBrackets() const { return false; }
75
76protected:
77 void dump(const Sink &sink, const QString &name, bool hasSquareBrackets) const;
78};
79
80class Empty final : public Base
81{
82public:
83 Empty() = default;
84 QString name() const { return QString(); }
85 bool checkName(QStringView s) const { return s.isEmpty(); }
86 void dump(const Sink &sink) const { Base::dump(sink, name: name(), hasSquareBrackets: hasSquareBrackets()); }
87};
88
89class Field final : public Base
90{
91public:
92 Field() = default;
93 Field(QStringView n): fieldName(n) {}
94 QString name() const { return fieldName.toString(); }
95 bool checkName(QStringView s) const { return s == fieldName; }
96 QStringView stringView() const { return fieldName; }
97 void dump(const Sink &sink) const { sink(fieldName); }
98
99 QStringView fieldName;
100};
101
102class Index final : public Base
103{
104public:
105 Index() = default;
106 Index(index_type i): indexValue(i) {}
107 QString name() const { return QString::number(indexValue); }
108 bool checkName(QStringView s) const { return s == name(); }
109 index_type index(index_type = -1) const { return indexValue; }
110 void dump(const Sink &sink) const { Base::dump(sink, name: name(), hasSquareBrackets: hasSquareBrackets()); }
111 bool hasSquareBrackets() const { return true; }
112
113 index_type indexValue = -1;
114};
115
116class Key final : public Base
117{
118public:
119 Key() = default;
120 Key(const QString &n) : keyValue(n) { }
121 QString name() const { return keyValue; }
122 bool checkName(QStringView s) const { return s == keyValue; }
123 QStringView stringView() const { return keyValue; }
124 void dump(const Sink &sink) const {
125 sink(u"[");
126 sinkEscaped(sink, s: keyValue);
127 sink(u"]");
128 }
129 bool hasSquareBrackets() const { return true; }
130
131 QString keyValue;
132};
133
134class Root final : public Base
135{
136public:
137 Root() = default;
138 Root(PathRoot r): contextKind(r), contextName() {}
139 Root(QStringView n) {
140 QMetaEnum metaEnum = QMetaEnum::fromType<PathRoot>();
141 contextKind = PathRoot::Other;
142 for (int i = 0; i < metaEnum.keyCount(); ++ i)
143 if (n.compare(other: QString::fromUtf8(utf8: metaEnum.key(index: i)), cs: Qt::CaseInsensitive) == 0)
144 contextKind = PathRoot(metaEnum.value(index: i));
145 if (contextKind == PathRoot::Other)
146 contextName = n;
147 }
148 QString name() const {
149 switch (contextKind) {
150 case PathRoot::Modules:
151 return QStringLiteral(u"$modules");
152 case PathRoot::Cpp:
153 return QStringLiteral(u"$cpp");
154 case PathRoot::Libs:
155 return QStringLiteral(u"$libs");
156 case PathRoot::Top:
157 return QStringLiteral(u"$top");
158 case PathRoot::Env:
159 return QStringLiteral(u"$env");
160 case PathRoot::Universe:
161 return QStringLiteral(u"$universe");
162 case PathRoot::Other:
163 return QString::fromUtf8(utf8: "$").append(s: contextName.toString());
164 }
165 Q_ASSERT(false && "Unexpected contextKind in name");
166 return QString();
167 }
168 bool checkName(QStringView s) const {
169 if (contextKind != PathRoot::Other)
170 return s.compare(other: name(), cs: Qt::CaseInsensitive) == 0;
171 return s.startsWith(c: QChar::fromLatin1(c: '$')) && s.mid(pos: 1) == contextName;
172 }
173 QStringView stringView() const { return contextName; }
174 void dump(const Sink &sink) const { sink(name()); }
175
176 PathRoot contextKind = PathRoot::Other;
177 QStringView contextName;
178};
179
180class Current final : public Base
181{
182public:
183 Current() = default;
184 Current(PathCurrent c): contextKind(c) {}
185 Current(QStringView n) {
186 QMetaEnum metaEnum = QMetaEnum::fromType<PathCurrent>();
187 contextKind = PathCurrent::Other;
188 for (int i = 0; i < metaEnum.keyCount(); ++ i)
189 if (n.compare(other: QString::fromUtf8(utf8: metaEnum.key(index: i)), cs: Qt::CaseInsensitive) == 0)
190 contextKind = PathCurrent(metaEnum.value(index: i));
191 if (contextKind == PathCurrent::Other)
192 contextName = n;
193 }
194 QString name() const {
195 switch (contextKind) {
196 case PathCurrent::Other:
197 return QString::fromUtf8(utf8: "@").append(s: contextName.toString());
198 case PathCurrent::Obj:
199 return QStringLiteral(u"@obj");
200 case PathCurrent::ObjChain:
201 return QStringLiteral(u"@objChain");
202 case PathCurrent::ScopeChain:
203 return QStringLiteral(u"@scopeChain");
204 case PathCurrent::Component:
205 return QStringLiteral(u"@component");
206 case PathCurrent::Module:
207 return QStringLiteral(u"@module");
208 case PathCurrent::Ids:
209 return QStringLiteral(u"@ids");
210 case PathCurrent::Types:
211 return QStringLiteral(u"@types");
212 case PathCurrent::LookupStrict:
213 return QStringLiteral(u"@lookupStrict");
214 case PathCurrent::LookupDynamic:
215 return QStringLiteral(u"@lookupDynamic");
216 case PathCurrent::Lookup:
217 return QStringLiteral(u"@lookup");
218 }
219 Q_ASSERT(false && "Unexpected contextKind in Current::name");
220 return QString();
221 }
222 bool checkName(QStringView s) const {
223 if (contextKind != PathCurrent::Other)
224 return s.compare(other: name(), cs: Qt::CaseInsensitive) == 0;
225 return s.startsWith(c: QChar::fromLatin1(c: '@')) && s.mid(pos: 1) == contextName;
226 }
227 QStringView stringView() const { return contextName; }
228 void dump(const Sink &sink) const { Base::dump(sink, name: name(), hasSquareBrackets: hasSquareBrackets()); }
229
230 PathCurrent contextKind = PathCurrent::Other;
231 QStringView contextName;
232};
233
234class Any final : public Base
235{
236public:
237 Any() = default;
238 QString name() const { return QLatin1String("*"); }
239 bool checkName(QStringView s) const { return s == u"*"; }
240 void dump(const Sink &sink) const { Base::dump(sink, name: name(), hasSquareBrackets: hasSquareBrackets()); }
241 bool hasSquareBrackets() const { return true; }
242};
243
244class QMLDOM_EXPORT Filter final : public Base
245{
246public:
247 Filter() = default;
248 Filter(const std::function<bool(const DomItem &)> &f,
249 QStringView filterDescription = u"<native code filter>");
250 QString name() const;
251 bool checkName(QStringView s) const;
252 QStringView stringView() const { return filterDescription; }
253 void dump(const Sink &sink) const { Base::dump(sink, name: name(), hasSquareBrackets: hasSquareBrackets()); }
254 bool hasSquareBrackets() const { return true; }
255
256 std::function<bool(const DomItem &)> filterFunction;
257 QStringView filterDescription;
258};
259
260class QMLDOM_EXPORT PathComponent {
261public:
262 PathComponent() = default;
263 PathComponent(const PathComponent &) = default;
264 PathComponent(PathComponent &&) = default;
265 PathComponent &operator=(const PathComponent &) = default;
266 PathComponent &operator=(PathComponent &&) = default;
267 ~PathComponent() = default;
268
269 Kind kind() const { return Kind(m_data.index()); }
270
271 QString name() const
272 {
273 return std::visit(visitor: [](auto &&d) { return d.name(); }, variants: m_data);
274 }
275
276 bool checkName(QStringView s) const
277 {
278 return std::visit(visitor: [s](auto &&d) { return d.checkName(s); }, variants: m_data);
279 }
280
281 QStringView stringView() const
282 {
283 return std::visit(visitor: [](auto &&d) { return d.stringView(); }, variants: m_data);
284 }
285
286 index_type index(index_type defaultValue=-1) const
287 {
288 return std::visit(visitor: [defaultValue](auto &&d) { return d.index(defaultValue); }, variants: m_data);
289 }
290
291 void dump(const Sink &sink) const
292 {
293 return std::visit(visitor: [sink](auto &&d) { return d.dump(sink); }, variants: m_data);
294 }
295
296 bool hasSquareBrackets() const
297 {
298 return std::visit(visitor: [](auto &&d) { return d.hasSquareBrackets(); }, variants: m_data);
299 }
300
301 const Empty *asEmpty() const { return std::get_if<Empty>(ptr: &m_data); }
302 const Field *asField() const { return std::get_if<Field>(ptr: &m_data); }
303 const Index *asIndex() const { return std::get_if<Index>(ptr: &m_data); }
304 const Key *asKey() const { return std::get_if<Key>(ptr: &m_data); }
305 const Root *asRoot() const { return std::get_if<Root>(ptr: &m_data); }
306 const Current *asCurrent() const { return std::get_if<Current>(ptr: &m_data); }
307 const Any *asAny() const { return std::get_if<Any>(ptr: &m_data); }
308 const Filter *asFilter() const { return std::get_if<Filter>(ptr: &m_data); }
309
310 static int cmp(const PathComponent &p1, const PathComponent &p2);
311
312 PathComponent(Empty &&o): m_data(std::move(o)) {}
313 PathComponent(Field &&o): m_data(std::move(o)) {}
314 PathComponent(Index &&o): m_data(std::move(o)) {}
315 PathComponent(Key &&o): m_data(std::move(o)) {}
316 PathComponent(Root &&o): m_data(std::move(o)) {}
317 PathComponent(Current &&o): m_data(std::move(o)) {}
318 PathComponent(Any &&o): m_data(std::move(o)) {}
319 PathComponent(Filter &&o): m_data(std::move(o)) {}
320
321private:
322 friend class QQmlJS::Dom::Path;
323 friend class QQmlJS::Dom::PathEls::TestPaths;
324
325 using Variant = std::variant<Empty, Field, Index, Key, Root, Current, Any, Filter>;
326
327 template<typename T, Kind K>
328 static constexpr bool variantTypeMatches
329 = std::is_same_v<std::variant_alternative_t<size_t(K), Variant>, T>;
330
331 static_assert(size_t(Kind::Empty) == 0);
332 static_assert(variantTypeMatches<Empty, Kind::Empty>);
333 static_assert(variantTypeMatches<Field, Kind::Field>);
334 static_assert(variantTypeMatches<Key, Kind::Key>);
335 static_assert(variantTypeMatches<Root, Kind::Root>);
336 static_assert(variantTypeMatches<Current, Kind::Current>);
337 static_assert(variantTypeMatches<Any, Kind::Any>);
338 static_assert(variantTypeMatches<Filter, Kind::Filter>);
339 static_assert(std::variant_size_v<Variant> == size_t(Kind::Filter) + 1);
340
341 Variant m_data;
342};
343
344inline bool operator==(const PathComponent& lhs, const PathComponent& rhs){ return PathComponent::cmp(p1: lhs,p2: rhs) == 0; }
345inline bool operator!=(const PathComponent& lhs, const PathComponent& rhs){ return PathComponent::cmp(p1: lhs,p2: rhs) != 0; }
346inline bool operator< (const PathComponent& lhs, const PathComponent& rhs){ return PathComponent::cmp(p1: lhs,p2: rhs) < 0; }
347inline bool operator> (const PathComponent& lhs, const PathComponent& rhs){ return PathComponent::cmp(p1: lhs,p2: rhs) > 0; }
348inline bool operator<=(const PathComponent& lhs, const PathComponent& rhs){ return PathComponent::cmp(p1: lhs,p2: rhs) <= 0; }
349inline bool operator>=(const PathComponent& lhs, const PathComponent& rhs){ return PathComponent::cmp(p1: lhs,p2: rhs) >= 0; }
350
351class PathData {
352public:
353 PathData(const QStringList &strData, const QVector<PathComponent> &components)
354 : strData(strData), components(components)
355 {}
356 PathData(const QStringList &strData, const QVector<PathComponent> &components,
357 const std::shared_ptr<PathData> &parent)
358 : strData(strData), components(components), parent(parent)
359 {}
360
361 QStringList strData;
362 QVector<PathComponent> components;
363 std::shared_ptr<PathData> parent;
364};
365
366} // namespace PathEls
367
368#define QMLDOM_USTRING(s) u##s
369#define QMLDOM_FIELD(name) inline constexpr const auto name = QMLDOM_USTRING(#name)
370/*!
371 \internal
372 In an ideal world, the Fields namespace would be an enum, not strings.
373 Use FieldType whenever you expect a static String from the Fields namespace instead of an
374 arbitrary QStringView.
375 */
376using FieldType = QStringView;
377// namespace, so it cam be reopened to add more entries
378namespace Fields{
379QMLDOM_FIELD(access);
380QMLDOM_FIELD(accessSemantics);
381QMLDOM_FIELD(allSources);
382QMLDOM_FIELD(alternative);
383QMLDOM_FIELD(annotations);
384QMLDOM_FIELD(arguments);
385QMLDOM_FIELD(astComments);
386QMLDOM_FIELD(astRelocatableDump);
387QMLDOM_FIELD(attachedType);
388QMLDOM_FIELD(attachedTypeName);
389QMLDOM_FIELD(autoExports);
390QMLDOM_FIELD(base);
391QMLDOM_FIELD(binaryExpression);
392QMLDOM_FIELD(bindable);
393QMLDOM_FIELD(bindingElement);
394QMLDOM_FIELD(bindingIdentifiers);
395QMLDOM_FIELD(bindingType);
396QMLDOM_FIELD(bindings);
397QMLDOM_FIELD(block);
398QMLDOM_FIELD(body);
399QMLDOM_FIELD(callee);
400QMLDOM_FIELD(canonicalFilePath);
401QMLDOM_FIELD(canonicalPath);
402QMLDOM_FIELD(caseBlock);
403QMLDOM_FIELD(caseClause);
404QMLDOM_FIELD(caseClauses);
405QMLDOM_FIELD(catchBlock);
406QMLDOM_FIELD(catchParameter);
407QMLDOM_FIELD(children);
408QMLDOM_FIELD(classNames);
409QMLDOM_FIELD(code);
410QMLDOM_FIELD(commentedElements);
411QMLDOM_FIELD(comments);
412QMLDOM_FIELD(components);
413QMLDOM_FIELD(condition);
414QMLDOM_FIELD(consequence);
415QMLDOM_FIELD(contents);
416QMLDOM_FIELD(contentsDate);
417QMLDOM_FIELD(cppType);
418QMLDOM_FIELD(currentExposedAt);
419QMLDOM_FIELD(currentIsValid);
420QMLDOM_FIELD(currentItem);
421QMLDOM_FIELD(currentRevision);
422QMLDOM_FIELD(declarations);
423QMLDOM_FIELD(defaultClause);
424QMLDOM_FIELD(defaultPropertyName);
425QMLDOM_FIELD(defaultValue);
426QMLDOM_FIELD(designerSupported);
427QMLDOM_FIELD(elLocation);
428QMLDOM_FIELD(elements);
429QMLDOM_FIELD(elementCanonicalPath);
430QMLDOM_FIELD(enumerations);
431QMLDOM_FIELD(errors);
432QMLDOM_FIELD(exportSource);
433QMLDOM_FIELD(exports);
434QMLDOM_FIELD(expr);
435QMLDOM_FIELD(expression);
436QMLDOM_FIELD(expressionType);
437QMLDOM_FIELD(extensionTypeName);
438QMLDOM_FIELD(fileLocationsTree);
439QMLDOM_FIELD(fileName);
440QMLDOM_FIELD(finallyBlock);
441QMLDOM_FIELD(regExpFlags);
442QMLDOM_FIELD(forStatement);
443QMLDOM_FIELD(fullRegion);
444QMLDOM_FIELD(get);
445QMLDOM_FIELD(globalScopeName);
446QMLDOM_FIELD(globalScopeWithName);
447QMLDOM_FIELD(hasCallback);
448QMLDOM_FIELD(hasCustomParser);
449QMLDOM_FIELD(idStr);
450QMLDOM_FIELD(identifier);
451QMLDOM_FIELD(ids);
452QMLDOM_FIELD(implicit);
453QMLDOM_FIELD(import);
454QMLDOM_FIELD(importId);
455QMLDOM_FIELD(importScope);
456QMLDOM_FIELD(importSources);
457QMLDOM_FIELD(imported);
458QMLDOM_FIELD(imports);
459QMLDOM_FIELD(inProgress);
460QMLDOM_FIELD(infoItem);
461QMLDOM_FIELD(inheritVersion);
462QMLDOM_FIELD(initializer);
463QMLDOM_FIELD(interfaceNames);
464QMLDOM_FIELD(isAlias);
465QMLDOM_FIELD(isComposite);
466QMLDOM_FIELD(isConstructor);
467QMLDOM_FIELD(isCreatable);
468QMLDOM_FIELD(isDefaultMember);
469QMLDOM_FIELD(isFinal);
470QMLDOM_FIELD(isInternal);
471QMLDOM_FIELD(isLatest);
472QMLDOM_FIELD(isList);
473QMLDOM_FIELD(isPointer);
474QMLDOM_FIELD(isReadonly);
475QMLDOM_FIELD(isRequired);
476QMLDOM_FIELD(isSignalHandler);
477QMLDOM_FIELD(isSingleton);
478QMLDOM_FIELD(isValid);
479QMLDOM_FIELD(jsFileWithPath);
480QMLDOM_FIELD(kind);
481QMLDOM_FIELD(lastRevision);
482QMLDOM_FIELD(label);
483QMLDOM_FIELD(lastValidRevision);
484QMLDOM_FIELD(left);
485QMLDOM_FIELD(loadInfo);
486QMLDOM_FIELD(loadOptions);
487QMLDOM_FIELD(loadPaths);
488QMLDOM_FIELD(loadsWithWork);
489QMLDOM_FIELD(localOffset);
490QMLDOM_FIELD(location);
491QMLDOM_FIELD(logicalPath);
492QMLDOM_FIELD(majorVersion);
493QMLDOM_FIELD(metaRevisions);
494QMLDOM_FIELD(methodType);
495QMLDOM_FIELD(methods);
496QMLDOM_FIELD(minorVersion);
497QMLDOM_FIELD(moduleIndex);
498QMLDOM_FIELD(moduleIndexWithUri);
499QMLDOM_FIELD(moduleScope);
500QMLDOM_FIELD(moreCaseClauses);
501QMLDOM_FIELD(nAllLoadedCallbacks);
502QMLDOM_FIELD(nCallbacks);
503QMLDOM_FIELD(nLoaded);
504QMLDOM_FIELD(nNotdone);
505QMLDOM_FIELD(name);
506QMLDOM_FIELD(nameIdentifiers);
507QMLDOM_FIELD(newlinesBefore);
508QMLDOM_FIELD(nextComponent);
509QMLDOM_FIELD(nextScope);
510QMLDOM_FIELD(notify);
511QMLDOM_FIELD(objects);
512QMLDOM_FIELD(onAttachedObject);
513QMLDOM_FIELD(operation);
514QMLDOM_FIELD(options);
515QMLDOM_FIELD(parameters);
516QMLDOM_FIELD(parent);
517QMLDOM_FIELD(parentObject);
518QMLDOM_FIELD(path);
519QMLDOM_FIELD(regExpPattern);
520QMLDOM_FIELD(plugins);
521QMLDOM_FIELD(postCode);
522QMLDOM_FIELD(postCommentLocations);
523QMLDOM_FIELD(postComments);
524QMLDOM_FIELD(pragma);
525QMLDOM_FIELD(pragmas);
526QMLDOM_FIELD(preCode);
527QMLDOM_FIELD(preCommentLocations);
528QMLDOM_FIELD(preComments);
529QMLDOM_FIELD(properties);
530QMLDOM_FIELD(propertyDef);
531QMLDOM_FIELD(propertyDefRef);
532QMLDOM_FIELD(propertyDefs);
533QMLDOM_FIELD(propertyInfos);
534QMLDOM_FIELD(propertyName);
535QMLDOM_FIELD(prototypes);
536QMLDOM_FIELD(qmlDirectoryWithPath);
537QMLDOM_FIELD(qmlFileWithPath);
538QMLDOM_FIELD(qmlFiles);
539QMLDOM_FIELD(qmldirFileWithPath);
540QMLDOM_FIELD(qmldirWithPath);
541QMLDOM_FIELD(qmltypesFileWithPath);
542QMLDOM_FIELD(qmltypesFiles);
543QMLDOM_FIELD(qualifiedImports);
544QMLDOM_FIELD(rawComment);
545QMLDOM_FIELD(read);
546QMLDOM_FIELD(referredObject);
547QMLDOM_FIELD(referredObjectPath);
548QMLDOM_FIELD(regionComments);
549QMLDOM_FIELD(regions);
550QMLDOM_FIELD(requestedAt);
551QMLDOM_FIELD(requestingUniverse);
552QMLDOM_FIELD(returnType);
553QMLDOM_FIELD(returnTypeName);
554QMLDOM_FIELD(right);
555QMLDOM_FIELD(rootComponent);
556QMLDOM_FIELD(scopeType);
557QMLDOM_FIELD(scriptElement);
558QMLDOM_FIELD(sources);
559QMLDOM_FIELD(statement);
560QMLDOM_FIELD(statements);
561QMLDOM_FIELD(status);
562QMLDOM_FIELD(stringValue);
563QMLDOM_FIELD(subComponents);
564QMLDOM_FIELD(subImports);
565QMLDOM_FIELD(subItems);
566QMLDOM_FIELD(symbol);
567QMLDOM_FIELD(symbols);
568QMLDOM_FIELD(target);
569QMLDOM_FIELD(targetPropertyName);
570QMLDOM_FIELD(templateLiteral);
571QMLDOM_FIELD(text);
572QMLDOM_FIELD(type);
573QMLDOM_FIELD(typeArgument);
574QMLDOM_FIELD(typeArgumentName);
575QMLDOM_FIELD(typeName);
576QMLDOM_FIELD(types);
577QMLDOM_FIELD(universe);
578QMLDOM_FIELD(updatedScriptExpressions);
579QMLDOM_FIELD(uri);
580QMLDOM_FIELD(uris);
581QMLDOM_FIELD(validExposedAt);
582QMLDOM_FIELD(validItem);
583QMLDOM_FIELD(value);
584QMLDOM_FIELD(valueTypeName);
585QMLDOM_FIELD(values);
586QMLDOM_FIELD(version);
587QMLDOM_FIELD(when);
588QMLDOM_FIELD(write);
589} // namespace Fields
590
591class Source;
592size_t qHash(const Path &, size_t);
593class PathIterator;
594// Define a iterator for it?
595// begin() can basically be itself, end() the empty path (zero length), iteration though dropFront()
596class QMLDOM_EXPORT Path{
597 Q_GADGET
598 Q_DECLARE_TR_FUNCTIONS(ErrorGroup);
599public:
600 using Kind = PathEls::Kind;
601 using Component = PathEls::PathComponent;
602 static ErrorGroups myErrors(); // use static consts and central registration instead?
603
604 Path() = default;
605 explicit Path(const PathEls::PathComponent &c) : m_endOffset(0), m_length(0)
606 {
607 *this = appendComponent(c);
608 }
609
610 int length() const { return m_length; }
611 Path operator[](int i) const;
612 explicit operator bool() const;
613
614 PathIterator begin() const;
615 PathIterator end() const;
616
617 PathRoot headRoot() const;
618 PathCurrent headCurrent() const;
619 Kind headKind() const;
620 QString headName() const;
621 bool checkHeadName(QStringView name) const;
622 index_type headIndex(index_type defaultValue=-1) const;
623 std::function<bool(const DomItem &)> headFilter() const;
624 Path head() const;
625 Path last() const;
626 Source split() const;
627
628 void dump(const Sink &sink) const;
629 QString toString() const;
630 Path dropFront(int n = 1) const;
631 Path dropTail(int n = 1) const;
632 Path mid(int offset, int length) const;
633 Path mid(int offset) const;
634 Path appendComponent(const PathEls::PathComponent &c);
635
636 // # Path construction
637 static Path fromString(const QString &s, const ErrorHandler &errorHandler = nullptr);
638 static Path fromString(QStringView s, const ErrorHandler &errorHandler = nullptr);
639 static Path Root(PathRoot r);
640 static Path Root(QStringView s=u"");
641 static Path Root(const QString &s);
642 static Path Index(index_type i);
643 static Path Field(QStringView s=u"");
644 static Path Field(const QString &s);
645 static Path Key(QStringView s=u"");
646 static Path Key(const QString &s);
647 static Path Current(PathCurrent c);
648 static Path Current(QStringView s=u"");
649 static Path Current(const QString &s);
650 static Path Empty();
651 // add
652 Path empty() const;
653 Path field(const QString &name) const;
654 Path field(QStringView name) const;
655 Path key(const QString &name) const;
656 Path key(QStringView name) const;
657 Path index(index_type i) const;
658 Path any() const;
659 Path filter(const std::function<bool(const DomItem &)> &, const QString &) const;
660 Path filter(const std::function<bool(const DomItem &)> &,
661 QStringView desc=u"<native code filter>") const;
662 Path current(PathCurrent s) const;
663 Path current(const QString &s) const;
664 Path current(QStringView s=u"") const;
665 Path path(const Path &toAdd, bool avoidToAddAsBase = false) const;
666
667 Path expandFront() const;
668 Path expandBack() const;
669
670 Path &operator++();
671 Path operator ++(int);
672
673 // iterator traits
674 using difference_type = long;
675 using value_type = Path;
676 using pointer = const Component*;
677 using reference = const Path&;
678 using iterator_category = std::forward_iterator_tag;
679
680 static int cmp(const Path &p1, const Path &p2);
681
682private:
683 const Component &component(int i) const;
684 explicit Path(quint16 endOffset, quint16 length,
685 const std::shared_ptr<PathEls::PathData> &data);
686 friend class QQmlJS::Dom::PathEls::TestPaths;
687 friend class FieldFilter;
688 friend size_t qHash(const Path &, size_t);
689
690 Path noEndOffset() const;
691
692 quint16 m_endOffset = 0;
693 quint16 m_length = 0;
694 std::shared_ptr<PathEls::PathData> m_data = {};
695};
696
697inline bool operator==(const Path &lhs, const Path &rhs)
698{
699 return lhs.length() == rhs.length() && Path::cmp(p1: lhs, p2: rhs) == 0;
700}
701inline bool operator!=(const Path &lhs, const Path &rhs)
702{
703 return lhs.length() != rhs.length() || Path::cmp(p1: lhs, p2: rhs) != 0;
704}
705inline bool operator<(const Path &lhs, const Path &rhs)
706{
707 return Path::cmp(p1: lhs, p2: rhs) < 0;
708}
709inline bool operator>(const Path &lhs, const Path &rhs)
710{
711 return Path::cmp(p1: lhs, p2: rhs) > 0;
712}
713inline bool operator<=(const Path &lhs, const Path &rhs)
714{
715 return Path::cmp(p1: lhs, p2: rhs) <= 0;
716}
717inline bool operator>=(const Path &lhs, const Path &rhs)
718{
719 return Path::cmp(p1: lhs, p2: rhs) >= 0;
720}
721
722class PathIterator {
723public:
724 Path currentEl;
725 Path operator *() const { return currentEl.head(); }
726 PathIterator operator ++() { currentEl = currentEl.dropFront(); return *this; }
727 PathIterator operator ++(int) { PathIterator res{.currentEl: currentEl}; currentEl = currentEl.dropFront(); return res; }
728 bool operator ==(const PathIterator &o) const { return currentEl == o.currentEl; }
729 bool operator !=(const PathIterator &o) const { return currentEl != o.currentEl; }
730};
731
732class Source {
733public:
734 Path pathToSource;
735 Path pathFromSource;
736};
737
738inline size_t qHash(const Path &path, size_t seed)
739{
740 const size_t bufSize = 256;
741 size_t buf[bufSize];
742 size_t *it = &buf[0];
743 *it++ = path.length();
744 if (path.length()>0) {
745 int iPath = path.length();
746 size_t maxPath = bufSize / 2 - 1;
747 size_t endPath = (size_t(iPath) > maxPath) ? maxPath - iPath : 0;
748 while (size_t(iPath) > endPath) {
749 Path p = path[--iPath];
750 Path::Kind k = p.headKind();
751 *it++ = size_t(k);
752 *it++ = qHash(key: p.component(i: 0).stringView(), seed)^size_t(p.headRoot())^size_t(p.headCurrent());
753 }
754 }
755
756 // TODO: Get rid of the reinterpret_cast.
757 // Rather hash the path components in a more structured way.
758 return qHash(key: QByteArray::fromRawData(data: reinterpret_cast<char *>(&buf[0]), size: (it - &buf[0])*sizeof(size_t)), seed);
759}
760
761inline QDebug operator<<(QDebug debug, const Path &p)
762{
763 debug << p.toString();
764 return debug;
765}
766
767} // end namespace Dom
768} // end namespace QQmlJS
769
770QT_END_NAMESPACE
771
772#endif // QMLDOM_PATH_H
773

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/qmldom/qqmldompath_p.h