<commit_before>// Copyright (c) 2017, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of hpp-core.
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core. If not, see <http://www.gnu.org/licenses/>.

#include <hpp/core/path-optimization/simple-time-parameterization.hh>

#include <limits>

#include <pinocchio/multibody/model.hpp>

#include <hpp/pinocchio/configuration.hh>
#include <hpp/pinocchio/device.hh>
#include <hpp/pinocchio/liegroup.hh>
#include <hpp/core/interpolated-path.hh>
#include <hpp/core/path-vector.hh>
#include <hpp/core/problem.hh>
#include <hpp/core/straight-path.hh>
#include <hpp/core/time-parameterization/polynomial.hh>

namespace hpp {
  namespace core {
    namespace pathOptimization {
      using timeParameterization::Polynomial;
      using std::isfinite;

      namespace {
        TimeParameterizationPtr_t computeTimeParameterizationFirstOrder (
            const value_type& s0, const value_type& s1, const value_type& B,
            value_type& T)
        {
          vector_t a(2);
          T = (s1 - s0) / B;
          a[0] = s0;
          a[1] = B;
          hppDout (info, "Time parametrization returned " << a.transpose()
              << ", " << T);
          if (!isfinite(T) || !a.allFinite() || a.hasNaN()) {
            HPP_THROW(std::logic_error, "Invalid time parameterization "
                "coefficients: " << a.transpose());
          }
          return TimeParameterizationPtr_t (new Polynomial (a));
        }

        TimeParameterizationPtr_t computeTimeParameterizationThirdOrder (
            const value_type& s0, const value_type& s1, const value_type& B,
            value_type& T)
        {
          vector_t a(4);
          T = 3 * (s1 - s0) / (2 * B);
          a[0] = s0;
          a[1] = 0;
          a[2] = 3 * (s1 - s0) / (T * T);
          a[3] = - 2 * a[2] / (3 * T);
          hppDout (info, "Time parametrization returned " << a.transpose()
              << ", " << T);
          if (!isfinite(T) || !a.allFinite() || a.hasNaN()) {
            HPP_THROW(std::logic_error, "Invalid time parameterization "
                "coefficients: " << a.transpose());
          }
          return TimeParameterizationPtr_t (new Polynomial (a));
        }

        TimeParameterizationPtr_t computeTimeParameterizationFifthOrder (
            const value_type& s0, const value_type& s1, const value_type& B,
            const value_type& C, value_type& T)
        {
          vector_t a(6);
          if (C > 0) {
            T = std::max(
                15 * (s1 - s0) / (8 * B)                     , // Velocity limit
                sqrt((10./std::sqrt(3))) * sqrt((s1 - s0) / C) // Acceleration limit
                );
          } else {
            T = 15 * (s1 - s0) / (8 * B);
          }

          value_type Tpow = T*T*T;
          a[0] = s0;
          a[1] = 0;
          a[2] = 0;
          a[3] =  10 * (s1 - s0) / Tpow;
          Tpow *= T;
          a[4] = -15 * (s1 - s0) / Tpow;
          Tpow *= T;
          a[5] =   6 * (s1 - s0) / Tpow;
          hppDout (info, "Time parametrization returned " << a.transpose()
              << ", " << T);
          if (!isfinite(T) || !a.allFinite() || a.hasNaN()) {
            HPP_THROW(std::logic_error, "Invalid time parameterization "
                "coefficients: " << a.transpose());
          }
          return TimeParameterizationPtr_t (new Polynomial (a));
        }

        void checkTimeParameterization (const TimeParameterizationPtr_t tp,
            const size_type order, const interval_t sr, const value_type B, const value_type& C, const value_type T)
        {
          using std::fabs;
          const value_type thr = std::sqrt(Eigen::NumTraits<value_type>::dummy_precision());
          if (   fabs(tp->value(0) - sr.first) >= thr
              || fabs(tp->value(T) - sr.second) >= thr) {
            HPP_THROW(std::logic_error, "Interval of TimeParameterization result"
                " is not correct. Expected " << sr.first << ", " << sr.second <<
                ". Got " << tp->value(0) << ", " << tp->value(T));
          }
          if (order >= 1
              && (fabs(tp->derivative(0, 1)) > thr
              ||  fabs(tp->derivative(T, 1)) > thr
              ||  ((C <= 0) && fabs(tp->derivative(T/2, 1) - B) > thr))
             ) {
            HPP_THROW(std::logic_error,
                "Derivative of TimeParameterization are not correct:"
                << "\ntp->derivative(0, 1) = " << tp->derivative(0, 1)
                << "\ntp->derivative(T, 1) = " << tp->derivative(T, 1)
                << "\ntp->derivative(T/2, 1) - B = " << tp->derivative(T/2, 1) - B
                << "\nT = " << T
                << "\nB = " << B
                << "\nC = " << C
                );
          }
          if (order >= 2
              && (fabs(tp->derivative(0, 2)) > thr
              ||  fabs(tp->derivative(T, 2)) > thr)
             ) {
            HPP_THROW(std::logic_error,
                "Derivative of TimeParameterization are not correct:"
                << "\ntp->derivative(0, 2) = " << tp->derivative(0, 2)
                << "\ntp->derivative(T, 2) = " << tp->derivative(T, 2)
                << "\nT = " << T
                );
          }
        }
      }

      SimpleTimeParameterizationPtr_t SimpleTimeParameterization::create (const Problem& problem)
      {
        SimpleTimeParameterizationPtr_t ptr (new SimpleTimeParameterization(problem));
        return ptr;
      }

      PathVectorPtr_t SimpleTimeParameterization::optimize (const PathVectorPtr_t& path)
      {
        if (path->length() == 0) {
          return path;
        }
        const value_type infinity = std::numeric_limits<value_type>::infinity();

        const value_type safety = problem().getParameter("SimpleTimeParameterization/safety").floatValue();
        const size_type order = problem().getParameter("SimpleTimeParameterization/order").intValue();
        const value_type maxAcc = problem().getParameter("SimpleTimeParameterization/maxAcceleration").floatValue();
        if (order <= 1 && maxAcc > 0) {
          throw std::invalid_argument ("Maximum acceleration cannot be set when order is <= to 1. Please set parameter SimpleTimeParameterization/maxAcceleration to a negative value.");
        }

        // Retrieve velocity limits
        const DevicePtr_t& robot = problem().robot();
        vector_t ub ( robot->model().velocityLimit),
                 lb (-robot->model().velocityLimit),
                 cb ((ub + lb) / 2);
        for (size_type i=0; i < cb.size(); ++i) {
          if (std::isnan (cb [i])) {
            HPP_THROW(std::runtime_error,
              "in SimpleTimeParameterization::optimize:\n"
              << "  the velocities of the input device should be bounded\n"
              << "  velocity bounds at rank " << i << " are [" << lb[i]
              << ", " << ub[i] << "].");
          }
        }
        assert (cb.size() + robot->extraConfigSpace().dimension()
            == robot->numberDof());

        // The velocity must be in [lb, ub]
        ub = cb + safety * (ub - cb);
        lb = cb + safety * (lb - cb);

        // When ub or lb are NaN, set them to infinity.
        ub = (ub.array() == ub.array()).select(ub,  infinity);
        lb = (lb.array() == lb.array()).select(lb, -infinity);

        hppDout (info, "Lower velocity bound :" << lb.transpose());
        hppDout (info, "Upper velocity bound :" << ub.transpose());

        if (   ( ub.array() <= 0 ).any()
            && ( lb.array() >= 0 ).any())
          throw std::invalid_argument ("The case where zero is not an admissible velocity is not implemented.");

        PathVectorPtr_t input = PathVector::create(
            path->outputSize(), path->outputDerivativeSize());
        PathVectorPtr_t output = PathVector::create(
            path->outputSize(), path->outputDerivativeSize());
        path->flatten(input);

        vector_t v (robot->numberDof());
        vector_t v_inv (robot->numberDof());
        for (std::size_t i = 0; i < input->numberPaths(); ++i) {
          PathPtr_t p = input->pathAtRank(i);
          interval_t paramRange = p->paramRange();
          p->timeParameterization (TimeParameterizationPtr_t(), paramRange);

          // Compute B
          p->velocityBound (v, paramRange.first, paramRange.second);
          v_inv = (v.array() == 0).select(infinity, v.cwiseInverse());
          const value_type B = std::min(
              ( ub.cwiseProduct(v_inv)).minCoeff(),
              (-lb.cwiseProduct(v_inv)).minCoeff());
          if (B <= 0 || B != B) {
            HPP_THROW(std::runtime_error,"Invalid parametrization derivative "
                "velocity bound: " << B);
          }

          // Compute the polynom and total time
          value_type T;
          TimeParameterizationPtr_t tp;
          switch (order) {
            case 0:
              tp = computeTimeParameterizationFirstOrder (paramRange.first, paramRange.second, B, T);
              break;
            case 1:
              tp = computeTimeParameterizationThirdOrder (paramRange.first, paramRange.second, B, T);
              break;
            case 2:
              tp = computeTimeParameterizationFifthOrder (paramRange.first, paramRange.second, B, maxAcc, T);
              break;
            default:
              throw std::invalid_argument ("Parameter SimpleTimeParameterization/order should be in { 0, 1, 2 }");
              break;
          }

          checkTimeParameterization (tp, order, paramRange, B, maxAcc, T);

          PathPtr_t pp = p->copy();
          pp->timeParameterization (tp, interval_t (0, T));

          output->appendPath (pp);
        }
        return output;
      }

      SimpleTimeParameterization::SimpleTimeParameterization (const Problem& problem):
        PathOptimizer(problem) {}

      // ----------- Declare parameters ------------------------------------- //

      HPP_START_PARAMETER_DECLARATION(SimpleTimeParameterization)
      Problem::declareParameter(ParameterDescription (Parameter::FLOAT,
            "SimpleTimeParameterization/safety",
            "A scaling factor for the joint bounds.",
            Parameter(1.)));
      Problem::declareParameter(ParameterDescription (Parameter::INT,
            "SimpleTimeParameterization/order",
            "The desired continuity order.",
            Parameter((size_type)0)));
      Problem::declareParameter(ParameterDescription (Parameter::FLOAT,
            "SimpleTimeParameterization/maxAcceleration",
            "The maximum acceleration for each degree of freedom. Not considered if negative.",
            Parameter((value_type)-1)));
      HPP_END_PARAMETER_DECLARATION(SimpleTimeParameterization)
    } // namespace pathOptimization
  } // namespace core
} // namespace hpp
<commit_msg>[SimpleTimeParameterization] Move check for NaNs in bounds.<commit_after>// Copyright (c) 2017, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of hpp-core.
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core. If not, see <http://www.gnu.org/licenses/>.

#include <hpp/core/path-optimization/simple-time-parameterization.hh>

#include <limits>

#include <pinocchio/multibody/model.hpp>

#include <hpp/pinocchio/configuration.hh>
#include <hpp/pinocchio/device.hh>
#include <hpp/pinocchio/liegroup.hh>
#include <hpp/core/interpolated-path.hh>
#include <hpp/core/path-vector.hh>
#include <hpp/core/problem.hh>
#include <hpp/core/straight-path.hh>
#include <hpp/core/time-parameterization/polynomial.hh>

namespace hpp {
  namespace core {
    namespace pathOptimization {
      using timeParameterization::Polynomial;
      using std::isfinite;

      namespace {
        TimeParameterizationPtr_t computeTimeParameterizationFirstOrder (
            const value_type& s0, const value_type& s1, const value_type& B,
            value_type& T)
        {
          vector_t a(2);
          T = (s1 - s0) / B;
          a[0] = s0;
          a[1] = B;
          hppDout (info, "Time parametrization returned " << a.transpose()
              << ", " << T);
          if (!isfinite(T) || !a.allFinite() || a.hasNaN()) {
            HPP_THROW(std::logic_error, "Invalid time parameterization "
                "coefficients: " << a.transpose());
          }
          return TimeParameterizationPtr_t (new Polynomial (a));
        }

        TimeParameterizationPtr_t computeTimeParameterizationThirdOrder (
            const value_type& s0, const value_type& s1, const value_type& B,
            value_type& T)
        {
          vector_t a(4);
          T = 3 * (s1 - s0) / (2 * B);
          a[0] = s0;
          a[1] = 0;
          a[2] = 3 * (s1 - s0) / (T * T);
          a[3] = - 2 * a[2] / (3 * T);
          hppDout (info, "Time parametrization returned " << a.transpose()
              << ", " << T);
          if (!isfinite(T) || !a.allFinite() || a.hasNaN()) {
            HPP_THROW(std::logic_error, "Invalid time parameterization "
                "coefficients: " << a.transpose());
          }
          return TimeParameterizationPtr_t (new Polynomial (a));
        }

        TimeParameterizationPtr_t computeTimeParameterizationFifthOrder (
            const value_type& s0, const value_type& s1, const value_type& B,
            const value_type& C, value_type& T)
        {
          vector_t a(6);
          if (C > 0) {
            T = std::max(
                15 * (s1 - s0) / (8 * B)                     , // Velocity limit
                sqrt((10./std::sqrt(3))) * sqrt((s1 - s0) / C) // Acceleration limit
                );
          } else {
            T = 15 * (s1 - s0) / (8 * B);
          }

          value_type Tpow = T*T*T;
          a[0] = s0;
          a[1] = 0;
          a[2] = 0;
          a[3] =  10 * (s1 - s0) / Tpow;
          Tpow *= T;
          a[4] = -15 * (s1 - s0) / Tpow;
          Tpow *= T;
          a[5] =   6 * (s1 - s0) / Tpow;
          hppDout (info, "Time parametrization returned " << a.transpose()
              << ", " << T);
          if (!isfinite(T) || !a.allFinite() || a.hasNaN()) {
            HPP_THROW(std::logic_error, "Invalid time parameterization "
                "coefficients: " << a.transpose());
          }
          return TimeParameterizationPtr_t (new Polynomial (a));
        }

        void checkTimeParameterization (const TimeParameterizationPtr_t tp,
            const size_type order, const interval_t sr, const value_type B, const value_type& C, const value_type T)
        {
          using std::fabs;
          const value_type thr = std::sqrt(Eigen::NumTraits<value_type>::dummy_precision());
          if (   fabs(tp->value(0) - sr.first) >= thr
              || fabs(tp->value(T) - sr.second) >= thr) {
            HPP_THROW(std::logic_error, "Interval of TimeParameterization result"
                " is not correct. Expected " << sr.first << ", " << sr.second <<
                ". Got " << tp->value(0) << ", " << tp->value(T));
          }
          if (order >= 1
              && (fabs(tp->derivative(0, 1)) > thr
              ||  fabs(tp->derivative(T, 1)) > thr
              ||  ((C <= 0) && fabs(tp->derivative(T/2, 1) - B) > thr))
             ) {
            HPP_THROW(std::logic_error,
                "Derivative of TimeParameterization are not correct:"
                << "\ntp->derivative(0, 1) = " << tp->derivative(0, 1)
                << "\ntp->derivative(T, 1) = " << tp->derivative(T, 1)
                << "\ntp->derivative(T/2, 1) - B = " << tp->derivative(T/2, 1) - B
                << "\nT = " << T
                << "\nB = " << B
                << "\nC = " << C
                );
          }
          if (order >= 2
              && (fabs(tp->derivative(0, 2)) > thr
              ||  fabs(tp->derivative(T, 2)) > thr)
             ) {
            HPP_THROW(std::logic_error,
                "Derivative of TimeParameterization are not correct:"
                << "\ntp->derivative(0, 2) = " << tp->derivative(0, 2)
                << "\ntp->derivative(T, 2) = " << tp->derivative(T, 2)
                << "\nT = " << T
                );
          }
        }
      }

      SimpleTimeParameterizationPtr_t SimpleTimeParameterization::create (const Problem& problem)
      {
        SimpleTimeParameterizationPtr_t ptr (new SimpleTimeParameterization(problem));
        return ptr;
      }

      PathVectorPtr_t SimpleTimeParameterization::optimize (const PathVectorPtr_t& path)
      {
        if (path->length() == 0) {
          return path;
        }
        const value_type infinity = std::numeric_limits<value_type>::infinity();

        const value_type safety = problem().getParameter("SimpleTimeParameterization/safety").floatValue();
        const size_type order = problem().getParameter("SimpleTimeParameterization/order").intValue();
        const value_type maxAcc = problem().getParameter("SimpleTimeParameterization/maxAcceleration").floatValue();
        if (order <= 1 && maxAcc > 0) {
          throw std::invalid_argument ("Maximum acceleration cannot be set when order is <= to 1. Please set parameter SimpleTimeParameterization/maxAcceleration to a negative value.");
        }

        // Retrieve velocity limits
        const DevicePtr_t& robot = problem().robot();
        vector_t ub ( robot->model().velocityLimit),
                 lb (-robot->model().velocityLimit),
                 cb ((ub + lb) / 2);
        assert (cb.size() + robot->extraConfigSpace().dimension()
            == robot->numberDof());

        // The velocity must be in [lb, ub]
        ub = cb + safety * (ub - cb);
        lb = cb + safety * (lb - cb);

        // When ub or lb are NaN, set them to infinity.
        ub = (ub.array() == ub.array()).select(ub,  infinity);
        lb = (lb.array() == lb.array()).select(lb, -infinity);

        for (size_type i=0; i < cb.size(); ++i) {
          if (std::isnan (lb [i]) || std::isnan (ub [i])) {
            HPP_THROW(std::runtime_error,
              "in SimpleTimeParameterization::optimize:\n"
              << "  the velocities of the input device should be bounded\n"
              << "  velocity bounds at rank " << i << " are [" << lb[i]
              << ", " << ub[i] << "].");
          }
        }

        hppDout (info, "Lower velocity bound :" << lb.transpose());
        hppDout (info, "Upper velocity bound :" << ub.transpose());

        if (   ( ub.array() <= 0 ).any()
            && ( lb.array() >= 0 ).any())
          throw std::invalid_argument ("The case where zero is not an admissible velocity is not implemented.");

        PathVectorPtr_t input = PathVector::create(
            path->outputSize(), path->outputDerivativeSize());
        PathVectorPtr_t output = PathVector::create(
            path->outputSize(), path->outputDerivativeSize());
        path->flatten(input);

        vector_t v (robot->numberDof());
        vector_t v_inv (robot->numberDof());
        for (std::size_t i = 0; i < input->numberPaths(); ++i) {
          PathPtr_t p = input->pathAtRank(i);
          interval_t paramRange = p->paramRange();
          p->timeParameterization (TimeParameterizationPtr_t(), paramRange);

          // Compute B
          p->velocityBound (v, paramRange.first, paramRange.second);
          v_inv = (v.array() == 0).select(infinity, v.cwiseInverse());
          const value_type B = std::min(
              ( ub.cwiseProduct(v_inv)).minCoeff(),
              (-lb.cwiseProduct(v_inv)).minCoeff());
          if (B <= 0 || B != B || !isfinite(B)) {
            HPP_THROW(std::runtime_error,"Invalid parametrization derivative "
                "velocity bound: " << B);
          }

          // Compute the polynom and total time
          value_type T;
          TimeParameterizationPtr_t tp;
          switch (order) {
            case 0:
              tp = computeTimeParameterizationFirstOrder (paramRange.first, paramRange.second, B, T);
              break;
            case 1:
              tp = computeTimeParameterizationThirdOrder (paramRange.first, paramRange.second, B, T);
              break;
            case 2:
              tp = computeTimeParameterizationFifthOrder (paramRange.first, paramRange.second, B, maxAcc, T);
              break;
            default:
              throw std::invalid_argument ("Parameter SimpleTimeParameterization/order should be in { 0, 1, 2 }");
              break;
          }

          checkTimeParameterization (tp, order, paramRange, B, maxAcc, T);

          PathPtr_t pp = p->copy();
          pp->timeParameterization (tp, interval_t (0, T));

          output->appendPath (pp);
        }
        return output;
      }

      SimpleTimeParameterization::SimpleTimeParameterization (const Problem& problem):
        PathOptimizer(problem) {}

      // ----------- Declare parameters ------------------------------------- //

      HPP_START_PARAMETER_DECLARATION(SimpleTimeParameterization)
      Problem::declareParameter(ParameterDescription (Parameter::FLOAT,
            "SimpleTimeParameterization/safety",
            "A scaling factor for the joint bounds.",
            Parameter(1.)));
      Problem::declareParameter(ParameterDescription (Parameter::INT,
            "SimpleTimeParameterization/order",
            "The desired continuity order.",
            Parameter((size_type)0)));
      Problem::declareParameter(ParameterDescription (Parameter::FLOAT,
            "SimpleTimeParameterization/maxAcceleration",
            "The maximum acceleration for each degree of freedom. Not considered if negative.",
            Parameter((value_type)-1)));
      HPP_END_PARAMETER_DECLARATION(SimpleTimeParameterization)
    } // namespace pathOptimization
  } // namespace core
} // namespace hpp
<|endoftext|>


