diff options
Diffstat (limited to 'src/xmlpatterns/utils/qnamepool_p.h')
-rw-r--r-- | src/xmlpatterns/utils/qnamepool_p.h | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/src/xmlpatterns/utils/qnamepool_p.h b/src/xmlpatterns/utils/qnamepool_p.h new file mode 100644 index 0000000..8d1beb9 --- /dev/null +++ b/src/xmlpatterns/utils/qnamepool_p.h @@ -0,0 +1,556 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_NamePool_H +#define Patternist_NamePool_H + +#include <QHash> +#include <QReadLocker> +#include <QReadWriteLock> +#include <QSharedData> +#include <QString> +#include <QVector> +#include <QXmlName> + +#include <QtXmlPatterns/private/qprimitives_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Store names such as namespace bindings and QNames and allows them to + * be referenced in efficient ways. + * + * Once a string have been inserted it stays there and cannot be removed. The + * only way to deallocate any string in the NamePool is to deallocate the + * NamePool itself, as a whole. + * + * This class is not only reentrant, it is thread-safe in all sense of the + * word. All functions of this class can be called concurrently. This is + * achieved by internal locking. + * + * @author Frans Englich <frans.englich@nokia.com> + * @todo Use QSubStrings, we can save very many heap allocations by that. + * @todo Check limits + */ + class Q_AUTOTEST_EXPORT NamePool : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<NamePool> Ptr; + + private: + friend class StandardNamespaces; + + enum + { + NoSuchValue = -1, + /** + * This must be identical to the amount of members in + * StandardNamespaces. + */ + StandardNamespaceCount = 11, + StandardPrefixCount = 9, + StandardLocalNameCount = 141 + }; + + QVector<QString> m_prefixes; + QVector<QString> m_namespaces; + QVector<QString> m_localNames; + + /** + * This hash contains no essential data, but speeds up + * finding a prefix in m_prefixes by mapping a prefix(the key) to + * the index into m_prefixes(which the value is). + * + * In other words, one can skip this variable at the cost of having + * to linearly loop over prefixes, in order to find the entry. + */ + QHash<QString, QXmlName::PrefixCode> m_prefixMapping; + + /** + * Same as m_prefixMapping but applies for URIs, and hence m_namespaces instead + * of m_prefixes. + */ + QHash<QString, QXmlName::NamespaceCode> m_namespaceMapping; + + QHash<QString, QXmlName::LocalNameCode> m_localNameMapping; + + enum DefaultCapacities + { + DefaultPrefixCapacity = 10, + DefaultURICapacity = DefaultPrefixCapacity, + /** + * It looks like it's quite common with 40-60 different local names per XML + * vocabulary. For background, see: + * + * - http://englich.wordpress.com/2007/01/11/representing-xml/ + * - http://englich.wordpress.com/2007/01/09/xmlstat/ + */ + DefaultLocalNameCapacity = 60 + }; + + public: + NamePool(); + + /** + * @short Allocates a namespace binding for @p prefix and @p uri. + * + * In the returned QXmlName, the local name is + * StandardLocalNames::empty, and QXmlName::prefix() and + * QXmlName::namespaceUri() returns @p prefix and @p uri, respectively. + * + * In older versions of this code, the class NamespaceBinding existed, + * but as part of having the public class QXmlName, it was dropped and + * a special interpretation/convention involving use of QXmlName was + * adopted. + */ + QXmlName allocateBinding(const QString &prefix, const QString &uri); + + QXmlName allocateQName(const QString &uri, const QString &localName, const QString &prefix = QString()); + + inline QXmlName allocateQName(const QXmlName::NamespaceCode uri, const QString &ln) + { + /* We don't lock here, but we do in allocateLocalName(). */ + return QXmlName(uri, allocateLocalName(ln)); + } + + inline const QString &stringForLocalName(const QXmlName::LocalNameCode code) const + { + const QReadLocker l(&lock); + return m_localNames.at(code); + } + + inline const QString &stringForPrefix(const QXmlName::PrefixCode code) const + { + const QReadLocker l(&lock); + return m_prefixes.at(code); + } + + inline const QString &stringForNamespace(const QXmlName::NamespaceCode code) const + { + const QReadLocker l(&lock); + return m_namespaces.at(code); + } + + QString displayName(const QXmlName qName) const; + + inline QString toLexical(const QXmlName qName) const + { + const QReadLocker l(&lock); + Q_ASSERT_X(!qName.isNull(), "", "It makes no sense to call toLexical() on a null name."); + + if(qName.hasPrefix()) + { + const QString &p = m_prefixes.at(qName.prefix()); + return p + QLatin1Char(':') + m_localNames.at(qName.localName()); + } + else + return m_localNames.at(qName.localName()); + } + + inline QXmlName::NamespaceCode allocateNamespace(const QString &uri) + { + const QWriteLocker l(&lock); + return unlockedAllocateNamespace(uri); + } + + inline QXmlName::LocalNameCode allocateLocalName(const QString &ln) + { + const QWriteLocker l(&lock); + return unlockedAllocateLocalName(ln); + } + + inline QXmlName::PrefixCode allocatePrefix(const QString &prefix) + { + const QWriteLocker l(&lock); + return unlockedAllocatePrefix(prefix); + } + + QString toClarkName(const QXmlName &name) const; + QXmlName fromClarkName(const QString &clarkName); + + private: + /** + * @note This function can not be called concurrently. + */ + QXmlName::NamespaceCode unlockedAllocateNamespace(const QString &uri); + + /** + * @note This function can not be called concurrently. + */ + QXmlName::LocalNameCode unlockedAllocateLocalName(const QString &ln); + + /** + * It's assumed that @p prefix is a valid @c NCName. + * + * @note This function can not be called concurrently. + */ + QXmlName::PrefixCode unlockedAllocatePrefix(const QString &prefix); + + Q_DISABLE_COPY(NamePool) + + /** + * @note This function can not be called concurrently. + */ + const QString &displayPrefix(const QXmlName::NamespaceCode nc) const; + + mutable QReadWriteLock lock; + }; + + /** + * @short Formats QName. + * + * @relates QXmlName + */ + static inline QString formatKeyword(const NamePool::Ptr &np, const QXmlName name) + { + return QLatin1String("<span class='XQuery-keyword'>") + + escape(np->displayName(name)) + + QLatin1String("</span>"); + } + + /** + * @see NamespaceResolver::Constants + */ + class StandardNamespaces + { + public: + enum ID + { + /** + * This does not mean empty in the sense of "empty", but + * in the sense of an empty string, "". + * + * Its value, zero, is significant. + */ + empty = 0, + fn, + local, + xml, + xmlns, + xs, + xsi, + xslt, + /** + * @short A special value that when passed as the namespace part + * to NamespaceResolver::addBinding(), undeclares the prefix. + * + * This is used by the namespace prolog declaration. + * + * A dummy value is added to the name pool. + */ + UndeclarePrefix, + + /** + * Signals that a node shouldn't inherit namespaces from its parent. Must be used + * with StandardPrefixes::StopNamespaceInheritance. + */ + StopNamespaceInheritance, + + /** + * A namespace used to identify for instance @c \#all template + * mode in XSL-T. + */ + InternalXSLT + }; + }; + + // const QString * a = &*qset.insert("foo"); + class StandardLocalNames + { + public: + enum + { + abs, + adjust_dateTime_to_timezone, + adjust_date_to_timezone, + adjust_time_to_timezone, + all, + arity, + avg, + base, + base_uri, + boolean, + ceiling, + codepoint_equal, + codepoints_to_string, + collection, + compare, + concat, + contains, + count, + current, + current_date, + current_dateTime, + current_time, + data, + dateTime, + day_from_date, + day_from_dateTime, + days_from_duration, + deep_equal, + Default, + default_collation, + distinct_values, + doc, + doc_available, + document, + document_uri, + element_available, + empty, + encode_for_uri, + ends_with, + error, + escape_html_uri, + exactly_one, + exists, + False, + floor, + function_available, + function_name, + generate_id, + generic_string_join, + hours_from_dateTime, + hours_from_duration, + hours_from_time, + id, + idref, + implicit_timezone, + index_of, + in_scope_prefixes, + insert_before, + iri_to_uri, + is_schema_aware, + key, + lang, + last, + local_name, + local_name_from_QName, + lower_case, + matches, + max, + min, + minutes_from_dateTime, + minutes_from_duration, + minutes_from_time, + month_from_date, + month_from_dateTime, + months_from_duration, + name, + namespace_uri, + namespace_uri_for_prefix, + namespace_uri_from_QName, + nilled, + node_name, + normalize_space, + normalize_unicode, + Not, + number, + one_or_more, + position, + prefix_from_QName, + product_name, + product_version, + property_name, + QName, + remove, + replace, + resolve_QName, + resolve_uri, + reverse, + root, + round, + round_half_to_even, + seconds_from_dateTime, + seconds_from_duration, + seconds_from_time, + sourceValue, + starts_with, + static_base_uri, + string, + string_join, + string_length, + string_to_codepoints, + subsequence, + substring, + substring_after, + substring_before, + sum, + supports_backwards_compatibility, + supports_serialization, + system_property, + timezone_from_date, + timezone_from_dateTime, + timezone_from_time, + tokenize, + trace, + translate, + True, + type_available, + unordered, + unparsed_entity_public_id, + unparsed_entity_uri, + unparsed_text, + unparsed_text_available, + upper_case, + vendor, + vendor_url, + version, + xml, + xmlns, + year_from_date, + year_from_dateTime, + years_from_duration, + zero_or_one + }; + }; + + class StandardPrefixes + { + public: + enum + { + /** + * This does not mean empty in the sense of "empty", but + * in the sense of an empty string, "". + * + * Its value, zero, is significant. + */ + empty = 0, + fn, + local, + xml, + xmlns, + xs, + xsi, + ns0, + StopNamespaceInheritance + }; + }; +} + +inline QXmlName::LocalNameCode QXmlName::localName() const +{ + return (m_qNameCode & LocalNameMask) >> LocalNameOffset; +} + +inline QXmlName::PrefixCode QXmlName::prefix() const +{ + return (m_qNameCode & PrefixMask) >> PrefixOffset; +} + +inline bool QXmlName::hasPrefix() const +{ + return prefix() != 0; +} + +inline bool QXmlName::hasNamespace() const +{ + return namespaceURI() != 0; +} + +inline QXmlName::NamespaceCode QXmlName::namespaceURI() const +{ + return (m_qNameCode & NamespaceMask) >> NamespaceOffset; +} + +inline bool QXmlName::isLexicallyEqual(const QXmlName &other) const +{ + return (m_qNameCode & LexicalQNameMask) == (other.m_qNameCode & LexicalQNameMask); +} + +inline void QXmlName::setPrefix(const PrefixCode c) +{ + m_qNameCode |= (c << PrefixOffset); +} + +inline void QXmlName::setNamespaceURI(const NamespaceCode c) +{ + m_qNameCode |= (c << NamespaceOffset); +} + +inline void QXmlName::setLocalName(const LocalNameCode c) +{ + m_qNameCode |= (c << LocalNameOffset); +} + +inline QXmlName::Code QXmlName::code() const +{ + return m_qNameCode; +} + +inline QXmlName::QXmlName(const NamespaceCode uri, + const LocalNameCode ln, + const PrefixCode p) : m_qNameCode((uri << NamespaceOffset) + + (ln << LocalNameOffset) + + (p << PrefixOffset)) +{ + /* We can't use members like prefix() here because if one of the + * values are to large, they would overflow into the others. */ + Q_ASSERT_X(p <= MaximumPrefixes, "", + qPrintable(QString::fromLatin1("NamePool prefix limits: max is %1, therefore %2 exceeds.").arg(MaximumPrefixes).arg(p))); + Q_ASSERT_X(ln <= MaximumLocalNames, "", + qPrintable(QString::fromLatin1("NamePool local name limits: max is %1, therefore %2 exceeds.").arg(MaximumLocalNames).arg(ln))); + Q_ASSERT_X(uri <= MaximumNamespaces, "", + qPrintable(QString::fromLatin1("NamePool namespace limits: max is %1, therefore %2 exceeds.").arg(MaximumNamespaces).arg(uri))); +} + + +Q_DECLARE_TYPEINFO(QPatternist::NamePool::Ptr, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif |