diff -r 000000000000 -r 1918ee327afb src/xmlpatterns/data/qitem_p.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/xmlpatterns/data/qitem_p.h Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,546 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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_Item_H +#define Patternist_Item_H + +#include +#include +#include +#include + +#include +#include + +/** + * @file + * @short Due to strong interdependencies, this file contains the definitions for + * the classes Item, QXmlNodeModelIndex, QAbstractXmlNodeModel and AtomicValue. The implementations are + * in their respective source files. + */ + +/** + * @class QSharedData + * @short Qt's base class for reference counting. + */ + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +template class QList; +template class QVector; +template class QAbstractXmlForwardIterator; + +class QSourceLocation; +class QAbstractXmlReceiver; + +namespace QPatternist +{ + class DynamicContext; + class Item; + class ItemType; + class QObjectNodeModel; + template class EmptyIterator; + template class ListIterator; + + /** + * @short Base class for all classes representing atomic values. + * + * Instantiating AtomicValues sub classes from a value of somekind, + * for a certain type is done in three different ways: + * + * - The static factory fromLexical which available in most classes. This + * function attempts to create a value from a QString that is considered + * a lexical representation of the value. Thus, this function performs validation, takes + * care of whitespace facets, and everything else related to instantiating a value from + * a lexical representation. + * - The static factory function fromValue. This function exists for + * values where a C++ type exists which corresponds to the type's value space. + * - By using instances available in CommonValues. This is the preferred method + * since it uses existing singleton instances and thus saves memory. CommonValues + * should be used whenever possible, it can be thought as a collection of constant values. + * + * For types that does not distinguish the value space and lexical space, such as xs:string, + * only the fromValue() function exist, and fromLexical() is omitted. + * + * @ingroup Patternist_xdm + * @author Frans Englich + */ + class AtomicValue : public QSharedData + , public CppCastingHelper + { + public: + virtual ~AtomicValue(); + + /** + * A smart pointer wrapping AtomicValue instances. + */ + typedef QExplicitlySharedDataPointer Ptr; + + /** + * A list if smart pointers wrapping AtomicValue instances. + */ + typedef QList List; + + /** + * Determines whether this atomic value has an error. This is used + * for implementing casting. + * + * @returns always @c false + */ + virtual bool hasError() const; + + /** + * Always fails by issuing the type error ReportContext::FORG0006. Sub-classes + * whose represented type do allow EBV to be extracted from, must thus + * re-implement this function. + */ + virtual bool evaluateEBV(const QExplicitlySharedDataPointer &context) const; + + virtual QString stringValue() const = 0; + virtual ItemType::Ptr type() const = 0; + + /** + * Converts @p value to a QVariant. + */ + static QVariant toQt(const AtomicValue *const value); + + static inline QVariant toQt(const AtomicValue::Ptr &value) + { + return toQt(value.data()); + } + + static Item toXDM(const QVariant &value); + + static ItemType::Ptr qtToXDMType(const QXmlItem &item); + protected: + inline AtomicValue() + { + } + }; + + /** + * @short Represents an item in the XPath 2.0 Data Model. + * + * There exists two types of items: nodes and atomic values. + * + * The XQuery 1.0 and XPath 2.0 Data Model and XML Path Language (XPath) 2.0 specification + * makes a very strong distinction between a sequence of items and an atomized sequence. + * + * @ingroup Patternist_xdm + * @author Frans Englich + */ + class Item + { + friend class QT_PREPEND_NAMESPACE(QXmlItem); + + public: + /** + * A smart pointer wrapping an Item instance. + */ + typedef QAbstractXmlForwardIterator Iterator; + + /** + * A list of Item instances, each wrapped in a smart pointer. + */ + typedef QList List; + + /** + * A vector of Item instances, each wrapped in a smart pointer. + */ + typedef QVector Vector; + + typedef QPatternist::SingletonIterator SingletonIterator; + typedef QPatternist::EmptyIterator EmptyIterator; + + /** + * Default constructor. + */ + inline Item() + { + /* Note that this function should be equal to reset(). */ + + /* This is the area which atomicValue uses. Becauase we want as() + * to return null on null-constructed objects, we initialize it. */ + node.data = 0; + + /* This signals that we're not an atomic value. */ + node.model = 0; + } + + inline Item(const QXmlNodeModelIndex &n) : node(n.m_storage) + { + } + + inline Item(const Item &other) : node(other.node) + { + Q_ASSERT_X(sizeof(QXmlNodeModelIndex) >= sizeof(AtomicValue), Q_FUNC_INFO, + "Since we're only copying the node member, it must be the largest."); + if(isAtomicValue()) + atomicValue->ref.ref(); + } + + inline Item(const AtomicValue::Ptr &a) + { + if(a) + { + atomicValue = a.data(); + atomicValue->ref.ref(); + + /* Signal that we're housing an atomic value. */ + node.model = reinterpret_cast(~0); + } + else + node.model = 0; /* Like the default constructor. */ + } + + inline Item(const AtomicValue *const a) + { + /* Note, the implementation is a copy of the constructor above. */ + + if(a) + { + atomicValue = a; + atomicValue->ref.ref(); + + /* Signal that we're housing an atomic value. */ + node.model = reinterpret_cast(~0); + } + else + node.model = 0; /* Like the default constructor. */ + } + + inline ~Item() + { + if(isAtomicValue() && !atomicValue->ref.deref()) + delete atomicValue; + } + + inline Item &operator=(const Item &other) + { + Q_ASSERT_X(sizeof(QXmlNodeModelIndex) >= sizeof(AtomicValue *), Q_FUNC_INFO, + "If this doesn't hold, we won't copy all data."); + + if(other.isAtomicValue()) + other.atomicValue->ref.ref(); + + if(isAtomicValue()) + { + if(!atomicValue->ref.deref()) + delete atomicValue; + } + + node = other.node; + + return *this; + } + + template + inline TCastTarget *as() const + { +#if defined(Patternist_DEBUG) && !defined(Q_CC_XLC) +/* At least on aix-xlc-64, the compiler cries when it sees dynamic_cast. */ + Q_ASSERT_X(atomicValue == 0 || dynamic_cast(atomicValue), + Q_FUNC_INFO, + "The cast is invalid. This class does not inherit the cast target."); +#endif + return const_cast(static_cast(atomicValue)); + } + + /** + * @short Returns the string value of this Item. + * + * In the case of a node, it is the node value corresponding to + * the particular node type. For atomic values, it is equivalent + * to the value cast as xs:string. + * + * Conceptually, this functions corresponds to the dm:string-value accessor. + * + * @see XQuery 1.0 and + * XPath 2.0 Data Model, 5.13 string-value Accessor + * @returns the string value. + */ + inline QString stringValue() const + { + if(isAtomicValue()) + return atomicValue->stringValue(); + else + return asNode().stringValue(); + } + + /** + * @short Returns the typed value of this item. + * + * Conceptually, this functions corresponds to the dm:typed-value accessor. Here are + * examples of what the typed value of an Item is: + * + * - The typed value of an atomic value is always the atomic value itself. + * - A comment node has always a typed value of type @c xs:string + * - For attribute and element nodes, the typed value can be arbitrary. For example, an + * element can have a sequence of @c xs:dateTime instances. + * + * @returns the typed value of this item + * @see XQuery 1.0 and + * XPath 2.0 Data Model, 5.15 typed-value Accessor + */ + Item::Iterator::Ptr sequencedTypedValue() const; + + /** + * @short Determines whether this item is an atomic value, or a node. + * + * If this Item is @c null, @c false is returned. + * + * @see isNode() + * @returns @c true if it is an atomic value, otherwise @c false. + */ + inline bool isAtomicValue() const + { + /* Setting node.model to ~0, signals that it's an atomic value. */ + return node.model == reinterpret_cast(~0); + } + + /** + * @short Determines whether this item is an atomic value, or a node. + * + * If this Item is @c null, false is returned. + * + * @see isAtomicValue() + * @returns @c true if this item is a node, otherwise @c false. + */ + inline bool isNode() const + { + //return !isAtomicValue(); + return node.model && node.model != reinterpret_cast(~0); + } + + /** + * @short Returns the ItemType this Item is of. + * + * For example, if this Item is an XML node, more specifically a text node, + * text() is returned. That is, BuiltinTypes::text. However, if this + * Item is an atomic value of type xs:long that is what's returned, + * BuiltinTypes::xsLong. + * + * @returns the type of this Item. + */ + inline QExplicitlySharedDataPointer type() const + { + if(isAtomicValue()) + return atomicValue->type(); + else + return asNode().type(); + } + + inline const AtomicValue *asAtomicValue() const + { + Q_ASSERT(isAtomicValue()); + return atomicValue; + } + + inline const QXmlNodeModelIndex &asNode() const + { + Q_ASSERT_X(isNode() || isNull(), Q_FUNC_INFO, + "This item isn't a valid QXmlNodeModelIndex."); + Q_ASSERT_X(sizeof(QXmlNodeModelIndex) == sizeof(QPatternist::NodeIndexStorage), Q_FUNC_INFO, + "If this doesn't hold, something is wrong."); + + return reinterpret_cast(node); + } + + inline operator bool() const + { + return node.model; + } + + inline bool isNull() const + { + return !node.model; + } + + inline void reset() + { + /* Note that this function should be equal to the default + * constructor. */ + node.model = 0; + node.data = 0; + } + + static inline Item fromPublic(const QXmlItem &i) + { + const Item it(i.m_node); + if(it.isAtomicValue()) + it.asAtomicValue()->ref.ref(); + + return it; + } + + static inline QXmlItem toPublic(const Item &i) + { + return QXmlItem(i); + } + + private: + union + { + NodeIndexStorage node; + const AtomicValue *atomicValue; + }; + }; + + template + inline Item toItem(const QExplicitlySharedDataPointer atomicValue) + { + return Item(atomicValue.data()); + } + + /** + * This is an overload, provided for convenience. + * @relates QXmlNodeModelIndex + */ + static inline QString formatData(const QXmlNodeModelIndex node) + { + return node.stringValue(); // This can be improved a lot. + } +} + + inline QXmlName QXmlNodeModelIndex::name() const + { + return m_storage.model->name(*this); + } + + inline QXmlNodeModelIndex QXmlNodeModelIndex::root() const + { + return m_storage.model->root(*this); + } + + inline QXmlNodeModelIndex::Iterator::Ptr QXmlNodeModelIndex::iterate(const QXmlNodeModelIndex::Axis axis) const + { + return m_storage.model->iterate(*this, axis); + } + + inline QUrl QXmlNodeModelIndex::documentUri() const + { + return m_storage.model->documentUri(*this); + } + + inline QUrl QXmlNodeModelIndex::baseUri() const + { + return m_storage.model->baseUri(*this); + } + + inline QXmlNodeModelIndex::NodeKind QXmlNodeModelIndex::kind() const + { + return m_storage.model->kind(*this); + } + + inline bool QXmlNodeModelIndex::isDeepEqual(const QXmlNodeModelIndex &other) const + { + return m_storage.model->isDeepEqual(*this, other); + } + + inline QXmlNodeModelIndex::DocumentOrder QXmlNodeModelIndex::compareOrder(const QXmlNodeModelIndex &other) const + { + Q_ASSERT_X(model() == other.model(), Q_FUNC_INFO, "The API docs guarantees the two nodes are from the same model"); + return m_storage.model->compareOrder(*this, other); + } + + inline bool QXmlNodeModelIndex::is(const QXmlNodeModelIndex &other) const + { + return m_storage.model == other.m_storage.model && + m_storage.data == other.m_storage.data && + m_storage.additionalData == other.m_storage.additionalData; + } + + inline void QXmlNodeModelIndex::sendNamespaces(QAbstractXmlReceiver *const receiver) const + { + m_storage.model->sendNamespaces(*this, receiver); + } + + inline QVector QXmlNodeModelIndex::namespaceBindings() const + { + return m_storage.model->namespaceBindings(*this); + } + + inline QXmlName::NamespaceCode QXmlNodeModelIndex::namespaceForPrefix(const QXmlName::PrefixCode prefix) const + { + return m_storage.model->namespaceForPrefix(*this, prefix); + } + + inline QString QXmlNodeModelIndex::stringValue() const + { + return m_storage.model->stringValue(*this); + } + + inline QPatternist::ItemType::Ptr QXmlNodeModelIndex::type() const + { + return m_storage.model->type(*this); + } + + inline QExplicitlySharedDataPointer > QXmlNodeModelIndex::sequencedTypedValue() const + { + return m_storage.model->sequencedTypedValue(*this); + } + + inline QXmlItem::QXmlItem(const QPatternist::Item &i) : m_node(i.node) + { + if(isAtomicValue()) + m_atomicValue->ref.ref(); + } + +Q_DECLARE_TYPEINFO(QPatternist::Item::Iterator::Ptr, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(QPatternist::AtomicValue, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif