<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/dom/DOMException.hpp>
#include <xercesc/dom/DOMNode.hpp>

#include "DOMDocumentImpl.hpp"
#include "DOMNodeListImpl.hpp"
#include "DOMRangeImpl.hpp"
#include "DOMNodeIteratorImpl.hpp"
#include "DOMParentNode.hpp"
#include "DOMCasts.hpp"

XERCES_CPP_NAMESPACE_BEGIN

DOMParentNode::DOMParentNode(DOMDocument *ownerDoc)
    : fOwnerDocument(ownerDoc), fFirstChild(0), fChildNodeList(castToNode(this))
{
}

// This only makes a shallow copy, cloneChildren must also be called for a
// deep clone
DOMParentNode::DOMParentNode(const DOMParentNode &other)  :
    fChildNodeList(castToNode(this))
{
    this->fOwnerDocument = other.fOwnerDocument;

    // Need to break the association w/ original kids
    this->fFirstChild = 0;
}

void DOMParentNode::changed()
{
    DOMDocumentImpl *doc = (DOMDocumentImpl *)this->getOwnerDocument();
    doc->changed();
}

int DOMParentNode::changes() const
{
    DOMDocumentImpl *doc = (DOMDocumentImpl *)this->getOwnerDocument();
    return doc->changes();
}

DOMNode * DOMParentNode::appendChild(DOMNode *newChild)
{
    return insertBefore(newChild, 0);
}

void DOMParentNode::cloneChildren(const DOMNode *other) {
  //    for (DOMNode *mykid = other.getFirstChild();
    for (DOMNode *mykid = other->getFirstChild();
         mykid != 0;
         mykid = mykid->getNextSibling())
    {
        appendChild(mykid->cloneNode(true));
    }
}

DOMDocument * DOMParentNode::getOwnerDocument() const {
    return fOwnerDocument;
}

// unlike getOwnerDocument this is not overriden by DocumentImpl to return 0
DOMDocument * DOMParentNode::getDocument() const {
    return fOwnerDocument;
}

void DOMParentNode::setOwnerDocument(DOMDocument* doc) {
    fOwnerDocument = doc;
}

DOMNodeList *DOMParentNode::getChildNodes() const {
    const DOMNodeList *ret = &fChildNodeList;
    return (DOMNodeList *)ret;   // cast off const.
}

DOMNode * DOMParentNode::getFirstChild() const {
    return fFirstChild;
}

DOMNode * DOMParentNode::getLastChild() const
{
    return lastChild();
}

DOMNode * DOMParentNode::lastChild() const
{
    // last child is stored as the previous sibling of first child
    if (fFirstChild == 0) {
        return 0;
    }

    DOMChildNode *firstChild = castToChildImpl(fFirstChild);
    DOMNode *ret = firstChild->previousSibling;
    return ret;
}

//
//  revisit.  Is this function used anywhere?  I don't see it.
//
void DOMParentNode::lastChild(DOMNode *node) {
    // store lastChild as previous sibling of first child
    if (fFirstChild != 0) {
        DOMChildNode *firstChild = castToChildImpl(fFirstChild);
        firstChild->previousSibling = node;
    }
}

bool DOMParentNode::hasChildNodes() const
{
    return fFirstChild!=0;
}

DOMNode *DOMParentNode::insertBefore(DOMNode *newChild, DOMNode *refChild) {
    DOMNodeImpl *thisNodeImpl = castToNodeImpl(this);
    if (thisNodeImpl->isReadOnly())
        throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);

    if (newChild->getOwnerDocument() != fOwnerDocument)
        throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0);

    // Prevent cycles in the tree
    //only need to do this if the node has children
    if(newChild->hasChildNodes()) {
        bool treeSafe=true;
        for(DOMNode *a=castToNode(this)->getParentNode();
            treeSafe && a!=0;
            a=a->getParentNode())
            treeSafe=(newChild!=a);
        if(!treeSafe)
            throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);
    }

    // refChild must in fact be a child of this node (or 0)
    if (refChild!=0 && refChild->getParentNode() != castToNode(this))
        throw DOMException(DOMException::NOT_FOUND_ERR,0);

    if (newChild->getNodeType() == DOMNode::DOCUMENT_FRAGMENT_NODE)
    {
        // SLOW BUT SAFE: We could insert the whole subtree without
        // juggling so many next/previous pointers. (Wipe out the
        // parent's child-list, patch the parent pointers, set the
        // ends of the list.) But we know some subclasses have special-
        // case behavior they add to insertBefore(), so we don't risk it.
        // This approch also takes fewer bytecodes.

        // NOTE: If one of the children is not a legal child of this
        // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children
        // have been transferred. (Alternative behaviors would be to
        // reparent up to the first failure point or reparent all those
        // which are acceptable to the target node, neither of which is
        // as robust. PR-DOM-0818 isn't entirely clear on which it
        // recommends?????

        // No need to check kids for right-document; if they weren't,
        // they wouldn't be kids of that DocFrag.
        for(DOMNode *kid=newChild->getFirstChild(); // Prescan
              kid!=0;
              kid=kid->getNextSibling())
        {
            if (!DOMDocumentImpl::isKidOK(castToNode(this), kid))
              throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);
        }
        while(newChild->hasChildNodes())     // Move
            insertBefore(newChild->getFirstChild(),refChild);
    }

    else if (!DOMDocumentImpl::isKidOK(castToNode(this), newChild))
        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);

    else
    {
        DOMNode *oldparent=newChild->getParentNode();
        if(oldparent!=0)
            oldparent->removeChild(newChild);

        // Attach up
        castToNodeImpl(newChild)->fOwnerNode = castToNode(this);
        castToNodeImpl(newChild)->isOwned(true);

        // Attach before and after
        // Note: fFirstChild.previousSibling == lastChild!!
        if (fFirstChild == 0) {
            // this our first and only child
            fFirstChild = newChild;
            castToNodeImpl(newChild)->isFirstChild(true);
            // castToChildImpl(newChild)->previousSibling = newChild;
            DOMChildNode *newChild_ci = castToChildImpl(newChild);
            newChild_ci->previousSibling = newChild;
        } else {
            if (refChild == 0) {
                // this is an append
                DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling;
                castToChildImpl(lastChild)->nextSibling = newChild;
                castToChildImpl(newChild)->previousSibling = lastChild;
                castToChildImpl(fFirstChild)->previousSibling = newChild;
            } else {
                // this is an insert
                if (refChild == fFirstChild) {
                    // at the head of the list
                    castToNodeImpl(fFirstChild)->isFirstChild(false);
                    castToChildImpl(newChild)->nextSibling = fFirstChild;
                    castToChildImpl(newChild)->previousSibling = castToChildImpl(fFirstChild)->previousSibling;
                    castToChildImpl(fFirstChild)->previousSibling = newChild;
                    fFirstChild = newChild;
                    castToNodeImpl(newChild)->isFirstChild(true);
                } else {
                    // somewhere in the middle
                    DOMNode *prev = castToChildImpl(refChild)->previousSibling;
                    castToChildImpl(newChild)->nextSibling = refChild;
                    castToChildImpl(prev)->nextSibling = newChild;
                    castToChildImpl(refChild)->previousSibling = newChild;
                    castToChildImpl(newChild)->previousSibling = prev;
                }
            }
        }
    }

    changed();

    if (this->getOwnerDocument() != 0) {
        Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges();
        if ( ranges != 0) {
            XMLSize_t sz = ranges->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    ranges->elementAt(i)->updateRangeForInsertedNode(newChild);
                }
            }
        }
    }

    return newChild;
}

DOMNode *DOMParentNode::removeChild(DOMNode *oldChild)
{
    if (castToNodeImpl(this)->isReadOnly())
        throw DOMException(
        DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);

    if (oldChild == 0 || oldChild->getParentNode() != castToNode(this))
        throw DOMException(DOMException::NOT_FOUND_ERR, 0);

    if (this->getOwnerDocument() !=  0  ) {
        //notify iterators
        NodeIterators* nodeIterators = ((DOMDocumentImpl *)this->getOwnerDocument())->getNodeIterators();
        if (nodeIterators != 0) {
            XMLSize_t sz = nodeIterators->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    if (nodeIterators->elementAt(i) != 0)
                        nodeIterators->elementAt(i)->removeNode(oldChild);
                }
            }
        }

        //fix other ranges for change before deleting the node
        Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges();
        if (ranges != 0) {
            XMLSize_t sz = ranges->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    if (ranges->elementAt(i) != 0)
                        ranges->elementAt(i)->updateRangeForDeletedNode(oldChild);
                }
            }
        }
    }

    // Patch linked list around oldChild
    // Note: lastChild == fFirstChild->previousSibling
    if (oldChild == fFirstChild) {
        // removing first child
        castToNodeImpl(oldChild)->isFirstChild(false);
        fFirstChild = castToChildImpl(oldChild)->nextSibling;
        if (fFirstChild != 0) {
            castToNodeImpl(fFirstChild)->isFirstChild(true);
            castToChildImpl(fFirstChild)->previousSibling = castToChildImpl(oldChild)->previousSibling;
        }
    } else {
        DOMNode *prev = castToChildImpl(oldChild)->previousSibling;
        DOMNode *next = castToChildImpl(oldChild)->nextSibling;
        castToChildImpl(prev)->nextSibling = next;
        if (next == 0) {
            // removing last child
            castToChildImpl(fFirstChild)->previousSibling = prev;
        } else {
            // removing some other child in the middle
            castToChildImpl(next)->previousSibling = prev;
        }
    }

    // Remove oldChild's references to tree
    castToNodeImpl(oldChild)->fOwnerNode = fOwnerDocument;
    castToNodeImpl(oldChild)->isOwned(false);
    castToChildImpl(oldChild)->nextSibling = 0;
    castToChildImpl(oldChild)->previousSibling = 0;

    changed();

    return oldChild;
}

DOMNode *DOMParentNode::replaceChild(DOMNode *newChild, DOMNode *oldChild)
{
    insertBefore(newChild, oldChild);
    // changed() already done.
    return removeChild(oldChild);
}

//Introduced in DOM Level 2

