<commit_before>/*

    ofxTableGestures (formerly OF-TangibleFramework)
    Developed for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2011 Daniel Gallardo Grassot <daniel.gallardo@upf.edu>

    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.

*/

#include "Figure.h"
#include "GlobalConfig.hpp"
#include "CollisionHelper.h"

using namespace Figures;

Figure::Figure():has_texture(false)
{
    bbox.Reset();
    matrix.SetIdentity();
}

Figure::~Figure()
{
    //dtor
}

void Figure::SetTexture(const std::string & path)
{
    if (path.compare("") == 0)
    {
        has_texture = false;
        return;
    }
    if(!texture.loadImage(path))
    {
        has_texture = false;
        return;
    }
    has_texture = true;
}

void Figure::SetTexture(ofImage& image)
{
    if(image.getHeight() == 0)
    {
        has_texture = false;
        return;
    }
    texture = image;
    has_texture = true;
}

void Figure::Draw()
{
    glGetDoublev(GL_MODELVIEW_MATRIX,matrix.data);
    if(CollisionHelper::debug_graphics)
    {
        bbox.Draw();
        ofNoFill();
        ofSetLineWidth(1.0f);
    }
    Design();
    if(CollisionHelper::debug_graphics)
        ofFill();

}

void Figure::DrawStroke()
{
    glGetDoublev(GL_MODELVIEW_MATRIX,matrix.data);
    DesignStroke();
    if(CollisionHelper::debug_graphics)
        bbox.Draw();
}

bool Figure::Collide(ofPoint const & point)
{
    ofPoint target = (CollisionHelper::ignore_transformation_matrix*matrix).TransformInverse(point);
    //std::cout << (CollisionHelper::ignore_transformation_matrix*matrix).ToString() << std::endl;
    //if(bbox.Collide(target.x,target.y) && CheckCollision(target))return true;
    //std::cout << target.x << " " << target.y << " -- " << point.x << " " << point.y << std::endl;
    if(bbox.Collide(target.x,target.y))
        if(CheckCollision(target))
            return true;
    return false;
}

ofPoint Figure::GetCentre()
{
    ofPoint center;
    /*center.x = 0;
    center.y = 0;
    center.z = 0;*/
    GetCentre(center.x,center.y);
    return matrix.Transform(center);
}

void Figure::GetCentre(float & x, float & y)
{
    ofPoint center;
    center.x = 0;
    center.y = 0;
    center.z = 0;
    matrix.Transform(center);
    x = center.x;
    y = center.y;
}
<commit_msg>removing ofxGlobalConfig reference<commit_after>/*

    ofxTableGestures (formerly OF-TangibleFramework)
    Developed for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2011 Daniel Gallardo Grassot <daniel.gallardo@upf.edu>

    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.

*/

#include "Figure.h"
#include "CollisionHelper.h"

using namespace Figures;

Figure::Figure():has_texture(false)
{
    bbox.Reset();
    matrix.SetIdentity();
}

Figure::~Figure()
{
    //dtor
}

void Figure::SetTexture(const std::string & path)
{
    if (path.compare("") == 0)
    {
        has_texture = false;
        return;
    }
    if(!texture.loadImage(path))
    {
        has_texture = false;
        return;
    }
    has_texture = true;
}

void Figure::SetTexture(ofImage& image)
{
    if(image.getHeight() == 0)
    {
        has_texture = false;
        return;
    }
    texture = image;
    has_texture = true;
}

void Figure::Draw()
{
    glGetDoublev(GL_MODELVIEW_MATRIX,matrix.data);
    if(CollisionHelper::debug_graphics)
    {
        bbox.Draw();
        ofNoFill();
        ofSetLineWidth(1.0f);
    }
    Design();
    if(CollisionHelper::debug_graphics)
        ofFill();

}

void Figure::DrawStroke()
{
    glGetDoublev(GL_MODELVIEW_MATRIX,matrix.data);
    DesignStroke();
    if(CollisionHelper::debug_graphics)
        bbox.Draw();
}

bool Figure::Collide(ofPoint const & point)
{
    ofPoint target = (CollisionHelper::ignore_transformation_matrix*matrix).TransformInverse(point);
    //std::cout << (CollisionHelper::ignore_transformation_matrix*matrix).ToString() << std::endl;
    //if(bbox.Collide(target.x,target.y) && CheckCollision(target))return true;
    //std::cout << target.x << " " << target.y << " -- " << point.x << " " << point.y << std::endl;
    if(bbox.Collide(target.x,target.y))
        if(CheckCollision(target))
            return true;
    return false;
}

ofPoint Figure::GetCentre()
{
    ofPoint center;
    /*center.x = 0;
    center.y = 0;
    center.z = 0;*/
    GetCentre(center.x,center.y);
    return matrix.Transform(center);
}

void Figure::GetCentre(float & x, float & y)
{
    ofPoint center;
    center.x = 0;
    center.y = 0;
    center.z = 0;
    matrix.Transform(center);
    x = center.x;
    y = center.y;
}
<|endoftext|>


<commit_before>#ifndef __CALCULATE_PARSER_HPP__
#define __CALCULATE_PARSER_HPP__

#include <algorithm>
#include <limits>
#include <ostream>
#include <queue>
#include <string>
#include <unordered_set>

#include "lexer.hpp"
#include "node.hpp"

namespace calculate {

template<typename BaseType>
class BaseParser {
public:
    using DefaultLexer = Lexer<BaseType>;
    using Lexer = BaseLexer<BaseType>;
    using Type = BaseType;

    using Symbol = Symbol<Node<BaseParser>>;
    using Variable = Variable<Node<BaseParser>>;
    using Constant = Constant<Node<BaseParser>>;
    using Function = Function<Node<BaseParser>>;
    using Operator = Operator<Node<BaseParser>>;

    using Expression = Node<BaseParser>;
    private: using VariableHandler = typename Expression::VariableHandler;

    public: using SymbolType = typename Symbol::SymbolType;
    public: using Associativity = typename Operator::Associativity;

private:
    std::shared_ptr<Lexer> _lexer;

public:
    util::SymbolContainer<Constant, BaseParser> constants;
    util::SymbolContainer<Function, BaseParser> functions;
    util::SymbolContainer<Operator, BaseParser> operators;

    template<typename LexerType>
    BaseParser(const LexerType& lexer) :
        _lexer{lexer.clone()},
        constants{_lexer.get()},
        functions{_lexer.get()},
        operators{_lexer.get()}
    {}

    BaseParser() : BaseParser{calculate::Lexer<Type>{}} {}

    virtual ~BaseParser() = default;

    const Lexer& lexer() const noexcept { return *_lexer; }

private:
    struct SymbolHandler {
        std::string token;
        SymbolType type;
        std::unique_ptr<Symbol> symbol;
    };

    SymbolHandler Left() const noexcept {
        return {_lexer->left, SymbolType::LEFT, nullptr};
    }

    SymbolHandler Right() const noexcept {
        return {_lexer->right, SymbolType::RIGHT, nullptr};
    }

    SymbolHandler Separator() const noexcept {
        return {_lexer->separator, SymbolType::SEPARATOR, nullptr};
    }

    std::queue<SymbolHandler> _tokenize(
        std::string expression,
        const std::shared_ptr<VariableHandler>& variables
    ) const {
        enum Group {NUMBER=1, NAME, SYMBOL, LEFT, RIGHT, SEPARATOR, DECIMAL};
        std::queue<SymbolHandler> symbols{};
        std::smatch match{};

        auto is = [&match](auto group) { return !match[group].str().empty(); };
        auto has = [&match](const auto& container, auto& founded) {
            return (founded = container.find(match.str())) != container.end();
        };

        decltype(constants.begin()) found_constant;
        decltype(functions.begin()) found_function;
        decltype(operators.begin()) found_operator;

        while (std::regex_search(expression, match, _lexer->tokenizer_regex)) {
            auto token = match.str();
            if (is(Group::DECIMAL))
                throw SyntaxError{"orphan decimal mark '" + token + "'"};
            else if (is(Group::LEFT))
                symbols.push(Left());
            else if (is(Group::RIGHT))
                symbols.push(Right());
            else if (is(Group::SEPARATOR))
                symbols.push(Separator());
            else if (is(Group::NAME) && has(constants, found_constant))
                symbols.push({
                    token,
                    SymbolType::CONSTANT,
                    found_constant->second.clone()
                });
            else if (is(Group::NAME) && has(functions, found_function))
                symbols.push({
                    token,
                    SymbolType::FUNCTION,
                    found_function->second.clone()
                });
            else if (is(Group::SYMBOL) && has(operators, found_operator))
                symbols.push({
                    token,
                    SymbolType::OPERATOR,
                    found_operator->second.clone()
                });
            else if (is(Group::NUMBER))
                symbols.push({
                    token,
                    SymbolType::CONSTANT,
                    Constant{_lexer->to_value(token)}.clone()
                });
            else {
                symbols.push({
                    token,
                    SymbolType::CONSTANT,
                    Variable{variables->at(token)}.clone()
                });
            }
            expression = match.suffix().str();
        }
        return symbols;
    }

