<commit_before>#include "Pointer.h"
#include "PointerSubgraph.h"
#include "PointerAnalysis.h"

namespace dg {
namespace analysis {
namespace pta {

// nodes representing NULL, unknown memory
// and invalidated memory
PSNode NULLPTR_LOC(PSNodeType::NULL_ADDR);
PSNode *NULLPTR = &NULLPTR_LOC;
PSNode UNKNOWN_MEMLOC(PSNodeType::UNKNOWN_MEM);
PSNode *UNKNOWN_MEMORY = &UNKNOWN_MEMLOC;
PSNode INVALIDATED_LOC(PSNodeType::INVALIDATED);
PSNode *INVALIDATED = &INVALIDATED_LOC;

// pointers to those memory
const Pointer PointerUnknown(UNKNOWN_MEMORY, UNKNOWN_OFFSET);
const Pointer PointerNull(NULLPTR, 0);

// replace all pointers to given target with one
// to that target, but UNKNOWN_OFFSET
bool PSNode::addPointsToUnknownOffset(PSNode *target)
{
    bool changed = false;
    for (auto I = pointsTo.begin(), E = pointsTo.end(); I != E;) {
        auto cur = I++;

        // erase pointers to the same memory but with concrete offset
        if (cur->target == target && !cur->offset.isUnknown()) {
            pointsTo.erase(cur);
            changed = true;
        }
    }

    // DONT use addPointsTo() method, it would recursively call
    // this method again, until stack overflow
    changed |= pointsTo.insert(Pointer(target, UNKNOWN_OFFSET)).second;

    return changed;
}

bool PointerAnalysis::processLoad(PSNode *node)
{
    bool changed = false;
    PSNode *operand = node->getOperand(0);

    if (operand->pointsTo.empty())
        return error(operand, "Load's operand has no points-to set");

    for (const Pointer& ptr : operand->pointsTo) {
        if (ptr.isNull())
            continue;

        // find memory objects holding relevant points-to
        // information
        std::vector<MemoryObject *> objects;
        getMemoryObjects(node, ptr, objects);

        // no objects found for this target? That is
        // load from unknown memory
        if (objects.empty()) {
            if (ptr.target->isZeroInitialized())
                // if the memory is zero initialized, then everything
                // is fine, we add nullptr
                changed |= node->addPointsTo(NULLPTR);
            else
                changed |= errorEmptyPointsTo(node, ptr.target);

            continue;
        }

        for (MemoryObject *o : objects) {
            // is the offset to the memory unknown?
            // In that case everything can be referenced,
            // so we need to copy the whole points-to
            if (ptr.offset.isUnknown()) {
                // we should load from memory that has
                // no pointers in it - it may be an error
                // FIXME: don't duplicate the code
                if (o->pointsTo.empty()) {
                    if (ptr.target->isZeroInitialized())
                        changed |= node->addPointsTo(NULLPTR);
                    else if (objects.size() == 1)
                        changed |= errorEmptyPointsTo(node, ptr.target);
                }

                // we have some pointers - copy them all,
                // since the offset is unknown
                for (auto& it : o->pointsTo) {
                    for (const Pointer &p : it.second) {
                        changed |= node->addPointsTo(p);
                    }
                }

                // this is all that we can do here...
                continue;
            }

            // load from empty points-to set
            // - that is load from unknown memory
            if (!o->pointsTo.count(ptr.offset)) {
                // if the memory is zero initialized, then everything
                // is fine, we add nullptr
                if (ptr.target->isZeroInitialized())
                    changed |= node->addPointsTo(NULLPTR);
                // if we don't have a definition even with unknown offset
                // it is an error
                // FIXME: don't triplicate the code!
                else if (!o->pointsTo.count(UNKNOWN_OFFSET))
                    changed |= errorEmptyPointsTo(node, ptr.target);
            } else {
                // we have pointers on that memory, so we can
                // do the work
                for (const Pointer& memptr : o->pointsTo[ptr.offset])
                    changed |= node->addPointsTo(memptr);
            }

            // plus always add the pointers at unknown offset,
            // since these can be what we need too
            if (o->pointsTo.count(UNKNOWN_OFFSET)) {
                for (const Pointer& memptr : o->pointsTo[UNKNOWN_OFFSET]) {
                    changed |= node->addPointsTo(memptr);
                }
            }
        }
    }

    return changed;
}

bool PointerAnalysis::processMemcpy(PSNode *node)
{
    bool changed = false;

    // what to copy
    std::vector<MemoryObject *> srcObjects;
    // where to copy
    std::vector<MemoryObject *> destObjects;
    PSNode *srcNode = node->getOperand(0);
    PSNode *destNode = node->getOperand(1);

    /* if one is zero initialized and we copy it whole,
     * set the other zero initialized too */
    if ((!destNode->isZeroInitialized() && srcNode->isZeroInitialized())
        && ((*node->offset == 0 && node->len.isUnknown())
            || node->offset.isUnknown())) {
        destNode->setZeroInitialized();
        changed = true;
    }

    // gather srcNode pointer objects
    for (const Pointer& ptr : srcNode->pointsTo) {
        assert(ptr.target && "Got nullptr as target");

        if (ptr.isNull())
            continue;

        getMemoryObjects(node, ptr, srcObjects);
    }

    // gather destNode objects
    for (const Pointer& dptr : destNode->pointsTo) {
        assert(dptr.target && "Got nullptr as target");

        if (dptr.isNull())
            continue;

        getMemoryObjects(node, dptr, destObjects);
    }

    if (srcObjects.empty()){
        if (srcNode->isZeroInitialized()) {
            // if the memory is zero initialized,
            // then everything is fine, we add nullptr
            changed |= node->addPointsTo(NULLPTR);
        } else {
            changed |= errorEmptyPointsTo(node, srcNode);
        }

        return changed;
    }

    for (MemoryObject *o : destObjects) {
        // copy every pointer from srcObjects that is in
        // the range to these objects
        for (MemoryObject *so : srcObjects) {
            for (auto& src : so->pointsTo) {
                // src.first is offset, src.second is a PointToSet

                // we need to copy ptrs at UNKNOWN_OFFSET always
                if (src.first.isUnknown() || node->offset.isUnknown()) {
                    changed |= o->addPointsTo(src.first, src.second);
                    continue;
                }

                if (node->len.isUnknown()) {
                    if (*src.first < *node->offset)
                        continue;
                } else {
                    if (!src.first.inRange(*node->offset,
                                           *node->offset + *node->len - 1))
                    continue;
                }

                changed |= o->addPointsTo(src.first, src.second);
            }
        }

        // we need to take care of the case when src is zero initialized,
        // but points-to somewhere, imagine this:
        //
        // struct s { ptr1, ptr2, ptr3 };
        // struct s1 = {0}; /* s1 is zero initialized */
        // struct s1.ptr1 = &a;
        // struct s2;
        // memcpy(s1, s2, 0, 16); /* copy first two pointers */
        //
        // in this case s2 will point to 'a' at offset 0, but won't
        // point to null at offset 8, but it should... fix it by adding
        // nullptr at UNKNOWN_OFFSET (we may loose precision, but we'll
        // be sound)
        if (srcNode->isZeroInitialized()
            && !((*node->offset == 0 && node->len.isUnknown())
                 || node->offset.isUnknown()))
            // src is zeroed and we don't copy whole memory?
            changed |= o->addPointsTo(UNKNOWN_OFFSET, NULLPTR);
    }

    return changed;
}

bool PointerAnalysis::processNode(PSNode *node)
{
    bool changed = false;
    std::vector<MemoryObject *> objects;

#ifdef DEBUG_ENABLED
    size_t prev_size = node->pointsTo.size();
#endif

    switch(node->type) {
        case PSNodeType::LOAD:
            changed |= processLoad(node);
            break;
        case PSNodeType::STORE:
            for (const Pointer& ptr : node->getOperand(1)->pointsTo) {
                PSNode *target = ptr.target;
                assert(target && "Got nullptr as target");

                if (ptr.isNull())
                    continue;

                objects.clear();
                getMemoryObjects(node, ptr, objects);
                for (MemoryObject *o : objects) {
                    for (const Pointer& to : node->getOperand(0)->pointsTo) {
                        changed |= o->addPointsTo(ptr.offset, to);
                    }
                }
            }
            break;
        case PSNodeType::FREE:
            for (const Pointer& ptr : node->getOperand(0)->pointsTo) {
                PSNode *target = ptr.target;
                assert(target && "Got nullptr as target");

                if (ptr.isNull())
                    continue;

                objects.clear();
                getMemoryObjectsPointingTo(node, ptr, objects);
                for (MemoryObject *o : objects) {
                    changed |= o->addPointsTo(UNKNOWN_OFFSET, INVALIDATED);
                }
            }
            break;
        case PSNodeType::INVALIDATE_LOCALS:
            node->setParent(node->getOperand(0)->getSingleSuccessor()->getParent());
            objects.clear();
            getLocalMemoryObjects(node, objects);
            for (MemoryObject *o : objects) {
                changed |= o->addPointsTo(UNKNOWN_OFFSET, INVALIDATED);
            }
            break;
        case PSNodeType::GEP:
            for (const Pointer& ptr : node->getOperand(0)->pointsTo) {
                uint64_t new_offset;
                if (ptr.offset.isUnknown() || node->offset.isUnknown())
                    // set it like this to avoid overflow when adding
                    new_offset = UNKNOWN_OFFSET;
                else
                    new_offset = *ptr.offset + *node->offset;

                // in the case PSNodeType::the memory has size 0, then every pointer
                // will have unknown offset with the exception that it points
                // to the begining of the memory - therefore make 0 exception
                if ((new_offset == 0 || new_offset < ptr.target->getSize())
                    && new_offset < max_offset)
                    changed |= node->addPointsTo(ptr.target, new_offset);
                else
                    changed |= node->addPointsToUnknownOffset(ptr.target);
            }
            break;
        case PSNodeType::CAST:
            // cast only copies the pointers
            for (const Pointer& ptr : node->getOperand(0)->pointsTo)
                changed |= node->addPointsTo(ptr);
            break;
        case PSNodeType::CONSTANT:
            // maybe warn? It has no sense to insert the constants into the graph.
            // On the other hand it is harmless. We can at least check if it is
            // correctly initialized 8-)
            assert(node->pointsTo.size() == 1
                   && "Constant should have exactly one pointer");
            break;
        case PSNodeType::CALL_RETURN:
            if (invalidate_nodes) {
                for (PSNode *op : node->operands) {
                    for (const Pointer& ptr : op->pointsTo) {
                        if (!ptr.target->isHeap() && !ptr.target->isGlobal())
                            changed |= node->addPointsTo(INVALIDATED);
                    }
                }
            }
            // fall-through
        case PSNodeType::RETURN:
            // gather pointers returned from subprocedure - the same way
            // as PHI works
        case PSNodeType::PHI:
            for (PSNode *op : node->operands)
                changed |= node->addPointsTo(op->pointsTo);
            break;
        case PSNodeType::CALL_FUNCPTR:
            // call via function pointer:
            // first gather the pointers that can be used to the
            // call and if something changes, let backend take some action
            // (for example build relevant subgraph)
            for (const Pointer& ptr : node->getOperand(0)->pointsTo) {
                if (node->addPointsTo(ptr)) {
                    changed = true;

                    if (ptr.isValid() && !ptr.isInvalidated()) {
                        functionPointerCall(node, ptr.target);
                    } else {
                        error(node, "Calling invalid pointer as a function!");
                        continue;
                    }
                }
            }
            break;
        case PSNodeType::MEMCPY:
            changed |= processMemcpy(node);
            break;
        case PSNodeType::ALLOC:
        case PSNodeType::DYN_ALLOC:
        case PSNodeType::FUNCTION:
            // these two always points to itself
            assert(node->doesPointsTo(node, 0));
            assert(node->pointsTo.size() == 1);
        case PSNodeType::CALL:
        case PSNodeType::ENTRY:
        case PSNodeType::NOOP:
            // just no op
            break;
        default:
            assert(0 && "Unknown type");
    }

#ifdef DEBUG_ENABLED
    // the change of points-to set is not the only
    // change that can happen, so we don't use it as an
    // indicator and we use the 'changed' variable instead.
    // However, this assertion must hold:
    assert((node->pointsTo.size() == prev_size || changed)
           && "BUG: Did not set change but changed points-to sets");
#endif

    return changed;
}

} // namespace pta
} // namespace analysis
} // namespace dg
<commit_msg>load node has unknown pointer info<commit_after>#include "Pointer.h"
#include "PointerSubgraph.h"
#include "PointerAnalysis.h"