void DOMParentNode::normalize()
{
    DOMNode *kid, *next;
    for (kid = fFirstChild; kid != 0; kid = next)
    {
        next = castToChildImpl(kid)->nextSibling;

        // If kid and next are both Text nodes (but _not_ CDATASection,
        // which is a subclass of Text), they can be merged.
        if (next != 0 &&
            kid->getNodeType() == DOMNode::TEXT_NODE   &&
            next->getNodeType() == DOMNode::TEXT_NODE )
        {
            ((DOMTextImpl *) kid)->appendData(((DOMTextImpl *) next)->getData());
            // revisit:
            //   should I release the removed node?
            //   not released in case user still referencing it externally
            removeChild(next);
            next = kid; // Don't advance; there might be another.
        }

        // Otherwise it might be an Element, which is handled recursively
        else
            if (kid->getNodeType() == DOMNode::ELEMENT_NODE)
                kid->normalize();
    }

    // changed() will have occurred when the removeChild() was done,
    // so does not have to be reissued.
}

//Introduced in DOM Level 3

bool DOMParentNode::isEqualNode(const DOMNode* arg) const
{
    if (arg && castToNodeImpl(this)->isSameNode(arg))
        return true;

    if (arg && castToNodeImpl(this)->isEqualNode(arg))
    {
        DOMNode *kid, *argKid;
        for (kid = fFirstChild, argKid = arg->getFirstChild();
             kid != 0 && argKid != 0;
             kid = kid->getNextSibling(), argKid = argKid->getNextSibling())
        {
            if (!kid->isEqualNode(argKid))
                return false;
        }
        return (kid || argKid) ? false : true;
    }
    return false;
}

//Non-standard extension
void DOMParentNode::release()
{
    DOMNode *kid, *next;
    for (kid = fFirstChild; kid != 0; kid = next)
    {
        next = castToChildImpl(kid)->nextSibling;

        // set is Owned false before releasing its child
        castToNodeImpl(kid)->isToBeReleased(true);
        kid->release();
    }
}

XERCES_CPP_NAMESPACE_END

<commit_msg>If insertBefore(A,A) is invoked, a crash would occur (bug# 26919)<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/dom/DOMException.hpp>
#include <xercesc/dom/DOMNode.hpp>

#include "DOMDocumentImpl.hpp"
#include "DOMNodeListImpl.hpp"
#include "DOMRangeImpl.hpp"
#include "DOMNodeIteratorImpl.hpp"
#include "DOMParentNode.hpp"
#include "DOMCasts.hpp"

XERCES_CPP_NAMESPACE_BEGIN

DOMParentNode::DOMParentNode(DOMDocument *ownerDoc)
    : fOwnerDocument(ownerDoc), fFirstChild(0), fChildNodeList(castToNode(this))
{
}

// This only makes a shallow copy, cloneChildren must also be called for a
// deep clone
DOMParentNode::DOMParentNode(const DOMParentNode &other)  :
    fChildNodeList(castToNode(this))
{
    this->fOwnerDocument = other.fOwnerDocument;

    // Need to break the association w/ original kids
    this->fFirstChild = 0;
}

void DOMParentNode::changed()
{
    DOMDocumentImpl *doc = (DOMDocumentImpl *)this->getOwnerDocument();
    doc->changed();
}

int DOMParentNode::changes() const
{
    DOMDocumentImpl *doc = (DOMDocumentImpl *)this->getOwnerDocument();
    return doc->changes();
}

DOMNode * DOMParentNode::appendChild(DOMNode *newChild)
{
    return insertBefore(newChild, 0);
}

void DOMParentNode::cloneChildren(const DOMNode *other) {
  //    for (DOMNode *mykid = other.getFirstChild();
    for (DOMNode *mykid = other->getFirstChild();
         mykid != 0;
         mykid = mykid->getNextSibling())
    {
        appendChild(mykid->cloneNode(true));
    }
}

DOMDocument * DOMParentNode::getOwnerDocument() const {
    return fOwnerDocument;
}

// unlike getOwnerDocument this is not overriden by DocumentImpl to return 0
DOMDocument * DOMParentNode::getDocument() const {
    return fOwnerDocument;
}

void DOMParentNode::setOwnerDocument(DOMDocument* doc) {
    fOwnerDocument = doc;
}

DOMNodeList *DOMParentNode::getChildNodes() const {
    const DOMNodeList *ret = &fChildNodeList;
    return (DOMNodeList *)ret;   // cast off const.
}

DOMNode * DOMParentNode::getFirstChild() const {
    return fFirstChild;
}

DOMNode * DOMParentNode::getLastChild() const
{
    return lastChild();
}

DOMNode * DOMParentNode::lastChild() const
{
    // last child is stored as the previous sibling of first child
    if (fFirstChild == 0) {
        return 0;
    }

    DOMChildNode *firstChild = castToChildImpl(fFirstChild);
    DOMNode *ret = firstChild->previousSibling;
    return ret;
}

//
//  revisit.  Is this function used anywhere?  I don't see it.
//
void DOMParentNode::lastChild(DOMNode *node) {
    // store lastChild as previous sibling of first child
    if (fFirstChild != 0) {
        DOMChildNode *firstChild = castToChildImpl(fFirstChild);
        firstChild->previousSibling = node;
    }
}

bool DOMParentNode::hasChildNodes() const
{
    return fFirstChild!=0;
}

DOMNode *DOMParentNode::insertBefore(DOMNode *newChild, DOMNode *refChild) {
    DOMNodeImpl *thisNodeImpl = castToNodeImpl(this);
    if (thisNodeImpl->isReadOnly())
        throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);

    if (newChild->getOwnerDocument() != fOwnerDocument)
        throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0);

    // Prevent cycles in the tree
    //only need to do this if the node has children
    if(newChild->hasChildNodes()) {
        bool treeSafe=true;
        for(DOMNode *a=castToNode(this)->getParentNode();
            treeSafe && a!=0;
            a=a->getParentNode())
            treeSafe=(newChild!=a);
        if(!treeSafe)
            throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);
    }

    // refChild must in fact be a child of this node (or 0)
    if (refChild!=0 && refChild->getParentNode() != castToNode(this))
        throw DOMException(DOMException::NOT_FOUND_ERR,0);

    // if the new node has to be placed before itself, we don't have to do anything
    // (even worse, we would crash if we continue, as we assume they are two distinct nodes)
    if (refChild!=0 && newChild->isSameNode(refChild))
        return newChild;

    if (newChild->getNodeType() == DOMNode::DOCUMENT_FRAGMENT_NODE)
    {
        // SLOW BUT SAFE: We could insert the whole subtree without
        // juggling so many next/previous pointers. (Wipe out the
        // parent's child-list, patch the parent pointers, set the
        // ends of the list.) But we know some subclasses have special-
        // case behavior they add to insertBefore(), so we don't risk it.
        // This approch also takes fewer bytecodes.

        // NOTE: If one of the children is not a legal child of this
        // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children
        // have been transferred. (Alternative behaviors would be to
        // reparent up to the first failure point or reparent all those
        // which are acceptable to the target node, neither of which is
        // as robust. PR-DOM-0818 isn't entirely clear on which it
        // recommends?????

        // No need to check kids for right-document; if they weren't,
        // they wouldn't be kids of that DocFrag.
        for(DOMNode *kid=newChild->getFirstChild(); // Prescan
              kid!=0;
              kid=kid->getNextSibling())
        {
            if (!DOMDocumentImpl::isKidOK(castToNode(this), kid))
              throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);
        }
        while(newChild->hasChildNodes())     // Move
            insertBefore(newChild->getFirstChild(),refChild);
    }

    else if (!DOMDocumentImpl::isKidOK(castToNode(this), newChild))
        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);

    else
    {
        DOMNode *oldparent=newChild->getParentNode();
        if(oldparent!=0)
            oldparent->removeChild(newChild);

        // Attach up
        castToNodeImpl(newChild)->fOwnerNode = castToNode(this);
        castToNodeImpl(newChild)->isOwned(true);

        // Attach before and after
        // Note: fFirstChild.previousSibling == lastChild!!
        if (fFirstChild == 0) {
            // this our first and only child
            fFirstChild = newChild;
            castToNodeImpl(newChild)->isFirstChild(true);
            // castToChildImpl(newChild)->previousSibling = newChild;
            DOMChildNode *newChild_ci = castToChildImpl(newChild);
            newChild_ci->previousSibling = newChild;
        } else {
            if (refChild == 0) {
                // this is an append
                DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling;
                castToChildImpl(lastChild)->nextSibling = newChild;
                castToChildImpl(newChild)->previousSibling = lastChild;
                castToChildImpl(fFirstChild)->previousSibling = newChild;
            } else {
                // this is an insert
                if (refChild == fFirstChild) {
                    // at the head of the list
                    castToNodeImpl(fFirstChild)->isFirstChild(false);
                    castToChildImpl(newChild)->nextSibling = fFirstChild;
                    castToChildImpl(newChild)->previousSibling = castToChildImpl(fFirstChild)->previousSibling;
                    castToChildImpl(fFirstChild)->previousSibling = newChild;
                    fFirstChild = newChild;
                    castToNodeImpl(newChild)->isFirstChild(true);
                } else {
                    // somewhere in the middle
                    DOMNode *prev = castToChildImpl(refChild)->previousSibling;
                    castToChildImpl(newChild)->nextSibling = refChild;
                    castToChildImpl(prev)->nextSibling = newChild;
                    castToChildImpl(refChild)->previousSibling = newChild;
                    castToChildImpl(newChild)->previousSibling = prev;
                }
            }
        }
    }

    changed();

    if (this->getOwnerDocument() != 0) {
        Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges();
        if ( ranges != 0) {
            XMLSize_t sz = ranges->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    ranges->elementAt(i)->updateRangeForInsertedNode(newChild);
                }
            }
        }
    }

    return newChild;
}