<commit_before>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofTrueTypeFont::setGlobalDpi(72);
    ofSetBackgroundColor(0, 0, 0);
    verdana14.load("verdana.ttf", 14, true, true);
    verdana14.setLineHeight(18.0f);
    verdana14.setLetterSpacing(1.037);

    // A simple DOL System, as describe at the beginning of the book
    vector<string> expectedSimpleDOL{
        "B",
        "A",
        "AB",
        "ABA",
        "ABAAB",
        "ABAABABA",
    };
    auto SimpleDOL = RuleTest(
                                            "A simple DOL System",
                                            "B",
                                            vector<string> {"A->AB", "B->A"},
                                            5,
                                            expectedSimpleDOL
                                            );
    SimpleDOL.executeTest();
    tests.push_back(SimpleDOL);

    // Bracketed edge rewriting system, second example page 25
    vector<string> expectedBracketedEdge{
        "F",
        "F[+F]F[-F][F]",
        "F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]]",
        "F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]][+F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]]]F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]][-F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]]][F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]]]"
    };
    auto bracketedEdge = RuleTest(
                              "A bracketed edge rewriting system",
                              "F",
                              vector<string> {"F->F[+F]F[-F][F]"},
                              3,
                              expectedBracketedEdge
                              );
    bracketedEdge.executeTest();
    tests.push_back(bracketedEdge);

    // parametric test rule with constants
    vector<string> expectedParametricWithConstantsResult{
        "A(12)",
        "F(12)[+A(6)][-A(6)]",
        "F(12)[+F(6)[+A(3)][-A(3)]][-F(6)[+A(3)][-A(3)]]"
    };
    map<string, float> constants;
    constants.insert(make_pair("R", 2.0));
    auto parametricWithConstants = RuleTest(
                                   "Parametric Grammar test with Constants",
                                   "A(12)",
                                   vector<string> {"A(s)->F(s)[+A(s/R)][-A(s/R)]"},
                                   2,
                                   expectedParametricWithConstantsResult,
                                   constants
                                   );
    parametricWithConstants.executeTest();
    tests.push_back(parametricWithConstants);

    //parametric test. Rules also in page 43 of "The Algorithmic Beauty of Plants"
    vector<string> parametricRules;
    parametricRules.push_back("A(x,y): y<=3 -> A(x*2,x+y)");
    parametricRules.push_back("A(x,y): y>3 -> B(x)A(x/y,0)");
    parametricRules.push_back("B(x) :x<1 -> C");
    parametricRules.push_back("B(x) : x>=1 -> B(x-1)");
    vector<string> expectedParametricResult {
        "B(2)A(4,4)",
        "B(1)B(4)A(1,0)",
        "B(0)B(3)A(2,1)",
        "CB(2)A(4,3)"
    };
    auto parametricTest = RuleTest("Parametric Grammar test",
                                   "B(2)A(4,4)",
                                   parametricRules,
                                   3,
                                   expectedParametricResult
                                   );
    parametricTest.executeTest();
    tests.push_back(parametricTest);
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
    int x = 20;
    int y = 20;
    for(auto test : tests){
        string text;
        if(test.isPassed()){
            ofSetColor(0,255,0);
            text = test.getTitle() += ": OK";
        }else{
            ofSetColor(255,0,0);
            text = test.getTitle() += ": ERROR, expected:\n";
            for(auto r :test.getExpectedResult()){
                text+= r + "\n";
            }
            text += "\ngot: \n";
            for(auto r :test.getResult()){
                cout << r + "\n\n"<< endl;
                text+= r + "\n";
            }
        }
        ofRectangle bounds = verdana14.getStringBoundingBox(text, 100, y);
        auto passed = test.isPassed() ? "OK" : "ERROR";
        verdana14.drawString(text , x, y );
        y += bounds.height+5;
    }
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<commit_msg>remove debug from draw method<commit_after>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofTrueTypeFont::setGlobalDpi(72);
    ofSetBackgroundColor(0, 0, 0);
    verdana14.load("verdana.ttf", 14, true, true);
    verdana14.setLineHeight(18.0f);
    verdana14.setLetterSpacing(1.037);

    // A simple DOL System, as describe at the beginning of the book
    vector<string> expectedSimpleDOL{
        "B",
        "A",
        "AB",
        "ABA",
        "ABAAB",
        "ABAABABA",
    };
    auto SimpleDOL = RuleTest(
                                            "A simple DOL System",
                                            "B",
                                            vector<string> {"A->AB", "B->A"},
                                            5,
                                            expectedSimpleDOL
                                            );
    SimpleDOL.executeTest();
    tests.push_back(SimpleDOL);

    // Bracketed edge rewriting system, second example page 25
    vector<string> expectedBracketedEdge{
        "F",
        "F[+F]F[-F][F]",
        "F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]]",
        "F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]][+F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]]]F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]][-F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]]][F[+F]F[-F][F][+F[+F]F[-F][F]]F[+F]F[-F][F][-F[+F]F[-F][F]][F[+F]F[-F][F]]]"
    };
    auto bracketedEdge = RuleTest(
                              "A bracketed edge rewriting system",
                              "F",
                              vector<string> {"F->F[+F]F[-F][F]"},
                              3,
                              expectedBracketedEdge
                              );
    bracketedEdge.executeTest();
    tests.push_back(bracketedEdge);

    // parametric test rule with constants
    vector<string> expectedParametricWithConstantsResult{
        "A(12)",
        "F(12)[+A(6)][-A(6)]",
        "F(12)[+F(6)[+A(3)][-A(3)]][-F(6)[+A(3)][-A(3)]]"
    };
    map<string, float> constants;
    constants.insert(make_pair("R", 2.0));
    auto parametricWithConstants = RuleTest(
                                   "Parametric Grammar test with Constants",
                                   "A(12)",
                                   vector<string> {"A(s)->F(s)[+A(s/R)][-A(s/R)]"},
                                   2,
                                   expectedParametricWithConstantsResult,
                                   constants
                                   );
    parametricWithConstants.executeTest();
    tests.push_back(parametricWithConstants);

    //parametric test. Rules also in page 43 of "The Algorithmic Beauty of Plants"
    vector<string> parametricRules;
    parametricRules.push_back("A(x,y): y<=3 -> A(x*2,x+y)");
    parametricRules.push_back("A(x,y): y>3 -> B(x)A(x/y,0)");
    parametricRules.push_back("B(x) :x<1 -> C");
    parametricRules.push_back("B(x) : x>=1 -> B(x-1)");
    vector<string> expectedParametricResult {
        "B(2)A(4,4)",
        "B(1)B(4)A(1,0)",
        "B(0)B(3)A(2,1)",
        "CB(2)A(4,3)"
    };
    auto parametricTest = RuleTest("Parametric Grammar test",
                                   "B(2)A(4,4)",
                                   parametricRules,
                                   3,
                                   expectedParametricResult
                                   );
    parametricTest.executeTest();
    tests.push_back(parametricTest);
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
    int x = 20;
    int y = 20;
    for(auto test : tests){
        string text;
        if(test.isPassed()){
            ofSetColor(0,255,0);
            text = test.getTitle() += ": OK";
        }else{
            ofSetColor(255,0,0);
            text = test.getTitle() += ": ERROR, expected:\n";
            for(auto r :test.getExpectedResult()){
                text+= r + "\n";
            }
            text += "\ngot: \n";
            for(auto r :test.getResult()){
                //cout << r + "\n\n"<< endl;
                text+= r + "\n";
            }
        }
        ofRectangle bounds = verdana14.getStringBoundingBox(text, 100, y);
        auto passed = test.isPassed() ? "OK" : "ERROR";
        verdana14.drawString(text , x, y );
        y += bounds.height+5;
    }
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "quickopenplugin.h"
#include "quickopenconstants.h"
#include "quickopenfiltersfilter.h"
#include "quickopenmanager.h"
#include "quickopentoolwindow.h"
#include "opendocumentsfilter.h"
#include "filesystemfilter.h"
#include "directoryfilter.h"
#include "settingspage.h"

#include <QtCore/QSettings>
#include <QtCore/QtPlugin>
#include <QtCore/QFuture>
#include <QtCore/QFutureWatcher>

#include <coreplugin/baseview.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/settingsdatabase.h>
#include <coreplugin/icore.h>
#include <coreplugin/uniqueidmanager.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <qtconcurrent/QtConcurrentTools>

/*!
    \namespace QuickOpen
    The QuickOpen namespace provides the hooks for Locator content.
*/
/*!
    \namespace QuickOpen::Internal
    \internal
*/

using namespace QuickOpen;
using namespace QuickOpen::Internal;

namespace {
    static bool filterLessThan(const IQuickOpenFilter *first, const IQuickOpenFilter *second)
    {
        return first->priority() < second->priority();
    }
}