namespace dg {
namespace analysis {
namespace pta {

// nodes representing NULL, unknown memory
// and invalidated memory
PSNode NULLPTR_LOC(PSNodeType::NULL_ADDR);
PSNode *NULLPTR = &NULLPTR_LOC;
PSNode UNKNOWN_MEMLOC(PSNodeType::UNKNOWN_MEM);
PSNode *UNKNOWN_MEMORY = &UNKNOWN_MEMLOC;
PSNode INVALIDATED_LOC(PSNodeType::INVALIDATED);
PSNode *INVALIDATED = &INVALIDATED_LOC;

// pointers to those memory
const Pointer PointerUnknown(UNKNOWN_MEMORY, UNKNOWN_OFFSET);
const Pointer PointerNull(NULLPTR, 0);

// replace all pointers to given target with one
// to that target, but UNKNOWN_OFFSET
bool PSNode::addPointsToUnknownOffset(PSNode *target)
{
    bool changed = false;
    for (auto I = pointsTo.begin(), E = pointsTo.end(); I != E;) {
        auto cur = I++;

        // erase pointers to the same memory but with concrete offset
        if (cur->target == target && !cur->offset.isUnknown()) {
            pointsTo.erase(cur);
            changed = true;
        }
    }

    // DONT use addPointsTo() method, it would recursively call
    // this method again, until stack overflow
    changed |= pointsTo.insert(Pointer(target, UNKNOWN_OFFSET)).second;

    return changed;
}

bool PointerAnalysis::processLoad(PSNode *node)
{
    bool changed = false;
    PSNode *operand = node->getOperand(0);

    if (operand->pointsTo.empty())
        return error(operand, "Load's operand has no points-to set");

    for (const Pointer& ptr : operand->pointsTo) {
        if (ptr.isNull())
            continue;

        if (ptr.isUnknown()) {
            changed |= node->addPointsTo(UNKNOWN_MEMORY, UNKNOWN_OFFSET);
            continue;
        }

        // find memory objects holding relevant points-to
        // information
        std::vector<MemoryObject *> objects;
        getMemoryObjects(node, ptr, objects);

        // no objects found for this target? That is
        // load from unknown memory
        if (objects.empty()) {
            if (ptr.target->isZeroInitialized())
                // if the memory is zero initialized, then everything
                // is fine, we add nullptr
                changed |= node->addPointsTo(NULLPTR);
            else
                changed |= errorEmptyPointsTo(node, ptr.target);

            continue;
        }

        for (MemoryObject *o : objects) {
            // is the offset to the memory unknown?
            // In that case everything can be referenced,
            // so we need to copy the whole points-to
            if (ptr.offset.isUnknown()) {
                // we should load from memory that has
                // no pointers in it - it may be an error
                // FIXME: don't duplicate the code
                if (o->pointsTo.empty()) {
                    if (ptr.target->isZeroInitialized())
                        changed |= node->addPointsTo(NULLPTR);
                    else if (objects.size() == 1)
                        changed |= errorEmptyPointsTo(node, ptr.target);
                }

                // we have some pointers - copy them all,
                // since the offset is unknown
                for (auto& it : o->pointsTo) {
                    for (const Pointer &p : it.second) {
                        changed |= node->addPointsTo(p);
                    }
                }

                // this is all that we can do here...
                continue;
            }

            // load from empty points-to set
            // - that is load from unknown memory
            if (!o->pointsTo.count(ptr.offset)) {
                // if the memory is zero initialized, then everything
                // is fine, we add nullptr
                if (ptr.target->isZeroInitialized())
                    changed |= node->addPointsTo(NULLPTR);
                // if we don't have a definition even with unknown offset
                // it is an error
                // FIXME: don't triplicate the code!
                else if (!o->pointsTo.count(UNKNOWN_OFFSET))
                    changed |= errorEmptyPointsTo(node, ptr.target);
            } else {
                // we have pointers on that memory, so we can
                // do the work
                for (const Pointer& memptr : o->pointsTo[ptr.offset])
                    changed |= node->addPointsTo(memptr);
            }

            // plus always add the pointers at unknown offset,
            // since these can be what we need too
            if (o->pointsTo.count(UNKNOWN_OFFSET)) {
                for (const Pointer& memptr : o->pointsTo[UNKNOWN_OFFSET]) {
                    changed |= node->addPointsTo(memptr);
                }
            }
        }
    }

    return changed;
}

bool PointerAnalysis::processMemcpy(PSNode *node)
{
    bool changed = false;

    // what to copy
    std::vector<MemoryObject *> srcObjects;
    // where to copy
    std::vector<MemoryObject *> destObjects;
    PSNode *srcNode = node->getOperand(0);
    PSNode *destNode = node->getOperand(1);

    /* if one is zero initialized and we copy it whole,
     * set the other zero initialized too */
    if ((!destNode->isZeroInitialized() && srcNode->isZeroInitialized())
        && ((*node->offset == 0 && node->len.isUnknown())
            || node->offset.isUnknown())) {
        destNode->setZeroInitialized();
        changed = true;
    }

    // gather srcNode pointer objects
    for (const Pointer& ptr : srcNode->pointsTo) {
        assert(ptr.target && "Got nullptr as target");

        if (ptr.isNull())
            continue;

        getMemoryObjects(node, ptr, srcObjects);
    }

    // gather destNode objects
    for (const Pointer& dptr : destNode->pointsTo) {
        assert(dptr.target && "Got nullptr as target");

        if (dptr.isNull())
            continue;

        getMemoryObjects(node, dptr, destObjects);
    }

    if (srcObjects.empty()){
        if (srcNode->isZeroInitialized()) {
            // if the memory is zero initialized,
            // then everything is fine, we add nullptr
            changed |= node->addPointsTo(NULLPTR);
        } else {
            changed |= errorEmptyPointsTo(node, srcNode);
        }

        return changed;
    }

    for (MemoryObject *o : destObjects) {
        // copy every pointer from srcObjects that is in
        // the range to these objects
        for (MemoryObject *so : srcObjects) {
            for (auto& src : so->pointsTo) {
                // src.first is offset, src.second is a PointToSet

                // we need to copy ptrs at UNKNOWN_OFFSET always
                if (src.first.isUnknown() || node->offset.isUnknown()) {
                    changed |= o->addPointsTo(src.first, src.second);
                    continue;
                }

                if (node->len.isUnknown()) {
                    if (*src.first < *node->offset)
                        continue;
                } else {
                    if (!src.first.inRange(*node->offset,
                                           *node->offset + *node->len - 1))
                    continue;
                }

                changed |= o->addPointsTo(src.first, src.second);
            }
        }

        // we need to take care of the case when src is zero initialized,
        // but points-to somewhere, imagine this:
        //
        // struct s { ptr1, ptr2, ptr3 };
        // struct s1 = {0}; /* s1 is zero initialized */
        // struct s1.ptr1 = &a;
        // struct s2;
        // memcpy(s1, s2, 0, 16); /* copy first two pointers */
        //
        // in this case s2 will point to 'a' at offset 0, but won't
        // point to null at offset 8, but it should... fix it by adding
        // nullptr at UNKNOWN_OFFSET (we may loose precision, but we'll
        // be sound)
        if (srcNode->isZeroInitialized()
            && !((*node->offset == 0 && node->len.isUnknown())
                 || node->offset.isUnknown()))
            // src is zeroed and we don't copy whole memory?
            changed |= o->addPointsTo(UNKNOWN_OFFSET, NULLPTR);
    }

    return changed;
}

bool PointerAnalysis::processNode(PSNode *node)
{
    bool changed = false;
    std::vector<MemoryObject *> objects;

#ifdef DEBUG_ENABLED
    size_t prev_size = node->pointsTo.size();
#endif

    switch(node->type) {
        case PSNodeType::LOAD:
            changed |= processLoad(node);
            break;
        case PSNodeType::STORE:
            for (const Pointer& ptr : node->getOperand(1)->pointsTo) {
                PSNode *target = ptr.target;
                assert(target && "Got nullptr as target");

                if (ptr.isNull())
                    continue;

                objects.clear();
                getMemoryObjects(node, ptr, objects);
                for (MemoryObject *o : objects) {
                    for (const Pointer& to : node->getOperand(0)->pointsTo) {
                        changed |= o->addPointsTo(ptr.offset, to);
                    }
                }
            }
            break;
        case PSNodeType::FREE:
            for (const Pointer& ptr : node->getOperand(0)->pointsTo) {
                PSNode *target = ptr.target;
                assert(target && "Got nullptr as target");

                if (ptr.isNull())
                    continue;

                objects.clear();
                getMemoryObjectsPointingTo(node, ptr, objects);
                for (MemoryObject *o : objects) {
                    changed |= o->addPointsTo(UNKNOWN_OFFSET, INVALIDATED);
                }
            }
            break;
        case PSNodeType::INVALIDATE_LOCALS:
            node->setParent(node->getOperand(0)->getSingleSuccessor()->getParent());
            objects.clear();
            getLocalMemoryObjects(node, objects);
            for (MemoryObject *o : objects) {
                changed |= o->addPointsTo(UNKNOWN_OFFSET, INVALIDATED);
            }
            break;
        case PSNodeType::GEP:
            for (const Pointer& ptr : node->getOperand(0)->pointsTo) {
                uint64_t new_offset;
                if (ptr.offset.isUnknown() || node->offset.isUnknown())
                    // set it like this to avoid overflow when adding
                    new_offset = UNKNOWN_OFFSET;
                else
                    new_offset = *ptr.offset + *node->offset;

                // in the case PSNodeType::the memory has size 0, then every pointer
                // will have unknown offset with the exception that it points
                // to the begining of the memory - therefore make 0 exception
                if ((new_offset == 0 || new_offset < ptr.target->getSize())
                    && new_offset < max_offset)
                    changed |= node->addPointsTo(ptr.target, new_offset);
                else
                    changed |= node->addPointsToUnknownOffset(ptr.target);
            }
            break;
        case PSNodeType::CAST:
            // cast only copies the pointers
            for (const Pointer& ptr : node->getOperand(0)->pointsTo)
                changed |= node->addPointsTo(ptr);
            break;
        case PSNodeType::CONSTANT:
            // maybe warn? It has no sense to insert the constants into the graph.
            // On the other hand it is harmless. We can at least check if it is
            // correctly initialized 8-)
            assert(node->pointsTo.size() == 1
                   && "Constant should have exactly one pointer");
            break;
        case PSNodeType::CALL_RETURN:
            if (invalidate_nodes) {
                for (PSNode *op : node->operands) {
                    for (const Pointer& ptr : op->pointsTo) {
                        if (!ptr.target->isHeap() && !ptr.target->isGlobal())
                            changed |= node->addPointsTo(INVALIDATED);
                    }
                }
            }
            // fall-through
        case PSNodeType::RETURN:
            // gather pointers returned from subprocedure - the same way
            // as PHI works
        case PSNodeType::PHI:
            for (PSNode *op : node->operands)
                changed |= node->addPointsTo(op->pointsTo);
            break;
        case PSNodeType::CALL_FUNCPTR:
            // call via function pointer:
            // first gather the pointers that can be used to the
            // call and if something changes, let backend take some action
            // (for example build relevant subgraph)
            for (const Pointer& ptr : node->getOperand(0)->pointsTo) {
                if (node->addPointsTo(ptr)) {
                    changed = true;

                    if (ptr.isValid() && !ptr.isInvalidated()) {
                        functionPointerCall(node, ptr.target);
                    } else {
                        error(node, "Calling invalid pointer as a function!");
                        continue;
                    }
                }
            }
            break;
        case PSNodeType::MEMCPY:
            changed |= processMemcpy(node);
            break;
        case PSNodeType::ALLOC:
        case PSNodeType::DYN_ALLOC:
        case PSNodeType::FUNCTION:
            // these two always points to itself
            assert(node->doesPointsTo(node, 0));
            assert(node->pointsTo.size() == 1);
        case PSNodeType::CALL:
        case PSNodeType::ENTRY:
        case PSNodeType::NOOP:
            // just no op
            break;
        default:
            assert(0 && "Unknown type");
    }

#ifdef DEBUG_ENABLED
    // the change of points-to set is not the only
    // change that can happen, so we don't use it as an
    // indicator and we use the 'changed' variable instead.
    // However, this assertion must hold:
    assert((node->pointsTo.size() == prev_size || changed)
           && "BUG: Did not set change but changed points-to sets");
#endif

    return changed;
}

} // namespace pta
} // namespace analysis
} // namespace dg
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
 */

#include "config.h"
#include "ConstructData.h"
#ifdef QT_BUILD_SCRIPT_LIB
#include "ExceptionHelpers.h"
#include "Interpreter.h"
#include "JSGlobalObject.h"
#endif

#include "JSFunction.h"

namespace JSC {

JSObject* construct(ExecState* exec, JSValue callee, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
{
    if (constructType == ConstructTypeHost) {
#ifdef QT_BUILD_SCRIPT_LIB
        Structure* structure;
        JSValue prototype = callee.get(exec, exec->propertyNames().prototype);
        if (prototype.isObject())
            structure = asObject(prototype)->inheritorID();
        else
            structure = exec->lexicalGlobalObject()->emptyObjectStructure();
        JSObject* thisObj = new (exec) JSObject(structure);

        ScopeChainNode* scopeChain = exec->scopeChain();
        Interpreter *interp = exec->interpreter();
        Register *oldEnd = interp->registerFile().end();
        int argc = 1 + args.size(); // implicit "this" parameter
        if (!interp->registerFile().grow(oldEnd + argc + RegisterFile::CallFrameHeaderSize))
            return asObject(createStackOverflowError(exec));
        CallFrame* newCallFrame = CallFrame::create(oldEnd);
        size_t dst = 0;
        newCallFrame[0] = JSValue(thisObj);
        ArgList::const_iterator it;
        for (it = args.begin(); it != args.end(); ++it)
            newCallFrame[++dst] = *it;
        newCallFrame += argc + RegisterFile::CallFrameHeaderSize;
        newCallFrame->init(0, /*vPC=*/0, scopeChain, exec, 0, argc, asObject(callee));
        JSObject *result = constructData.native.function(newCallFrame, asObject(callee), args);
        interp->registerFile().shrink(oldEnd);
        return result;
#else
        return constructData.native.function(exec, asObject(object), args);
#endif
    }
    ASSERT(constructType == ConstructTypeJS);
    // FIXME: Can this be done more efficiently using the constructData?
    return asFunction(callee)->construct(exec, args);
}

} // namespace JSC
<commit_msg>construct a QScriptObject instead of a JSObject<commit_after>/*
 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
 */

#include "config.h"
#include "ConstructData.h"
#ifdef QT_BUILD_SCRIPT_LIB
#include "ExceptionHelpers.h"
#include "Interpreter.h"
#include "JSGlobalObject.h"
#include "bridge/qscriptobject_p.h"
#endif

#include "JSFunction.h"

namespace JSC {

JSObject* construct(ExecState* exec, JSValue callee, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
{
    if (constructType == ConstructTypeHost) {
#ifdef QT_BUILD_SCRIPT_LIB
        Structure* structure;
        JSValue prototype = callee.get(exec, exec->propertyNames().prototype);
        if (prototype.isObject())
            structure = asObject(prototype)->inheritorID();
        else
            structure = exec->lexicalGlobalObject()->emptyObjectStructure();
        JSObject* thisObj = new (exec) QScriptObject(structure);

        ScopeChainNode* scopeChain = exec->scopeChain();
        Interpreter *interp = exec->interpreter();
        Register *oldEnd = interp->registerFile().end();
        int argc = 1 + args.size(); // implicit "this" parameter
        if (!interp->registerFile().grow(oldEnd + argc + RegisterFile::CallFrameHeaderSize))
            return asObject(createStackOverflowError(exec));
        CallFrame* newCallFrame = CallFrame::create(oldEnd);
        size_t dst = 0;
        newCallFrame[0] = JSValue(thisObj);
        ArgList::const_iterator it;
        for (it = args.begin(); it != args.end(); ++it)
            newCallFrame[++dst] = *it;
        newCallFrame += argc + RegisterFile::CallFrameHeaderSize;
        newCallFrame->init(0, /*vPC=*/0, scopeChain, exec, 0, argc, asObject(callee));
        JSObject *result = constructData.native.function(newCallFrame, asObject(callee), args);
        if (!result)
            result = thisObj;
        interp->registerFile().shrink(oldEnd);
        return result;
#else
        return constructData.native.function(exec, asObject(object), args);
#endif
    }
    ASSERT(constructType == ConstructTypeJS);
    // FIXME: Can this be done more efficiently using the constructData?
    return asFunction(callee)->construct(exec, args);
}

} // namespace JSC
<|endoftext|>


<commit_before>/* Copyright 2007-2015 QReal Research Group
 *
 * Licensed 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 "miscellaniousPage.h"
#include "ui_miscellaniousPage.h"

#include <qrkernel/settingsManager.h>
#include <qrutils/widgets/qRealFileDialog.h>

using namespace qReal;

PreferencesMiscellaniousPage::PreferencesMiscellaniousPage(QWidget *parent)
		: PreferencesPage(parent)
		, mUi(new Ui::PreferencesMiscellaniousPage)
{
	mUi->setupUi(this);
	setObjectName("preferencesMiscellaniousPage");
	setWindowIcon(QIcon(":/preferencesDialog/images/miscellaneous.png"));

	connect(mUi->imagesPathBrowseButton, SIGNAL(clicked()), this, SLOT(browseImagesPath()));
	connect(mUi->toolbarSizeSlider, &QSlider::valueChanged
			, [=](int value ) { SettingsManager::setValue("toolbarSize", value); });

	restoreSettings();
}

PreferencesMiscellaniousPage::~PreferencesMiscellaniousPage()
{
	delete mUi;
}

void PreferencesMiscellaniousPage::changeEvent(QEvent *e)
{
	switch (e->type()) {
	case QEvent::LanguageChange:
		mUi->retranslateUi(this);
		break;
	default:
		break;
	}
}

void PreferencesMiscellaniousPage::browseImagesPath()
{
	const QString path = utils::QRealFileDialog::getExistingDirectory("OpenImagesOnMiscellaniousPage"
			, this, tr("Open Directory")).replace("\\", "/");
	if (!path.isEmpty()) {
		mUi->imagesPathEdit->setText(path);
	}
}

void PreferencesMiscellaniousPage::save()
{
	SettingsManager::setValue("Splashscreen", mUi->splashScreenCheckBox->isChecked());
	SettingsManager::setValue("Antialiasing", mUi->antialiasingCheckBox->isChecked());

	SettingsManager::setValue("pathToImages", mUi->imagesPathEdit->text());
	SettingsManager::setValue("recentProjectsLimit", mUi->recentProjectsLimitSpinBox->value());

	SettingsManager::setValue("toolbarSize", mUi->toolbarSizeSlider->value());
}

void PreferencesMiscellaniousPage::restoreSettings()
{
	mUi->antialiasingCheckBox->setChecked(SettingsManager::value("Antialiasing").toBool());
	mUi->splashScreenCheckBox->setChecked(SettingsManager::value("Splashscreen").toBool());

	mUi->toolbarSizeSlider->setValue(SettingsManager::value("toolbarSize").toInt());

	mUi->imagesPathEdit->setText(SettingsManager::value("pathToImages").toString());
}
<commit_msg>fix missed save step in miscellanious page<commit_after>/* Copyright 2007-2015 QReal Research Group
 *
 * Licensed 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 "miscellaniousPage.h"
#include "ui_miscellaniousPage.h"

#include <qrkernel/settingsManager.h>
#include <qrutils/widgets/qRealFileDialog.h>

using namespace qReal;

PreferencesMiscellaniousPage::PreferencesMiscellaniousPage(QWidget *parent)
		: PreferencesPage(parent)
		, mUi(new Ui::PreferencesMiscellaniousPage)
{
	mUi->setupUi(this);
	setObjectName("preferencesMiscellaniousPage");
	setWindowIcon(QIcon(":/preferencesDialog/images/miscellaneous.png"));

	connect(mUi->imagesPathBrowseButton, SIGNAL(clicked()), this, SLOT(browseImagesPath()));
	connect(mUi->toolbarSizeSlider, &QSlider::valueChanged
			, [=](int value ) { SettingsManager::setValue("toolbarSize", value); });

	restoreSettings();
}

PreferencesMiscellaniousPage::~PreferencesMiscellaniousPage()
{
	delete mUi;
}

void PreferencesMiscellaniousPage::changeEvent(QEvent *e)
{
	switch (e->type()) {
	case QEvent::LanguageChange:
		mUi->retranslateUi(this);
		break;
	default:
		break;
	}
}

void PreferencesMiscellaniousPage::browseImagesPath()
{
	const QString path = utils::QRealFileDialog::getExistingDirectory("OpenImagesOnMiscellaniousPage"
			, this, tr("Open Directory")).replace("\\", "/");
	if (!path.isEmpty()) {
		mUi->imagesPathEdit->setText(path);
	}
}

void PreferencesMiscellaniousPage::save()
{
	SettingsManager::setValue("Splashscreen", mUi->splashScreenCheckBox->isChecked());
	SettingsManager::setValue("Antialiasing", mUi->antialiasingCheckBox->isChecked());

	SettingsManager::setValue("pathToImages", mUi->imagesPathEdit->text());
	SettingsManager::setValue("recentProjectsLimit", mUi->recentProjectsLimitSpinBox->value());

	SettingsManager::setValue("toolbarSize", mUi->toolbarSizeSlider->value());
}

void PreferencesMiscellaniousPage::restoreSettings()
{
	mUi->antialiasingCheckBox->setChecked(SettingsManager::value("Antialiasing").toBool());
	mUi->splashScreenCheckBox->setChecked(SettingsManager::value("Splashscreen").toBool());

	mUi->recentProjectsLimitSpinBox->setValue(SettingsManager::value("recentProjectsLimit").toInt());

	mUi->toolbarSizeSlider->setValue(SettingsManager::value("toolbarSize").toInt());

	mUi->imagesPathEdit->setText(SettingsManager::value("pathToImages").toString());
}
<|endoftext|>


<commit_before>/**
 * @file kernelpca_impl.hpp
 * @author Ajinkya Kale
 *
 * Implementation of KernelPCA class to perform Kernel Principal Components
 * Analysis on the specified data set.
 */
#ifndef __MLPACK_METHODS_KERNEL_PCA_KERNEL_PCA_IMPL_HPP
#define __MLPACK_METHODS_KERNEL_PCA_KERNEL_PCA_IMPL_HPP

// In case it hasn't already been included.
#include "kernel_pca.hpp"

#include <iostream>

using namespace std; // This'll have to go before the release.

namespace mlpack {
namespace kpca {

template <typename KernelType>
KernelPCA<KernelType>::KernelPCA(const KernelType kernel,
                       const bool centerData,
                       const bool scaleData) :
      kernel(kernel),
      centerData(centerData),
      scaleData(scaleData)
{
}

/**
 * Apply Kernel Principal Component Analysis to the provided data set.
 *
 * @param data - Data matrix
 * @param transformedData - Data with KernelPCA applied
 * @param eigVal - contains eigen values in a column vector
 * @param coeff - KernelPCA Loadings/Coeffs/EigenVectors
 */
template <typename KernelType>
void KernelPCA<KernelType>::Apply(const arma::mat& data,
                                  arma::mat& transformedData,
                                  arma::vec& eigVal,
                                  arma::mat& coeffs)
{
  arma::mat transData = trans(data);

  if (centerData)
  {
    arma::rowvec means = arma::mean(transData, 0);
    transData = transData - arma::ones<arma::colvec>(transData.n_rows) * means;
    cout << "centering data" << endl;
  }
  transData.print("TRANSDATA");
  arma::mat centeredData = trans(transData);

  arma::mat kernelMat(centeredData.n_rows, centeredData.n_rows);

  for (size_t i = 0; i < centeredData.n_rows; i++)
  {
    for (size_t j = 0; j < centeredData.n_rows; j++)
    {
      arma::vec v1 = trans(centeredData.row(i));
      arma::vec v2 = trans(centeredData.row(j));
      kernelMat(i, j) = kernel.Evaluate(v1, v2);
    }
  }

  kernelMat.print("KERNEL MATRIX : ");
  arma::mat matCov = (cov(centeredData));
  matCov.print("COV MATRIX : ");

  transData = kernelMat; // Use the kernel matrix to do the transformations
  // after this point.

  if (scaleData)
  {
    transData = transData / (arma::ones<arma::colvec>(transData.n_rows) *
        stddev(transData, 0, 0));
  }

  arma::mat covMat = cov(transData);
  arma::eig_sym(eigVal, coeffs, covMat);

  int nEigVal = eigVal.n_elem;
  for(int i = 0; i < floor(nEigVal / 2); i++)
    eigVal.swap_rows(i, (nEigVal - 1) - i);

  coeffs = arma::fliplr(coeffs);
  transformedData = trans(coeffs) * data;
  arma::colvec transformedDataMean = arma::mean(transformedData, 1);
  transformedData = transformedData - (transformedDataMean *
      arma::ones<arma::rowvec>(transformedData.n_cols));
}

/**
 * Apply Kernel Principal Component Analysis to the provided data set.
 *
 * @param data - Data matrix
 * @param transformedData - Data with KernelPCA applied
 * @param eigVal - contains eigen values in a column vector
 */
template <typename KernelType>
void KernelPCA<KernelType>::Apply(const arma::mat& data,
                                  arma::mat& transformedData,
                                  arma::vec& eigVal)
{
  arma::mat coeffs;
  Apply(data, transformedData, eigVal, coeffs);
}

/**
 * Apply Dimensionality Reduction using Kernel Principal Component Analysis
 * to the provided data set.
 *
 * @param data - M x N Data matrix
 * @param newDimension - matrix consisting of N column vectors,
 * where each vector is the projection of the corresponding data vector
 * from data matrix onto the basis vectors contained in the columns of
 * coeff/eigen vector matrix with only newDimension number of columns chosen.
 */
template <typename KernelType>
void KernelPCA<KernelType>::Apply(arma::mat& data, const size_t newDimension)
{
  arma::mat coeffs;
  arma::vec eigVal;

  Apply(data, data, eigVal, coeffs);

  if (newDimension < coeffs.n_rows && newDimension > 0)
    data.shed_rows(newDimension, data.n_rows - 1);
}

}; // namespace mlpack
}; // namespace kpca

#endif
<commit_msg>kernel pca works with linear Kernel now.<commit_after>/**
 * @file kernel_pca_impl.hpp
 * @author Ajinkya Kale
 *
 * Implementation of KPCA class to perform Kernel Principal Components Analysis on the
 * specified data set.
 */
#include "kpca.hpp"
#include <iostream>
#include <cmath>

using namespace std;
namespace mlpack {
namespace kpca {

template <typename KernelType>
KPCA<KernelType>::KPCA(const KernelType kernel,
                       const bool centerData,
                       const bool scaleData) :
      kernel_(kernel),
      centerData_(centerData),
      scaleData_(scaleData)
{
}

/**
 * Apply Kernel Principal Component Analysis to the provided data set.
 *
 * @param data - Data matrix
 * @param transformedData - Data with KPCA applied
 * @param eigVal - contains eigen values in a column vector
 * @param coeff - KPCA Loadings/Coeffs/EigenVectors
 */
template <typename KernelType>
void KPCA<KernelType>::Apply(const arma::mat& data, arma::mat& transformedData,
           arma::vec& eigVal, arma::mat& coeffs)
{
  arma::mat transData = trans(data);

  if(centerData_)
  {
    arma::rowvec means = arma::mean(transData, 0);
    transData = transData - arma::ones<arma::colvec>(transData.n_rows) * means;
  }
  arma::mat centeredData = trans(transData);
  arma::mat kernelMat = GetKernelMatrix(kernel_, centeredData);
  arma::eig_sym(eigVal, coeffs, kernelMat);

  int n_eigVal = eigVal.n_elem;
  for(int i = 0; i < floor(n_eigVal / 2); i++)
    eigVal.swap_rows(i, (n_eigVal - 1) - i);

  coeffs = arma::fliplr(coeffs);

  transformedData = trans(coeffs) * data;
  arma::colvec transformedDataMean = arma::mean(transformedData, 1);
  transformedData = transformedData - (transformedDataMean * arma::ones<arma::rowvec>(transformedData.n_cols));
}

/**
 * Apply Kernel Principal Component Analysis to the provided data set.
 *
 * @param data - Data matrix
 * @param transformedData - Data with KPCA applied
 * @param eigVal - contains eigen values in a column vector
 */
template <typename KernelType>
void KPCA<KernelType>::Apply(const arma::mat& data, arma::mat& transformedData,
           arma::vec& eigVal)
{
  arma::mat coeffs;
  Apply(data, transformedData,
              eigVal, coeffs);
}

/**
 * Apply Dimensionality Reduction using Kernel Principal Component Analysis
 * to the provided data set.
 *
 * @param data - M x N Data matrix
 * @param newDimension - matrix consisting of N column vectors,
 * where each vector is the projection of the corresponding data vector
 * from data matrix onto the basis vectors contained in the columns of
 * coeff/eigen vector matrix with only newDimension number of columns chosen.
 */
template <typename KernelType>
void KPCA<KernelType>::Apply(arma::mat& data, const int newDimension)
{
  arma::mat coeffs;
  arma::vec eigVal;

  Apply(data, data, eigVal, coeffs);

  if(newDimension < coeffs.n_rows && newDimension > 0)
    data.shed_rows(newDimension, data.n_rows - 1);
}

/*template <typename KernelType>
KPCA<KernelType>::~KPCA()
{
}*/

}; // namespace mlpack
}; // namespace kpca

template <typename KernelType>
arma::mat GetKernelMatrix(KernelType kernel, arma::mat transData)
{
  arma::mat kernelMat(transData.n_rows, transData.n_rows);

  for(int i = 0; i < transData.n_rows; i++)
  {
    for(int j = 0; j < transData.n_rows; j++)
    {
      arma::vec v1 = trans(transData.row(i));
      arma::vec v2 = trans(transData.row(j));
      kernelMat(i, j) = kernel.Evaluate(v1, v2);
    }
  }
  return kernelMat;
}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2016-2017 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "appleseedtranslator.h"

// appleseed-maya headers.
#include "appleseedmaya/appleseedsession.h"
#include "appleseedmaya/logger.h"

// appleseed.foundation headers.
#include "foundation/utility/string.h"

// Maya headers.
#include "appleseedmaya/_beginmayaheaders.h"
#include <maya/MCommonRenderSettingsData.h>
#include <maya/MRenderUtil.h>
#include "appleseedmaya/_endmayaheaders.h"

// Standard headers.
#include <cstdlib>
#include <string>
#include <vector>

namespace asf = foundation;

const MString AppleseedTranslator::translatorName("appleseed");

AppleseedTranslator::AppleseedTranslator()
{
}

void* AppleseedTranslator::creator()
{
    return new AppleseedTranslator();
}

MString AppleseedTranslator::defaultExtension() const
{
    return "appleseed";
}

MStatus AppleseedTranslator::writer(
    const MFileObject&                  file,
    const MString&                      opts,
    MPxFileTranslator::FileAccessMode   mode)
{
    RENDERER_LOG_DEBUG("AppleseedTranslator::write called, options = %s", opts.asChar());

    AppleseedSession::Options options;

    // Parse the options string.
    std::vector<std::string> tokens;
    asf::tokenize(
        asf::trim_both(opts.asChar()),
        ";",
        tokens);

    std::vector<std::string> optNameValue;
    for(size_t i = 0, e = tokens.size(); i < e; ++i)
    {
        optNameValue.clear();
        asf::tokenize(
            asf::trim_both(tokens[i]),
            "=",
            optNameValue);

        if (optNameValue.size() == 2)
        {
            if (optNameValue[0] == "activeCamera")
                options.m_camera = optNameValue[1].c_str();
            else if (optNameValue[0] == "exportAnim")
                options.m_sequence = (optNameValue[1] == "true");
            else if (optNameValue[0] == "startFrame")
                options.m_firstFrame = atoi(optNameValue[1].c_str());
            else if (optNameValue[0] == "endFrame")
                options.m_lastFrame = atoi(optNameValue[1].c_str());
            else if (optNameValue[0] == "stepFrame")
                options.m_frameStep = atoi(optNameValue[1].c_str());
            else
            {
                RENDERER_LOG_WARNING(
                    "Unknown option %s in appleseed translator.", tokens[i].c_str());
            }
        }
        else
        {
            RENDERER_LOG_WARNING(
                "Bad option %s in appleseed translator.", tokens[i].c_str());
        }
    }

    if (MPxFileTranslator::kExportAccessMode == mode)
        options.m_selectionOnly = false;
    else if (MPxFileTranslator::kExportActiveAccessMode == mode)
        options.m_selectionOnly = true;

    // Get width and height from render globals.
    MCommonRenderSettingsData renderSettings;
    MRenderUtil::getCommonRenderSettings(renderSettings);
    options.m_width = renderSettings.width;
    options.m_height = renderSettings.height;

    // Export the scene.
    return AppleseedSession::projectExport(file.fullName(), options);
}

bool AppleseedTranslator::haveWriteMethod() const
{
    return true;
}
<commit_msg>Cleanup when exporting packed projects.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2016-2017 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "appleseedtranslator.h"

// appleseed-maya headers.
#include "appleseedmaya/appleseedsession.h"
#include "appleseedmaya/logger.h"

// appleseed.foundation headers.
#include "foundation/utility/string.h"

// Maya headers.
#include "appleseedmaya/_beginmayaheaders.h"
#include <maya/MCommonRenderSettingsData.h>
#include <maya/MRenderUtil.h>
#include "appleseedmaya/_endmayaheaders.h"

// Boost headers.
#include "boost/filesystem/path.hpp"
#include "boost/filesystem/convenience.hpp"
#include "boost/filesystem/operations.hpp"

// Standard headers.
#include <cstdlib>
#include <string>
#include <vector>

namespace bfs = boost::filesystem;
namespace asf = foundation;

const MString AppleseedTranslator::translatorName("appleseed");

AppleseedTranslator::AppleseedTranslator()
{
}

void* AppleseedTranslator::creator()
{
    return new AppleseedTranslator();
}

MString AppleseedTranslator::defaultExtension() const
{
    return "appleseed";
}

MStatus AppleseedTranslator::writer(
    const MFileObject&                  file,
    const MString&                      opts,
    MPxFileTranslator::FileAccessMode   mode)
{
    RENDERER_LOG_DEBUG("AppleseedTranslator::write called, options = %s", opts.asChar());

    AppleseedSession::Options options;

    // Parse the options string.
    std::vector<std::string> tokens;
    asf::tokenize(
        asf::trim_both(opts.asChar()),
        ";",
        tokens);

    std::vector<std::string> optNameValue;
    for(size_t i = 0, e = tokens.size(); i < e; ++i)
    {
        optNameValue.clear();
        asf::tokenize(
            asf::trim_both(tokens[i]),
            "=",
            optNameValue);

        if (optNameValue.size() == 2)
        {
            if (optNameValue[0] == "activeCamera")
                options.m_camera = optNameValue[1].c_str();
            else if (optNameValue[0] == "exportAnim")
                options.m_sequence = (optNameValue[1] == "true");
            else if (optNameValue[0] == "startFrame")
                options.m_firstFrame = atoi(optNameValue[1].c_str());
            else if (optNameValue[0] == "endFrame")
                options.m_lastFrame = atoi(optNameValue[1].c_str());
            else if (optNameValue[0] == "stepFrame")
                options.m_frameStep = atoi(optNameValue[1].c_str());
            else
            {
                RENDERER_LOG_WARNING(
                    "Unknown option %s in appleseed translator.", tokens[i].c_str());
            }
        }
        else
        {
            RENDERER_LOG_WARNING(
                "Bad option %s in appleseed translator.", tokens[i].c_str());
        }
    }

    if (MPxFileTranslator::kExportAccessMode == mode)
        options.m_selectionOnly = false;
    else if (MPxFileTranslator::kExportActiveAccessMode == mode)
        options.m_selectionOnly = true;

    // Get width and height from render globals.
    MCommonRenderSettingsData renderSettings;
    MRenderUtil::getCommonRenderSettings(renderSettings);
    options.m_width = renderSettings.width;
    options.m_height = renderSettings.height;

    // Export the scene.

    // Check if we are exporting a packed project.
    if (asf::ends_with(file.fullName().asChar(), ".appleseedz"))
    {
        // Export the project in a tmp directory.
        const bfs::path originalProjectPath(file.fullName().asChar());
        const bfs::path packDirectory(originalProjectPath.parent_path() / "_asTmpProjectPacking");

        if (!bfs::create_directory(packDirectory))
        {
            RENDERER_LOG_ERROR(
                "Could not create tmp packing directory: %s",
                packDirectory.string().c_str());
            return MS::kFailure;
        }

        const bfs::path packedProjectPath(packDirectory / originalProjectPath.filename());
        const MStatus result = AppleseedSession::projectExport(packedProjectPath.string().c_str(), options);

        if (result)
        {
            // Move the packed project to the requested place.
            bfs::rename(packedProjectPath, originalProjectPath);
        }

        // Cleanup packing directory.
        bfs::remove_all(packDirectory);

        return result;
    }
    else
        return AppleseedSession::projectExport(file.fullName(), options);
}

bool AppleseedTranslator::haveWriteMethod() const
{
    return true;
}
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <unistd.h>

using namespace std;

void writepin(int state) {
  ofstream filehandler;
  string filename = "/dev/shm/pin_12";
  filehandler.open(filename.c_str());
  if (filehandler.is_open()) {
    filehandler << state << endl;
    filehandler.close();
  } else {
    cout << "ERROR: could not write to " << filename << endl;
  }
}

void createraindays() {
  // we use the current year as seed
  time_t now = time(0);
  struct tm *nowt = localtime(&now);

  // buffer for filename and the actual
  // file handler
  char buffer[128];
  ofstream outhandler;

  // definition of rain times.
  // rainpause = 4 => it will rain about every 4 days
  // raindurationmin/raindurationmax is in seconds
  // rainstarthour/rainstophour should be configured in
  // a way it does not interfere with the noon light
  static unsigned short RAINPROBMAX = 256;
  static unsigned short RAINPAUSE = 4;
  static unsigned short DURATIONMIN = 60;
  static unsigned short DURATIONMAX = 240;
  static unsigned short RAINSTARTOUR = 13;
  static unsigned short RAINSTOPHOUR = 20;

  unsigned short rainprobability = RAINPROBMAX / RAINPAUSE;
  unsigned long rainduration = 0;
  unsigned int rainstartsecond = 0;
  unsigned short state = 0;
  unsigned int currentyear=nowt->tm_year;

  cout << "creating rain directory" << endl;
  // mkdir did not work for some strange reason, so I'm lazy
  snprintf(buffer, sizeof(buffer), "mkdir -p /dev/shm/rain/");
  system(buffer);
  // calculate all rain times for the complete year
  // the seed is the actual year so we have persistent
  // states across reboots
  cout << "calculating rain days ... " << endl;
  srand(nowt->tm_year);
  nowt = localtime(&now);
  nowt->tm_yday = 0;
  nowt->tm_hour = 1;
  nowt->tm_min = 0;
  nowt->tm_sec = 0;
  now = mktime(nowt);
  while (currentyear == nowt->tm_year) {
    if ((rand() % RAINPROBMAX) < rainprobability) {
      state = 1;
      rainduration = rand() % (DURATIONMAX - DURATIONMIN) + DURATIONMIN;
      // because we will add a random hour to the calculated value
      // we have to subtract one from the difference of rainstop and
      // rainstart
      rainstartsecond =
          (RAINSTARTOUR + rand() % (RAINSTOPHOUR - RAINSTARTOUR - 1)) * 3600 + rand() % 60 * 60 + rand() % 60;
      rainprobability = 0;
    } else {
      rainduration = 0;
      rainstartsecond = 0;
      rainprobability += RAINPROBMAX / RAINPAUSE;
    }
    snprintf(buffer, sizeof(buffer), "/dev/shm/rain/%d", nowt->tm_yday);
    outhandler.open(buffer);
    if (outhandler.is_open()) {
      outhandler << rainduration << endl;
      outhandler << rainstartsecond << endl;
      outhandler << nowt->tm_year+1900 << "-" << nowt->tm_mon+1 << "-" << nowt->tm_mday << endl;
      outhandler.close();
    } else {
      cout << "ERROR: could not write to " << buffer << endl;
    }
    // we add two seconds more to each day to
    // compensate for leap seconds. this may be a bit overkill
    // but, hey ...
    // it will not be a problem in the long run, because we only
    // calculate times for one year and we only have 366*2 seconds
    // (leap year) which is less than a day.
    now += 86402;
    nowt = localtime(&now);
  }
  cout << "calculating done." << endl;
}

int main() {
  time_t now = time(0);
  struct tm *nowt = localtime(&now);
  time_t start = time(0);
  struct tm *startt = localtime(&start);
  unsigned long rainduration = 0;
  unsigned int rainstartsecond = 0, currentsecond = 0;
  unsigned short state = 0, laststate = 0;
  ifstream inhandler;
  char buffer[128];
  string line;

  // startup
  cout << "starting up ..." << endl;

  // init the file with 0
  writepin(0);

  // now the loop starts :-)
  while (true) {
    now = time(0);
    nowt = localtime(&now);
    // compensate for a new year
    if (startt->tm_year != nowt->tm_year) {
      createraindays();
    }
    currentsecond = nowt->tm_hour * 3600 + nowt->tm_min * 60 + nowt->tm_sec;
    snprintf(buffer, sizeof(buffer), "/dev/shm/rain/%d", nowt->tm_yday);
    inhandler.open(buffer);
    if (inhandler.is_open()) {
      // read two lines from the file and convert them to long
      // the file format is well defined
      getline(inhandler, line);
      rainduration = strtol(line.c_str(), NULL, 10);
      getline(inhandler, line);
      rainstartsecond = strtol(line.c_str(), NULL, 10);
      inhandler.close();

      // check if we should set the pin to 1
      state = 0;
      if (rainduration > 0) {
        if ((currentsecond >= rainstartsecond) && (currentsecond < rainstartsecond + rainduration)) {
          state = 1;
        }
      }

      // cool down for ten seconds every minute
      if ((nowt->tm_sec >= 0) && (nowt->tm_sec < 10)) {
        state = 0;
      }

      // log and actual write of file
      if (laststate != state) {
        cout << "toggling state to " << state << endl;
        laststate = state;
        writepin(state);
      }
    } else {
      cout << "ERROR: could not read from " << buffer << endl;
      cout << "trying to recalculate rain days" << endl;
      createraindays();
    }
    // sleep for 10 seconds
    usleep(10000000);
  }
}<commit_msg>lower rain frequency<commit_after>#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <unistd.h>

using namespace std;

void writepin(int state) {
  ofstream filehandler;
  string filename = "/dev/shm/pin_12";
  filehandler.open(filename.c_str());
  if (filehandler.is_open()) {
    filehandler << state << endl;
    filehandler.close();
  } else {
    cout << "ERROR: could not write to " << filename << endl;
  }
}

void createraindays() {
  // we use the current year as seed
  time_t now = time(0);
  struct tm *nowt = localtime(&now);

  // buffer for filename and the actual
  // file handler
  char buffer[128];
  ofstream outhandler;

  // definition of rain times.
  // rainpause = 4 => it will rain about every 4 days
  // rainpause = 6 => it will rain about every 6 days
  // raindurationmin/raindurationmax is in seconds
  // rainstarthour/rainstophour should be configured in
  // a way it does not interfere with the noon light
  static unsigned short RAINPROBMAX = 256;
  static unsigned short RAINPAUSE = 6;
  static unsigned short DURATIONMIN = 60;
  static unsigned short DURATIONMAX = 240;
  static unsigned short RAINSTARTOUR = 13;
  static unsigned short RAINSTOPHOUR = 20;

  unsigned short rainprobability = RAINPROBMAX / RAINPAUSE;
  unsigned long rainduration = 0;
  unsigned int rainstartsecond = 0;
  unsigned short state = 0;
  unsigned int currentyear=nowt->tm_year;

  cout << "creating rain directory" << endl;
  // mkdir did not work for some strange reason, so I'm lazy
  snprintf(buffer, sizeof(buffer), "mkdir -p /dev/shm/rain/");
  system(buffer);
  // calculate all rain times for the complete year
  // the seed is the actual year so we have persistent
  // states across reboots
  cout << "calculating rain days ... " << endl;
  srand(nowt->tm_year);
  nowt = localtime(&now);
  nowt->tm_yday = 0;
  nowt->tm_hour = 1;
  nowt->tm_min = 0;
  nowt->tm_sec = 0;
  now = mktime(nowt);
  while (currentyear == nowt->tm_year) {
    if ((rand() % RAINPROBMAX) < rainprobability) {
      state = 1;
      rainduration = rand() % (DURATIONMAX - DURATIONMIN) + DURATIONMIN;
      // because we will add a random hour to the calculated value
      // we have to subtract one from the difference of rainstop and
      // rainstart
      rainstartsecond =
          (RAINSTARTOUR + rand() % (RAINSTOPHOUR - RAINSTARTOUR - 1)) * 3600 + rand() % 60 * 60 + rand() % 60;
      rainprobability = 0;
    } else {
      rainduration = 0;
      rainstartsecond = 0;
      rainprobability += RAINPROBMAX / RAINPAUSE;
    }
    snprintf(buffer, sizeof(buffer), "/dev/shm/rain/%d", nowt->tm_yday);
    outhandler.open(buffer);
    if (outhandler.is_open()) {
      outhandler << rainduration << endl;
      outhandler << rainstartsecond << endl;
      outhandler << nowt->tm_year+1900 << "-" << nowt->tm_mon+1 << "-" << nowt->tm_mday << endl;
      outhandler.close();
    } else {
      cout << "ERROR: could not write to " << buffer << endl;
    }
    // we add two seconds more to each day to
    // compensate for leap seconds. this may be a bit overkill
    // but, hey ...
    // it will not be a problem in the long run, because we only
    // calculate times for one year and we only have 366*2 seconds
    // (leap year) which is less than a day.
    now += 86402;
    nowt = localtime(&now);
  }
  cout << "calculating done." << endl;
}

int main() {
  time_t now = time(0);
  struct tm *nowt = localtime(&now);
  time_t start = time(0);
  struct tm *startt = localtime(&start);
  unsigned long rainduration = 0;
  unsigned int rainstartsecond = 0, currentsecond = 0;
  unsigned short state = 0, laststate = 0;
  ifstream inhandler;
  char buffer[128];
  string line;

  // startup
  cout << "starting up ..." << endl;

  // init the file with 0
  writepin(0);

  // now the loop starts :-)
  while (true) {
    now = time(0);
    nowt = localtime(&now);
    // compensate for a new year
    if (startt->tm_year != nowt->tm_year) {
      createraindays();
    }
    currentsecond = nowt->tm_hour * 3600 + nowt->tm_min * 60 + nowt->tm_sec;
    snprintf(buffer, sizeof(buffer), "/dev/shm/rain/%d", nowt->tm_yday);
    inhandler.open(buffer);
    if (inhandler.is_open()) {
      // read two lines from the file and convert them to long
      // the file format is well defined
      getline(inhandler, line);
      rainduration = strtol(line.c_str(), NULL, 10);
      getline(inhandler, line);
      rainstartsecond = strtol(line.c_str(), NULL, 10);
      inhandler.close();

      // check if we should set the pin to 1
      state = 0;
      if (rainduration > 0) {
        if ((currentsecond >= rainstartsecond) && (currentsecond < rainstartsecond + rainduration)) {
          state = 1;
        }
      }

      // cool down for ten seconds every minute
      if ((nowt->tm_sec >= 0) && (nowt->tm_sec < 10)) {
        state = 0;
      }

      // log and actual write of file
      if (laststate != state) {
        cout << "toggling state to " << state << endl;
        laststate = state;
        writepin(state);
      }
    } else {
      cout << "ERROR: could not read from " << buffer << endl;
      cout << "trying to recalculate rain days" << endl;
      createraindays();
    }
    // sleep for 10 seconds
    usleep(10000000);
  }
}
<|endoftext|>


<commit_before>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "TestFixtures/SimpleObject.hpp"
#include <autowiring/Autowired.h>
#include <autowiring/ContextMember.h>
#include THREAD_HEADER

class PostConstructTest:
  public testing::Test
{};

using namespace std;

class ContextExposer:
  public CoreContext
{
public:
  size_t DeferredCount(void) const {
    size_t ct = 0;
    for(const auto& entry : CoreContext::m_typeMemos)
      for(auto cur = entry.second.pFirst; cur; cur = cur->GetFlink())
        ct++;
    return ct;
  }
};

// Two classes to make up the cyclic dependency:
class A:
  public ContextMember
{
public:
  int m_value = 2;

  int GetValue(void) const {return m_value;}
};

// For testing NotifyWhenAutowired with heirarchies
class Interface
{
public:
  virtual int GetValue() = 0;
};

class Implementation :
  public ContextMember,
  public Interface
{
public:
  virtual int GetValue() override { return 2; }
};

class Naive:
  public ContextMember
{
public:
  Naive(void) {
    if(!m_a)
      throw exception();
  }

  Autowired<A> m_a;
};

class Smarter:
  public ContextMember
{
public:
  Smarter(void)
  {
    m_a.NotifyWhenAutowired([this] () {
      this->value = m_a->GetValue();
    });
  }

  int value = 1;
  Autowired<A> m_a;
};

class SmarterInterface
{
public:
  SmarterInterface(void)
  {
    m_interface.NotifyWhenAutowired([this] () {
      this->value = m_interface->GetValue();
    });
  }