DOMNode *DOMParentNode::removeChild(DOMNode *oldChild)
{
    if (castToNodeImpl(this)->isReadOnly())
        throw DOMException(
        DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);

    if (oldChild == 0 || oldChild->getParentNode() != castToNode(this))
        throw DOMException(DOMException::NOT_FOUND_ERR, 0);

    if (this->getOwnerDocument() !=  0  ) {
        //notify iterators
        NodeIterators* nodeIterators = ((DOMDocumentImpl *)this->getOwnerDocument())->getNodeIterators();
        if (nodeIterators != 0) {
            XMLSize_t sz = nodeIterators->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    if (nodeIterators->elementAt(i) != 0)
                        nodeIterators->elementAt(i)->removeNode(oldChild);
                }
            }
        }

        //fix other ranges for change before deleting the node
        Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges();
        if (ranges != 0) {
            XMLSize_t sz = ranges->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    if (ranges->elementAt(i) != 0)
                        ranges->elementAt(i)->updateRangeForDeletedNode(oldChild);
                }
            }
        }
    }

    // Patch linked list around oldChild
    // Note: lastChild == fFirstChild->previousSibling
    if (oldChild == fFirstChild) {
        // removing first child
        castToNodeImpl(oldChild)->isFirstChild(false);
        fFirstChild = castToChildImpl(oldChild)->nextSibling;
        if (fFirstChild != 0) {
            castToNodeImpl(fFirstChild)->isFirstChild(true);
            castToChildImpl(fFirstChild)->previousSibling = castToChildImpl(oldChild)->previousSibling;
        }
    } else {
        DOMNode *prev = castToChildImpl(oldChild)->previousSibling;
        DOMNode *next = castToChildImpl(oldChild)->nextSibling;
        castToChildImpl(prev)->nextSibling = next;
        if (next == 0) {
            // removing last child
            castToChildImpl(fFirstChild)->previousSibling = prev;
        } else {
            // removing some other child in the middle
            castToChildImpl(next)->previousSibling = prev;
        }
    }

    // Remove oldChild's references to tree
    castToNodeImpl(oldChild)->fOwnerNode = fOwnerDocument;
    castToNodeImpl(oldChild)->isOwned(false);
    castToChildImpl(oldChild)->nextSibling = 0;
    castToChildImpl(oldChild)->previousSibling = 0;

    changed();

    return oldChild;
}

DOMNode *DOMParentNode::replaceChild(DOMNode *newChild, DOMNode *oldChild)
{
    insertBefore(newChild, oldChild);
    // changed() already done.
    return removeChild(oldChild);
}

//Introduced in DOM Level 2

void DOMParentNode::normalize()
{
    DOMNode *kid, *next;
    for (kid = fFirstChild; kid != 0; kid = next)
    {
        next = castToChildImpl(kid)->nextSibling;

        // If kid and next are both Text nodes (but _not_ CDATASection,
        // which is a subclass of Text), they can be merged.
        if (next != 0 &&
            kid->getNodeType() == DOMNode::TEXT_NODE   &&
            next->getNodeType() == DOMNode::TEXT_NODE )
        {
            ((DOMTextImpl *) kid)->appendData(((DOMTextImpl *) next)->getData());
            // revisit:
            //   should I release the removed node?
            //   not released in case user still referencing it externally
            removeChild(next);
            next = kid; // Don't advance; there might be another.
        }

        // Otherwise it might be an Element, which is handled recursively
        else
            if (kid->getNodeType() == DOMNode::ELEMENT_NODE)
                kid->normalize();
    }

    // changed() will have occurred when the removeChild() was done,
    // so does not have to be reissued.
}

//Introduced in DOM Level 3

bool DOMParentNode::isEqualNode(const DOMNode* arg) const
{
    if (arg && castToNodeImpl(this)->isSameNode(arg))
        return true;

    if (arg && castToNodeImpl(this)->isEqualNode(arg))
    {
        DOMNode *kid, *argKid;
        for (kid = fFirstChild, argKid = arg->getFirstChild();
             kid != 0 && argKid != 0;
             kid = kid->getNextSibling(), argKid = argKid->getNextSibling())
        {
            if (!kid->isEqualNode(argKid))
                return false;
        }
        return (kid || argKid) ? false : true;
    }
    return false;
}

//Non-standard extension
void DOMParentNode::release()
{
    DOMNode *kid, *next;
    for (kid = fFirstChild; kid != 0; kid = next)
    {
        next = castToChildImpl(kid)->nextSibling;

        // set is Owned false before releasing its child
        castToNodeImpl(kid)->isToBeReleased(true);
        kid->release();
    }
}

XERCES_CPP_NAMESPACE_END

<|endoftext|>


<commit_before>#include <w32api/xcmc.h>
#include "QueryServerConnection.h"
using Poco::Net::StreamSocket;
using Poco::Net::TCPServerConnection;

QueryServerConnection::QueryServerConnection(const StreamSocket &socket) : TCPServerConnection(socket) {}

void QueryServerConnection::run() {
    StreamSocket theSock = this->socket();
    std::string message = "Hello!\r\n";
    theSock.sendBytes(message.c_str(), sizeof(message));
    theSock.close();

    return;
}
<commit_msg>Remove windows API header<commit_after>#include "QueryServerConnection.h"
using Poco::Net::StreamSocket;
using Poco::Net::TCPServerConnection;

QueryServerConnection::QueryServerConnection(const StreamSocket &socket) : TCPServerConnection(socket) {}