QuickOpenPlugin::QuickOpenPlugin()
{
    m_refreshTimer.setSingleShot(false);
    connect(&m_refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
}

QuickOpenPlugin::~QuickOpenPlugin()
{
    removeObject(m_openDocumentsFilter);
    removeObject(m_fileSystemFilter);
    removeObject(m_settingsPage);
    delete m_openDocumentsFilter;
    delete m_fileSystemFilter;
    delete m_settingsPage;
    qDeleteAll(m_customFilters);
}

bool QuickOpenPlugin::initialize(const QStringList &, QString *)
{
    Core::ICore *core = Core::ICore::instance();
    m_settingsPage = new SettingsPage(this);
    addObject(m_settingsPage);

    m_quickOpenToolWindow = new QuickOpenToolWindow(this);
    m_quickOpenToolWindow->setEnabled(false);
    Core::BaseView *view = new Core::BaseView;
    view->setUniqueViewName("QuickOpen");
    view->setWidget(m_quickOpenToolWindow);
    view->setContext(QList<int>() << core->uniqueIDManager()
        ->uniqueIdentifier(QLatin1String("QuickOpenToolWindow")));
    view->setDefaultPosition(Core::IView::First);
    addAutoReleasedObject(view);

    const QString actionId = QLatin1String("QtCreator.QuickOpen");
    QAction *action = new QAction(m_quickOpenToolWindow->windowIcon(), m_quickOpenToolWindow->windowTitle(), this);
    Core::Command *cmd = core->actionManager()->registerAction(action, actionId, QList<int>() << Core::Constants::C_GLOBAL_ID);
    cmd->setDefaultKeySequence(QKeySequence("Ctrl+K"));
    connect(action, SIGNAL(triggered()), this, SLOT(openQuickOpen()));

    Core::ActionContainer *mtools = core->actionManager()->actionContainer(Core::Constants::M_TOOLS);
    mtools->addAction(cmd);

    addObject(new QuickOpenManager(m_quickOpenToolWindow));

    m_openDocumentsFilter = new OpenDocumentsFilter(core->editorManager());
    addObject(m_openDocumentsFilter);

    m_fileSystemFilter = new FileSystemFilter(core->editorManager(), m_quickOpenToolWindow);
    addObject(m_fileSystemFilter);

    addAutoReleasedObject(new QuickOpenFiltersFilter(this, m_quickOpenToolWindow));

    connect(core, SIGNAL(coreOpened()), this, SLOT(startSettingsLoad()));
    return true;
}

void QuickOpenPlugin::openQuickOpen()
{
    m_quickOpenToolWindow->setFocus();
}

void QuickOpenPlugin::extensionsInitialized()
{
    m_filters = ExtensionSystem::PluginManager::instance()->getObjects<IQuickOpenFilter>();
    qSort(m_filters.begin(), m_filters.end(), filterLessThan);
}

void QuickOpenPlugin::startSettingsLoad()
{
    m_loadWatcher.setFuture(QtConcurrent::run(this, &QuickOpenPlugin::loadSettings));
    connect(&m_loadWatcher, SIGNAL(finished()), this, SLOT(settingsLoaded()));
}

namespace QuickOpen {
namespace Internal {

template <typename S>
static void loadSettingsHelper(QuickOpenPlugin *p, S *settings)
{
    settings->beginGroup("QuickOpen");
    p->m_refreshTimer.setInterval(settings->value("RefreshInterval", 60).toInt() * 60000);

    foreach (IQuickOpenFilter *filter, p->m_filters) {
        if (settings->contains(filter->name())) {
            const QByteArray state = settings->value(filter->name()).toByteArray();
            if (!state.isEmpty())
                filter->restoreState(state);
        }
    }
    settings->beginGroup("CustomFilters");
    QList<IQuickOpenFilter *> customFilters;
    foreach (const QString &key, settings->childKeys()) {
        IQuickOpenFilter *filter = new DirectoryFilter;
        filter->restoreState(settings->value(key).toByteArray());
        p->m_filters.append(filter);
        customFilters.append(filter);
    }
    p->setCustomFilters(customFilters);
    settings->endGroup();
    settings->endGroup();
}

} // namespace Internal
} // namespace QuickOpen

void QuickOpenPlugin::loadSettings()
{
    Core::ICore *core = Core::ICore::instance();
    QSettings *qs = core->settings();

    // Backwards compatibility to old settings location
    if (qs->contains("QuickOpen/FiltersFilter")) {
        loadSettingsHelper(this, qs);
    } else {
        Core::SettingsDatabase *settings = core->settingsDatabase();
        loadSettingsHelper(this, settings);
    }

    qs->remove("QuickOpen");
}

void QuickOpenPlugin::settingsLoaded()
{
    m_quickOpenToolWindow->updateFilterList();
    m_quickOpenToolWindow->setEnabled(true);
    if (m_refreshTimer.interval() > 0)
        m_refreshTimer.start();
}

void QuickOpenPlugin::saveSettings()
{
    Core::ICore *core = Core::ICore::instance();
    if (core && core->settingsDatabase()) {
        Core::SettingsDatabase *s = core->settingsDatabase();
        s->beginGroup("QuickOpen");
        s->remove("");
        s->setValue("RefreshInterval", refreshInterval());
        foreach (IQuickOpenFilter *filter, m_filters) {
            if (!m_customFilters.contains(filter))
                s->setValue(filter->name(), filter->saveState());
        }
        s->beginGroup("CustomFilters");
        int i = 0;
        foreach (IQuickOpenFilter *filter, m_customFilters) {
            s->setValue(QString("directory%1").arg(i), filter->saveState());
            ++i;
        }
        s->endGroup();
        s->endGroup();
    }
}

/*!
    \fn QList<IQuickOpenFilter*> QuickOpenPlugin::filter()

    Return all filters, including the ones created by the user.
*/
QList<IQuickOpenFilter*> QuickOpenPlugin::filters()
{
    return m_filters;
}

/*!
    \fn QList<IQuickOpenFilter*> QuickOpenPlugin::customFilter()

    This returns a subset of all the filters, that contains only the filters that
    have been created by the user at some point (maybe in a previous session).
 */
QList<IQuickOpenFilter*> QuickOpenPlugin::customFilters()
{
    return m_customFilters;
}

void QuickOpenPlugin::setFilters(QList<IQuickOpenFilter*> f)
{
    m_filters = f;
    m_quickOpenToolWindow->updateFilterList();
}

void QuickOpenPlugin::setCustomFilters(QList<IQuickOpenFilter *> filters)
{
    m_customFilters = filters;
}

int QuickOpenPlugin::refreshInterval()
{
    return m_refreshTimer.interval() / 60000;
}

void QuickOpenPlugin::setRefreshInterval(int interval)
{
    if (interval < 1) {
        m_refreshTimer.stop();
        m_refreshTimer.setInterval(0);
        return;
    }
    m_refreshTimer.setInterval(interval * 60000);
    m_refreshTimer.start();
}

void QuickOpenPlugin::refresh(QList<IQuickOpenFilter*> filters)
{
    if (filters.isEmpty())
        filters = m_filters;
    QFuture<void> task = QtConcurrent::run(&IQuickOpenFilter::refresh, filters);
    Core::FutureProgress *progress = Core::ICore::instance()
            ->progressManager()->addTask(task, tr("Indexing"),
                                         QuickOpen::Constants::TASK_INDEX,
                                         Core::ProgressManager::CloseOnSuccess);
    connect(progress, SIGNAL(finished()), this, SLOT(saveSettings()));
}

Q_EXPORT_PLUGIN(QuickOpenPlugin)
<commit_msg>Fixed compile error with gcc 3.3<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "quickopenplugin.h"
#include "quickopenconstants.h"
#include "quickopenfiltersfilter.h"
#include "quickopenmanager.h"
#include "quickopentoolwindow.h"
#include "opendocumentsfilter.h"
#include "filesystemfilter.h"
#include "directoryfilter.h"
#include "settingspage.h"

#include <QtCore/QSettings>
#include <QtCore/QtPlugin>
#include <QtCore/QFuture>
#include <QtCore/QFutureWatcher>

#include <coreplugin/baseview.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/settingsdatabase.h>
#include <coreplugin/icore.h>
#include <coreplugin/uniqueidmanager.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <qtconcurrent/QtConcurrentTools>

/*!
    \namespace QuickOpen
    The QuickOpen namespace provides the hooks for Locator content.
*/
/*!
    \namespace QuickOpen::Internal
    \internal
*/

using namespace QuickOpen;
using namespace QuickOpen::Internal;

namespace {
    static bool filterLessThan(const IQuickOpenFilter *first, const IQuickOpenFilter *second)
    {
        return first->priority() < second->priority();
    }
}

QuickOpenPlugin::QuickOpenPlugin()
{
    m_refreshTimer.setSingleShot(false);
    connect(&m_refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
}

QuickOpenPlugin::~QuickOpenPlugin()
{
    removeObject(m_openDocumentsFilter);
    removeObject(m_fileSystemFilter);
    removeObject(m_settingsPage);
    delete m_openDocumentsFilter;
    delete m_fileSystemFilter;
    delete m_settingsPage;
    qDeleteAll(m_customFilters);
}

bool QuickOpenPlugin::initialize(const QStringList &, QString *)
{
    Core::ICore *core = Core::ICore::instance();
    m_settingsPage = new SettingsPage(this);
    addObject(m_settingsPage);

    m_quickOpenToolWindow = new QuickOpenToolWindow(this);
    m_quickOpenToolWindow->setEnabled(false);
    Core::BaseView *view = new Core::BaseView;
    view->setUniqueViewName("QuickOpen");
    view->setWidget(m_quickOpenToolWindow);
    view->setContext(QList<int>() << core->uniqueIDManager()
        ->uniqueIdentifier(QLatin1String("QuickOpenToolWindow")));
    view->setDefaultPosition(Core::IView::First);
    addAutoReleasedObject(view);

    const QString actionId = QLatin1String("QtCreator.QuickOpen");
    QAction *action = new QAction(m_quickOpenToolWindow->windowIcon(), m_quickOpenToolWindow->windowTitle(), this);
    Core::Command *cmd = core->actionManager()->registerAction(action, actionId, QList<int>() << Core::Constants::C_GLOBAL_ID);
    cmd->setDefaultKeySequence(QKeySequence("Ctrl+K"));
    connect(action, SIGNAL(triggered()), this, SLOT(openQuickOpen()));

    Core::ActionContainer *mtools = core->actionManager()->actionContainer(Core::Constants::M_TOOLS);
    mtools->addAction(cmd);

    addObject(new QuickOpenManager(m_quickOpenToolWindow));

    m_openDocumentsFilter = new OpenDocumentsFilter(core->editorManager());
    addObject(m_openDocumentsFilter);

    m_fileSystemFilter = new FileSystemFilter(core->editorManager(), m_quickOpenToolWindow);
    addObject(m_fileSystemFilter);

    addAutoReleasedObject(new QuickOpenFiltersFilter(this, m_quickOpenToolWindow));

    connect(core, SIGNAL(coreOpened()), this, SLOT(startSettingsLoad()));
    return true;
}

void QuickOpenPlugin::openQuickOpen()
{
    m_quickOpenToolWindow->setFocus();
}

void QuickOpenPlugin::extensionsInitialized()
{
    m_filters = ExtensionSystem::PluginManager::instance()->getObjects<IQuickOpenFilter>();
    qSort(m_filters.begin(), m_filters.end(), filterLessThan);
}

void QuickOpenPlugin::startSettingsLoad()
{
    m_loadWatcher.setFuture(QtConcurrent::run(this, &QuickOpenPlugin::loadSettings));
    connect(&m_loadWatcher, SIGNAL(finished()), this, SLOT(settingsLoaded()));
}

namespace QuickOpen {
namespace Internal {

template <typename S>
static void loadSettingsHelper(QuickOpenPlugin *p, S *settings)
{
    settings->beginGroup("QuickOpen");
    p->m_refreshTimer.setInterval(settings->value("RefreshInterval", 60).toInt() * 60000);

    foreach (IQuickOpenFilter *filter, p->m_filters) {
        if (settings->contains(filter->name())) {
            const QByteArray state = settings->value(filter->name()).toByteArray();
            if (!state.isEmpty())
                filter->restoreState(state);
        }
    }
    settings->beginGroup("CustomFilters");
    QList<IQuickOpenFilter *> customFilters;
    const QStringList keys = settings->childKeys();
    foreach (const QString &key, keys) {
        IQuickOpenFilter *filter = new DirectoryFilter;
        filter->restoreState(settings->value(key).toByteArray());
        p->m_filters.append(filter);
        customFilters.append(filter);
    }
    p->setCustomFilters(customFilters);
    settings->endGroup();
    settings->endGroup();
}

} // namespace Internal
} // namespace QuickOpen

void QuickOpenPlugin::loadSettings()
{
    Core::ICore *core = Core::ICore::instance();
    QSettings *qs = core->settings();

    // Backwards compatibility to old settings location
    if (qs->contains("QuickOpen/FiltersFilter")) {
        loadSettingsHelper(this, qs);
    } else {
        Core::SettingsDatabase *settings = core->settingsDatabase();
        loadSettingsHelper(this, settings);
    }

    qs->remove("QuickOpen");
}

void QuickOpenPlugin::settingsLoaded()
{
    m_quickOpenToolWindow->updateFilterList();
    m_quickOpenToolWindow->setEnabled(true);
    if (m_refreshTimer.interval() > 0)
        m_refreshTimer.start();
}

void QuickOpenPlugin::saveSettings()
{
    Core::ICore *core = Core::ICore::instance();
    if (core && core->settingsDatabase()) {
        Core::SettingsDatabase *s = core->settingsDatabase();
        s->beginGroup("QuickOpen");
        s->remove("");
        s->setValue("RefreshInterval", refreshInterval());
        foreach (IQuickOpenFilter *filter, m_filters) {
            if (!m_customFilters.contains(filter))
                s->setValue(filter->name(), filter->saveState());
        }
        s->beginGroup("CustomFilters");
        int i = 0;
        foreach (IQuickOpenFilter *filter, m_customFilters) {
            s->setValue(QString("directory%1").arg(i), filter->saveState());
            ++i;
        }
        s->endGroup();
        s->endGroup();
    }
}

/*!
    \fn QList<IQuickOpenFilter*> QuickOpenPlugin::filter()

    Return all filters, including the ones created by the user.
*/
QList<IQuickOpenFilter*> QuickOpenPlugin::filters()
{
    return m_filters;
}

/*!
    \fn QList<IQuickOpenFilter*> QuickOpenPlugin::customFilter()

    This returns a subset of all the filters, that contains only the filters that
    have been created by the user at some point (maybe in a previous session).
 */
QList<IQuickOpenFilter*> QuickOpenPlugin::customFilters()
{
    return m_customFilters;
}

void QuickOpenPlugin::setFilters(QList<IQuickOpenFilter*> f)
{
    m_filters = f;
    m_quickOpenToolWindow->updateFilterList();
}

void QuickOpenPlugin::setCustomFilters(QList<IQuickOpenFilter *> filters)
{
    m_customFilters = filters;
}

int QuickOpenPlugin::refreshInterval()
{
    return m_refreshTimer.interval() / 60000;
}

void QuickOpenPlugin::setRefreshInterval(int interval)
{
    if (interval < 1) {
        m_refreshTimer.stop();
        m_refreshTimer.setInterval(0);
        return;
    }
    m_refreshTimer.setInterval(interval * 60000);
    m_refreshTimer.start();
}

void QuickOpenPlugin::refresh(QList<IQuickOpenFilter*> filters)
{
    if (filters.isEmpty())
        filters = m_filters;
    QFuture<void> task = QtConcurrent::run(&IQuickOpenFilter::refresh, filters);
    Core::FutureProgress *progress = Core::ICore::instance()
            ->progressManager()->addTask(task, tr("Indexing"),
                                         QuickOpen::Constants::TASK_INDEX,
                                         Core::ProgressManager::CloseOnSuccess);
    connect(progress, SIGNAL(finished()), this, SLOT(saveSettings()));
}

Q_EXPORT_PLUGIN(QuickOpenPlugin)
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
using namespace std;

const int DEPTH = 5;
const int TIMES = 10000;

struct point {
  int x, y;
  point(int tx, int ty) {
    x = tx;
    y = ty;
  }
  bool operator==(const point& right) const {
    return x == right.x && y == right.y;
  }
};

struct pass {
  vector<point> V;
  int reduce;
  int turn;
  pass(vector<point> tV, int treduce, int tturn) {
    V = tV;
    reduce = treduce;
    turn = tturn;
  }
  bool operator<(const pass& right) const {
    return ((reduce - turn)/(int)V.size() )
      < ((right.reduce - right.turn)/(int)right.V.size() );
  }
};

const int infty = 1000000;
random_device rd;
mt19937 mt(rd());
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};

int A[30][30];
int A_sum = 0;
int red_sum = 0;
vector<point> result;

vector<point> P;
int T[1000];
int G[1000];
int reduce;
int turn;
bool actual = false;

int count_sub(int l, int r) {
  // cerr << "l = " << l << ", r = " << r << endl;
  int mini = infty;
  for (auto i = l; i < r; i++) {
    mini = min(mini, T[i]-G[i]);
  }
  for (auto i = l; i < r; i++) {
    G[i] += mini;
  }
  int ans = mini;
  bool temp[1000];
  temp[0] = false;
  for (auto i = l; i < r; i++) {
    temp[i-l+1] = (T[i] > G[i]);
  }
  temp[r-l+1] = false;
  bool now = false;
  int left, right;
  for (auto i = 0; i < r-l+2; i++) {
    if (!now && !temp[i]) {
      continue;
    } else if (!now && temp[i]) {
      now = true;
      left = l+i-1;
    } else if (now && temp[i]) {
      continue;
    } else {
      now = false;
      right = l+i-1;
      ans += count_sub(left, right);
    }
  }
  // cerr << "ans = " << ans << endl;
  if (actual) {
    for (auto i = 0; i < mini; i++) {
      for (auto j = l; j < r; j++) {
        result.push_back(P[j]);
        A[P[j].x][P[j].y]--;
        red_sum++;
      }
    }
  }
  return ans;
}

bool count(int r) {
  for (auto i = 0; i < r; i++) {
    G[i] = r-1-i;
  }
  reduce = 0;
  for (auto i = 0; i < r; i++) {
    if (T[i] - G[i] < 0) return false;
    reduce += T[i] - G[i];
  }
  turn = count_sub(0, r);
  return true;
}

void count_test() {
  int M;
  cin >> M;
  for (auto i = 0; i < M; i++) {
    cin >> T[i];
  }
  if (count(M)) {
    cerr << "reduce = " << reduce << ", turn = " << turn << endl;
  } else {
    cerr << "failed" << endl;
  }
}

vector<pass> Passes[30][30];
bool visited[30][30];

bool valid(int i, int j) {
  return 0 <= i && i < 30 && 0 <= j && j < 30 && !visited[i][j];
}

void make_pass(int i, int j) {
  int M = mt()%DEPTH+1;
  int now_i = i;
  int now_j = j;
  vector<point> V;
  V.push_back(point(now_i, now_j));
  for (auto k = 0; k < M-1; k++) {
    int r = mt()%4;
    now_i += dx[r];
    now_j += dy[r];
    if (!valid(now_i, now_j)) return;
    point tp = point(now_i, now_j);
    for (auto x : V) {
      if (tp == x) {
        return;
      }
    }
    V.push_back(tp);
  }
  for (auto i = 0; i < M; i++) {
    T[i] = A[V[i].x][V[i].y];
  }
  if (count(M)) {
    Passes[i][j].push_back(pass(V, reduce, turn));
  }
}

void input() {
  for (auto i = 0; i < 30; i++) {
    for (auto j = 0; j < 30; j++) {
      cin >> A[i][j];
      A_sum += A[i][j];
    }
  }
}

void output() {
  for (auto p : result) {
    cout << p.x+1 << " " << p.y+1 << endl;
  }
}

void solve() {
  while (A_sum > red_sum) {
    int maxi = 0;
    int max_i, max_j;
    for (auto i = 0; i < 30; i++) {
      for (auto j = 0; j < 30; j++) {
        if (A[i][j] > maxi) {
          maxi = A[i][j];
          max_i = i;
          max_j = j;
        }
        visited[i][j] = (A[i][j] == 0);
        Passes[i][j].clear();
      }
    }
    vector<point> X;
    int now_i = max_i;
    int now_j = max_j;
    while (true) {
      for (auto i = 0; i < TIMES; i++) {
        make_pass(now_i, now_j);
      }
      pass maxi = *(Passes[now_i][now_j].begin());
      for (auto temp : Passes[now_i][now_j]) {
        maxi = max(temp, maxi);
      }
      if ((int)maxi.V.size() == 1) {
        if (X.empty()) {
          X = maxi.V;
        }
        break;
      }
      vector<point> tX;
      tX = X;
      auto it = maxi.V.begin();
      if (!tX.empty()) {
        it++;
      }
      for (; it != maxi.V.end(); it++) {
        tX.push_back(*it);
        visited[(*it).x][(*it).y] = true;
      }
      for (auto i = 0; i < (int)tX.size(); i++) {
        T[i] = A[tX[i].x][tX[i].y];
      }
      if (count((int)tX.size())) {
        X = tX;
        it = maxi.V.end()-1;
        now_i = (*it).x;
        now_j = (*it).y;
      } else {
        break;
      }
    }
    actual = true;
    P = X;
    /*
    cerr << "red_sum = " << red_sum << endl;
    for (auto temp : P) {
      cerr << "(" << temp.x << ", " << temp.y << ") ";
    }
    cerr << endl;
    */
    for (auto i = 0; i < (int)P.size(); i++) {
      T[i] = A[P[i].x][P[i].y];
    }
    count((int)P.size());
    actual = false;
  }
}

int main() {
  input();
  solve();
  output();
}
<commit_msg>final submit<commit_after>#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <cmath>
using namespace std;

const int DEPTH = 4;
const int TIMES = 10000;

struct point {
  int x, y;
  point(int tx, int ty) {
    x = tx;
    y = ty;
  }
  bool operator==(const point& right) const {
    return x == right.x && y == right.y;
  }
};

struct pass {
  vector<point> V;
  int reduce;
  int turn;
  double hikaku;
  pass(vector<point> tV, int treduce, int tturn) {
    V = tV;
    reduce = treduce;
    turn = tturn;
    hikaku = (reduce - turn)/sqrt((int)V.size());
  }
  bool operator<(const pass& right) const {
    return hikaku < right.hikaku;
  }
};

const int infty = 1000000;
random_device rd;
mt19937 mt(rd());
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};