  int value = 1;
  Autowired<Interface> m_interface;
};

class FailedAutowiringInstance {
};

TEST_F(PostConstructTest, VerifyNaiveBehavior) {
  // Create a context and add just the naive class, to verify the problematic behavior:
  AutoCurrentContext ctxt;
  ASSERT_THROW(ctxt->Inject<Naive>(), std::exception) << "Naive class didn't throw an exception as expected";
}

TEST_F(PostConstructTest, VerifyExpectedDeferrmentCount) {
  AutoCurrentContext ctxt;

  // Add the smart class, which should introduce a single deferred count:
  ctxt->Inject<Smarter>();

  // Now test the count:
  ASSERT_EQ(
    1UL,
    ((ContextExposer&)*ctxt).DeferredCount()
  ) << "Unexpected number of deferred initializers";
}

TEST_F(PostConstructTest, VerifySmartBehavior) {
  AutoCurrentContext ctxt;

  // Add the smart class, which has a member that autowired type A
  ctxt->Inject<Smarter>();

  // Check that we can get the item we just injected
  Autowired<Smarter> smarter;
  ASSERT_TRUE(smarter.IsAutowired()) << "Slot was not satisfied as expected";
  ASSERT_EQ(1, smarter->value) << "Unexpected initial value of SmarterA instance";

  // Now inject A, and see if delayed autowiring has taken place:
  ctxt->Inject<A>();
  ASSERT_FALSE(!smarter->m_a.get()) << "Autowired member was not wired as expected";

  // Verify the value was updated by the notification routine
  ASSERT_EQ(2, smarter->value) << "Post-construction notification routine wasn't invoked as expected";
}

TEST_F(PostConstructTest, VerifySmartBehaviorWithInheritance) {
  AutoCurrentContext ctxt;

  // Add the smart classes, which should succeed
  ctxt->Inject<SmarterInterface>();

  //Initially value should be one, which is the default
  Autowired<SmarterInterface> smarterI;
  ASSERT_EQ(1, smarterI->value) << "Unexpected initial value of SmarterA instance";

  //Now add Implementation and check the wiring
  ctxt->Inject<Implementation>();
  ASSERT_FALSE(!smarterI->m_interface.get()) << "Autowired subclass was not wired as expected";

  ASSERT_EQ(2, smarterI->value) << "Post-construction notification routine wasn't invoked on subclass";
}

TEST_F(PostConstructTest, VerifyLoopingFailedAutowiring) {
  for(size_t i = 10; i--;) {
    Autowired<FailedAutowiringInstance> ignored;
    ASSERT_FALSE(ignored.IsAutowired()) << "Successfully autowired an instance that should not have been autowirable";
  }
}

TEST_F(PostConstructTest, VerifyTrivialNotifyWhenAutowired) {
  // Inject a type first:
  AutoRequired<SimpleObject>();

  // Now autowire, and add a registration:
  bool called = false;
  Autowired<SimpleObject> so;
  so.NotifyWhenAutowired([&called] { called = true; });

  ASSERT_TRUE(called) << "An autowiring notification was not invoked on an already-satisfied field as expected";
}

TEST_F(PostConstructTest, MultiNotifyWhenAutowired) {
  // Add multiple notifications on the same space:
  int field = 0;
  Autowired<SimpleObject> so;
  for(size_t i = 10; i--;)
    so.NotifyWhenAutowired([&field] { field++; });

  // Inject the type to trigger the autowiring
  AutoRequired<SimpleObject>();

  // Verify that the notification got hit ten times:
  ASSERT_EQ(10, field) << "Autowiring lambdas did not run the expected number of times";
}

TEST_F(PostConstructTest, NotificationTeardownRace) {
  std::shared_ptr<CoreContext> pContext;

  auto quit = false;
  auto shouldQuit = MakeAtExit([&quit] { quit = true; });
  std::atomic<size_t> counter{0};

  // This thread sets up the race pathology:
  std::thread t([&] {
    while(!quit) {
      // Barrier until setup time:
      while(counter != 1)
        std::this_thread::yield();

      if(!pContext)
        break;

      // Set the context current, then try to autowire:
      CurrentContextPusher pshr(pContext);
      Autowired<SimpleObject> sobj;
      sobj.NotifyWhenAutowired([] {});

      // Now barrier, and then we will try to race against the context
      // for teardown.
      counter++;
    }
  });

  for(size_t i = 0; i < 200; i++) {
    // Make a new context:
    AutoCreateContext ctxt;
    pContext = ctxt;

    // Wake up the other thread, let it set a notify-when-autowired:
    counter++;
    while(counter != 2)
      std::this_thread::yield();

    // Counter goes back to zero before we make the next loop iteration:
    counter = 0;

    // Now we reset our pContext pointer, and then tell the thread
    // to race with us against context teardown:
    pContext.reset();
  }

  // All done, wait for the thread to back out:
  quit = true;
  counter = 1;
  t.join();
}

TEST_F(PostConstructTest, VerifyAllInstancesSatisfied) {
  // Create all of our slots and bind to them:
  const size_t ct = 3;
  Autowired<SimpleObject> aw[ct];
  bool hit[ct] = {};

  for(size_t i = ct; i--;)
    aw[i].NotifyWhenAutowired([&hit, i] { hit[i] = true; });

  // Now we inject our simple object:
  AutoRequired<SimpleObject>();

  // Verify that everything got hit:
  for(size_t i = 0; i < ct; i++) {
    ASSERT_TRUE(aw[i]) << "Autowired slot " << i << " was not post-bound correctly";
    ASSERT_TRUE(hit[i]) << "Autowired slot " << i << " did not fire all of its post-construct notifiers as expected";
  }
}

TEST_F(PostConstructTest, ContextNotifyWhenAutowired) {
  auto called = std::make_shared<bool>(false);
  AutoCurrentContext ctxt;

  // Now we'd like to be notified when SimpleObject gets added:
  ctxt->NotifyWhenAutowired<SimpleObject>(
    [called] {
      *called = true;
    }
  );

  // Should only be two uses, at this point, of the capture of the above lambda:
  ASSERT_EQ(2L, called.use_count()) << "Unexpected number of references held in a capture lambda";

  // Create another entry that will add another slot to the deferred list:
  Autowired<SimpleObject> sobj;

  // Insert the SimpleObject, see if the lambda got hit:
  AutoRequired<SimpleObject>();
  ASSERT_TRUE(*called) << "Context-wide autowiring notification was not hit as expected when a matching type was injected into a context";

  // Our shared pointer should be unique by this point, because the lambda should have been destroyed
  ASSERT_TRUE(called.unique()) << "Autowiring notification lambda was not properly cleaned up";
}

TEST_F(PostConstructTest, ContextNotifyWhenAutowiredPostConstruct) {
  auto called = std::make_shared<bool>(false);
  AutoCurrentContext ctxt;

  // Create an object that will satisfy subsequent notification call:
  AutoRequired<SimpleObject> sobj;

  // Notification should be immediate:
  ctxt->NotifyWhenAutowired<SimpleObject>(
    [called] {
      *called = true;
    }
  );

  // Insert the SimpleObject, see if the lambda got hit:
  ASSERT_TRUE(*called) << "Context-wide autowiring notification was not hit as expected when a matching type was injected into a context";

  // Our shared pointer should be unique by this point, because the lambda should have been destroyed
  ASSERT_TRUE(called.unique()) << "Autowiring notification lambda was not properly cleaned up";
}

class OtherObject : public SimpleObject {};

TEST_F(PostConstructTest, RecursiveNotificationPreConstruction) {
  auto called = std::make_shared<bool>(false);
  AutoCurrentContext ctxt;

  // Ensure that nested calls do not created deadlock
  // Notification should be deferred:
  ctxt->NotifyWhenAutowired<SimpleObject>(
  [called] {
    AutoCurrentContext()->NotifyWhenAutowired<OtherObject>(
    [called] {
      *called = true;
    });
  });

  // Create an object that will satisfy subsequent notification call:
  AutoRequired<SimpleObject> sobj;
  AutoRequired<OtherObject> oobj;

  // Insert the SimpleObject, see if the lambda got hit:
  ASSERT_TRUE(*called) << "Context-wide autowiring notification was not hit as expected when a matching type was injected into a context";

  // Our shared pointer should be unique by this point, because the lambda should have been destroyed
  ASSERT_TRUE(called.unique()) << "Autowiring notification lambda was not properly cleaned up";
}

TEST_F(PostConstructTest, RecursiveNotificationPostConstruction) {
  auto called = std::make_shared<bool>(false);
  AutoCurrentContext ctxt;

  // Create an object that will satisfy subsequent notification call:
  AutoRequired<SimpleObject> sobj;
  AutoRequired<OtherObject> oobj;

  // Ensure that nested calls do not created deadlock
  // Notification should be immediate:
  ctxt->NotifyWhenAutowired<SimpleObject>(
  [called] {
    AutoCurrentContext()->NotifyWhenAutowired<OtherObject>(
    [called] {
      *called = true;
    });
  });

  // Insert the SimpleObject, see if the lambda got hit:
  ASSERT_TRUE(*called) << "Context-wide autowiring notification was not hit as expected when a matching type was injected into a context";

  // Our shared pointer should be unique by this point, because the lambda should have been destroyed
  ASSERT_TRUE(called.unique()) << "Autowiring notification lambda was not properly cleaned up";
}

struct ClassWithAutoInit:
  std::enable_shared_from_this<ClassWithAutoInit>
{
  void AutoInit(void) {
    ASSERT_TRUE(m_constructed) << "A postconstruct routine was called BEFORE the corresponding constructor";
    m_postConstructed = true;

    auto myself = shared_from_this();
    ASSERT_EQ(this, myself.get()) << "Reflexive shared_from_this did not return a shared pointer to this as expected";
  }

  bool m_constructed = true;
  bool m_postConstructed = false;
};

static_assert(has_autoinit<ClassWithAutoInit>::value, "AutoInit-bearing class did not pass a static type check");

TEST_F(PostConstructTest, PostConstructGetsCalled) {
  AutoRequired<ClassWithAutoInit> cwai;
  ASSERT_TRUE(cwai->m_constructed) << "Trivial constructor call was not made as expected";
  ASSERT_TRUE(cwai->m_postConstructed) << "Auto-initialization routine was not called on an initializable type";
}

struct PostConstructThrowsException {
  void AutoInit(void) const {
    throw std::runtime_error("Autoinit crashing for no reason");
  }
};

TEST_F(PostConstructTest, PostConstructCanSafelyThrow) {
  ASSERT_ANY_THROW(AutoRequired<PostConstructThrowsException>()) << "AutoInit call threw an exception, but it was incorrectly eaten by Autowiring";

  Autowired<PostConstructThrowsException> pcte;
  ASSERT_FALSE(pcte.IsAutowired()) << "A context member which threw an exception post-construction was incorrectly introduced into a context";
}

namespace {
  class EmptyType : public CoreObject {};
}

TEST_F(PostConstructTest, StrictNotificationArrangement) {
  int call[7] = {-1, -1, -1, -1, -1, -1, -1};
  int callIdx = 1;

  AutoCurrentContext ctxt;
  Autowired<EmptyType> obj1;
  obj1.NotifyWhenAutowired([&] {
    call[0] = callIdx++;
  });
  ctxt->NotifyWhenAutowired<EmptyType>([&] {
    call[1] = callIdx++;
  });
  obj1.NotifyWhenAutowired([&] {
    call[2] = callIdx++;
  });
  ctxt->NotifyWhenAutowired<EmptyType>([&] {
    call[3] = callIdx++;
  });
  Autowired<EmptyType> obj2;
  obj2.NotifyWhenAutowired([&] {
    call[4] = callIdx++;
  });
  obj1.NotifyWhenAutowired([&] {
    call[5] = callIdx++;
  });
  obj2.NotifyWhenAutowired([&] {
    call[6] = callIdx++;
  });

  ctxt->Inject<EmptyType>();

  for (int i = 0; i < 7; i++)
    ASSERT_EQ(i + 1, call[i]) << "Registered autowired handler was not called in the correct order";
}
<commit_msg>remove unnecessary test<commit_after>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "TestFixtures/SimpleObject.hpp"
#include <autowiring/Autowired.h>
#include <autowiring/ContextMember.h>
#include THREAD_HEADER

class PostConstructTest:
  public testing::Test
{};

using namespace std;

// Two classes to make up the cyclic dependency:
class A:
  public ContextMember
{
public:
  int m_value = 2;

  int GetValue(void) const {return m_value;}
};

// For testing NotifyWhenAutowired with heirarchies
class Interface
{
public:
  virtual int GetValue() = 0;
};

class Implementation :
  public ContextMember,
  public Interface
{
public:
  virtual int GetValue() override { return 2; }
};

class Naive:
  public ContextMember
{
public:
  Naive(void) {
    if(!m_a)
      throw exception();
  }

  Autowired<A> m_a;
};

class Smarter:
  public ContextMember
{
public:
  Smarter(void)
  {
    m_a.NotifyWhenAutowired([this] () {
      this->value = m_a->GetValue();
    });
  }

  int value = 1;
  Autowired<A> m_a;
};

class SmarterInterface
{
public:
  SmarterInterface(void)
  {
    m_interface.NotifyWhenAutowired([this] () {
      this->value = m_interface->GetValue();
    });
  }