void QueryServerConnection::run() {
    StreamSocket theSock = this->socket();
    std::string message = "Hello!\r\n";
    theSock.sendBytes(message.c_str(), sizeof(message));
    theSock.close();

    return;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/host/desktop_resizer.h"

#include "base/logging.h"

namespace remoting {

namespace {
class DesktopResizerMac : public DesktopResizer {
 public:
  DesktopResizerMac() {
  }

  virtual SkISize GetCurrentSize() OVERRIDE {
    NOTIMPLEMENTED();
    return SkISize::Make(0, 0);
  }

  virtual std::list<SkISize> GetSupportedSizes(
      const SkISize& preferred) OVERRIDE {
    NOTIMPLEMENTED();
    return std::list<SkISize>();
  }

  virtual void SetSize(const SkISize& size) OVERRIDE {
    NOTIMPLEMENTED();
  }

  virtual void RestoreSize(const SkISize& original) OVERRIDE {
    NOTIMPLEMENTED();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(DesktopResizerMac);
};
}  // namespace

scoped_ptr<DesktopResizer> DesktopResizer::Create() {
  return scoped_ptr<DesktopResizer>(new DesktopResizerMac);
}

}  // namespace remoting
<commit_msg>Mac resize-to-client implementation.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/host/desktop_resizer.h"

#include <Carbon/Carbon.h>

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"

namespace remoting {

class DesktopResizerMac : public DesktopResizer {
 public:
  DesktopResizerMac();

  // DesktopResizer interface
  virtual SkISize GetCurrentSize() OVERRIDE;
  virtual std::list<SkISize> GetSupportedSizes(
      const SkISize& preferred) OVERRIDE;
  virtual void SetSize(const SkISize& size) OVERRIDE;
  virtual void RestoreSize(const SkISize& original) OVERRIDE;

 private:
  // If there is a single display, get its id and return true, otherwise return
  // false. We don't currently support resize-to-client on multi-monitor Macs.
  bool GetSoleDisplayId(CGDirectDisplayID* display);

  void GetSupportedModesAndSizes(
      base::mac::ScopedCFTypeRef<CFMutableArrayRef>* modes,
      std::list<SkISize>* sizes);

  DISALLOW_COPY_AND_ASSIGN(DesktopResizerMac);
};

DesktopResizerMac::DesktopResizerMac() {}

SkISize DesktopResizerMac::GetCurrentSize() {
  CGDirectDisplayID display;
  if (!base::mac::IsOSSnowLeopard() && GetSoleDisplayId(&display)) {
    CGRect rect = CGDisplayBounds(display);
    return SkISize::Make(rect.size.width, rect.size.height);
  }
  return SkISize::Make(0, 0);
}

std::list<SkISize> DesktopResizerMac::GetSupportedSizes(
    const SkISize& preferred) {
  base::mac::ScopedCFTypeRef<CFMutableArrayRef> modes;
  std::list<SkISize> sizes;
  GetSupportedModesAndSizes(&modes, &sizes);
  return sizes;
}

void DesktopResizerMac::SetSize(const SkISize& size) {
  CGDirectDisplayID display;
  if (base::mac::IsOSSnowLeopard() || !GetSoleDisplayId(&display)) {
    return;
  }

  base::mac::ScopedCFTypeRef<CFMutableArrayRef> modes;
  std::list<SkISize> sizes;
  GetSupportedModesAndSizes(&modes, &sizes);
  // There may be many modes with the requested size. Pick the one with the
  // highest color depth.
  int index = 0, best_depth = 0;
  CGDisplayModeRef best_mode = NULL;
  for (std::list<SkISize>::const_iterator i = sizes.begin(); i != sizes.end();
       ++i, ++index) {
    if (*i == size) {
      CGDisplayModeRef mode = const_cast<CGDisplayModeRef>(
          static_cast<const CGDisplayMode*>(
              CFArrayGetValueAtIndex(modes, index)));
      int depth = 0;
      base::mac::ScopedCFTypeRef<CFStringRef> encoding(
          CGDisplayModeCopyPixelEncoding(mode));
      if (CFStringCompare(encoding, CFSTR(IO32BitDirectPixels),
                          kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
        depth = 32;
      } else if (CFStringCompare(
          encoding, CFSTR(IO16BitDirectPixels),
          kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
        depth = 16;
      } else if(CFStringCompare(
          encoding, CFSTR(IO8BitIndexedPixels),
          kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
        depth = 8;
      }
      if (depth > best_depth) {
        best_depth = depth;
        best_mode = mode;
      }
    }
  }
  if (best_mode) {
    LOG(INFO) << "Changing mode to " << best_mode << " (" << size.width()
              << "x" << size.height() << "x" << best_depth << ")";
    CGDisplaySetDisplayMode(display, best_mode, NULL);
  }
}

void DesktopResizerMac::RestoreSize(const SkISize& original) {
  SetSize(original);
}

void DesktopResizerMac::GetSupportedModesAndSizes(
    base::mac::ScopedCFTypeRef<CFMutableArrayRef>* modes,
    std::list<SkISize>* sizes) {
  CGDirectDisplayID display;
  if (GetSoleDisplayId(&display)) {
    base::mac::ScopedCFTypeRef<CFArrayRef>
        all_modes(CGDisplayCopyAllDisplayModes(display, NULL));
    modes->reset(CFArrayCreateMutableCopy(NULL, 0, all_modes));
    CFIndex count = CFArrayGetCount(*modes);
    for (CFIndex i = 0; i < count; ++i) {
      CGDisplayModeRef mode = const_cast<CGDisplayModeRef>(
          static_cast<const CGDisplayMode*>(
              CFArrayGetValueAtIndex(*modes, i)));
      if (CGDisplayModeIsUsableForDesktopGUI(mode)) {
        SkISize size = SkISize::Make(CGDisplayModeGetWidth(mode),
                                     CGDisplayModeGetHeight(mode));
        sizes->push_back(size);
      } else {
        CFArrayRemoveValueAtIndex(*modes, i);
        --count;
        --i;
      }
    }
  }
}

bool DesktopResizerMac::GetSoleDisplayId(CGDirectDisplayID* display) {
  // This code only supports a single display, but allocates space for two
  // to allow the multi-monitor case to be detected.
  CGDirectDisplayID displays[2];
  uint32_t num_displays;
  CGError err = CGGetActiveDisplayList(arraysize(displays),
                                       displays, &num_displays);
  if (err != kCGErrorSuccess || num_displays != 1) {
    return false;
  }
  *display = displays[0];
  return true;
}

scoped_ptr<DesktopResizer> DesktopResizer::Create() {
  return scoped_ptr<DesktopResizer>(new DesktopResizerMac);
}

}  // namespace remoting
<|endoftext|>


<commit_before>/*
 * Copyright © 2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <gtest/gtest.h>
#include "brw_vec4.h"
#include "brw_vs.h"

using namespace brw;

int ret = 0;

class copy_propagation_test : public ::testing::Test {
   virtual void SetUp();

public:
   struct brw_context *brw;
   struct gl_context *ctx;
   struct gl_shader_program *shader_prog;
   struct brw_vertex_program *vp;
   vec4_visitor *v;
};

class copy_propagation_vec4_visitor : public vec4_visitor
{
public:
   copy_propagation_vec4_visitor(struct brw_context *brw,
                                  struct gl_shader_program *shader_prog)
      : vec4_visitor(brw, NULL, NULL, NULL, NULL, shader_prog,
                     MESA_SHADER_VERTEX, NULL,
                     false, false /* no_spills */,
                     ST_NONE, ST_NONE, ST_NONE)
   {
   }

protected:
   virtual dst_reg *make_reg_for_system_value(ir_variable *ir)
   {
      assert(!"Not reached");
      return NULL;
   }

   virtual void setup_payload()
   {
      assert(!"Not reached");
   }

   virtual void emit_prolog()
   {
      assert(!"Not reached");
   }

   virtual void emit_program_code()
   {
      assert(!"Not reached");
   }

   virtual void emit_thread_end()
   {
      assert(!"Not reached");
   }

   virtual void emit_urb_write_header(int mrf)
   {
      assert(!"Not reached");
   }

   virtual vec4_instruction *emit_urb_write_opcode(bool complete)
   {
      assert(!"Not reached");
      unreachable();
   }
};

void copy_propagation_test::SetUp()
{
   brw = (struct brw_context *)calloc(1, sizeof(*brw));
   ctx = &brw->ctx;

   vp = ralloc(NULL, struct brw_vertex_program);

   shader_prog = ralloc(NULL, struct gl_shader_program);

   v = new copy_propagation_vec4_visitor(brw, shader_prog);

   _mesa_init_vertex_program(ctx, &vp->program, GL_VERTEX_SHADER, 0);

   brw->gen = 4;
}

static void
copy_propagation(vec4_visitor *v)
{
   bool print = false;

   if (print) {
      fprintf(stderr, "instructions before:\n");
      v->dump_instructions();
   }

   v->opt_copy_propagation();

   if (print) {
      fprintf(stderr, "instructions after:\n");
      v->dump_instructions();
   }
}

TEST_F(copy_propagation_test, test_swizzle_swizzle)
{
   dst_reg a = dst_reg(v, glsl_type::vec4_type);
   dst_reg b = dst_reg(v, glsl_type::vec4_type);
   dst_reg c = dst_reg(v, glsl_type::vec4_type);

   v->emit(v->ADD(a, src_reg(a), src_reg(a)));

   v->emit(v->MOV(b, swizzle(src_reg(a), BRW_SWIZZLE4(SWIZZLE_Y,
                                                      SWIZZLE_Z,
                                                      SWIZZLE_W,
                                                      SWIZZLE_X))));

   vec4_instruction *test_mov =
      v->MOV(c, swizzle(src_reg(b), BRW_SWIZZLE4(SWIZZLE_Y,
                                                 SWIZZLE_Z,
                                                 SWIZZLE_W,
                                                 SWIZZLE_X)));
   v->emit(test_mov);

   copy_propagation(v);

   EXPECT_EQ(test_mov->src[0].reg, a.reg);
   EXPECT_EQ(test_mov->src[0].swizzle, BRW_SWIZZLE4(SWIZZLE_Z,
                                                    SWIZZLE_W,
                                                    SWIZZLE_X,
                                                    SWIZZLE_Y));
}
<commit_msg>i965/vec4: unit test for copy propagation and writemask<commit_after>/*
 * Copyright © 2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <gtest/gtest.h>
#include "brw_vec4.h"
#include "brw_vs.h"

using namespace brw;

int ret = 0;

class copy_propagation_test : public ::testing::Test {
   virtual void SetUp();

public:
   struct brw_context *brw;
   struct gl_context *ctx;
   struct gl_shader_program *shader_prog;
   struct brw_vertex_program *vp;
   vec4_visitor *v;
};

class copy_propagation_vec4_visitor : public vec4_visitor
{
public:
   copy_propagation_vec4_visitor(struct brw_context *brw,
                                  struct gl_shader_program *shader_prog)
      : vec4_visitor(brw, NULL, NULL, NULL, NULL, shader_prog,
                     MESA_SHADER_VERTEX, NULL,
                     false, false /* no_spills */,
                     ST_NONE, ST_NONE, ST_NONE)
   {
   }

protected:
   virtual dst_reg *make_reg_for_system_value(ir_variable *ir)
   {
      assert(!"Not reached");
      return NULL;
   }

   virtual void setup_payload()
   {
      assert(!"Not reached");
   }

   virtual void emit_prolog()
   {
      assert(!"Not reached");
   }

   virtual void emit_program_code()
   {
      assert(!"Not reached");
   }

   virtual void emit_thread_end()
   {
      assert(!"Not reached");
   }

   virtual void emit_urb_write_header(int mrf)
   {
      assert(!"Not reached");
   }

   virtual vec4_instruction *emit_urb_write_opcode(bool complete)
   {
      assert(!"Not reached");
      unreachable();
   }
};

void copy_propagation_test::SetUp()
{
   brw = (struct brw_context *)calloc(1, sizeof(*brw));
   ctx = &brw->ctx;

   vp = ralloc(NULL, struct brw_vertex_program);

   shader_prog = ralloc(NULL, struct gl_shader_program);

   v = new copy_propagation_vec4_visitor(brw, shader_prog);

   _mesa_init_vertex_program(ctx, &vp->program, GL_VERTEX_SHADER, 0);

   brw->gen = 4;
}

static void
copy_propagation(vec4_visitor *v)
{
   bool print = false;

   if (print) {
      fprintf(stderr, "instructions before:\n");
      v->dump_instructions();
   }

   v->opt_copy_propagation();

   if (print) {
      fprintf(stderr, "instructions after:\n");
      v->dump_instructions();
   }
}

TEST_F(copy_propagation_test, test_swizzle_swizzle)
{
   dst_reg a = dst_reg(v, glsl_type::vec4_type);
   dst_reg b = dst_reg(v, glsl_type::vec4_type);
   dst_reg c = dst_reg(v, glsl_type::vec4_type);

   v->emit(v->ADD(a, src_reg(a), src_reg(a)));

   v->emit(v->MOV(b, swizzle(src_reg(a), BRW_SWIZZLE4(SWIZZLE_Y,
                                                      SWIZZLE_Z,
                                                      SWIZZLE_W,
                                                      SWIZZLE_X))));

   vec4_instruction *test_mov =
      v->MOV(c, swizzle(src_reg(b), BRW_SWIZZLE4(SWIZZLE_Y,
                                                 SWIZZLE_Z,
                                                 SWIZZLE_W,
                                                 SWIZZLE_X)));
   v->emit(test_mov);

   copy_propagation(v);

   EXPECT_EQ(test_mov->src[0].reg, a.reg);
   EXPECT_EQ(test_mov->src[0].swizzle, BRW_SWIZZLE4(SWIZZLE_Z,
                                                    SWIZZLE_W,
                                                    SWIZZLE_X,
                                                    SWIZZLE_Y));
}

TEST_F(copy_propagation_test, test_swizzle_writemask)
{
   dst_reg a = dst_reg(v, glsl_type::vec4_type);
   dst_reg b = dst_reg(v, glsl_type::vec4_type);
   dst_reg c = dst_reg(v, glsl_type::vec4_type);

   v->emit(v->MOV(b, swizzle(src_reg(a), BRW_SWIZZLE4(SWIZZLE_X,
                                                      SWIZZLE_Y,
                                                      SWIZZLE_X,
                                                      SWIZZLE_Z))));

   v->emit(v->MOV(writemask(a, WRITEMASK_XYZ), src_reg(1.0f)));

   vec4_instruction *test_mov =
      v->MOV(c, swizzle(src_reg(b), BRW_SWIZZLE4(SWIZZLE_W,
                                                 SWIZZLE_W,
                                                 SWIZZLE_W,
                                                 SWIZZLE_W)));
   v->emit(test_mov);

   copy_propagation(v);

   /* should not copy propagate */
   EXPECT_EQ(test_mov->src[0].reg, b.reg);
   EXPECT_EQ(test_mov->src[0].swizzle, BRW_SWIZZLE4(SWIZZLE_W,
                                                    SWIZZLE_W,
                                                    SWIZZLE_W,
                                                    SWIZZLE_W));
}
<|endoftext|>


<commit_before>// *****************************************************************************************************************************
// array_mat.hpp
// Linear Math Libraries
// Arbitrary-sized matrix class
// The matrix data is stored in column-major format. [j] returns column j,
// and [j][i] returns the item at column j, row i.
// Author(s): Cory Douthat
// Copyright (c) 2020 Cory Douthat, All Rights Reserved.
// *****************************************************************************************************************************

#ifndef ARRAY_MAT_HPP_
#define ARRAY_MAT_HPP_

#include <stdlib.h>
#define _USE_MATH_DEFINES	//For PI definition
#include <cmath>

#include "mat.hpp"

template <class T>
const T& min(const T& a, const T& b)
{
    return !(b < a) ? a : b;
}

template<class T>
const T& max(const T& a, const T& b)
{
    return (a < b) ? b : a;
}

template <typename T>
class ArrayMat
{
    // DATA
    T *v;
    unsigned int rows, cols;
public:
    // FUNCTIONS
    // Constructors and Destructor
    ArrayMat() : v(nullptr), rows(0), cols(0) {}
    ArrayMat(const ArrayMat<T>& b) { *this = b; }
    ArrayMat(unsigned int r, unsigned int c) { allocate(r, c); }
    ArrayMat(unsigned int r, unsigned int c, T s) { allocateValue(r, c, s); }
    ~ArrayMat() { clear(); }

    // Basic Operators
    const ArrayMat<T>& operator =(const ArrayMat<T>& b);    // Operator = (assignment)
    // Matrix Operators
    const ArrayMat<T>& operator +(const ArrayMat<T>& b)const;	// Operator +
    const ArrayMat<T>& operator -(const ArrayMat<T>& b)const;	// Operator -
    const ArrayMat<T>& operator *(const ArrayMat<T>& b)const;	// Operator *
    // Scalar Operators
    const ArrayMat<T>& operator *(T s)const;					// Operator * (scalar)
    const ArrayMat<T>& operator -()const { return *this * -1; }	// Operator - (scalar inverse)
    const ArrayMat<T>& operator *=(T s);                    // Operator *= (scalar)
    // Other Member Functions
    bool isEmpty()const;                                    // Check if empty (null pointer)
    void clear();                                           // Erase and set to null/zero
    void allocate(unsigned int r, unsigned int c);          // Allocate memory
    void allocateZero(unsigned int r, unsigned int c);      // Allocate memory (to zeros)
    void allocateValue(unsigned int r, unsigned int c, T s);// Allocate memory (to s value)
    T get(unsigned int col, unsigned int row)const;		    // Get element
    void set(unsigned int col, unsigned int row, T s);	    // Set element
    const T* getData()const { return v; };                   // Return const pointer to data
    unsigned int getCount()const { return rows * cols; }    // Return number of elements
    //T det()const;                                         // Determinant (square matrix)
    const ArrayMat<T>& transp()const;						// Transpose
    //ArrayMat<T> inv()const;							    // Inverse (square matrix)
    const ArrayMat<T>& invDiag()const;                      // Inverse (diagonal matrix)

    // Friend Functions
    template <typename sT> friend const ArrayMat<sT>& operator *(sT a, const ArrayMat<sT>& b);

    // Static Member Functions
    static T dotProduct(const ArrayMat<T>& a, const ArrayMat<T>& b);

    // Discrete Matrix (Mat2, Mat3, Mat4) Functions
#ifdef MAT_HPP_
    // Operators
    bool operator==(const Mat2<T> b)const;
    bool operator==(const Mat3<T> b)const;
    bool operator==(const Mat4<T> b)const;
    bool operator!=(const Mat2<T> b)const { return !(*this == b); }
    bool operator!=(const Mat3<T> b)const { return !(*this == b); }
    bool operator!=(const Mat4<T> b)const { return !(*this == b); }
#endif
};

// BASIC OPERATORS
// *****************************************************************************************************************************

template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator =(const ArrayMat<T>& b)
{
    // Check for empty b matrix
    if (b.isEmpty() || !(b.v))
    {
        clear();
    }
    else
    {
        // Check for non-null pointer or different dimensions
        if (!v || rows != b.rows || cols != b.cols)
        {
            clear();
            allocate(b.rows, b.cols);
        }

        memcpy(v, b.v, rows * cols * sizeof(T));
    }

    return *this;
}

// MATRIX OPERATORS
// *****************************************************************************************************************************

// + operator
// Will attempt to add matrices even if dimensions don't match
// Output will match dimensions of first addend (a)
template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator +(const ArrayMat<T>& b)const
{
    ArrayMat<T> *y = new ArrayMat<T>;
    unsigned int min_r, min_c;

    // Check for empty b matrix
    if (b.isEmpty())
        return *this;

    // Check for empty this matrix
    if (isEmpty())
        return b;

    y->allocate(rows, cols);
    min_r = min(rows, b.rows);
    min_c = min(cols, b.cols);

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            if (i < min_r && j < min_c)
                y->set(j, i, get(j, i) + b.get(j, i));
            else
                y->set(j, i, get(j, i));
        }
    }

    return *y;
}