    std::queue<SymbolHandler> _parse_infix(
        std::queue<SymbolHandler>&& symbols
    ) const {
        using Associativity = typename Operator::Associativity;

        std::string parsed{};
        std::queue<SymbolHandler> collected{};
        SymbolHandler previous{Left()};
        SymbolHandler current{};
        std::stack<std::size_t> parenthesis_counter{};

        auto fill_parenthesis = [&]() {
            while (!parenthesis_counter.empty()) {
                if (parenthesis_counter.top() == 0) {
                    collected.push(Right());
                    previous = Right();
                    parenthesis_counter.pop();
                }
                else
                    break;
            }
        };

        auto collect_symbol = [&](bool original=true) {
            switch (previous.type) {
            case (SymbolType::RIGHT):
            case (SymbolType::CONSTANT):
                if (
                    current.type == SymbolType::RIGHT ||
                    current.type == SymbolType::SEPARATOR ||
                    current.type == SymbolType::OPERATOR
                )
                    break;
                else
                    throw SyntaxError{};
            case (SymbolType::LEFT):
            case (SymbolType::SEPARATOR):
            case (SymbolType::OPERATOR):
                if (
                    current.type == SymbolType::CONSTANT ||
                    current.type == SymbolType::LEFT ||
                    current.type == SymbolType::FUNCTION
                )
                    break;
                else
                    throw SyntaxError{};
            case (SymbolType::FUNCTION):
                if (current.type == SymbolType::LEFT)
                    break;
                else
                    throw SyntaxError{};
            }

            if (
                previous.type == SymbolType::CONSTANT ||
                previous.type == SymbolType::RIGHT
            ) {
                auto cop = static_cast<Operator*>(current.symbol.get());
                if (
                    current.type != SymbolType::OPERATOR ||
                    cop->associativity() != Associativity::RIGHT
                )
                    fill_parenthesis();
            }

            collected.push(std::move(current));
            if (original)
                parsed += current.token;
            previous = std::move(current);
        };

        if (symbols.size() == 0)
            throw EmptyExpression{};

        try {
            while (!symbols.empty()) {
                current = std::move(symbols.front());
                symbols.pop();

                if (current.type != SymbolType::OPERATOR)
                    collect_symbol();
                else {
                    auto cop = static_cast<Operator*>(current.symbol.get());
                    if (cop->alias().empty())
                        collect_symbol();
                    else if (symbols.empty())
                        throw SyntaxError{};
                    else {
                        switch (previous.type) {
                        case (SymbolType::LEFT):
                        case (SymbolType::SEPARATOR):
                        case (SymbolType::OPERATOR):
                            parsed += current.token;
                            current = {
                                cop->alias(),
                                SymbolType::FUNCTION,
                                functions.at(cop->alias()).clone()
                            };
                            collect_symbol(false);
                            current = Left();
                            collect_symbol(false);
                            parenthesis_counter.push(0);
                            break;
                        default:
                            collect_symbol();
                        }
                    }
                }
            }

            if (!parenthesis_counter.empty()) {
                if (current.type == SymbolType::LEFT)
                    parenthesis_counter.top()++;
                else if (current.type == SymbolType::RIGHT)
                    parenthesis_counter.top()--;
            }

            if (
                previous.type == SymbolType::CONSTANT ||
                previous.type == SymbolType::RIGHT
            )
                fill_parenthesis();
            else
                throw SyntaxError{};
        }
        catch (const SyntaxError&) {
            parsed += " '" + current.token + "' ";
            while (!symbols.empty()) {
                current = std::move(symbols.front());
                symbols.pop();
                parsed += current.token;
            }
            throw SyntaxError{parsed};
        }
        return collected;
    }

    std::queue<SymbolHandler> _shunting_yard(
        std::queue<SymbolHandler>&& symbols
    ) const {
        using Associativity = typename Operator::Associativity;

        std::queue<SymbolHandler> collected{};
        std::stack<SymbolHandler> operations{};
        SymbolHandler element{};
        SymbolHandler another{};

        std::stack<std::size_t> expected_counter{};
        std::stack<std::size_t> provided_counter{};
        std::stack<bool> apply_function{};
        bool was_function{false};

        if (symbols.size() == 0)
            throw EmptyExpression{};

        while (!symbols.empty()) {
            element = std::move(symbols.front());
            symbols.pop();

            switch (element.type) {
            case (SymbolType::LEFT):
                operations.push(std::move(element));
                apply_function.push(was_function);
                was_function = false;
                break;

            case (SymbolType::RIGHT):
                while (!operations.empty()) {
                    if (operations.top().type != SymbolType::LEFT) {
                        collected.push(std::move(operations.top()));
                        operations.pop();
                    }
                    else
                        break;
                }
                if (
                    !operations.empty() &&
                    operations.top().type == SymbolType::LEFT
                )
                    operations.pop();
                else
                    throw ParenthesisMismatch{};
                if (apply_function.top()) {
                    if (expected_counter.top() != provided_counter.top())
                        throw ArgumentsMismatch{
                            operations.top().token,
                            expected_counter.top(),
                            provided_counter.top()
                        };
                    expected_counter.pop();
                    provided_counter.pop();
                }
                apply_function.pop();
                break;

            case (SymbolType::SEPARATOR):
                while (!operations.empty()) {
                    if (operations.top().type != SymbolType::LEFT) {
                        collected.push(std::move(operations.top()));
                        operations.pop();
                    }
                    else
                        break;
                }
                if (apply_function.empty() || !apply_function.top())
                    throw SyntaxError{
                        "separator '" + element.token + "' outside function"
                    };
                provided_counter.top()++;
                if (operations.empty())
                    throw ParenthesisMismatch{};
                break;

            case (SymbolType::CONSTANT):
                collected.push(std::move(element));
                break;

            case (SymbolType::FUNCTION):
                expected_counter.push(element.symbol->arguments());
                provided_counter.push(1);
                was_function = true;
                operations.push(std::move(element));
                break;

            case (SymbolType::OPERATOR):
                while (!operations.empty()) {
                    auto& another = operations.top();
                    if (another.type == SymbolType::LEFT)
                        break;
                    else if (another.type == SymbolType::FUNCTION) {
                        collected.push(std::move(another));
                        operations.pop();
                        break;
                    }
                    else {
                        auto eop = static_cast<Operator*>(element.symbol.get());
                        auto aop = static_cast<Operator*>(another.symbol.get());
                        auto l1 =
                            eop->associativity() !=
                            Associativity::RIGHT;
                        auto p1 = eop->precedence();
                        auto p2 = aop->precedence();
                        if ((l1 && (p1 <= p2)) || (!l1 && (p1 < p2))) {
                            collected.push(std::move(another));
                            operations.pop();
                        }
                        else
                            break;
                    }
                }
                operations.push(std::move(element));
                break;
            }
        }

        while (!operations.empty()) {
            element = std::move(operations.top());
            operations.pop();
            if (element.type == SymbolType::LEFT)
                throw ParenthesisMismatch{};
            collected.push(std::move(element));
        }

        return collected;
    }

    Expression _build_tree(
        std::queue<SymbolHandler>&& symbols,
        const std::shared_ptr<VariableHandler>& variables
    ) const {
        std::stack<Expression> operands{};
        std::stack<Expression> extract{};
        SymbolHandler element{};
        std::size_t hash{};

        while (!symbols.empty()) {
            element = std::move(symbols.front());
            symbols.pop();

            if (
                element.type == SymbolType::LEFT ||
                element.type == SymbolType::RIGHT ||
                element.type == SymbolType::SEPARATOR
            )
                throw SyntaxError{
                    "symbol '" + element.token + "' not allowed in "
                    "postfix notation"
                };

            else if (element.type == SymbolType::CONSTANT) {
                util::hash_combine(hash, *(element.symbol));
                operands.emplace(
                    Expression(
                        _lexer,
                        variables,
                        element.token,
                        std::move(element.symbol),
                        {},
                        hash
                    )
                );
            }

            else {
                std::vector<Expression> nodes{};
                util::hash_combine(hash, *(element.symbol));
                nodes.reserve(element.symbol->arguments());

                for (std::size_t i = 0; i < element.symbol->arguments(); i++) {
                    if (operands.empty())
                        throw ArgumentsMismatch{
                            element.token,
                            element.symbol->arguments(),
                            i
                        };
                    extract.emplace(std::move(operands.top()));
                    operands.pop();
                }
                while (!extract.empty()) {
                    nodes.emplace_back(std::move(extract.top()));
                    extract.pop();
                }
                operands.emplace(
                    Expression(
                        _lexer,
                        variables,
                        element.token,
                        std::move(element.symbol),
                        std::move(nodes),
                        hash
                    )
                );
            }
        }

        if (operands.size() > 1) {
            operands.pop();
            throw UnusedSymbol{operands.top().token()};
        }

        auto pruned = operands.top()._pruned();
        for (const auto& variable : variables->variables)
            if (
                std::find(
                    pruned.begin(),
                    pruned.end(),
                    variable
                ) == pruned.end()
            )
                throw UnusedSymbol(variable);
        return std::move(operands.top());
    }

public:
    Type to_value(const std::string& expression) const {
        return Type{from_infix(expression)};
    }

    std::string to_string(Type value) const {
        return _lexer->to_string(value);
    }

    Expression create_node(Type value) const {
        return from_infix(to_string(value));
    }

    Expression create_node(
        const std::string& token,
        const std::vector<Expression>& nodes={},
        const std::vector<std::string>& variables={}
    ) const {
        std::string postfix{};

        auto context = std::make_shared<VariableHandler>(variables, *_lexer);
        for (const auto& node : nodes)
            postfix += node.postfix() + " ";
        return _build_tree(_tokenize(postfix + token, context), context);
    }

    Expression from_infix(
        const std::string& expression,
        const std::vector<std::string>& variables={}
    ) const {
        auto context = std::make_shared<VariableHandler>(variables, *_lexer);
        return _build_tree(
            _shunting_yard(_parse_infix(_tokenize(expression, context))),
            context
        );
    }

    Expression from_postfix(
        const std::string& expression,
        const std::vector<std::string>& variables={}
    ) const {
        auto context = std::make_shared<VariableHandler>(variables, *_lexer);
        return _build_tree(_tokenize(expression, context), context);
    }

    Expression parse(const std::string& expression) const {
        std::vector<std::string> variables{};

        while (true) {
            try {
                return from_infix(expression, variables);
            }
            catch (const UndefinedSymbol& exception) {
                variables.emplace_back(exception.token);
            }
            catch (const UnsuitableName& exception) {
                throw UndefinedSymbol{exception.token};
            }
        }
    }

    Expression optimize(const Expression& node) const noexcept {
        if (node.variables().empty())
            return create_node(node._symbol->evaluate(node._nodes));

        auto nodes = std::vector<Expression>{};
        nodes.reserve(node._symbol->arguments());
        for (auto another : node._nodes)
            nodes.emplace_back(optimize(another));
        return create_node(node._token, std::move(nodes), node.variables());
    }
};

}

#endif
<commit_msg>Don't leave unused things<commit_after>#ifndef __CALCULATE_PARSER_HPP__
#define __CALCULATE_PARSER_HPP__

#include <algorithm>
#include <limits>
#include <ostream>
#include <queue>
#include <string>
#include <unordered_set>

#include "lexer.hpp"
#include "node.hpp"

namespace calculate {

template<typename BaseType>
class BaseParser {
public:
    using DefaultLexer = Lexer<BaseType>;
    using Lexer = BaseLexer<BaseType>;
    using Type = BaseType;

    using Symbol = Symbol<Node<BaseParser>>;
    using Variable = Variable<Node<BaseParser>>;
    using Constant = Constant<Node<BaseParser>>;
    using Function = Function<Node<BaseParser>>;
    using Operator = Operator<Node<BaseParser>>;

    using Expression = Node<BaseParser>;
    private: using VariableHandler = typename Expression::VariableHandler;

    public: using SymbolType = typename Symbol::SymbolType;
    public: using Associativity = typename Operator::Associativity;

private:
    std::shared_ptr<Lexer> _lexer;

public:
    util::SymbolContainer<Constant, BaseParser> constants;
    util::SymbolContainer<Function, BaseParser> functions;
    util::SymbolContainer<Operator, BaseParser> operators;

    template<typename LexerType>
    BaseParser(const LexerType& lexer) :
        _lexer{lexer.clone()},
        constants{_lexer.get()},
        functions{_lexer.get()},
        operators{_lexer.get()}
    {}

    BaseParser() : BaseParser{DefaultLexer{}} {}

    virtual ~BaseParser() = default;

