<commit_before>#include "kinds.hpp"

#include "sexpr.hpp"
#include "ast.hpp"

#include <algorithm>

namespace slip {

  namespace kinds {

    template<class ... C>
    static std::ostream& debug(std::ostream& out, C&& ... c);

    ref<function> operator>>=(const kind& lhs, const kind& rhs) {
      return make_ref<function>(lhs, rhs);
    }

    const constructor func_ctor = constant("->", types() >>= types() >>= types() );

    constructor constructor::operator()(const constructor& arg) const {
      return make_ref<application>(*this, arg);
    }

    monotype operator>>=(const monotype& lhs, const monotype& rhs) {
      return (func_ctor(lhs))(rhs);

    }

    struct kind_visitor {
      kind operator()(const constant& self) const { return self.kind; }
      kind operator()(const ref<variable>& self) const { return self->kind; }

      kind operator()(const ref<application>& self) const  {
        return self->func.kind().get< ref<function> >()->to;
      }

    };

    struct kind constructor::kind() const {
      return map<struct kind>(kind_visitor());
    }

    struct kind_ostream {

      void operator()(types, std::ostream& out) const {
        out << '*';
      }

      void operator()(const ref<function>& self, std::ostream& out) const {
        // TODO parentheses
        out << self->from << " -> " << self->to << std::endl;
      }

    };

    std::ostream& operator<<(std::ostream& out, const kind& self) {
      self.apply(kind_ostream(), out);
      return out;
    }

    template<class T>
    struct traits {
      static constant type();
    };

    const constant unit_type("unit", types()),
      boolean_type("boolean", types()),
      integer_type("integer", types()),
      real_type("real", types()),
      string_type("string", types()),
      symbol_type("symbol", types());

    template<> constant traits< slip::unit >::type() { return unit_type; }
    template<> constant traits< slip::boolean >::type() { return boolean_type; }
    template<> constant traits< slip::integer >::type() { return integer_type; }
    template<> constant traits< slip::real >::type() { return real_type; }
    template<> constant traits< slip::string >::type() { return string_type; }
    template<> constant traits< slip::symbol >::type() { return symbol_type; }

    typechecker::typechecker(ref<env_type> env, ref<uf_type> uf)
      : env( env ),
        uf( uf ) {

    }

    static monotype infer(typechecker& self, const ast::expr& node);

    // unification
    struct unification_error {
      unification_error(constructor lhs, constructor rhs) : lhs(lhs), rhs(rhs) { }
      const constructor lhs, rhs;
    };

    struct occurs_error {
      ref<variable> var;
      constructor type;         // TODO do we want monotype here?
    };

    template<class UF>
    struct occurs_check {

      bool operator()(const constant& self, const ref<variable>& var, UF& uf) const {
        return false;
      }

      bool operator()(const ref<variable>& self, const ref<variable>& var, UF& uf) const {

        // TODO not sure if this should be done here

        if(self->depth > var->depth) {
          // we are trying to unify var with app( ... self ... ) but var has
          // lower depth: we need to "lower" self to var's depth so that self
          // generalizes just like var
          // ref<variable> lower = make_ref<variable>(var->kind, var->depth);

          // assert(uf.find(self).kind() == lower->kind);
          // debug( std::clog << "linking", constructor(self), constructor(lower) ) << std::endl;
          // uf.link(uf.find(self), lower);
        }

        return self == var;
      }

      bool operator()(const ref<application>& self, const ref<variable>& var, UF& uf) const {

        if( uf.find(self->arg).template map<bool>(occurs_check(), var, uf) ) return true;
        if( uf.find(self->func).template map<bool>(occurs_check(), var, uf) ) return true;

        return false;
      }

    };

    template<class UF>
    struct unify_visitor {

      const bool try_reverse;

      unify_visitor(bool try_reverse = true)
        : try_reverse(try_reverse) { }

      template<class T>
      void operator()(const T& self, const constructor& rhs, UF& uf) const {

        // double dispatch
        if( try_reverse ) {
          return rhs.apply( unify_visitor(false), self, uf);
        } else {
          throw unification_error(self, rhs);
        }
      }

      void operator()(const ref<variable>& self, const constructor& rhs, UF& uf) const {
        assert( uf.find(self) == self );
        assert( uf.find(rhs) == rhs );

        if( constructor(self) != rhs && rhs.map<bool>(occurs_check<UF>(), self, uf)) {
          throw occurs_error{self, rhs.get< ref<application> >()};
        }

        assert(self->kind == rhs.kind());

        // debug( std::clog << "linking", constructor(self), rhs ) << std::endl;
        uf.link(self, rhs);

      }

      void operator()(const constant& lhs, const constant& rhs, UF& uf) const {
        if( !(lhs == rhs) ) {
          throw unification_error(lhs, rhs);
        }
      }

      void operator()(const ref<application>& lhs, const ref<application>& rhs, UF& uf) const {
        // if( !(lhs->func == rhs->func) ) {
        //   debug( std::clog << "func mismatch: ", lhs->func, rhs->func) << std::endl;
        //   throw unification_error(lhs, rhs);
        // }

        uf.find(lhs->arg).apply( unify_visitor(), uf.find(rhs->arg), uf);
        uf.find(lhs->func).apply( unify_visitor(), uf.find(rhs->func), uf);

      }

    };

    // expression inference
    struct expr_visitor {

      template<class T>
      monotype operator()(const ast::literal<T>& self, typechecker& tc) const {
        return traits<T>::type();
      }

      monotype operator()(const ast::variable& self, typechecker& tc) const {
        const polytype& p = tc.find(self.name);
        return tc.instantiate(p);
      }

      monotype operator()(const ref<ast::lambda>& self, typechecker& tc) const {

        typechecker sub = tc.scope();

        // create/define arg types
        const list< ref<variable> > args = map(self->args, [&](const symbol& s) {
            const ref<variable> var = tc.fresh( types() );
            // note: var stays monomorphic after generalization
            sub.def(s, sub.generalize(var) );
            return var;
          });

        // infer body type in subcontext
        const monotype body_type = infer(sub, self->body);

        // return complete application type
        return foldr(body_type, args, [](const ref<variable>& lhs, const monotype& rhs) -> monotype {
            return lhs >>= rhs;
          });

      }

      monotype operator()(const ref<ast::application>& self, typechecker& tc) const {

        const monotype func = infer(tc, self->func);

        // infer arg types
        const list<monotype> args = map(self->args, [&](const ast::expr& e) {
            return infer(tc, e);
          });

        // construct function type
        const monotype result = tc.fresh( types() );

        const monotype sig = foldr(result, args, [&](const monotype& lhs, const monotype& rhs) {
            return lhs >>= rhs;
          });

        try{
          tc.unify(func, sig);
        } catch( occurs_error ) {
          throw type_error("occurs check");
        }

        return result;
      }

      template<class T>
      monotype operator()(const T& self, typechecker& tc) const {
        throw error("infer unimplemented");
      }

    };

    static monotype infer(typechecker& self, const ast::expr& node) {
      return node.map<monotype>(expr_visitor(), self);
    }

    // finding nice representants
    struct nice {

      template<class UF>
      constructor operator()(const constant& self, UF& uf) const {
        return self;
      }

      template<class UF>
      constructor operator()(const ref<variable>& self, UF& uf) const {

        const constructor res = uf->find(self);

        if(res == monotype(self)) {
          // debug(std::clog << "nice: ", constructor(self), res) << std::endl;
          return res;
        }

        return res.map<constructor>(nice(), uf);
      }

      template<class UF>
      constructor operator()(const ref<application>& self, UF& uf) const {
        const auto func = self->func.map<constructor>(nice(), uf);
        const auto arg = self->arg.map<constructor>(nice(), uf);
        // debug(std::clog << "nice: ", func, arg, func(arg)) << std::endl;

        return func(arg);
      }

    };

    // instantiation
    struct instantiate_visitor {
      using map_type = std::map< ref<variable>, ref<variable> >;

      monotype operator()(const constant& self, const map_type& m) const {
        return self;
      }

      monotype operator()(const ref<variable>& self, const map_type& m) const {
        auto it = m.find(self);
        if(it == m.end()) return self;
        return it->second;
      }

      monotype operator()(const ref<application>& self, const map_type& m) const {
        return make_ref<application>( self->func.map<monotype>(instantiate_visitor(), m),
                                      self->func.map<monotype>(instantiate_visitor(), m) );
      }

    };

    monotype typechecker::instantiate(const polytype& poly) const {
      instantiate_visitor::map_type map;

      // associate each bound variable to a fresh one
      auto out = std::inserter(map, map.begin());
      std::transform(poly.forall.begin(), poly.forall.end(), out, [&](const ref<variable>& v) {
          return std::make_pair(v, fresh(v->kind));
        });

      return poly.body.map<monotype>(instantiate_visitor(), map);
    }

    // env lookup/def
    struct unbound_variable : type_error {
      unbound_variable(symbol id) : type_error("unbound variable " + id.name()) { }
    };

    const polytype& typechecker::find(symbol id) const {

      if(polytype* p = env->find(id)) {
        return *p;
      }

      throw unbound_variable(id);
    }

    typechecker& typechecker::def(symbol id, const polytype& p) {
      auto res = env->locals.emplace( std::make_pair(id, p) );
      if(!res.second) throw error("redefinition of " + id.name());
      return *this;
    }

    ref<variable> typechecker::fresh(kind k) const {
      return make_ref<variable>(k, env->depth);
    }

    typechecker typechecker::scope() const {
      // TODO should we use nested union-find too?
      return typechecker( make_ref<env_type>(env), uf);
    }

    // variables
    struct vars_visitor {

      using result_type = std::set< ref<variable> >;

      void operator()(const constant&, result_type& res) const { }

      void operator()(const ref<variable>& self, result_type& res) const {
        res.insert(self);
      }

      void operator()(const ref<application>& self, result_type& res) const {
        self->func.apply( vars_visitor(), res );
        self->arg.apply( vars_visitor(), res );
      }

    };

    static vars_visitor::result_type vars(const constructor& self) {
      vars_visitor::result_type res;
      self.apply(vars_visitor(), res);
      return res;
    }