int A[30][30];
int A_sum = 0;
int red_sum = 0;
vector<point> result;

vector<point> P;
int T[1000];
int G[1000];
int reduce;
int turn;
bool actual = false;

int count_sub(int l, int r) {
  // cerr << "l = " << l << ", r = " << r << endl;
  int mini = infty;
  for (auto i = l; i < r; i++) {
    mini = min(mini, T[i]-G[i]);
  }
  for (auto i = l; i < r; i++) {
    G[i] += mini;
  }
  int ans = mini;
  bool temp[1000];
  temp[0] = false;
  for (auto i = l; i < r; i++) {
    temp[i-l+1] = (T[i] > G[i]);
  }
  temp[r-l+1] = false;
  bool now = false;
  int left, right;
  for (auto i = 0; i < r-l+2; i++) {
    if (!now && !temp[i]) {
      continue;
    } else if (!now && temp[i]) {
      now = true;
      left = l+i-1;
    } else if (now && temp[i]) {
      continue;
    } else {
      now = false;
      right = l+i-1;
      ans += count_sub(left, right);
    }
  }
  // cerr << "ans = " << ans << endl;
  if (actual) {
    for (auto i = 0; i < mini; i++) {
      for (auto j = l; j < r; j++) {
        result.push_back(P[j]);
        A[P[j].x][P[j].y]--;
        red_sum++;
      }
    }
  }
  return ans;
}

bool count(int r) {
  for (auto i = 0; i < r; i++) {
    G[i] = r-1-i;
  }
  reduce = 0;
  for (auto i = 0; i < r; i++) {
    if (T[i] - G[i] < 0) return false;
    reduce += T[i] - G[i];
  }
  turn = count_sub(0, r);
  return true;
}

void count_test() {
  int M;
  cin >> M;
  for (auto i = 0; i < M; i++) {
    cin >> T[i];
  }
  if (count(M)) {
    cerr << "reduce = " << reduce << ", turn = " << turn << endl;
  } else {
    cerr << "failed" << endl;
  }
}

vector<pass> Passes[30][30];
bool visited[30][30];

bool valid(int i, int j) {
  return 0 <= i && i < 30 && 0 <= j && j < 30 && !visited[i][j];
}

void make_pass(int i, int j) {
  int M = mt()%DEPTH+1;
  int now_i = i;
  int now_j = j;
  vector<point> V;
  V.push_back(point(now_i, now_j));
  for (auto k = 0; k < M-1; k++) {
    int r = mt()%4;
    now_i += dx[r];
    now_j += dy[r];
    if (!valid(now_i, now_j)) return;
    point tp = point(now_i, now_j);
    for (auto x : V) {
      if (tp == x) {
        return;
      }
    }
    V.push_back(tp);
  }
  for (auto i = 0; i < M; i++) {
    T[i] = A[V[i].x][V[i].y];
  }
  if (count(M)) {
    Passes[i][j].push_back(pass(V, reduce, turn));
  }
}

void input() {
  for (auto i = 0; i < 30; i++) {
    for (auto j = 0; j < 30; j++) {
      cin >> A[i][j];
      A_sum += A[i][j];
    }
  }
}

void output() {
  for (auto p : result) {
    cout << p.x+1 << " " << p.y+1 << endl;
  }
}

