1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
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
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
168
        inline const QString &stringForLocalName(const QXmlName::LocalNameCode code) const
169
        {
170
            const QReadLocker l(&lock);
171
            return m_localNames.at(code);
172
        }
173
174
        inline const QString &stringForPrefix(const QXmlName::PrefixCode code) const
175
        {
176
            const QReadLocker l(&lock);
177
            return m_prefixes.at(code);
178
        }
179
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
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
202
        inline QXmlName::NamespaceCode allocateNamespace(const QString &uri)
203
        {
204
            const QWriteLocker l(&lock);
205
            return unlockedAllocateNamespace(uri);
206
        }
207
208
        inline QXmlName::LocalNameCode allocateLocalName(const QString &ln)
209
        {
210
            const QWriteLocker l(&lock);
211
            return unlockedAllocateLocalName(ln);
212
        }
213
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
     */
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
483
inline QXmlName::LocalNameCode QXmlName::localName() const
484
{
485
    return (m_qNameCode & LocalNameMask) >> LocalNameOffset;
486
}
487
488
inline QXmlName::PrefixCode QXmlName::prefix() const
489
{
490
    return (m_qNameCode & PrefixMask) >> PrefixOffset;
491
}
492
493
inline bool QXmlName::hasPrefix() const
494
{
495
    return prefix() != 0;
496
}
497
498
inline bool QXmlName::hasNamespace() const
499
{
500
    return namespaceURI() != 0;
501
}
502
503
inline QXmlName::NamespaceCode QXmlName::namespaceURI() const
504
{
505
    return (m_qNameCode & NamespaceMask) >> NamespaceOffset;
506
}
507
508
inline bool QXmlName::isLexicallyEqual(const QXmlName &other) const
509
{
510
    return (m_qNameCode & LexicalQNameMask) == (other.m_qNameCode & LexicalQNameMask);
511
}
512
513
inline void QXmlName::setPrefix(const PrefixCode c)
514
{
515
    m_qNameCode |= (c << PrefixOffset);
516
}
517
518
inline void QXmlName::setNamespaceURI(const NamespaceCode c)
519
{
520
    m_qNameCode |= (c << NamespaceOffset);
521
}
522
523
inline void QXmlName::setLocalName(const LocalNameCode c)
524
{
525
    m_qNameCode |= (c << LocalNameOffset);
526
}
527
528
inline QXmlName::Code QXmlName::code() const
529
{
530
    return m_qNameCode;
531
}
532
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