    // generalization
    polytype typechecker::generalize(const monotype& mono) const {
      // debug(std::clog << "gen: ", mono) << std::endl;
      polytype res(mono.map<monotype>(nice(), uf));

      const auto all = vars(res.body);

      // copy free variables (i.e. instantiated at a larger depth)
      auto out = std::back_inserter(res.forall);

      const std::size_t depth = this->env->depth;
      std::copy_if(all.begin(), all.end(), out, [depth](const ref<variable>& v) {
          return v->depth >= depth;
        });

      return res;
    }

    polytype infer(typechecker& self, const ast::toplevel& node) {

      const monotype res = infer(self, node.get<ast::expr>());
      return self.generalize(res);
    }

    // ostream

    struct var_repr {
      std::size_t index;
      bool quantified;
    };

    static std::ostream& operator<<(std::ostream& out, const var_repr& self) {
      if( self.quantified ) out << "'";
      else out << "!";
      return out << char('a' + self.index);
    }

    using ostream_map = std::map< ref<variable>, var_repr >;

    struct ostream_visitor {

      void operator()(const constant& self, std::ostream& out, ostream_map& osm) const {
        out << self.name;
      }

      void operator()(const ref<variable>& self, std::ostream& out, ostream_map& osm) const {
        auto err = osm.emplace( std::make_pair(self, var_repr{osm.size(), false} ));
        out << err.first->second;
      }

      void operator()(const ref<application>& self, std::ostream& out, ostream_map& osm) const {
        // TODO parentheses

        if(self->func == func_ctor) {
          // this must be why ocaml's types are written in reverse
          self->arg.apply(ostream_visitor(), out, osm);
          out << ' ';
          self->func.apply(ostream_visitor(), out, osm);
        } else {
          self->func.apply(ostream_visitor(), out, osm);
          out << ' ';
          self->arg.apply(ostream_visitor(), out, osm);
        }

      }

    };

    static std::ostream& ostream(std::ostream& out, const polytype& self, ostream_map& osm) {
      for(const ref<variable>& var : self.forall) {
        osm.emplace( std::make_pair(var, var_repr{osm.size(), true} ) );
      }

      self.body.apply( ostream_visitor(), out, osm );
      return out;
    }

    std::ostream& operator<<(std::ostream& out, const polytype& self) {
      ostream_map osm;
      return ostream(out, self, osm);
    }

    void typechecker::unify(const constructor& lhs, const constructor& rhs) {
      // debug( std::clog << "unifying: ", lhs, rhs) << std::endl;
      uf->find(lhs).apply( unify_visitor<uf_type>(), uf->find(rhs), *uf);
    }

    template<class ... C>
    static std::ostream& debug(std::ostream& out, C&& ... c) {
      ostream_map osm;
      const int expand[] = {
        (c.apply( ostream_visitor(), std::clog << "   " , osm ) , 0)...
      }; (void) expand;

      return out;
    }
  }

}
<commit_msg>typing conditions<commit_after>#include "kinds.hpp"

#include "sexpr.hpp"
#include "ast.hpp"

#include <algorithm>

namespace slip {

  namespace kinds {

    template<class ... C>
    static std::ostream& debug(std::ostream& out, C&& ... c);

    ref<function> operator>>=(const kind& lhs, const kind& rhs) {
      return make_ref<function>(lhs, rhs);
    }

    const constructor func_ctor = constant("->", types() >>= types() >>= types() );

    constructor constructor::operator()(const constructor& arg) const {
      return make_ref<application>(*this, arg);
    }

    monotype operator>>=(const monotype& lhs, const monotype& rhs) {
      return (func_ctor(lhs))(rhs);

    }

    struct kind_visitor {
      kind operator()(const constant& self) const { return self.kind; }
      kind operator()(const ref<variable>& self) const { return self->kind; }

      kind operator()(const ref<application>& self) const  {
        return self->func.kind().get< ref<function> >()->to;
      }

    };

    struct kind constructor::kind() const {
      return map<struct kind>(kind_visitor());
    }

    struct kind_ostream {

      void operator()(types, std::ostream& out) const {
        out << '*';
      }

      void operator()(const ref<function>& self, std::ostream& out) const {
        // TODO parentheses
        out << self->from << " -> " << self->to << std::endl;
      }

    };

    std::ostream& operator<<(std::ostream& out, const kind& self) {
      self.apply(kind_ostream(), out);
      return out;
    }

    template<class T>
    struct traits {
      static constant type();
    };

    const constant unit_type("unit", types()),
      boolean_type("boolean", types()),
      integer_type("integer", types()),
      real_type("real", types()),
      string_type("string", types()),
      symbol_type("symbol", types());

    template<> constant traits< slip::unit >::type() { return unit_type; }
    template<> constant traits< slip::boolean >::type() { return boolean_type; }
    template<> constant traits< slip::integer >::type() { return integer_type; }
    template<> constant traits< slip::real >::type() { return real_type; }
    template<> constant traits< slip::string >::type() { return string_type; }
    template<> constant traits< slip::symbol >::type() { return symbol_type; }

    typechecker::typechecker(ref<env_type> env, ref<uf_type> uf)
      : env( env ),
        uf( uf ) {

    }

    static monotype infer(typechecker& self, const ast::expr& node);

    // unification
    struct unification_error {
      unification_error(constructor lhs, constructor rhs) : lhs(lhs), rhs(rhs) { }
      const constructor lhs, rhs;
    };

    struct occurs_error {
      ref<variable> var;
      constructor type;         // TODO do we want monotype here?
    };

    template<class UF>
    struct occurs_check {

      bool operator()(const constant& self, const ref<variable>& var, UF& uf) const {
        return false;
      }

      bool operator()(const ref<variable>& self, const ref<variable>& var, UF& uf) const {

        // TODO not sure if this should be done here

        if(self->depth > var->depth) {
          // we are trying to unify var with app( ... self ... ) but var has
          // lower depth: we need to "lower" self to var's depth so that self
          // generalizes just like var
          // ref<variable> lower = make_ref<variable>(var->kind, var->depth);

          // assert(uf.find(self).kind() == lower->kind);
          // debug( std::clog << "linking", constructor(self), constructor(lower) ) << std::endl;
          // uf.link(uf.find(self), lower);
        }

        return self == var;
      }

      bool operator()(const ref<application>& self, const ref<variable>& var, UF& uf) const {

        if( uf.find(self->arg).template map<bool>(occurs_check(), var, uf) ) return true;
        if( uf.find(self->func).template map<bool>(occurs_check(), var, uf) ) return true;

        return false;
      }

    };

    template<class UF>
    struct unify_visitor {

      const bool try_reverse;

      unify_visitor(bool try_reverse = true)
        : try_reverse(try_reverse) { }

      template<class T>
      void operator()(const T& self, const constructor& rhs, UF& uf) const {

        // double dispatch
        if( try_reverse ) {
          return rhs.apply( unify_visitor(false), self, uf);
        } else {
          throw unification_error(self, rhs);
        }
      }

      void operator()(const ref<variable>& self, const constructor& rhs, UF& uf) const {
        assert( uf.find(self) == self );
        assert( uf.find(rhs) == rhs );

        if( constructor(self) != rhs && rhs.map<bool>(occurs_check<UF>(), self, uf)) {
          throw occurs_error{self, rhs.get< ref<application> >()};
        }

        assert(self->kind == rhs.kind());

        // debug( std::clog << "linking", constructor(self), rhs ) << std::endl;
        uf.link(self, rhs);

      }

      void operator()(const constant& lhs, const constant& rhs, UF& uf) const {
        if( !(lhs == rhs) ) {
          throw unification_error(lhs, rhs);
        }
      }

      void operator()(const ref<application>& lhs, const ref<application>& rhs, UF& uf) const {
        uf.find(lhs->arg).apply( unify_visitor(), uf.find(rhs->arg), uf);
        uf.find(lhs->func).apply( unify_visitor(), uf.find(rhs->func), uf);
      }

    };

    // expression inference
    struct expr_visitor {

      template<class T>
      monotype operator()(const ast::literal<T>& self, typechecker& tc) const {
        return traits<T>::type();
      }

      monotype operator()(const ast::variable& self, typechecker& tc) const {
        const polytype& p = tc.find(self.name);
        return tc.instantiate(p);
      }

      monotype operator()(const ref<ast::lambda>& self, typechecker& tc) const {

        typechecker sub = tc.scope();

        // create/define arg types
        const list< ref<variable> > args = map(self->args, [&](const symbol& s) {
            const ref<variable> var = tc.fresh( types() );
            // note: var stays monomorphic after generalization
            sub.def(s, sub.generalize(var) );
            return var;
          });

        // infer body type in subcontext
        const monotype body_type = infer(sub, self->body);

        // return complete application type
        return foldr(body_type, args, [](const ref<variable>& lhs, const monotype& rhs) -> monotype {
            return lhs >>= rhs;
          });

      }

      monotype operator()(const ref<ast::application>& self, typechecker& tc) const {

        const monotype func = infer(tc, self->func);

        // infer arg types
        const list<monotype> args = map(self->args, [&](const ast::expr& e) {
            return infer(tc, e);
          });

        // construct function type
        const monotype result = tc.fresh( types() );

        const monotype sig = foldr(result, args, [&](const monotype& lhs, const monotype& rhs) {
            return lhs >>= rhs;
          });

        try{
          tc.unify(func, sig);
        } catch( occurs_error ) {
          throw type_error("occurs check");
        }

        return result;
      }

      monotype operator()(const ref<ast::condition>& self, typechecker& tc) const {
        const monotype result = tc.fresh( types() );

        for(const ast::condition::branch& b : self->branches) {

          const monotype test = infer(tc, b.test);
          tc.unify(boolean_type, test);

          const monotype value = infer(tc, b.value);
          tc.unify(value, result);
        };

        return result;
      }

      template<class T>
      monotype operator()(const T& self, typechecker& tc) const {
        throw error("infer unimplemented");
      }

    };

    static monotype infer(typechecker& self, const ast::expr& node) {
      return node.map<monotype>(expr_visitor(), self);
    }

    // finding nice representants
    struct nice {