// - operator
// Will attempt to subtract matrices even if dimensions don't match
// Output will match dimensions of first term (a)
template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator -(const ArrayMat<T>& b)const
{
    ArrayMat<T> *y = new ArrayMat<T>;
    unsigned int min_r, min_c;

    // Check for empty b matrix
    if (b.isEmpty())
        return *this;

    // Check for empty this matrix
    if (isEmpty())
        return -b;

    y->allocate(rows, cols);
    min_r = min(rows, b.rows);
    min_c = min(cols, b.cols);

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            if (i < min_r && j < min_c)
                y->set(j, i, get(j, i) - b.get(j, i));
            else
                y->set(j, i, get(j, i));
        }
    }

    return *y;
}

// operator *
// Only allowed when number of columns in a equals rows in b
// Will return empty matrix if these conditions aren't met
template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator *(const ArrayMat<T>& b)const
{
    ArrayMat<T> *y = new ArrayMat<T>;

    // Check conditions
    if (isEmpty() || b.isEmpty() || cols != b.rows)
        return *y;   // No operation, empty matrix

    y->allocateZero(rows, b.cols);

    for (unsigned int j = 0; j < y->cols; j++)			//j = cols of y/b
    {
        for (unsigned int i = 0; i < y->rows; i++)		//i = rows of y/a
        {
            for (unsigned int k = 0; k < y->cols; k++)	//k = sum index
            {
                y->set(j, i, y->get(j, i) + get(k, i) * b.get(j, k));
            }
        }
    }

    return *y;
}

// SCALAR OPERATORS
// *****************************************************************************************************************************

template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator *(T s)const
{
    ArrayMat<T> *y = new ArrayMat<T>;

    if (isEmpty())
        return *this;

    y->allocate(rows, cols);

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            y->set(j, i, get(j, i) * s);
        }
    }

    return *y;
}

template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator *=(T s)
{
    if (isEmpty())
        return *this;

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            set(j, i, get(j, i) * s);
        }
    }

    return *this;
}

// OTHER MEMBER FUNCTIONS
// *****************************************************************************************************************************

// Check if empty (null pointer)
template <typename T>
bool ArrayMat<T>::isEmpty()const
{
    if (rows == 0 || cols == 0)
        return true;
    else
        return false;
}

// Erase and set to null/zero
template <typename T>
void ArrayMat<T>::clear()
{
    if (v)
        delete[] v;

    v = nullptr;

    rows = cols = 0;
}

// Allocate memory
template <typename T>
void ArrayMat<T>::allocate(unsigned int r, unsigned int c)
{
    clear();

    rows = r;
    cols = c;

    v = new T[cols * rows];
}

// Allocate memory (to zeros)
template <typename T>
void ArrayMat<T>::allocateZero(unsigned int r, unsigned int c)
{
    allocate(r, c);
    memset(v, 0, rows * cols * sizeof(T));
}

// Allocate memory (to s value)
template <typename T>
void ArrayMat<T>::allocateValue(unsigned int r, unsigned int c, T s)
{
    allocate(r, c);
    memset(v, s, rows * cols * sizeof(T));
}

template <typename T>
T ArrayMat<T>::get(unsigned int col, unsigned int row)const
{
    if (!isEmpty() && col <= cols && row <= rows)
        return v[col * rows + row];
    else
        return T(NAN);
}

template <typename T>
void ArrayMat<T>::set(unsigned int col, unsigned int row, T s)
{

    if (!isEmpty() && col <= cols && row <= rows)
        v[col * rows + row] = s;
}

// Transpose
template <typename T>
const ArrayMat<T>& ArrayMat<T>::transp()const
{
    ArrayMat<T> *y = new ArrayMat<T>;

    if (isEmpty())
        return *y;

    y->allocate(cols, rows);

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            y->set(i, j, get(j, i));
        }
    }

    return *y;
}

// Inverse (diagonal matrix only)
template <typename T>
const ArrayMat<T>& ArrayMat<T>::invDiag()const
{
    ArrayMat<T> *y = new ArrayMat<T>;

    // Check for empty or non-square matrix
    if (isEmpty() || rows != cols)
        return *y;

    y->allocateZero(rows, cols);

    for (unsigned int i = 0; i < rows; i++)
    {
        y->set(i, i, T(1) / get(i, i));
    }

    return *y;
}

// FRIEND FUNCTIONS
// *****************************************************************************************************************************
template <typename sT>
const ArrayMat<sT>& operator *(sT a, const ArrayMat<sT>& b)
{
    return b * a;
}

// STATIC MEMBER FUNCTIONS
// *****************************************************************************************************************************
template <typename T>
T ArrayMat<T>::dotProduct(const ArrayMat<T>& a, const ArrayMat<T>& b)
{
    T temp = 0;

    if (a.cols == b.cols == 1 && a.rows == b.rows)
    {
        for (unsigned int i = 0; i < a.rows; i++)
        {
            temp += a.get(0, i) * b.get(0, i);
        }

        return temp;
    }
    else
        return NAN;
}

