<commit_before>#include "CompliantStaticSolver.h"

#include <sofa/core/ObjectFactory.h>

#include <boost/math/tools/minima.hpp>
#include <boost/tuple/tuple.hpp>

#include "../utils/nr.h"
#include "../utils/scoped.h"

#include "../constraint/Constraint.h"

namespace sofa {
namespace component {
namespace odesolver {

// TODO use std::numeric_limits

CompliantStaticSolver::CompliantStaticSolver()
    : epsilon(initData(&epsilon, 1e-16, "epsilon", "division by zero threshold")),
      line_search(initData(&line_search, unsigned(LS_SECANT), "line_search",
                           "line search method, 0: none (use dt), 1: brent, 2: secant (default). (warning: brent does not work with constraints.")),
      conjugate(initData(&conjugate, true, "conjugate", "conjugate descent directions")),
      ls_precision(initData(&ls_precision, 1e-8, "ls_precision", "line search precision")),
      ls_iterations(initData(&ls_iterations, unsigned(10), "ls_iterations",
                             "line search iterations")),
      ls_step(initData(&ls_step, 1e-8, "ls_step",
                       "line search bracketing step (should not cross any extrema from current position"))
{

}

struct CompliantStaticSolver::helper {

    simulation::common::VectorOperations vec;
    simulation::common::MechanicalOperations mec;

    core::behavior::MultiVecDeriv dx;
    core::behavior::MultiVecDeriv f;

    helper(const core::ExecParams* params,
           core::objectmodel::BaseContext* ctx) : vec(params, ctx),
                                                  mec(params, ctx),
                                                  dx( &vec, core::VecDerivId::dx() ),
                                                  f( &vec, core::VecDerivId::force() )    {
    }

    // TODO const args ?
    SReal dot(core::MultiVecDerivId lhs, core::MultiVecDerivId rhs)  {
        vec.v_dot(lhs, rhs);
        return vec.finish();
    }

    // arg can't be dx !
    void K(core::MultiVecDerivId res, core::MultiVecDerivId arg) {
        vec.v_eq(dx, arg);
        vec.v_clear( res );

        mec.addMBKdx( res , 0, 0, -1, true, true);
        mec.projectResponse( res );
    }

    void forces(core::MultiVecDerivId res) {
        mec.computeForce( res );
        mec.projectResponse( res );
    }

    template<class Vec>
    void realloc(Vec& res) {
        res.realloc( &vec, false, true );
    }

    template<class Res, class A, class B>
    void set(Res& res,
             A& a,
             B& b,
             SReal lambda) {
        vec.v_op(res, a, b, lambda);
    }

    template<class A, class B>
    void set(A& res,
             B& b) {
        vec.v_eq(res, b);
    }

};

CompliantStaticSolver::ls_info::ls_info()
    : eps(0),
      iterations(15),
      precision(1e-7),
      fixed_step(1e-5),
      bracket_step(1e-8) {

}

// minimizes (implicit) potential function in direction dir) by
// zeroing g = grad^T dir using secant method

// precond:
// - op.f contains forces for current pos
void CompliantStaticSolver::ls_secant(helper& op,
                                      core::MultiVecCoordId pos,
                                      core::MultiVecDerivId dir,
                                      const ls_info& info) {
    scoped::timer step("ls_secant");

    SReal dg = 0;
    SReal dx = 0;

    SReal g_prev = 0;
    SReal total = 0;

    // slightly damp newton iterations TODO hardcode
    static const SReal damping = 1e-14;

    SReal fixed = info.fixed_step;

    for(unsigned k = 0, n = info.iterations; k < n; ++k) {

        if( k ) {
            // update forces
            op.mec.propagateX(pos, true);
            op.forces( op.f );
        }

        const SReal g = op.dot(op.f, dir);

        // std::cout << "line search (secant) " << k << " "  << total << " " << g << std::endl;

        // are we done ?
        if( std::abs(g) <= info.precision ) break;

        dg = g - g_prev;

        const SReal dx_prev = dx;

        // fallback on fixed step
        dx = fixed;

        // (damped) secant method
        if( k && (std::abs(dg) > info.eps)) {
            dx = -(dx_prev / (dg + damping)) * g;
        } else {

            // try to move more to change function
            fixed *= 2;

        }

        total += dx;

        // move dx along dir
        op.set(pos, pos, dir, dx);

        // next
        g_prev = g;
    }

}

struct CompliantStaticSolver::potential_energy {

    // WARNING: backup/restore pos on scope entry/exit
    potential_energy(helper& op,
                     const core::MultiVecCoordId& pos,
                     const core::MultiVecDerivId& dir,
                     const core::MultiVecCoordId& tmp,
                     bool restore = true)
        : op(op),
          pos(pos),
          dir(dir),
          tmp(tmp),
          restore(restore) {

        // backup start position
        op.set(tmp, pos);
    }

    helper& op;

    const core::MultiVecCoordId& pos;
    const core::MultiVecDerivId& dir;
    const core::MultiVecCoordId& tmp;

    // do we restore pos in dtor ?
    bool restore;

    SReal operator()(SReal x) const {

        // move to x along dir
        op.set(pos, tmp, dir, x);

        // update forces/energy
        op.mec.propagateX(pos, true);

        // TODO apparently, this is not needed
        // op.forces(op.f);

        // note: potential energy only works for pos !
        SReal dummy, result;
        op.mec.computeEnergy(dummy, result);

        // std::cout << "potential energy: " << x << ", " << result << std::endl;

        return result;
    }

    ~potential_energy() {
        if( restore ) {
            op.set(pos, tmp);
        }
    }

};

void CompliantStaticSolver::ls_brent(helper& op,
                                     core::MultiVecCoordId pos,
                                     core::MultiVecDerivId dir,
                                     const ls_info& info,
                                     core::MultiVecCoordId tmp) {
    scoped::timer step("ls_brent");
    typedef utils::nr::optimization<SReal> opt;

    opt::func_call a, b, c;

    a.x = 0;
    b.x = info.bracket_step;

    opt::func_call res;

    {
        // we need the scope because f might reset pos on scope exit
        const potential_energy f(op, pos, dir, tmp, false);

        opt::minimum_bracket(a, b, c, f);

        // std::cout << "bracketing: " << a.x << ", " << c.x << std::endl;

        // TODO compute this from precision
        const int bits = 32;
        {
            using namespace boost;
            boost::uintmax_t iter = info.iterations;
            tie(res.x, res.f) = math::tools::brent_find_minima(f,
                                                               a.x, c.x,
                                                               bits,
                                                               iter);
            // std::cout << "brent: " << res.x << std::endl;
        }

    }

    // TODO make sure the last function call is the closest to the optimium
    // op.set(pos, pos, dir, res.x);

    // TODO do we want to do this ?
    // op.mec.propagateX(pos, true);
    // op.forces(op.f);

}

// accumulate force in an external vector
class AugmentedLagrangianVisitor : public simulation::MechanicalVisitor {

public:
    AugmentedLagrangianVisitor(const sofa::core::MechanicalParams* mparams,
                               core::MultiVecId id)
        : MechanicalVisitor(mparams),
          id(id) { }

    core::MultiVecId id;

    Result mstate(simulation::Node* node,
                  core::behavior::BaseMechanicalState* mm) {

        linearsolver::Constraint* c = node->get<linearsolver::Constraint>(core::objectmodel::BaseContext::Local);

        if( c ) {
            // TODO project ?

            // add force to external force
            mm->vOp(params, id.getId(mm), core::ConstVecId::force() );
        }

        return RESULT_CONTINUE;
    }

    virtual Result fwdMappedMechanicalState(simulation::Node* node,
                                            core::behavior::BaseMechanicalState* mm) {
        return mstate(node, mm);
    }

    virtual Result fwdMechanicalState(simulation::Node* node,
                                      core::behavior::BaseMechanicalState* mm) {
        return mstate(node, mm);
    }

};

// somehow setting external force directly does not work
class WriteExternalForceVisitor : public simulation::MechanicalVisitor {
public:
    WriteExternalForceVisitor(const sofa::core::MechanicalParams* mparams,
                              core::MultiVecId id)
        : MechanicalVisitor(mparams),
          id(id) { }

    core::MultiVecId id;

    Result mstate(simulation::Node* /*node*/,
                  core::behavior::BaseMechanicalState* mm) {

        // add force to external force

        // we need to add to externalForce (gravity)
        mm->vOp(params, core::VecId::externalForce(), id.getId(mm));
        // core::VecId::externalForce(),
        // , 1.0 );

        return RESULT_CONTINUE;
    }

    virtual Result fwdMappedMechanicalState(simulation::Node* node,
                                            core::behavior::BaseMechanicalState* mm) {
        return mstate(node, mm);
    }

    virtual Result fwdMechanicalState(simulation::Node* node,
                                      core::behavior::BaseMechanicalState* mm) {
        return mstate(node, mm);
    }

};

SOFA_DECL_CLASS(CompliantStaticSolver)
static int CompliantStaticSolverClass = core::RegisterObject("Static solver")
    .add< CompliantStaticSolver >();