      template<class UF>
      constructor operator()(const constant& self, UF& uf) const {
        return self;
      }

      template<class UF>
      constructor operator()(const ref<variable>& self, UF& uf) const {

        const constructor res = uf->find(self);

        if(res == monotype(self)) {
          // debug(std::clog << "nice: ", constructor(self), res) << std::endl;
          return res;
        }

        return res.map<constructor>(nice(), uf);
      }

      template<class UF>
      constructor operator()(const ref<application>& self, UF& uf) const {
        const auto func = self->func.map<constructor>(nice(), uf);
        const auto arg = self->arg.map<constructor>(nice(), uf);
        // debug(std::clog << "nice: ", func, arg, func(arg)) << std::endl;

        return func(arg);
      }

    };

    // instantiation
    struct instantiate_visitor {
      using map_type = std::map< ref<variable>, ref<variable> >;

      monotype operator()(const constant& self, const map_type& m) const {
        return self;
      }

      monotype operator()(const ref<variable>& self, const map_type& m) const {
        auto it = m.find(self);
        if(it == m.end()) return self;
        return it->second;
      }

      monotype operator()(const ref<application>& self, const map_type& m) const {
        return make_ref<application>( self->func.map<monotype>(instantiate_visitor(), m),
                                      self->func.map<monotype>(instantiate_visitor(), m) );
      }

    };

    monotype typechecker::instantiate(const polytype& poly) const {
      instantiate_visitor::map_type map;

      // associate each bound variable to a fresh one
      auto out = std::inserter(map, map.begin());
      std::transform(poly.forall.begin(), poly.forall.end(), out, [&](const ref<variable>& v) {
          return std::make_pair(v, fresh(v->kind));
        });

      return poly.body.map<monotype>(instantiate_visitor(), map);
    }

    // env lookup/def
    struct unbound_variable : type_error {
      unbound_variable(symbol id) : type_error("unbound variable " + id.name()) { }
    };

    const polytype& typechecker::find(symbol id) const {

      if(polytype* p = env->find(id)) {
        return *p;
      }

      throw unbound_variable(id);
    }

    typechecker& typechecker::def(symbol id, const polytype& p) {
      auto res = env->locals.emplace( std::make_pair(id, p) );
      if(!res.second) throw error("redefinition of " + id.name());
      return *this;
    }

    ref<variable> typechecker::fresh(kind k) const {
      return make_ref<variable>(k, env->depth);
    }

    typechecker typechecker::scope() const {
      // TODO should we use nested union-find too?
      return typechecker( make_ref<env_type>(env), uf);
    }

    // variables
    struct vars_visitor {

      using result_type = std::set< ref<variable> >;

      void operator()(const constant&, result_type& res) const { }

      void operator()(const ref<variable>& self, result_type& res) const {
        res.insert(self);
      }

      void operator()(const ref<application>& self, result_type& res) const {
        self->func.apply( vars_visitor(), res );
        self->arg.apply( vars_visitor(), res );
      }

    };

    static vars_visitor::result_type vars(const constructor& self) {
      vars_visitor::result_type res;
      self.apply(vars_visitor(), res);
      return res;
    }

    // generalization
    polytype typechecker::generalize(const monotype& mono) const {
      // debug(std::clog << "gen: ", mono) << std::endl;
      polytype res(mono.map<monotype>(nice(), uf));

      const auto all = vars(res.body);

      // copy free variables (i.e. instantiated at a larger depth)
      auto out = std::back_inserter(res.forall);

      const std::size_t depth = this->env->depth;
      std::copy_if(all.begin(), all.end(), out, [depth](const ref<variable>& v) {
          return v->depth >= depth;
        });

      return res;
    }

    polytype infer(typechecker& self, const ast::toplevel& node) {

      const monotype res = infer(self, node.get<ast::expr>());
      return self.generalize(res);
    }

    // ostream

    struct var_repr {
      std::size_t index;
      bool quantified;
    };

    static std::ostream& operator<<(std::ostream& out, const var_repr& self) {
      if( self.quantified ) out << "'";
      else out << "!";
      return out << char('a' + self.index);
    }

    using ostream_map = std::map< ref<variable>, var_repr >;

    struct ostream_visitor {

      void operator()(const constant& self, std::ostream& out, ostream_map& osm) const {
        out << self.name;
      }

      void operator()(const ref<variable>& self, std::ostream& out, ostream_map& osm) const {
        auto err = osm.emplace( std::make_pair(self, var_repr{osm.size(), false} ));
        out << err.first->second;
      }

      void operator()(const ref<application>& self, std::ostream& out, ostream_map& osm) const {
        // TODO parentheses

        if(self->func == func_ctor) {
          // this must be why ocaml's types are written in reverse
          self->arg.apply(ostream_visitor(), out, osm);
          out << ' ';
          self->func.apply(ostream_visitor(), out, osm);
        } else {
          self->func.apply(ostream_visitor(), out, osm);
          out << ' ';
          self->arg.apply(ostream_visitor(), out, osm);
        }

      }

    };

    static std::ostream& ostream(std::ostream& out, const polytype& self, ostream_map& osm) {
      for(const ref<variable>& var : self.forall) {
        osm.emplace( std::make_pair(var, var_repr{osm.size(), true} ) );
      }

      self.body.apply( ostream_visitor(), out, osm );
      return out;
    }

    std::ostream& operator<<(std::ostream& out, const polytype& self) {
      ostream_map osm;
      return ostream(out, self, osm);
    }

    void typechecker::unify(const constructor& lhs, const constructor& rhs) {
      // debug( std::clog << "unifying: ", lhs, rhs) << std::endl;
      uf->find(lhs).apply( unify_visitor<uf_type>(), uf->find(rhs), *uf);
    }