void solve() {
  while (A_sum > red_sum) {
    int maxi = 0;
    int max_i, max_j;
    for (auto i = 0; i < 30; i++) {
      for (auto j = 0; j < 30; j++) {
        if (A[i][j] > maxi) {
          maxi = A[i][j];
          max_i = i;
          max_j = j;
        }
        visited[i][j] = (A[i][j] == 0);
        Passes[i][j].clear();
      }
    }
    vector<point> X;
    int now_i = max_i;
    int now_j = max_j;
    while (true) {
      for (auto i = 0; i < TIMES; i++) {
        make_pass(now_i, now_j);
      }
      pass maxi = *(Passes[now_i][now_j].begin());
      for (auto temp : Passes[now_i][now_j]) {
        maxi = max(temp, maxi);
      }
      if ((int)maxi.V.size() == 1) {
        if (X.empty()) {
          X = maxi.V;
        }
        break;
      }
      vector<point> tX;
      tX = X;
      auto it = maxi.V.begin();
      if (!tX.empty()) {
        it++;
      }
      for (; it != maxi.V.end(); it++) {
        tX.push_back(*it);
        visited[(*it).x][(*it).y] = true;
      }
      for (auto i = 0; i < (int)tX.size(); i++) {
        T[i] = A[tX[i].x][tX[i].y];
      }
      if (count((int)tX.size())) {
        X = tX;
        it = maxi.V.end()-1;
        now_i = (*it).x;
        now_j = (*it).y;
      } else {
        break;
      }
    }
    actual = true;
    P = X;
    /*
    cerr << "red_sum = " << red_sum << endl;
    for (auto temp : P) {
      cerr << "(" << temp.x << ", " << temp.y << ") ";
    }
    cerr << endl;
    */
    for (auto i = 0; i < (int)P.size(); i++) {
      T[i] = A[P[i].x][P[i].y];
    }
    count((int)P.size());
    actual = false;
  }
}

int main() {
  input();
  solve();
  output();
}
<|endoftext|>


<commit_before>#define HAS_HTTP_CLIENT_LOG
#include <boost/thread.hpp>
#include "asynchttpclient.h"
#include "synchttpclient.h"
#include "asyncdownload.h"
#include "syncdownload.h"

boost::asio::io_service g_io_service;

void handle_response(const ResponseInfo& r)
{
    if (r.timeout)
    {
        std::cout << "timeout" << std::endl;
    }
    else if (!r.error_msg.empty())
    {
        std::cout << r.error_msg.c_str() << std::endl;
    }
    else if (-1 == r.status_code)
    {
        std::cout << "unknown error" << std::endl;
    }
    else
    {
        std::cout << "response size=" << r.content.size()
            << ", content:\r\n" << r.content.c_str() << std::endl;
    }
}

void cb_async_http(boost::shared_ptr<CAsyncHttpClient>& pClient,
                   const ResponseInfo& r)
{
    handle_response(r);
}