    void CompliantStaticSolver::solve(const core::ExecParams* params,
                                SReal dt,
                                core::MultiVecCoordId pos,
                                core::MultiVecDerivId vel) {

        helper op(params, getContext() );

        // mparams setup
        op.mec.mparams.setImplicit(false);
        op.mec.mparams.setEnergy(true);

        // descent direction
        op.realloc(dir);

        // lagrange multipliers
        op.realloc(lambda);

        // some work vector for postions
        op.realloc(tmp);

        // first iteration
        if(!iteration) {
            op.vec.v_clear( lambda );
            previous = 0;

        }

        // why on earth does this dot work ?!

        // core::behavior::MultiVecDeriv ext(&op.vec, core::VecDerivId::externalForce() );
        // op.set(ext, lambda);
        {
            WriteExternalForceVisitor vis(&op.mec.mparams, lambda.id());
            getContext()->executeVisitor(&vis, true);

            // core::behavior::MultiVecDeriv ext(&op.vec, core::VecDerivId::externalForce() );
            // std::cout << ext << std::endl;
        }

        // obtain (projected) gradient
        op.forces( op.f );

        // note: we *could* skip the above when line-search is on
        // after the first iteration, but we would miss any change in
        // the scene (e.g. mouse interaction)

        // polar-ribiere
        const SReal current = op.dot(op.f, op.f);

        if(!iteration) {
            // something large at first ?

            // TODO figure out a reasonable default
            augmented = std::sqrt(current) / 2.0;
        }

        SReal beta = 0;

        const SReal eps = epsilon.getValue();
        if( conjugate.getValue() && std::abs(previous) > eps ) {

            {
                if(iteration > 0) {
                    // polak-ribiere
                    beta = (current - op.dot(vel, op.f) ) / previous;

                    // dai-yuan
                    // beta = current / (op.dot(dir, vel) - op.dot(dir, op.f) );
                }

                // direction reset
                // beta = std::max(0.0, beta);
            }

        }

        // conjugation
        op.set(dir, op.f, dir, beta);

        // polak-ribiere
        {
            // backup previous f to vel
            op.set(vel, op.f);
        }

        // line search
        const unsigned ls = line_search.getValue();
        if( ls ) {
            ls_info info;

            info.eps = eps;
            info.precision = ls_precision.getValue();
            info.iterations = ls_iterations.getValue();
            info.fixed_step = dt;
            info.bracket_step = ls_step.getValue();

            switch( ls ) {

            case LS_SECANT:
                ls_secant(op, pos, dir.id(), info);
                break;

            case LS_BRENT:
                ls_brent(op, pos, dir.id(), info, tmp.id());
                break;

            default:
                throw std::runtime_error("bad line-search");
            }

        } else {
            // fixed step
            op.set(pos, pos, dir.id(), dt);
        }

        const SReal error = std::sqrt( op.dot(op.f, op.f) );

        if( f_printLog.getValue() ) {
            sout << "forces norm: " << error << sendl;
        }

        // augmented lagrangian
        if( error <= augmented ) {

            // TODO don't waste time if we have no constraints
            op.mec.propagateX(pos, true);
            op.forces(op.f);

            AugmentedLagrangianVisitor vis(&op.mec.mparams, lambda.id() );
            getContext()->executeVisitor( &vis, true );

            // TODO should we reset CG ?
            // op.vec.v_clear(dir);

            augmented /= 2;

            if( f_printLog.getValue() ) {
                sout << "augmented lagrangian threshold: " << augmented << sendl;
            }

        }

        // next iteration
        previous = current;

        ++iteration;
    }

    void CompliantStaticSolver::reset() {
        iteration = 0;

    }

    void CompliantStaticSolver::init() {

    }

}
}
}
<commit_msg>fix windows compilation<commit_after>#include "CompliantStaticSolver.h"

#include <sofa/core/ObjectFactory.h>

#include <boost/math/tools/minima.hpp>
#include <boost/tuple/tuple.hpp>

#include "../utils/nr.h"
#include "../utils/scoped.h"

#include "../constraint/Constraint.h"

namespace sofa {
namespace component {
namespace odesolver {

// TODO use std::numeric_limits

CompliantStaticSolver::CompliantStaticSolver()
    : epsilon(initData(&epsilon, 1e-16, "epsilon", "division by zero threshold")),
      line_search(initData(&line_search, unsigned(LS_SECANT), "line_search",
                           "line search method, 0: none (use dt), 1: brent, 2: secant (default). (warning: brent does not work with constraints.")),
      conjugate(initData(&conjugate, true, "conjugate", "conjugate descent directions")),
      ls_precision(initData(&ls_precision, 1e-8, "ls_precision", "line search precision")),
      ls_iterations(initData(&ls_iterations, unsigned(10), "ls_iterations",
                             "line search iterations")),
      ls_step(initData(&ls_step, 1e-8, "ls_step",
                       "line search bracketing step (should not cross any extrema from current position"))
{

}

struct CompliantStaticSolver::helper {

    simulation::common::VectorOperations vec;
    simulation::common::MechanicalOperations mec;

    core::behavior::MultiVecDeriv dx;
    core::behavior::MultiVecDeriv f;

    helper(const core::ExecParams* params,
           core::objectmodel::BaseContext* ctx) : vec(params, ctx),
                                                  mec(params, ctx),
                                                  dx( &vec, core::VecDerivId::dx() ),
                                                  f( &vec, core::VecDerivId::force() )    {
    }

    // TODO const args ?
    SReal dot(core::MultiVecDerivId lhs, core::MultiVecDerivId rhs)  {
        vec.v_dot(lhs, rhs);
        return vec.finish();
    }

    // arg can't be dx !
    void K(core::MultiVecDerivId res, core::MultiVecDerivId arg) {
        vec.v_eq(dx, arg);
        vec.v_clear( res );

        mec.addMBKdx( res , 0, 0, -1, true, true);
        mec.projectResponse( res );
    }

    void forces(core::MultiVecDerivId res) {
        mec.computeForce( res );
        mec.projectResponse( res );
    }

    template<class Vec>
    void realloc(Vec& res) {
        res.realloc( &vec, false, true );
    }

    template<class Res, class A, class B>
    void set(Res& res,
             A& a,
             B& b,
             SReal lambda) {
        vec.v_op(res, a, b, lambda);
    }

    template<class A, class B>
    void set(A& res,
             B& b) {
        vec.v_eq(res, b);
    }

};

CompliantStaticSolver::ls_info::ls_info()
    : eps(0),
      iterations(15),
      precision(1e-7),
      fixed_step(1e-5),
      bracket_step(1e-8) {

}

// minimizes (implicit) potential function in direction dir) by
// zeroing g = grad^T dir using secant method

// precond:
// - op.f contains forces for current pos
void CompliantStaticSolver::ls_secant(helper& op,
                                      core::MultiVecCoordId pos,
                                      core::MultiVecDerivId dir,
                                      const ls_info& info) {
    scoped::timer step("ls_secant");

    SReal dg = 0;
    SReal dx = 0;

    SReal g_prev = 0;
    SReal total = 0;

    // slightly damp newton iterations TODO hardcode
    static const SReal damping = 1e-14;

    SReal fixed = info.fixed_step;

    for(unsigned k = 0, n = info.iterations; k < n; ++k) {

        if( k ) {
            // update forces
            op.mec.propagateX(pos, true);
            op.forces( op.f );
        }

        const SReal g = op.dot(op.f, dir);

        // std::cout << "line search (secant) " << k << " "  << total << " " << g << std::endl;

        // are we done ?
        if( std::abs(g) <= info.precision ) break;

        dg = g - g_prev;

        const SReal dx_prev = dx;

        // fallback on fixed step
        dx = fixed;

        // (damped) secant method
        if( k && (std::abs(dg) > info.eps)) {
            dx = -(dx_prev / (dg + damping)) * g;
        } else {

            // try to move more to change function
            fixed *= 2;

        }

        total += dx;

        // move dx along dir
        op.set(pos, pos, dir, dx);

        // next
        g_prev = g;
    }

}

struct CompliantStaticSolver::potential_energy {

    // WARNING: backup/restore pos on scope entry/exit
    potential_energy(helper& op,
                     const core::MultiVecCoordId& pos,
                     const core::MultiVecDerivId& dir,
                     const core::MultiVecCoordId& tmp,
                     bool restore = true)
        : op(op),
          pos(pos),
          dir(dir),
          tmp(tmp),
          restore(restore) {

        // backup start position
        op.set(tmp, pos);
    }

    helper& op;

    const core::MultiVecCoordId& pos;
    const core::MultiVecDerivId& dir;
    const core::MultiVecCoordId& tmp;

    // do we restore pos in dtor ?
    bool restore;

    SReal operator()(SReal x) const {

        // move to x along dir
        op.set(pos, tmp, dir, x);

        // update forces/energy
        op.mec.propagateX(pos, true);

        // TODO apparently, this is not needed
        // op.forces(op.f);

        // note: potential energy only works for pos !
        SReal dummy, result;
        op.mec.computeEnergy(dummy, result);

        // std::cout << "potential energy: " << x << ", " << result << std::endl;

        return result;
    }

    ~potential_energy() {
        if( restore ) {
            op.set(pos, tmp);
        }
    }

};

void CompliantStaticSolver::ls_brent(helper& op,
                                     core::MultiVecCoordId pos,
                                     core::MultiVecDerivId dir,
                                     const ls_info& info,
                                     core::MultiVecCoordId tmp) {
    scoped::timer step("ls_brent");
    typedef utils::nr::optimization<SReal> opt;

    opt::func_call a, b, c;

    a.x = 0;
    b.x = info.bracket_step;

    opt::func_call res;

    {
        // we need the scope because f might reset pos on scope exit
        const potential_energy f(op, pos, dir, tmp, false);

        opt::minimum_bracket(a, b, c, f);

        // std::cout << "bracketing: " << a.x << ", " << c.x << std::endl;

        // TODO compute this from precision
        const int bits = 32;
        {
            using namespace boost;
            boost::uintmax_t iter = info.iterations;
            tie(res.x, res.f) = math::tools::brent_find_minima(f,
                                                               a.x, c.x,
                                                               bits,
                                                               iter);
            // std::cout << "brent: " << res.x << std::endl;
        }

    }

    // TODO make sure the last function call is the closest to the optimium
    // op.set(pos, pos, dir, res.x);

    // TODO do we want to do this ?
    // op.mec.propagateX(pos, true);
    // op.forces(op.f);

}

// accumulate force in an external vector
class AugmentedLagrangianVisitor : public simulation::MechanicalVisitor {

public:
    AugmentedLagrangianVisitor(const sofa::core::MechanicalParams* mparams,
                               core::MultiVecId id)
        : MechanicalVisitor(mparams),
          id(id) { }