    template<class ... C>
    static std::ostream& debug(std::ostream& out, C&& ... c) {
      ostream_map osm;
      const int expand[] = {
        (c.apply( ostream_visitor(), std::clog << "   " , osm ) , 0)...
      }; (void) expand;

      return out;
    }
  }

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.cactus
 */

#include <fstream>
#include <sstream>
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/io/gzip_stream.h"
#include "google/protobuf/io/coded_stream.h"

#include "vglight.h"

using namespace std;
using namespace vg;
using namespace google::protobuf::io;

VGLight::VGLight() : _numEdges(0)
{
}

VGLight::~VGLight()
{
}

/** Most code copy-pasted from VG stream constructor (vg.cpp)  and
 * the functions it calls
 */
void VGLight::loadGraph(istream& in)
{
  ZeroCopyInputStream *raw_in = new IstreamInputStream(&in);
  GzipInputStream *gzip_in = new GzipInputStream(raw_in);
  CodedInputStream *coded_in = new CodedInputStream(gzip_in);

  uint64_t count;
  coded_in->ReadVarint64(&count);
  if (!count)
  {
    throw runtime_error("Empty stream");
  }

  _graphs.clear();

  do
  {
    std::string s;
    for (uint64_t i = 0; i < count; ++i)
    {
      uint32_t msgSize = 0;
      delete coded_in;
      coded_in = new CodedInputStream(gzip_in);
      // the messages are prefixed by their size
      coded_in->ReadVarint32(&msgSize);
      if ((msgSize > 0) &&
          (coded_in->ReadString(&s, msgSize)))
      {
        Graph object;
        object.ParseFromString(s);
        _graphs.push_back(object);
      }
    }
  } while (coded_in->ReadVarint64(&count));

  mergeGraphs();

  delete coded_in;
  delete gzip_in;
  delete raw_in;
}

void VGLight::loadGraph(const Graph& graph)
{
  _graphs.resize(1);
  _graphs[0] = graph;
  mergeGraphs();
}

void VGLight::mergeGraphs()
{
  _paths.clear();
  _nodes.clear();
  _fromEdges.clear();
  _toEdges.clear();
  _numEdges = 0;

  for (size_t i = 0; i < _graphs.size(); ++i)
  {
    for (size_t j = 0; j < _graphs[i].node_size(); ++j)
    {
      _nodes.insert(_graphs[i].mutable_node(j));
    }
    for (size_t j = 0; j < _graphs[i].edge_size(); ++j)
    {
      const Edge* edge = _graphs[i].mutable_edge(j);
      _fromEdges.insert(pair<int64_t, const Edge*>(edge->from(), edge));
      _toEdges.insert(pair<int64_t, const Edge*>(edge->to(), edge));
      ++_numEdges;
    }
    for (size_t j = 0; j < _graphs[i].path_size(); ++j)
    {
      Path* path = _graphs[i].mutable_path(j);
      pair<PathMap::iterator, bool> ret = _paths.insert(
        pair<string, MappingList>(path->name(), MappingList()));
      for (size_t k = 0; k < path->mapping_size(); ++k)
      {
        ret.first->second.push_back(path->mapping(k));
      }
      // sort by rank and remove dupes
      set<Mapping, MappingRankLess> mappingSet(ret.first->second.begin(),
                                               ret.first->second.end());
      ret.first->second = MappingList(mappingSet.begin(), mappingSet.end());
    }
  }
}

void VGLight::getInEdges(const Node* node,
                         vector<const Edge*>& ins) const
{
  ins.clear();
  pair<EdgeMap::const_iterator, EdgeMap::const_iterator> ret;

  ret = _toEdges.equal_range(node->id());
  for (EdgeMap::const_iterator i = ret.first; i != ret.second; ++i)
  {
    ins.push_back(i->second);
  }
}

void VGLight::getOutEdges(const Node* node,
                         vector<const Edge*>& outs) const
{
  outs.clear();
  pair<EdgeMap::const_iterator, EdgeMap::const_iterator> ret;

  ret = _fromEdges.equal_range(node->id());
  for (EdgeMap::const_iterator i = ret.first; i != ret.second; ++i)
  {
    outs.push_back(i->second);
  }
}

void VGLight::getPathDNA(const string& pathName, string& outDNA) const
{
  assert(_paths.find(pathName) != _paths.end());
  const MappingList& mappingList = _paths.find(pathName)->second;
  getPathDNA(mappingList, outDNA);
}

void VGLight::getPathDNA(const MappingList& mappingList, string& outDNA) const
{
  outDNA.erase();
  for (MappingList::const_iterator i = mappingList.begin();
       i != mappingList.end(); ++i)
  {
    const Position& pos = i->position();
    bool reversed = i->is_reverse();
    const Node* node = getNode(pos.node_id());
    int64_t segmentLength = getSegmentLength(*i);
    int64_t offset = pos.offset();
    if (reversed)
    {
      offset -= segmentLength - 1;
    }
    string dna = node->sequence().substr(offset, segmentLength);
    if (reversed)
    {
      reverseComplement(dna);
    }
    outDNA += dna;
  }
}

int64_t VGLight::getSegmentLength(const Mapping& mapping) const
{
  int64_t segmentLength = 0;
  // no edits: take distance from offset to end of node
  if (mapping.edit_size() == 0)
  {
    const Position& pos = mapping.position();
    const Node* node = getNode(pos.node_id());
    if (!mapping.is_reverse())
    {
      segmentLength = node->sequence().length() - pos.offset();
    }
    else
    {
      segmentLength = pos.offset() + 1;
    }
  }
  // has edits: take total length of edits (???)
  else
  {
    int numEdits = mapping.edit_size();
    for (int i = 0; i < numEdits; ++i)
    {
      const Edit& edit = mapping.edit(i);
      if (edit.from_length() != edit.to_length())
      {
        stringstream msg;
        msg << "Nontrivial edit found: to_length != from_length";
        throw runtime_error(msg.str());
      }
      else if (edit.sequence().length() > 0)
      {
        stringstream msg;
        msg << "Nontrivial edit found: sequence=" << edit.sequence()
            << " (only empty sequence supported)";
        throw runtime_error(msg.str());
      }
      segmentLength += mapping.edit(i).from_length();
    }
  }
  return segmentLength;
}

char VGLight::reverseComplement(char c)
{
  switch (c)
  {
  case 'A' : return 'T';
  case 'a' : return 't';
  case 'C' : return 'G';
  case 'c' : return 'g';
  case 'G' : return 'C';
  case 'g' : return 'c';
  case 'T' : return 'A';
  case 't' : return 'a';
  default : break;
  }
  return c;
}

void VGLight::reverseComplement(std::string& s)
{
  if (!s.empty())
  {
    size_t j = s.length() - 1;
    size_t i = 0;
    char buf;
    do
    {
      while (j > 0 && s[j] == '-')
      {
        --j;
      }
      while (i < s.length() - 1 && s[i] == '-')
      {
        ++i;
      }

      if (i >= j || s[i] == '-' || s[j] == '-')
      {
        if (i == j && s[i] != '-')
        {
          s[i] = reverseComplement(s[i]);
        }
        break;
      }

      buf = reverseComplement(s[i]);
      s[i] = reverseComplement(s[j]);
      s[j] = buf;

      ++i;
      --j;
    } while (true);
  }
}
<commit_msg>accept rankless paths with a warning instead of silently screwing up<commit_after>/*
 * Copyright (C) 2015 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.cactus
 */

#include <fstream>
#include <sstream>
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/io/gzip_stream.h"
#include "google/protobuf/io/coded_stream.h"

#include "vglight.h"

using namespace std;
using namespace vg;
using namespace google::protobuf::io;

VGLight::VGLight() : _numEdges(0)
{
}

VGLight::~VGLight()
{
}

/** Most code copy-pasted from VG stream constructor (vg.cpp)  and
 * the functions it calls
 */
void VGLight::loadGraph(istream& in)
{
  ZeroCopyInputStream *raw_in = new IstreamInputStream(&in);
  GzipInputStream *gzip_in = new GzipInputStream(raw_in);
  CodedInputStream *coded_in = new CodedInputStream(gzip_in);

  uint64_t count;
  coded_in->ReadVarint64(&count);
  if (!count)
  {
    throw runtime_error("Empty stream");
  }

  _graphs.clear();

  do
  {
    std::string s;
    for (uint64_t i = 0; i < count; ++i)
    {
      uint32_t msgSize = 0;
      delete coded_in;
      coded_in = new CodedInputStream(gzip_in);
      // the messages are prefixed by their size
      coded_in->ReadVarint32(&msgSize);
      if ((msgSize > 0) &&
          (coded_in->ReadString(&s, msgSize)))
      {
        Graph object;
        object.ParseFromString(s);
        _graphs.push_back(object);
      }
    }
  } while (coded_in->ReadVarint64(&count));

  mergeGraphs();

  delete coded_in;
  delete gzip_in;
  delete raw_in;
}

void VGLight::loadGraph(const Graph& graph)
{
  _graphs.resize(1);
  _graphs[0] = graph;
  mergeGraphs();
}

void VGLight::mergeGraphs()
{
  _paths.clear();
  _nodes.clear();
  _fromEdges.clear();
  _toEdges.clear();
  _numEdges = 0;

  for (size_t i = 0; i < _graphs.size(); ++i)
  {
    for (size_t j = 0; j < _graphs[i].node_size(); ++j)
    {
      _nodes.insert(_graphs[i].mutable_node(j));
    }
    for (size_t j = 0; j < _graphs[i].edge_size(); ++j)
    {
      const Edge* edge = _graphs[i].mutable_edge(j);
      _fromEdges.insert(pair<int64_t, const Edge*>(edge->from(), edge));
      _toEdges.insert(pair<int64_t, const Edge*>(edge->to(), edge));
      ++_numEdges;
    }
    for (size_t j = 0; j < _graphs[i].path_size(); ++j)
    {
      Path* path = _graphs[i].mutable_path(j);
      pair<PathMap::iterator, bool> ret = _paths.insert(
        pair<string, MappingList>(path->name(), MappingList()));
      for (size_t k = 0; k < path->mapping_size(); ++k)
      {
        ret.first->second.push_back(path->mapping(k));
      }
      // sort by rank and remove dupes
      set<Mapping, MappingRankLess> mappingSet(ret.first->second.begin(),
                                               ret.first->second.end());
      if (mappingSet.size() > 1 || mappingSet.begin()->rank() > 0)
      {
        ret.first->second = MappingList(mappingSet.begin(), mappingSet.end());
      }
      else
      {
        cerr << "Warning: rank not specified for mapping in path "
             << path->name() << endl;
      }
    }
  }
}

void VGLight::getInEdges(const Node* node,
                         vector<const Edge*>& ins) const
{
  ins.clear();
  pair<EdgeMap::const_iterator, EdgeMap::const_iterator> ret;

  ret = _toEdges.equal_range(node->id());
  for (EdgeMap::const_iterator i = ret.first; i != ret.second; ++i)
  {
    ins.push_back(i->second);
  }
}

void VGLight::getOutEdges(const Node* node,
                         vector<const Edge*>& outs) const
{
  outs.clear();
  pair<EdgeMap::const_iterator, EdgeMap::const_iterator> ret;

  ret = _fromEdges.equal_range(node->id());
  for (EdgeMap::const_iterator i = ret.first; i != ret.second; ++i)
  {
    outs.push_back(i->second);
  }
}

void VGLight::getPathDNA(const string& pathName, string& outDNA) const
{
  assert(_paths.find(pathName) != _paths.end());
  const MappingList& mappingList = _paths.find(pathName)->second;
  getPathDNA(mappingList, outDNA);
}

void VGLight::getPathDNA(const MappingList& mappingList, string& outDNA) const
{
  outDNA.erase();
  for (MappingList::const_iterator i = mappingList.begin();
       i != mappingList.end(); ++i)
  {
    const Position& pos = i->position();
    bool reversed = i->is_reverse();
    const Node* node = getNode(pos.node_id());
    int64_t segmentLength = getSegmentLength(*i);
    int64_t offset = pos.offset();
    if (reversed)
    {
      offset -= segmentLength - 1;
    }
    string dna = node->sequence().substr(offset, segmentLength);
    if (reversed)
    {
      reverseComplement(dna);
    }
    outDNA += dna;
  }
}

int64_t VGLight::getSegmentLength(const Mapping& mapping) const
{
  int64_t segmentLength = 0;
  // no edits: take distance from offset to end of node
  if (mapping.edit_size() == 0)
  {
    const Position& pos = mapping.position();
    const Node* node = getNode(pos.node_id());
    if (!mapping.is_reverse())
    {
      segmentLength = node->sequence().length() - pos.offset();
    }
    else
    {
      segmentLength = pos.offset() + 1;
    }
  }
  // has edits: take total length of edits (???)
  else
  {
    int numEdits = mapping.edit_size();
    for (int i = 0; i < numEdits; ++i)
    {
      const Edit& edit = mapping.edit(i);
      if (edit.from_length() != edit.to_length())
      {
        stringstream msg;
        msg << "Nontrivial edit found: to_length != from_length";
        throw runtime_error(msg.str());
      }
      else if (edit.sequence().length() > 0)
      {
        stringstream msg;
        msg << "Nontrivial edit found: sequence=" << edit.sequence()
            << " (only empty sequence supported)";
        throw runtime_error(msg.str());
      }
      segmentLength += mapping.edit(i).from_length();
    }
  }
  return segmentLength;
}

char VGLight::reverseComplement(char c)
{
  switch (c)
  {
  case 'A' : return 'T';
  case 'a' : return 't';
  case 'C' : return 'G';
  case 'c' : return 'g';
  case 'G' : return 'C';
  case 'g' : return 'c';
  case 'T' : return 'A';
  case 't' : return 'a';
  default : break;
  }
  return c;
}

void VGLight::reverseComplement(std::string& s)
{
  if (!s.empty())
  {
    size_t j = s.length() - 1;
    size_t i = 0;
    char buf;
    do
    {
      while (j > 0 && s[j] == '-')
      {
        --j;
      }
      while (i < s.length() - 1 && s[i] == '-')
      {
        ++i;
      }

      if (i >= j || s[i] == '-' || s[j] == '-')
      {
        if (i == j && s[i] != '-')
        {
          s[i] = reverseComplement(s[i]);
        }
        break;
      }

      buf = reverseComplement(s[i]);
      s[i] = reverseComplement(s[j]);
      s[j] = buf;

      ++i;
      --j;
    } while (true);
  }
}
<|endoftext|>


<commit_before>#include <v8.h>
#include <nan.h>

#include "../common.h"
#include "../structures/handles.h"
#include "../structures/oc-payload.h"

extern "C" {
#include <ocstack.h>
}

using namespace v8;
using namespace node;

NAN_METHOD(bind_OCNotifyAllObservers) {
  NanScope();

  VALIDATE_ARGUMENT_COUNT(args, 2);
  VALIDATE_ARGUMENT_TYPE(args, 0, IsArray);
  VALIDATE_ARGUMENT_TYPE(args, 1, IsNumber);

  OCResourceHandle handle;
  if (!c_OCResourceHandle(Local<Array>::Cast(args[0]), &handle)) {
    NanReturnUndefined();
  }

  NanReturnValue(NanNew<Number>(OCNotifyAllObservers(
      handle, (OCQualityOfService)args[1]->Uint32Value())));
}

NAN_METHOD(bind_OCNotifyListOfObservers) {
  NanScope();

  VALIDATE_ARGUMENT_COUNT(args, 5);
  VALIDATE_ARGUMENT_TYPE(args, 0, IsArray);
  VALIDATE_ARGUMENT_TYPE(args, 1, IsArray);
  VALIDATE_ARGUMENT_TYPE(args, 2, IsNumber);
  VALIDATE_ARGUMENT_TYPE(args, 3, IsObject);
  VALIDATE_ARGUMENT_TYPE(args, 4, IsNumber);

  OCResourceHandle handle;
  if (!c_OCResourceHandle(Local<Array>::Cast(args[0]), &handle)) {
    NanReturnUndefined();
  }

  // Construct the C array of observation IDs.
  Local<Array> obsIds = Local<Array>::Cast(args[1]);
  uint8_t arrayLength = (uint8_t)obsIds->Length();
  uint8_t numberOfIds = (uint8_t)args[2]->Uint32Value();

  // If the array contains fewer IDs than the reported number, we use the lower
  // number
  numberOfIds = (numberOfIds < arrayLength ? numberOfIds : arrayLength);

  OCObservationId *c_observations =
      (OCObservationId *)malloc(numberOfIds * sizeof(OCObservationId));
  if (!c_observations && numberOfIds > 0) {
    NanThrowError(
        "OCNotifyListOfObservers: Failed to allocate list of observers");
    NanReturnUndefined();
  }

  // Populate a C-like array from the V8 array
  int index;
  for (index = 0; index < numberOfIds; index++) {
    Local<Value> oneObservationId = obsIds->Get(index);
    if (!(oneObservationId->IsNumber())) {
      NanThrowTypeError("OCObservationID must satisfy IsNumber()");
      NanReturnUndefined();
    }
    c_observations[index] = (OCObservationId)oneObservationId->Uint32Value();
  }

  OCRepPayload* payload;
  if (args[3]->IsObject()) {
    if (!c_OCPayload(args[3]->ToObject(), (OCPayload **)&payload)) {
      NanReturnUndefined();
    }
  }

  Local<Number> returnValue = NanNew<Number>(
      OCNotifyListOfObservers(handle, c_observations, numberOfIds, payload,
                              (OCQualityOfService)args[4]->Uint32Value()));

  free(c_observations);

  NanReturnValue(returnValue);
}
<commit_msg>Functions: Free payload after notifying list of observers<commit_after>#include <v8.h>
#include <nan.h>

#include "../common.h"
#include "../structures/handles.h"
#include "../structures/oc-payload.h"

extern "C" {
#include <ocstack.h>
#include <ocpayload.h>
}

using namespace v8;
using namespace node;

NAN_METHOD(bind_OCNotifyAllObservers) {
  NanScope();

  VALIDATE_ARGUMENT_COUNT(args, 2);
  VALIDATE_ARGUMENT_TYPE(args, 0, IsArray);
  VALIDATE_ARGUMENT_TYPE(args, 1, IsNumber);

  OCResourceHandle handle;
  if (!c_OCResourceHandle(Local<Array>::Cast(args[0]), &handle)) {
    NanReturnUndefined();
  }

  NanReturnValue(NanNew<Number>(OCNotifyAllObservers(
      handle, (OCQualityOfService)args[1]->Uint32Value())));
}

NAN_METHOD(bind_OCNotifyListOfObservers) {
  NanScope();

  VALIDATE_ARGUMENT_COUNT(args, 5);
  VALIDATE_ARGUMENT_TYPE(args, 0, IsArray);
  VALIDATE_ARGUMENT_TYPE(args, 1, IsArray);
  VALIDATE_ARGUMENT_TYPE(args, 2, IsNumber);
  VALIDATE_ARGUMENT_TYPE(args, 3, IsObject);
  VALIDATE_ARGUMENT_TYPE(args, 4, IsNumber);

  OCResourceHandle handle;
  if (!c_OCResourceHandle(Local<Array>::Cast(args[0]), &handle)) {
    NanReturnUndefined();
  }

  // Construct the C array of observation IDs.
  Local<Array> obsIds = Local<Array>::Cast(args[1]);
  uint8_t arrayLength = (uint8_t)obsIds->Length();
  uint8_t numberOfIds = (uint8_t)args[2]->Uint32Value();

  // If the array contains fewer IDs than the reported number, we use the lower
  // number
  numberOfIds = (numberOfIds < arrayLength ? numberOfIds : arrayLength);

  OCObservationId *c_observations =
      (OCObservationId *)malloc(numberOfIds * sizeof(OCObservationId));
  if (!c_observations && numberOfIds > 0) {
    NanThrowError(
        "OCNotifyListOfObservers: Failed to allocate list of observers");
    NanReturnUndefined();
  }

  // Populate a C-like array from the V8 array
  int index;
  for (index = 0; index < numberOfIds; index++) {
    Local<Value> oneObservationId = obsIds->Get(index);
    if (!(oneObservationId->IsNumber())) {
      NanThrowTypeError("OCObservationID must satisfy IsNumber()");
      NanReturnUndefined();
    }
    c_observations[index] = (OCObservationId)oneObservationId->Uint32Value();
  }

  OCRepPayload* payload;
  if (args[3]->IsObject()) {
    if (!c_OCPayload(args[3]->ToObject(), (OCPayload **)&payload)) {
      NanReturnUndefined();
    }
  }

  Local<Number> returnValue = NanNew<Number>(
      OCNotifyListOfObservers(handle, c_observations, numberOfIds, payload,
                              (OCQualityOfService)args[4]->Uint32Value()));

  free(c_observations);
  OCRepPayloadDestroy(payload);

  NanReturnValue(returnValue);
}
<|endoftext|>


<commit_before>#include <psp2/ctrl.h>
#include <psp2/touch.h>
#include <psp2/moduleinfo.h>
#include <psp2/kernel/processmgr.h>

#include <cstdio>
#include <vita2d.h>

#include "../libvitamenu/menu_manager.h"
#include "../libvitamenu/menu.h"
#include "../libvitamenu/menu_item.h"
#include "../libvitamenu/utils.h"

PSP2_MODULE_INFO(0, 0, "touchvitalibsample");

void log(std::string s)
{
	printf("%s%s", s.c_str(), "\n");
}

void test_function()
{
	log("I was called!");
}

int main() {
	log("Starting");
	vita2d_init();

	char menu_name[] = "Sample Menu";
	char item1_name[] = "Item 1";
	char item2_name[] = "Item 2";
	char item3_name[] = "Item 3";

	Menu * menu = new Menu(NULL, 100, 50, RED, &menu_name[0]);

	MenuManager * manager = new MenuManager(menu);

	menu->addMenuItem(new MenuItem(&item1_name[0], 100, 100, &test_function));
	menu->addMenuItem(new MenuItem(&item2_name[0], 100, 116, &test_function));
	menu->addMenuItem(new MenuItem(&item3_name[0], 100, 132, &test_function));

	//input for both touch and joysticks
	SceCtrlData pad;
	SceTouchData touch;

	while(1) {
		//read input
		sceCtrlPeekBufferPositive(0, &pad, 1);
		sceTouchPeek(0, &touch, 1);

		//quit when you press select

		if (pad.buttons & PSP2_CTRL_TRIANGLE)
		{
			break;
		}

		manager->handleDpad(&pad);

		manager->handleTouch(&touch);

		if(touch.reportNum > 0)
		{
			/* Front touchscreen: 1920x1088 */
			//int x = lerp(touch.report[0].x, 1920, SCREEN_W) - w/2;
		//	int y = lerp(touch.report[0].y, 1088, SCREEN_H) - 16/2;

		}

		vita2d_start_drawing();
		vita2d_clear_screen();

		manager->draw();

		vita2d_end_drawing();
		vita2d_swap_buffers();
	}

	log("Stopped.\n");

	vita2d_fini();

	sceKernelExitProcess(0);
	delete manager;

	return 0;
}<commit_msg>Sample homebrew example is functional; touch needs extra padding<commit_after>#include <psp2/ctrl.h>
#include <psp2/touch.h>
#include <psp2/moduleinfo.h>
#include <psp2/kernel/processmgr.h>

#include <cstdio>
#include <vita2d.h>

#include "../libvitamenu/menu_manager.h"
#include "../libvitamenu/menu.h"
#include "../libvitamenu/menu_item.h"
#include "../libvitamenu/utils.h"

PSP2_MODULE_INFO(0, 0, "touchvitalibsample");

void log(std::string s)
{
	printf("%s%s", s.c_str(), "\n");
}

void test_function()
{
	log("I was called!");
}

int main() {
	log("Starting");
	vita2d_init();

	char menu_name[] = "Sample Menu";
	char item1_name[] = "Item 1";
	char item2_name[] = "Item 2";
	char item3_name[] = "Item 3";

	Menu * menu = new Menu(NULL, 100, 50, RED, &menu_name[0]);

	MenuManager * manager = new MenuManager(menu);

	menu->addMenuItem(new MenuItem(&item1_name[0], 100, 100, &test_function));
	menu->addMenuItem(new MenuItem(&item2_name[0], 100, 164, &test_function));
	menu->addMenuItem(new MenuItem(&item3_name[0], 100, 228, &test_function));

	//input for both touch and joysticks
	SceCtrlData pad;
	SceTouchData touch;

	while(1) {
		//read input
		sceCtrlPeekBufferPositive(0, &pad, 1);
		sceTouchPeek(0, &touch, 1);

		//quit when you press triangle
		if (pad.buttons & PSP2_CTRL_TRIANGLE)
		{
			break;
		}

		manager->handleDpad(&pad);

		manager->handleTouch(&touch);

		vita2d_start_drawing();
		vita2d_clear_screen();

		manager->draw();

		vita2d_end_drawing();
		vita2d_swap_buffers();
	}

	log("Stopped.\n");

	vita2d_fini();

	sceKernelExitProcess(0);
	delete manager;

	return 0;
}<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2013 Danny Y., Rapptz

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef SOL_OBJECT_HPP
#define SOL_OBJECT_HPP

#include "reference.hpp"
#include "stack.hpp"

namespace sol {
class object : public reference {
public:
    object(lua_State* L, int index = -1): reference(L, index) {}
    object() = default;