    const Lexer& lexer() const noexcept { return *_lexer; }

private:
    struct SymbolHandler {
        std::string token;
        SymbolType type;
        std::unique_ptr<Symbol> symbol;
    };

    SymbolHandler Left() const noexcept {
        return {_lexer->left, SymbolType::LEFT, nullptr};
    }

    SymbolHandler Right() const noexcept {
        return {_lexer->right, SymbolType::RIGHT, nullptr};
    }

    SymbolHandler Separator() const noexcept {
        return {_lexer->separator, SymbolType::SEPARATOR, nullptr};
    }

    std::queue<SymbolHandler> _tokenize(
        std::string expression,
        const std::shared_ptr<VariableHandler>& variables
    ) const {
        enum Group {NUMBER=1, NAME, SYMBOL, LEFT, RIGHT, SEPARATOR, DECIMAL};
        std::queue<SymbolHandler> symbols{};
        std::smatch match{};

        auto is = [&match](auto group) { return !match[group].str().empty(); };
        auto has = [&match](const auto& container, auto& founded) {
            return (founded = container.find(match.str())) != container.end();
        };

        decltype(constants.begin()) found_constant;
        decltype(functions.begin()) found_function;
        decltype(operators.begin()) found_operator;

        while (std::regex_search(expression, match, _lexer->tokenizer_regex)) {
            auto token = match.str();
            if (is(Group::DECIMAL))
                throw SyntaxError{"orphan decimal mark '" + token + "'"};
            else if (is(Group::LEFT))
                symbols.push(Left());
            else if (is(Group::RIGHT))
                symbols.push(Right());
            else if (is(Group::SEPARATOR))
                symbols.push(Separator());
            else if (is(Group::NAME) && has(constants, found_constant))
                symbols.push({
                    token,
                    SymbolType::CONSTANT,
                    found_constant->second.clone()
                });
            else if (is(Group::NAME) && has(functions, found_function))
                symbols.push({
                    token,
                    SymbolType::FUNCTION,
                    found_function->second.clone()
                });
            else if (is(Group::SYMBOL) && has(operators, found_operator))
                symbols.push({
                    token,
                    SymbolType::OPERATOR,
                    found_operator->second.clone()
                });
            else if (is(Group::NUMBER))
                symbols.push({
                    token,
                    SymbolType::CONSTANT,
                    Constant{_lexer->to_value(token)}.clone()
                });
            else {
                symbols.push({
                    token,
                    SymbolType::CONSTANT,
                    Variable{variables->at(token)}.clone()
                });
            }
            expression = match.suffix().str();
        }
        return symbols;
    }

    std::queue<SymbolHandler> _parse_infix(
        std::queue<SymbolHandler>&& symbols
    ) const {
        using Associativity = typename Operator::Associativity;

        std::string parsed{};
        std::queue<SymbolHandler> collected{};
        SymbolHandler previous{Left()};
        SymbolHandler current{};
        std::stack<std::size_t> parenthesis_counter{};

        auto fill_parenthesis = [&]() {
            while (!parenthesis_counter.empty()) {
                if (parenthesis_counter.top() == 0) {
                    collected.push(Right());
                    previous = Right();
                    parenthesis_counter.pop();
                }
                else
                    break;
            }
        };

        auto collect_symbol = [&](bool original=true) {
            switch (previous.type) {
            case (SymbolType::RIGHT):
            case (SymbolType::CONSTANT):
                if (
                    current.type == SymbolType::RIGHT ||
                    current.type == SymbolType::SEPARATOR ||
                    current.type == SymbolType::OPERATOR
                )
                    break;
                else
                    throw SyntaxError{};
            case (SymbolType::LEFT):
            case (SymbolType::SEPARATOR):
            case (SymbolType::OPERATOR):
                if (
                    current.type == SymbolType::CONSTANT ||
                    current.type == SymbolType::LEFT ||
                    current.type == SymbolType::FUNCTION
                )
                    break;
                else
                    throw SyntaxError{};
            case (SymbolType::FUNCTION):
                if (current.type == SymbolType::LEFT)
                    break;
                else
                    throw SyntaxError{};
            }

            if (
                previous.type == SymbolType::CONSTANT ||
                previous.type == SymbolType::RIGHT
            ) {
                auto cop = static_cast<Operator*>(current.symbol.get());
                if (
                    current.type != SymbolType::OPERATOR ||
                    cop->associativity() != Associativity::RIGHT
                )
                    fill_parenthesis();
            }

            collected.push(std::move(current));
            if (original)
                parsed += current.token;
            previous = std::move(current);
        };

        if (symbols.size() == 0)
            throw EmptyExpression{};

        try {
            while (!symbols.empty()) {
                current = std::move(symbols.front());
                symbols.pop();

                if (current.type != SymbolType::OPERATOR)
                    collect_symbol();
                else {
                    auto cop = static_cast<Operator*>(current.symbol.get());
                    if (cop->alias().empty())
                        collect_symbol();
                    else if (symbols.empty())
                        throw SyntaxError{};
                    else {
                        switch (previous.type) {
                        case (SymbolType::LEFT):
                        case (SymbolType::SEPARATOR):
                        case (SymbolType::OPERATOR):
                            parsed += current.token;
                            current = {
                                cop->alias(),
                                SymbolType::FUNCTION,
                                functions.at(cop->alias()).clone()
                            };
                            collect_symbol(false);
                            current = Left();
                            collect_symbol(false);
                            parenthesis_counter.push(0);
                            break;
                        default:
                            collect_symbol();
                        }
                    }
                }
            }

            if (!parenthesis_counter.empty()) {
                if (current.type == SymbolType::LEFT)
                    parenthesis_counter.top()++;
                else if (current.type == SymbolType::RIGHT)
                    parenthesis_counter.top()--;
            }

            if (
                previous.type == SymbolType::CONSTANT ||
                previous.type == SymbolType::RIGHT
            )
                fill_parenthesis();
            else
                throw SyntaxError{};
        }
        catch (const SyntaxError&) {
            parsed += " '" + current.token + "' ";
            while (!symbols.empty()) {
                current = std::move(symbols.front());
                symbols.pop();
                parsed += current.token;
            }
            throw SyntaxError{parsed};
        }
        return collected;
    }

    std::queue<SymbolHandler> _shunting_yard(
        std::queue<SymbolHandler>&& symbols
    ) const {
        using Associativity = typename Operator::Associativity;

        std::queue<SymbolHandler> collected{};
        std::stack<SymbolHandler> operations{};
        SymbolHandler element{};
        SymbolHandler another{};

        std::stack<std::size_t> expected_counter{};
        std::stack<std::size_t> provided_counter{};
        std::stack<bool> apply_function{};
        bool was_function{false};

        if (symbols.size() == 0)
            throw EmptyExpression{};

        while (!symbols.empty()) {
            element = std::move(symbols.front());
            symbols.pop();

            switch (element.type) {
            case (SymbolType::LEFT):
                operations.push(std::move(element));
                apply_function.push(was_function);
                was_function = false;
                break;

            case (SymbolType::RIGHT):
                while (!operations.empty()) {
                    if (operations.top().type != SymbolType::LEFT) {
                        collected.push(std::move(operations.top()));
                        operations.pop();
                    }
                    else
                        break;
                }
                if (
                    !operations.empty() &&
                    operations.top().type == SymbolType::LEFT
                )
                    operations.pop();
                else
                    throw ParenthesisMismatch{};
                if (apply_function.top()) {
                    if (expected_counter.top() != provided_counter.top())
                        throw ArgumentsMismatch{
                            operations.top().token,
                            expected_counter.top(),
                            provided_counter.top()
                        };
                    expected_counter.pop();
                    provided_counter.pop();
                }
                apply_function.pop();
                break;

            case (SymbolType::SEPARATOR):
                while (!operations.empty()) {
                    if (operations.top().type != SymbolType::LEFT) {
                        collected.push(std::move(operations.top()));
                        operations.pop();
                    }
                    else
                        break;
                }
                if (apply_function.empty() || !apply_function.top())
                    throw SyntaxError{
                        "separator '" + element.token + "' outside function"
                    };
                provided_counter.top()++;
                if (operations.empty())
                    throw ParenthesisMismatch{};
                break;

            case (SymbolType::CONSTANT):
                collected.push(std::move(element));
                break;

            case (SymbolType::FUNCTION):
                expected_counter.push(element.symbol->arguments());
                provided_counter.push(1);
                was_function = true;
                operations.push(std::move(element));
                break;

            case (SymbolType::OPERATOR):
                while (!operations.empty()) {
                    auto& another = operations.top();
                    if (another.type == SymbolType::LEFT)
                        break;
                    else if (another.type == SymbolType::FUNCTION) {
                        collected.push(std::move(another));
                        operations.pop();
                        break;
                    }
                    else {
                        auto eop = static_cast<Operator*>(element.symbol.get());
                        auto aop = static_cast<Operator*>(another.symbol.get());
                        auto l1 =
                            eop->associativity() !=
                            Associativity::RIGHT;
                        auto p1 = eop->precedence();
                        auto p2 = aop->precedence();
                        if ((l1 && (p1 <= p2)) || (!l1 && (p1 < p2))) {
                            collected.push(std::move(another));
                            operations.pop();
                        }
                        else
                            break;
                    }
                }
                operations.push(std::move(element));
                break;
            }
        }

        while (!operations.empty()) {
            element = std::move(operations.top());
            operations.pop();
            if (element.type == SymbolType::LEFT)
                throw ParenthesisMismatch{};
            collected.push(std::move(element));
        }

        return collected;
    }

    Expression _build_tree(
        std::queue<SymbolHandler>&& symbols,
        const std::shared_ptr<VariableHandler>& variables
    ) const {
        std::stack<Expression> operands{};
        std::stack<Expression> extract{};
        SymbolHandler element{};
        std::size_t hash{};

        while (!symbols.empty()) {
            element = std::move(symbols.front());
            symbols.pop();

            if (
                element.type == SymbolType::LEFT ||
                element.type == SymbolType::RIGHT ||
                element.type == SymbolType::SEPARATOR
            )
                throw SyntaxError{
                    "symbol '" + element.token + "' not allowed in "
                    "postfix notation"
                };

            else if (element.type == SymbolType::CONSTANT) {
                util::hash_combine(hash, *(element.symbol));
                operands.emplace(
                    Expression(
                        _lexer,
                        variables,
                        element.token,
                        std::move(element.symbol),
                        {},
                        hash
                    )
                );
            }

            else {
                std::vector<Expression> nodes{};
                util::hash_combine(hash, *(element.symbol));
                nodes.reserve(element.symbol->arguments());

                for (std::size_t i = 0; i < element.symbol->arguments(); i++) {
                    if (operands.empty())
                        throw ArgumentsMismatch{
                            element.token,
                            element.symbol->arguments(),
                            i
                        };
                    extract.emplace(std::move(operands.top()));
                    operands.pop();
                }
                while (!extract.empty()) {
                    nodes.emplace_back(std::move(extract.top()));
                    extract.pop();
                }
                operands.emplace(
                    Expression(
                        _lexer,
                        variables,
                        element.token,
                        std::move(element.symbol),
                        std::move(nodes),
                        hash
                    )
                );
            }
        }

        if (operands.size() > 1) {
            operands.pop();
            throw UnusedSymbol{operands.top().token()};
        }

        auto pruned = operands.top()._pruned();
        for (const auto& variable : variables->variables)
            if (
                std::find(
                    pruned.begin(),
                    pruned.end(),
                    variable
                ) == pruned.end()
            )
                throw UnusedSymbol(variable);
        return std::move(operands.top());
    }

public:
    Type to_value(const std::string& expression) const {
        return Type{from_infix(expression)};
    }