  int value = 1;
  Autowired<Interface> m_interface;
};

class FailedAutowiringInstance {
};

TEST_F(PostConstructTest, VerifyNaiveBehavior) {
  // Create a context and add just the naive class, to verify the problematic behavior:
  AutoCurrentContext ctxt;
  ASSERT_THROW(ctxt->Inject<Naive>(), std::exception) << "Naive class didn't throw an exception as expected";
}

TEST_F(PostConstructTest, VerifySmartBehavior) {
  AutoCurrentContext ctxt;

  // Add the smart class, which has a member that autowired type A
  ctxt->Inject<Smarter>();

  // Check that we can get the item we just injected
  Autowired<Smarter> smarter;
  ASSERT_TRUE(smarter.IsAutowired()) << "Slot was not satisfied as expected";
  ASSERT_EQ(1, smarter->value) << "Unexpected initial value of SmarterA instance";

  // Now inject A, and see if delayed autowiring has taken place:
  ctxt->Inject<A>();
  ASSERT_FALSE(!smarter->m_a.get()) << "Autowired member was not wired as expected";

  // Verify the value was updated by the notification routine
  ASSERT_EQ(2, smarter->value) << "Post-construction notification routine wasn't invoked as expected";
}

TEST_F(PostConstructTest, VerifySmartBehaviorWithInheritance) {
  AutoCurrentContext ctxt;

  // Add the smart classes, which should succeed
  ctxt->Inject<SmarterInterface>();

  //Initially value should be one, which is the default
  Autowired<SmarterInterface> smarterI;
  ASSERT_EQ(1, smarterI->value) << "Unexpected initial value of SmarterA instance";

  //Now add Implementation and check the wiring
  ctxt->Inject<Implementation>();
  ASSERT_FALSE(!smarterI->m_interface.get()) << "Autowired subclass was not wired as expected";

  ASSERT_EQ(2, smarterI->value) << "Post-construction notification routine wasn't invoked on subclass";
}

TEST_F(PostConstructTest, VerifyLoopingFailedAutowiring) {
  for(size_t i = 10; i--;) {
    Autowired<FailedAutowiringInstance> ignored;
    ASSERT_FALSE(ignored.IsAutowired()) << "Successfully autowired an instance that should not have been autowirable";
  }
}

TEST_F(PostConstructTest, VerifyTrivialNotifyWhenAutowired) {
  // Inject a type first:
  AutoRequired<SimpleObject>();

  // Now autowire, and add a registration:
  bool called = false;
  Autowired<SimpleObject> so;
  so.NotifyWhenAutowired([&called] { called = true; });

  ASSERT_TRUE(called) << "An autowiring notification was not invoked on an already-satisfied field as expected";
}

TEST_F(PostConstructTest, MultiNotifyWhenAutowired) {
  // Add multiple notifications on the same space:
  int field = 0;
  Autowired<SimpleObject> so;
  for(size_t i = 10; i--;)
    so.NotifyWhenAutowired([&field] { field++; });

  // Inject the type to trigger the autowiring
  AutoRequired<SimpleObject>();

  // Verify that the notification got hit ten times:
  ASSERT_EQ(10, field) << "Autowiring lambdas did not run the expected number of times";
}

TEST_F(PostConstructTest, NotificationTeardownRace) {
  std::shared_ptr<CoreContext> pContext;

  auto quit = false;
  auto shouldQuit = MakeAtExit([&quit] { quit = true; });
  std::atomic<size_t> counter{0};

  // This thread sets up the race pathology:
  std::thread t([&] {
    while(!quit) {
      // Barrier until setup time:
      while(counter != 1)
        std::this_thread::yield();

      if(!pContext)
        break;

      // Set the context current, then try to autowire:
      CurrentContextPusher pshr(pContext);
      Autowired<SimpleObject> sobj;
      sobj.NotifyWhenAutowired([] {});

      // Now barrier, and then we will try to race against the context
      // for teardown.
      counter++;
    }
  });

  for(size_t i = 0; i < 200; i++) {
    // Make a new context:
    AutoCreateContext ctxt;
    pContext = ctxt;

    // Wake up the other thread, let it set a notify-when-autowired:
    counter++;
    while(counter != 2)
      std::this_thread::yield();

    // Counter goes back to zero before we make the next loop iteration:
    counter = 0;

    // Now we reset our pContext pointer, and then tell the thread
    // to race with us against context teardown:
    pContext.reset();
  }

  // All done, wait for the thread to back out:
  quit = true;
  counter = 1;
  t.join();
}

TEST_F(PostConstructTest, VerifyAllInstancesSatisfied) {
  // Create all of our slots and bind to them:
  const size_t ct = 3;
  Autowired<SimpleObject> aw[ct];
  bool hit[ct] = {};

  for(size_t i = ct; i--;)
    aw[i].NotifyWhenAutowired([&hit, i] { hit[i] = true; });

  // Now we inject our simple object:
  AutoRequired<SimpleObject>();

  // Verify that everything got hit:
  for(size_t i = 0; i < ct; i++) {
    ASSERT_TRUE(aw[i]) << "Autowired slot " << i << " was not post-bound correctly";
    ASSERT_TRUE(hit[i]) << "Autowired slot " << i << " did not fire all of its post-construct notifiers as expected";
  }
}

TEST_F(PostConstructTest, ContextNotifyWhenAutowired) {
  auto called = std::make_shared<bool>(false);
  AutoCurrentContext ctxt;

  // Now we'd like to be notified when SimpleObject gets added:
  ctxt->NotifyWhenAutowired<SimpleObject>(
    [called] {
      *called = true;
    }
  );

  // Should only be two uses, at this point, of the capture of the above lambda:
  ASSERT_EQ(2L, called.use_count()) << "Unexpected number of references held in a capture lambda";

  // Create another entry that will add another slot to the deferred list:
  Autowired<SimpleObject> sobj;

  // Insert the SimpleObject, see if the lambda got hit:
  AutoRequired<SimpleObject>();
  ASSERT_TRUE(*called) << "Context-wide autowiring notification was not hit as expected when a matching type was injected into a context";

  // Our shared pointer should be unique by this point, because the lambda should have been destroyed
  ASSERT_TRUE(called.unique()) << "Autowiring notification lambda was not properly cleaned up";
}

TEST_F(PostConstructTest, ContextNotifyWhenAutowiredPostConstruct) {
  auto called = std::make_shared<bool>(false);
  AutoCurrentContext ctxt;

  // Create an object that will satisfy subsequent notification call:
  AutoRequired<SimpleObject> sobj;

  // Notification should be immediate:
  ctxt->NotifyWhenAutowired<SimpleObject>(
    [called] {
      *called = true;
    }
  );

  // Insert the SimpleObject, see if the lambda got hit:
  ASSERT_TRUE(*called) << "Context-wide autowiring notification was not hit as expected when a matching type was injected into a context";

  // Our shared pointer should be unique by this point, because the lambda should have been destroyed
  ASSERT_TRUE(called.unique()) << "Autowiring notification lambda was not properly cleaned up";
}

class OtherObject : public SimpleObject {};

TEST_F(PostConstructTest, RecursiveNotificationPreConstruction) {
  auto called = std::make_shared<bool>(false);
  AutoCurrentContext ctxt;

  // Ensure that nested calls do not created deadlock
  // Notification should be deferred:
  ctxt->NotifyWhenAutowired<SimpleObject>(
  [called] {
    AutoCurrentContext()->NotifyWhenAutowired<OtherObject>(
    [called] {
      *called = true;
    });
  });

  // Create an object that will satisfy subsequent notification call:
  AutoRequired<SimpleObject> sobj;
  AutoRequired<OtherObject> oobj;

  // Insert the SimpleObject, see if the lambda got hit:
  ASSERT_TRUE(*called) << "Context-wide autowiring notification was not hit as expected when a matching type was injected into a context";

  // Our shared pointer should be unique by this point, because the lambda should have been destroyed
  ASSERT_TRUE(called.unique()) << "Autowiring notification lambda was not properly cleaned up";
}

TEST_F(PostConstructTest, RecursiveNotificationPostConstruction) {
  auto called = std::make_shared<bool>(false);
  AutoCurrentContext ctxt;

  // Create an object that will satisfy subsequent notification call:
  AutoRequired<SimpleObject> sobj;
  AutoRequired<OtherObject> oobj;

  // Ensure that nested calls do not created deadlock
  // Notification should be immediate:
  ctxt->NotifyWhenAutowired<SimpleObject>(
  [called] {
    AutoCurrentContext()->NotifyWhenAutowired<OtherObject>(
    [called] {
      *called = true;
    });
  });

  // Insert the SimpleObject, see if the lambda got hit:
  ASSERT_TRUE(*called) << "Context-wide autowiring notification was not hit as expected when a matching type was injected into a context";

  // Our shared pointer should be unique by this point, because the lambda should have been destroyed
  ASSERT_TRUE(called.unique()) << "Autowiring notification lambda was not properly cleaned up";
}

struct ClassWithAutoInit:
  std::enable_shared_from_this<ClassWithAutoInit>
{
  void AutoInit(void) {
    ASSERT_TRUE(m_constructed) << "A postconstruct routine was called BEFORE the corresponding constructor";
    m_postConstructed = true;

    auto myself = shared_from_this();
    ASSERT_EQ(this, myself.get()) << "Reflexive shared_from_this did not return a shared pointer to this as expected";
  }

  bool m_constructed = true;
  bool m_postConstructed = false;
};

static_assert(has_autoinit<ClassWithAutoInit>::value, "AutoInit-bearing class did not pass a static type check");

TEST_F(PostConstructTest, PostConstructGetsCalled) {
  AutoRequired<ClassWithAutoInit> cwai;
  ASSERT_TRUE(cwai->m_constructed) << "Trivial constructor call was not made as expected";
  ASSERT_TRUE(cwai->m_postConstructed) << "Auto-initialization routine was not called on an initializable type";
}

struct PostConstructThrowsException {
  void AutoInit(void) const {
    throw std::runtime_error("Autoinit crashing for no reason");
  }
};

TEST_F(PostConstructTest, PostConstructCanSafelyThrow) {
  ASSERT_ANY_THROW(AutoRequired<PostConstructThrowsException>()) << "AutoInit call threw an exception, but it was incorrectly eaten by Autowiring";

  Autowired<PostConstructThrowsException> pcte;
  ASSERT_FALSE(pcte.IsAutowired()) << "A context member which threw an exception post-construction was incorrectly introduced into a context";
}

namespace {
  class EmptyType : public CoreObject {};
}

TEST_F(PostConstructTest, StrictNotificationArrangement) {
  int call[7] = {-1, -1, -1, -1, -1, -1, -1};
  int callIdx = 1;

  AutoCurrentContext ctxt;
  Autowired<EmptyType> obj1;
  obj1.NotifyWhenAutowired([&] {
    call[0] = callIdx++;
  });
  ctxt->NotifyWhenAutowired<EmptyType>([&] {
    call[1] = callIdx++;
  });
  obj1.NotifyWhenAutowired([&] {
    call[2] = callIdx++;
  });
  ctxt->NotifyWhenAutowired<EmptyType>([&] {
    call[3] = callIdx++;
  });
  Autowired<EmptyType> obj2;
  obj2.NotifyWhenAutowired([&] {
    call[4] = callIdx++;
  });
  obj1.NotifyWhenAutowired([&] {
    call[5] = callIdx++;
  });
  obj2.NotifyWhenAutowired([&] {
    call[6] = callIdx++;
  });

  ctxt->Inject<EmptyType>();

  for (int i = 0; i < 7; i++)
    ASSERT_EQ(i + 1, call[i]) << "Registered autowired handler was not called in the correct order";
}
<|endoftext|>