    template<typename T>
    T as() {
        push();
        type_assert(state(), -1, type_of<T>());
        return stack::get<T>(state());
    }

    template<typename T>
    bool is() {
        push();
        auto expected = type_of<T>();
        auto actual = lua_type(state(), -1);
        return (static_cast<int>(expected) == actual) || (expected == type::poly);
    }
};
} // sol

#endif // SOL_OBJECT_HPP<commit_msg>Add operator== and operator!= support for sol::object and nil<commit_after>// The MIT License (MIT)

// Copyright (c) 2013 Danny Y., Rapptz

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef SOL_OBJECT_HPP
#define SOL_OBJECT_HPP

#include "reference.hpp"
#include "stack.hpp"

namespace sol {
class object : public reference {
public:
    object(lua_State* L, int index = -1): reference(L, index) {}
    object() = default;

    template<typename T>
    T as() const {
        push();
        type_assert(state(), -1, type_of<T>());
        return stack::get<T>(state());
    }

    template<typename T>
    bool is() const {
        push();
        auto expected = type_of<T>();
        auto actual = lua_type(state(), -1);
        return (static_cast<int>(expected) == actual) || (expected == type::poly);
    }
};

bool operator==(const object& lhs, const nil_t&) {
    return lhs.is<nil_t>();
}

bool operator==(const nil_t&, const object& rhs) {
    return rhs.is<nil_t>();
}

bool operator!=(const object& lhs, const nil_t&) {
    return !lhs.is<nil_t>();
}

bool operator!=(const nil_t&, const object& rhs) {
    return !rhs.is<nil_t>();
}
} // sol

#endif // SOL_OBJECT_HPP<|endoftext|>


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

#include "GrOptDrawState.h"

#include "GrDrawState.h"
#include "GrDrawTargetCaps.h"

GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
                               BlendOptFlags blendOptFlags,
                               GrBlendCoeff optSrcCoeff,
                               GrBlendCoeff optDstCoeff,
                               const GrDrawTargetCaps& caps) {
    fRenderTarget.set(SkSafeRef(drawState.getRenderTarget()), kWrite_GrIOType);
    fColor = drawState.getColor();
    fCoverage = drawState.getCoverage();
    fViewMatrix = drawState.getViewMatrix();
    fBlendConstant = drawState.getBlendConstant();
    fFlagBits = drawState.getFlagBits();
    fVAPtr = drawState.getVertexAttribs();
    fVACount = drawState.getVertexAttribCount();
    fVAStride = drawState.getVertexStride();
    fStencilSettings = drawState.getStencil();
    fDrawFace = (DrawFace)drawState.getDrawFace();
    fBlendOptFlags = blendOptFlags;
    fSrcBlend = optSrcCoeff;
    fDstBlend = optDstCoeff;

    memcpy(fFixedFunctionVertexAttribIndices,
           drawState.getFixedFunctionVertexAttribIndices(),
           sizeof(fFixedFunctionVertexAttribIndices));

    fInputColorIsUsed = true;
    fInputCoverageIsUsed = true;

    int firstColorStageIdx = 0;
    int firstCoverageStageIdx = 0;
    bool separateCoverageFromColor;

    uint8_t fixedFunctionVAToRemove = 0;

    this->computeEffectiveColorStages(drawState, &firstColorStageIdx, &fixedFunctionVAToRemove);
    this->computeEffectiveCoverageStages(drawState, &firstCoverageStageIdx);
    this->adjustFromBlendOpts(drawState, &firstColorStageIdx, &firstCoverageStageIdx,
                              &fixedFunctionVAToRemove);
    // Should not be setting any more FFVA to be removed at this point
    this->removeFixedFunctionVertexAttribs(fixedFunctionVAToRemove);
    this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx);
    this->setOutputStateInfo(drawState, caps, firstCoverageStageIdx, &separateCoverageFromColor);

    // Copy GeometryProcesssor from DS or ODS
    if (drawState.hasGeometryProcessor()) {
        fGeometryProcessor.initAndRef(drawState.fGeometryProcessor);
    } else {
        fGeometryProcessor.reset(NULL);
    }

    // Copy Color Stages from DS to ODS
    if (firstColorStageIdx < drawState.numColorStages()) {
        fFragmentStages.reset(&drawState.getColorStage(firstColorStageIdx),
                              drawState.numColorStages() - firstColorStageIdx);
    } else {
        fFragmentStages.reset();
    }

    fNumColorStages = fFragmentStages.count();

    // Copy Coverage Stages from DS to ODS
    if (firstCoverageStageIdx < drawState.numCoverageStages()) {
        fFragmentStages.push_back_n(drawState.numCoverageStages() - firstCoverageStageIdx,
                                    &drawState.getCoverageStage(firstCoverageStageIdx));
        if (!separateCoverageFromColor) {
            fNumColorStages = fFragmentStages.count();
        }
    }
};

GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState, const GrDrawTargetCaps& caps,
                                       GrGpu::DrawType drawType) {
    if (NULL == drawState.fCachedOptState || caps.getUniqueID() != drawState.fCachedCapsID) {
        GrBlendCoeff srcCoeff;
        GrBlendCoeff dstCoeff;
        BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
                                                                          &srcCoeff,
                                                                          &dstCoeff);

        // If our blend coeffs are set to 0,1 we know we will not end up drawing unless we are
        // stenciling. When path rendering the stencil settings are not always set on the draw state
        // so we must check the draw type. In cases where we will skip drawing we simply return a
        // null GrOptDrawState.
        if (kZero_GrBlendCoeff == srcCoeff && kOne_GrBlendCoeff == dstCoeff &&
            !drawState.getStencil().doesWrite() && GrGpu::kStencilPath_DrawType != drawType) {
            return NULL;
        }

        drawState.fCachedOptState = SkNEW_ARGS(GrOptDrawState, (drawState, blendFlags, srcCoeff,
                                                                dstCoeff, caps));
        drawState.fCachedCapsID = caps.getUniqueID();
    } else {
#ifdef SK_DEBUG
        GrBlendCoeff srcCoeff;
        GrBlendCoeff dstCoeff;
        BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
                                                                          &srcCoeff,
                                                                          &dstCoeff);
        SkASSERT(GrOptDrawState(drawState, blendFlags, srcCoeff, dstCoeff, caps) ==
                 *drawState.fCachedOptState);
#endif
    }
    drawState.fCachedOptState->ref();
    return drawState.fCachedOptState;
}

void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
                                        const GrDrawTargetCaps& caps,
                                        int firstCoverageStageIdx,
                                        bool* separateCoverageFromColor) {
    // Set this default and then possibly change our mind if there is coverage.
    fPrimaryOutputType = kModulate_PrimaryOutputType;
    fSecondaryOutputType = kNone_SecondaryOutputType;

    // If we do have coverage determine whether it matters.
    *separateCoverageFromColor = this->hasGeometryProcessor();
    if (!this->isCoverageDrawing() &&
        (ds.numCoverageStages() - firstCoverageStageIdx > 0 ||
         ds.hasGeometryProcessor() ||
         this->hasCoverageVertexAttribute())) {

        if (caps.dualSourceBlendingSupport()) {
            if (kZero_GrBlendCoeff == fDstBlend) {
                // write the coverage value to second color
                fSecondaryOutputType =  kCoverage_SecondaryOutputType;
                *separateCoverageFromColor = true;
                fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
            } else if (kSA_GrBlendCoeff == fDstBlend) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
                *separateCoverageFromColor = true;
                fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
            } else if (kSC_GrBlendCoeff == fDstBlend) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
                *separateCoverageFromColor = true;
                fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
            }
        } else if (fReadsDst &&
                   kOne_GrBlendCoeff == fSrcBlend &&
                   kZero_GrBlendCoeff == fDstBlend) {
            fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
            *separateCoverageFromColor = true;
        }
    }
}

void GrOptDrawState::adjustFromBlendOpts(const GrDrawState& ds,
                                         int* firstColorStageIdx,
                                         int* firstCoverageStageIdx,
                                         uint8_t* fixedFunctionVAToRemove) {
    switch (fBlendOptFlags) {
        case kNone_BlendOpt:
        case kSkipDraw_BlendOptFlag:
            break;
        case kCoverageAsAlpha_BlendOptFlag:
            fFlagBits |= kCoverageDrawing_StateBit;
            break;
        case kEmitCoverage_BlendOptFlag:
            fColor = 0xffffffff;
            fInputColorIsUsed = true;
            *firstColorStageIdx = ds.numColorStages();
            *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
            break;
        case kEmitTransBlack_BlendOptFlag:
            fColor = 0;
            fCoverage = 0xff;
            fInputColorIsUsed = true;
            fInputCoverageIsUsed = true;
            *firstColorStageIdx = ds.numColorStages();
            *firstCoverageStageIdx = ds.numCoverageStages();
            *fixedFunctionVAToRemove |= (0x1 << kColor_GrVertexAttribBinding |
                                         0x1 << kCoverage_GrVertexAttribBinding);
            break;
        default:
            SkFAIL("Unknown BlendOptFlag");
    }
}