    core::MultiVecId id;

    Result mstate(simulation::Node* node,
                  core::behavior::BaseMechanicalState* mm) {

        linearsolver::Constraint* c = node->get<linearsolver::Constraint>(core::objectmodel::BaseContext::Local);

        if( c ) {
            // TODO project ?

            // add force to external force
            mm->vOp(params, id.getId(mm), core::ConstVecId::force() );
        }

        return RESULT_CONTINUE;
    }

    virtual Result fwdMappedMechanicalState(simulation::Node* node,
                                            core::behavior::BaseMechanicalState* mm) {
        return mstate(node, mm);
    }

    virtual Result fwdMechanicalState(simulation::Node* node,
                                      core::behavior::BaseMechanicalState* mm) {
        return mstate(node, mm);
    }

};

// somehow setting external force directly does not work
class WriteExternalForceVisitor : public simulation::MechanicalVisitor {
public:
    WriteExternalForceVisitor(const sofa::core::MechanicalParams* mparams,
                              core::MultiVecId id)
        : MechanicalVisitor(mparams),
          id(id) { }

    core::MultiVecId id;

    Result mstate(simulation::Node* /*node*/,
                  core::behavior::BaseMechanicalState* mm) {

        // add force to external force

        // we need to add to externalForce (gravity)
        mm->vOp(params, core::VecId::externalForce(), id.getId(mm));
        // core::VecId::externalForce(),
        // , 1.0 );

        return RESULT_CONTINUE;
    }

    virtual Result fwdMappedMechanicalState(simulation::Node* node,
                                            core::behavior::BaseMechanicalState* mm) {
        return mstate(node, mm);
    }

    virtual Result fwdMechanicalState(simulation::Node* node,
                                      core::behavior::BaseMechanicalState* mm) {
        return mstate(node, mm);
    }

};

SOFA_DECL_CLASS(CompliantStaticSolver)
static int CompliantStaticSolverClass = core::RegisterObject("Static solver")
    .add< CompliantStaticSolver >();

    void CompliantStaticSolver::solve(const core::ExecParams* params,
                                SReal dt,
                                core::MultiVecCoordId pos,
                                core::MultiVecDerivId vel) {

        helper op(params, getContext() );

        // mparams setup
        op.mec.mparams.setImplicit(false);
        op.mec.mparams.setEnergy(true);

        // descent direction
        op.realloc(dir);

        // lagrange multipliers
        op.realloc(lambda);

        // some work vector for postions
        op.realloc(tmp);

        // first iteration
        if(!iteration) {
            op.vec.v_clear( lambda );
            previous = 0;

        }

        // why on earth does this dot work ?!

        // core::behavior::MultiVecDeriv ext(&op.vec, core::VecDerivId::externalForce() );
        // op.set(ext, lambda);
        {
            WriteExternalForceVisitor vis(&op.mec.mparams, lambda.id());
            getContext()->executeVisitor(&vis, true);

            // core::behavior::MultiVecDeriv ext(&op.vec, core::VecDerivId::externalForce() );
            // std::cout << ext << std::endl;
        }

        // obtain (projected) gradient
        op.forces( op.f );

        // note: we *could* skip the above when line-search is on
        // after the first iteration, but we would miss any change in
        // the scene (e.g. mouse interaction)

        // polar-ribiere
        const SReal current = op.dot(op.f, op.f);

        if(!iteration) {
            // something large at first ?

            // TODO figure out a reasonable default
            augmented = std::sqrt(current) / 2.0;
        }

        SReal beta = 0;

        const SReal eps = epsilon.getValue();
        if( conjugate.getValue() && std::abs(previous) > eps ) {

            {
                if(iteration > 0) {
                    // polak-ribiere
                    beta = (current - op.dot(vel, op.f) ) / previous;

<<<<<<< HEAD
                    // dai-yuan
                    // beta = current / (op.dot(dir, vel) - op.dot(dir, op.f) );
=======
                    // direction reset
                    beta = std::max((SReal)0.0, beta);
>>>>>>> fix windows compilation
                }

                // direction reset
                // beta = std::max(0.0, beta);
            }

        }

        // conjugation
        op.set(dir, op.f, dir, beta);

        // polak-ribiere
        {
            // backup previous f to vel
            op.set(vel, op.f);
        }

        // line search
        const unsigned ls = line_search.getValue();
        if( ls ) {
            ls_info info;

            info.eps = eps;
            info.precision = ls_precision.getValue();
            info.iterations = ls_iterations.getValue();
            info.fixed_step = dt;
            info.bracket_step = ls_step.getValue();

            switch( ls ) {

            case LS_SECANT:
                ls_secant(op, pos, dir.id(), info);
                break;

            case LS_BRENT:
                ls_brent(op, pos, dir.id(), info, tmp.id());
                break;

            default:
                throw std::runtime_error("bad line-search");
            }

        } else {
            // fixed step
            op.set(pos, pos, dir.id(), dt);
        }

        const SReal error = std::sqrt( op.dot(op.f, op.f) );

        if( f_printLog.getValue() ) {
            sout << "forces norm: " << error << sendl;
        }

        // augmented lagrangian
        if( error <= augmented ) {

            // TODO don't waste time if we have no constraints
            op.mec.propagateX(pos, true);
            op.forces(op.f);

            AugmentedLagrangianVisitor vis(&op.mec.mparams, lambda.id() );
            getContext()->executeVisitor( &vis, true );

            // TODO should we reset CG ?
            // op.vec.v_clear(dir);

            augmented /= 2;

            if( f_printLog.getValue() ) {
                sout << "augmented lagrangian threshold: " << augmented << sendl;
            }

        }

        // next iteration
        previous = current;

        ++iteration;
    }

    void CompliantStaticSolver::reset() {
        iteration = 0;

    }

    void CompliantStaticSolver::init() {

    }

}
}
}
<|endoftext|>


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

// This is really Posix minus Mac. Mac code is in base_paths_mac.mm.

#include "base/base_paths.h"

#include <unistd.h>

#include "base/env_var.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/sys_string_conversions.h"
#include "base/xdg_util.h"

namespace base {

#if defined(OS_LINUX)
const char kSelfExe[] = "/proc/self/exe";
#elif defined(OS_SOLARIS)
const char kSelfExe[] = getexecname();
#elif defined(OS_FREEBSD)
const char kSelfExe[] = "/proc/curproc/file";
#endif

bool PathProviderPosix(int key, FilePath* result) {
  FilePath path;
  switch (key) {
    case base::FILE_EXE:
    case base::FILE_MODULE: {  // TODO(evanm): is this correct?
      char bin_dir[PATH_MAX + 1];
      int bin_dir_size = readlink(kSelfExe, bin_dir, PATH_MAX);
      if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
        NOTREACHED() << "Unable to resolve " << kSelfExe << ".";
        return false;
      }
      bin_dir[bin_dir_size] = 0;
      *result = FilePath(bin_dir);
      return true;
    }
    case base::DIR_SOURCE_ROOT: {
      // Allow passing this in the environment, for more flexibility in build
      // tree configurations (sub-project builds, gyp --output_dir, etc.)
      scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
      std::string cr_source_root;
      if (env->GetEnv("CR_SOURCE_ROOT", &cr_source_root)) {
        path = FilePath(cr_source_root);
        if (file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
          *result = path;
          return true;
        } else {
          LOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not "
                       << "point to the correct source root directory.";
        }
      }
      // On POSIX, unit tests execute two levels deep from the source root.
      // For example:  sconsbuild/{Debug|Release}/net_unittest
      if (PathService::Get(base::DIR_EXE, &path)) {
        path = path.DirName().DirName();
        if (file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
          *result = path;
          return true;
        }
      }
      // If that failed (maybe the build output is symlinked to a different
      // drive) try assuming the current directory is the source root.
      if (file_util::GetCurrentDirectory(&path) &&
          file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
        *result = path;
        return true;
      }
      LOG(ERROR) << "Couldn't find your source root.  "
                 << "Try running from your chromium/src directory.";
      return false;
    }
    case base::DIR_USER_CACHE:
      scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
      FilePath cache_dir(base::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
                                               ".cache"));
      *result = cache_dir;
      return true;
  }
  return false;
}

}  // namespace base
<commit_msg>use sysctl instead of /proc on FreeBSD (unfortunately this approach is not available on OpenBSD though) patch from sprewell Review URL: http://codereview.chromium.org/1979006<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This is really Posix minus Mac. Mac code is in base_paths_mac.mm.

#include "base/base_paths.h"

#include <unistd.h>
#if defined(OS_FREEBSD)
#include <sys/param.h>
#include <sys/sysctl.h>
#endif

#include "base/env_var.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/sys_string_conversions.h"
#include "base/xdg_util.h"