    std::string to_string(Type value) const {
        return _lexer->to_string(value);
    }

    Expression create_node(Type value) const {
        return from_infix(to_string(value));
    }

    Expression create_node(
        const std::string& token,
        const std::vector<Expression>& nodes={},
        const std::vector<std::string>& variables={}
    ) const {
        std::string postfix{};

        auto context = std::make_shared<VariableHandler>(variables, *_lexer);
        for (const auto& node : nodes)
            postfix += node.postfix() + " ";
        return _build_tree(_tokenize(postfix + token, context), context);
    }

    Expression from_infix(
        const std::string& expression,
        const std::vector<std::string>& variables={}
    ) const {
        auto context = std::make_shared<VariableHandler>(variables, *_lexer);
        return _build_tree(
            _shunting_yard(_parse_infix(_tokenize(expression, context))),
            context
        );
    }

    Expression from_postfix(
        const std::string& expression,
        const std::vector<std::string>& variables={}
    ) const {
        auto context = std::make_shared<VariableHandler>(variables, *_lexer);
        return _build_tree(_tokenize(expression, context), context);
    }

    Expression parse(const std::string& expression) const {
        std::vector<std::string> variables{};

        while (true) {
            try {
                return from_infix(expression, variables);
            }
            catch (const UndefinedSymbol& exception) {
                variables.emplace_back(exception.token);
            }
            catch (const UnsuitableName& exception) {
                throw UndefinedSymbol{exception.token};
            }
        }
    }

    Expression optimize(const Expression& node) const noexcept {
        if (node.variables().empty())
            return create_node(node._symbol->evaluate(node._nodes));

        auto nodes = std::vector<Expression>{};
        nodes.reserve(node._symbol->arguments());
        for (auto another : node._nodes)
            nodes.emplace_back(optimize(another));
        return create_node(node._token, std::move(nodes), node.variables());
    }
};

}

#endif
<|endoftext|>


<commit_before>#include <iosfwd>
#include <sstream>
#include "refs.h"
#include "helper.h"
#include "cache.h"
#include "duktape-java.h"

using namespace std;

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    jvm = vm;
    populateCache();
    return JNI_VERSION_1_6;
}

JNIEXPORT jstring JNICALL Java_at_renehollander_duktape_Duktape__1getVersion(JNIEnv *env, jclass cls) {
    stringstream version;
    version << DUK_VERSION / 10000 << "." << DUK_VERSION % 10000 / 100 << "." << DUK_VERSION % 10000 % 100;
    return env->NewStringUTF(version.str().c_str());
}

void duj_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) {
    JNIEnv *env = setupJNIEnv();
    DuktapeUserData *userData = getDuktapeUserData(ctx);
    env->CallObjectMethod(userData->duktape, methodIdCache.AtReneHollanderDuktapeDuktapeFatalErrorHandler, code, env->NewStringUTF(msg));
    resetJNIEnv(env);
}

JNIEXPORT jlong JNICALL Java_at_renehollander_duktape_Duktape__1createContext(JNIEnv *env, jclass cls, jobject duktape) {
    DuktapeUserData *userData = (DuktapeUserData *) malloc(sizeof(MemoryInfo));
    userData->memoryInfo.currentHeapSize = 0;
    duk_context *ctx = duk_create_heap(counting_alloc_function, counting_realloc_function, counting_free_function, userData, duj_fatal_handler);
    duj_ref_setup(ctx);

    // Store Array.splice on heap stash to protect it from modification with prototyping
    duk_push_array(ctx);
    duk_get_prop_string(ctx, -1, "splice");
    duj_ref(ctx, "Array.splice");
    duk_pop(ctx);

    userData->duktape = env->NewGlobalRef(duktape);
    userData->unrefData.mark_for_unref_indexed = new std::vector<int>();
    userData->unrefData.mark_for_unref_named = new std::vector<std::string>();

    return (jlong) ctx;
}

JNIEXPORT void JNICALL Java_at_renehollander_duktape_Duktape__1destroyContext(JNIEnv *env, jclass cls, jlong contextPointer) {
    duk_context *ctx = (void *) contextPointer;
    DuktapeUserData *userData = getDuktapeUserData(ctx);

    duk_destroy_heap(ctx);

    env->DeleteGlobalRef(userData->duktape);
    delete userData->unrefData.mark_for_unref_indexed;
    delete userData->unrefData.mark_for_unref_named;

    free(userData);
}

JNIEXPORT jint JNICALL Java_at_renehollander_duktape_Duktape__1getRefCount(JNIEnv *env, jclass cls, jlong contextPointer) {
    duk_context *ctx = (void *) contextPointer;
    return duj_get_ref_count(ctx);
}

JNIEXPORT void JNICALL Java_at_renehollander_duktape_Duktape__1gc(JNIEnv *env, jclass cls, jlong contextPointer) {
    duk_context *ctx = (void *) contextPointer;
    duj_check_marked_for_unref(ctx);
    duk_gc(ctx, 0);
}

JNIEXPORT jlong JNICALL Java_at_renehollander_duktape_Duktape__1getHeapUsage(JNIEnv *env, jclass cls, jlong contextPointer) {
    duk_context *ctx = (void *) contextPointer;
    DuktapeUserData *userData = getDuktapeUserData(ctx);
    return (jlong) userData->memoryInfo.currentHeapSize;
}

JNIEXPORT jobject JNICALL Java_at_renehollander_duktape_Duktape__1execute(JNIEnv *env, jclass cls, jlong contextPointer, jstring jScript) {
    duk_context *ctx = (void *) contextPointer;

    const char *script = env->GetStringUTFChars(jScript, 0);
    duk_push_string(ctx, script);
    env->ReleaseStringUTFChars(jScript, script);

    duk_peval(ctx);

    jobject retVal = duj_value_to_java_object(env, ctx);
    return retVal;
}<commit_msg>fixed bad memory allocation<commit_after>#include <iosfwd>
#include <sstream>
#include "refs.h"
#include "helper.h"
#include "cache.h"
#include "duktape-java.h"

using namespace std;

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    jvm = vm;
    populateCache();
    return JNI_VERSION_1_6;
}

JNIEXPORT jstring JNICALL Java_at_renehollander_duktape_Duktape__1getVersion(JNIEnv *env, jclass cls) {
    stringstream version;
    version << DUK_VERSION / 10000 << "." << DUK_VERSION % 10000 / 100 << "." << DUK_VERSION % 10000 % 100;
    return env->NewStringUTF(version.str().c_str());
}

void duj_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) {
    JNIEnv *env = setupJNIEnv();
    DuktapeUserData *userData = getDuktapeUserData(ctx);
    env->CallObjectMethod(userData->duktape, methodIdCache.AtReneHollanderDuktapeDuktapeFatalErrorHandler, code, env->NewStringUTF(msg));
    resetJNIEnv(env);
}

JNIEXPORT jlong JNICALL Java_at_renehollander_duktape_Duktape__1createContext(JNIEnv *env, jclass cls, jobject duktape) {
    DuktapeUserData *userData = (DuktapeUserData *) malloc(sizeof(DuktapeUserData));
    userData->memoryInfo.currentHeapSize = 0;
    duk_context *ctx = duk_create_heap(counting_alloc_function, counting_realloc_function, counting_free_function, userData, duj_fatal_handler);
    duj_ref_setup(ctx);

    // Store Array.splice on heap stash to protect it from modification with prototyping
    duk_push_array(ctx);
    duk_get_prop_string(ctx, -1, "splice");
    duj_ref(ctx, "Array.splice");
    duk_pop(ctx);

    userData->duktape = env->NewGlobalRef(duktape);
    userData->unrefData.mark_for_unref_indexed = new std::vector<int>();
    userData->unrefData.mark_for_unref_named = new std::vector<std::string>();

    return (jlong) ctx;
}

JNIEXPORT void JNICALL Java_at_renehollander_duktape_Duktape__1destroyContext(JNIEnv *env, jclass cls, jlong contextPointer) {
    duk_context *ctx = (void *) contextPointer;
    DuktapeUserData *userData = getDuktapeUserData(ctx);

    duk_destroy_heap(ctx);

    env->DeleteGlobalRef(userData->duktape);
    delete userData->unrefData.mark_for_unref_indexed;
    delete userData->unrefData.mark_for_unref_named;

    free(userData);
}

JNIEXPORT jint JNICALL Java_at_renehollander_duktape_Duktape__1getRefCount(JNIEnv *env, jclass cls, jlong contextPointer) {
    duk_context *ctx = (void *) contextPointer;
    return duj_get_ref_count(ctx);
}

JNIEXPORT void JNICALL Java_at_renehollander_duktape_Duktape__1gc(JNIEnv *env, jclass cls, jlong contextPointer) {
    duk_context *ctx = (void *) contextPointer;
    duj_check_marked_for_unref(ctx);
    duk_gc(ctx, 0);
}

JNIEXPORT jlong JNICALL Java_at_renehollander_duktape_Duktape__1getHeapUsage(JNIEnv *env, jclass cls, jlong contextPointer) {
    duk_context *ctx = (void *) contextPointer;
    DuktapeUserData *userData = getDuktapeUserData(ctx);
    return (jlong) userData->memoryInfo.currentHeapSize;
}

JNIEXPORT jobject JNICALL Java_at_renehollander_duktape_Duktape__1execute(JNIEnv *env, jclass cls, jlong contextPointer, jstring jScript) {
    duk_context *ctx = (void *) contextPointer;

    const char *script = env->GetStringUTFChars(jScript, 0);
    duk_push_string(ctx, script);
    env->ReleaseStringUTFChars(jScript, script);

    duk_peval(ctx);

    jobject retVal = duj_value_to_java_object(env, ctx);
    return retVal;
}<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// 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.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <iostream> // TODO Remove
#include <cmake.h>
#include <Context.h>
#include <Eval.h>
#include <Variant.h>
#include <Dates.h>
#include <Filter.h>
#include <i18n.h>
#include <text.h>
#include <util.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
// Const iterator that can be derefenced into a Task by domSource.
static Task dummy;
static Task& contextTask = dummy;