void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
    int numToRemove = 0;
    uint8_t maskCheck = 0x1;
    // Count the number of vertex attributes that we will actually remove
    for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
        if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
            ++numToRemove;
        }
        maskCheck <<= 1;
    }

    fOptVA.reset(fVACount - numToRemove);

    GrVertexAttrib* dst = fOptVA.get();
    const GrVertexAttrib* src = fVAPtr;

    for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) {
        const GrVertexAttrib& currAttrib = *src;
        if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
            uint8_t maskCheck = 0x1 << currAttrib.fBinding;
            if (maskCheck & removeVAFlag) {
                SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
                fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
                continue;
            }
            fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
        }
        memcpy(dst, src, sizeof(GrVertexAttrib));
        ++newIdx;
        ++dst;
    }
    fVACount -= numToRemove;
    fVAPtr = fOptVA.get();
}

void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds, int* firstColorStageIdx,
                                                 uint8_t* fixedFunctionVAToRemove) {
    // Set up color and flags for ConstantColorComponent checks
    GrProcessor::InvariantOutput inout;
    inout.fIsSingleComponent = false;
    if (!this->hasColorVertexAttribute()) {
        inout.fColor = ds.getColor();
        inout.fValidFlags = kRGBA_GrColorComponentFlags;
    } else {
        if (ds.vertexColorsAreOpaque()) {
            inout.fColor = 0xFF << GrColor_SHIFT_A;
            inout.fValidFlags = kA_GrColorComponentFlag;
        } else {
            inout.fValidFlags = 0;
            // not strictly necessary but we get false alarms from tools about uninit.
            inout.fColor = 0;
        }
    }

    for (int i = 0; i < ds.numColorStages(); ++i) {
        const GrFragmentProcessor* fp = ds.getColorStage(i).getProcessor();
        fp->computeInvariantOutput(&inout);
        if (!inout.fWillUseInputColor) {
            *firstColorStageIdx = i;
            fInputColorIsUsed = false;
        }
        if (kRGBA_GrColorComponentFlags == inout.fValidFlags) {
            *firstColorStageIdx = i + 1;
            fColor = inout.fColor;
            fInputColorIsUsed = true;
            *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
            // Since we are clearing all previous color stages we are in a state where we have found
            // zero stages that don't multiply the inputColor.
            inout.fNonMulStageFound = false;
        }
    }
}

void GrOptDrawState::computeEffectiveCoverageStages(const GrDrawState& ds,
                                                    int* firstCoverageStageIdx) {
    // We do not try to optimize out constantColor coverage effects here. It is extremely rare
    // to have a coverage effect that returns a constant value for all four channels. Thus we
    // save having to make extra virtual calls by not checking for it.

    // Don't do any optimizations on coverage stages. It should not be the case where we do not use
    // input coverage in an effect
#ifdef OptCoverageStages
    GrProcessor::InvariantOutput inout;
    for (int i = 0; i < ds.numCoverageStages(); ++i) {
        const GrFragmentProcessor* fp = ds.getCoverageStage(i).getProcessor();
        fp->computeInvariantOutput(&inout);
        if (!inout.fWillUseInputColor) {
            *firstCoverageStageIdx = i;
            fInputCoverageIsUsed = false;
        }
    }
#endif
}

static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
    if (stage.getProcessor()->willReadDstColor()) {
        *readsDst = true;
    }
    if (stage.getProcessor()->willReadFragmentPosition()) {
        *readsFragPosition = true;
    }
}

void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx,
                                   int firstCoverageStageIdx) {
    // We will need a local coord attrib if there is one currently set on the optState and we are
    // actually generating some effect code
    fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() &&
        ds.numTotalStages() - firstColorStageIdx - firstCoverageStageIdx > 0;

    fReadsDst = false;
    fReadsFragPosition = false;

    for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) {
        const GrFragmentStage& stage = ds.getColorStage(s);
        get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
    }
    for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
        const GrFragmentStage& stage = ds.getCoverageStage(s);
        get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
    }
    if (ds.hasGeometryProcessor()) {
        const GrGeometryProcessor& gp = *ds.getGeometryProcessor();
        fReadsFragPosition = fReadsFragPosition || gp.willReadFragmentPosition();
    }
}

////////////////////////////////////////////////////////////////////////////////

bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
    return this->isEqual(that);
}

bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
    bool usingVertexColors = this->hasColorVertexAttribute();
    if (!usingVertexColors && this->fColor != that.fColor) {
        return false;
    }

    if (this->getRenderTarget() != that.getRenderTarget() ||
        this->fFragmentStages.count() != that.fFragmentStages.count() ||
        this->fNumColorStages != that.fNumColorStages ||
        !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
        this->fSrcBlend != that.fSrcBlend ||
        this->fDstBlend != that.fDstBlend ||
        this->fBlendConstant != that.fBlendConstant ||
        this->fFlagBits != that.fFlagBits ||
        this->fVACount != that.fVACount ||
        this->fVAStride != that.fVAStride ||
        memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
        this->fStencilSettings != that.fStencilSettings ||
        this->fDrawFace != that.fDrawFace ||
        this->fInputColorIsUsed != that.fInputColorIsUsed ||
        this->fInputCoverageIsUsed != that.fInputCoverageIsUsed ||
        this->fReadsDst != that.fReadsDst ||
        this->fReadsFragPosition != that.fReadsFragPosition ||
        this->fRequiresLocalCoordAttrib != that.fRequiresLocalCoordAttrib ||
        this->fPrimaryOutputType != that.fPrimaryOutputType ||
        this->fSecondaryOutputType != that.fSecondaryOutputType) {
        return false;
    }

    bool usingVertexCoverage = this->hasCoverageVertexAttribute();
    if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
        return false;
    }

    bool explicitLocalCoords = this->hasLocalCoordAttribute();
    if (this->hasGeometryProcessor()) {
        if (!that.hasGeometryProcessor()) {
            return false;
        } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
            return false;
        }
    } else if (that.hasGeometryProcessor()) {
        return false;
    }

    for (int i = 0; i < this->numFragmentStages(); i++) {
        if (!GrFragmentStage::AreCompatible(this->getFragmentStage(i), that.getFragmentStage(i),
                                            explicitLocalCoords)) {
            return false;
        }
    }

    SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices,
                         that.fFixedFunctionVertexAttribIndices,
                         sizeof(this->fFixedFunctionVertexAttribIndices)));

    return true;
}

<commit_msg>Add check to see if we need to remove fixed funciton VA in OptDrawState<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrOptDrawState.h"

#include "GrDrawState.h"
#include "GrDrawTargetCaps.h"

GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
                               BlendOptFlags blendOptFlags,
                               GrBlendCoeff optSrcCoeff,
                               GrBlendCoeff optDstCoeff,
                               const GrDrawTargetCaps& caps) {
    fRenderTarget.set(SkSafeRef(drawState.getRenderTarget()), kWrite_GrIOType);
    fColor = drawState.getColor();
    fCoverage = drawState.getCoverage();
    fViewMatrix = drawState.getViewMatrix();
    fBlendConstant = drawState.getBlendConstant();
    fFlagBits = drawState.getFlagBits();
    fVAPtr = drawState.getVertexAttribs();
    fVACount = drawState.getVertexAttribCount();
    fVAStride = drawState.getVertexStride();
    fStencilSettings = drawState.getStencil();
    fDrawFace = (DrawFace)drawState.getDrawFace();
    fBlendOptFlags = blendOptFlags;
    fSrcBlend = optSrcCoeff;
    fDstBlend = optDstCoeff;

    memcpy(fFixedFunctionVertexAttribIndices,
           drawState.getFixedFunctionVertexAttribIndices(),
           sizeof(fFixedFunctionVertexAttribIndices));

    fInputColorIsUsed = true;
    fInputCoverageIsUsed = true;

    int firstColorStageIdx = 0;
    int firstCoverageStageIdx = 0;
    bool separateCoverageFromColor;

    uint8_t fixedFunctionVAToRemove = 0;

    this->computeEffectiveColorStages(drawState, &firstColorStageIdx, &fixedFunctionVAToRemove);
    this->computeEffectiveCoverageStages(drawState, &firstCoverageStageIdx);
    this->adjustFromBlendOpts(drawState, &firstColorStageIdx, &firstCoverageStageIdx,
                              &fixedFunctionVAToRemove);
    // Should not be setting any more FFVA to be removed at this point
    if (0 != fixedFunctionVAToRemove) {
        this->removeFixedFunctionVertexAttribs(fixedFunctionVAToRemove);
    }
    this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx);
    this->setOutputStateInfo(drawState, caps, firstCoverageStageIdx, &separateCoverageFromColor);

    // Copy GeometryProcesssor from DS or ODS
    if (drawState.hasGeometryProcessor()) {
        fGeometryProcessor.initAndRef(drawState.fGeometryProcessor);
    } else {
        fGeometryProcessor.reset(NULL);
    }

    // Copy Color Stages from DS to ODS
    if (firstColorStageIdx < drawState.numColorStages()) {
        fFragmentStages.reset(&drawState.getColorStage(firstColorStageIdx),
                              drawState.numColorStages() - firstColorStageIdx);
    } else {
        fFragmentStages.reset();
    }

    fNumColorStages = fFragmentStages.count();

    // Copy Coverage Stages from DS to ODS
    if (firstCoverageStageIdx < drawState.numCoverageStages()) {
        fFragmentStages.push_back_n(drawState.numCoverageStages() - firstCoverageStageIdx,
                                    &drawState.getCoverageStage(firstCoverageStageIdx));
        if (!separateCoverageFromColor) {
            fNumColorStages = fFragmentStages.count();
        }
    }
};

GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState, const GrDrawTargetCaps& caps,
                                       GrGpu::DrawType drawType) {
    if (NULL == drawState.fCachedOptState || caps.getUniqueID() != drawState.fCachedCapsID) {
        GrBlendCoeff srcCoeff;
        GrBlendCoeff dstCoeff;
        BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
                                                                          &srcCoeff,
                                                                          &dstCoeff);

        // If our blend coeffs are set to 0,1 we know we will not end up drawing unless we are
        // stenciling. When path rendering the stencil settings are not always set on the draw state
        // so we must check the draw type. In cases where we will skip drawing we simply return a
        // null GrOptDrawState.
        if (kZero_GrBlendCoeff == srcCoeff && kOne_GrBlendCoeff == dstCoeff &&
            !drawState.getStencil().doesWrite() && GrGpu::kStencilPath_DrawType != drawType) {
            return NULL;
        }

        drawState.fCachedOptState = SkNEW_ARGS(GrOptDrawState, (drawState, blendFlags, srcCoeff,
                                                                dstCoeff, caps));
        drawState.fCachedCapsID = caps.getUniqueID();
    } else {
#ifdef SK_DEBUG
        GrBlendCoeff srcCoeff;
        GrBlendCoeff dstCoeff;
        BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
                                                                          &srcCoeff,
                                                                          &dstCoeff);
        SkASSERT(GrOptDrawState(drawState, blendFlags, srcCoeff, dstCoeff, caps) ==
                 *drawState.fCachedOptState);
#endif
    }
    drawState.fCachedOptState->ref();
    return drawState.fCachedOptState;
}

void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
                                        const GrDrawTargetCaps& caps,
                                        int firstCoverageStageIdx,
                                        bool* separateCoverageFromColor) {
    // Set this default and then possibly change our mind if there is coverage.
    fPrimaryOutputType = kModulate_PrimaryOutputType;
    fSecondaryOutputType = kNone_SecondaryOutputType;

    // If we do have coverage determine whether it matters.
    *separateCoverageFromColor = this->hasGeometryProcessor();
    if (!this->isCoverageDrawing() &&
        (ds.numCoverageStages() - firstCoverageStageIdx > 0 ||
         ds.hasGeometryProcessor() ||
         this->hasCoverageVertexAttribute())) {

        if (caps.dualSourceBlendingSupport()) {
            if (kZero_GrBlendCoeff == fDstBlend) {
                // write the coverage value to second color
                fSecondaryOutputType =  kCoverage_SecondaryOutputType;
                *separateCoverageFromColor = true;
                fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
            } else if (kSA_GrBlendCoeff == fDstBlend) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
                *separateCoverageFromColor = true;
                fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
            } else if (kSC_GrBlendCoeff == fDstBlend) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
                *separateCoverageFromColor = true;
                fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
            }
        } else if (fReadsDst &&
                   kOne_GrBlendCoeff == fSrcBlend &&
                   kZero_GrBlendCoeff == fDstBlend) {
            fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
            *separateCoverageFromColor = true;
        }
    }
}

void GrOptDrawState::adjustFromBlendOpts(const GrDrawState& ds,
                                         int* firstColorStageIdx,
                                         int* firstCoverageStageIdx,
                                         uint8_t* fixedFunctionVAToRemove) {
    switch (fBlendOptFlags) {
        case kNone_BlendOpt:
        case kSkipDraw_BlendOptFlag:
            break;
        case kCoverageAsAlpha_BlendOptFlag:
            fFlagBits |= kCoverageDrawing_StateBit;
            break;
        case kEmitCoverage_BlendOptFlag:
            fColor = 0xffffffff;
            fInputColorIsUsed = true;
            *firstColorStageIdx = ds.numColorStages();
            *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
            break;
        case kEmitTransBlack_BlendOptFlag:
            fColor = 0;
            fCoverage = 0xff;
            fInputColorIsUsed = true;
            fInputCoverageIsUsed = true;
            *firstColorStageIdx = ds.numColorStages();
            *firstCoverageStageIdx = ds.numCoverageStages();
            *fixedFunctionVAToRemove |= (0x1 << kColor_GrVertexAttribBinding |
                                         0x1 << kCoverage_GrVertexAttribBinding);
            break;
        default:
            SkFAIL("Unknown BlendOptFlag");
    }
}

void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
    int numToRemove = 0;
    uint8_t maskCheck = 0x1;
    // Count the number of vertex attributes that we will actually remove
    for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
        if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
            ++numToRemove;
        }
        maskCheck <<= 1;
    }

    fOptVA.reset(fVACount - numToRemove);

    GrVertexAttrib* dst = fOptVA.get();
    const GrVertexAttrib* src = fVAPtr;

    for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) {
        const GrVertexAttrib& currAttrib = *src;
        if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
            uint8_t maskCheck = 0x1 << currAttrib.fBinding;
            if (maskCheck & removeVAFlag) {
                SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
                fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
                continue;
            }
            fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
        }
        memcpy(dst, src, sizeof(GrVertexAttrib));
        ++newIdx;
        ++dst;
    }
    fVACount -= numToRemove;
    fVAPtr = fOptVA.get();
}

void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds, int* firstColorStageIdx,
                                                 uint8_t* fixedFunctionVAToRemove) {
    // Set up color and flags for ConstantColorComponent checks
    GrProcessor::InvariantOutput inout;
    inout.fIsSingleComponent = false;
    if (!this->hasColorVertexAttribute()) {
        inout.fColor = ds.getColor();
        inout.fValidFlags = kRGBA_GrColorComponentFlags;
    } else {
        if (ds.vertexColorsAreOpaque()) {
            inout.fColor = 0xFF << GrColor_SHIFT_A;
            inout.fValidFlags = kA_GrColorComponentFlag;
        } else {
            inout.fValidFlags = 0;
            // not strictly necessary but we get false alarms from tools about uninit.
            inout.fColor = 0;
        }
    }

    for (int i = 0; i < ds.numColorStages(); ++i) {
        const GrFragmentProcessor* fp = ds.getColorStage(i).getProcessor();
        fp->computeInvariantOutput(&inout);
        if (!inout.fWillUseInputColor) {
            *firstColorStageIdx = i;
            fInputColorIsUsed = false;
        }
        if (kRGBA_GrColorComponentFlags == inout.fValidFlags) {
            *firstColorStageIdx = i + 1;
            fColor = inout.fColor;
            fInputColorIsUsed = true;
            *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
            // Since we are clearing all previous color stages we are in a state where we have found
            // zero stages that don't multiply the inputColor.
            inout.fNonMulStageFound = false;
        }
    }
}

void GrOptDrawState::computeEffectiveCoverageStages(const GrDrawState& ds,
                                                    int* firstCoverageStageIdx) {
    // We do not try to optimize out constantColor coverage effects here. It is extremely rare
    // to have a coverage effect that returns a constant value for all four channels. Thus we
    // save having to make extra virtual calls by not checking for it.

    // Don't do any optimizations on coverage stages. It should not be the case where we do not use
    // input coverage in an effect
#ifdef OptCoverageStages
    GrProcessor::InvariantOutput inout;
    for (int i = 0; i < ds.numCoverageStages(); ++i) {
        const GrFragmentProcessor* fp = ds.getCoverageStage(i).getProcessor();
        fp->computeInvariantOutput(&inout);
        if (!inout.fWillUseInputColor) {
            *firstCoverageStageIdx = i;
            fInputCoverageIsUsed = false;
        }
    }
#endif
}

static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
    if (stage.getProcessor()->willReadDstColor()) {
        *readsDst = true;
    }
    if (stage.getProcessor()->willReadFragmentPosition()) {
        *readsFragPosition = true;
    }
}

void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx,
                                   int firstCoverageStageIdx) {
    // We will need a local coord attrib if there is one currently set on the optState and we are
    // actually generating some effect code
    fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() &&
        ds.numTotalStages() - firstColorStageIdx - firstCoverageStageIdx > 0;

    fReadsDst = false;
    fReadsFragPosition = false;

    for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) {
        const GrFragmentStage& stage = ds.getColorStage(s);
        get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
    }
    for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
        const GrFragmentStage& stage = ds.getCoverageStage(s);
        get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
    }
    if (ds.hasGeometryProcessor()) {
        const GrGeometryProcessor& gp = *ds.getGeometryProcessor();
        fReadsFragPosition = fReadsFragPosition || gp.willReadFragmentPosition();
    }
}

////////////////////////////////////////////////////////////////////////////////

bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
    return this->isEqual(that);
}

bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
    bool usingVertexColors = this->hasColorVertexAttribute();
    if (!usingVertexColors && this->fColor != that.fColor) {
        return false;
    }

    if (this->getRenderTarget() != that.getRenderTarget() ||
        this->fFragmentStages.count() != that.fFragmentStages.count() ||
        this->fNumColorStages != that.fNumColorStages ||
        !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
        this->fSrcBlend != that.fSrcBlend ||
        this->fDstBlend != that.fDstBlend ||
        this->fBlendConstant != that.fBlendConstant ||
        this->fFlagBits != that.fFlagBits ||
        this->fVACount != that.fVACount ||
        this->fVAStride != that.fVAStride ||
        memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
        this->fStencilSettings != that.fStencilSettings ||
        this->fDrawFace != that.fDrawFace ||
        this->fInputColorIsUsed != that.fInputColorIsUsed ||
        this->fInputCoverageIsUsed != that.fInputCoverageIsUsed ||
        this->fReadsDst != that.fReadsDst ||
        this->fReadsFragPosition != that.fReadsFragPosition ||
        this->fRequiresLocalCoordAttrib != that.fRequiresLocalCoordAttrib ||
        this->fPrimaryOutputType != that.fPrimaryOutputType ||
        this->fSecondaryOutputType != that.fSecondaryOutputType) {
        return false;
    }

    bool usingVertexCoverage = this->hasCoverageVertexAttribute();
    if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
        return false;
    }

    bool explicitLocalCoords = this->hasLocalCoordAttribute();
    if (this->hasGeometryProcessor()) {
        if (!that.hasGeometryProcessor()) {
            return false;
        } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
            return false;
        }
    } else if (that.hasGeometryProcessor()) {
        return false;
    }

    for (int i = 0; i < this->numFragmentStages(); i++) {
        if (!GrFragmentStage::AreCompatible(this->getFragmentStage(i), that.getFragmentStage(i),
                                            explicitLocalCoords)) {
            return false;
        }
    }

    SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices,
                         that.fFixedFunctionVertexAttribIndices,
                         sizeof(this->fFixedFunctionVertexAttribIndices)));

    return true;
}

<|endoftext|>