namespace base {

#if defined(OS_LINUX)
const char kSelfExe[] = "/proc/self/exe";
#elif defined(OS_SOLARIS)
const char kSelfExe[] = getexecname();
#endif

bool PathProviderPosix(int key, FilePath* result) {
  FilePath path;
  switch (key) {
    case base::FILE_EXE:
    case base::FILE_MODULE: {  // TODO(evanm): is this correct?
#if defined(OS_LINUX)
      char bin_dir[PATH_MAX + 1];
      int bin_dir_size = readlink(kSelfExe, bin_dir, PATH_MAX);
      if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
        NOTREACHED() << "Unable to resolve " << kSelfExe << ".";
        return false;
      }
      bin_dir[bin_dir_size] = 0;
      *result = FilePath(bin_dir);
      return true;
#elif defined(OS_FREEBSD)
      int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
      char bin_dir[PATH_MAX + 1];
      size_t length = sizeof(bin_dir);
      int error = sysctl(name, 4, bin_dir, &length, NULL, 0);
      if (error < 0 || length == 0 || strlen(bin_dir) == 0) {
        NOTREACHED() << "Unable to resolve path.";
        return false;
      }
      bin_dir[strlen(bin_dir)] = 0;
      *result = FilePath(bin_dir);
      return true;
#endif
    }
    case base::DIR_SOURCE_ROOT: {
      // Allow passing this in the environment, for more flexibility in build
      // tree configurations (sub-project builds, gyp --output_dir, etc.)
      scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
      std::string cr_source_root;
      if (env->GetEnv("CR_SOURCE_ROOT", &cr_source_root)) {
        path = FilePath(cr_source_root);
        if (file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
          *result = path;
          return true;
        } else {
          LOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not "
                       << "point to the correct source root directory.";
        }
      }
      // On POSIX, unit tests execute two levels deep from the source root.
      // For example:  sconsbuild/{Debug|Release}/net_unittest
      if (PathService::Get(base::DIR_EXE, &path)) {
        path = path.DirName().DirName();
        if (file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
          *result = path;
          return true;
        }
      }
      // If that failed (maybe the build output is symlinked to a different
      // drive) try assuming the current directory is the source root.
      if (file_util::GetCurrentDirectory(&path) &&
          file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
        *result = path;
        return true;
      }
      LOG(ERROR) << "Couldn't find your source root.  "
                 << "Try running from your chromium/src directory.";
      return false;
    }
    case base::DIR_USER_CACHE:
      scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
      FilePath cache_dir(base::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
                                               ".cache"));
      *result = cache_dir;
      return true;
  }
  return false;
}

}  // namespace base
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: app.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: rt $ $Date: 2004-06-17 11:45:28 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _BASICAPP_HXX
#define _BASICAPP_HXX

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _HELP_HXX //autogen
#include <vcl/help.hxx>
#endif
#ifndef _MENU_HXX //autogen
#include <vcl/menu.hxx>
#endif
#ifndef _WRKWIN_HXX //autogen
#include <vcl/wrkwin.hxx>
#endif
#ifndef _TIMER_HXX //autogen
#include <vcl/timer.hxx>
#endif
#ifndef _SFXBRDCST_HXX
#include <svtools/brdcst.hxx>
#endif
#ifndef _SFXLSTNER_HXX
#include <svtools/lstner.hxx>
#endif

class BasicFrame;
#include "mybasic.hxx"

class EditList;
class AppWin;
class AppEdit;
class AppBasEd;
class MsgEdit;
class AppError;
class StatusLine;
class BasicPrinter;
struct TTLogMsg;

class BasicApp : public Application {
    short       nWait;              // Wait-Zaehler
public:
//  Help*       pHelp;              // Hilfesystem
    BasicFrame* pFrame;             // Frame Window
//  MenuBar*    pMainMenu;          // Hauptmenue
    Accelerator*    pMainAccel;     // Acceleratoren

    void  Main( );

    void  LoadIniFile();
    void  SetFocus();
    void  Wait( BOOL );
    DECL_LINK( LateInit, void * );

#ifdef DBG_UTIL
    DbgPrintLine DbgPrintMsgBox;
#endif
};

typedef USHORT FileType;

#define FT_NO_FILE          (FileType)0x00      // Ein Fehler ist aufgetreten ...
#define FT_BASIC_SOURCE     (FileType)0x01
#define FT_BASIC_INCLUDE    (FileType)0x02
#define FT_RESULT_FILE      (FileType)0x04
#define FT_RESULT_FILE_TXT  (FileType)0x08
#define FT_BASIC_LIBRARY    (FileType)0x10

struct WinInfoRec;
class DisplayHidDlg;

class FloatingExecutionStatus;

class BasicFrame : public WorkWindow, public SfxBroadcaster, public SfxListener
{
virtual BOOL Close();               // Schliessen
    BOOL CloseAll();                // Alle Fenster schliessen
    BOOL CompileAll();              // Alle Texte compilieren
    AutoTimer aLineNum;             // Zeigt die Zeilennummer an
virtual void Resize();
virtual void Move();
virtual void GetFocus();
    void LoadLibrary();
    void SaveLibrary();
    BOOL bIsAutoRun;
    DisplayHidDlg* pDisplayHidDlg;

//  BreakPoint *pRunToCursorBP;

    SbxVariable *pEditVar;

    Timer aCheckFiles;      // Prfen der Dateien auf nderungen
    BOOL bAutoReload;
    BOOL bAutoSave;
    DECL_LINK( CheckAllFiles, Timer* );

    MyBasicRef  pBasic;             // BASIC-Engine

    String aAppName;                // Inhalt der Titelteile der App:
    String aAppFile;                // AppName AppFile [AppMode]
    String aAppMode;
    void UpdateTitle();
    DECL_LINK( CloseButtonClick, void* );
    DECL_LINK( FloatButtonClick, void* );
    DECL_LINK( HideButtonClick, void* );

    FloatingExecutionStatus *pExecutionStatus;

public:
    BOOL IsAutoRun();
    void SetAutoRun( BOOL bAuto );
    BOOL bInBreak;                  // TRUE, wenn im Break-Handler
    StatusLine* pStatus;            // Statuszeile
    EditList*   pList;              // List der Edit-Fenster
    AppWin*     pWork;              // aktuelles Edit-Fenster
    BasicPrinter* pPrn;             // Drucker
    BOOL bDisas;                    // TRUE: disassemble
    USHORT nFlags;                  // Debugging-Flags
    USHORT nMaximizedWindows;       // Anzahl der Fenster, die maximized sind
    void FocusWindow( AppWin *pWin );
    void WinMax_Restore();
    void WinShow_Hide();
    void RemoveWindow( AppWin *pWin );
    void AddWindow( AppWin *pWin );
    void WindowRenamed( AppWin *pWin );

    BasicFrame();
   ~BasicFrame();
    MyBasic& Basic()                { return *pBasic; }
    void AddToLRU(String const& aFile);
    void LoadLRU();
    DECL_LINK( InitMenu, Menu * );
    DECL_LINK( DeInitMenu, Menu * );
    DECL_LINK( HighlightMenu, Menu * );
    DECL_LINK( MenuCommand, Menu * );
    DECL_LINK( Accel, Accelerator * );
    DECL_LINK( ShowLineNr, AutoTimer * );
    MsgEdit* GetMsgTree( String aLogFileName );
    DECL_LINK( Log, TTLogMsg * );
    DECL_LINK( WinInfo, WinInfoRec * );
    BOOL LoadFile( String aFilename );
    long Command( short,BOOL=FALSE );// Kommando-Handler
    BOOL SaveAll();                 // Alle Fenster speichern
    BOOL QueryFileName( String& rName, FileType nFileType, BOOL bSave );// Dateinamen ermitteln
    DECL_LINK( ModuleWinExists, String* );
    DECL_LINK( WriteString, String* );
    AppBasEd* CreateModuleWin( SbModule* pMod );
    AppBasEd* FindModuleWin( const String& );
    AppError* FindErrorWin( const String& );
    AppWin* FindWin( const String& );
    AppWin* FindWin( USHORT nWinId );
    AppWin* IsWinValid( AppWin* pMaybeWin );
    USHORT BreakHandler();          // Break-Handler-Callback

    void SetEditVar( SbxVariable *pVar ){ pEditVar = pVar;}
    SbxVariable* GetEditVar(){ return pEditVar;}
    BOOL IsAutoReload() { return bAutoReload; }
    BOOL IsAutoSave() { return bAutoSave; }
    void LoadIniFile();

    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );

    void SetAppMode( const String &aNewMode ){ aAppMode = aNewMode; UpdateTitle(); }

    String GenRealString( const String &aResString );

};

extern BasicApp aBasicApp;

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.8.120); FILE MERGED 2005/09/05 14:35:47 rt 1.8.120.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: app.hxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 21:09:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _BASICAPP_HXX
#define _BASICAPP_HXX

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _HELP_HXX //autogen
#include <vcl/help.hxx>
#endif
#ifndef _MENU_HXX //autogen
#include <vcl/menu.hxx>
#endif
#ifndef _WRKWIN_HXX //autogen
#include <vcl/wrkwin.hxx>
#endif
#ifndef _TIMER_HXX //autogen
#include <vcl/timer.hxx>
#endif
#ifndef _SFXBRDCST_HXX
#include <svtools/brdcst.hxx>
#endif
#ifndef _SFXLSTNER_HXX
#include <svtools/lstner.hxx>
#endif

class BasicFrame;
#include "mybasic.hxx"

class EditList;
class AppWin;
class AppEdit;
class AppBasEd;
class MsgEdit;
class AppError;
class StatusLine;
class BasicPrinter;
struct TTLogMsg;

class BasicApp : public Application {
    short       nWait;              // Wait-Zaehler
public:
//  Help*       pHelp;              // Hilfesystem
    BasicFrame* pFrame;             // Frame Window
//  MenuBar*    pMainMenu;          // Hauptmenue
    Accelerator*    pMainAccel;     // Acceleratoren

    void  Main( );

    void  LoadIniFile();
    void  SetFocus();
    void  Wait( BOOL );
    DECL_LINK( LateInit, void * );

#ifdef DBG_UTIL
    DbgPrintLine DbgPrintMsgBox;
#endif
};