void thread_async()
{
    while (true)
    {
        RequestInfo req;
        req.set_url("http://www.baidu.com/123");
        req.set_method(METHOD_GET);
        boost::shared_ptr<CAsyncHttpClient> pClient
            = boost::make_shared<CAsyncHttpClient>(boost::ref(g_io_service), 5);
        /*ProxyInfo proxy;
        proxy.type = PROXY_HTTP;
        proxy.server = "127.0.0.1";
        proxy.port = 8888;
        pClient->set_proxy(proxy);*/
        pClient->make_request(req, boost::bind(cb_async_http, pClient, _1));
        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
}

void test_sync()
{
    while (true)
    {
        RequestInfo req;
        req.set_url("http://www.baidu.com/123");
        req.set_method(METHOD_GET);
        CSyncHttpClient client(5);
        handle_response(client.make_request(req));
        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
}

void test_async()
{
    boost::thread t(thread_async);
    {
        boost::asio::io_service::work work(g_io_service);
        g_io_service.run();
    }
}

void cb_async_download(boost::shared_ptr<CAsyncHttpDownload>& pClient,
                       const ResponseInfo& r)
{
    handle_response(r);
}

void download_async()
{
    while (true)
    {
        RequestInfo req;
        req.set_url("http://www.baidu.com/123");
        req.set_method(METHOD_GET);
        boost::shared_ptr<CAsyncHttpDownload> pClient
            = boost::make_shared<CAsyncHttpDownload>(boost::ref(g_io_service), 5);
        pClient->download(req, "D:\\test_download.txt",
            boost::bind(cb_async_download, pClient, _1));
        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
}

void test_async_download()
{
    boost::thread t(download_async);
    {
        boost::asio::io_service::work work(g_io_service);
        g_io_service.run();
    }
}

void test_sync_download()
{
    while (true)
    {
        RequestInfo req;
        req.set_url("http://www.baidu.com/123");
        req.set_method(METHOD_GET);
        CSyncHttpDownload client(5);
        handle_response(client.download(req, "D:\\test_download.txt"));
        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
}

int main()
{
    test_async();
    return 0;
}

<commit_msg>modify test code<commit_after>#define HAS_HTTP_CLIENT_LOG
#include <boost/thread.hpp>
#include "asynchttpclient.h"
#include "synchttpclient.h"
#include "asyncdownload.h"
#include "syncdownload.h"

boost::asio::io_service g_io_service;

void handle_response(const ResponseInfo& r)
{
    if (r.timeout)
    {
        std::cout << "timeout" << std::endl;
    }
    else if (!r.error_msg.empty())
    {
        std::cout << r.error_msg.c_str() << std::endl;
    }
    else if (-1 == r.status_code)
    {
        std::cout << "unknown error" << std::endl;
    }
    else if (200 != r.status_code)
    {
        std::cout << "http error: " << r.status_code << ", " << r.status_msg << std::endl;
    }
    else
    {
        std::cout << "response size=" << r.content.size()
            << ", content:\r\n" << r.content.c_str() << std::endl;
    }
}

void cb_async_http(boost::shared_ptr<CAsyncHttpClient>& pClient,
                   const ResponseInfo& r)
{
    handle_response(r);
}

void thread_async()
{
    while (true)
    {
        RequestInfo req;
        req.set_url("http://www.baidu.com/123");
        req.set_method(METHOD_GET);
        boost::shared_ptr<CAsyncHttpClient> pClient
            = boost::make_shared<CAsyncHttpClient>(boost::ref(g_io_service), 5);
        /*ProxyInfo proxy;
        proxy.type = PROXY_HTTP;
        proxy.server = "127.0.0.1";
        proxy.port = 8888;
        pClient->set_proxy(proxy);*/
        pClient->make_request(req, boost::bind(cb_async_http, pClient, _1));
        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
}

void test_sync()
{
    while (true)
    {
        RequestInfo req;
        req.set_url("http://www.baidu.com/123");
        req.set_method(METHOD_GET);
        CSyncHttpClient client(5);
        handle_response(client.make_request(req));
        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
}

void test_async()
{
    boost::thread t(thread_async);
    {
        boost::asio::io_service::work work(g_io_service);
        g_io_service.run();
    }
}

void cb_async_download(boost::shared_ptr<CAsyncHttpDownload>& pClient,
                       const ResponseInfo& r)
{
    handle_response(r);
}

void download_async()
{
    while (true)
    {
        RequestInfo req;
        req.set_url("http://www.baidu.com/123");
        req.set_method(METHOD_GET);
        boost::shared_ptr<CAsyncHttpDownload> pClient
            = boost::make_shared<CAsyncHttpDownload>(boost::ref(g_io_service), 5);
        pClient->download(req, "D:\\test_download.txt",
            boost::bind(cb_async_download, pClient, _1));
        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
}

void test_async_download()
{
    boost::thread t(download_async);
    {
        boost::asio::io_service::work work(g_io_service);
        g_io_service.run();
    }
}

void test_sync_download()
{
    while (true)
    {
        RequestInfo req;
        req.set_url("http://www.baidu.com/123");
        req.set_method(METHOD_GET);
        CSyncHttpDownload client(5);
        handle_response(client.download(req, "D:\\test_download.txt"));
        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
}

int main()
{
    test_async();
    return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/sksl/dsl/DSLCore.h"

#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLIRGenerator.h"
#include "src/sksl/dsl/priv/DSLWriter.h"
#include "src/sksl/ir/SkSLBreakStatement.h"
#include "src/sksl/ir/SkSLContinueStatement.h"
#include "src/sksl/ir/SkSLDiscardStatement.h"
#include "src/sksl/ir/SkSLDoStatement.h"
#include "src/sksl/ir/SkSLForStatement.h"
#include "src/sksl/ir/SkSLIfStatement.h"
#include "src/sksl/ir/SkSLReturnStatement.h"

namespace SkSL {

namespace dsl {

#if SK_SUPPORT_GPU && !defined(SKSL_STANDALONE)
void Start(SkSL::Compiler* compiler) {
    DSLWriter::SetInstance(std::make_unique<DSLWriter>(compiler));
}

void End() {
    DSLWriter::SetInstance(nullptr);
}
#endif // SK_SUPPORT_GPU && !defined(SKSL_STANDALONE)

void SetErrorHandler(ErrorHandler* errorHandler) {
    DSLWriter::SetErrorHandler(errorHandler);
}

static char swizzle_component(SwizzleComponent c) {
    switch (c) {
        case X:
            return 'x';
        case Y:
            return 'y';
        case Z:
            return 'z';
        case W:
            return 'w';
        case ZERO:
            return '0';
        case ONE:
            return '1';
        default:
            SkUNREACHABLE;
    }
}

class DSLCore {
public:
    static DSLVar sk_FragColor() {
        return DSLVar("sk_FragColor");
    }

    static DSLVar sk_FragCoord() {
        return DSLVar("sk_FragCoord");
    }

    template <typename... Args>
    static DSLExpression Call(const char* name, Args... args) {
        SkSL::IRGenerator& ir = DSLWriter::IRGenerator();
        SkSL::ExpressionArray argArray;
        argArray.reserve_back(sizeof...(args));

        // in C++17, we could just do:
        // (argArray.push_back(args.release()), ...);
        int unused[] = {0, (DSLWriter::Ignore(argArray.push_back(args.release())), 0)...};
        static_cast<void>(unused);

        return ir.call(/*offset=*/-1, ir.convertIdentifier(-1, name), std::move(argArray));
    }

    static DSLStatement Break() {
        return std::unique_ptr<SkSL::Statement>(new SkSL::BreakStatement(/*offset=*/-1));
    }

    static DSLStatement Continue() {
        return std::unique_ptr<SkSL::Statement>(new SkSL::ContinueStatement(/*offset=*/-1));
    }

    static DSLStatement Declare(DSLVar& var, DSLExpression initialValue) {
        if (!var.fDeclaration) {
            DSLWriter::ReportError("Declare failed (was the variable already declared?)");
            return DSLStatement();
        }
        VarDeclaration& decl = var.fDeclaration->as<SkSL::VarDeclaration>();
        std::unique_ptr<Expression> expr = initialValue.coerceAndRelease(decl.var().type());
        if (expr) {
            decl.fValue = std::move(expr);
        }
        return DSLStatement(std::move(var.fDeclaration));
    }

    static DSLStatement Discard() {
        return std::unique_ptr<SkSL::Statement>(new SkSL::DiscardStatement(/*offset=*/-1));
    }

    static DSLStatement Do(DSLStatement stmt, DSLExpression test) {
        return DSLWriter::IRGenerator().convertDo(stmt.release(), test.release());
    }

    static DSLStatement For(DSLStatement initializer, DSLExpression test, DSLExpression next,
                            DSLStatement stmt) {
        return DSLWriter::IRGenerator().convertFor(/*offset=*/-1, initializer.release(),
                                                   test.release(), next.release(), stmt.release());
    }

    static DSLStatement If(DSLExpression test, DSLStatement ifTrue, DSLStatement ifFalse) {
        return DSLWriter::IRGenerator().convertIf(/*offset=*/-1, /*isStatic=*/false, test.release(),
                                                  ifTrue.release(), ifFalse.release());
    }

    static DSLStatement Return(DSLExpression value) {
        // note that because Return is called before the function in which it resides exists, at
        // this point we do not know the function's return type. We therefore do not check for
        // errors, or coerce the value to the correct type, until the return statement is actually
        // added to a function
        std::unique_ptr<SkSL::Expression> expr = value.release();
        if (expr) {
            return std::unique_ptr<SkSL::Statement>(new ReturnStatement(std::move(expr)));
        } else {
            return std::unique_ptr<SkSL::Statement>(new ReturnStatement(/*offset=*/-1));
        }
    }

    static DSLExpression Swizzle(DSLExpression base, SwizzleComponent a) {
        char mask[] = { swizzle_component(a), 0 };
        return DSLWriter::IRGenerator().convertSwizzle(base.release(), mask);
    }

    static DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b) {
        char mask[] = { swizzle_component(a), swizzle_component(b), 0 };
        return DSLWriter::IRGenerator().convertSwizzle(base.release(), mask);
    }

    static DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b,
                                 SwizzleComponent c) {
        char mask[] = { swizzle_component(a), swizzle_component(b), swizzle_component(c), 0 };
        return DSLWriter::IRGenerator().convertSwizzle(base.release(), mask);
    }

    static DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b,
                                 SwizzleComponent c, SwizzleComponent d) {
        char mask[] = { swizzle_component(a), swizzle_component(b), swizzle_component(c),
                        swizzle_component(d), 0 };
        return DSLWriter::IRGenerator().convertSwizzle(base.release(), mask);
    }

    static DSLExpression Select(DSLExpression test, DSLExpression ifTrue, DSLExpression ifFalse) {
        return DSLWriter::IRGenerator().convertTernaryExpression(test.release(), ifTrue.release(),
                                                                 ifFalse.release());
    }

    static DSLStatement While(DSLExpression test, DSLStatement stmt) {
        return DSLWriter::IRGenerator().convertWhile(/*offset=*/-1, test.release(), stmt.release());
    }
};

DSLVar sk_FragColor() {
    return DSLCore::sk_FragColor();
}

DSLVar sk_FragCoord() {
    return DSLCore::sk_FragCoord();
}

DSLStatement Break() {
    return DSLCore::Break();
}

DSLStatement Continue() {
    return DSLCore::Continue();
}

DSLStatement Declare(DSLVar& var, DSLExpression initialValue) {
    return DSLCore::Declare(var, std::move(initialValue));
}

DSLStatement Discard() {
    return DSLCore::Discard();
}

DSLStatement Do(DSLStatement stmt, DSLExpression test) {
    return DSLCore::Do(std::move(stmt), std::move(test));
}

DSLStatement For(DSLStatement initializer, DSLExpression test, DSLExpression next,
                 DSLStatement stmt) {
    return DSLCore::For(std::move(initializer), std::move(test), std::move(next), std::move(stmt));
}

DSLStatement If(DSLExpression test, DSLStatement ifTrue, DSLStatement ifFalse) {
    return DSLCore::If(std::move(test), std::move(ifTrue), std::move(ifFalse));
}

DSLStatement Return(DSLExpression expr) {
    return DSLCore::Return(std::move(expr));
}

DSLExpression Select(DSLExpression test, DSLExpression ifTrue, DSLExpression ifFalse) {
    return DSLCore::Select(std::move(test), std::move(ifTrue), std::move(ifFalse));
}

DSLStatement While(DSLExpression test, DSLStatement stmt) {
    return DSLCore::While(std::move(test), std::move(stmt));
}

DSLExpression Abs(DSLExpression x) {
    return DSLCore::Call("abs", std::move(x));
}

DSLExpression All(DSLExpression x) {
    return DSLCore::Call("all", std::move(x));
}

DSLExpression Any(DSLExpression x) {
    return DSLCore::Call("any", std::move(x));
}

DSLExpression Ceil(DSLExpression x) {
    return DSLCore::Call("ceil", std::move(x));
}

DSLExpression Clamp(DSLExpression x, DSLExpression min, DSLExpression max) {
    return DSLCore::Call("clamp", std::move(x), std::move(min), std::move(max));
}

DSLExpression Cos(DSLExpression x) {
    return DSLCore::Call("cos", std::move(x));
}

DSLExpression Cross(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("cross", std::move(x), std::move(y));
}

DSLExpression Degrees(DSLExpression x) {
    return DSLCore::Call("degrees", std::move(x));
}

DSLExpression Distance(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("distance", std::move(x), std::move(y));
}

DSLExpression Dot(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("dot", std::move(x), std::move(y));
}

DSLExpression Equal(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("equal", std::move(x), std::move(y));
}

DSLExpression Exp(DSLExpression x) {
    return DSLCore::Call("exp", std::move(x));
}

DSLExpression Exp2(DSLExpression x) {
    return DSLCore::Call("exp2", std::move(x));
}

DSLExpression Faceforward(DSLExpression n, DSLExpression i, DSLExpression nref) {
    return DSLCore::Call("faceforward", std::move(n), std::move(i), std::move(nref));
}

DSLExpression Fract(DSLExpression x) {
    return DSLCore::Call("fract", std::move(x));
}

DSLExpression Floor(DSLExpression x) {
    return DSLCore::Call("floor", std::move(x));
}

DSLExpression GreaterThan(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("greaterThan", std::move(x), std::move(y));
}

DSLExpression GreaterThanEqual(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("greaterThanEqual", std::move(x), std::move(y));
}

DSLExpression Inverse(DSLExpression x) {
    return DSLCore::Call("inverse", std::move(x));
}

DSLExpression Inversesqrt(DSLExpression x) {
    return DSLCore::Call("inversesqrt", std::move(x));
}

DSLExpression Length(DSLExpression x) {
    return DSLCore::Call("length", std::move(x));
}

DSLExpression LessThan(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("lessThan", std::move(x), std::move(y));
}

DSLExpression LessThanEqual(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("lessThanEqual", std::move(x), std::move(y));
}

DSLExpression Log(DSLExpression x) {
    return DSLCore::Call("log", std::move(x));
}

DSLExpression Log2(DSLExpression x) {
    return DSLCore::Call("log2", std::move(x));
}

DSLExpression Max(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("max", std::move(x), std::move(y));
}

DSLExpression Min(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("min", std::move(x), std::move(y));
}

DSLExpression Mix(DSLExpression x, DSLExpression y, DSLExpression a) {
    return DSLCore::Call("mix", std::move(x), std::move(y), std::move(a));
}

DSLExpression Mod(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("mod", std::move(x), std::move(y));
}

DSLExpression Normalize(DSLExpression x) {
    return DSLCore::Call("normalize", std::move(x));
}

DSLExpression NotEqual(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("notEqual", std::move(x), std::move(y));
}

DSLExpression Pow(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("pow", std::move(x), std::move(y));
}

DSLExpression Radians(DSLExpression x) {
    return DSLCore::Call("radians", std::move(x));
}

DSLExpression Reflect(DSLExpression i, DSLExpression n) {
    return DSLCore::Call("reflect", std::move(i), std::move(n));
}

DSLExpression Refract(DSLExpression i, DSLExpression n, DSLExpression eta) {
    return DSLCore::Call("refract", std::move(i), std::move(n), std::move(eta));
}

DSLExpression Saturate(DSLExpression x) {
    return DSLCore::Call("saturate", std::move(x));
}

DSLExpression Sign(DSLExpression x) {
    return DSLCore::Call("sign", std::move(x));
}

DSLExpression Sin(DSLExpression x) {
    return DSLCore::Call("sin", std::move(x));
}

DSLExpression Smoothstep(DSLExpression edge1, DSLExpression edge2, DSLExpression x) {
    return DSLCore::Call("smoothstep", std::move(edge1), std::move(edge2), std::move(x));
}

DSLExpression Sqrt(DSLExpression x) {
    return DSLCore::Call("sqrt", std::move(x));
}

DSLExpression Step(DSLExpression edge, DSLExpression x) {
    return DSLCore::Call("step", std::move(edge), std::move(x));
}

DSLExpression Swizzle(DSLExpression base, SwizzleComponent a) {
    return DSLCore::Swizzle(std::move(base), a);
}

DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b) {
    return DSLCore::Swizzle(std::move(base), a, b);
}

DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b,
                      SwizzleComponent c) {
    return DSLCore::Swizzle(std::move(base), a, b, c);
}

DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b,
                      SwizzleComponent c, SwizzleComponent d) {
    return DSLCore::Swizzle(std::move(base), a, b, c, d);
}

DSLExpression Tan(DSLExpression x) {
    return DSLCore::Call("tan", std::move(x));
}

DSLExpression Unpremul(DSLExpression x) {
    return DSLCore::Call("unpremul", std::move(x));
}

} // namespace dsl

} // namespace SkSL
<commit_msg>Added assert to catch unbalanced DSL FP Start/Ends<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/sksl/dsl/DSLCore.h"

#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLIRGenerator.h"
#include "src/sksl/dsl/priv/DSLWriter.h"
#include "src/sksl/ir/SkSLBreakStatement.h"
#include "src/sksl/ir/SkSLContinueStatement.h"
#include "src/sksl/ir/SkSLDiscardStatement.h"
#include "src/sksl/ir/SkSLDoStatement.h"
#include "src/sksl/ir/SkSLForStatement.h"
#include "src/sksl/ir/SkSLIfStatement.h"
#include "src/sksl/ir/SkSLReturnStatement.h"

namespace SkSL {

namespace dsl {

#if SK_SUPPORT_GPU && !defined(SKSL_STANDALONE)
void Start(SkSL::Compiler* compiler) {
    DSLWriter::SetInstance(std::make_unique<DSLWriter>(compiler));
}

void End() {
    SkASSERTF(!DSLWriter::InFragmentProcessor(),
              "more calls to StartFragmentProcessor than to EndFragmentProcessor");
    DSLWriter::SetInstance(nullptr);
}
#endif // SK_SUPPORT_GPU && !defined(SKSL_STANDALONE)

void SetErrorHandler(ErrorHandler* errorHandler) {
    DSLWriter::SetErrorHandler(errorHandler);
}

static char swizzle_component(SwizzleComponent c) {
    switch (c) {
        case X:
            return 'x';
        case Y:
            return 'y';
        case Z:
            return 'z';
        case W:
            return 'w';
        case ZERO:
            return '0';
        case ONE:
            return '1';
        default:
            SkUNREACHABLE;
    }
}

class DSLCore {
public:
    static DSLVar sk_FragColor() {
        return DSLVar("sk_FragColor");
    }

    static DSLVar sk_FragCoord() {
        return DSLVar("sk_FragCoord");
    }

    template <typename... Args>
    static DSLExpression Call(const char* name, Args... args) {
        SkSL::IRGenerator& ir = DSLWriter::IRGenerator();
        SkSL::ExpressionArray argArray;
        argArray.reserve_back(sizeof...(args));

        // in C++17, we could just do:
        // (argArray.push_back(args.release()), ...);
        int unused[] = {0, (DSLWriter::Ignore(argArray.push_back(args.release())), 0)...};
        static_cast<void>(unused);

        return ir.call(/*offset=*/-1, ir.convertIdentifier(-1, name), std::move(argArray));
    }

    static DSLStatement Break() {
        return std::unique_ptr<SkSL::Statement>(new SkSL::BreakStatement(/*offset=*/-1));
    }

    static DSLStatement Continue() {
        return std::unique_ptr<SkSL::Statement>(new SkSL::ContinueStatement(/*offset=*/-1));
    }

    static DSLStatement Declare(DSLVar& var, DSLExpression initialValue) {
        if (!var.fDeclaration) {
            DSLWriter::ReportError("Declare failed (was the variable already declared?)");
            return DSLStatement();
        }
        VarDeclaration& decl = var.fDeclaration->as<SkSL::VarDeclaration>();
        std::unique_ptr<Expression> expr = initialValue.coerceAndRelease(decl.var().type());
        if (expr) {
            decl.fValue = std::move(expr);
        }
        return DSLStatement(std::move(var.fDeclaration));
    }

    static DSLStatement Discard() {
        return std::unique_ptr<SkSL::Statement>(new SkSL::DiscardStatement(/*offset=*/-1));
    }

    static DSLStatement Do(DSLStatement stmt, DSLExpression test) {
        return DSLWriter::IRGenerator().convertDo(stmt.release(), test.release());
    }

    static DSLStatement For(DSLStatement initializer, DSLExpression test, DSLExpression next,
                            DSLStatement stmt) {
        return DSLWriter::IRGenerator().convertFor(/*offset=*/-1, initializer.release(),
                                                   test.release(), next.release(), stmt.release());
    }

    static DSLStatement If(DSLExpression test, DSLStatement ifTrue, DSLStatement ifFalse) {
        return DSLWriter::IRGenerator().convertIf(/*offset=*/-1, /*isStatic=*/false, test.release(),
                                                  ifTrue.release(), ifFalse.release());
    }

    static DSLStatement Return(DSLExpression value) {
        // note that because Return is called before the function in which it resides exists, at
        // this point we do not know the function's return type. We therefore do not check for
        // errors, or coerce the value to the correct type, until the return statement is actually
        // added to a function
        std::unique_ptr<SkSL::Expression> expr = value.release();
        if (expr) {
            return std::unique_ptr<SkSL::Statement>(new ReturnStatement(std::move(expr)));
        } else {
            return std::unique_ptr<SkSL::Statement>(new ReturnStatement(/*offset=*/-1));
        }
    }

    static DSLExpression Swizzle(DSLExpression base, SwizzleComponent a) {
        char mask[] = { swizzle_component(a), 0 };
        return DSLWriter::IRGenerator().convertSwizzle(base.release(), mask);
    }

    static DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b) {
        char mask[] = { swizzle_component(a), swizzle_component(b), 0 };
        return DSLWriter::IRGenerator().convertSwizzle(base.release(), mask);
    }

    static DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b,
                                 SwizzleComponent c) {
        char mask[] = { swizzle_component(a), swizzle_component(b), swizzle_component(c), 0 };
        return DSLWriter::IRGenerator().convertSwizzle(base.release(), mask);
    }

    static DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b,
                                 SwizzleComponent c, SwizzleComponent d) {
        char mask[] = { swizzle_component(a), swizzle_component(b), swizzle_component(c),
                        swizzle_component(d), 0 };
        return DSLWriter::IRGenerator().convertSwizzle(base.release(), mask);
    }

    static DSLExpression Select(DSLExpression test, DSLExpression ifTrue, DSLExpression ifFalse) {
        return DSLWriter::IRGenerator().convertTernaryExpression(test.release(), ifTrue.release(),
                                                                 ifFalse.release());
    }

    static DSLStatement While(DSLExpression test, DSLStatement stmt) {
        return DSLWriter::IRGenerator().convertWhile(/*offset=*/-1, test.release(), stmt.release());
    }
};

DSLVar sk_FragColor() {
    return DSLCore::sk_FragColor();
}

DSLVar sk_FragCoord() {
    return DSLCore::sk_FragCoord();
}

DSLStatement Break() {
    return DSLCore::Break();
}

DSLStatement Continue() {
    return DSLCore::Continue();
}

DSLStatement Declare(DSLVar& var, DSLExpression initialValue) {
    return DSLCore::Declare(var, std::move(initialValue));
}

DSLStatement Discard() {
    return DSLCore::Discard();
}

DSLStatement Do(DSLStatement stmt, DSLExpression test) {
    return DSLCore::Do(std::move(stmt), std::move(test));
}

DSLStatement For(DSLStatement initializer, DSLExpression test, DSLExpression next,
                 DSLStatement stmt) {
    return DSLCore::For(std::move(initializer), std::move(test), std::move(next), std::move(stmt));
}

DSLStatement If(DSLExpression test, DSLStatement ifTrue, DSLStatement ifFalse) {
    return DSLCore::If(std::move(test), std::move(ifTrue), std::move(ifFalse));
}

DSLStatement Return(DSLExpression expr) {
    return DSLCore::Return(std::move(expr));
}

DSLExpression Select(DSLExpression test, DSLExpression ifTrue, DSLExpression ifFalse) {
    return DSLCore::Select(std::move(test), std::move(ifTrue), std::move(ifFalse));
}

DSLStatement While(DSLExpression test, DSLStatement stmt) {
    return DSLCore::While(std::move(test), std::move(stmt));
}

DSLExpression Abs(DSLExpression x) {
    return DSLCore::Call("abs", std::move(x));
}

DSLExpression All(DSLExpression x) {
    return DSLCore::Call("all", std::move(x));
}

DSLExpression Any(DSLExpression x) {
    return DSLCore::Call("any", std::move(x));
}

DSLExpression Ceil(DSLExpression x) {
    return DSLCore::Call("ceil", std::move(x));
}

DSLExpression Clamp(DSLExpression x, DSLExpression min, DSLExpression max) {
    return DSLCore::Call("clamp", std::move(x), std::move(min), std::move(max));
}

DSLExpression Cos(DSLExpression x) {
    return DSLCore::Call("cos", std::move(x));
}

DSLExpression Cross(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("cross", std::move(x), std::move(y));
}

DSLExpression Degrees(DSLExpression x) {
    return DSLCore::Call("degrees", std::move(x));
}

DSLExpression Distance(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("distance", std::move(x), std::move(y));
}

DSLExpression Dot(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("dot", std::move(x), std::move(y));
}

DSLExpression Equal(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("equal", std::move(x), std::move(y));
}

DSLExpression Exp(DSLExpression x) {
    return DSLCore::Call("exp", std::move(x));
}

DSLExpression Exp2(DSLExpression x) {
    return DSLCore::Call("exp2", std::move(x));
}

DSLExpression Faceforward(DSLExpression n, DSLExpression i, DSLExpression nref) {
    return DSLCore::Call("faceforward", std::move(n), std::move(i), std::move(nref));
}

DSLExpression Fract(DSLExpression x) {
    return DSLCore::Call("fract", std::move(x));
}

DSLExpression Floor(DSLExpression x) {
    return DSLCore::Call("floor", std::move(x));
}

DSLExpression GreaterThan(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("greaterThan", std::move(x), std::move(y));
}

DSLExpression GreaterThanEqual(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("greaterThanEqual", std::move(x), std::move(y));
}

DSLExpression Inverse(DSLExpression x) {
    return DSLCore::Call("inverse", std::move(x));
}

DSLExpression Inversesqrt(DSLExpression x) {
    return DSLCore::Call("inversesqrt", std::move(x));
}

DSLExpression Length(DSLExpression x) {
    return DSLCore::Call("length", std::move(x));
}

DSLExpression LessThan(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("lessThan", std::move(x), std::move(y));
}

DSLExpression LessThanEqual(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("lessThanEqual", std::move(x), std::move(y));
}

DSLExpression Log(DSLExpression x) {
    return DSLCore::Call("log", std::move(x));
}

DSLExpression Log2(DSLExpression x) {
    return DSLCore::Call("log2", std::move(x));
}

DSLExpression Max(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("max", std::move(x), std::move(y));
}

DSLExpression Min(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("min", std::move(x), std::move(y));
}

DSLExpression Mix(DSLExpression x, DSLExpression y, DSLExpression a) {
    return DSLCore::Call("mix", std::move(x), std::move(y), std::move(a));
}

DSLExpression Mod(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("mod", std::move(x), std::move(y));
}

DSLExpression Normalize(DSLExpression x) {
    return DSLCore::Call("normalize", std::move(x));
}

DSLExpression NotEqual(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("notEqual", std::move(x), std::move(y));
}

DSLExpression Pow(DSLExpression x, DSLExpression y) {
    return DSLCore::Call("pow", std::move(x), std::move(y));
}

DSLExpression Radians(DSLExpression x) {
    return DSLCore::Call("radians", std::move(x));
}

DSLExpression Reflect(DSLExpression i, DSLExpression n) {
    return DSLCore::Call("reflect", std::move(i), std::move(n));
}

DSLExpression Refract(DSLExpression i, DSLExpression n, DSLExpression eta) {
    return DSLCore::Call("refract", std::move(i), std::move(n), std::move(eta));
}

DSLExpression Saturate(DSLExpression x) {
    return DSLCore::Call("saturate", std::move(x));
}

DSLExpression Sign(DSLExpression x) {
    return DSLCore::Call("sign", std::move(x));
}

DSLExpression Sin(DSLExpression x) {
    return DSLCore::Call("sin", std::move(x));
}

DSLExpression Smoothstep(DSLExpression edge1, DSLExpression edge2, DSLExpression x) {
    return DSLCore::Call("smoothstep", std::move(edge1), std::move(edge2), std::move(x));
}

DSLExpression Sqrt(DSLExpression x) {
    return DSLCore::Call("sqrt", std::move(x));
}

DSLExpression Step(DSLExpression edge, DSLExpression x) {
    return DSLCore::Call("step", std::move(edge), std::move(x));
}

DSLExpression Swizzle(DSLExpression base, SwizzleComponent a) {
    return DSLCore::Swizzle(std::move(base), a);
}

DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b) {
    return DSLCore::Swizzle(std::move(base), a, b);
}

DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b,
                      SwizzleComponent c) {
    return DSLCore::Swizzle(std::move(base), a, b, c);
}

DSLExpression Swizzle(DSLExpression base, SwizzleComponent a, SwizzleComponent b,
                      SwizzleComponent c, SwizzleComponent d) {
    return DSLCore::Swizzle(std::move(base), a, b, c, d);
}

DSLExpression Tan(DSLExpression x) {
    return DSLCore::Call("tan", std::move(x));
}

DSLExpression Unpremul(DSLExpression x) {
    return DSLCore::Call("unpremul", std::move(x));
}

} // namespace dsl

} // namespace SkSL
<|endoftext|>