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