////////////////////////////////////////////////////////////////////////////////
static bool domSource (const std::string& identifier, Variant& value)
{
  std::string stringValue = context.dom.get (identifier, contextTask);
  if (stringValue != identifier)
  {
    value = Variant (stringValue);
    return true;
  }

  return false;
}

////////////////////////////////////////////////////////////////////////////////
Filter::Filter ()
: _startCount (0)
, _endCount (0)
{
}

////////////////////////////////////////////////////////////////////////////////
Filter::~Filter ()
{
}

////////////////////////////////////////////////////////////////////////////////
// Take an input set of tasks and filter into a subset.
void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output)
{
  context.timer_filter.start ();

  _startCount = (int) input.size ();

  if (context.config.getBoolean ("debug"))
  {
    Tree* t = context.parser.tree ();
    if (t)
      context.debug (t->dump ());
  }

  std::string filterExpr = context.parser.getFilterExpression ();
  context.debug ("\033[1;37;42mFILTER\033[0m " + filterExpr);

  if (filterExpr.length ())
  {
    Eval eval;
    eval.addSource (namedDates);
    eval.addSource (domSource);

    // Debug output from Eval during compilation is useful.  During evaluation
    // it is mostly noise.
    eval.debug (context.config.getBoolean ("debug"));
    eval.compileExpression (filterExpr);
    eval.debug (false);

    std::vector <Task>::const_iterator task;
    for (task = input.begin (); task != input.end (); ++task)
    {
      // Set up context for any DOM references.
      contextTask = *task;

      Variant var;
      eval.evaluateCompiledExpression (var);
      if (var.get_bool ())
        output.push_back (*task);
    }
  }
  else
    output = input;

  _endCount = (int) output.size ();
  context.debug (format ("Filtered {1} tasks --> {2} tasks", _startCount, _endCount));
  context.timer_filter.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Take the set of all tasks and filter into a subset.
void Filter::subset (std::vector <Task>& output)
{
  context.timer_filter.start ();

  if (context.config.getBoolean ("debug"))
  {
    Tree* t = context.parser.tree ();
    if (t)
      context.debug (t->dump ());
  }

  std::string filterExpr = context.parser.getFilterExpression ();
  context.debug ("\033[1;37;42mFILTER\033[0m " + filterExpr);

  if (filterExpr.length ())
  {
    context.timer_filter.stop ();
    const std::vector <Task>& pending = context.tdb2.pending.get_tasks ();
    context.timer_filter.start ();
    _startCount = (int) pending.size ();

    Eval eval;
    eval.addSource (namedDates);
    eval.addSource (domSource);

    // Debug output from Eval during compilation is useful.  During evaluation
    // it is mostly noise.
    eval.debug (context.config.getBoolean ("debug"));
    eval.compileExpression (filterExpr);
    eval.debug (false);

    output.clear ();
    std::vector <Task>::const_iterator task;

    for (task = pending.begin (); task != pending.end (); ++task)
    {
      // Set up context for any DOM references.
      contextTask = *task;

      Variant var;
      eval.evaluateCompiledExpression (var);
      if (var.get_bool ())
        output.push_back (*task);
    }

    if (! pendingOnly ())
    {
      context.timer_filter.stop ();
      const std::vector <Task>& completed = context.tdb2.completed.get_tasks (); // TODO Optional
      context.timer_filter.start ();
      _startCount += (int) completed.size ();

      for (task = completed.begin (); task != completed.end (); ++task)
      {
        // Set up context for any DOM references.
        contextTask = *task;

        Variant var;
        eval.evaluateCompiledExpression (var);
        if (var.get_bool ())
          output.push_back (*task);
      }
    }
  }
  else
  {
    safety ();

    context.timer_filter.stop ();
    const std::vector <Task>& pending   = context.tdb2.pending.get_tasks ();
    const std::vector <Task>& completed = context.tdb2.completed.get_tasks ();
    context.timer_filter.start ();

    std::vector <Task>::const_iterator task;
    for (task = pending.begin (); task != pending.end (); ++task)
      output.push_back (*task);

    for (task = completed.begin (); task != completed.end (); ++task)
      output.push_back (*task);
  }

  _endCount = (int) output.size ();
  context.debug (format ("Filtered {1} tasks --> {2} tasks", _startCount, _endCount));
  context.timer_filter.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// If the filter contains the restriction "status:pending", as the first filter
// term, then completed.data does not need to be loaded.
bool Filter::pendingOnly ()
{
  Tree* tree = context.parser.tree ();

  // If the filter starts with "status:pending", the completed.data does not
  // need to be accessed..
  if (tree->_branches.size () > 0 &&
      tree->_branches[0]->attribute ("name")  == "status" &&
      tree->_branches[0]->attribute ("value") == "pending")
  {
    context.debug ("Filter::pendingOnly - skipping completed.data (status:pending first)");
    return true;
  }

  // Shortcut: If the filter contains no 'or' or 'xor' operators, IDs and no UUIDs.
  int countId   = 0;
  int countUUID = 0;
  int countOr   = 0;
  int countXor  = 0;

  std::vector <Tree*>::iterator i;
  for (i = tree->_branches.begin (); i != tree->_branches.end (); ++i)
  {
    if ((*i)->hasTag ("OP"))
    {
      if ((*i)->attribute ("canonical") == "or")  ++countOr;
      if ((*i)->attribute ("canonical") == "xor") ++countXor;
    }
    else if ((*i)->hasTag ("ID"))   ++countId;
    else if ((*i)->hasTag ("UUID")) ++countUUID;
  }

  if (countOr   == 0 &&
      countXor  == 0 &&
      countUUID == 0 &&
      countId    > 0)
  {
    context.debug ("Filter::pendingOnly - skipping completed.data (IDs, no OR, no XOR, no UUID)");
    return true;
  }

  return false;
}

////////////////////////////////////////////////////////////////////////////////
// Disaster avoidance mechanism. If a WRITECMD has no filter, then it can cause
// all tasks to be modified. This is usually not intended.
void Filter::safety ()
{
  Tree* tree = context.parser.tree ();
  std::vector <Tree*>::iterator i;
  for (i = tree->_branches.begin (); i != tree->_branches.end (); ++i)
  {
    if ((*i)->hasTag ("WRITECMD"))
    {
      if (context.parser.getFilterExpression () == "")
      {
        // If user is willing to be asked, this can be avoided.
        if (context.config.getBoolean ("confirmation") &&
            confirm (STRING_TASK_SAFETY_VALVE))
          return;

        // Sounds the alarm.
        throw std::string (STRING_TASK_SAFETY_FAIL);
      }

      // Nothing to see here. Move along.
      return;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>Filter<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// 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.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <iostream> // TODO Remove
#include <cmake.h>
#include <Context.h>
#include <Eval.h>
#include <Variant.h>
#include <Dates.h>
#include <Filter.h>
#include <i18n.h>
#include <text.h>
#include <util.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
// Const iterator that can be derefenced into a Task by domSource.
static Task dummy;
static Task& contextTask = dummy;

////////////////////////////////////////////////////////////////////////////////
static bool domSource (const std::string& identifier, Variant& value)
{
  std::string stringValue = context.dom.get (identifier, contextTask);
  if (stringValue != identifier)
  {
    value = Variant (stringValue);
    return true;
  }

  return false;
}

////////////////////////////////////////////////////////////////////////////////
Filter::Filter ()
: _startCount (0)
, _endCount (0)
{
}

////////////////////////////////////////////////////////////////////////////////
Filter::~Filter ()
{
}

////////////////////////////////////////////////////////////////////////////////
// Take an input set of tasks and filter into a subset.
void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output)
{
  context.timer_filter.start ();

  _startCount = (int) input.size ();

  if (context.config.getBoolean ("debug"))
  {
    Tree* t = context.parser.tree ();
    if (t)
      context.debug (t->dump ());
  }

  std::string filterExpr = context.parser.getFilterExpression ();
  context.debug ("\033[1;37;42mFILTER\033[0m " + filterExpr);

  if (filterExpr.length ())
  {
    Eval eval;
    eval.addSource (namedDates);
    eval.addSource (domSource);

    // Debug output from Eval during compilation is useful.  During evaluation
    // it is mostly noise.
    eval.debug (context.config.getBoolean ("debug"));
    eval.compileExpression (filterExpr);
    eval.debug (false);

    std::vector <Task>::const_iterator task;
    for (task = input.begin (); task != input.end (); ++task)
    {
      // Set up context for any DOM references.
      contextTask = *task;

      Variant var;
      eval.evaluateCompiledExpression (var);
      if (var.get_bool ())
        output.push_back (*task);
    }
  }
  else
    output = input;

  _endCount = (int) output.size ();
  context.debug (format ("Filtered {1} tasks --> {2} tasks [list subset]", _startCount, _endCount));
  context.timer_filter.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Take the set of all tasks and filter into a subset.
void Filter::subset (std::vector <Task>& output)
{
  context.timer_filter.start ();

  if (context.config.getBoolean ("debug"))
  {
    Tree* t = context.parser.tree ();
    if (t)
      context.debug (t->dump ());
  }

  bool shortcut = false;
  std::string filterExpr = context.parser.getFilterExpression ();
  context.debug ("\033[1;37;42mFILTER\033[0m " + filterExpr);

  if (filterExpr.length ())
  {
    context.timer_filter.stop ();
    const std::vector <Task>& pending = context.tdb2.pending.get_tasks ();
    context.timer_filter.start ();
    _startCount = (int) pending.size ();

    Eval eval;
    eval.addSource (namedDates);
    eval.addSource (domSource);

    // Debug output from Eval during compilation is useful.  During evaluation
    // it is mostly noise.
    eval.debug (context.config.getBoolean ("debug"));
    eval.compileExpression (filterExpr);
    eval.debug (false);

    output.clear ();
    std::vector <Task>::const_iterator task;

    for (task = pending.begin (); task != pending.end (); ++task)
    {
      // Set up context for any DOM references.
      contextTask = *task;

      Variant var;
      eval.evaluateCompiledExpression (var);
      if (var.get_bool ())
        output.push_back (*task);
    }

    shortcut = pendingOnly ();
    if (! shortcut)
    {
      context.timer_filter.stop ();
      const std::vector <Task>& completed = context.tdb2.completed.get_tasks (); // TODO Optional
      context.timer_filter.start ();
      _startCount += (int) completed.size ();

      for (task = completed.begin (); task != completed.end (); ++task)
      {
        // Set up context for any DOM references.
        contextTask = *task;

        Variant var;
        eval.evaluateCompiledExpression (var);
        if (var.get_bool ())
          output.push_back (*task);
      }
    }
  }
  else
  {
    safety ();

    context.timer_filter.stop ();
    const std::vector <Task>& pending   = context.tdb2.pending.get_tasks ();
    const std::vector <Task>& completed = context.tdb2.completed.get_tasks ();
    context.timer_filter.start ();

    std::vector <Task>::const_iterator task;
    for (task = pending.begin (); task != pending.end (); ++task)
      output.push_back (*task);

    for (task = completed.begin (); task != completed.end (); ++task)
      output.push_back (*task);
  }

  _endCount = (int) output.size ();
  context.debug (format ("Filtered {1} tasks --> {2} tasks [{3}]", _startCount, _endCount, (shortcut ? "pending only" : "all tasks")));
  context.timer_filter.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// If the filter contains the restriction "status:pending", as the first filter
// term, then completed.data does not need to be loaded.
bool Filter::pendingOnly ()
{
  Tree* tree = context.parser.tree ();

  // If the filter starts with "status:pending", the completed.data does not
  // need to be accessed..
  if (tree->_branches.size () > 0 &&
      tree->_branches[0]->attribute ("name")  == "status" &&
      tree->_branches[0]->attribute ("value") == "pending")
  {
    context.debug ("Filter::pendingOnly - skipping completed.data (status:pending first)");
    return true;
  }

  // Shortcut: If the filter contains no 'or' or 'xor' operators, IDs and no UUIDs.
  int countId   = 0;
  int countUUID = 0;
  int countOr   = 0;
  int countXor  = 0;

  std::vector <Tree*>::iterator i;
  for (i = tree->_branches.begin (); i != tree->_branches.end (); ++i)
  {
    if ((*i)->hasTag ("OP"))
    {
      if ((*i)->attribute ("canonical") == "or")  ++countOr;
      if ((*i)->attribute ("canonical") == "xor") ++countXor;
    }
    else if ((*i)->hasTag ("ID"))   ++countId;
    else if ((*i)->hasTag ("UUID")) ++countUUID;
  }

  if (countOr   == 0 &&
      countXor  == 0 &&
      countUUID == 0 &&
      countId    > 0)
  {
    context.debug ("Filter::pendingOnly - skipping completed.data (IDs, no OR, no XOR, no UUID)");
    return true;
  }

  return false;
}

////////////////////////////////////////////////////////////////////////////////
// Disaster avoidance mechanism. If a WRITECMD has no filter, then it can cause
// all tasks to be modified. This is usually not intended.
void Filter::safety ()
{
  Tree* tree = context.parser.tree ();
  std::vector <Tree*>::iterator i;
  for (i = tree->_branches.begin (); i != tree->_branches.end (); ++i)
  {
    if ((*i)->hasTag ("WRITECMD"))
    {
      if (context.parser.getFilterExpression () == "")
      {
        // If user is willing to be asked, this can be avoided.
        if (context.config.getBoolean ("confirmation") &&
            confirm (STRING_TASK_SAFETY_VALVE))
          return;

        // Sounds the alarm.
        throw std::string (STRING_TASK_SAFETY_FAIL);
      }

      // Nothing to see here. Move along.
      return;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief definition of abstruct exception class
	Copyright (C) 2008 Cybozu Labs, Inc., all rights reserved.
*/
#include <string>
#include <sstream>
#include <errno.h>
#ifdef _WIN32
	#include <winsock2.h>
	#include <windows.h>
#else
	#include <string.h> // for strerror_r
#endif
#include <cybozu/inttype.hpp>

namespace cybozu {

const bool DontThrow = true;

namespace exception {

/* get max 10 characters to avoid buffer overrun */
inline std::string makeString(const char *str, size_t size)
{
	return std::string(str, std::min<size_t>(size,10));
}

/**
	convert errno to string
	@param err [in] errno
	@note for both windows and linux
*/
inline std::string ConvertErrorNoToString(int err)
{
	char errBuf[256];
#ifdef _WIN32
	strerror_s(errBuf, sizeof(errBuf), err);
	return errBuf;
#elif defined(_GNU_SOURCE)
	return ::strerror_r(err, errBuf, sizeof(errBuf));
#else
	if (strerror_r(err, errBuf, sizeof(errBuf)) == 0) {
		return errBuf;
	} else {
		return "strerror_r error";
	}
#endif
}

} // cybozu::exception

class Exception : public std::exception {
	std::string str_;
public:
	explicit Exception(const std::string& name = "")
		: str_(name)
	{
	}
	~Exception() throw() {}
	const char *what() const throw() { return str_.c_str(); }
	const std::string& toString() const throw() { return str_; }
	template<class T>
	Exception& operator<<(const T& x)
	{
		str_ += ':';
		std::ostringstream os;
		os << x;
		str_ += os.str();
		return *this;
	}
};

class ErrorNo {
#ifdef _WIN32
	typedef unsigned int NativeErrorNo;
#else
	typedef int NativeErrorNo;
#endif
	NativeErrorNo err_;
public:
	explicit ErrorNo(NativeErrorNo err)
		: err_(err)
	{
	}
	ErrorNo()
		: err_(getLatestNativeErrorNo())
	{
	}
	NativeErrorNo getLatestNativeErrorNo() const
	{
#ifdef _WIN32
		return ::GetLastError();
#else
		return errno;
#endif
	}
	/**
		convert NativeErrNo to string(maybe UTF8)
		@param err [in] errno
		@note Linux   : same as ConvertErrorNoToString
			  Windows : for Win32 API(use en-us)
	*/
	std::string toString() const
	{
#ifdef _WIN32
		const int msgSize = 256;
		wchar_t msg[msgSize];
		int size = FormatMessageW(
			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			0,
			err_,
			MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
			msg,
			msgSize,
			NULL
		);
		if (size <= 0) return "";
		// remove last "\r\n"
		if (size > 2 && msg[size - 2] == '\r') {
			msg[size - 2] = 0;
			size -= 2;
		}
		std::string ret;
		ret.resize(size);
		// assume ascii only
		for (int i = 0; i < size; i++) {
			ret[i] = (char)msg[i];
		}
		return ret;
#else
		return exception::ConvertErrorNoToString(err_);
#endif
	}
};

inline std::ostream& operator<<(std::ostream& os, const cybozu::ErrorNo& self)
{
	return os << self.toString();
}

} // cybozu
<commit_msg>print stacktrace if CYBOZU_USE_STACKTRACE is defined<commit_after>#pragma once
/**
	@file
	@brief definition of abstruct exception class
	Copyright (C) 2008 Cybozu Labs, Inc., all rights reserved.
*/
#include <string>
#include <sstream>
#include <errno.h>
#ifdef _WIN32
	#include <winsock2.h>
	#include <windows.h>
#else
	#include <string.h> // for strerror_r
#endif
#include <cybozu/inttype.hpp>
#ifdef CYBOZU_USE_STACKTRACE
	#include <cybozu/stacktrace.hpp>
#endif

namespace cybozu {

const bool DontThrow = true;

namespace exception {

/* get max 10 characters to avoid buffer overrun */
inline std::string makeString(const char *str, size_t size)
{
	return std::string(str, std::min<size_t>(size,10));
}

/**
	convert errno to string
	@param err [in] errno
	@note for both windows and linux
*/
inline std::string ConvertErrorNoToString(int err)
{
	char errBuf[256];
#ifdef _WIN32
	strerror_s(errBuf, sizeof(errBuf), err);
	return errBuf;
#elif defined(_GNU_SOURCE)
	return ::strerror_r(err, errBuf, sizeof(errBuf));
#else
	if (strerror_r(err, errBuf, sizeof(errBuf)) == 0) {
		return errBuf;
	} else {
		return "strerror_r error";
	}
#endif
}

} // cybozu::exception

class Exception : public std::exception {
	std::string str_;
public:
	explicit Exception(const std::string& name = "")
		: str_(name)
	{
#ifdef CYBOZU_USE_STACKTRACE
		str_ += ';';
		str_ += cybozu::StackTrace().toString();
#endif
	}
	~Exception() throw() {}
	const char *what() const throw() { return str_.c_str(); }
	const std::string& toString() const throw() { return str_; }
	template<class T>
	Exception& operator<<(const T& x)
	{
		str_ += ':';
		std::ostringstream os;
		os << x;
		str_ += os.str();
		return *this;
	}
};

class ErrorNo {
#ifdef _WIN32
	typedef unsigned int NativeErrorNo;
#else
	typedef int NativeErrorNo;
#endif
	NativeErrorNo err_;
public:
	explicit ErrorNo(NativeErrorNo err)
		: err_(err)
	{
	}
	ErrorNo()
		: err_(getLatestNativeErrorNo())
	{
	}
	NativeErrorNo getLatestNativeErrorNo() const
	{
#ifdef _WIN32
		return ::GetLastError();
#else
		return errno;
#endif
	}
	/**
		convert NativeErrNo to string(maybe UTF8)
		@param err [in] errno
		@note Linux   : same as ConvertErrorNoToString
			  Windows : for Win32 API(use en-us)
	*/
	std::string toString() const
	{
#ifdef _WIN32
		const int msgSize = 256;
		wchar_t msg[msgSize];
		int size = FormatMessageW(
			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			0,
			err_,
			MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
			msg,
			msgSize,
			NULL
		);
		if (size <= 0) return "";
		// remove last "\r\n"
		if (size > 2 && msg[size - 2] == '\r') {
			msg[size - 2] = 0;
			size -= 2;
		}
		std::string ret;
		ret.resize(size);
		// assume ascii only
		for (int i = 0; i < size; i++) {
			ret[i] = (char)msg[i];
		}
		return ret;
#else
		return exception::ConvertErrorNoToString(err_);
#endif
	}
};

inline std::ostream& operator<<(std::ostream& os, const cybozu::ErrorNo& self)
{
	return os << self.toString();
}

} // cybozu
<|endoftext|>


<commit_before>/*=========================================================================

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/
#include "otbWrapperApplicationRegistry.h"
#include "otbWrapperApplicationFactoryBase.h"
#include "otbMacro.h"
#include "itksys/SystemTools.hxx"
#include "itkDynamicLoader.h"
#include "itkDirectory.h"
#include "itkMutexLock.h"
#include "itkMutexLockHolder.h"

#include <iterator>

namespace otb
{
namespace Wrapper
{

class ApplicationPrivateRegistry
{
public:
  typedef std::pair<Application*, void* > AppHandlePairType;
  typedef std::list<AppHandlePairType>    AppHandleContainerType;

  ~ApplicationPrivateRegistry()
  {
  AppHandleContainerType::iterator it;
  for (it = m_Container.begin() ; it != m_Container.end() ; ++it)
    {
    itk::DynamicLoader::CloseLibrary( (*it).second);
    }
  m_Container.clear();
  }

  AppHandleContainerType m_Container;
};
// static finalizer to close opened libraries
static ApplicationPrivateRegistry m_ApplicationPrivateRegistryGlobal;

ApplicationRegistry::ApplicationRegistry()
{
}

ApplicationRegistry::~ApplicationRegistry()
{
}

void
ApplicationRegistry::SetApplicationPath(std::string newpath)
{
  std::ostringstream putEnvPath;
  putEnvPath << "OTB_APPLICATION_PATH=" << newpath;

  // do NOT use putenv() directly, since the string memory must be managed carefully
  itksys::SystemTools::PutEnv(putEnvPath.str().c_str());
}

void
ApplicationRegistry::AddApplicationPath(std::string newpath)
{
  std::ostringstream putEnvPath;
  putEnvPath << "OTB_APPLICATION_PATH=";

  // Can be NULL if the env var is not set
  const char* currentEnv = itksys::SystemTools::GetEnv("OTB_APPLICATION_PATH");

#if defined(WIN32)
  const char pathSeparator = ';';
#else
  const char pathSeparator = ':';
#endif

  putEnvPath << newpath << pathSeparator;

  if (currentEnv)
    {
    putEnvPath << currentEnv;
    }

  // do NOT use putenv() directly, since the string memory must be managed carefully
  itksys::SystemTools::PutEnv(putEnvPath.str().c_str());
}

Application::Pointer
ApplicationRegistry::CreateApplication(const std::string& name, bool useFactory)
{
  ApplicationPointer appli;

  // Fast search : uses OTB_APPLICATION_PATH
  appli = ApplicationRegistry::CreateApplicationFaster(name);
  if (appli.IsNotNull())
    {
    return appli;
    }

  // Classic search : uses factories registered by ITK ( see ITK_AUTOLOAD_PATH )
  if (useFactory)
    {
    LightObject::Pointer possibleApp = itk::ObjectFactoryBase::CreateInstance(name.c_str());
    if (possibleApp.IsNotNull())
      {
      // Downcast
      Application* app = dynamic_cast<Application*> (possibleApp.GetPointer());
      if (app)
        {
          appli = app;
          appli->Init();
        }
      else
        {
        otbMsgDevMacro( << "Error ApplicationRegistry factory did not return an Application: " << possibleApp->GetNameOfClass() << std::endl );
        }
      }
    }

  return appli;
}

typedef itk::ObjectFactoryBase * ( *ITK_LOAD_FUNCTION )();

Application::Pointer
ApplicationRegistry::CreateApplicationFaster(const std::string& name)
{
  ApplicationPointer appli = NULL;

  std::string appExtension = itksys::DynamicLoader::LibExtension();
#ifdef __APPLE__
  appExtension = ".dylib";
#endif
  std::ostringstream appLibName;
  appLibName << "otbapp_" << name << appExtension;

#if defined(WIN32)
  const char pathSeparator = ';';
#else
  const char pathSeparator = ':';
#endif

#ifdef _WIN32
  const char sep = '\\';
#else
  const char sep = '/';
#endif

  const char* otbAppPath = itksys::SystemTools::GetEnv("OTB_APPLICATION_PATH");
  std::vector<itksys::String> pathList;
  if (otbAppPath)
    {
    pathList = itksys::SystemTools::SplitString(otbAppPath,pathSeparator,false);
    }
  for (unsigned int i=0 ; i<pathList.size() ; ++i)
    {
    std::string possiblePath = pathList[i];
    if ( !possiblePath.empty() && possiblePath[possiblePath.size() - 1] != sep )
      {
      possiblePath += sep;
      }
    possiblePath += appLibName.str();

    appli = LoadApplicationFromPath(possiblePath,name);
    if (appli.IsNotNull())
      {
      break;
      }
    }

  return appli;
}

std::vector<std::string>
ApplicationRegistry::GetAvailableApplications(bool useFactory)
{
  ApplicationPointer appli;
  std::set<std::string> appSet;

  std::string appPrefix("otbapp_");
  std::string appExtension = itksys::DynamicLoader::LibExtension();
#ifdef __APPLE__
  appExtension = ".dylib";
#endif

#if defined(WIN32)
  const char pathSeparator = ';';
#else
  const char pathSeparator = ':';
#endif

#ifdef _WIN32
  const char sep = '\\';
#else
  const char sep = '/';
#endif

  const char* otbAppPath = itksys::SystemTools::GetEnv("OTB_APPLICATION_PATH");
  std::vector<itksys::String> pathList;
  if (otbAppPath)
    {
    pathList = itksys::SystemTools::SplitString(otbAppPath,pathSeparator,false);
    }
  for (unsigned int k=0 ; k<pathList.size() ; ++k)
    {
    itk::Directory::Pointer dir = itk::Directory::New();
    if (!dir->Load(pathList[k].c_str()))
      {
      continue;
      }
    for (unsigned int i = 0; i < dir->GetNumberOfFiles(); i++)
      {
      const char *filename = dir->GetFile(i);
      std::string sfilename(filename);
      std::string::size_type extPos = sfilename.rfind(appExtension);
      std::string::size_type prefixPos = sfilename.find(appPrefix);

      // Check if current file is a shared lib with the right pattern
      if (extPos + appExtension.size() == sfilename.size() &&
          prefixPos == 0)
        {
        std::string name = sfilename.substr(appPrefix.size(),extPos-appPrefix.size());
        std::string fullpath = pathList[k];
        if (!fullpath.empty() && fullpath[fullpath.size() - 1] != sep)
          {
          fullpath.push_back(sep);
          }
        fullpath.append(sfilename);
        appli = LoadApplicationFromPath(fullpath,name);
        if (appli.IsNotNull())
          {
          appSet.insert(name);
          }
        appli = NULL;
        }
      }
    }

  if (useFactory)
    {
    std::list<LightObject::Pointer> allobjects = itk::ObjectFactoryBase::CreateAllInstance("otbWrapperApplication");
    // Downcast and Sanity check
    for (std::list<LightObject::Pointer>::iterator i = allobjects.begin(); i != allobjects.end(); ++i)
      {
      Application* app = dynamic_cast<Application*> (i->GetPointer());
      if (app)
        {
        app->Init();
        std::string curName(app->GetName());
        appSet.insert(curName);
        }
      else
        {
        otbMsgDevMacro( << "Error ApplicationRegistry factory did not return an Application: " << (*i)->GetNameOfClass() << std::endl );
        }
      }
    }

  std::vector<std::string> appVec;
  std::copy(appSet.begin(), appSet.end(), std::back_inserter(appVec));
  return appVec;
}

Application::Pointer
ApplicationRegistry::LoadApplicationFromPath(std::string path,std::string name)
{
  Application::Pointer appli;

  static itk::SimpleMutexLock mutex;

  if (itksys::SystemTools::FileExists(path.c_str(),true))
    {
    itk::LibHandle lib = itk::DynamicLoader::OpenLibrary(path.c_str());
    if (lib)
      {
      /**
       * Look for the symbol itkLoad in the library
       */
      ITK_LOAD_FUNCTION loadfunction =
        ( ITK_LOAD_FUNCTION ) itk::DynamicLoader::GetSymbolAddress(lib, "itkLoad");
      /**
       * if the symbol is found call it to create the factory
       * from the library
       */
      if ( loadfunction )
        {
        itk::ObjectFactoryBase *newfactory = ( *loadfunction )( );
        // Downcast
        ApplicationFactoryBase* appFactory = dynamic_cast<ApplicationFactoryBase*>(newfactory);

        if (appFactory)
          {
          appli = appFactory->CreateApplication(name.c_str());
          if (appli.IsNotNull())
            {
            appli->Init();
            // mutex lock to ensure thread safety
            itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(mutex);

            ApplicationPrivateRegistry::AppHandlePairType curPair;
            curPair.first = appli.GetPointer();
            curPair.second = (void*) lib;
            m_ApplicationPrivateRegistryGlobal.m_Container.push_back(curPair);
            return appli;
            }
          }
        }
      itk::DynamicLoader::CloseLibrary(lib);
      }
    }
  return appli;
}

} // end namespace Wrapper
} //end namespace otb
<commit_msg>ENH: add callback to unregister deleted applications, and method to release unused handles<commit_after>/*=========================================================================

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/
#include "otbWrapperApplicationRegistry.h"
#include "otbWrapperApplicationFactoryBase.h"
#include "otbMacro.h"
#include "itksys/SystemTools.hxx"
#include "itkDynamicLoader.h"
#include "itkDirectory.h"
#include "itkMutexLock.h"
#include "itkMutexLockHolder.h"

#include <iterator>

namespace otb
{
namespace Wrapper
{

class ApplicationPrivateRegistry
{
public:
  typedef std::pair<Application*, void* > AppHandlePairType;
  typedef std::list<AppHandlePairType>    AppHandleContainerType;

  /** Add a pair (application, library handle) in the private registry */
  bool AddPair(Application *app, void *handle)
    {
    AppHandlePairType pair;
    if (app && handle)
      {
      // mutex lock to ensure thread safety
      itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(m_Mutex);
      pair.first = app;
      pair.second = handle;
      m_Container.push_back(pair);
      return true;
      }
    return false;
    }

  /** When an application is deleted, unregister its pointer from private registry */
  void UnregisterApp(const Application *app)
    {
    if (app)
      {
      // mutex lock to ensure thread safety
      itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(m_Mutex);
      AppHandleContainerType::iterator it = m_Container.begin();
      while (it != m_Container.end())
        {
        if ((*it).first == app)
          {
          (*it).first = NULL;
          }
        ++it;
        }
      }
    }

  /** Release the library handles from applications already deleted */
  void ReleaseUnusedHandle()
    {
    itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(m_Mutex);
    AppHandleContainerType::iterator it;
    for (it = m_Container.begin() ; it != m_Container.end() ; ++it)
      {
      if ((*it).first == NULL)
        {
        itk::DynamicLoader::CloseLibrary( (*it).second);
        (*it).second = NULL;
        }
      }
    m_Container.remove(AppHandlePairType(NULL,NULL));
    }

  /** close all handles at program exit */
  ~ApplicationPrivateRegistry()
  {
  AppHandleContainerType::iterator it;
  for (it = m_Container.begin() ; it != m_Container.end() ; ++it)
    {
    itk::DynamicLoader::CloseLibrary( (*it).second);
    }
  m_Container.clear();
  }

private:
  AppHandleContainerType m_Container;

  itk::SimpleMutexLock m_Mutex;
};
// static finalizer to close opened libraries
static ApplicationPrivateRegistry m_ApplicationPrivateRegistryGlobal;

// Define callbacks to unregister applications in ApplicationPrivateRegistry
void DeleteAppCallback(itk::Object *obj,const itk::EventObject &, void *)
  {
  Application *appPtr = dynamic_cast<Application*>(obj);
  m_ApplicationPrivateRegistryGlobal.UnregisterApp(appPtr);
  }
void DeleteAppConstCallback(const itk::Object *obj,const itk::EventObject &, void *)
  {
  const Application *appPtr = dynamic_cast<const Application*>(obj);
  m_ApplicationPrivateRegistryGlobal.UnregisterApp(appPtr);
  }

ApplicationRegistry::ApplicationRegistry()
{
}

ApplicationRegistry::~ApplicationRegistry()
{
}

void
ApplicationRegistry::SetApplicationPath(std::string newpath)
{
  std::ostringstream putEnvPath;
  putEnvPath << "OTB_APPLICATION_PATH=" << newpath;

  // do NOT use putenv() directly, since the string memory must be managed carefully
  itksys::SystemTools::PutEnv(putEnvPath.str().c_str());

  // TODO  : releaseUnusedHandle() ?
}

void
ApplicationRegistry::AddApplicationPath(std::string newpath)
{
  std::ostringstream putEnvPath;
  putEnvPath << "OTB_APPLICATION_PATH=";

  // Can be NULL if the env var is not set
  const char* currentEnv = itksys::SystemTools::GetEnv("OTB_APPLICATION_PATH");

#if defined(WIN32)
  const char pathSeparator = ';';
#else
  const char pathSeparator = ':';
#endif

  putEnvPath << newpath << pathSeparator;

  if (currentEnv)
    {
    putEnvPath << currentEnv;
    }

  // do NOT use putenv() directly, since the string memory must be managed carefully
  itksys::SystemTools::PutEnv(putEnvPath.str().c_str());
}

Application::Pointer
ApplicationRegistry::CreateApplication(const std::string& name, bool useFactory)
{
  ApplicationPointer appli;

  // Fast search : uses OTB_APPLICATION_PATH
  appli = ApplicationRegistry::CreateApplicationFaster(name);
  if (appli.IsNotNull())
    {
    return appli;
    }

  // Classic search : uses factories registered by ITK ( see ITK_AUTOLOAD_PATH )
  if (useFactory)
    {
    LightObject::Pointer possibleApp = itk::ObjectFactoryBase::CreateInstance(name.c_str());
    if (possibleApp.IsNotNull())
      {
      // Downcast
      Application* app = dynamic_cast<Application*> (possibleApp.GetPointer());
      if (app)
        {
          appli = app;
          appli->Init();
        }
      else
        {
        otbMsgDevMacro( << "Error ApplicationRegistry factory did not return an Application: " << possibleApp->GetNameOfClass() << std::endl );
        }
      }
    }

  return appli;
}

typedef itk::ObjectFactoryBase * ( *ITK_LOAD_FUNCTION )();

Application::Pointer
ApplicationRegistry::CreateApplicationFaster(const std::string& name)
{
  ApplicationPointer appli = NULL;

  std::string appExtension = itksys::DynamicLoader::LibExtension();
#ifdef __APPLE__
  appExtension = ".dylib";
#endif
  std::ostringstream appLibName;
  appLibName << "otbapp_" << name << appExtension;

#if defined(WIN32)
  const char pathSeparator = ';';
#else
  const char pathSeparator = ':';
#endif

#ifdef _WIN32
  const char sep = '\\';
#else
  const char sep = '/';
#endif

  const char* otbAppPath = itksys::SystemTools::GetEnv("OTB_APPLICATION_PATH");
  std::vector<itksys::String> pathList;
  if (otbAppPath)
    {
    pathList = itksys::SystemTools::SplitString(otbAppPath,pathSeparator,false);
    }
  for (unsigned int i=0 ; i<pathList.size() ; ++i)
    {
    std::string possiblePath = pathList[i];
    if ( !possiblePath.empty() && possiblePath[possiblePath.size() - 1] != sep )
      {
      possiblePath += sep;
      }
    possiblePath += appLibName.str();

    appli = LoadApplicationFromPath(possiblePath,name);
    if (appli.IsNotNull())
      {
      break;
      }
    }

  return appli;
}

std::vector<std::string>
ApplicationRegistry::GetAvailableApplications(bool useFactory)
{
  // TODO  : releaseUnusedHandle() ?

  ApplicationPointer appli;
  std::set<std::string> appSet;

  std::string appPrefix("otbapp_");
  std::string appExtension = itksys::DynamicLoader::LibExtension();
#ifdef __APPLE__
  appExtension = ".dylib";
#endif

#if defined(WIN32)
  const char pathSeparator = ';';
#else
  const char pathSeparator = ':';
#endif

#ifdef _WIN32
  const char sep = '\\';
#else
  const char sep = '/';
#endif

  const char* otbAppPath = itksys::SystemTools::GetEnv("OTB_APPLICATION_PATH");
  std::vector<itksys::String> pathList;
  if (otbAppPath)
    {
    pathList = itksys::SystemTools::SplitString(otbAppPath,pathSeparator,false);
    }
  for (unsigned int k=0 ; k<pathList.size() ; ++k)
    {
    itk::Directory::Pointer dir = itk::Directory::New();
    if (!dir->Load(pathList[k].c_str()))
      {
      continue;
      }
    for (unsigned int i = 0; i < dir->GetNumberOfFiles(); i++)
      {
      const char *filename = dir->GetFile(i);
      std::string sfilename(filename);
      std::string::size_type extPos = sfilename.rfind(appExtension);
      std::string::size_type prefixPos = sfilename.find(appPrefix);

      // Check if current file is a shared lib with the right pattern
      if (extPos + appExtension.size() == sfilename.size() &&
          prefixPos == 0)
        {
        std::string name = sfilename.substr(appPrefix.size(),extPos-appPrefix.size());
        std::string fullpath = pathList[k];
        if (!fullpath.empty() && fullpath[fullpath.size() - 1] != sep)
          {
          fullpath.push_back(sep);
          }
        fullpath.append(sfilename);
        appli = LoadApplicationFromPath(fullpath,name);
        if (appli.IsNotNull())
          {
          appSet.insert(name);
          }
        appli = NULL;
        }
      }
    }

  if (useFactory)
    {
    std::list<LightObject::Pointer> allobjects = itk::ObjectFactoryBase::CreateAllInstance("otbWrapperApplication");
    // Downcast and Sanity check
    for (std::list<LightObject::Pointer>::iterator i = allobjects.begin(); i != allobjects.end(); ++i)
      {
      Application* app = dynamic_cast<Application*> (i->GetPointer());
      if (app)
        {
        app->Init();
        std::string curName(app->GetName());
        appSet.insert(curName);
        }
      else
        {
        otbMsgDevMacro( << "Error ApplicationRegistry factory did not return an Application: " << (*i)->GetNameOfClass() << std::endl );
        }
      }
    }

  std::vector<std::string> appVec;
  std::copy(appSet.begin(), appSet.end(), std::back_inserter(appVec));
  return appVec;
}

Application::Pointer
ApplicationRegistry::LoadApplicationFromPath(std::string path,std::string name)
{
  Application::Pointer appli;

  if (itksys::SystemTools::FileExists(path.c_str(),true))
    {
    itk::LibHandle lib = itk::DynamicLoader::OpenLibrary(path.c_str());
    if (lib)
      {
      /**
       * Look for the symbol itkLoad in the library
       */
      ITK_LOAD_FUNCTION loadfunction =
        ( ITK_LOAD_FUNCTION ) itk::DynamicLoader::GetSymbolAddress(lib, "itkLoad");
      /**
       * if the symbol is found call it to create the factory
       * from the library
       */
      if ( loadfunction )
        {
        itk::ObjectFactoryBase *newfactory = ( *loadfunction )( );
        // Downcast
        ApplicationFactoryBase* appFactory = dynamic_cast<ApplicationFactoryBase*>(newfactory);

        if (appFactory)
          {
          appli = appFactory->CreateApplication(name.c_str());
          if (appli.IsNotNull())
            {
            appli->Init();
            // register library handle
            m_ApplicationPrivateRegistryGlobal.AddPair(appli.GetPointer(), (void*) lib);
            // set a callback on DeleteEvent
            itk::CStyleCommand::Pointer command = itk::CStyleCommand::New();
            command->SetCallback(&DeleteAppCallback);
            command->SetConstCallback(&DeleteAppConstCallback);
            appli->AddObserver(itk::DeleteEvent(),command);
            return appli;
            }
          }
        }
      itk::DynamicLoader::CloseLibrary(lib);
      }
    }
  return appli;
}

} // end namespace Wrapper
} //end namespace otb
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Standard implementation of the determinant
 */

#pragma once

namespace etl {

/*!
 * \copydoc etl::lu
 */
template <typename AT, typename LT, typename UT, typename PT>
bool lu(const AT& A, LT& L, UT& U, PT& P);

namespace impl {

namespace standard {

/*!
 * \brief Compute the determinant of the given matrix
 * \return The determinant of the given matrix
 */
template <typename AT>
value_t<AT> det(const AT& A) {
    const auto n = etl::dim<0>(A);

    if(is_permutation_matrix(A)){
        size_t t = 0;
        for(size_t i = 0; i < n; ++i){
            for(size_t j = 0; j < n; ++j){
                if(A(i, j) != 0.0 && i != j){
                    ++t;
                }
            }
        }

        return std::pow(value_t<AT>(-1.0), t - 1);
    }

    if(is_triangular(A)){
        value_t<AT> det(1.0);
        for(size_t i = 0; i < n; ++i){
            det *= A(i, i);
        }
        return det;
    }

    auto L = force_temporary_dim_only(A);
    auto U = force_temporary_dim_only(A);
    auto P = force_temporary_dim_only(A);

    etl::lu(A, L, U, P);

    return det(L) * det(U) * det(P);
}

} //end of namespace standard
} //end of namespace impl
} //end of namespace etl
<commit_msg>Cleanup code style<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Standard implementation of the determinant
 */

#pragma once

namespace etl {

/*!
 * \copydoc etl::lu
 */
template <typename AT, typename LT, typename UT, typename PT>
bool lu(const AT& A, LT& L, UT& U, PT& P);

namespace impl {

namespace standard {

/*!
 * \brief Compute the determinant of the given matrix
 * \return The determinant of the given matrix
 */
template <typename AT>
value_t<AT> det(const AT& A) {
    using T = value_t<AT>;

    const auto n = etl::dim<0>(A);

    if (is_permutation_matrix(A)) {
        size_t t = 0;

        for (size_t i = 0; i < n; ++i) {
            for (size_t j = 0; j < n; ++j) {
                if (A(i, j) != 0.0 && i != j) {
                    ++t;
                }
            }
        }

        return std::pow(T(-1.0), t - 1);
    }

    if (is_triangular(A)) {
        T det(1.0);

        for (size_t i = 0; i < n; ++i) {
            det *= A(i, i);
        }

        return det;
    }

    auto L = force_temporary_dim_only(A);
    auto U = force_temporary_dim_only(A);
    auto P = force_temporary_dim_only(A);

    etl::lu(A, L, U, P);

    return det(L) * det(U) * det(P);
}

} //end of namespace standard
} //end of namespace impl
} //end of namespace etl
<|endoftext|>