// DISCRETE MATRIX (MAT2, MAT3, MAT4) FUNCTIONS
// *****************************************************************************************************************************
#ifdef MAT_HPP_
// Operators

template <typename T>
bool ArrayMat<T>::operator==(const Mat2<T> b)const
{
    if (r != 2 || c != 2)
        return false;
    else if (memcmp(v, b.getData(), 2 * 2 * sizeof(T)))
        return false;
    else
        return true;
}

template <typename T>
bool ArrayMat<T>::operator==(const Mat3<T> b)const
{
    if (r != 3 || c != 3)
        return false;
    else if (memcmp(v, b.getData(), 3 * 3 * sizeof(T)))
        return false;
    else
        return true;
}

template <typename T>
bool ArrayMat<T>::operator==(const Mat4<T> b)const
{
    if (rows != 4 || cols != 4)
        return false;
    else if (memcmp(v, b.getData(), 4 * 4 * sizeof(T)))
        return false;
    else
        return true;
}
#endif

#endif
<commit_msg>Fix ArrayMat multiplication<commit_after>// *****************************************************************************************************************************
// array_mat.hpp
// Linear Math Libraries
// Arbitrary-sized matrix class
// The matrix data is stored in column-major format. [j] returns column j,
// and [j][i] returns the item at column j, row i.
// Author(s): Cory Douthat
// Copyright (c) 2020 Cory Douthat, All Rights Reserved.
// *****************************************************************************************************************************

#ifndef ARRAY_MAT_HPP_
#define ARRAY_MAT_HPP_

#include <stdlib.h>
#define _USE_MATH_DEFINES	//For PI definition
#include <cmath>

#include "mat.hpp"

template <class T>
const T& min(const T& a, const T& b)
{
    return !(b < a) ? a : b;
}

template<class T>
const T& max(const T& a, const T& b)
{
    return (a < b) ? b : a;
}

template <typename T>
class ArrayMat
{
    // DATA
    T *v;
    unsigned int rows, cols;
public:
    // FUNCTIONS
    // Constructors and Destructor
    ArrayMat() : v(nullptr), rows(0), cols(0) {}
    ArrayMat(const ArrayMat<T>& b) { *this = b; }
    ArrayMat(unsigned int r, unsigned int c) { allocate(r, c); }
    ArrayMat(unsigned int r, unsigned int c, T s) { allocateValue(r, c, s); }
    ~ArrayMat() { clear(); }

    // Basic Operators
    const ArrayMat<T>& operator =(const ArrayMat<T>& b);    // Operator = (assignment)
    // Matrix Operators
    const ArrayMat<T>& operator +(const ArrayMat<T>& b)const;	// Operator +
    const ArrayMat<T>& operator -(const ArrayMat<T>& b)const;	// Operator -
    const ArrayMat<T>& operator *(const ArrayMat<T>& b)const;	// Operator *
    // Scalar Operators
    const ArrayMat<T>& operator *(T s)const;					// Operator * (scalar)
    const ArrayMat<T>& operator -()const { return *this * -1; }	// Operator - (scalar inverse)
    const ArrayMat<T>& operator *=(T s);                    // Operator *= (scalar)
    // Other Member Functions
    bool isEmpty()const;                                    // Check if empty (null pointer)
    void clear();                                           // Erase and set to null/zero
    void allocate(unsigned int r, unsigned int c);          // Allocate memory
    void allocateZero(unsigned int r, unsigned int c);      // Allocate memory (to zeros)
    void allocateValue(unsigned int r, unsigned int c, T s);// Allocate memory (to s value)
    T get(unsigned int col, unsigned int row)const;		    // Get element
    void set(unsigned int col, unsigned int row, T s);	    // Set element
    const T* getData()const { return v; };                   // Return const pointer to data
    unsigned int getCount()const { return rows * cols; }    // Return number of elements
    //T det()const;                                         // Determinant (square matrix)
    const ArrayMat<T>& transp()const;						// Transpose
    //ArrayMat<T> inv()const;							    // Inverse (square matrix)
    const ArrayMat<T>& invDiag()const;                      // Inverse (diagonal matrix)

    // Friend Functions
    template <typename sT> friend const ArrayMat<sT>& operator *(sT a, const ArrayMat<sT>& b);

    // Static Member Functions
    static T dotProduct(const ArrayMat<T>& a, const ArrayMat<T>& b);

    // Discrete Matrix (Mat2, Mat3, Mat4) Functions
#ifdef MAT_HPP_
    // Operators
    bool operator==(const Mat2<T> b)const;
    bool operator==(const Mat3<T> b)const;
    bool operator==(const Mat4<T> b)const;
    bool operator!=(const Mat2<T> b)const { return !(*this == b); }
    bool operator!=(const Mat3<T> b)const { return !(*this == b); }
    bool operator!=(const Mat4<T> b)const { return !(*this == b); }
#endif
};

// BASIC OPERATORS
// *****************************************************************************************************************************

template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator =(const ArrayMat<T>& b)
{
    // Check for empty b matrix
    if (b.isEmpty() || !(b.v))
    {
        clear();
    }
    else
    {
        // Check for non-null pointer or different dimensions
        if (!v || rows != b.rows || cols != b.cols)
        {
            clear();
            allocate(b.rows, b.cols);
        }

        memcpy(v, b.v, rows * cols * sizeof(T));
    }

    return *this;
}

// MATRIX OPERATORS
// *****************************************************************************************************************************

// + operator
// Will attempt to add matrices even if dimensions don't match
// Output will match dimensions of first addend (a)
template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator +(const ArrayMat<T>& b)const
{
    ArrayMat<T> *y = new ArrayMat<T>;
    unsigned int min_r, min_c;

    // Check for empty b matrix
    if (b.isEmpty())
        return *this;

    // Check for empty this matrix
    if (isEmpty())
        return b;

    y->allocate(rows, cols);
    min_r = min(rows, b.rows);
    min_c = min(cols, b.cols);

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            if (i < min_r && j < min_c)
                y->set(j, i, get(j, i) + b.get(j, i));
            else
                y->set(j, i, get(j, i));
        }
    }

    return *y;
}

// - operator
// Will attempt to subtract matrices even if dimensions don't match
// Output will match dimensions of first term (a)
template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator -(const ArrayMat<T>& b)const
{
    ArrayMat<T> *y = new ArrayMat<T>;
    unsigned int min_r, min_c;

    // Check for empty b matrix
    if (b.isEmpty())
        return *this;

    // Check for empty this matrix
    if (isEmpty())
        return -b;

    y->allocate(rows, cols);
    min_r = min(rows, b.rows);
    min_c = min(cols, b.cols);

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            if (i < min_r && j < min_c)
                y->set(j, i, get(j, i) - b.get(j, i));
            else
                y->set(j, i, get(j, i));
        }
    }

    return *y;
}

// operator *
// Only allowed when number of columns in a equals rows in b
// Will return empty matrix if these conditions aren't met
template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator *(const ArrayMat<T>& b)const
{
    ArrayMat<T> *y = new ArrayMat<T>;

    // Check conditions
    if (isEmpty() || b.isEmpty() || cols != b.rows)
        return *y;   // No operation, empty matrix

    y->allocateZero(rows, b.cols);

    for (unsigned int j = 0; j < y->cols; j++)			//j = cols of y/b
    {
        for (unsigned int i = 0; i < y->rows; i++)		//i = rows of y/a
        {
            for (unsigned int k = 0; k < b.rows; k++)	//k = sum index
            {
                y->set(j, i, y->get(j, i) + get(k, i) * b.get(j, k));
            }
        }
    }

    return *y;
}

// SCALAR OPERATORS
// *****************************************************************************************************************************

template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator *(T s)const
{
    ArrayMat<T> *y = new ArrayMat<T>;

    if (isEmpty())
        return *this;

    y->allocate(rows, cols);

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            y->set(j, i, get(j, i) * s);
        }
    }

    return *y;
}

template <typename T>
const ArrayMat<T>& ArrayMat<T>::operator *=(T s)
{
    if (isEmpty())
        return *this;

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            set(j, i, get(j, i) * s);
        }
    }

    return *this;
}

// OTHER MEMBER FUNCTIONS
// *****************************************************************************************************************************

// Check if empty (null pointer)
template <typename T>
bool ArrayMat<T>::isEmpty()const
{
    if (rows == 0 || cols == 0)
        return true;
    else
        return false;
}

// Erase and set to null/zero
template <typename T>
void ArrayMat<T>::clear()
{
    if (v)
        delete[] v;

    v = nullptr;

    rows = cols = 0;
}

// Allocate memory
template <typename T>
void ArrayMat<T>::allocate(unsigned int r, unsigned int c)
{
    clear();

    rows = r;
    cols = c;

    v = new T[cols * rows];
}

// Allocate memory (to zeros)
template <typename T>
void ArrayMat<T>::allocateZero(unsigned int r, unsigned int c)
{
    allocate(r, c);
    memset(v, 0, rows * cols * sizeof(T));
}

// Allocate memory (to s value)
template <typename T>
void ArrayMat<T>::allocateValue(unsigned int r, unsigned int c, T s)
{
    allocate(r, c);
    memset(v, s, rows * cols * sizeof(T));
}

template <typename T>
T ArrayMat<T>::get(unsigned int col, unsigned int row)const
{
    if (!isEmpty() && col <= cols && row <= rows)
        return v[col * rows + row];
    else
        return T(NAN);
}

template <typename T>
void ArrayMat<T>::set(unsigned int col, unsigned int row, T s)
{

    if (!isEmpty() && col <= cols && row <= rows)
        v[col * rows + row] = s;
}

// Transpose
template <typename T>
const ArrayMat<T>& ArrayMat<T>::transp()const
{
    ArrayMat<T> *y = new ArrayMat<T>;

    if (isEmpty())
        return *y;

    y->allocate(cols, rows);

    for (unsigned int j = 0; j < cols; j++)
    {
        for (unsigned int i = 0; i < rows; i++)
        {
            y->set(i, j, get(j, i));
        }
    }

    return *y;
}

