1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40//
41// W A R N I N G
42// -------------
43//
44// This file is not part of the Qt API. It exists purely as an
45// implementation detail. This header file may change from version to
46// version without notice, or even be removed.
47//
48// We mean it.
49
50#ifndef Patternist_NamePool_H
51#define Patternist_NamePool_H
52
53#include <QHash>
54#include <QReadLocker>
55#include <QReadWriteLock>
56#include <QSharedData>
57#include <QString>
58#include <QVector>
59#include <QXmlName>
60
61#include <QtXmlPatterns/private/qprimitives_p.h>
62
63QT_BEGIN_NAMESPACE
64
65namespace QPatternist
66{
67 /**
68 * @short Store names such as namespace bindings and QNames and allows them to
69 * be referenced in efficient ways.
70 *
71 * Once a string have been inserted it stays there and cannot be removed. The
72 * only way to deallocate any string in the NamePool is to deallocate the
73 * NamePool itself, as a whole.
74 *
75 * This class is not only reentrant, it is thread-safe in all sense of the
76 * word. All functions of this class can be called concurrently. This is
77 * achieved by internal locking.
78 *
79 * @author Frans Englich <frans.englich@nokia.com>
80 * @todo Use QSubStrings, we can save very many heap allocations by that.
81 * @todo Check limits
82 */
83 class Q_AUTOTEST_EXPORT NamePool : public QSharedData
84 {
85 public:
86 typedef QExplicitlySharedDataPointer<NamePool> Ptr;
87
88 private:
89 friend class StandardNamespaces;
90
91 enum
92 {
93 NoSuchValue = -1,
94 /**
95 * This must be identical to the amount of members in
96 * StandardNamespaces.
97 */
98 StandardNamespaceCount = 11,
99 StandardPrefixCount = 9,
100 StandardLocalNameCount = 141
101 };
102
103 QVector<QString> m_prefixes;
104 QVector<QString> m_namespaces;
105 QVector<QString> m_localNames;
106
107 /**
108 * This hash contains no essential data, but speeds up
109 * finding a prefix in m_prefixes by mapping a prefix(the key) to
110 * the index into m_prefixes(which the value is).
111 *
112 * In other words, one can skip this variable at the cost of having
113 * to linearly loop over prefixes, in order to find the entry.
114 */
115 QHash<QString, QXmlName::PrefixCode> m_prefixMapping;
116
117 /**
118 * Same as m_prefixMapping but applies for URIs, and hence m_namespaces instead
119 * of m_prefixes.
120 */
121 QHash<QString, QXmlName::NamespaceCode> m_namespaceMapping;
122
123 QHash<QString, QXmlName::LocalNameCode> m_localNameMapping;
124
125 enum DefaultCapacities
126 {
127 DefaultPrefixCapacity = 10,
128 DefaultURICapacity = DefaultPrefixCapacity,
129 /**
130 * It looks like it's quite common with 40-60 different local names per XML
131 * vocabulary. For background, see:
132 *
133 * - http://englich.wordpress.com/2007/01/11/representing-xml/
134 * - http://englich.wordpress.com/2007/01/09/xmlstat/
135 */
136 DefaultLocalNameCapacity = 60
137 };
138
139 public:
140 NamePool();
141
142 /**
143 * @short Allocates a namespace binding for @p prefix and @p uri.
144 *
145 * In the returned QXmlName, the local name is
146 * StandardLocalNames::empty, and QXmlName::prefix() and
147 * QXmlName::namespaceUri() returns @p prefix and @p uri, respectively.
148 *
149 * In older versions of this code, the class NamespaceBinding existed,
150 * but as part of having the public class QXmlName, it was dropped and
151 * a special interpretation/convention involving use of QXmlName was
152 * adopted.
153 */
154 QXmlName allocateBinding(const QString &prefix, const QString &uri);
155
156 QXmlName allocateQName(const QString &uri, const QString &localName, const QString &prefix = QString());
157
158 inline QXmlName allocateQName(const QXmlName::NamespaceCode uri, const QString &ln)
159 {
160 /* We don't lock here, but we do in allocateLocalName(). */
161 return QXmlName(uri, allocateLocalName(ln));
162 }
163
164 inline const QString &stringForLocalName(const QXmlName::LocalNameCode code) const
165 {
166 const QReadLocker l(&lock);
167 return m_localNames.at(i: code);
168 }
169
170 inline const QString &stringForPrefix(const QXmlName::PrefixCode code) const
171 {
172 const QReadLocker l(&lock);
173 return m_prefixes.at(i: code);
174 }
175
176 inline const QString &stringForNamespace(const QXmlName::NamespaceCode code) const
177 {
178 const QReadLocker l(&lock);
179 return m_namespaces.at(i: code);
180 }
181
182 QString displayName(const QXmlName qName) const;
183
184 inline QString toLexical(const QXmlName qName) const
185 {
186 const QReadLocker l(&lock);
187 Q_ASSERT_X(!qName.isNull(), "", "It makes no sense to call toLexical() on a null name.");
188
189 if(qName.hasPrefix())
190 {
191 const QString &p = m_prefixes.at(i: qName.prefix());
192 return p + QLatin1Char(':') + m_localNames.at(i: qName.localName());
193 }
194 else
195 return m_localNames.at(i: qName.localName());
196 }
197
198 inline QXmlName::NamespaceCode allocateNamespace(const QString &uri)
199 {
200 const QWriteLocker l(&lock);
201 return unlockedAllocateNamespace(uri);
202 }
203
204 inline QXmlName::LocalNameCode allocateLocalName(const QString &ln)
205 {
206 const QWriteLocker l(&lock);
207 return unlockedAllocateLocalName(ln);
208 }
209
210 inline QXmlName::PrefixCode allocatePrefix(const QString &prefix)
211 {
212 const QWriteLocker l(&lock);
213 return unlockedAllocatePrefix(prefix);
214 }
215
216 QString toClarkName(const QXmlName &name) const;
217 QXmlName fromClarkName(const QString &clarkName);
218
219 private:
220 /**
221 * @note This function can not be called concurrently.
222 */
223 QXmlName::NamespaceCode unlockedAllocateNamespace(const QString &uri);
224
225 /**
226 * @note This function can not be called concurrently.
227 */
228 QXmlName::LocalNameCode unlockedAllocateLocalName(const QString &ln);
229
230 /**
231 * It's assumed that @p prefix is a valid @c NCName.
232 *
233 * @note This function can not be called concurrently.
234 */
235 QXmlName::PrefixCode unlockedAllocatePrefix(const QString &prefix);
236
237 Q_DISABLE_COPY(NamePool)
238
239 /**
240 * @note This function can not be called concurrently.
241 */
242 const QString &displayPrefix(const QXmlName::NamespaceCode nc) const;
243
244 mutable QReadWriteLock lock;
245 };
246
247 /**
248 * @short Formats QName.
249 *
250 * @relates QXmlName
251 */
252 static inline QString formatKeyword(const NamePool::Ptr &np, const QXmlName name)
253 {
254 return QLatin1String("<span class='XQuery-keyword'>") +
255 escape(input: np->displayName(qName: name)) +
256 QLatin1String("</span>");
257 }
258
259 /**
260 * @see NamespaceResolver::Constants
261 */
262 class StandardNamespaces
263 {
264 public:
265 enum ID
266 {
267 /**
268 * This does not mean empty in the sense of "empty", but
269 * in the sense of an empty string, "".
270 *
271 * Its value, zero, is significant.
272 */
273 empty = 0,
274 fn,
275 local,
276 xml,
277 xmlns,
278 xs,
279 xsi,
280 xslt,
281 /**
282 * @short A special value that when passed as the namespace part
283 * to NamespaceResolver::addBinding(), undeclares the prefix.
284 *
285 * This is used by the namespace prolog declaration.
286 *
287 * A dummy value is added to the name pool.
288 */
289 UndeclarePrefix,
290
291 /**
292 * Signals that a node shouldn't inherit namespaces from its parent. Must be used
293 * with StandardPrefixes::StopNamespaceInheritance.
294 */
295 StopNamespaceInheritance,
296
297 /**
298 * A namespace used to identify for instance @c \#all template
299 * mode in XSL-T.
300 */
301 InternalXSLT
302 };
303 };
304
305 // const QString * a = &*qset.insert("foo");
306 class StandardLocalNames
307 {
308 public:
309 enum
310 {
311 abs,
312 adjust_dateTime_to_timezone,
313 adjust_date_to_timezone,
314 adjust_time_to_timezone,
315 all,
316 arity,
317 avg,
318 base,
319 base_uri,
320 boolean,
321 ceiling,
322 codepoint_equal,
323 codepoints_to_string,
324 collection,
325 compare,
326 concat,
327 contains,
328 count,
329 current,
330 current_date,
331 current_dateTime,
332 current_time,
333 data,
334 dateTime,
335 day_from_date,
336 day_from_dateTime,
337 days_from_duration,
338 deep_equal,
339 Default,
340 default_collation,
341 distinct_values,
342 doc,
343 doc_available,
344 document,
345 document_uri,
346 element_available,
347 empty,
348 encode_for_uri,
349 ends_with,
350 error,
351 escape_html_uri,
352 exactly_one,
353 exists,
354 False,
355 floor,
356 function_available,
357 function_name,
358 generate_id,
359 generic_string_join,
360 hours_from_dateTime,
361 hours_from_duration,
362 hours_from_time,
363 id,
364 idref,
365 implicit_timezone,
366 index_of,
367 in_scope_prefixes,
368 insert_before,
369 iri_to_uri,
370 is_schema_aware,
371 key,
372 lang,
373 last,
374 local_name,
375 local_name_from_QName,
376 lower_case,
377 matches,
378 max,
379 min,
380 minutes_from_dateTime,
381 minutes_from_duration,
382 minutes_from_time,
383 month_from_date,
384 month_from_dateTime,
385 months_from_duration,
386 name,
387 namespace_uri,
388 namespace_uri_for_prefix,
389 namespace_uri_from_QName,
390 nilled,
391 node_name,
392 normalize_space,
393 normalize_unicode,
394 Not,
395 number,
396 one_or_more,
397 position,
398 prefix_from_QName,
399 product_name,
400 product_version,
401 property_name,
402 QName,
403 remove,
404 replace,
405 resolve_QName,
406 resolve_uri,
407 reverse,
408 root,
409 round,
410 round_half_to_even,
411 seconds_from_dateTime,
412 seconds_from_duration,
413 seconds_from_time,
414 sourceValue,
415 starts_with,
416 static_base_uri,
417 string,
418 string_join,
419 string_length,
420 string_to_codepoints,
421 subsequence,
422 substring,
423 substring_after,
424 substring_before,
425 sum,
426 supports_backwards_compatibility,
427 supports_serialization,
428 system_property,
429 timezone_from_date,
430 timezone_from_dateTime,
431 timezone_from_time,
432 tokenize,
433 trace,
434 translate,
435 True,
436 type_available,
437 unordered,
438 unparsed_entity_public_id,
439 unparsed_entity_uri,
440 unparsed_text,
441 unparsed_text_available,
442 upper_case,
443 vendor,
444 vendor_url,
445 version,
446 xml,
447 xmlns,
448 year_from_date,
449 year_from_dateTime,
450 years_from_duration,
451 zero_or_one
452 };
453 };
454
455 class StandardPrefixes
456 {
457 public:
458 enum
459 {
460 /**
461 * This does not mean empty in the sense of "empty", but
462 * in the sense of an empty string, "".
463 *
464 * Its value, zero, is significant.
465 */
466 empty = 0,
467 fn,
468 local,
469 xml,
470 xmlns,
471 xs,
472 xsi,
473 ns0,
474 StopNamespaceInheritance
475 };
476 };
477}
478
479inline QXmlName::LocalNameCode QXmlName::localName() const
480{
481 return (m_qNameCode & LocalNameMask) >> LocalNameOffset;
482}
483
484inline QXmlName::PrefixCode QXmlName::prefix() const
485{
486 return (m_qNameCode & PrefixMask) >> PrefixOffset;
487}
488
489inline bool QXmlName::hasPrefix() const
490{
491 return prefix() != 0;
492}
493
494inline bool QXmlName::hasNamespace() const
495{
496 return namespaceURI() != 0;
497}
498
499inline QXmlName::NamespaceCode QXmlName::namespaceURI() const
500{
501 return (m_qNameCode & NamespaceMask) >> NamespaceOffset;
502}
503
504inline bool QXmlName::isLexicallyEqual(const QXmlName &other) const
505{
506 return (m_qNameCode & LexicalQNameMask) == (other.m_qNameCode & LexicalQNameMask);
507}
508
509inline void QXmlName::setPrefix(const PrefixCode c)
510{
511 m_qNameCode |= (c << PrefixOffset);
512}
513
514inline void QXmlName::setNamespaceURI(const NamespaceCode c)
515{
516 m_qNameCode |= (c << NamespaceOffset);
517}
518
519inline void QXmlName::setLocalName(const LocalNameCode c)
520{
521 m_qNameCode |= (c << LocalNameOffset);
522}
523
524inline QXmlName::Code QXmlName::code() const
525{
526 return m_qNameCode;
527}
528
529inline QXmlName::QXmlName(const NamespaceCode uri,
530 const LocalNameCode ln,
531 const PrefixCode p) : m_qNameCode((uri << NamespaceOffset) +
532 (ln << LocalNameOffset) +
533 (p << PrefixOffset))
534{
535 /* We can't use members like prefix() here because if one of the
536 * values are to large, they would overflow into the others. */
537 Q_ASSERT_X(p <= MaximumPrefixes, "",
538 qPrintable(QString::fromLatin1("NamePool prefix limits: max is %1, therefore %2 exceeds.").arg(MaximumPrefixes).arg(p)));
539 Q_ASSERT_X(ln <= MaximumLocalNames, "",
540 qPrintable(QString::fromLatin1("NamePool local name limits: max is %1, therefore %2 exceeds.").arg(MaximumLocalNames).arg(ln)));
541 Q_ASSERT_X(uri <= MaximumNamespaces, "",
542 qPrintable(QString::fromLatin1("NamePool namespace limits: max is %1, therefore %2 exceeds.").arg(MaximumNamespaces).arg(uri)));
543}
544
545
546Q_DECLARE_TYPEINFO(QPatternist::NamePool::Ptr, Q_MOVABLE_TYPE);
547
548QT_END_NAMESPACE
549
550#endif
551

source code of qtxmlpatterns/src/xmlpatterns/utils/qnamepool_p.h