typedef USHORT FileType;

#define FT_NO_FILE          (FileType)0x00      // Ein Fehler ist aufgetreten ...
#define FT_BASIC_SOURCE     (FileType)0x01
#define FT_BASIC_INCLUDE    (FileType)0x02
#define FT_RESULT_FILE      (FileType)0x04
#define FT_RESULT_FILE_TXT  (FileType)0x08
#define FT_BASIC_LIBRARY    (FileType)0x10

struct WinInfoRec;
class DisplayHidDlg;

class FloatingExecutionStatus;

class BasicFrame : public WorkWindow, public SfxBroadcaster, public SfxListener
{
virtual BOOL Close();               // Schliessen
    BOOL CloseAll();                // Alle Fenster schliessen
    BOOL CompileAll();              // Alle Texte compilieren
    AutoTimer aLineNum;             // Zeigt die Zeilennummer an
virtual void Resize();
virtual void Move();
virtual void GetFocus();
    void LoadLibrary();
    void SaveLibrary();
    BOOL bIsAutoRun;
    DisplayHidDlg* pDisplayHidDlg;

//  BreakPoint *pRunToCursorBP;

    SbxVariable *pEditVar;

    Timer aCheckFiles;      // Prfen der Dateien auf nderungen
    BOOL bAutoReload;
    BOOL bAutoSave;
    DECL_LINK( CheckAllFiles, Timer* );

    MyBasicRef  pBasic;             // BASIC-Engine

    String aAppName;                // Inhalt der Titelteile der App:
    String aAppFile;                // AppName AppFile [AppMode]
    String aAppMode;
    void UpdateTitle();
    DECL_LINK( CloseButtonClick, void* );
    DECL_LINK( FloatButtonClick, void* );
    DECL_LINK( HideButtonClick, void* );

    FloatingExecutionStatus *pExecutionStatus;

public:
    BOOL IsAutoRun();
    void SetAutoRun( BOOL bAuto );
    BOOL bInBreak;                  // TRUE, wenn im Break-Handler
    StatusLine* pStatus;            // Statuszeile
    EditList*   pList;              // List der Edit-Fenster
    AppWin*     pWork;              // aktuelles Edit-Fenster
    BasicPrinter* pPrn;             // Drucker
    BOOL bDisas;                    // TRUE: disassemble
    USHORT nFlags;                  // Debugging-Flags
    USHORT nMaximizedWindows;       // Anzahl der Fenster, die maximized sind
    void FocusWindow( AppWin *pWin );
    void WinMax_Restore();
    void WinShow_Hide();
    void RemoveWindow( AppWin *pWin );
    void AddWindow( AppWin *pWin );
    void WindowRenamed( AppWin *pWin );

    BasicFrame();
   ~BasicFrame();
    MyBasic& Basic()                { return *pBasic; }
    void AddToLRU(String const& aFile);
    void LoadLRU();
    DECL_LINK( InitMenu, Menu * );
    DECL_LINK( DeInitMenu, Menu * );
    DECL_LINK( HighlightMenu, Menu * );
    DECL_LINK( MenuCommand, Menu * );
    DECL_LINK( Accel, Accelerator * );
    DECL_LINK( ShowLineNr, AutoTimer * );
    MsgEdit* GetMsgTree( String aLogFileName );
    DECL_LINK( Log, TTLogMsg * );
    DECL_LINK( WinInfo, WinInfoRec * );
    BOOL LoadFile( String aFilename );
    long Command( short,BOOL=FALSE );// Kommando-Handler
    BOOL SaveAll();                 // Alle Fenster speichern
    BOOL QueryFileName( String& rName, FileType nFileType, BOOL bSave );// Dateinamen ermitteln
    DECL_LINK( ModuleWinExists, String* );
    DECL_LINK( WriteString, String* );
    AppBasEd* CreateModuleWin( SbModule* pMod );
    AppBasEd* FindModuleWin( const String& );
    AppError* FindErrorWin( const String& );
    AppWin* FindWin( const String& );
    AppWin* FindWin( USHORT nWinId );
    AppWin* IsWinValid( AppWin* pMaybeWin );
    USHORT BreakHandler();          // Break-Handler-Callback

    void SetEditVar( SbxVariable *pVar ){ pEditVar = pVar;}
    SbxVariable* GetEditVar(){ return pEditVar;}
    BOOL IsAutoReload() { return bAutoReload; }
    BOOL IsAutoSave() { return bAutoSave; }
    void LoadIniFile();

    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );

    void SetAppMode( const String &aNewMode ){ aAppMode = aNewMode; UpdateTitle(); }

    String GenRealString( const String &aResString );

};

extern BasicApp aBasicApp;

#endif
<|endoftext|>