// Inverse (diagonal matrix only)
template <typename T>
const ArrayMat<T>& ArrayMat<T>::invDiag()const
{
    ArrayMat<T> *y = new ArrayMat<T>;

    // Check for empty or non-square matrix
    if (isEmpty() || rows != cols)
        return *y;

    y->allocateZero(rows, cols);

    for (unsigned int i = 0; i < rows; i++)
    {
        y->set(i, i, T(1) / get(i, i));
    }

    return *y;
}

// FRIEND FUNCTIONS
// *****************************************************************************************************************************
template <typename sT>
const ArrayMat<sT>& operator *(sT a, const ArrayMat<sT>& b)
{
    return b * a;
}

// STATIC MEMBER FUNCTIONS
// *****************************************************************************************************************************
template <typename T>
T ArrayMat<T>::dotProduct(const ArrayMat<T>& a, const ArrayMat<T>& b)
{
    T temp = 0;

    if (a.cols == b.cols == 1 && a.rows == b.rows)
    {
        for (unsigned int i = 0; i < a.rows; i++)
        {
            temp += a.get(0, i) * b.get(0, i);
        }

        return temp;
    }
    else
        return NAN;
}

// DISCRETE MATRIX (MAT2, MAT3, MAT4) FUNCTIONS
// *****************************************************************************************************************************
#ifdef MAT_HPP_
// Operators

template <typename T>
bool ArrayMat<T>::operator==(const Mat2<T> b)const
{
    if (r != 2 || c != 2)
        return false;
    else if (memcmp(v, b.getData(), 2 * 2 * sizeof(T)))
        return false;
    else
        return true;
}

template <typename T>
bool ArrayMat<T>::operator==(const Mat3<T> b)const
{
    if (r != 3 || c != 3)
        return false;
    else if (memcmp(v, b.getData(), 3 * 3 * sizeof(T)))
        return false;
    else
        return true;
}

template <typename T>
bool ArrayMat<T>::operator==(const Mat4<T> b)const
{
    if (rows != 4 || cols != 4)
        return false;
    else if (memcmp(v, b.getData(), 4 * 4 * sizeof(T)))
        return false;
    else
        return true;
}
#endif

#endif
<|endoftext|>


<commit_before>//===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
#include <fcntl.h>
#include <sys/stat.h>
#ifdef _WIN32
#include "lldb/Host/windows/windows.h"
#else
#include <sys/mman.h>
#endif

// C++ Includes
#include <cerrno>
#include <climits>

// Other libraries and framework includes
#include "llvm/Support/MathExtras.h"

// Project includes
#include "lldb/Core/DataBufferMemoryMap.h"
#include "lldb/Core/Error.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Core/Log.h"

using namespace lldb;
using namespace lldb_private;

//----------------------------------------------------------------------
// Default Constructor
//----------------------------------------------------------------------
DataBufferMemoryMap::DataBufferMemoryMap() :
    m_mmap_addr(nullptr),
    m_mmap_size(0),
    m_data(nullptr),
    m_size(0)
{
}

//----------------------------------------------------------------------
// Virtual destructor since this class inherits from a pure virtual
// base class.
//----------------------------------------------------------------------
DataBufferMemoryMap::~DataBufferMemoryMap()
{
    Clear();
}

//----------------------------------------------------------------------
// Return a pointer to the bytes owned by this object, or nullptr if
// the object contains no bytes.
//----------------------------------------------------------------------
uint8_t *
DataBufferMemoryMap::GetBytes()
{
    return m_data;
}

//----------------------------------------------------------------------
// Return a const pointer to the bytes owned by this object, or nullptr
// if the object contains no bytes.
//----------------------------------------------------------------------
const uint8_t *
DataBufferMemoryMap::GetBytes() const
{
    return m_data;
}

//----------------------------------------------------------------------
// Return the number of bytes this object currently contains.
//----------------------------------------------------------------------
uint64_t
DataBufferMemoryMap::GetByteSize() const
{
    return m_size;
}

//----------------------------------------------------------------------
// Reverts this object to an empty state by unmapping any memory
// that is currently owned.
//----------------------------------------------------------------------
void
DataBufferMemoryMap::Clear()
{
    if (m_mmap_addr != nullptr)
    {
        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
        if (log)
            log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", (void *)m_mmap_addr,
                        (uint64_t)m_mmap_size);
#ifdef _WIN32
        UnmapViewOfFile(m_mmap_addr);
#else
        ::munmap((void *)m_mmap_addr, m_mmap_size);
#endif
        m_mmap_addr = nullptr;
        m_mmap_size = 0;
        m_data = nullptr;
        m_size = 0;
    }
}

//----------------------------------------------------------------------
// Memory map "length" bytes from "file" starting "offset"
// bytes into the file. If "length" is set to SIZE_MAX, then
// map as many bytes as possible.
//
// Returns the number of bytes mapped starting from the requested
// offset.
//----------------------------------------------------------------------
size_t
DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
                                            lldb::offset_t offset,
                                            size_t length,
                                            bool writeable)
{
    if (filespec != nullptr)
    {
        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
        if (log)
        {
            log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i",
                        filespec->GetPath().c_str(),
                        offset,
                        (uint64_t)length,
                        writeable);
        }
        char path[PATH_MAX];
        if (filespec->GetPath(path, sizeof(path)))
        {
            uint32_t options = File::eOpenOptionRead;
            if (writeable)
                options |= File::eOpenOptionWrite;

            File file;
            Error error (file.Open(path, options));
            if (error.Success())
            {
                const bool fd_is_file = true;
                return MemoryMapFromFileDescriptor (file.GetDescriptor(), offset, length, writeable, fd_is_file);
            }
        }
    }
    // We should only get here if there was an error
    Clear();
    return 0;
}

#ifdef _WIN32
static size_t win32memmapalignment = 0;
void LoadWin32MemMapAlignment ()
{
  SYSTEM_INFO data;
  GetSystemInfo(&data);
  win32memmapalignment = data.dwAllocationGranularity;
}
#endif

//----------------------------------------------------------------------
// The file descriptor FD is assumed to already be opened as read only
// and the STAT structure is assumed to a valid pointer and already
// containing valid data from a call to stat().
//
// Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into
// the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes
// as possible.
//
// RETURNS
//  Number of bytes mapped starting from the requested offset.
//----------------------------------------------------------------------
size_t
DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
                                                  lldb::offset_t offset,
                                                  size_t length,
                                                  bool writeable,
                                                  bool fd_is_file)
{
    Clear();
    if (fd >= 0)
    {
        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE));
        if (log)
        {
            log->Printf("DataBufferMemoryMap::MemoryMapFromFileDescriptor(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
                        fd,
                        offset,
                        (uint64_t)length,
                        writeable,
                        fd_is_file);
        }
#ifdef _WIN32
        HANDLE handle = (HANDLE)_get_osfhandle(fd);
        DWORD file_size_low, file_size_high;
        file_size_low = GetFileSize(handle, &file_size_high);
        const lldb::offset_t file_size = llvm::Make_64(file_size_high, file_size_low);
        const lldb::offset_t max_bytes_available = file_size - offset;
        const size_t max_bytes_mappable = (size_t)std::min<lldb::offset_t>(SIZE_MAX, max_bytes_available);
        if (length == SIZE_MAX || length > max_bytes_mappable)
        {
            // Cap the length if too much data was requested
            length = max_bytes_mappable;
        }

        if (length > 0)
        {
            HANDLE fileMapping = CreateFileMapping(handle, nullptr, writeable ? PAGE_READWRITE : PAGE_READONLY, file_size_high, file_size_low, nullptr);
            if (fileMapping != nullptr)
            {
                if (win32memmapalignment == 0) LoadWin32MemMapAlignment();
                lldb::offset_t realoffset = offset;
                lldb::offset_t delta = 0;
                if (realoffset % win32memmapalignment != 0) {
                  realoffset = realoffset / win32memmapalignment * win32memmapalignment;
                  delta = offset - realoffset;
	            }

                LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta);
                m_mmap_addr = (uint8_t *)data;
                if (!data) {
                  Error error;
                  error.SetErrorToErrno ();
                } else {
                  m_data = m_mmap_addr + delta;
                  m_size = length;
                }
                CloseHandle(fileMapping);
            }
        }
#else
        struct stat stat;
        if (::fstat(fd, &stat) == 0)
        {
            if (S_ISREG(stat.st_mode) &&
                (stat.st_size > static_cast<off_t>(offset)))
            {
                const size_t max_bytes_available = stat.st_size - offset;
                if (length == SIZE_MAX)
                {
                    length = max_bytes_available;
                }
                else if (length > max_bytes_available)
                {
                    // Cap the length if too much data was requested
                    length = max_bytes_available;
                }

                if (length > 0)
                {
                    int prot = PROT_READ;
                    if (writeable)
                        prot |= PROT_WRITE;

                    int flags = MAP_PRIVATE;
                    if (fd_is_file)
                        flags |= MAP_FILE;

                    m_mmap_addr = (uint8_t *)::mmap(nullptr, length, prot, flags, fd, offset);
                    Error error;

                    if (m_mmap_addr == (void*)-1)
                    {
                        error.SetErrorToErrno ();
                        if (error.GetError() == EINVAL)
                        {
                            // We may still have a shot at memory mapping if we align things correctly
                            size_t page_offset = offset % HostInfo::GetPageSize();
                            if (page_offset != 0)
                            {
                                m_mmap_addr = (uint8_t *)::mmap(nullptr, length + page_offset, prot, flags, fd, offset - page_offset);
                                if (m_mmap_addr == (void*)-1)
                                {
                                    // Failed to map file
                                    m_mmap_addr = nullptr;
                                }
                                else if (m_mmap_addr != nullptr)
                                {
                                    // We recovered and were able to memory map
                                    // after we aligned things to page boundaries

                                    // Save the actual mmap'ed size
                                    m_mmap_size = length + page_offset;
                                    // Our data is at an offset into the mapped data
                                    m_data = m_mmap_addr + page_offset;
                                    // Our pretend size is the size that was requested
                                    m_size = length;
                                }
                            }
                        }
                        if (error.GetError() == ENOMEM)
                        {
                           error.SetErrorStringWithFormat("could not allocate %" PRId64 " bytes of memory to mmap in file", (uint64_t) length);
                        }
                    }
                    else
                    {
                        // We were able to map the requested data in one chunk
                        // where our mmap and actual data are the same.
                        m_mmap_size = length;
                        m_data = m_mmap_addr;
                        m_size = length;
                    }

                    if (log)
                    {
                        log->Printf(
                            "DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64
                            ", error = %s",
                            (void *)m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString());
                    }
                }
            }
        }
