<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id$
 */

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

#include "DOMDocumentImpl.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(this)
{
}

// This only makes a shallow copy, cloneChildren must also be called for a
// deep clone
DOMParentNode::DOMParentNode(const DOMParentNode &other)  :
    fChildNodeList(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) {
    //not really in the specs, but better than nothing
    if(newChild==NULL)
        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager);

    DOMNodeImpl *thisNodeImpl = castToNodeImpl(this);
    if (thisNodeImpl->isReadOnly())
        throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMParentNodeMemoryManager);

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

    // 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, GetDOMParentNodeMemoryManager);
    }

    // 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, GetDOMParentNodeMemoryManager);

    // 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, GetDOMParentNodeMemoryManager);
        }
        while(newChild->hasChildNodes())     // Move
            insertBefore(newChild->getFirstChild(),refChild);
    }

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

    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) {
            unsigned int sz = ranges->size();
            if (sz != 0) {
                for (unsigned int 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, GetDOMParentNodeMemoryManager);

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

    if (this->getOwnerDocument() !=  0  ) {
        //notify iterators
        NodeIterators* nodeIterators = ((DOMDocumentImpl *)this->getOwnerDocument())->getNodeIterators();
        if (nodeIterators != 0) {
            unsigned int sz = nodeIterators->size();
            if (sz != 0) {
                for (unsigned int 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) {
            unsigned int sz = ranges->size();
            if (sz != 0) {
                for (unsigned int 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);
}

DOMNode * DOMParentNode::appendChildFast(DOMNode *newChild)
{
    // This function makes the following assumptions:
    //
    // - newChild != 0
    // - newChild is not read-only
    // - newChild is not a document fragment
    // - owner documents of this node and newChild are the same
    // - appending newChild to this node cannot result in a cycle
    // - DOMDocumentImpl::isKidOK (this, newChild) return true (that is,
    //   appending newChild to this node results in a valid structure)
    // - newChild->getParentNode() is 0
    // - there are no ranges set for this document
    //

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

    // Attach before and after
    // Note: fFirstChild.previousSibling == lastChild!!
    if (fFirstChild != 0)
    {
        DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling;
        castToChildImpl(lastChild)->nextSibling = newChild;
        castToChildImpl(newChild)->previousSibling = lastChild;
        castToChildImpl(fFirstChild)->previousSibling = newChild;
    }
    else
    {
        // 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;
    }

    changed();

    return newChild;
}

//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>When importing a DOMDocumentFragment, be sure to call the insertBefore function using the virtaul table, or derived classes will not be notified of each added node (i.e. DOMDocument will not store the pointer to the root element)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id$
 */

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

#include "DOMDocumentImpl.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(this)
{
}

// This only makes a shallow copy, cloneChildren must also be called for a
// deep clone
DOMParentNode::DOMParentNode(const DOMParentNode &other)  :
    fChildNodeList(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) {
    //not really in the specs, but better than nothing
    if(newChild==NULL)
        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager);

    DOMNodeImpl *thisNodeImpl = castToNodeImpl(this);
    if (thisNodeImpl->isReadOnly())
        throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMParentNodeMemoryManager);

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

    // 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, GetDOMParentNodeMemoryManager);
    }

    // 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, GetDOMParentNodeMemoryManager);

    // 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, GetDOMParentNodeMemoryManager);
        }
        while(newChild->hasChildNodes())     // Move
            castToNode(this)->insertBefore(newChild->getFirstChild(),refChild);
    }

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

    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) {
            unsigned int sz = ranges->size();
            if (sz != 0) {
                for (unsigned int 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, GetDOMParentNodeMemoryManager);

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

    if (this->getOwnerDocument() !=  0  ) {
        //notify iterators
        NodeIterators* nodeIterators = ((DOMDocumentImpl *)this->getOwnerDocument())->getNodeIterators();
        if (nodeIterators != 0) {
            unsigned int sz = nodeIterators->size();
            if (sz != 0) {
                for (unsigned int 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) {
            unsigned int sz = ranges->size();
            if (sz != 0) {
                for (unsigned int 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);
}

DOMNode * DOMParentNode::appendChildFast(DOMNode *newChild)
{
    // This function makes the following assumptions:
    //
    // - newChild != 0
    // - newChild is not read-only
    // - newChild is not a document fragment
    // - owner documents of this node and newChild are the same
    // - appending newChild to this node cannot result in a cycle
    // - DOMDocumentImpl::isKidOK (this, newChild) return true (that is,
    //   appending newChild to this node results in a valid structure)
    // - newChild->getParentNode() is 0
    // - there are no ranges set for this document
    //

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

    // Attach before and after
    // Note: fFirstChild.previousSibling == lastChild!!
    if (fFirstChild != 0)
    {
        DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling;
        castToChildImpl(lastChild)->nextSibling = newChild;
        castToChildImpl(newChild)->previousSibling = lastChild;
        castToChildImpl(fFirstChild)->previousSibling = newChild;
    }
    else
    {
        // 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;
    }

    changed();

    return newChild;
}

//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>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "WrapHelper.h"

#include "../player/BoostPython.h"
#include "../player/BitmapManager.h"

#include "../graphics/Bitmap.h"
#include "../graphics/BitmapLoader.h"
#include "../graphics/FilterResizeBilinear.h"

#include "../base/CubicSpline.h"
#include "../base/GeomHelper.h"

#include "../glm/gtx/vector_angle.hpp"

#include <vector>
#include <sstream>

using namespace boost::python;
using namespace std;
using namespace avg;

namespace bp = boost::python;

template<class POINT>
class_<POINT> export_point(const string& sName)
{
    return class_<POINT>(sName.c_str(), no_init)
        .def("__len__", &Vec2Helper::len)
        .def("__getitem__", &Vec2Helper::getItem)
        .def("__str__", &Vec2Helper::str)
        .def("__repr__", &Vec2Helper::repr)
        .def("__hash__", &Vec2Helper::getHash)
        .def("getNormalized", &Vec2Helper::safeGetNormalized)
        .def("getNorm", &Vec2Helper::getNorm)
        .def("getRotated", &getRotated)
        .def("getRotated", &getRotatedPivot)
        .def(self == self)
        .def(self != self)
        .def(-self)
        .def(self + self)
        .def(self - self)
        .def(float() * self)
        .def(self * float())
        .def(self / float())
        .def("isInPolygon", &pointInPolygon)
        .def("getAngle", &getAngle)
        .def("fromPolar", &fromPolar)
        .staticmethod("fromPolar")
        .def("angle", &Vec2Helper::vecAngle)
        .staticmethod("angle")
    ;
}

struct Pixel32_to_python_tuple
{
    static PyObject* convert (avg::Pixel32 px)
    {
        return bp::incref(bp::make_tuple(
                px.getR(), px.getG(), px.getB(), px.getA()).ptr());
    }
};

static bp::object Bitmap_getPixels(Bitmap& bitmap, bool bCopyData=true)
{
    const unsigned char* pBuffer = bitmap.getPixels();
    int buffSize = bitmap.getMemNeeded();
    if (bCopyData) {
        return bp::object(string((const char*)pBuffer, buffSize));
    } else {
#if PY_MAJOR_VERSION < 3
        PyObject* pyBuffer = PyBuffer_FromReadWriteMemory(
                const_cast<unsigned char*>(pBuffer), buffSize);
        PyObject* py_memView = PyMemoryView_FromObject(pyBuffer);
#else
        PyObject* py_memView = PyMemoryView_FromMemory(
                const_cast<char*>(reinterpret_cast<const char*>(pBuffer)),
                buffSize, PyBUF_READ);
#endif
        return bp::object(handle<>(py_memView));
    }
}

BOOST_PYTHON_FUNCTION_OVERLOADS(Bitmap_getPixels_overloads, Bitmap_getPixels,
        1, 2);

static void Bitmap_setPixels(Bitmap& bitmap, PyObject* exporter)
{
    Py_buffer bufferView;
    if (PyObject_CheckBuffer(exporter)) {
        PyObject_GetBuffer(exporter, &bufferView, PyBUF_READ);
    } else {
        throw Exception(AVG_ERR_INVALID_ARGS,
               "Second parameter to Bitmap.setPixels must support the buffer interface.");
    }
    const unsigned char* cxx_buf = reinterpret_cast<unsigned char*>(bufferView.buf);
    bitmap.setPixels(cxx_buf);
    PyBuffer_Release(&bufferView);
}

ConstVec2 Bitmap_getSize(Bitmap* This)
{
    return (glm::vec2)(This->getSize());
}

BitmapPtr Bitmap_getResized(BitmapPtr This, const glm::vec2& size)
{
    return FilterResizeBilinear(IntPoint(size)).apply(This);
}

glm::vec2* createPoint()
{
    return new glm::vec2(0,0);
}

BitmapPtr createBitmapFromFile(const UTF8String& sFName)
{
    return loadBitmap(sFName);
}

BitmapPtr createBitmapWithRect(BitmapPtr pBmp,
        const glm::vec2& tlPos, const glm::vec2& brPos)
{
    if (tlPos.x >= brPos.x || tlPos.y >= brPos.y) {
        throw Exception(AVG_ERR_OUT_OF_RANGE,
                "Can't create a bitmap with zero or negative width/height.");
    }
    IntPoint size = pBmp->getSize();
    if (tlPos.x < 0 || tlPos.y < 0 || brPos.x > size.x || brPos.y > size.y) {
        throw Exception(AVG_ERR_OUT_OF_RANGE,
                "Attempt to create a subbitmap that doesn't fit into the parent bitmap.");
    }
    IntRect rect = IntRect(IntPoint(tlPos), IntPoint(brPos));
    return BitmapPtr(new Bitmap(*pBmp, rect));
}

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(loadBitmap_overloads, BitmapManager::loadBitmapPy,
        2, 3);

void export_bitmap()
{
    export_point<glm::vec2>("Point2D")
        .def("__init__", make_constructor(createPoint))
        .def(init<float, float>())
        .def(init<const glm::vec2&>())
        .def("__setitem__", &Vec2Helper::setItem)
        .add_property("x", &Vec2Helper::getX, &Vec2Helper::setX,"")
        .add_property("y", &Vec2Helper::getY, &Vec2Helper::setY,"")
    ;

    export_point<ConstVec2>("ConstPoint2D")
        .add_property("x", &Vec2Helper::getX, "")
        .add_property("y", &Vec2Helper::getY, "")
    ;

    implicitly_convertible<ConstVec2, glm::vec2>();
    implicitly_convertible<glm::vec2, ConstVec2>();

    enum_<PixelFormat>("pixelformat")
        .value("B5G6R5", B5G6R5)
        .value("B8G8R8", B8G8R8)
        .value("B8G8R8A8", B8G8R8A8)
        .value("B8G8R8X8", B8G8R8X8)
        .value("A8B8G8R8", A8B8G8R8)
        .value("X8B8G8R8", X8B8G8R8)
        .value("R5G6B5", R5G6B5)
        .value("R8G8B8", R8G8B8)
        .value("R8G8B8A8", R8G8B8A8)
        .value("R8G8B8X8", R8G8B8X8)
        .value("A8R8G8B8", A8R8G8B8)
        .value("X8R8G8B8", X8R8G8B8)
        .value("I8", I8)
        .value("I16", I16)
        .value("A8", A8)
        .value("YCbCr411", YCbCr411)
        .value("YCbCr422", YCbCr422)
        .value("YUYV422", YUYV422)
        .value("YCbCr420p", YCbCr420p)
        .value("YCbCrJ420p", YCbCrJ420p)
        .value("YCbCrA420p", YCbCrA420p)
        .value("BAYER8", BAYER8)
        .value("BAYER8_RGGB", BAYER8_RGGB)
        .value("BAYER8_GBRG", BAYER8_GBRG)
        .value("BAYER8_GRBG", BAYER8_GRBG)
        .value("BAYER8_BGGR", BAYER8_BGGR)
        .value("R32G32B32A32F", R32G32B32A32F)
        .value("I32F", I32F)
        .export_values();

    def("getSupportedPixelFormats", &getSupportedPixelFormats);

    to_python_converter<Pixel32, Pixel32_to_python_tuple>();

    class_<Bitmap, boost::shared_ptr<Bitmap> >("Bitmap", no_init)
        .def(init<glm::vec2, PixelFormat, UTF8String>())
        .def(init<Bitmap>())
        .def("__init__", make_constructor(createBitmapWithRect))
        .def("__init__", make_constructor(createBitmapFromFile))
        .def("blt", &Bitmap::blt)
        .def("getResized", &Bitmap_getResized)
        .def("save", &Bitmap::save)
        .def("getSize", &Bitmap_getSize)
        .def("getFormat", &Bitmap::getPixelFormat)
        .def("getPixels", &Bitmap_getPixels, Bitmap_getPixels_overloads())
        .def("setPixels", &Bitmap_setPixels)
        .def("getPixel", &Bitmap::getPythonPixel)
        .def("subtract", &Bitmap::subtract)
        .def("getAvg", &Bitmap::getAvg)
        .def("getChannelAvg", &Bitmap::getChannelAvg)
        .def("getStdDev", &Bitmap::getStdDev)
        .def("getName", &Bitmap::getName,
                return_value_policy<copy_const_reference>())
    ;

    class_<BitmapManager>("BitmapManager", no_init)
        .def("get", &BitmapManager::get,
                return_value_policy<reference_existing_object>())
        .staticmethod("get")
        .def("loadBitmap", &BitmapManager::loadBitmapPy, loadBitmap_overloads())
        .def("setNumThreads", &BitmapManager::setNumThreads)
    ;

    class_<CubicSpline, boost::noncopyable>("CubicSpline", no_init)
        .def(init<const vector<glm::vec2>&>())
        .def(init<const vector<glm::vec2>&, bool>())
        .def("interpolate", &CubicSpline::interpolate)
    ;
}
<commit_msg>Got rid of unnecessary casts; return buffer from Bitmap::getPixels(True).<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "WrapHelper.h"

#include "../player/BoostPython.h"
#include "../player/BitmapManager.h"

#include "../graphics/Bitmap.h"
#include "../graphics/BitmapLoader.h"
#include "../graphics/FilterResizeBilinear.h"

#include "../base/CubicSpline.h"
#include "../base/GeomHelper.h"

#include "../glm/gtx/vector_angle.hpp"

#include <vector>
#include <sstream>

using namespace boost::python;
using namespace std;
using namespace avg;

namespace bp = boost::python;

template<class POINT>
class_<POINT> export_point(const string& sName)
{
    return class_<POINT>(sName.c_str(), no_init)
        .def("__len__", &Vec2Helper::len)
        .def("__getitem__", &Vec2Helper::getItem)
        .def("__str__", &Vec2Helper::str)
        .def("__repr__", &Vec2Helper::repr)
        .def("__hash__", &Vec2Helper::getHash)
        .def("getNormalized", &Vec2Helper::safeGetNormalized)
        .def("getNorm", &Vec2Helper::getNorm)
        .def("getRotated", &getRotated)
        .def("getRotated", &getRotatedPivot)
        .def(self == self)
        .def(self != self)
        .def(-self)
        .def(self + self)
        .def(self - self)
        .def(float() * self)
        .def(self * float())
        .def(self / float())
        .def("isInPolygon", &pointInPolygon)
        .def("getAngle", &getAngle)
        .def("fromPolar", &fromPolar)
        .staticmethod("fromPolar")
        .def("angle", &Vec2Helper::vecAngle)
        .staticmethod("angle")
    ;
}

struct Pixel32_to_python_tuple
{
    static PyObject* convert (avg::Pixel32 px)
    {
        return bp::incref(bp::make_tuple(
                px.getR(), px.getG(), px.getB(), px.getA()).ptr());
    }
};

static bp::object Bitmap_getPixels(Bitmap& bitmap, bool bCopyData=true)
{
    unsigned char* pBuffer = bitmap.getPixels();
    int buffSize = bitmap.getMemNeeded();
    if (bCopyData) {
        char * pBufCopy = new char[buffSize];
        memcpy(pBufCopy, pBuffer, buffSize);
        return bp::object(handle<>(PyBuffer_FromMemory(pBuffer, buffSize)));
    } else {
#if PY_MAJOR_VERSION < 3
        PyObject* pyBuffer = PyBuffer_FromReadWriteMemory(pBuffer, buffSize);
        PyObject* py_memView = PyMemoryView_FromObject(pyBuffer);
#else
        PyObject* py_memView = PyMemoryView_FromMemory((char*)pBuffer,
                buffSize, PyBUF_READ);
#endif
        return bp::object(handle<>(py_memView));
    }
}

BOOST_PYTHON_FUNCTION_OVERLOADS(Bitmap_getPixels_overloads, Bitmap_getPixels,
        1, 2);

static void Bitmap_setPixels(Bitmap& bitmap, PyObject* exporter)
{
    Py_buffer bufferView;
    if (PyObject_CheckBuffer(exporter)) {
        PyObject_GetBuffer(exporter, &bufferView, PyBUF_READ);
    } else {
        throw Exception(AVG_ERR_INVALID_ARGS,
               "Second parameter to Bitmap.setPixels must support the buffer interface.");
    }
    const unsigned char* cxx_buf = reinterpret_cast<unsigned char*>(bufferView.buf);
    bitmap.setPixels(cxx_buf);
    PyBuffer_Release(&bufferView);
}

ConstVec2 Bitmap_getSize(Bitmap* This)
{
    return (glm::vec2)(This->getSize());
}

BitmapPtr Bitmap_getResized(BitmapPtr This, const glm::vec2& size)
{
    return FilterResizeBilinear(IntPoint(size)).apply(This);
}

glm::vec2* createPoint()
{
    return new glm::vec2(0,0);
}

BitmapPtr createBitmapFromFile(const UTF8String& sFName)
{
    return loadBitmap(sFName);
}

BitmapPtr createBitmapWithRect(BitmapPtr pBmp,
        const glm::vec2& tlPos, const glm::vec2& brPos)
{
    if (tlPos.x >= brPos.x || tlPos.y >= brPos.y) {
        throw Exception(AVG_ERR_OUT_OF_RANGE,
                "Can't create a bitmap with zero or negative width/height.");
    }
    IntPoint size = pBmp->getSize();
    if (tlPos.x < 0 || tlPos.y < 0 || brPos.x > size.x || brPos.y > size.y) {
        throw Exception(AVG_ERR_OUT_OF_RANGE,
                "Attempt to create a subbitmap that doesn't fit into the parent bitmap.");
    }
    IntRect rect = IntRect(IntPoint(tlPos), IntPoint(brPos));
    return BitmapPtr(new Bitmap(*pBmp, rect));
}

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(loadBitmap_overloads, BitmapManager::loadBitmapPy,
        2, 3);

void export_bitmap()
{
    export_point<glm::vec2>("Point2D")
        .def("__init__", make_constructor(createPoint))
        .def(init<float, float>())
        .def(init<const glm::vec2&>())
        .def("__setitem__", &Vec2Helper::setItem)
        .add_property("x", &Vec2Helper::getX, &Vec2Helper::setX,"")
        .add_property("y", &Vec2Helper::getY, &Vec2Helper::setY,"")
    ;

    export_point<ConstVec2>("ConstPoint2D")
        .add_property("x", &Vec2Helper::getX, "")
        .add_property("y", &Vec2Helper::getY, "")
    ;

    implicitly_convertible<ConstVec2, glm::vec2>();
    implicitly_convertible<glm::vec2, ConstVec2>();

    enum_<PixelFormat>("pixelformat")
        .value("B5G6R5", B5G6R5)
        .value("B8G8R8", B8G8R8)
        .value("B8G8R8A8", B8G8R8A8)
        .value("B8G8R8X8", B8G8R8X8)
        .value("A8B8G8R8", A8B8G8R8)
        .value("X8B8G8R8", X8B8G8R8)
        .value("R5G6B5", R5G6B5)
        .value("R8G8B8", R8G8B8)
        .value("R8G8B8A8", R8G8B8A8)
        .value("R8G8B8X8", R8G8B8X8)
        .value("A8R8G8B8", A8R8G8B8)
        .value("X8R8G8B8", X8R8G8B8)
        .value("I8", I8)
        .value("I16", I16)
        .value("A8", A8)
        .value("YCbCr411", YCbCr411)
        .value("YCbCr422", YCbCr422)
        .value("YUYV422", YUYV422)
        .value("YCbCr420p", YCbCr420p)
        .value("YCbCrJ420p", YCbCrJ420p)
        .value("YCbCrA420p", YCbCrA420p)
        .value("BAYER8", BAYER8)
        .value("BAYER8_RGGB", BAYER8_RGGB)
        .value("BAYER8_GBRG", BAYER8_GBRG)
        .value("BAYER8_GRBG", BAYER8_GRBG)
        .value("BAYER8_BGGR", BAYER8_BGGR)
        .value("R32G32B32A32F", R32G32B32A32F)
        .value("I32F", I32F)
        .export_values();

    def("getSupportedPixelFormats", &getSupportedPixelFormats);

    to_python_converter<Pixel32, Pixel32_to_python_tuple>();

    class_<Bitmap, boost::shared_ptr<Bitmap> >("Bitmap", no_init)
        .def(init<glm::vec2, PixelFormat, UTF8String>())
        .def(init<Bitmap>())
        .def("__init__", make_constructor(createBitmapWithRect))
        .def("__init__", make_constructor(createBitmapFromFile))
        .def("blt", &Bitmap::blt)
        .def("getResized", &Bitmap_getResized)
        .def("save", &Bitmap::save)
        .def("getSize", &Bitmap_getSize)
        .def("getFormat", &Bitmap::getPixelFormat)
        .def("getPixels", &Bitmap_getPixels, Bitmap_getPixels_overloads())
        .def("setPixels", &Bitmap_setPixels)
        .def("getPixel", &Bitmap::getPythonPixel)
        .def("subtract", &Bitmap::subtract)
        .def("getAvg", &Bitmap::getAvg)
        .def("getChannelAvg", &Bitmap::getChannelAvg)
        .def("getStdDev", &Bitmap::getStdDev)
        .def("getName", &Bitmap::getName,
                return_value_policy<copy_const_reference>())
    ;

    class_<BitmapManager>("BitmapManager", no_init)
        .def("get", &BitmapManager::get,
                return_value_policy<reference_existing_object>())
        .staticmethod("get")
        .def("loadBitmap", &BitmapManager::loadBitmapPy, loadBitmap_overloads())
        .def("setNumThreads", &BitmapManager::setNumThreads)
    ;

    class_<CubicSpline, boost::noncopyable>("CubicSpline", no_init)
        .def(init<const vector<glm::vec2>&>())
        .def(init<const vector<glm::vec2>&, bool>())
        .def("interpolate", &CubicSpline::interpolate)
    ;
}
<|endoftext|>


<commit_before>
#include "../../core/logs.h"
#include "../../private/graphics/opengl/glew/glew.h"
#include <iostream>
#include "glwindow.h"
#include "texture.h"

namespace Yuni
{
namespace UI
{

	bool GLWindow::initialize()
	{
		// Black background
		::glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		// Depth Buffer setup
		::glClearDepth(1.0f);
		// Enables Depth Testing
		::glEnable(GL_DEPTH_TEST);
		// The type of Depth Testing to do
		::glDepthFunc(GL_LEQUAL);
		// Enable back-face culling
		::glEnable(GL_CULL_FACE);

		// Display OpenGL version
#ifndef NDEBUG
		Yuni::Logs::Logger<> logs;
		const uint8* version = ::glGetString(GL_VERSION);
		logs.notice() << "OpenGL " << (const char*)version;
#endif

		// Init GLEW
		GLenum error = ::glewInit();
		if (GLEW_OK != error)
		{
#ifndef NDEBUG
			logs.error() << ::glewGetErrorString(error);
#endif
			return false;
		}

		// Wait for the context to be ready before initializing some GL objects in the main window
		RenderWindow::initialize();
		activeView()->initShaders();

		return true;
	}

	void GLWindow::resize(uint width, uint height)
	{
		// Prevent A Divide By Zero
		if (0 == height)
			height = 1;

		// Reset The Current Viewport
		::glViewport(0, 0, width, height);

		// Select the Projection Matrix
		::glMatrixMode(GL_PROJECTION);
		// Reset the Projection Matrix
		::glLoadIdentity();

		// Calculate the Aspect Ratio of the window
		::gluPerspective(60.0f, (GLfloat)width / (GLfloat)height, 0.01f, 1000.0f);

		// Select the Modelview Matrix
		::glMatrixMode(GL_MODELVIEW);
		// Reset the Modelview Matrix
		::glLoadIdentity();

		RenderWindow::resize(width, height);
	}

	void GLWindow::drawFullWindowQuad(const Gfx3D::Texture::Ptr& texture) const
	{
		auto textureType = multiSampling() ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
		::glBindTexture(textureType, texture->id());

		::glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT);
		::glDisable(GL_DEPTH_TEST);
		//::glCullFace(GL_FRONT);

		::glMatrixMode(GL_PROJECTION);
		::glPushMatrix();
		::glLoadIdentity();
		::gluOrtho2D(-1.0f, 1.0f, 1.0f, -1.0f);

		::glMatrixMode(GL_MODELVIEW);
		::glPushMatrix();
		::glLoadIdentity();

		::glBegin(GL_QUADS);
		::glTexCoord2f(0.0f, 1.0f);
		::glVertex2f(-1.0f, -1.0f);
		::glTexCoord2f(0.0f, 0.0f);
		::glVertex2f(-1.0f, 1.0f);
		::glTexCoord2f(1.0f, 0.0f);
		::glVertex2f(1.0f, 1.0f);
		::glTexCoord2f(1.0f, 1.0f);
		::glVertex2f(1.0f, -1.0f);
		::glEnd();

		/*
		// Texture coordinates are useless when 2D shaders are activated
		// but they are used when no post-processing effect is present
		const float texCoord[] =
			{
				0.0f, 0.0f,
				0.0f, 1.0f,
				1.0f, 1.0f,
				0.0f, 0.0f,
				1.0f, 1.0f,
				1.0f, 0.0f
			};
		::glEnableVertexAttribArray(Gfx3D::Vertex<>::vaTextureCoord);
		::glVertexAttribPointer(Gfx3D::Vertex<>::vaTextureCoord, 2, GL_FLOAT, 0, 0, texCoord);
		// Set vertex positions
		const float vertices[] =
			{
				-1.0f, 1.0f,
				-1.0f, -1.0f,
				1.0f, -1.0f,
				-1.0f, 1.0f,
				1.0f, -1.0f,
				1.0f, 1.0f
			};
		::glEnableVertexAttribArray(Gfx3D::Vertex<>::vaPosition);
		::glVertexAttribPointer(Gfx3D::Vertex<>::vaPosition, 2, GL_FLOAT, 0, 0, vertices);
		// Draw
		::glDrawArrays(GL_TRIANGLES, 0, 6);
		*/

		::glMatrixMode(GL_PROJECTION);
		::glPopMatrix();
		::glMatrixMode(GL_MODELVIEW);
		::glPopMatrix();

		::glPopAttrib();
		//::glCullFace(GL_BACK);

		::glBindTexture(textureType, 0);
	}

	void GLWindow::clear() const
	{
		pFB.activate();
		::glClear(GL_COLOR_BUFFER_BIT);
		pFB.deactivate();
	}

	void GLWindow::clear(const Color::RGB<>& color) const
	{
		pFB.activate();
		::glClearColor(color.red, color.green, color.blue, 1.0f);
		::glClear(GL_COLOR_BUFFER_BIT);
		pFB.deactivate();
	}

	void GLWindow::clearRect(int x, int y, uint width, uint height) const
	{
		pFB.activate();
		// We offer coordinates top-left to bottom-right
		// but GL coordinates are bottom-left to top-right, so convert Y
		::glEnable(GL_SCISSOR_TEST);
		::glScissor(x, pHeight - height - y, width, height);
		::glClear(GL_COLOR_BUFFER_BIT);
		::glDisable(GL_SCISSOR_TEST);
		pFB.deactivate();
	}

} // namespace UI
} // namespace Yuni
<commit_msg>UI : Temporarily removed back-face culling until a definite foolproof last draw step is found.<commit_after>
#include "../../core/logs.h"
#include "../../private/graphics/opengl/glew/glew.h"
#include <iostream>
#include "glwindow.h"
#include "texture.h"

namespace Yuni
{
namespace UI
{

	bool GLWindow::initialize()
	{
		// Black background
		::glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		// Depth Buffer setup
		::glClearDepth(1.0f);
		// Enables Depth Testing
		::glEnable(GL_DEPTH_TEST);
		// The type of Depth Testing to do
		::glDepthFunc(GL_LEQUAL);
		// Enable back-face culling
		//::glEnable(GL_CULL_FACE);

		// Display OpenGL version
#ifndef NDEBUG
		Yuni::Logs::Logger<> logs;
		const uint8* version = ::glGetString(GL_VERSION);
		logs.notice() << "OpenGL " << (const char*)version;
#endif

		// Init GLEW
		GLenum error = ::glewInit();
		if (GLEW_OK != error)
		{
#ifndef NDEBUG
			logs.error() << ::glewGetErrorString(error);
#endif
			return false;
		}

		// Wait for the context to be ready before initializing some GL objects in the main window
		RenderWindow::initialize();
		activeView()->initShaders();

		return true;
	}

	void GLWindow::resize(uint width, uint height)
	{
		// Prevent A Divide By Zero
		if (0 == height)
			height = 1;

		// Reset The Current Viewport
		::glViewport(0, 0, width, height);

		// Select the Projection Matrix
		::glMatrixMode(GL_PROJECTION);
		// Reset the Projection Matrix
		::glLoadIdentity();

		// Calculate the Aspect Ratio of the window
		::gluPerspective(60.0f, (GLfloat)width / (GLfloat)height, 0.01f, 1000.0f);

		// Select the Modelview Matrix
		::glMatrixMode(GL_MODELVIEW);
		// Reset the Modelview Matrix
		::glLoadIdentity();

		RenderWindow::resize(width, height);
	}

	void GLWindow::drawFullWindowQuad(const Gfx3D::Texture::Ptr& texture) const
	{
		auto textureType = multiSampling() ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
		::glBindTexture(textureType, texture->id());

		::glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT);
		::glDisable(GL_DEPTH_TEST);
		//::glCullFace(GL_FRONT);

		::glMatrixMode(GL_PROJECTION);
		::glPushMatrix();
		::glLoadIdentity();
		::gluOrtho2D(-1.0f, 1.0f, 1.0f, -1.0f);

		::glMatrixMode(GL_MODELVIEW);
		::glPushMatrix();
		::glLoadIdentity();

		::glBegin(GL_QUADS);
		::glTexCoord2f(0.0f, 1.0f);
		::glVertex2f(-1.0f, -1.0f);
		::glTexCoord2f(0.0f, 0.0f);
		::glVertex2f(-1.0f, 1.0f);
		::glTexCoord2f(1.0f, 0.0f);
		::glVertex2f(1.0f, 1.0f);
		::glTexCoord2f(1.0f, 1.0f);
		::glVertex2f(1.0f, -1.0f);
		::glEnd();

		// Texture coordinates are useless when 2D shaders are activated
		// but they are used when no post-processing effect is present
		// const float texCoord[] =
		// 	{
		// 		0.0f, 1.0f,
		// 		0.0f, 0.0f,
		// 		1.0f, 0.0f,
		// 		0.0f, 1.0f,
		// 		1.0f, 0.0f,
		// 		1.0f, 1.0f
		// 	};
		// ::glEnableVertexAttribArray(Gfx3D::Vertex<>::vaTextureCoord);
		// ::glVertexAttribPointer(Gfx3D::Vertex<>::vaTextureCoord, 2, GL_FLOAT, 0, 0, texCoord);
		// Set vertex positions
		/*const float vertices[] =
			{
				-1.0f, 1.0f,
				-1.0f, -1.0f,
				1.0f, -1.0f,
				-1.0f, 1.0f,
				1.0f, -1.0f,
				1.0f, 1.0f
			};
		::glEnableVertexAttribArray(Gfx3D::Vertex<>::vaPosition);
		::glVertexAttribPointer(Gfx3D::Vertex<>::vaPosition, 2, GL_FLOAT, 0, 0, vertices);
		// Draw
		::glDrawArrays(GL_TRIANGLES, 0, 6);

		::glDisableVertexAttribArray(Gfx3D::Vertex<>::vaPosition);
		::glDisableVertexAttribArray(Gfx3D::Vertex<>::vaTextureCoord);
		*/
		::glMatrixMode(GL_PROJECTION);
		::glPopMatrix();
		::glMatrixMode(GL_MODELVIEW);
		::glPopMatrix();

		::glPopAttrib();
		//::glCullFace(GL_BACK);

		::glBindTexture(textureType, 0);
	}

	void GLWindow::clear() const
	{
		pFB.activate();
		::glClear(GL_COLOR_BUFFER_BIT);
		pFB.deactivate();
	}

	void GLWindow::clear(const Color::RGB<>& color) const
	{
		pFB.activate();
		::glClearColor(color.red, color.green, color.blue, 1.0f);
		::glClear(GL_COLOR_BUFFER_BIT);
		pFB.deactivate();
	}

	void GLWindow::clearRect(int x, int y, uint width, uint height) const
	{
		pFB.activate();
		// We offer coordinates top-left to bottom-right
		// but GL coordinates are bottom-left to top-right, so convert Y
		::glEnable(GL_SCISSOR_TEST);
		::glScissor(x, pHeight - height - y, width, height);
		::glClear(GL_COLOR_BUFFER_BIT);
		::glDisable(GL_SCISSOR_TEST);
		pFB.deactivate();
	}

} // namespace UI
} // namespace Yuni
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <glog/logging.h>

#include <iostream>
#include <map>

#include <process/dispatch.hpp>
#include <process/once.hpp>
#include <process/process.hpp>

#include <stout/duration.hpp>
#include <stout/fatal.hpp>
#include <stout/foreach.hpp>
#include <stout/path.hpp>
#include <stout/strings.hpp>
#include <stout/tuple.hpp>

#include "zookeeper/zookeeper.hpp"

using process::Future;
using process::PID;
using process::Process;
using process::Promise;

using std::map;
using std::string;
using std::vector;

using tuples::tuple;

class ZooKeeperImpl
{
public:
  ZooKeeperImpl(ZooKeeper* zk,
                const string& servers,
                const Duration& timeout,
                Watcher* watcher)
    : servers(servers),
      zk(zk),
      watcher(watcher)
  {
    if (watcher == NULL) {
      LOG(FATAL) << "Cannot instantiate ZooKeeper with NULL watcher";
    }

    zh = zookeeper_init(
        servers.c_str(),
        event,
        static_cast<int>(timeout.ms()),
        NULL,
        this,
        0);

    if (zh == NULL) {
      PLOG(FATAL) << "Failed to create ZooKeeper, zookeeper_init";
    }
  }

  ~ZooKeeperImpl()
  {
    int ret = zookeeper_close(zh);
    if (ret != ZOK) {
      LOG(FATAL) << "Failed to cleanup ZooKeeper, zookeeper_close: "
                 << zerror(ret);
    }
  }

  Future<int> authenticate(const string& scheme, const string& credentials)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*>* args = new tuple<Promise<int>*>(promise);

    int ret = zoo_add_auth(zh, scheme.c_str(), credentials.data(),
                           credentials.size(), voidCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> create(const string& path, const string& data,
                     const ACL_vector& acl, int flags, string* result)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, string*>* args =
      new tuple<Promise<int>*, string*>(promise, result);

    int ret = zoo_acreate(zh, path.c_str(), data.data(), data.size(), &acl,
                          flags, stringCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> remove(const string& path, int version)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*>* args = new tuple<Promise<int>*>(promise);

    int ret = zoo_adelete(zh, path.c_str(), version, voidCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> exists(const string& path, bool watch, Stat* stat)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, Stat*>* args =
      new tuple<Promise<int>*, Stat*>(promise, stat);

    int ret = zoo_aexists(zh, path.c_str(), watch, statCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> get(const string& path, bool watch, string* result, Stat* stat)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, string*, Stat*>* args =
      new tuple<Promise<int>*, string*, Stat*>(promise, result, stat);

    int ret = zoo_aget(zh, path.c_str(), watch, dataCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> getChildren(const string& path,
                          bool watch,
                          vector<string>* results)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, vector<string>*>* args =
      new tuple<Promise<int>*, vector<string>*>(promise, results);

    int ret = zoo_aget_children(zh, path.c_str(), watch, stringsCompletion,
                                args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> set(const string& path, const string& data, int version)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, Stat*>* args =
      new tuple<Promise<int>*, Stat*>(promise, NULL);

    int ret = zoo_aset(zh, path.c_str(), data.data(), data.size(),
                       version, statCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

private:
  // This method is registered as a watcher callback function and is
  // invoked by a single ZooKeeper event thread.
  static void event(
      zhandle_t* zh,
      int type,
      int state,
      const char* path,
      void* ctx)
  {
    ZooKeeperImpl* impl = static_cast<ZooKeeperImpl*>(ctx);
    impl->watcher->process(impl->zk, type, state, string(path));
  }

  static void voidCompletion(int ret, const void *data)
  {
    const tuple<Promise<int>*>* args =
      reinterpret_cast<const tuple<Promise<int>*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);

    promise->set(ret);

    delete promise;
    delete args;
  }

  static void stringCompletion(int ret, const char* value, const void* data)
  {
    const tuple<Promise<int>*, string*> *args =
      reinterpret_cast<const tuple<Promise<int>*, string*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);
    string* result = tuples::get<1>(*args);

    if (ret == 0) {
      if (result != NULL) {
        result->assign(value);
      }
    }

    promise->set(ret);

    delete promise;
    delete args;
  }

  static void statCompletion(int ret, const Stat* stat, const void* data)
  {
    const tuple<Promise<int>*, Stat*>* args =
      reinterpret_cast<const tuple<Promise<int>*, Stat*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);
    Stat *stat_result = tuples::get<1>(*args);

    if (ret == 0) {
      if (stat_result != NULL) {
        *stat_result = *stat;
      }
    }

    promise->set(ret);

    delete promise;
    delete args;
  }

  static void dataCompletion(
      int ret,
      const char* value,
      int value_len,
      const Stat* stat,
      const void* data)
  {
    const tuple<Promise<int>*, string*, Stat*>* args =
      reinterpret_cast<const tuple<Promise<int>*, string*, Stat*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);
    string* result = tuples::get<1>(*args);
    Stat* stat_result = tuples::get<2>(*args);

    if (ret == 0) {
      if (result != NULL) {
        result->assign(value, value_len);
      }

      if (stat_result != NULL) {
        *stat_result = *stat;
      }
    }

    promise->set(ret);

    delete promise;
    delete args;
  }

  static void stringsCompletion(
      int ret,
      const String_vector* values,
      const void* data)
  {
    const tuple<Promise<int>*, vector<string>*>* args =
      reinterpret_cast<const tuple<Promise<int>*, vector<string>*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);
    vector<string>* results = tuples::get<1>(*args);

    if (ret == 0) {
      if (results != NULL) {
        for (int i = 0; i < values->count; i++) {
          results->push_back(values->data[i]);
        }
      }
    }

    promise->set(ret);

    delete promise;
    delete args;
  }

private:
  friend class ZooKeeper;

  const string servers; // ZooKeeper host:port pairs.

  ZooKeeper* zk; // ZooKeeper instance.
  zhandle_t* zh; // ZooKeeper connection handle.

  Watcher* watcher; // Associated Watcher instance.
};

ZooKeeper::ZooKeeper(const string& servers,
                     const Duration& timeout,
                     Watcher* watcher)
{
  impl = new ZooKeeperImpl(this, servers, timeout, watcher);
}

ZooKeeper::~ZooKeeper()
{
  delete impl;
}

int ZooKeeper::getState()
{
  return zoo_state(impl->zh);
}

int64_t ZooKeeper::getSessionId()
{
  return zoo_client_id(impl->zh)->client_id;
}

Duration ZooKeeper::getSessionTimeout() const
{
  // ZooKeeper server uses int representation of milliseconds for
  // session timeouts.
  // See:
  // http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html
  return Milliseconds(zoo_recv_timeout(impl->zh));
}

int ZooKeeper::authenticate(const string& scheme, const string& credentials)
{
  return impl->authenticate(scheme, credentials).get();
}

int ZooKeeper::create(
    const string& path,
    const string& data,
    const ACL_vector& acl,
    int flags,
    string* result,
    bool recursive)
{
  if (!recursive) {
    return impl->create(path, data, acl, flags, result).get();
  }

  // First check if the path exists.
  int code = impl->exists(path, false, NULL).get();
  if (code == ZOK) {
    return ZNODEEXISTS;
  }

  // Now recursively create the parent path.
  // NOTE: We don't use 'dirname()' to get the parent path here
  // because, it doesn't return the expected path when a path ends
  // with "/". For example, to create path "/a/b/", we want to
  // recursively create "/a/b", instead of just creating "/a".
  const string& parent = path.substr(0, path.find_last_of("/"));
  if (!parent.empty()) {
    code = create(parent, "", acl, 0, result, true);
    if (code != ZOK && code != ZNODEEXISTS) {
      return code;
    }
  }

  // Finally create the path.
  // TODO(vinod): Delete any intermediate nodes created if this fails.
  // This requires synchronization because the deletion might affect
  // other callers (different threads/processes) acting on this path.
  return impl->create(path, data, acl, flags, result).get();
}

int ZooKeeper::remove(const string& path, int version)
{
  return impl->remove(path, version).get();
}

int ZooKeeper::exists(const string& path, bool watch, Stat* stat)
{
  return impl->exists(path, watch, stat).get();
}

int ZooKeeper::get(const string& path, bool watch, string* result, Stat* stat)
{
  return impl->get(path, watch, result, stat).get();
}

int ZooKeeper::getChildren(const string& path, bool watch,
                           vector<string>* results)
{
  return impl->getChildren(path, watch, results).get();
}

int ZooKeeper::set(const string& path, const string& data, int version)
{
  return impl->set(path, data, version).get();
}

string ZooKeeper::message(int code) const
{
  return string(zerror(code));
}

bool ZooKeeper::retryable(int code)
{
  switch (code) {
    case ZCONNECTIONLOSS:
    case ZOPERATIONTIMEOUT:
    case ZSESSIONEXPIRED:
    case ZSESSIONMOVED:
      return true;

    case ZOK: // No need to retry!

    case ZSYSTEMERROR: // Should not be encountered, here for completeness.
    case ZRUNTIMEINCONSISTENCY:
    case ZDATAINCONSISTENCY:
    case ZMARSHALLINGERROR:
    case ZUNIMPLEMENTED:
    case ZBADARGUMENTS:
    case ZINVALIDSTATE:

    case ZAPIERROR: // Should not be encountered, here for completeness.
    case ZNONODE:
    case ZNOAUTH:
    case ZBADVERSION:
    case ZNOCHILDRENFOREPHEMERALS:
    case ZNODEEXISTS:
    case ZNOTEMPTY:
    case ZINVALIDCALLBACK:
    case ZINVALIDACL:
    case ZAUTHFAILED:
    case ZCLOSING:
    case ZNOTHING: // Is this used? It's not exposed in the Java API.
      return false;

    default:
      LOG(FATAL) << "Unknown ZooKeeper code: " << code;
  }
}
<commit_msg>Fixed a compiler warning using UNREACHABLE in zookeeper.cpp.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <glog/logging.h>

#include <iostream>
#include <map>

#include <process/dispatch.hpp>
#include <process/once.hpp>
#include <process/process.hpp>

#include <stout/duration.hpp>
#include <stout/fatal.hpp>
#include <stout/foreach.hpp>
#include <stout/path.hpp>
#include <stout/strings.hpp>
#include <stout/tuple.hpp>
#include <stout/unreachable.hpp>

#include "zookeeper/zookeeper.hpp"

using process::Future;
using process::PID;
using process::Process;
using process::Promise;

using std::map;
using std::string;
using std::vector;

using tuples::tuple;

class ZooKeeperImpl
{
public:
  ZooKeeperImpl(ZooKeeper* zk,
                const string& servers,
                const Duration& timeout,
                Watcher* watcher)
    : servers(servers),
      zk(zk),
      watcher(watcher)
  {
    if (watcher == NULL) {
      LOG(FATAL) << "Cannot instantiate ZooKeeper with NULL watcher";
    }

    zh = zookeeper_init(
        servers.c_str(),
        event,
        static_cast<int>(timeout.ms()),
        NULL,
        this,
        0);

    if (zh == NULL) {
      PLOG(FATAL) << "Failed to create ZooKeeper, zookeeper_init";
    }
  }

  ~ZooKeeperImpl()
  {
    int ret = zookeeper_close(zh);
    if (ret != ZOK) {
      LOG(FATAL) << "Failed to cleanup ZooKeeper, zookeeper_close: "
                 << zerror(ret);
    }
  }

  Future<int> authenticate(const string& scheme, const string& credentials)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*>* args = new tuple<Promise<int>*>(promise);

    int ret = zoo_add_auth(zh, scheme.c_str(), credentials.data(),
                           credentials.size(), voidCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> create(const string& path, const string& data,
                     const ACL_vector& acl, int flags, string* result)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, string*>* args =
      new tuple<Promise<int>*, string*>(promise, result);

    int ret = zoo_acreate(zh, path.c_str(), data.data(), data.size(), &acl,
                          flags, stringCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> remove(const string& path, int version)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*>* args = new tuple<Promise<int>*>(promise);

    int ret = zoo_adelete(zh, path.c_str(), version, voidCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> exists(const string& path, bool watch, Stat* stat)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, Stat*>* args =
      new tuple<Promise<int>*, Stat*>(promise, stat);

    int ret = zoo_aexists(zh, path.c_str(), watch, statCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> get(const string& path, bool watch, string* result, Stat* stat)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, string*, Stat*>* args =
      new tuple<Promise<int>*, string*, Stat*>(promise, result, stat);

    int ret = zoo_aget(zh, path.c_str(), watch, dataCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> getChildren(const string& path,
                          bool watch,
                          vector<string>* results)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, vector<string>*>* args =
      new tuple<Promise<int>*, vector<string>*>(promise, results);

    int ret = zoo_aget_children(zh, path.c_str(), watch, stringsCompletion,
                                args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

  Future<int> set(const string& path, const string& data, int version)
  {
    Promise<int>* promise = new Promise<int>();

    Future<int> future = promise->future();

    tuple<Promise<int>*, Stat*>* args =
      new tuple<Promise<int>*, Stat*>(promise, NULL);

    int ret = zoo_aset(zh, path.c_str(), data.data(), data.size(),
                       version, statCompletion, args);

    if (ret != ZOK) {
      delete promise;
      delete args;
      return ret;
    }

    return future;
  }

private:
  // This method is registered as a watcher callback function and is
  // invoked by a single ZooKeeper event thread.
  static void event(
      zhandle_t* zh,
      int type,
      int state,
      const char* path,
      void* ctx)
  {
    ZooKeeperImpl* impl = static_cast<ZooKeeperImpl*>(ctx);
    impl->watcher->process(impl->zk, type, state, string(path));
  }

  static void voidCompletion(int ret, const void *data)
  {
    const tuple<Promise<int>*>* args =
      reinterpret_cast<const tuple<Promise<int>*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);

    promise->set(ret);

    delete promise;
    delete args;
  }

  static void stringCompletion(int ret, const char* value, const void* data)
  {
    const tuple<Promise<int>*, string*> *args =
      reinterpret_cast<const tuple<Promise<int>*, string*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);
    string* result = tuples::get<1>(*args);

    if (ret == 0) {
      if (result != NULL) {
        result->assign(value);
      }
    }

    promise->set(ret);

    delete promise;
    delete args;
  }

  static void statCompletion(int ret, const Stat* stat, const void* data)
  {
    const tuple<Promise<int>*, Stat*>* args =
      reinterpret_cast<const tuple<Promise<int>*, Stat*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);
    Stat *stat_result = tuples::get<1>(*args);

    if (ret == 0) {
      if (stat_result != NULL) {
        *stat_result = *stat;
      }
    }

    promise->set(ret);

    delete promise;
    delete args;
  }

  static void dataCompletion(
      int ret,
      const char* value,
      int value_len,
      const Stat* stat,
      const void* data)
  {
    const tuple<Promise<int>*, string*, Stat*>* args =
      reinterpret_cast<const tuple<Promise<int>*, string*, Stat*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);
    string* result = tuples::get<1>(*args);
    Stat* stat_result = tuples::get<2>(*args);

    if (ret == 0) {
      if (result != NULL) {
        result->assign(value, value_len);
      }

      if (stat_result != NULL) {
        *stat_result = *stat;
      }
    }

    promise->set(ret);

    delete promise;
    delete args;
  }

  static void stringsCompletion(
      int ret,
      const String_vector* values,
      const void* data)
  {
    const tuple<Promise<int>*, vector<string>*>* args =
      reinterpret_cast<const tuple<Promise<int>*, vector<string>*>*>(data);

    Promise<int>* promise = tuples::get<0>(*args);
    vector<string>* results = tuples::get<1>(*args);

    if (ret == 0) {
      if (results != NULL) {
        for (int i = 0; i < values->count; i++) {
          results->push_back(values->data[i]);
        }
      }
    }

    promise->set(ret);

    delete promise;
    delete args;
  }

private:
  friend class ZooKeeper;

  const string servers; // ZooKeeper host:port pairs.

  ZooKeeper* zk; // ZooKeeper instance.
  zhandle_t* zh; // ZooKeeper connection handle.

  Watcher* watcher; // Associated Watcher instance.
};

ZooKeeper::ZooKeeper(const string& servers,
                     const Duration& timeout,
                     Watcher* watcher)
{
  impl = new ZooKeeperImpl(this, servers, timeout, watcher);
}

ZooKeeper::~ZooKeeper()
{
  delete impl;
}

int ZooKeeper::getState()
{
  return zoo_state(impl->zh);
}

int64_t ZooKeeper::getSessionId()
{
  return zoo_client_id(impl->zh)->client_id;
}

Duration ZooKeeper::getSessionTimeout() const
{
  // ZooKeeper server uses int representation of milliseconds for
  // session timeouts.
  // See:
  // http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html
  return Milliseconds(zoo_recv_timeout(impl->zh));
}

int ZooKeeper::authenticate(const string& scheme, const string& credentials)
{
  return impl->authenticate(scheme, credentials).get();
}

int ZooKeeper::create(
    const string& path,
    const string& data,
    const ACL_vector& acl,
    int flags,
    string* result,
    bool recursive)
{
  if (!recursive) {
    return impl->create(path, data, acl, flags, result).get();
  }

  // First check if the path exists.
  int code = impl->exists(path, false, NULL).get();
  if (code == ZOK) {
    return ZNODEEXISTS;
  }

  // Now recursively create the parent path.
  // NOTE: We don't use 'dirname()' to get the parent path here
  // because, it doesn't return the expected path when a path ends
  // with "/". For example, to create path "/a/b/", we want to
  // recursively create "/a/b", instead of just creating "/a".
  const string& parent = path.substr(0, path.find_last_of("/"));
  if (!parent.empty()) {
    code = create(parent, "", acl, 0, result, true);
    if (code != ZOK && code != ZNODEEXISTS) {
      return code;
    }
  }

  // Finally create the path.
  // TODO(vinod): Delete any intermediate nodes created if this fails.
  // This requires synchronization because the deletion might affect
  // other callers (different threads/processes) acting on this path.
  return impl->create(path, data, acl, flags, result).get();
}

int ZooKeeper::remove(const string& path, int version)
{
  return impl->remove(path, version).get();
}

int ZooKeeper::exists(const string& path, bool watch, Stat* stat)
{
  return impl->exists(path, watch, stat).get();
}

int ZooKeeper::get(const string& path, bool watch, string* result, Stat* stat)
{
  return impl->get(path, watch, result, stat).get();
}

int ZooKeeper::getChildren(const string& path, bool watch,
                           vector<string>* results)
{
  return impl->getChildren(path, watch, results).get();
}

int ZooKeeper::set(const string& path, const string& data, int version)
{
  return impl->set(path, data, version).get();
}

string ZooKeeper::message(int code) const
{
  return string(zerror(code));
}

bool ZooKeeper::retryable(int code)
{
  switch (code) {
    case ZCONNECTIONLOSS:
    case ZOPERATIONTIMEOUT:
    case ZSESSIONEXPIRED:
    case ZSESSIONMOVED:
      return true;

    case ZOK: // No need to retry!

    case ZSYSTEMERROR: // Should not be encountered, here for completeness.
    case ZRUNTIMEINCONSISTENCY:
    case ZDATAINCONSISTENCY:
    case ZMARSHALLINGERROR:
    case ZUNIMPLEMENTED:
    case ZBADARGUMENTS:
    case ZINVALIDSTATE:

    case ZAPIERROR: // Should not be encountered, here for completeness.
    case ZNONODE:
    case ZNOAUTH:
    case ZBADVERSION:
    case ZNOCHILDRENFOREPHEMERALS:
    case ZNODEEXISTS:
    case ZNOTEMPTY:
    case ZINVALIDCALLBACK:
    case ZINVALIDACL:
    case ZAUTHFAILED:
    case ZCLOSING:
    case ZNOTHING: // Is this used? It's not exposed in the Java API.
      return false;

    default:
      LOG(FATAL) << "Unknown ZooKeeper code: " << code;
      return UNREACHABLE(); // Make compiler happy.
  }
}
<|endoftext|>


<commit_before>
/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2017, mtezych
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * 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.
 *
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS 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 COPYRIGHT HOLDER OR
 * 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.
 */

#if defined(__linux__)

    // [Linux] - alloca (size_t size) -> void*
    // ~ http://man7.org/linux/man-pages/man3/alloca.3.html
    #include <alloca.h>

    // [GCC] - Common Function Attributes
    // ~ https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
    #define always_inline __attribute__((always_inline)) inline

#elif defined(_WIN32)

    // [Microsoft CRT] - _alloca (size_t size) -> void*
    // ~ https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/alloca
    #include <malloc.h>

    // [Micrsoft Visual C++] - Inline Functions
    // ~ https://docs.microsoft.com/en-us/cpp/cpp/inline-functions-cpp
    #define always_inline __forceinline

#else

    #error "Unsupported platform!"

#endif

#include <cassert>

#include <cstddef>

namespace cxx
{
    //
    // The stack_alloc() function only allocates memory.
    // It does *not* create C++ objects under rules of the C++ abstract machine.
    //
    // Therefore, client code is required to
    // call placement new operator to create a C++ object.
    //
    // ~ https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rt2ivJnc4hg/4RKYJeF5CQAJ
    //
    template <typename type>
    always_inline auto stack_alloc (const std::ptrdiff_t size) noexcept -> type*
    {
        assert(size > 0);

    #if defined(__linux__)

        return static_cast<type*>(alloca(sizeof(type) * size));

    #elif defined(_WIN32)

        return static_cast<type*>(_alloca(sizeof(type) * size));

    #endif
    }
}

#include <new>

namespace cxx
{
    template <typename element>
    class stack_array
    {
    private:

        element*       data_;
        std::ptrdiff_t size_;
        std::ptrdiff_t capacity_;

    public:

        always_inline stack_array (const std::ptrdiff_t capacity)
        :
            data_     { stack_alloc<element>(capacity) },
            size_     { 0                              },
            capacity_ { capacity                       }
        {
            assert(capacity > 0);
        }

        auto data () noexcept -> element*
        {
            return data_;
        }

        auto data () const noexcept -> const element*
        {
            return data_;
        }

        auto size () const noexcept -> std::ptrdiff_t
        {
            return size_;
        }

        auto capacity () const noexcept -> std::ptrdiff_t
        {
            return capacity_;
        }

        auto push (const element& value) -> void
        {
            new (data_ + size_) element(value);

            ++size_;
        }

        auto push (element&& value) -> void
        {
            new (data_ + size_) element(std::move(value));

            ++size_;
        }

        auto operator [] (const std::ptrdiff_t index) noexcept -> element&
        {
            assert((index >= 0) && (index < size_));

            return data_[index];
        }

        auto operator [] (const std::ptrdiff_t index) const noexcept -> const element&
        {
            assert((index >= 0) && (index < size_));

            return data_[index];
        }
    };
}

#include <algorithm>

#include <numeric>

namespace test
{
    auto stack_alloc () -> bool
    {
        struct span
        {
            int*           data;
            std::ptrdiff_t size;
        };

        const auto array = span { cxx::stack_alloc<int>(4096), 4096 };

        for (auto i = 0; i < array.size; ++i)
        {
            new (array.data + i) int { 1 };
        }

        // std::fill(array.data, array.data + array.size, 1);

        auto sum = std::accumulate(array.data, array.data + array.size, 0);

        return sum == array.size;
    }

    auto stack_array () -> bool
    {
        auto array = cxx::stack_array<int> { 4096 };

        for (auto i = 0; i < array.capacity(); ++i)
        {
            array.push(1);
        }

        // std::fill(array.data(), array.data() + array.size(), 1);

        auto sum = std::accumulate(array.data(), array.data() + array.size(), 0);

        return sum == array.size();
    }
}

#include <cstdlib>

auto main () -> int
{
    const auto validate = [] (const bool condition)
    {
        if (!condition)
        {
            std::exit(EXIT_FAILURE);
        }
    };

    validate(test::stack_alloc());
    validate(test::stack_array());

    return EXIT_SUCCESS;
}
<commit_msg>Stack Alloc -> Refactored stack_alloc() to return memory_block.<commit_after>
/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2017, mtezych
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * 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.
 *
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS 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 COPYRIGHT HOLDER OR
 * 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.
 */

#if defined(__linux__)

    // [Linux] - alloca (size_t size) -> void*
    // ~ http://man7.org/linux/man-pages/man3/alloca.3.html
    #include <alloca.h>

    // [GCC] - Common Function Attributes
    // ~ https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
    #define always_inline __attribute__((always_inline)) inline

#elif defined(_WIN32)

    // [Microsoft CRT] - _alloca (size_t size) -> void*
    // ~ https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/alloca
    #include <malloc.h>

    // [Micrsoft Visual C++] - Inline Functions
    // ~ https://docs.microsoft.com/en-us/cpp/cpp/inline-functions-cpp
    #define always_inline __forceinline

#else

    #error "Unsupported platform!"

#endif

#include <cassert>

#include <cstddef>

namespace cxx
{
    template <typename type>
    struct memory_block
    {
        type*          addr;
        std::ptrdiff_t size;
    };

    //
    // The stack_alloc() function only allocates memory.
    // It does *not* create C++ objects under rules of the C++ abstract machine.
    //
    // Therefore, client code is required to
    // call placement new operator to create a C++ object.
    //
    // ~ https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rt2ivJnc4hg/4RKYJeF5CQAJ
    //
    template <typename type>
    always_inline
    auto stack_alloc (const std::ptrdiff_t count = 1) noexcept -> memory_block<type>
    {
        assert(count > 0);

    #if defined(__linux__)

        return { static_cast<type*>( alloca(sizeof(type) * count)), count };

    #elif defined(_WIN32)

        return { static_cast<type*>(_alloca(sizeof(type) * count)), count };

    #endif
    }
}

#include <new>

namespace cxx
{
    template <typename element>
    class stack_array
    {
    private:

        memory_block<element> storage;
        std::ptrdiff_t        length;

    public:

        always_inline
        explicit stack_array (const std::ptrdiff_t capacity)
        :
            storage { stack_alloc<element>(capacity) },
            length  { 0                              }
        {
            assert(capacity > 0);
        }

        ~stack_array () = default;

        stack_array (stack_array&& array)      = delete;
        stack_array (const stack_array& array) = delete;

        stack_array& operator = (stack_array&& array)      = delete;
        stack_array& operator = (const stack_array& array) = delete;

        auto data () noexcept -> element*
        {
            return storage.addr;
        }

        auto data () const noexcept -> const element*
        {
            return storage.addr;
        }

        auto size () const noexcept -> std::ptrdiff_t
        {
            return length;
        }

        auto capacity () const noexcept -> std::ptrdiff_t
        {
            return storage.size;
        }

        auto push (const element& value) -> void
        {
            assert(length < storage.size);

            new (storage.addr + length) element(value);

            ++length;
        }

        auto push (element&& value) -> void
        {
            assert(length < storage.size);

            new (storage.addr + length) element(std::move(value));

            ++length;
        }

        auto operator [] (const std::ptrdiff_t index) noexcept -> element&
        {
            assert((index >= 0) && (index < length));

            return storage.addr[index];
        }

        auto operator [] (const std::ptrdiff_t index) const noexcept -> const element&
        {
            assert((index >= 0) && (index < length));

            return storage.addr[index];
        }
    };
}

#include <algorithm>

#include <numeric>

namespace test
{
    auto stack_alloc () -> bool
    {
        const auto array = cxx::stack_alloc<int>(4096);

        for (auto i = 0; i < array.size; ++i)
        {
            new (array.addr + i) int { 1 };
        }

        // std::fill(array.data, array.data + array.size, 1);

        auto sum = std::accumulate(array.addr, array.addr + array.size, 0);

        return sum == array.size;
    }

    auto stack_array () -> bool
    {
        auto array = cxx::stack_array<int> { 4096 };

        for (auto i = 0; i < array.capacity(); ++i)
        {
            array.push(1);
        }

        // std::fill(array.data(), array.data() + array.size(), 1);

        auto sum = std::accumulate(array.data(), array.data() + array.size(), 0);

        return sum == array.size();
    }
}

#include <cstdlib>

auto main () -> int
{
    const auto validate = [] (const bool condition)
    {
        if (!condition)
        {
            std::exit(EXIT_FAILURE);
        }
    };

    validate(test::stack_alloc());
    validate(test::stack_array());

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "global_info.h"
#include "sqlext.h"

const char* ODBC_DRIVER_NAME = "Simplic.CDN.ODBC ANSI";

GlobalInfo* GlobalInfo::_singletonInstance = NULL;

GlobalInfo::GlobalInfo(HINSTANCE hInstance)
{
	m_hInstance = hInstance;
	m_info_initialized = false;
}

GlobalInfo::~GlobalInfo()
{
}

void GlobalInfo::initializeInfo()
{
	m_info.addField(SQL_DRIVER_NAME, new StringInfoField("Simplic.CDN.ODBC.dll"));
	m_info.addField(SQL_DRIVER_ODBC_VER, new StringInfoField("03.00"));

	m_info.addField(SQL_CURSOR_COMMIT_BEHAVIOR, new FixedSizeInfoField<SQLUSMALLINT>(SQL_CB_CLOSE));
	m_info.addField(SQL_CURSOR_ROLLBACK_BEHAVIOR, new FixedSizeInfoField<SQLUSMALLINT>(SQL_CB_CLOSE));
	m_info.addField(SQL_GETDATA_EXTENSIONS, new FixedSizeInfoField<SQLUINTEGER>(0));

	m_info.addField(SQL_MAX_CATALOG_NAME_LEN, new FixedSizeInfoField<SQLUSMALLINT>(0));
	m_info.addField(SQL_MAX_SCHEMA_NAME_LEN, new FixedSizeInfoField<SQLUSMALLINT>(0));
	m_info.addField(SQL_TXN_CAPABLE, new FixedSizeInfoField<SQLUSMALLINT>(0));
	m_info.addField(SQL_IDENTIFIER_CASE, new FixedSizeInfoField<SQLUSMALLINT>(SQL_IC_MIXED));
	m_info.addField(SQL_SEARCH_PATTERN_ESCAPE, new StringInfoField(""));
	m_info.addField(SQL_QUALIFIER_NAME_SEPARATOR, new StringInfoField("."));
	m_info.addField(SQL_NON_NULLABLE_COLUMNS, new FixedSizeInfoField<SQLUSMALLINT>(SQL_NNC_NON_NULL));
	m_info.addField(SQL_SCROLL_CONCURRENCY, new FixedSizeInfoField<SQLUINTEGER>(0));
	m_info.addField(SQL_TXN_ISOLATION_OPTION, new FixedSizeInfoField<SQLUINTEGER>(0));

	m_info.addField(SQL_DBMS_VER, new StringInfoField("00.00.0000"));
	m_info.addField(SQL_DBMS_NAME, new StringInfoField("Simplic.CDN.ODBC"));
}

void GlobalInfo::createSingletonInstance(HINSTANCE hInstance)
{
	_singletonInstance = new GlobalInfo(hInstance);
	_singletonInstance->initializeInfo();
}

void GlobalInfo::deleteSingletonInstance()
{
	if (_singletonInstance != NULL) delete _singletonInstance;
}

std::string GlobalInfo::getDriverPath() const
{
	char buf[MAX_PATH] = {0};
	GetModuleFileNameA(m_hInstance, buf, MAX_PATH);
	return std::string(buf);
}

OdbcInfoField* GlobalInfo::getInfoField(DbConnection* conn, SQLUSMALLINT type)
{
	// TODO: Support querying information from the DbConnection,
	// if any is provided to us
	return m_info.getField(type);
}
<commit_msg>Set odbc details<commit_after>#include "stdafx.h"
#include "global_info.h"
#include "sqlext.h"

const char* ODBC_DRIVER_NAME = "Simplic.CDN.ODBC ANSI";

GlobalInfo* GlobalInfo::_singletonInstance = NULL;

GlobalInfo::GlobalInfo(HINSTANCE hInstance)
{
	m_hInstance = hInstance;
	m_info_initialized = false;
}

GlobalInfo::~GlobalInfo()
{
}

void GlobalInfo::initializeInfo()
{
	m_info.addField(SQL_DRIVER_NAME, new StringInfoField("Simplic.CDN.ODBC.dll"));
	m_info.addField(SQL_DRIVER_ODBC_VER, new StringInfoField("03.00"));

	m_info.addField(SQL_CURSOR_COMMIT_BEHAVIOR, new FixedSizeInfoField<SQLUSMALLINT>(SQL_CB_CLOSE));
	m_info.addField(SQL_CURSOR_ROLLBACK_BEHAVIOR, new FixedSizeInfoField<SQLUSMALLINT>(SQL_CB_CLOSE));
	m_info.addField(SQL_GETDATA_EXTENSIONS, new FixedSizeInfoField<SQLUINTEGER>(0));

	m_info.addField(SQL_MAX_CATALOG_NAME_LEN, new FixedSizeInfoField<SQLUSMALLINT>(0));
	m_info.addField(SQL_MAX_SCHEMA_NAME_LEN, new FixedSizeInfoField<SQLUSMALLINT>(0));
	m_info.addField(SQL_TXN_CAPABLE, new FixedSizeInfoField<SQLUSMALLINT>(0));
	m_info.addField(SQL_IDENTIFIER_CASE, new FixedSizeInfoField<SQLUSMALLINT>(SQL_IC_MIXED));
	m_info.addField(SQL_SEARCH_PATTERN_ESCAPE, new StringInfoField(""));
	m_info.addField(SQL_QUALIFIER_NAME_SEPARATOR, new StringInfoField("."));
	m_info.addField(SQL_NON_NULLABLE_COLUMNS, new FixedSizeInfoField<SQLUSMALLINT>(SQL_NNC_NON_NULL));
	m_info.addField(SQL_SCROLL_CONCURRENCY, new FixedSizeInfoField<SQLUINTEGER>(0));
	m_info.addField(SQL_TXN_ISOLATION_OPTION, new FixedSizeInfoField<SQLUINTEGER>(0));

	m_info.addField(SQL_DBMS_VER, new StringInfoField("00.01.1300"));
	m_info.addField(SQL_DBMS_NAME, new StringInfoField("Simplic.CDN"));
}

void GlobalInfo::createSingletonInstance(HINSTANCE hInstance)
{
	_singletonInstance = new GlobalInfo(hInstance);
	_singletonInstance->initializeInfo();
}

void GlobalInfo::deleteSingletonInstance()
{
	if (_singletonInstance != NULL) delete _singletonInstance;
}

std::string GlobalInfo::getDriverPath() const
{
	char buf[MAX_PATH] = {0};
	GetModuleFileNameA(m_hInstance, buf, MAX_PATH);
	return std::string(buf);
}

OdbcInfoField* GlobalInfo::getInfoField(DbConnection* conn, SQLUSMALLINT type)
{
	// TODO: Support querying information from the DbConnection,
	// if any is provided to us
	return m_info.getField(type);
}
<|endoftext|>