<commit_before>#include<iostream>
#include<stdlib.h>
#include<cstring>
using namespace std;
void bubbleSort(int a[], int N);
void insertSort(int a[], int N);
void quickSort(int a[], int left, int right);
void testSort();
void testA(int a[], int N){
	bool ok=true;
	for(int i=0; i<N-1; i++){
		if(a[i]>a[i+1]){
			ok = false;
			break;
		}
	}
	if(!ok){
		for(int i=0; i<N; i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
	}
}
int main(){
	testSort();
	return 0;
}

void testSort(){
	int a[15];
	int N=15;
	int b[15];
	int testNum=1000;
	for(int i=0; i<testNum; i++){
		for(int j=0; j<N; j++){
			a[j] = rand()%1000;
		}
		memcpy(b, a, sizeof(a));
		bubbleSort(b, N);
		testA(b, N);

		memcpy(b, a, sizeof(a));
		quickSort(b, 0, N);
		testA(b, N);
	}
}

void bubbleSort(int a[], int N){
	int minNum,minInd;
	for(int i=0; i<N; i++){
		minNum = a[i];
		minInd = i;
		for(int j=i+1; j<N; j++){
			if(minNum > a[j]){
				minNum = a[j];
				minInd = j;
			}
		}
		a[minInd] = a[i];
		a[i] = minNum;
	}
}

void quickSort(int a[], int left, int right){
	if(right-left <= 1)
		return;
	int p=a[left];
	int i=left+1,j=right;
	int temp;
	while(i<=j){
		while(i<=j && a[i]<p) i++;
		while(i<=j && a[j]>=p) j--;
		if(i<j){
			temp = a[i];
			a[i] = a[j];
			a[j] = temp;
			i++;
			j--;
		} else {
			a[left] = a[j];
			a[j] = p;
		}
	}
	quickSort(a, left, j-1);
	quickSort(a, j+1, right);
}

void quickSort2(int arr[], int left, int right) {
      int i = left, j = right;
      int tmp;
      int pivot = arr[(left + right) / 2];

      /* partition */
      while (i <= j) {
            while (arr[i] < pivot)
                  i++;
            while (arr[j] > pivot)
                  j--;
            if (i <= j) {
                  tmp = arr[i];
                  arr[i] = arr[j];
                  arr[j] = tmp;
                  i++;
                  j--;
            }
      };

      /* recursion */
      if (left < j)
            quickSort(arr, left, j);
      if (i < right)
            quickSort(arr, i, right);
}<commit_msg>add quickSort in sort.cpp<commit_after>#include<iostream>
#include<stdlib.h>
#include<cstring>
using namespace std;
void bubbleSort(int a[], int N);
void insertSort(int a[], int N);
void quickSort(int a[], int left, int right);
void testSort();
void printA(int a[], int N) {
	for (int i = 0; i<N; i++) {
		cout << a[i] << " ";
	}
	cout << endl;
}
void printA(int a[], int left,int right) {
	for (int i = left; i<=right; i++) {
		cout << a[i] << " ";
	}
	cout << endl;
}
void testA(int a[], int N) {
	bool ok = true;
	for (int i = 0; i<N - 1; i++) {
		if (a[i]>a[i + 1]) {
			ok = false;
			break;
		}
	}
	if (!ok) {
		cout << "false: ";
		printA(a, N);
	}
}
int main() {
	testSort();
	return 0;
}

void testSort() {
	const int N = 150;
	const int testNum = 10000;
	int a[N], b[N];
	for (int i = 0; i<testNum; i++) {
		for (int j = 0; j<N; j++) {
			a[j] = rand() % 1000;
		}
		memcpy(b, a, sizeof(a));
		bubbleSort(b, N);
		testA(b, N);

		memcpy(b, a, sizeof(a));
		quickSort(b, 0, N-1);
		testA(b, N);
	}
}

void bubbleSort(int a[], int N) {
	int minNum, minInd;
	for (int i = 0; i<N; i++) {
		minNum = a[i];
		minInd = i;
		for (int j = i + 1; j<N; j++) {
			if (minNum > a[j]) {
				minNum = a[j];
				minInd = j;
			}
		}
		a[minInd] = a[i];
		a[i] = minNum;
	}
}

void quickSort(int a[], int left, int right) {
	if (right - left < 1)
		return;
	int p = a[left];
	int i = left, j = right;
	int temp;
	// printA(a, left, right);
	while (i < j) {
		while (i < j && a[j] >= p) j--;
		a[i] = a[j];
		while (i < j && a[i] <= p) i++;
		a[j] = a[i];
	}
	a[i] = p;
	// printA(a, left, right);
	quickSort(a, left, j - 1);
	quickSort(a, j + 1, right);
}

void quickSort2(int arr[], int left, int right) {
	int i = left, j = right;
	int tmp;
	int pivot = arr[(left + right) / 2];

	/* partition */
	while (i <= j) {
		while (arr[i] < pivot)
			i++;
		while (arr[j] > pivot)
			j--;
		if (i <= j) {
			tmp = arr[i];
			arr[i] = arr[j];
			arr[j] = tmp;
			i++;
			j--;
		}
	};

	/* recursion */
	if (left < j)
		quickSort(arr, left, j);
	if (i < right)
		quickSort(arr, i, right);
}<|endoftext|>


<commit_before>#include "textures/constant_texture.h"

ConstantTexture::ConstantTexture(const Colorf &color) : color(color){}
Colorf ConstantTexture::sample(const DifferentialGeometry &) const {
	return color;
}
Colorf ConstantTexture::sample(const TextureSample &sample) const {
	return color;
}

<commit_msg>Clean up unused param warning<commit_after>#include "textures/constant_texture.h"

ConstantTexture::ConstantTexture(const Colorf &color) : color(color){}
Colorf ConstantTexture::sample(const DifferentialGeometry&) const {
	return color;
}
Colorf ConstantTexture::sample(const TextureSample&) const {
	return color;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */

#include "test/av1_txfm_test.h"
#include "av1/common/av1_fwd_txfm1d.h"
#include "av1/common/av1_inv_txfm1d.h"

using libaom_test::ACMRandom;
using libaom_test::input_base;

namespace {
const int txfm_type_num = 2;
const int txfm_size_num = 5;
const int txfm_size_ls[5] = { 4, 8, 16, 32, 64 };

const TxfmFunc fwd_txfm_func_ls[2][5] = {
  {
      av1_fdct4_new, av1_fdct8_new, av1_fdct16_new, av1_fdct32_new,
#if CONFIG_TX64X64
      av1_fdct64_new,
#else
      NULL,
#endif
  },
  { av1_fadst4_new, av1_fadst8_new, av1_fadst16_new, av1_fadst32_new, NULL }
};

const TxfmFunc inv_txfm_func_ls[2][5] = {
  {
      av1_idct4_new, av1_idct8_new, av1_idct16_new, av1_idct32_new,
#if CONFIG_TX64X64
      av1_idct64_new,
#else
      NULL,
#endif
  },
  { av1_iadst4_new, av1_iadst8_new, av1_iadst16_new, av1_iadst32_new, NULL }
};

// the maximum stage number of fwd/inv 1d dct/adst txfm is 12
const int8_t cos_bit[12] = { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 };
const int8_t range_bit[12] = { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 };

#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof(x[0]))

TEST(av1_inv_txfm1d, round_trip) {
  ACMRandom rnd(ACMRandom::DeterministicSeed());
  for (int si = 0; si < txfm_size_num; ++si) {
    int txfm_size = txfm_size_ls[si];
    int32_t input[64];
    int32_t output[64];
    int32_t round_trip_output[64];

    assert(txfm_size <= ARRAY_SIZE(input));

    for (int ti = 0; ti < txfm_type_num; ++ti) {
      TxfmFunc fwd_txfm_func = fwd_txfm_func_ls[ti][si];
      TxfmFunc inv_txfm_func = inv_txfm_func_ls[ti][si];
      int max_error = 2;

      if (fwd_txfm_func != NULL) {
        const int count_test_block = 5000;
        for (int ci = 0; ci < count_test_block; ++ci) {
          for (int ni = 0; ni < txfm_size; ++ni) {
            input[ni] = rnd.Rand16() % input_base - rnd.Rand16() % input_base;
          }

          fwd_txfm_func(input, output, cos_bit, range_bit);
          inv_txfm_func(output, round_trip_output, cos_bit, range_bit);

          for (int ni = 0; ni < txfm_size; ++ni) {
            int node_err =
                abs(input[ni] - round_shift(round_trip_output[ni],
                                            get_max_bit(txfm_size) - 1));
            EXPECT_LE(node_err, max_error);
          }
        }
      }
    }
  }
}

}  // namespace
<commit_msg>Group TX by sizes<commit_after>/*
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */

#include "test/av1_txfm_test.h"
#include "av1/common/av1_fwd_txfm1d.h"
#include "av1/common/av1_inv_txfm1d.h"

using libaom_test::ACMRandom;
using libaom_test::input_base;

namespace {
const int txfm_type_num = 2;
const int txfm_size_ls[5] = { 4, 8, 16, 32, 64 };

const TxfmFunc fwd_txfm_func_ls[][2] = {
  { av1_fdct4_new, av1_fadst4_new },
  { av1_fdct8_new, av1_fadst8_new },
  { av1_fdct16_new, av1_fadst16_new },
  { av1_fdct32_new, av1_fadst32_new },
#if CONFIG_TX64X64
  { av1_fdct64_new, NULL },
#endif
};

const TxfmFunc inv_txfm_func_ls[][2] = {
  { av1_idct4_new, av1_iadst4_new },
  { av1_idct8_new, av1_iadst8_new },
  { av1_idct16_new, av1_iadst16_new },
  { av1_idct32_new, av1_iadst32_new },
#if CONFIG_TX64X64
  { av1_idct64_new, NULL },
#endif
};

// the maximum stage number of fwd/inv 1d dct/adst txfm is 12
const int8_t cos_bit[12] = { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 };
const int8_t range_bit[12] = { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 };

#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof(x[0]))

TEST(av1_inv_txfm1d, round_trip) {
  ACMRandom rnd(ACMRandom::DeterministicSeed());
  for (int si = 0; si < ARRAY_SIZE(fwd_txfm_func_ls); ++si) {
    int txfm_size = txfm_size_ls[si];
    int32_t input[64];
    int32_t output[64];
    int32_t round_trip_output[64];

    assert(txfm_size <= ARRAY_SIZE(input));

    for (int ti = 0; ti < txfm_type_num; ++ti) {
      TxfmFunc fwd_txfm_func = fwd_txfm_func_ls[si][ti];
      TxfmFunc inv_txfm_func = inv_txfm_func_ls[si][ti];
      int max_error = 2;

      if (fwd_txfm_func != NULL) {
        const int count_test_block = 5000;
        for (int ci = 0; ci < count_test_block; ++ci) {
          for (int ni = 0; ni < txfm_size; ++ni) {
            input[ni] = rnd.Rand16() % input_base - rnd.Rand16() % input_base;
          }

          fwd_txfm_func(input, output, cos_bit, range_bit);
          inv_txfm_func(output, round_trip_output, cos_bit, range_bit);

          for (int ni = 0; ni < txfm_size; ++ni) {
            int node_err =
                abs(input[ni] - round_shift(round_trip_output[ni],
                                            get_max_bit(txfm_size) - 1));
            EXPECT_LE(node_err, max_error);
          }
        }
      }
    }
  }
}

}  // namespace
<|endoftext|>


<commit_before>// Copyright © 2017 Dmitriy Khaustov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Dmitriy Khaustov aka xDimon
// Contacts: khaustov.dm@gmail.com
// File created on: 2017.03.29

// WebsocketServer.cpp

#include <sstream>
#include <memory>
#include <cstring>
#include "../net/ConnectionManager.hpp"
#include "../net/TcpConnection.hpp"
#include "../server/Server.hpp"
#include "../utils/Base64.hpp"
#include "../utils/hash/SHA1.hpp"
#include "../utils/Time.hpp"
#include "websocket/WsContext.hpp"
#include "WebsocketServer.hpp"
#include "http/HttpResponse.hpp"

REGISTER_TRANSPORT(websocket, WebsocketServer);

bool WebsocketServer::processing(std::shared_ptr<Connection> connection_)
{
	auto connection = std::dynamic_pointer_cast<TcpConnection>(connection_);
	if (!connection)
	{
		throw std::runtime_error("Bad connection-type for this transport");
	}

	if (!connection->getContext())
	{
		connection->setContext(std::make_shared<WsContext>(connection)->ptr());
	}
	auto context = std::dynamic_pointer_cast<WsContext>(connection->getContext());
	if (!context)
	{
		throw std::runtime_error("Bad context-type for this transport");
	}

	if (!context->established())
	{
		// Проверка готовности заголовков
		auto endHeaders = static_cast<const char *>(memmem(connection->dataPtr(), connection->dataLen(), "\r\n\r\n", 4));

		if (!endHeaders && connection->dataLen() < (1 << 12))
		{
			_log.debug("Not anough data for read headers (%zu bytes)", connection->dataLen());
			return true;
		}

		if (!endHeaders || (endHeaders - connection->dataPtr()) > (1 << 12))
		{
			_log.debug("Headers part of request too large (%zu bytes)", endHeaders - connection->dataPtr());

			HttpResponse(400)
				<< HttpHeader("Connection", "close")
				<< "Headers data too large\n"
				>> *connection;

			return true;
		}

		size_t headersSize = endHeaders - connection->dataPtr() + 4;

		_log.debug("Read %zu bytes of request headers", headersSize);

		try
		{
			// Читаем запрос
			auto request = std::make_shared<HttpRequest>(connection->dataPtr(), connection->dataPtr() + headersSize);

			// Пропускаем байты заголовка
			connection->skip(headersSize);

			context->setRequest(request);

			// Допустим только GET
			if (context->getRequest()->method() != HttpRequest::Method::GET)
			{
				throw std::runtime_error("Unsupported method");
			}

			// Проверка заголовков
			if (
				request->getHeader("Connection") != "Upgrade" ||
				request->getHeader("Upgrade") != "websocket" ||
				request->getHeader("Sec-WebSocket-Key") == ""
			)
			{
				throw std::runtime_error("Bad headers");
			}

			auto& wsKey = request->getHeader("Sec-WebSocket-Key");

			// (echo -n "$1"; echo -n '258EAFA5-E914-47DA-95CA-C5AB0DC85B11') | sha1sum | xxd -r -p | base64
			auto acceptKey = Base64::encode(SHA1::encode_bin(wsKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));

			auto handler = getHandler(context->getRequest()->uri().path());
			if (!handler)
			{
				HttpResponse(404, "WebSocket Upgrade Failure")
					<< HttpHeader("X-ServerTransport", "websocket", true)
					<< HttpHeader("Connection", "Close")
					<< "Not found service-handler for uri " << context->getRequest()->uri().path()
					>> *connection;

				connection->close();
				context.reset();
				return true;
			}

			HttpResponse(101, "Web Socket Protocol Handshake")
				<< HttpHeader("X-ServerTransport", "websocket", true)
				<< HttpHeader("Upgrade", "websocket")
				<< HttpHeader("Connection", "Upgrade")
				<< HttpHeader("Sec-WebSocket-Accept", acceptKey)
				>> *connection;

			if (!handler)
			{
				std::string msg("##Not found service-handler for uri ");
				msg += context->getRequest()->uri().path();
				uint16_t code = htobe16(1008); // Policy Violation
				memcpy(const_cast<char *>(msg.data()), &code, sizeof(code));
				WsFrame::send(connection, WsFrame::Opcode::Close, msg.c_str(), msg.length());
				context.reset();
				connection->close();
				return true;
			}

			context->getRequest().reset();

			context->setHandler(std::move(handler));

			context->setEstablished();
		}
		catch (std::runtime_error &exception)
		{
			HttpResponse(400)
				<< HttpHeader("X-ServerTransport", "websocket", true)
				<< HttpHeader("Connection", "Close")
				<< exception.what()
				>> *connection;

			connection->close();

			return true;
		}
	}

	int n = 0;

	// Цикл извлечения фреймов
	for (;;)
	{
		// http://learn.javascript.ru/websockets#описание-фрейма

		// Пробуем читать новый фрейм
		if (!context->getFrame())
		{
			// Недостаточно данных для получения размера заголовка фрейма
			if (connection->dataLen() < 2)
			{
				if (connection->dataLen())
				{
					_log.debug("Not anough data for calc frame header size (%zu < 2)", connection->dataLen());
				}
				else
				{
					_log.debug("No more data");
				}
				break;
			}

			// Недостаточно данных для чтения заголовка фрейма
			size_t headerSize = WsFrame::calcHeaderSize(connection->dataPtr());
			if (connection->dataLen() < headerSize)
			{
				_log.debug("Not anough data for get frame header (%zu < %zu)", connection->dataLen(), headerSize);
				break;
			}

			auto frame = std::shared_ptr<WsFrame>(new WsFrame(connection->dataPtr(), connection->dataPtr() + connection->dataLen()));

			_log.debug("Read %zu bytes of frame header. Size of data: %zu bytes", headerSize, frame->contentLength());

			context->setFrame(frame);

			// Пропускаем байты заголовка фрейма
			connection->skip(headerSize);
		}

		// Читаем данные фрейма
		if (context->getFrame()->contentLength() > context->getFrame()->dataLen())
		{
			size_t len = std::min(context->getFrame()->contentLength() - context->getFrame()->dataLen(), connection->dataLen());

			context->getFrame()->write(connection->dataPtr(), len);

			connection->skip(len);

			if (context->getFrame()->contentLength() > context->getFrame()->dataLen())
			{
				_log.debug("Not anough data for read frame body (%zu < %zu)", context->getFrame()->dataLen(), context->getFrame()->contentLength());
				break;
			}
		}

		context->getFrame()->applyMask();

		if (context->getFrame()->opcode() == WsFrame::Opcode::Text || context->getFrame()->opcode() == WsFrame::Opcode::Binary)
		{
			ServerTransport::Transmitter transmitter =
				[connection,opcode = context->getFrame()->opcode()]
					(const char*data, size_t size, const std::string&, bool close){
					WsFrame::send(connection, opcode, data, size);
					if (close)
					{
						std::string msg("##Bye!");
						uint16_t code = htobe16(1000); // Normal Closure
						memcpy(const_cast<char *>(msg.data()), &code, sizeof(code));

						WsFrame::send(connection, WsFrame::Opcode::Close, msg.c_str(), msg.length());
						connection->close();
					}
					ConnectionManager::watch(connection);
				};

			context->setTransmitter(transmitter);
			context->handle(context->getFrame()->dataPtr(), context->getFrame()->dataLen());
			context->getFrame().reset();
			n++;
			continue;
		}
//		else if (context->getFrame()->opcode() == WsFrame::Opcode::Text)
//		{
//			_log.debug("TEXT-FRAME: \"%s\" %zu bytes", context->getFrame()->dataPtr(), context->getFrame()->dataLen());
//			WsFrame::send(connection, WsFrame::Opcode::Text, context->getFrame()->dataPtr(), context->getFrame()->dataLen());
//			context->getFrame().reset();
//			n++;
//			continue;
//		}
//		else if (context->getFrame()->opcode() == WsFrame::Opcode::Binary)
//		{
//			_log.debug("BINARY-FRAME: %zu bytes", context->getFrame()->dataLen());
//			WsFrame::send(connection, WsFrame::Opcode::Text, "Received binary data", 21);
//			context->getFrame().reset();
//			n++;
//			continue;
//		}
		else if (context->getFrame()->opcode() == WsFrame::Opcode::Ping)
		{
			WsFrame::send(connection, WsFrame::Opcode::Pong, context->getFrame()->dataPtr(), context->getFrame()->dataLen());
			_log.debug("PING-FRAME: %zu bytes", context->getFrame()->dataLen());
			context->getFrame().reset();
			n++;
			continue;
		}
		else if (context->getFrame()->opcode() == WsFrame::Opcode::Close)
		{
			_log.debug("CLOSE-FRAME: %zu bytes", context->getFrame()->dataLen());
			WsFrame::send(connection, WsFrame::Opcode::Close, "Bye!", 4);
			context.reset();
			connection->close();
			n++;
			break;
		}
		else
		{
			_log.debug("UNSUPPORTED-FRAME(#%d): %zu bytes", static_cast<int>(context->getFrame()->opcode()), context->getFrame()->dataLen());
			WsFrame::send(connection, WsFrame::Opcode::Close, "Unsupported opcode", 21);
			context.reset();
			n++;
			break;
		}
	}

	_log.debug("Processed %d request, remain %zu bytes", n, connection->dataLen());

	return true;
}

void WebsocketServer::bindHandler(const std::string& selector, ServerTransport::Handler handler)
{
	if (_handlers.find(selector) != _handlers.end())
	{
		throw std::runtime_error("Handler already set early");
	}

	_handlers.emplace(selector, handler);
}

ServerTransport::Handler WebsocketServer::getHandler(std::string subject)
{
	do
	{
		auto i = _handlers.upper_bound(subject);

		if (i != _handlers.end())
		{
//			_log.debug(">>> '%s' upper_bound: '%s'", subject.c_str(), i->first.c_str());
			if (i->first == subject)
			{
//				_log.debug(">>> DONE: found '%s'", i->first.c_str());
				return i->second;
			}
		}
//		_log.debug(">>> '%s' upper_bound: end", subject.c_str());

		if (i == _handlers.begin())
		{
//			_log.debug(">>> '%s' upper_bound: begin", subject.c_str());
//			_log.debug(">>> DONE: not found");
			break;
		}

		--i;
//		_log.debug(">>> '%s' previously:  '%s'", subject.c_str(), i->first.c_str());

		size_t len = std::min(subject.length(), i->first.length());

		int cmpres = std::strncmp(i->first.c_str(), subject.c_str(), len);
		if (cmpres == 0)
		{
//			_log.debug(">>> DONE: found '%s'", i->first.c_str());
			return i->second;
		}
		else if (cmpres > 0)
		{
//			_log.debug(">>> DONE: not found");
			return nullptr;
		}

		subject.resize(--len);
//		_log.debug(">>> sbj decrease to '%s'", subject.c_str(), i->first.c_str());
	}
	while (subject.length());

	return nullptr;
}
<commit_msg>Add flash-policy-file responce by WebsocketServer<commit_after>// Copyright © 2017 Dmitriy Khaustov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Dmitriy Khaustov aka xDimon
// Contacts: khaustov.dm@gmail.com
// File created on: 2017.03.29

// WebsocketServer.cpp

#include <sstream>
#include <memory>
#include <cstring>
#include "../net/ConnectionManager.hpp"
#include "../net/TcpConnection.hpp"
#include "../server/Server.hpp"
#include "../utils/Base64.hpp"
#include "../utils/hash/SHA1.hpp"
#include "../utils/Time.hpp"
#include "websocket/WsContext.hpp"
#include "WebsocketServer.hpp"
#include "http/HttpResponse.hpp"

REGISTER_TRANSPORT(websocket, WebsocketServer);

bool WebsocketServer::processing(std::shared_ptr<Connection> connection_)
{
	auto connection = std::dynamic_pointer_cast<TcpConnection>(connection_);
	if (!connection)
	{
		throw std::runtime_error("Bad connection-type for this transport");
	}

	if (!connection->getContext())
	{
		connection->setContext(std::make_shared<WsContext>(connection)->ptr());
	}
	auto context = std::dynamic_pointer_cast<WsContext>(connection->getContext());
	if (!context)
	{
		throw std::runtime_error("Bad context-type for this transport");
	}

	if (!context->established())
	{
		if (connection->dataLen() >= 22 && !memcmp(connection->dataPtr(), "<policy-file-request/>", 22))
		{
			const std::string& policyFile = R"(<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-access-from domain="*" secure="false" to-ports="*"/>
  <allow-access-from domain="*" secure="true" to-ports="*"/>
  <site-control permitted-cross-domain-policies="master-only"/>
</cross-domain-policy>
)";

			char zero = 0;
			connection->write(policyFile.c_str(), policyFile.length());
			connection->write(&zero, 1);
			connection->close();

			_log.debug("Sent policy file");

			return true;
		}

		// Проверка готовности заголовков
		auto endHeaders = static_cast<const char *>(memmem(connection->dataPtr(), connection->dataLen(), "\r\n\r\n", 4));

		if (!endHeaders && connection->dataLen() < (1 << 12))
		{
			_log.debug("Not anough data for read headers (%zu bytes)", connection->dataLen());
			return true;
		}

		if (!endHeaders || (endHeaders - connection->dataPtr()) > (1 << 12))
		{
			_log.debug("Headers part of request too large (%zu bytes)", endHeaders - connection->dataPtr());

			HttpResponse(400)
				<< HttpHeader("Connection", "close")
				<< "Headers data too large\n"
				>> *connection;

			return true;
		}

		size_t headersSize = endHeaders - connection->dataPtr() + 4;

		_log.debug("Read %zu bytes of request headers", headersSize);

		try
		{
			// Читаем запрос
			auto request = std::make_shared<HttpRequest>(connection->dataPtr(), connection->dataPtr() + headersSize);

			// Пропускаем байты заголовка
			connection->skip(headersSize);

			context->setRequest(request);

			// Допустим только GET
			if (context->getRequest()->method() != HttpRequest::Method::GET)
			{
				throw std::runtime_error("Unsupported method");
			}

			// Проверка заголовков
			if (
				request->getHeader("Connection") != "Upgrade" ||
				request->getHeader("Upgrade") != "websocket" ||
				request->getHeader("Sec-WebSocket-Key") == ""
			)
			{
				throw std::runtime_error("Bad headers");
			}

			auto& wsKey = request->getHeader("Sec-WebSocket-Key");

			// (echo -n "$1"; echo -n '258EAFA5-E914-47DA-95CA-C5AB0DC85B11') | sha1sum | xxd -r -p | base64
			auto acceptKey = Base64::encode(SHA1::encode_bin(wsKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));

			auto handler = getHandler(context->getRequest()->uri().path());
			if (!handler)
			{
				HttpResponse(404, "WebSocket Upgrade Failure")
					<< HttpHeader("X-ServerTransport", "websocket", true)
					<< HttpHeader("Connection", "Close")
					<< "Not found service-handler for uri " << context->getRequest()->uri().path()
					>> *connection;

				connection->close();
				context.reset();
				return true;
			}

			HttpResponse(101, "Web Socket Protocol Handshake")
				<< HttpHeader("X-ServerTransport", "websocket", true)
				<< HttpHeader("Upgrade", "websocket")
				<< HttpHeader("Connection", "Upgrade")
				<< HttpHeader("Sec-WebSocket-Accept", acceptKey)
				>> *connection;

			if (!handler)
			{
				std::string msg("##Not found service-handler for uri ");
				msg += context->getRequest()->uri().path();
				uint16_t code = htobe16(1008); // Policy Violation
				memcpy(const_cast<char *>(msg.data()), &code, sizeof(code));
				WsFrame::send(connection, WsFrame::Opcode::Close, msg.c_str(), msg.length());
				context.reset();
				connection->close();
				return true;
			}

			context->getRequest().reset();

			context->setHandler(std::move(handler));

			context->setEstablished();
		}
		catch (std::runtime_error &exception)
		{
			HttpResponse(400)
				<< HttpHeader("X-ServerTransport", "websocket", true)
				<< HttpHeader("Connection", "Close")
				<< exception.what()
				>> *connection;

			connection->close();

			return true;
		}
	}

	int n = 0;

	// Цикл извлечения фреймов
	for (;;)
	{
		// http://learn.javascript.ru/websockets#описание-фрейма

		// Пробуем читать новый фрейм
		if (!context->getFrame())
		{
			// Недостаточно данных для получения размера заголовка фрейма
			if (connection->dataLen() < 2)
			{
				if (connection->dataLen())
				{
					_log.debug("Not anough data for calc frame header size (%zu < 2)", connection->dataLen());
				}
				else
				{
					_log.debug("No more data");
				}
				break;
			}

			// Недостаточно данных для чтения заголовка фрейма
			size_t headerSize = WsFrame::calcHeaderSize(connection->dataPtr());
			if (connection->dataLen() < headerSize)
			{
				_log.debug("Not anough data for get frame header (%zu < %zu)", connection->dataLen(), headerSize);
				break;
			}

			auto frame = std::shared_ptr<WsFrame>(new WsFrame(connection->dataPtr(), connection->dataPtr() + connection->dataLen()));

			_log.debug("Read %zu bytes of frame header. Size of data: %zu bytes", headerSize, frame->contentLength());

			context->setFrame(frame);

			// Пропускаем байты заголовка фрейма
			connection->skip(headerSize);
		}

		// Читаем данные фрейма
		if (context->getFrame()->contentLength() > context->getFrame()->dataLen())
		{
			size_t len = std::min(context->getFrame()->contentLength() - context->getFrame()->dataLen(), connection->dataLen());

			context->getFrame()->write(connection->dataPtr(), len);

			connection->skip(len);

			if (context->getFrame()->contentLength() > context->getFrame()->dataLen())
			{
				_log.debug("Not anough data for read frame body (%zu < %zu)", context->getFrame()->dataLen(), context->getFrame()->contentLength());
				break;
			}
		}

		context->getFrame()->applyMask();

		if (context->getFrame()->opcode() == WsFrame::Opcode::Text || context->getFrame()->opcode() == WsFrame::Opcode::Binary)
		{
			ServerTransport::Transmitter transmitter =
				[connection,opcode = context->getFrame()->opcode()]
					(const char*data, size_t size, const std::string&, bool close){
					WsFrame::send(connection, opcode, data, size);
					if (close)
					{
						std::string msg("##Bye!");
						uint16_t code = htobe16(1000); // Normal Closure
						memcpy(const_cast<char *>(msg.data()), &code, sizeof(code));

						WsFrame::send(connection, WsFrame::Opcode::Close, msg.c_str(), msg.length());
						connection->close();
					}
					ConnectionManager::watch(connection);
				};

			context->setTransmitter(transmitter);
			context->handle(context->getFrame()->dataPtr(), context->getFrame()->dataLen());
			context->getFrame().reset();
			n++;
			continue;
		}
//		else if (context->getFrame()->opcode() == WsFrame::Opcode::Text)
//		{
//			_log.debug("TEXT-FRAME: \"%s\" %zu bytes", context->getFrame()->dataPtr(), context->getFrame()->dataLen());
//			WsFrame::send(connection, WsFrame::Opcode::Text, context->getFrame()->dataPtr(), context->getFrame()->dataLen());
//			context->getFrame().reset();
//			n++;
//			continue;
//		}
//		else if (context->getFrame()->opcode() == WsFrame::Opcode::Binary)
//		{
//			_log.debug("BINARY-FRAME: %zu bytes", context->getFrame()->dataLen());
//			WsFrame::send(connection, WsFrame::Opcode::Text, "Received binary data", 21);
//			context->getFrame().reset();
//			n++;
//			continue;
//		}
		else if (context->getFrame()->opcode() == WsFrame::Opcode::Ping)
		{
			WsFrame::send(connection, WsFrame::Opcode::Pong, context->getFrame()->dataPtr(), context->getFrame()->dataLen());
			_log.debug("PING-FRAME: %zu bytes", context->getFrame()->dataLen());
			context->getFrame().reset();
			n++;
			continue;
		}
		else if (context->getFrame()->opcode() == WsFrame::Opcode::Close)
		{
			_log.debug("CLOSE-FRAME: %zu bytes", context->getFrame()->dataLen());
			WsFrame::send(connection, WsFrame::Opcode::Close, "Bye!", 4);
			context.reset();
			connection->close();
			n++;
			break;
		}
		else
		{
			_log.debug("UNSUPPORTED-FRAME(#%d): %zu bytes", static_cast<int>(context->getFrame()->opcode()), context->getFrame()->dataLen());
			WsFrame::send(connection, WsFrame::Opcode::Close, "Unsupported opcode", 21);
			context.reset();
			n++;
			break;
		}
	}

	_log.debug("Processed %d request, remain %zu bytes", n, connection->dataLen());

	return true;
}

void WebsocketServer::bindHandler(const std::string& selector, ServerTransport::Handler handler)
{
	if (_handlers.find(selector) != _handlers.end())
	{
		throw std::runtime_error("Handler already set early");
	}

	_handlers.emplace(selector, handler);
}

ServerTransport::Handler WebsocketServer::getHandler(std::string subject)
{
	do
	{
		auto i = _handlers.upper_bound(subject);

		if (i != _handlers.end())
		{
//			_log.debug(">>> '%s' upper_bound: '%s'", subject.c_str(), i->first.c_str());
			if (i->first == subject)
			{
//				_log.debug(">>> DONE: found '%s'", i->first.c_str());
				return i->second;
			}
		}
//		_log.debug(">>> '%s' upper_bound: end", subject.c_str());

		if (i == _handlers.begin())
		{
//			_log.debug(">>> '%s' upper_bound: begin", subject.c_str());
//			_log.debug(">>> DONE: not found");
			break;
		}

		--i;
//		_log.debug(">>> '%s' previously:  '%s'", subject.c_str(), i->first.c_str());

		size_t len = std::min(subject.length(), i->first.length());

		int cmpres = std::strncmp(i->first.c_str(), subject.c_str(), len);
		if (cmpres == 0)
		{
//			_log.debug(">>> DONE: found '%s'", i->first.c_str());
			return i->second;
		}
		else if (cmpres > 0)
		{
//			_log.debug(">>> DONE: not found");
			return nullptr;
		}

		subject.resize(--len);
//		_log.debug(">>> sbj decrease to '%s'", subject.c_str(), i->first.c_str());
	}
	while (subject.length());

	return nullptr;
}
<|endoftext|>