#endif
    }
    return GetByteSize ();
}
<commit_msg>Adopt mmap flags that allow mmap'ed memory to be less crash prone.<commit_after>//===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
#include <fcntl.h>
#include <sys/stat.h>
#ifdef _WIN32
#include "lldb/Host/windows/windows.h"
#else
#include <sys/mman.h>

#define MAP_EXTRA_HOST_READ_FLAGS 0

#if defined (__APPLE__)
//----------------------------------------------------------------------
// Newer versions of MacOSX have a flag that will allow us to read from
// binaries whose code signature is invalid without crashing by using
// the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media
// is mapped we can avoid crashing and return zeroes to any pages we try
// to read if the media becomes unavailable by using the
// MAP_RESILIENT_MEDIA flag.
//----------------------------------------------------------------------
#if defined(MAP_RESILIENT_CODESIGN)
    #undef MAP_EXTRA_HOST_READ_FLAGS
    #if defined(MAP_RESILIENT_MEDIA)
        #define MAP_EXTRA_HOST_READ_FLAGS MAP_RESILIENT_CODESIGN | MAP_RESILIENT_MEDIA
    #else
        #define MAP_EXTRA_HOST_READ_FLAGS MAP_RESILIENT_CODESIGN
    #endif
#endif // #if defined(MAP_RESILIENT_CODESIGN)
#endif // #if defined (__APPLE__)

#endif // #else #ifdef _WIN32
// C++ Includes
#include <cerrno>
#include <climits>

// Other libraries and framework includes
#include "llvm/Support/MathExtras.h"

// Project includes
#include "lldb/Core/DataBufferMemoryMap.h"
#include "lldb/Core/Error.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Core/Log.h"

using namespace lldb;
using namespace lldb_private;

//----------------------------------------------------------------------
// Default Constructor
//----------------------------------------------------------------------
DataBufferMemoryMap::DataBufferMemoryMap() :
    m_mmap_addr(nullptr),
    m_mmap_size(0),
    m_data(nullptr),
    m_size(0)
{
}

//----------------------------------------------------------------------
// Virtual destructor since this class inherits from a pure virtual
// base class.
//----------------------------------------------------------------------
DataBufferMemoryMap::~DataBufferMemoryMap()
{
    Clear();
}

//----------------------------------------------------------------------
// Return a pointer to the bytes owned by this object, or nullptr if
// the object contains no bytes.
//----------------------------------------------------------------------
uint8_t *
DataBufferMemoryMap::GetBytes()
{
    return m_data;
}

//----------------------------------------------------------------------
// Return a const pointer to the bytes owned by this object, or nullptr
// if the object contains no bytes.
//----------------------------------------------------------------------
const uint8_t *
DataBufferMemoryMap::GetBytes() const
{
    return m_data;
}

//----------------------------------------------------------------------
// Return the number of bytes this object currently contains.
//----------------------------------------------------------------------
uint64_t
DataBufferMemoryMap::GetByteSize() const
{
    return m_size;
}

//----------------------------------------------------------------------
// Reverts this object to an empty state by unmapping any memory
// that is currently owned.
//----------------------------------------------------------------------
void
DataBufferMemoryMap::Clear()
{
    if (m_mmap_addr != nullptr)
    {
        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
        if (log)
            log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", (void *)m_mmap_addr,
                        (uint64_t)m_mmap_size);
#ifdef _WIN32
        UnmapViewOfFile(m_mmap_addr);
#else
        ::munmap((void *)m_mmap_addr, m_mmap_size);
#endif
        m_mmap_addr = nullptr;
        m_mmap_size = 0;
        m_data = nullptr;
        m_size = 0;
    }
}

//----------------------------------------------------------------------
// Memory map "length" bytes from "file" starting "offset"
// bytes into the file. If "length" is set to SIZE_MAX, then
// map as many bytes as possible.
//
// Returns the number of bytes mapped starting from the requested
// offset.
//----------------------------------------------------------------------
size_t
DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
                                            lldb::offset_t offset,
                                            size_t length,
                                            bool writeable)
{
    if (filespec != nullptr)
    {
        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
        if (log)
        {
            log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i",
                        filespec->GetPath().c_str(),
                        offset,
                        (uint64_t)length,
                        writeable);
        }
        char path[PATH_MAX];
        if (filespec->GetPath(path, sizeof(path)))
        {
            uint32_t options = File::eOpenOptionRead;
            if (writeable)
                options |= File::eOpenOptionWrite;

            File file;
            Error error (file.Open(path, options));
            if (error.Success())
            {
                const bool fd_is_file = true;
                return MemoryMapFromFileDescriptor (file.GetDescriptor(), offset, length, writeable, fd_is_file);
            }
        }
    }
    // We should only get here if there was an error
    Clear();
    return 0;
}

#ifdef _WIN32
static size_t win32memmapalignment = 0;
void LoadWin32MemMapAlignment ()
{
  SYSTEM_INFO data;
  GetSystemInfo(&data);
  win32memmapalignment = data.dwAllocationGranularity;
}
#endif

//----------------------------------------------------------------------
// The file descriptor FD is assumed to already be opened as read only
// and the STAT structure is assumed to a valid pointer and already
// containing valid data from a call to stat().
//
// Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into
// the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes
// as possible.
//
// RETURNS
//  Number of bytes mapped starting from the requested offset.
//----------------------------------------------------------------------
size_t
DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
                                                  lldb::offset_t offset,
                                                  size_t length,
                                                  bool writeable,
                                                  bool fd_is_file)
{
    Clear();
    if (fd >= 0)
    {
        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE));
        if (log)
        {
            log->Printf("DataBufferMemoryMap::MemoryMapFromFileDescriptor(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
                        fd,
                        offset,
                        (uint64_t)length,
                        writeable,
                        fd_is_file);
        }
#ifdef _WIN32
        HANDLE handle = (HANDLE)_get_osfhandle(fd);
        DWORD file_size_low, file_size_high;
        file_size_low = GetFileSize(handle, &file_size_high);
        const lldb::offset_t file_size = llvm::Make_64(file_size_high, file_size_low);
        const lldb::offset_t max_bytes_available = file_size - offset;
        const size_t max_bytes_mappable = (size_t)std::min<lldb::offset_t>(SIZE_MAX, max_bytes_available);
        if (length == SIZE_MAX || length > max_bytes_mappable)
        {
            // Cap the length if too much data was requested
            length = max_bytes_mappable;
        }

        if (length > 0)
        {
            HANDLE fileMapping = CreateFileMapping(handle, nullptr, writeable ? PAGE_READWRITE : PAGE_READONLY, file_size_high, file_size_low, nullptr);
            if (fileMapping != nullptr)
            {
                if (win32memmapalignment == 0) LoadWin32MemMapAlignment();
                lldb::offset_t realoffset = offset;
                lldb::offset_t delta = 0;
                if (realoffset % win32memmapalignment != 0) {
                  realoffset = realoffset / win32memmapalignment * win32memmapalignment;
                  delta = offset - realoffset;
	            }

                LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta);
                m_mmap_addr = (uint8_t *)data;
                if (!data) {
                  Error error;
                  error.SetErrorToErrno ();
                } else {
                  m_data = m_mmap_addr + delta;
                  m_size = length;
                }
                CloseHandle(fileMapping);
            }
        }
#else
        struct stat stat;
        if (::fstat(fd, &stat) == 0)
        {
            if (S_ISREG(stat.st_mode) &&
                (stat.st_size > static_cast<off_t>(offset)))
            {
                const size_t max_bytes_available = stat.st_size - offset;
                if (length == SIZE_MAX)
                {
                    length = max_bytes_available;
                }
                else if (length > max_bytes_available)
                {
                    // Cap the length if too much data was requested
                    length = max_bytes_available;
                }

                if (length > 0)
                {
                    int prot = PROT_READ;
                    int flags = MAP_PRIVATE;
                    if (writeable)
                        prot |= PROT_WRITE;
                    else
                        flags |= MAP_EXTRA_HOST_READ_FLAGS;

                    if (fd_is_file)
                        flags |= MAP_FILE;

                    m_mmap_addr = (uint8_t *)::mmap(nullptr, length, prot, flags, fd, offset);
                    Error error;

                    if (m_mmap_addr == (void*)-1)
                    {
                        error.SetErrorToErrno ();
                        if (error.GetError() == EINVAL)
                        {
                            // We may still have a shot at memory mapping if we align things correctly
                            size_t page_offset = offset % HostInfo::GetPageSize();
                            if (page_offset != 0)
                            {
                                m_mmap_addr = (uint8_t *)::mmap(nullptr, length + page_offset, prot, flags, fd, offset - page_offset);
                                if (m_mmap_addr == (void*)-1)
                                {
                                    // Failed to map file
                                    m_mmap_addr = nullptr;
                                }
                                else if (m_mmap_addr != nullptr)
                                {
                                    // We recovered and were able to memory map
                                    // after we aligned things to page boundaries

                                    // Save the actual mmap'ed size
                                    m_mmap_size = length + page_offset;
                                    // Our data is at an offset into the mapped data
                                    m_data = m_mmap_addr + page_offset;
                                    // Our pretend size is the size that was requested
                                    m_size = length;
                                }
                            }
                        }
                        if (error.GetError() == ENOMEM)
                        {
                           error.SetErrorStringWithFormat("could not allocate %" PRId64 " bytes of memory to mmap in file", (uint64_t) length);
                        }
                    }
                    else
                    {
                        // We were able to map the requested data in one chunk
                        // where our mmap and actual data are the same.
                        m_mmap_size = length;
                        m_data = m_mmap_addr;
                        m_size = length;
                    }

                    if (log)
                    {
                        log->Printf(
                            "DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64
                            ", error = %s",
                            (void *)m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString());
                    }
                }
            }
        }
#endif
    }
    return GetByteSize ();
}
<|endoftext|>