<commit_before>#ifndef RUNNER_INTERPRETER_VISIT_HXX
# define RUNNER_INTERPRETER_VISIT_HXX

# include <boost/bind.hpp>

# include <libport/compiler.hh>
# include <libport/finally.hh>
# include <libport/foreach.hh>

# include <ast/all.hh>
# include <ast/print.hh>

# include <kernel/exception.hh>
# include <kernel/uconnection.hh>

# include <object/code-class.hh>
# include <object/global-class.hh>
# include <object/list-class.hh>
# include <object/tag-class.hh>
# include <object/symbols.hh>

# include <runner/interpreter.hh>

# include <libport/compilation.hh>

/// Job echo.
#define JECHO(Title, Content)                           \
  ECHO ("job " << ME << ", " Title ": " << Content)

/// Job & astecho.
#define JAECHO(Title, Ast)                      \
  JECHO (Title, AST(Ast))

/* Yield and trace. */
#define YIELD()                                 \
  do                                            \
  {                                             \
    ECHO ("job " << ME << " yielding on AST: "  \
	  << &e << ' ' << AST(e));              \
    yield ();                                   \
  } while (0)

namespace runner
{
  using boost::bind;
  using libport::Finally;

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::And* e)
  {
    // Collect all subrunners
    scheduler::jobs_type jobs;

    // Create separate runners for every child but the first
    foreach (const ast::rConstExp& child,
             boost::make_iterator_range(e->children_get(), 1, 0))
    {
      Interpreter* job = new Interpreter(*this, eval(child));
      // Propagate errors from subrunners.
      link(job);
      jobs.push_back(job);
      job->start_job();
    }

    // Evaluate the first child in this runner
    rRoutine code = eval(e->children_get().front()).unsafe_cast<object::Code>();
    assert(code);
    // This is a closure, it won't use its 'this'
    object::objects_type args;
    args.push_back(rObject());
    apply_urbi(code, SYMBOL(), args, 0);

    // Wait for all other jobs to terminate
    yield_until_terminated(jobs);

    return object::void_class;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::LocalAssignment* e)
  {
    rObject val = eval(e->value_get());
    stacks_.set(e, val);
    return val;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Call* e)
  {
    // The invoked slot (probably a function).
    const ast::rConstExp& ast_tgt = e->target_get();
    rObject tgt = ast_tgt->implicit() ? stacks_.self() : eval(ast_tgt);
    return apply(tgt, e->name_get(), e->arguments_get(), e->location_get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::CallMsg*)
  {
    return stacks_.call();
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::LocalDeclaration* d)
  {
    rObject val = eval(d->value_get());
    stacks_.def(d, val);
    return val;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Float* e)
  {
    return new object::Float(e->value_get());
  }

  LIBPORT_SPEED_INLINE object::rObject Interpreter::visit(const ast::Routine* e, bool closure)
  {
    rRoutine res = make_routine(e);

    // Capture variables
    foreach (const ast::rLocalDeclaration& dec,
             *e->captured_variables_get())
    {
      ast::rLocal local = dec->value_get().unsafe_cast<ast::Local>();
      assert(local);
      res->captures_get().push_back(stacks_.rget(local));
    }

    // Capture 'this' and 'call' in closures
    if (closure)
    {
      res->self_get() = stacks_.self();
      res->call_get() = stacks_.call();
    }

    return res;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Function* e)
  {
    return visit(e, false);
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Closure* e)
  {
    return visit(e, true);
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::If* e)
  {
    // Evaluate the test.
    JAECHO ("test", e->test_get ());
    rObject cond = operator()(e->test_get().get());

    if (object::is_true(cond, SYMBOL(if)))
    {
      JAECHO ("then", e->thenclause_get());
      return e->thenclause_get()->eval(*this);
    }
    else
    {
      JAECHO ("else", e->elseclause_get());
      return e->elseclause_get()->eval(*this);
    }
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::List* e)
  {
    object::List::value_type res;
    // Evaluate every expression in the list
    foreach (const ast::rConstExp& c, e->value_get())
    {
      rObject v = eval(c);
      // Refuse void in literal lists
      if (v == object::void_class)
      {
        object::WrongArgumentType e(SYMBOL(new));
        e.location_set(c->location_get());
        throw e;
      }
      res.push_back(v);
    }
    return new object::List(res);
    //ECHO ("result: " << *result_);
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Lazy* e)
  {
    return operator()(e->strict_get().get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Local* e)
  {
    const rObject& value = stacks_.get(e);

    passert("Local variable read before being set", value);

    if (e->arguments_get())
      // FIXME: Register in the call stack
      return apply(stacks_.self(), value,
                   e->name_get(), e->arguments_get(),
                   e->location_get());
    else
      return value;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Message* e)
  {
    send_message(e->tag_get(), e->text_get());
    return object::void_class;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Nary* e)
  {
    // List of runners for Stmt flavored by a comma.
    scheduler::jobs_type runners;

    // In case we're empty, {} evaluates to void.
    rObject res = object::void_class;

    bool tail = false;
    foreach (const ast::rConstExp& c, e->children_get())
    {
      // Allow some time to pass before we execute what follows.  If
      // we don't do this, the ;-operator would act almost like the
      // |-operator because it would always start to execute its RHS
      // immediately. However, we don't want to do it before the first
      // statement or if we only have one statement in the scope.
      if (tail++)
	YIELD();

      JAECHO("child", c);

      if (c.unsafe_cast<const ast::Stmt>() &&
	  c.unsafe_cast<const ast::Stmt>()->flavor_get() == ast::flavor_comma)
      {
	// The new runners are attached to the same tags as we are.
	Interpreter* subrunner = new Interpreter(*this, eval(c));
	// If the subrunner throws an exception, propagate it here ASAP, unless
	// we are at the top level.
	if (!e->toplevel_get())
	  link(subrunner);
	runners.push_back(subrunner);
	subrunner->start_job ();
      }
      else
      {
	// If at toplevel, print errors and continue, else rethrow them
	try
	{
          // We do not use operator() to avoid duplicating the catch
          // of UrbiExceptions
          res = c->eval(*this);
	  // We need to keep checking for void here because it can not be passed
	  // to the << function
	  if (e->toplevel_get()
              && res.get() // FIXME: What's that for?
              && res != object::void_class)
	  {
	    try
	    {
	      assertion(res);
	      ECHO("toplevel: returning a result to the connection.");

	      // Display the value using the topLevel channel.
	      // If it is not (yet) defined, do nothing, unless the environment
	      // variable TOPLEVEL_DEBUG is set.

	      static bool toplevel_debug = getenv("TOPLEVEL_DEBUG");
	      if (rObject topLevel =
	        object::global_class->slot_locate(SYMBOL(topLevel), false,
		  true))
	      {
		rObject e = topLevel->slot_get(SYMBOL(LT_LT));
                objects_type args;
                args.push_back(topLevel);
                args.push_back(res);
		apply(e, SYMBOL(topLevel), args);
	      }
	      else if (toplevel_debug)
		lobby_->value_get().connection.new_result(res);
	    }
	    catch (std::exception &ke)
	    {
	      std::cerr << "Exception when printing result: "
                        << ke.what() << std::endl;
	    }
	    catch (object::UrbiException& e)
	    {
	      throw;
	    }
	    catch (...)
	    {
	      std::cerr << "Unknown exception when printing result"
                        << std::endl;
	    }
	  }
	}
	catch (object::UrbiException& ue)
	{
          propagate_error_(ue, c->location_get());
	  if (e->toplevel_get())
	    show_error_(ue);
	  else
	    throw;
	}
      }
    }

    // If the Nary is not the toplevel one, all subrunners must be finished when
    // the runner exits the Nary node. However, it we have a scopeTag, we must
    // issue a "stop" which may interrupt subrunners.
    if (!e->toplevel_get() && !runners.empty())
    {
      const scheduler::rTag& tag = scope_tag_get();
      if (tag)
	tag->stop(scheduler_get(), object::void_class);
      yield_until_terminated(runners);
    }

    return res;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Noop*)
  {
    return object::void_class;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Pipe* e)
  {
    object::rObject res;

    // Run all child without yielding
    foreach (const ast::rConstExp& child, e->children_get())
      res = operator()(child.get());

    return res;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Scope* e)
  {
    libport::Finally finally;
    create_scope_tag();
    finally << boost::bind(&Interpreter::cleanup_scope_tag, this);
    finally << libport::restore(non_interruptible_);
    return operator()(e->body_get().get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Do* e)
  {
    Finally finally;

    rObject tgt = eval(e->target_get());

    finally << stacks_.switch_self(tgt);

    visit(static_cast<const ast::Scope*>(e));
    // This is arguable. Do, just like Scope, should maybe return
    // their last inner value.
    return tgt;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Stmt* e)
  {
    JAECHO ("expression", e->expression_get());
    return operator()(e->expression_get().get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::String* e)
  {
    return new object::String(libport::Symbol(e->value_get()));
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Tag* t)
  {
    return eval_tag(t->exp_get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::TaggedStmt* t)
  {
    int result_depth = tags_get().size();
    try
    {
      // FIXME: might be simplified after type checking code is moved
      // to Object
      object::rObject unchecked_tag = eval(t->tag_get());
      object::type_check<object::Tag>(unchecked_tag, SYMBOL(tagged_stmt));
      const object::rTag& urbi_tag = unchecked_tag->as<object::Tag>();
      const scheduler::rTag& tag = urbi_tag->value_get();

      // If tag is blocked, do not start and ignore the
      // statement completely but use the provided payload.
      if (tag->blocked())
	return boost::any_cast<rObject>(tag->payload_get());

      push_tag (tag);
      Finally finally(bind(&Interpreter::pop_tag, this));
      // If the latest tag causes us to be frozen, let the
      // scheduler handle this properly to avoid duplicating the
      // logic.
      if (tag->frozen())
	yield();
      urbi_tag->triggerEnter(*this);
      rObject res = eval (t->exp_get());
      urbi_tag->triggerLeave(*this);
      return res;
    }
    catch (scheduler::StopException& e)
    {
      // Rewind up to the appropriate depth.
      if (e.depth_get() < result_depth)
	throw;
      // Extract the value from the exception.
      return boost::any_cast<rObject>(e.payload_get());
      // If we are frozen, reenter the scheduler for a while.
      if (frozen())
	yield();
    }
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::This*)
  {
    return stacks_.self();
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::While* e)
  {
    const bool must_yield = e->flavor_get() == ast::flavor_semicolon;
    bool tail = false;
    // Evaluate the test.
    while (true)
    {
      if (must_yield && tail++)
	YIELD();
      JAECHO ("while test", e->test_get());
      rObject cond = operator()(e->test_get().get());
      if (!object::is_true(cond, SYMBOL(while)))
	break;

      JAECHO ("while body", e->body_get());

      e->body_get()->eval(*this);
    }
    return object::void_class;
  }

  // Invalid nodes
#define INVALID(Node)                                      \
  LIBPORT_SPEED_INLINE object::rObject                     \
  Interpreter::visit(const ast::Node* n)                   \
  {                                                        \
    static_cast<void>(n);                                  \
    pabort("Invalid node in the Interpreter: " << *n);     \
  }                                                        \

  INVALID(Assignment);
  INVALID(Binding);
  INVALID(Break);
  INVALID(Continue);
  INVALID(Declaration);
  INVALID(Decrementation);
  INVALID(Delete);
  INVALID(Foreach);
  INVALID(Implicit);
  INVALID(Incrementation);
  INVALID(MetaCall);
  INVALID(MetaExp);
  INVALID(MetaLValue);
  INVALID(OpAssignment);
  INVALID(PropertyRead);
  INVALID(PropertyWrite);
  INVALID(Return);

#undef INVALID

}

#endif
<commit_msg>Skip statements when evaluating a nary.<commit_after>#ifndef RUNNER_INTERPRETER_VISIT_HXX
# define RUNNER_INTERPRETER_VISIT_HXX

# include <boost/bind.hpp>

# include <libport/compiler.hh>
# include <libport/finally.hh>
# include <libport/foreach.hh>

# include <ast/all.hh>
# include <ast/print.hh>

# include <kernel/exception.hh>
# include <kernel/uconnection.hh>

# include <object/code-class.hh>
# include <object/global-class.hh>
# include <object/list-class.hh>
# include <object/tag-class.hh>
# include <object/symbols.hh>

# include <runner/interpreter.hh>

# include <libport/compilation.hh>

/// Job echo.
#define JECHO(Title, Content)                           \
  ECHO ("job " << ME << ", " Title ": " << Content)

/// Job & astecho.
#define JAECHO(Title, Ast)                      \
  JECHO (Title, AST(Ast))

/* Yield and trace. */
#define YIELD()                                 \
  do                                            \
  {                                             \
    ECHO ("job " << ME << " yielding on AST: "  \
	  << &e << ' ' << AST(e));              \
    yield ();                                   \
  } while (0)

namespace runner
{
  using boost::bind;
  using libport::Finally;

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::And* e)
  {
    // Collect all subrunners
    scheduler::jobs_type jobs;

    // Create separate runners for every child but the first
    foreach (const ast::rConstExp& child,
             boost::make_iterator_range(e->children_get(), 1, 0))
    {
      Interpreter* job = new Interpreter(*this, eval(child));
      // Propagate errors from subrunners.
      link(job);
      jobs.push_back(job);
      job->start_job();
    }

    // Evaluate the first child in this runner
    rRoutine code = eval(e->children_get().front()).unsafe_cast<object::Code>();
    assert(code);
    // This is a closure, it won't use its 'this'
    object::objects_type args;
    args.push_back(rObject());
    apply_urbi(code, SYMBOL(), args, 0);

    // Wait for all other jobs to terminate
    yield_until_terminated(jobs);

    return object::void_class;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::LocalAssignment* e)
  {
    rObject val = eval(e->value_get());
    stacks_.set(e, val);
    return val;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Call* e)
  {
    // The invoked slot (probably a function).
    const ast::rConstExp& ast_tgt = e->target_get();
    rObject tgt = ast_tgt->implicit() ? stacks_.self() : eval(ast_tgt);
    return apply(tgt, e->name_get(), e->arguments_get(), e->location_get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::CallMsg*)
  {
    return stacks_.call();
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::LocalDeclaration* d)
  {
    rObject val = eval(d->value_get());
    stacks_.def(d, val);
    return val;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Float* e)
  {
    return new object::Float(e->value_get());
  }

  LIBPORT_SPEED_INLINE object::rObject Interpreter::visit(const ast::Routine* e, bool closure)
  {
    rRoutine res = make_routine(e);

    // Capture variables
    foreach (const ast::rLocalDeclaration& dec,
             *e->captured_variables_get())
    {
      ast::rLocal local = dec->value_get().unsafe_cast<ast::Local>();
      assert(local);
      res->captures_get().push_back(stacks_.rget(local));
    }

    // Capture 'this' and 'call' in closures
    if (closure)
    {
      res->self_get() = stacks_.self();
      res->call_get() = stacks_.call();
    }

    return res;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Function* e)
  {
    return visit(e, false);
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Closure* e)
  {
    return visit(e, true);
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::If* e)
  {
    // Evaluate the test.
    JAECHO ("test", e->test_get ());
    rObject cond = operator()(e->test_get().get());

    if (object::is_true(cond, SYMBOL(if)))
    {
      JAECHO ("then", e->thenclause_get());
      return e->thenclause_get()->eval(*this);
    }
    else
    {
      JAECHO ("else", e->elseclause_get());
      return e->elseclause_get()->eval(*this);
    }
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::List* e)
  {
    object::List::value_type res;
    // Evaluate every expression in the list
    foreach (const ast::rConstExp& c, e->value_get())
    {
      rObject v = eval(c);
      // Refuse void in literal lists
      if (v == object::void_class)
      {
        object::WrongArgumentType e(SYMBOL(new));
        e.location_set(c->location_get());
        throw e;
      }
      res.push_back(v);
    }
    return new object::List(res);
    //ECHO ("result: " << *result_);
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Lazy* e)
  {
    return operator()(e->strict_get().get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Local* e)
  {
    const rObject& value = stacks_.get(e);

    passert("Local variable read before being set", value);

    if (e->arguments_get())
      // FIXME: Register in the call stack
      return apply(stacks_.self(), value,
                   e->name_get(), e->arguments_get(),
                   e->location_get());
    else
      return value;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Message* e)
  {
    send_message(e->tag_get(), e->text_get());
    return object::void_class;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Nary* e)
  {
    // List of runners for Stmt flavored by a comma.
    scheduler::jobs_type runners;

    // In case we're empty, {} evaluates to void.
    rObject res = object::void_class;

    bool tail = false;
    foreach (const ast::rConstExp& c, e->children_get())
    {
      // Allow some time to pass before we execute what follows.  If
      // we don't do this, the ;-operator would act almost like the
      // |-operator because it would always start to execute its RHS
      // immediately. However, we don't want to do it before the first
      // statement or if we only have one statement in the scope.
      if (tail++)
	YIELD();

      JAECHO("child", c);

      const ast::Stmt* stmt = dynamic_cast<const ast::Stmt*>(c.get());
      const ast::Exp* exp = stmt ? stmt->expression_get().get() : c.get();

      if (stmt && stmt->flavor_get() == ast::flavor_comma)
      {
	// The new runners are attached to the same tags as we are.
	Interpreter* subrunner = new Interpreter(*this, operator()(exp));
	// If the subrunner throws an exception, propagate it here ASAP, unless
	// we are at the top level.
	if (!e->toplevel_get())
	  link(subrunner);
	runners.push_back(subrunner);
	subrunner->start_job ();
      }
      else
      {
	// If at toplevel, print errors and continue, else rethrow them
	try
	{
          // We do not use operator() to avoid duplicating the catch
          // of UrbiExceptions
          res = operator()(exp);
	  // We need to keep checking for void here because it can not be passed
	  // to the << function
	  if (e->toplevel_get()
              && res.get() // FIXME: What's that for?
              && res != object::void_class)
	  {
	    try
	    {
	      assertion(res);
	      ECHO("toplevel: returning a result to the connection.");

	      // Display the value using the topLevel channel.
	      // If it is not (yet) defined, do nothing, unless the environment
	      // variable TOPLEVEL_DEBUG is set.

	      static bool toplevel_debug = getenv("TOPLEVEL_DEBUG");
	      if (rObject topLevel =
	        object::global_class->slot_locate(SYMBOL(topLevel), false,
		  true))
	      {
		rObject e = topLevel->slot_get(SYMBOL(LT_LT));
                objects_type args;
                args.push_back(topLevel);
                args.push_back(res);
		apply(e, SYMBOL(topLevel), args);
	      }
	      else if (toplevel_debug)
		lobby_->value_get().connection.new_result(res);
	    }
	    catch (std::exception &ke)
	    {
	      std::cerr << "Exception when printing result: "
                        << ke.what() << std::endl;
	    }
	    catch (object::UrbiException& e)
	    {
	      throw;
	    }
	    catch (...)
	    {
	      std::cerr << "Unknown exception when printing result"
                        << std::endl;
	    }
	  }
	}
	catch (object::UrbiException& ue)
	{
          propagate_error_(ue, c->location_get());
	  if (e->toplevel_get())
	    show_error_(ue);
	  else
	    throw;
	}
      }
    }

    // If the Nary is not the toplevel one, all subrunners must be finished when
    // the runner exits the Nary node. However, it we have a scopeTag, we must
    // issue a "stop" which may interrupt subrunners.
    if (!e->toplevel_get() && !runners.empty())
    {
      const scheduler::rTag& tag = scope_tag_get();
      if (tag)
	tag->stop(scheduler_get(), object::void_class);
      yield_until_terminated(runners);
    }

    return res;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Noop*)
  {
    return object::void_class;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Pipe* e)
  {
    object::rObject res;

    // Run all child without yielding
    foreach (const ast::rConstExp& child, e->children_get())
      res = operator()(child.get());

    return res;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Scope* e)
  {
    libport::Finally finally;
    create_scope_tag();
    finally << boost::bind(&Interpreter::cleanup_scope_tag, this);
    finally << libport::restore(non_interruptible_);
    return operator()(e->body_get().get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Do* e)
  {
    Finally finally;

    rObject tgt = eval(e->target_get());

    finally << stacks_.switch_self(tgt);

    visit(static_cast<const ast::Scope*>(e));
    // This is arguable. Do, just like Scope, should maybe return
    // their last inner value.
    return tgt;
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Stmt* e)
  {
    JAECHO ("expression", e->expression_get());
    return operator()(e->expression_get().get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::String* e)
  {
    return new object::String(libport::Symbol(e->value_get()));
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::Tag* t)
  {
    return eval_tag(t->exp_get());
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::TaggedStmt* t)
  {
    int result_depth = tags_get().size();
    try
    {
      // FIXME: might be simplified after type checking code is moved
      // to Object
      object::rObject unchecked_tag = eval(t->tag_get());
      object::type_check<object::Tag>(unchecked_tag, SYMBOL(tagged_stmt));
      const object::rTag& urbi_tag = unchecked_tag->as<object::Tag>();
      const scheduler::rTag& tag = urbi_tag->value_get();

      // If tag is blocked, do not start and ignore the
      // statement completely but use the provided payload.
      if (tag->blocked())
	return boost::any_cast<rObject>(tag->payload_get());

      push_tag (tag);
      Finally finally(bind(&Interpreter::pop_tag, this));
      // If the latest tag causes us to be frozen, let the
      // scheduler handle this properly to avoid duplicating the
      // logic.
      if (tag->frozen())
	yield();
      urbi_tag->triggerEnter(*this);
      rObject res = eval (t->exp_get());
      urbi_tag->triggerLeave(*this);
      return res;
    }
    catch (scheduler::StopException& e)
    {
      // Rewind up to the appropriate depth.
      if (e.depth_get() < result_depth)
	throw;
      // Extract the value from the exception.
      return boost::any_cast<rObject>(e.payload_get());
      // If we are frozen, reenter the scheduler for a while.
      if (frozen())
	yield();
    }
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::This*)
  {
    return stacks_.self();
  }

  LIBPORT_SPEED_INLINE object::rObject
  Interpreter::visit(const ast::While* e)
  {
    const bool must_yield = e->flavor_get() == ast::flavor_semicolon;
    bool tail = false;
    // Evaluate the test.
    while (true)
    {
      if (must_yield && tail++)
	YIELD();
      JAECHO ("while test", e->test_get());
      rObject cond = operator()(e->test_get().get());
      if (!object::is_true(cond, SYMBOL(while)))
	break;

      JAECHO ("while body", e->body_get());

      e->body_get()->eval(*this);
    }
    return object::void_class;
  }

  // Invalid nodes
#define INVALID(Node)                                      \
  LIBPORT_SPEED_INLINE object::rObject                     \
  Interpreter::visit(const ast::Node* n)                   \
  {                                                        \
    static_cast<void>(n);                                  \
    pabort("Invalid node in the Interpreter: " << *n);     \
  }                                                        \

  INVALID(Assignment);
  INVALID(Binding);
  INVALID(Break);
  INVALID(Continue);
  INVALID(Declaration);
  INVALID(Decrementation);
  INVALID(Delete);
  INVALID(Foreach);
  INVALID(Implicit);
  INVALID(Incrementation);
  INVALID(MetaCall);
  INVALID(MetaExp);
  INVALID(MetaLValue);
  INVALID(OpAssignment);
  INVALID(PropertyRead);
  INVALID(PropertyWrite);
  INVALID(Return);

#undef INVALID

}

#endif
<|endoftext|>


<commit_before>#include "./TimedTaskChain.h"

#ifndef __TESTING_TIMEDTASKCHAIN__
#include "../../core/PWSprefs.h"
#endif

// static
int TimedTaskChain::DefaultTaskDelay()
{
#ifndef __TESTING_TIMEDTASKCHAIN__
    static const int defaultDelay = PWSprefs::GetInstance()->GetPref(PWSprefs::TimedTaskChainDelay);
#else
    static const int defaultDelay = 100;
#endif
    return defaultDelay;
}

// static
TimedTaskChain& TimedTaskChain::CreateTaskChain(std::initializer_list<TaskType> tasks)
{
    return *new TimedTaskChain(tasks);
}

// static
TimedTaskChain& TimedTaskChain::CreateTaskChain(const TaskType &task)
{
    return CreateTaskChain({task});
}

//static
TimedTaskChain& TimedTaskChain::CreateTaskChain(std::initializer_list<TaskWithInterval> tasks)
{
    return *new TimedTaskChain(tasks);
}

TimedTaskChain::TimedTaskChain(std::initializer_list<TaskType> tasks):   m_errorHandler(nullptr)
{
    for (auto t: tasks)
        m_tasks.push_back({t, DefaultTaskDelay()});

    // even if m_tasks is empty
    m_nextTask = m_tasks.begin();

    // if m_tasks is empty, it would get destructed in the next timer callback
    Next();
}

TimedTaskChain::TimedTaskChain(std::initializer_list<TaskWithInterval> tasks): m_errorHandler{nullptr},
                                                                            m_tasks{tasks},
                                                                            m_nextTask{m_tasks.begin()}
{
    Next();
}

void TimedTaskChain::Next()
{
    Start(m_nextTask->second, wxTIMER_ONE_SHOT);
}

void TimedTaskChain::RunTask()
{
    if (m_nextTask != m_tasks.end()) {
        try {
            m_nextTask->first();
            m_nextTask++;
        }
        catch(std::exception& e) {
            if (m_errorHandler)
                m_errorHandler(e);

            m_nextTask = m_tasks.end();
        }
        Next();
    }
    else {
        delete this;
    }
}

void TimedTaskChain::Notify()
{
    RunTask();
}

#ifdef __TESTING_TIMEDTASKCHAIN__
#include <wx/app.h>
#include <iostream>

/*
 * Use this to compile from vim
 *
 *      set makeprg=g++\ -std=c++11\ %\ `wx-config\ --cxxflags`\ `wx-config\ --libs`
 *
 * And this to run it from command-line
 *
 *      g++ -D__TESTING_TIMEDTASKCHAIN__ TimedTaskChain.cpp -std=c++11 `wx-config --cxxflags --libs`
 *
 *
 */

class TaskApp: public wxApp
{
    const char *errmsg{"Here we throw!"};
    int total{0};
    wxStopWatch watch;

    void Quit()
    {
        static int testsRunning = TestsToRun.size();
        if (--testsRunning == 0)
            ExitMainLoop();
    }

    void TestSequentialExecution()
    {
		TimedTaskChain::CreateTaskChain( [this]() { total = 10; } )
                                .then( [this]() { assert(total == 10); total *= 2; })
								.then( [this]() { assert(total == 20); total += 3; })
								.then( [this]() { assert(total == 23); total += 34; })
                                .then( [this]() { assert(total == 57); Quit(); });
    }

    void TestErrorHandling()
    {
		TimedTaskChain::CreateTaskChain( [](void) {  } )
                                .then( []() {  })
								.then( [this]() { throw std::logic_error(this->errmsg); })
								.then( []() { assert(!!"Task executed after exception was thrown!" ); })
                                .OnError( [this](const std::exception& e) { assert(strcmp(e.what(), this->errmsg) == 0); Quit(); } );
    }

    void TestTaskDelays()
    {
        watch.Start();
        TimedTaskChain::CreateTaskChain( {{[this](){ watch.Pause(); assert(watch.Time() >= 100); watch.Resume();}, 100}} )
                                .then( [this](){ watch.Pause(); assert(watch.Time() >= 500); watch.Resume();}, 500 )
                                .then( [this](){ watch.Pause(); assert(watch.Time() >= 50);  watch.Resume();}, 50  )
                                .then( [this](){ watch.Pause(); assert(watch.Time() >= 300); Quit();}, 300 );
    }

    typedef std::mem_fun_t<void, TaskApp> TestFunction;
    std::array<TestFunction, 3> TestsToRun ={ { std::mem_fun(&TaskApp::TestSequentialExecution),
                                                std::mem_fun(&TaskApp::TestErrorHandling),
                                                std::mem_fun(&TaskApp::TestTaskDelays)
                                              }
    };

public:
	bool OnInit()
	{
        for ( auto t: TestsToRun )
            t(this);

		return true;
	}
};

wxIMPLEMENT_APP(TaskApp);

#endif //__TESTING_TIMEDTASKCHAIN__
<commit_msg>Fix an out-of-bounds array access (bug 1290)<commit_after>#include "./TimedTaskChain.h"

#ifndef __TESTING_TIMEDTASKCHAIN__
#include "../../core/PWSprefs.h"
#endif

// static
int TimedTaskChain::DefaultTaskDelay()
{
#ifndef __TESTING_TIMEDTASKCHAIN__
    static const int defaultDelay = PWSprefs::GetInstance()->GetPref(PWSprefs::TimedTaskChainDelay);
#else
    static const int defaultDelay = 100;
#endif
    return defaultDelay;
}

// static
TimedTaskChain& TimedTaskChain::CreateTaskChain(std::initializer_list<TaskType> tasks)
{
    return *new TimedTaskChain(tasks);
}

// static
TimedTaskChain& TimedTaskChain::CreateTaskChain(const TaskType &task)
{
    return CreateTaskChain({task});
}

//static
TimedTaskChain& TimedTaskChain::CreateTaskChain(std::initializer_list<TaskWithInterval> tasks)
{
    return *new TimedTaskChain(tasks);
}

TimedTaskChain::TimedTaskChain(std::initializer_list<TaskType> tasks):   m_errorHandler(nullptr)
{
    for (auto t: tasks)
        m_tasks.push_back({t, DefaultTaskDelay()});

    // even if m_tasks is empty
    m_nextTask = m_tasks.begin();

    // if m_tasks is empty, it would get destructed in the next timer callback
    Next();
}

TimedTaskChain::TimedTaskChain(std::initializer_list<TaskWithInterval> tasks): m_errorHandler{nullptr},
                                                                            m_tasks{tasks},
                                                                            m_nextTask{m_tasks.begin()}
{
    Next();
}

void TimedTaskChain::Next()
{
  Start(m_nextTask == m_tasks.end()? DefaultTaskDelay(): m_nextTask->second, wxTIMER_ONE_SHOT);
}

void TimedTaskChain::RunTask()
{
    if (m_nextTask != m_tasks.end()) {
        try {
            m_nextTask->first();
            m_nextTask++;
        }
        catch(std::exception& e) {
            if (m_errorHandler)
                m_errorHandler(e);

            m_nextTask = m_tasks.end();
        }
        Next();
    }
    else {
        delete this;
    }
}

void TimedTaskChain::Notify()
{
    RunTask();
}

#ifdef __TESTING_TIMEDTASKCHAIN__
#include <wx/app.h>
#include <iostream>

/*
 * Use this to compile from vim
 *
 *      set makeprg=g++\ -std=c++11\ %\ `wx-config\ --cxxflags`\ `wx-config\ --libs`
 *
 * And this to run it from command-line
 *
 *      g++ -D__TESTING_TIMEDTASKCHAIN__ TimedTaskChain.cpp -std=c++11 `wx-config --cxxflags --libs`
 *
 *
 */

class TaskApp: public wxApp
{
    const char *errmsg{"Here we throw!"};
    int total{0};
    wxStopWatch watch;

    void Quit()
    {
        static int testsRunning = TestsToRun.size();
        if (--testsRunning == 0)
            ExitMainLoop();
    }

    void TestSequentialExecution()
    {
		TimedTaskChain::CreateTaskChain( [this]() { total = 10; } )
                                .then( [this]() { assert(total == 10); total *= 2; })
								.then( [this]() { assert(total == 20); total += 3; })
								.then( [this]() { assert(total == 23); total += 34; })
                                .then( [this]() { assert(total == 57); Quit(); });
    }

    void TestErrorHandling()
    {
		TimedTaskChain::CreateTaskChain( [](void) {  } )
                                .then( []() {  })
								.then( [this]() { throw std::logic_error(this->errmsg); })
								.then( []() { assert(!!"Task executed after exception was thrown!" ); })
                                .OnError( [this](const std::exception& e) { assert(strcmp(e.what(), this->errmsg) == 0); Quit(); } );
    }

    void TestTaskDelays()
    {
        watch.Start();
        TimedTaskChain::CreateTaskChain( {{[this](){ watch.Pause(); assert(watch.Time() >= 100); watch.Resume();}, 100}} )
                                .then( [this](){ watch.Pause(); assert(watch.Time() >= 500); watch.Resume();}, 500 )
                                .then( [this](){ watch.Pause(); assert(watch.Time() >= 50);  watch.Resume();}, 50  )
                                .then( [this](){ watch.Pause(); assert(watch.Time() >= 300); Quit();}, 300 );
    }

    typedef std::mem_fun_t<void, TaskApp> TestFunction;
    std::array<TestFunction, 3> TestsToRun ={ { std::mem_fun(&TaskApp::TestSequentialExecution),
                                                std::mem_fun(&TaskApp::TestErrorHandling),
                                                std::mem_fun(&TaskApp::TestTaskDelays)
                                              }
    };

public:
	bool OnInit()
	{
        for ( auto t: TestsToRun )
            t(this);

		return true;
	}
};

wxIMPLEMENT_APP(TaskApp);

#endif //__TESTING_TIMEDTASKCHAIN__
<|endoftext|>


<commit_before>/*****************************************************************************
  bamAncillary.cpp

  (c) 2009 - Aaron Quinlan
  Hall Laboratory
  Department of Biochemistry and Molecular Genetics
  University of Virginia
  aaronquinlan@gmail.com

  Licensed under the GNU General Public License 2.0+ license.
******************************************************************************/
#include "BamAncillary.h"
using namespace std;

// 10   15   20      25    30               4000
// acccctttggacct---ataggga.................aaaa
// acccc---ggaccttttataggga.................aaaa
// 5M   3D 6M    2I 7M      20N             4M

namespace BamTools {
    void getBamBlocks(const BamAlignment &bam, const RefVector &refs,
                      vector<BED> &blocks, bool breakOnDeletionOps) {

    	CHRPOS currPosition = bam.Position;
        CHRPOS blockStart   = bam.Position;
        string chrom        = refs.at(bam.RefID).RefName;
        string name         = bam.Name;
        string strand       = "+";
        string score        = ToString(bam.MapQuality);
        if (bam.IsReverseStrand()) strand = "-";

    	vector<CigarOp>::const_iterator cigItr = bam.CigarData.begin();
    	vector<CigarOp>::const_iterator cigEnd = bam.CigarData.end();
        for ( ; cigItr != cigEnd; ++cigItr ) {
            if (cigItr->Type == 'M') {
                currPosition += cigItr->Length;
    			blocks.push_back( BED(chrom, blockStart, currPosition, name, score, strand) );
    			blockStart    = currPosition;
            }
            else if (cigItr->Type == 'D') {
                if (breakOnDeletionOps == false)
                    currPosition += cigItr->Length;
                else {
                    currPosition += cigItr->Length;
                    blockStart    = currPosition;
                }
            }
            else if (cigItr->Type == 'N') {
                currPosition += cigItr->Length;
                blockStart    = currPosition;            }
            else if (cigItr->Type == 'S' || cigItr->Type == 'H' || cigItr->Type == 'P' || cigItr->Type == 'I') {
                // do nothing
            }
            else {
                cerr << "Input error: invalid CIGAR type (" << cigItr->Type
    				<< ") for: " << bam.Name << endl;
    			exit(1);
            }
    	}
    }
}<commit_msg>Added newline to end of BamAncillary.cpp to avoid compile warnings.<commit_after>/*****************************************************************************
  bamAncillary.cpp

  (c) 2009 - Aaron Quinlan
  Hall Laboratory
  Department of Biochemistry and Molecular Genetics
  University of Virginia
  aaronquinlan@gmail.com

  Licensed under the GNU General Public License 2.0+ license.
******************************************************************************/
#include "BamAncillary.h"
using namespace std;

// 10   15   20      25    30               4000
// acccctttggacct---ataggga.................aaaa
// acccc---ggaccttttataggga.................aaaa
// 5M   3D 6M    2I 7M      20N             4M

namespace BamTools {
    void getBamBlocks(const BamAlignment &bam, const RefVector &refs,
                      vector<BED> &blocks, bool breakOnDeletionOps) {

    	CHRPOS currPosition = bam.Position;
        CHRPOS blockStart   = bam.Position;
        string chrom        = refs.at(bam.RefID).RefName;
        string name         = bam.Name;
        string strand       = "+";
        string score        = ToString(bam.MapQuality);
        if (bam.IsReverseStrand()) strand = "-";

    	vector<CigarOp>::const_iterator cigItr = bam.CigarData.begin();
    	vector<CigarOp>::const_iterator cigEnd = bam.CigarData.end();
        for ( ; cigItr != cigEnd; ++cigItr ) {
            if (cigItr->Type == 'M') {
                currPosition += cigItr->Length;
    			blocks.push_back( BED(chrom, blockStart, currPosition, name, score, strand) );
    			blockStart    = currPosition;
            }
            else if (cigItr->Type == 'D') {
                if (breakOnDeletionOps == false)
                    currPosition += cigItr->Length;
                else {
                    currPosition += cigItr->Length;
                    blockStart    = currPosition;
                }
            }
            else if (cigItr->Type == 'N') {
                currPosition += cigItr->Length;
                blockStart    = currPosition;            }
            else if (cigItr->Type == 'S' || cigItr->Type == 'H' || cigItr->Type == 'P' || cigItr->Type == 'I') {
                // do nothing
            }
            else {
                cerr << "Input error: invalid CIGAR type (" << cigItr->Type
    				<< ") for: " << bam.Name << endl;
    			exit(1);
            }
    	}
    }
}
<|endoftext|>


<commit_before>
#pragma once

#include "numerics/matrix_computations.hpp"

#include <utility>

#include "base/tags.hpp"
#include "numerics/fixed_arrays.hpp"
#include "numerics/unbounded_arrays.hpp"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace numerics {
namespace internal_matrix_computations {

using base::uninitialized;
using quantities::Abs;
using quantities::Pow;
using quantities::Sqrt;

template<typename Scalar_>
struct CholeskyDecompositionGenerator<UnboundedUpperTriangularMatrix<Scalar_>> {
  using Scalar = Scalar_;
  using Result = UnboundedUpperTriangularMatrix<SquareRoot<Scalar>>;
  static Result Uninitialized(UnboundedUpperTriangularMatrix<Scalar> const& u);
};

template<typename Scalar_, int columns>
struct CholeskyDecompositionGenerator<
    FixedUpperTriangularMatrix<Scalar_, columns>> {
  using Scalar = Scalar_;
  using Result = FixedUpperTriangularMatrix<SquareRoot<Scalar>, columns>;
  static Result Uninitialized(
      FixedUpperTriangularMatrix<Scalar, columns> const& u);
};

template<typename Scalar_>
struct ᵗRDRDecompositionGenerator<UnboundedVector<Scalar_>,
                                  UnboundedUpperTriangularMatrix<Scalar_>> {
  using Scalar = Scalar_;
  struct Result {
    UnboundedUpperTriangularMatrix<double> R;
    UnboundedVector<Scalar> D;
  };
  static Result Uninitialized(UnboundedUpperTriangularMatrix<Scalar> const& u);
};

template<typename Scalar_, int columns>
struct ᵗRDRDecompositionGenerator<
    FixedVector<Scalar_, columns>,
    FixedUpperTriangularMatrix<Scalar_, columns>> {
  using Scalar = Scalar_;
  struct Result {
    FixedUpperTriangularMatrix<double, columns> R;
    FixedVector<Scalar, columns> D;
  };
  static Result Uninitialized(
      FixedUpperTriangularMatrix<Scalar, columns> const& u);
};

template<typename LScalar, typename RScalar,
         template<typename S> typename TriangularMatrix>
struct SubstitutionGenerator<TriangularMatrix<LScalar>,
                             UnboundedVector<RScalar>> {
  using Result = UnboundedVector<Quotient<RScalar, LScalar>>;
  static Result Uninitialized(TriangularMatrix<LScalar> const& m);
};

template<typename LScalar, typename RScalar, int dimension,
         template<typename S, int d> typename TriangularMatrix>
struct SubstitutionGenerator<TriangularMatrix<LScalar, dimension>,
                             FixedVector<RScalar, dimension>> {
  using Result = FixedVector<Quotient<RScalar, LScalar>, dimension>;
  static Result Uninitialized(TriangularMatrix<LScalar, dimension> const& m);
};

template<typename MScalar, typename VScalar>
struct RayleighQuotientGenerator<UnboundedMatrix<MScalar>,
                                 UnboundedVector<VScalar>> {
  using Result = MScalar;
};

template<typename MScalar, typename VScalar, int dimension>
struct RayleighQuotientGenerator<FixedMatrix<MScalar, dimension, dimension>,
                                 FixedVector<VScalar, dimension>> {
  using Result = MScalar;
};

template<typename MScalar, typename VScalar>
struct SolveGenerator<UnboundedMatrix<MScalar>, UnboundedVector<VScalar>> {
  using Scalar = MScalar;
  using Result = UnboundedVector<Quotient<VScalar, MScalar>>;
  static UnboundedLowerTriangularMatrix<double> UninitializedL(
      UnboundedMatrix<MScalar> const& m);
  static UnboundedUpperTriangularMatrix<MScalar> UninitializedU(
      UnboundedMatrix<MScalar> const& m);
};

template<typename MScalar, typename VScalar, int rows, int columns>
struct SolveGenerator<FixedMatrix<MScalar, rows, columns>,
                      FixedVector<VScalar, rows>> {
  using Scalar = MScalar;
  using Result = FixedVector<Quotient<VScalar, MScalar>, columns>;
  static FixedLowerTriangularMatrix<double, rows> UninitializedL(
      FixedMatrix<MScalar, rows, columns> const& m);
  static FixedUpperTriangularMatrix<MScalar, columns> UninitializedU(
      FixedMatrix<MScalar, rows, columns> const& m);
};

template<typename Scalar_>
auto CholeskyDecompositionGenerator<UnboundedUpperTriangularMatrix<Scalar_>>::
Uninitialized(UnboundedUpperTriangularMatrix<Scalar> const& u) -> Result {
  return Result(u.columns(), uninitialized);
}

template<typename Scalar_, int columns>
auto CholeskyDecompositionGenerator<
    FixedUpperTriangularMatrix<Scalar_, columns>>::
Uninitialized(FixedUpperTriangularMatrix<Scalar, columns> const& u) -> Result {
  return Result(uninitialized);
}

template<typename Scalar_>
auto ᵗRDRDecompositionGenerator<UnboundedVector<Scalar_>,
                                UnboundedUpperTriangularMatrix<Scalar_>>::
Uninitialized(UnboundedUpperTriangularMatrix<Scalar> const& u) -> Result {
  return {UnboundedUpperTriangularMatrix<double>(u.columns(), uninitialized),
          UnboundedVector<Scalar>(u.columns(), uninitialized)};
}

template<typename Scalar_, int columns>
auto ᵗRDRDecompositionGenerator<FixedVector<Scalar_, columns>,
                                FixedUpperTriangularMatrix<Scalar_, columns>>::
Uninitialized(FixedUpperTriangularMatrix<Scalar, columns> const& u) -> Result {
  return {FixedUpperTriangularMatrix<double, columns>(uninitialized),
          FixedVector<Scalar, columns>(uninitialized)};
}

template<typename LScalar, typename RScalar,
         template<typename S> typename TriangularMatrix>
auto SubstitutionGenerator<TriangularMatrix<LScalar>,
                           UnboundedVector<RScalar>>::
Uninitialized(TriangularMatrix<LScalar> const& m) -> Result {
  return Result(m.columns(), uninitialized);
}

template<typename LScalar, typename RScalar, int dimension,
         template<typename S, int d> typename TriangularMatrix>
auto SubstitutionGenerator<TriangularMatrix<LScalar, dimension>,
                           FixedVector<RScalar, dimension>>::Uninitialized(
    TriangularMatrix<LScalar, dimension> const& m) -> Result {
  return Result(uninitialized);
}

template<typename MScalar, typename VScalar>
UnboundedLowerTriangularMatrix<double>
SolveGenerator<UnboundedMatrix<MScalar>, UnboundedVector<VScalar>>::
UninitializedL(UnboundedMatrix<MScalar> const& m) {
  return UnboundedLowerTriangularMatrix<double>(m.rows(), uninitialized);
}

template<typename MScalar, typename VScalar>
UnboundedUpperTriangularMatrix<MScalar>
SolveGenerator<UnboundedMatrix<MScalar>, UnboundedVector<VScalar>>::
UninitializedU(UnboundedMatrix<MScalar> const& m) {
  return UnboundedUpperTriangularMatrix<MScalar>(m.columns(), uninitialized);
}

template<typename MScalar, typename VScalar, int rows, int columns>
FixedLowerTriangularMatrix<double, rows>
SolveGenerator<FixedMatrix<MScalar, rows, columns>,
               FixedVector<VScalar, rows>>::
UninitializedL(FixedMatrix<MScalar, rows, columns> const& m) {
  return FixedLowerTriangularMatrix<double, rows>(uninitialized);
}

template<typename MScalar, typename VScalar, int rows, int columns>
FixedUpperTriangularMatrix<MScalar, columns>
SolveGenerator<FixedMatrix<MScalar, rows, columns>,
               FixedVector<VScalar, rows>>::
UninitializedU(FixedMatrix<MScalar, rows, columns> const& m) {
  return FixedUpperTriangularMatrix<MScalar, columns>(uninitialized);
}

// [Hig02], Algorithm 10.2.
template<typename UpperTriangularMatrix>
typename CholeskyDecompositionGenerator<UpperTriangularMatrix>::Result
CholeskyDecomposition(UpperTriangularMatrix const& A) {
  using G = CholeskyDecompositionGenerator<UpperTriangularMatrix>;
  using Scalar = typename G::Scalar;
  auto R = G::Uninitialized(A);
  for (int j = 0; j < A.columns(); ++j) {
    for (int i = 0; i < j; ++i) {
      Scalar Σrₖᵢrₖⱼ{};
      for (int k = 0; k < i; ++k) {
        Σrₖᵢrₖⱼ += R[k][i] * R[k][j];
      }
      R[i][j] = (A[i][j] - Σrₖᵢrₖⱼ) / R[i][i];
    }
    Scalar Σrₖⱼ²{};
    for (int k = 0; k < j; ++k) {
      Σrₖⱼ² += Pow<2>(R[k][j]);
    }
    // This will produce NaNs if the matrix is not positive definite.
    R[j][j] = Sqrt(A[j][j] - Σrₖⱼ²);
  }
  return R;
}

// [KM13], formulæ (10) and (11).
template<typename Vector, typename UpperTriangularMatrix>
typename ᵗRDRDecompositionGenerator<Vector, UpperTriangularMatrix>::Result
ᵗRDRDecomposition(UpperTriangularMatrix const& A) {
  using G = ᵗRDRDecompositionGenerator<Vector, UpperTriangularMatrix>;
  using Scalar = typename G::Scalar;
  auto result = G::Uninitialized(A);
  auto& R = result.R;
  auto& D = result.D;
  for (int i = 0; i < A.columns(); ++i) {
    Scalar Σrₖᵢ²dₖ{};
    for (int k = 0; k < i; ++k) {
      Σrₖᵢ²dₖ += Pow<2>(R[k][i]) * D[k];
    }
    D[i] = A[i][i] - Σrₖᵢ²dₖ;
    for (int j = i + 1; j < A.columns(); ++j) {
      Scalar Σrₖᵢrₖⱼdₖ{};
      for (int k = 0; k < i; ++k) {
        Σrₖᵢrₖⱼdₖ += R[k][i] * R[k][j] * D[k];
      }
      R[i][j] = (A[i][j] - Σrₖᵢrₖⱼdₖ) / D[i];
    }
    R[i][i] = 1;
  }
  return result;
}

// [Hig02], Algorithm 8.1.
template<typename UpperTriangularMatrix, typename Vector>
typename SubstitutionGenerator<UpperTriangularMatrix, Vector>::Result
BackSubstitution(UpperTriangularMatrix const& U,
                 Vector const& b) {
  using G = SubstitutionGenerator<UpperTriangularMatrix, Vector>;
  auto x = G::Uninitialized(U);
  int const n = x.size() - 1;
  x[n] = b[n] / U[n][n];
  for (int i = n - 1; i >= 0; --i) {
    auto s = b[i];
    for (int j = i + 1; j <= n; ++j) {
      s -= U[i][j] * x[j];
    }
    x[i] = s / U[i][i];
  }
  return x;
}

// [Hig02] says: "We will not state the analogous algorithm for solving a lower
// triangular system, forward substitution."  So we follow
// https://en.wikipedia.org/wiki/Triangular_matrix#Forward_substitution.
template<typename LowerTriangularMatrix, typename Vector>
typename SubstitutionGenerator<LowerTriangularMatrix, Vector>::Result
ForwardSubstitution(LowerTriangularMatrix const& L,
                    Vector const& b) {
  using G = SubstitutionGenerator<LowerTriangularMatrix, Vector>;
  auto x = G::Uninitialized(L);
  x[0] = b[0] / L[0][0];
  for (int i = 1; i < b.size(); ++i) {
    auto s = b[i];
    for (int j = 0; j < i; ++j) {
      s -= L[i][j] * x[j];
    }
    x[i] = s / L[i][i];
  }
  return x;
}

template<typename Matrix, typename Vector>
typename RayleighQuotientGenerator<Matrix, Vector>::Result RayleighQuotient(
    Matrix const& A, Vector const& x) {
  // [GV13], section 8.2.3.
  return x.Transpose() * (A * x) / (x.Transpose() * x);
}

template<typename Matrix, typename Vector>
typename SolveGenerator<Matrix, Vector>::Result
Solve(Matrix A, Vector b) {
  // This implementation follows [Hig02].
  using G = SolveGenerator<Matrix, Vector>;
  using Scalar = typename G::Scalar;

  // The units make it inconvenient to overlay L and U onto A.
  auto L = G::UninitializedL(A);
  auto U = G::UninitializedU(A);

  // Doolittle's method: write P * A = L * U where P is an implicit permutation
  // that is also applied to b.  See [Hig02], Algorithm 9.2 p. 162.
  for (int k = 0; k < A.columns(); ++k) {
    // Partial pivoting.
    int r = -1;
    Scalar max{};
    for (int i = k; i < A.rows(); ++i) {
      if (Abs(A[i][k]) > max) {
        r = i;
        max = Abs(A[i][k]);
      }
    }
    CHECK_LE(0, r) << A << " cannot pivot";
    CHECK_LT(r, A.rows()) << A << " cannot pivot";

    // Swap the rows of A.
    for (int i = 0; i < A.columns(); ++i) {
      std::swap(A[k][i], A[r][i]);
    }

    // Swap the rows of L.
    for (int i = 0; i < k; ++i) {
      std::swap(L[k][i], L[r][i]);
    }

    std::swap(b[k], b[r]);
    CHECK_NE(Scalar{}, A[k][k]) << A << " is singular";

    for (int j = k; j < A.columns(); ++j) {
      auto U_kj = A[k][j];
      for (int i = 0; i < k; ++i) {
        U_kj -= L[k][i] * U[i][j];
      }
      U[k][j] = U_kj;
    }
    for (int i = k + 1; i < A.rows(); ++i) {
      auto L_ik = A[i][k];
      for (int j = 0; j < k; ++j) {
        L_ik -= L[i][j] * U[j][k];
      }
      L[i][k] = L_ik / U[k][k];
    }
    L[k][k] = 1;
  }

  // For the resolution of triangular systems see [Hig02], Algorithm 8.1 p. 140.

  // Find y such that L * y = P * b.
  auto const y = ForwardSubstitution(L, b);
  // Find x such that U * x = y.
  auto const x = BackSubstitution(U, y);

  return x;
}

}  // namespace internal_matrix_computations
}  // namespace numerics
}  // namespace principia
<commit_msg>Silly include.<commit_after>
#pragma once

#include "numerics/matrix_computations.hpp"

#include <algorithm>

#include "base/tags.hpp"
#include "numerics/fixed_arrays.hpp"
#include "numerics/unbounded_arrays.hpp"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace numerics {
namespace internal_matrix_computations {

using base::uninitialized;
using quantities::Abs;
using quantities::Pow;
using quantities::Sqrt;

template<typename Scalar_>
struct CholeskyDecompositionGenerator<UnboundedUpperTriangularMatrix<Scalar_>> {
  using Scalar = Scalar_;
  using Result = UnboundedUpperTriangularMatrix<SquareRoot<Scalar>>;
  static Result Uninitialized(UnboundedUpperTriangularMatrix<Scalar> const& u);
};

template<typename Scalar_, int columns>
struct CholeskyDecompositionGenerator<
    FixedUpperTriangularMatrix<Scalar_, columns>> {
  using Scalar = Scalar_;
  using Result = FixedUpperTriangularMatrix<SquareRoot<Scalar>, columns>;
  static Result Uninitialized(
      FixedUpperTriangularMatrix<Scalar, columns> const& u);
};

template<typename Scalar_>
struct ᵗRDRDecompositionGenerator<UnboundedVector<Scalar_>,
                                  UnboundedUpperTriangularMatrix<Scalar_>> {
  using Scalar = Scalar_;
  struct Result {
    UnboundedUpperTriangularMatrix<double> R;
    UnboundedVector<Scalar> D;
  };
  static Result Uninitialized(UnboundedUpperTriangularMatrix<Scalar> const& u);
};

template<typename Scalar_, int columns>
struct ᵗRDRDecompositionGenerator<
    FixedVector<Scalar_, columns>,
    FixedUpperTriangularMatrix<Scalar_, columns>> {
  using Scalar = Scalar_;
  struct Result {
    FixedUpperTriangularMatrix<double, columns> R;
    FixedVector<Scalar, columns> D;
  };
  static Result Uninitialized(
      FixedUpperTriangularMatrix<Scalar, columns> const& u);
};

template<typename LScalar, typename RScalar,
         template<typename S> typename TriangularMatrix>
struct SubstitutionGenerator<TriangularMatrix<LScalar>,
                             UnboundedVector<RScalar>> {
  using Result = UnboundedVector<Quotient<RScalar, LScalar>>;
  static Result Uninitialized(TriangularMatrix<LScalar> const& m);
};

template<typename LScalar, typename RScalar, int dimension,
         template<typename S, int d> typename TriangularMatrix>
struct SubstitutionGenerator<TriangularMatrix<LScalar, dimension>,
                             FixedVector<RScalar, dimension>> {
  using Result = FixedVector<Quotient<RScalar, LScalar>, dimension>;
  static Result Uninitialized(TriangularMatrix<LScalar, dimension> const& m);
};

template<typename MScalar, typename VScalar>
struct RayleighQuotientGenerator<UnboundedMatrix<MScalar>,
                                 UnboundedVector<VScalar>> {
  using Result = MScalar;
};

template<typename MScalar, typename VScalar, int dimension>
struct RayleighQuotientGenerator<FixedMatrix<MScalar, dimension, dimension>,
                                 FixedVector<VScalar, dimension>> {
  using Result = MScalar;
};

template<typename MScalar, typename VScalar>
struct SolveGenerator<UnboundedMatrix<MScalar>, UnboundedVector<VScalar>> {
  using Scalar = MScalar;
  using Result = UnboundedVector<Quotient<VScalar, MScalar>>;
  static UnboundedLowerTriangularMatrix<double> UninitializedL(
      UnboundedMatrix<MScalar> const& m);
  static UnboundedUpperTriangularMatrix<MScalar> UninitializedU(
      UnboundedMatrix<MScalar> const& m);
};

template<typename MScalar, typename VScalar, int rows, int columns>
struct SolveGenerator<FixedMatrix<MScalar, rows, columns>,
                      FixedVector<VScalar, rows>> {
  using Scalar = MScalar;
  using Result = FixedVector<Quotient<VScalar, MScalar>, columns>;
  static FixedLowerTriangularMatrix<double, rows> UninitializedL(
      FixedMatrix<MScalar, rows, columns> const& m);
  static FixedUpperTriangularMatrix<MScalar, columns> UninitializedU(
      FixedMatrix<MScalar, rows, columns> const& m);
};

template<typename Scalar_>
auto CholeskyDecompositionGenerator<UnboundedUpperTriangularMatrix<Scalar_>>::
Uninitialized(UnboundedUpperTriangularMatrix<Scalar> const& u) -> Result {
  return Result(u.columns(), uninitialized);
}

template<typename Scalar_, int columns>
auto CholeskyDecompositionGenerator<
    FixedUpperTriangularMatrix<Scalar_, columns>>::
Uninitialized(FixedUpperTriangularMatrix<Scalar, columns> const& u) -> Result {
  return Result(uninitialized);
}

template<typename Scalar_>
auto ᵗRDRDecompositionGenerator<UnboundedVector<Scalar_>,
                                UnboundedUpperTriangularMatrix<Scalar_>>::
Uninitialized(UnboundedUpperTriangularMatrix<Scalar> const& u) -> Result {
  return {UnboundedUpperTriangularMatrix<double>(u.columns(), uninitialized),
          UnboundedVector<Scalar>(u.columns(), uninitialized)};
}

template<typename Scalar_, int columns>
auto ᵗRDRDecompositionGenerator<FixedVector<Scalar_, columns>,
                                FixedUpperTriangularMatrix<Scalar_, columns>>::
Uninitialized(FixedUpperTriangularMatrix<Scalar, columns> const& u) -> Result {
  return {FixedUpperTriangularMatrix<double, columns>(uninitialized),
          FixedVector<Scalar, columns>(uninitialized)};
}

template<typename LScalar, typename RScalar,
         template<typename S> typename TriangularMatrix>
auto SubstitutionGenerator<TriangularMatrix<LScalar>,
                           UnboundedVector<RScalar>>::
Uninitialized(TriangularMatrix<LScalar> const& m) -> Result {
  return Result(m.columns(), uninitialized);
}

template<typename LScalar, typename RScalar, int dimension,
         template<typename S, int d> typename TriangularMatrix>
auto SubstitutionGenerator<TriangularMatrix<LScalar, dimension>,
                           FixedVector<RScalar, dimension>>::Uninitialized(
    TriangularMatrix<LScalar, dimension> const& m) -> Result {
  return Result(uninitialized);
}

template<typename MScalar, typename VScalar>
UnboundedLowerTriangularMatrix<double>
SolveGenerator<UnboundedMatrix<MScalar>, UnboundedVector<VScalar>>::
UninitializedL(UnboundedMatrix<MScalar> const& m) {
  return UnboundedLowerTriangularMatrix<double>(m.rows(), uninitialized);
}

template<typename MScalar, typename VScalar>
UnboundedUpperTriangularMatrix<MScalar>
SolveGenerator<UnboundedMatrix<MScalar>, UnboundedVector<VScalar>>::
UninitializedU(UnboundedMatrix<MScalar> const& m) {
  return UnboundedUpperTriangularMatrix<MScalar>(m.columns(), uninitialized);
}

template<typename MScalar, typename VScalar, int rows, int columns>
FixedLowerTriangularMatrix<double, rows>
SolveGenerator<FixedMatrix<MScalar, rows, columns>,
               FixedVector<VScalar, rows>>::
UninitializedL(FixedMatrix<MScalar, rows, columns> const& m) {
  return FixedLowerTriangularMatrix<double, rows>(uninitialized);
}

template<typename MScalar, typename VScalar, int rows, int columns>
FixedUpperTriangularMatrix<MScalar, columns>
SolveGenerator<FixedMatrix<MScalar, rows, columns>,
               FixedVector<VScalar, rows>>::
UninitializedU(FixedMatrix<MScalar, rows, columns> const& m) {
  return FixedUpperTriangularMatrix<MScalar, columns>(uninitialized);
}

// [Hig02], Algorithm 10.2.
template<typename UpperTriangularMatrix>
typename CholeskyDecompositionGenerator<UpperTriangularMatrix>::Result
CholeskyDecomposition(UpperTriangularMatrix const& A) {
  using G = CholeskyDecompositionGenerator<UpperTriangularMatrix>;
  using Scalar = typename G::Scalar;
  auto R = G::Uninitialized(A);
  for (int j = 0; j < A.columns(); ++j) {
    for (int i = 0; i < j; ++i) {
      Scalar Σrₖᵢrₖⱼ{};
      for (int k = 0; k < i; ++k) {
        Σrₖᵢrₖⱼ += R[k][i] * R[k][j];
      }
      R[i][j] = (A[i][j] - Σrₖᵢrₖⱼ) / R[i][i];
    }
    Scalar Σrₖⱼ²{};
    for (int k = 0; k < j; ++k) {
      Σrₖⱼ² += Pow<2>(R[k][j]);
    }
    // This will produce NaNs if the matrix is not positive definite.
    R[j][j] = Sqrt(A[j][j] - Σrₖⱼ²);
  }
  return R;
}

// [KM13], formulæ (10) and (11).
template<typename Vector, typename UpperTriangularMatrix>
typename ᵗRDRDecompositionGenerator<Vector, UpperTriangularMatrix>::Result
ᵗRDRDecomposition(UpperTriangularMatrix const& A) {
  using G = ᵗRDRDecompositionGenerator<Vector, UpperTriangularMatrix>;
  using Scalar = typename G::Scalar;
  auto result = G::Uninitialized(A);
  auto& R = result.R;
  auto& D = result.D;
  for (int i = 0; i < A.columns(); ++i) {
    Scalar Σrₖᵢ²dₖ{};
    for (int k = 0; k < i; ++k) {
      Σrₖᵢ²dₖ += Pow<2>(R[k][i]) * D[k];
    }
    D[i] = A[i][i] - Σrₖᵢ²dₖ;
    for (int j = i + 1; j < A.columns(); ++j) {
      Scalar Σrₖᵢrₖⱼdₖ{};
      for (int k = 0; k < i; ++k) {
        Σrₖᵢrₖⱼdₖ += R[k][i] * R[k][j] * D[k];
      }
      R[i][j] = (A[i][j] - Σrₖᵢrₖⱼdₖ) / D[i];
    }
    R[i][i] = 1;
  }
  return result;
}

// [Hig02], Algorithm 8.1.
template<typename UpperTriangularMatrix, typename Vector>
typename SubstitutionGenerator<UpperTriangularMatrix, Vector>::Result
BackSubstitution(UpperTriangularMatrix const& U,
                 Vector const& b) {
  using G = SubstitutionGenerator<UpperTriangularMatrix, Vector>;
  auto x = G::Uninitialized(U);
  int const n = x.size() - 1;
  x[n] = b[n] / U[n][n];
  for (int i = n - 1; i >= 0; --i) {
    auto s = b[i];
    for (int j = i + 1; j <= n; ++j) {
      s -= U[i][j] * x[j];
    }
    x[i] = s / U[i][i];
  }
  return x;
}

// [Hig02] says: "We will not state the analogous algorithm for solving a lower
// triangular system, forward substitution."  So we follow
// https://en.wikipedia.org/wiki/Triangular_matrix#Forward_substitution.
template<typename LowerTriangularMatrix, typename Vector>
typename SubstitutionGenerator<LowerTriangularMatrix, Vector>::Result
ForwardSubstitution(LowerTriangularMatrix const& L,
                    Vector const& b) {
  using G = SubstitutionGenerator<LowerTriangularMatrix, Vector>;
  auto x = G::Uninitialized(L);
  x[0] = b[0] / L[0][0];
  for (int i = 1; i < b.size(); ++i) {
    auto s = b[i];
    for (int j = 0; j < i; ++j) {
      s -= L[i][j] * x[j];
    }
    x[i] = s / L[i][i];
  }
  return x;
}

template<typename Matrix, typename Vector>
typename RayleighQuotientGenerator<Matrix, Vector>::Result RayleighQuotient(
    Matrix const& A, Vector const& x) {
  // [GV13], section 8.2.3.
  return x.Transpose() * (A * x) / (x.Transpose() * x);
}

template<typename Matrix, typename Vector>
typename SolveGenerator<Matrix, Vector>::Result
Solve(Matrix A, Vector b) {
  // This implementation follows [Hig02].
  using G = SolveGenerator<Matrix, Vector>;
  using Scalar = typename G::Scalar;

  // The units make it inconvenient to overlay L and U onto A.
  auto L = G::UninitializedL(A);
  auto U = G::UninitializedU(A);

  // Doolittle's method: write P * A = L * U where P is an implicit permutation
  // that is also applied to b.  See [Hig02], Algorithm 9.2 p. 162.
  for (int k = 0; k < A.columns(); ++k) {
    // Partial pivoting.
    int r = -1;
    Scalar max{};
    for (int i = k; i < A.rows(); ++i) {
      if (Abs(A[i][k]) > max) {
        r = i;
        max = Abs(A[i][k]);
      }
    }
    CHECK_LE(0, r) << A << " cannot pivot";
    CHECK_LT(r, A.rows()) << A << " cannot pivot";

    // Swap the rows of A.
    for (int i = 0; i < A.columns(); ++i) {
      std::swap(A[k][i], A[r][i]);
    }

    // Swap the rows of L.
    for (int i = 0; i < k; ++i) {
      std::swap(L[k][i], L[r][i]);
    }

    std::swap(b[k], b[r]);
    CHECK_NE(Scalar{}, A[k][k]) << A << " is singular";

    for (int j = k; j < A.columns(); ++j) {
      auto U_kj = A[k][j];
      for (int i = 0; i < k; ++i) {
        U_kj -= L[k][i] * U[i][j];
      }
      U[k][j] = U_kj;
    }
    for (int i = k + 1; i < A.rows(); ++i) {
      auto L_ik = A[i][k];
      for (int j = 0; j < k; ++j) {
        L_ik -= L[i][j] * U[j][k];
      }
      L[i][k] = L_ik / U[k][k];
    }
    L[k][k] = 1;
  }

  // For the resolution of triangular systems see [Hig02], Algorithm 8.1 p. 140.

  // Find y such that L * y = P * b.
  auto const y = ForwardSubstitution(L, b);
  // Find x such that U * x = y.
  auto const x = BackSubstitution(U, y);

  return x;
}

}  // namespace internal_matrix_computations
}  // namespace numerics
}  // namespace principia
<|endoftext|>


<commit_before>#include "StdAfx.h"
#include "Setup.h"

class SCRIPT_DECL WarsongGulchBattlemaster : public GossipScript
{
public:
    void GossipHello(Object* pObject, Player * plr, bool AutoSend)
    {
        GossipMenu *Menu;
        uint32 Team = plr->GetTeam();
        if(Team > 1) Team = 1;

        // Check if the player can be entered into the bg or not.
        if(plr->getLevel() < 10)
        {
            uint32 FactMessages[2] = { 7599, 7688 };

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
        }
        else
        {
            uint32 FactMessages[2] = { 7689, 7705 }; // need to find the second one

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
            Menu->AddItem( 0, "I would like to enter the battleground.", 1);
        }

        if(AutoSend)
            Menu->SendTo(plr);
    }

    void GossipSelectOption(Object* pObject, Player * plr, uint32 Id, uint32 IntId, const char * Code)
    {
        // Send battleground list.
		if(pObject->GetTypeId()!=TYPEID_UNIT)
			return;

        plr->GetSession()->SendBattlegroundList(((Creature*)pObject), 2);  // WSG = 2
    }

    void Destroy()
    {
        delete this;
    }
};

class SCRIPT_DECL ArathiBasinBattlemaster : public GossipScript
{
public:
    void GossipHello(Object* pObject, Player * plr, bool AutoSend)
    {
        GossipMenu *Menu;
        uint32 Team = plr->GetTeam();
        if(Team > 1) Team = 1;

        // Check if the player can be entered into the bg or not.
        if(plr->getLevel() < 20)
        {
            uint32 FactMessages[2] = { 7700, 7667 };

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
        }
        else
        {
            uint32 FactMessages[2] = { 7700, 7555 }; // need to find the second one

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
            Menu->AddItem( 0, "I would like to enter the battleground.", 1);
        }

        if(AutoSend)
            Menu->SendTo(plr);
    }

    void GossipSelectOption(Object* pObject, Player * plr, uint32 Id, uint32 IntId, const char * Code)
    {
		// Send battleground list.
		if(pObject->GetTypeId()!=TYPEID_UNIT)
			return;

		plr->GetSession()->SendBattlegroundList(((Creature*)pObject), 3);  // WSG = 2
    }

    void Destroy()
    {
        delete this;
    }
};

class SCRIPT_DECL AlteracValleyBattlemaster : public GossipScript
{
public:
    void GossipHello(Object* pObject, Player * plr, bool AutoSend)
	{
        GossipMenu *Menu;
        uint32 Team = plr->GetTeam();
        if(Team > 1) Team = 1;

        // Check if the player can be entered into the bg or not.
        if(plr->getLevel() < 60)
        {
            uint32 FactMessages[2] = { 7658, 7658 };

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
        }
        else
        {
            uint32 FactMessages[2] = { 7658, 7659 }; // need to find the second one

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
            Menu->AddItem( 0, "I would like to enter the battleground.", 1);
        }

        if(AutoSend)
            Menu->SendTo(plr);
    }

    void GossipSelectOption(Object* pObject, Player * plr, uint32 Id, uint32 IntId, const char * Code)
    {
		// Send battleground list.
		if(pObject->GetTypeId()!=TYPEID_UNIT)
			return;

		plr->GetSession()->SendBattlegroundList(((Creature*)pObject), 1);  // WSG = 2
    }

    void Destroy()
    {
        delete this;
    }
};

void SetupBattlemaster(ScriptMgr * mgr)
{
	GossipScript * wsg = (GossipScript*) new WarsongGulchBattlemaster;
	GossipScript * ab = (GossipScript*) new ArathiBasinBattlemaster;
	GossipScript * av = (GossipScript*) new AlteracValleyBattlemaster;

    /* Battlemaster List */
    mgr->register_gossip_script(19910, wsg); // Gargok
    mgr->register_gossip_script(15105, wsg); // Warsong Emissary
    mgr->register_gossip_script(20118, wsg); // Jihi
    mgr->register_gossip_script(16696, wsg); // Krukk
    mgr->register_gossip_script(2804, wsg);  // Kurden Bloodclaw
    mgr->register_gossip_script(20272, wsg); // Lylandor
    mgr->register_gossip_script(20269, wsg); // Montok Redhands
    mgr->register_gossip_script(19908, wsg); // Su'ura Swiftarrow
    mgr->register_gossip_script(15102, wsg); // Silverwing Emissary
    mgr->register_gossip_script(14981, wsg); // Elfarran
    mgr->register_gossip_script(14982, wsg); // Lylandris
    mgr->register_gossip_script(2302, wsg);  // Aethalas
    mgr->register_gossip_script(10360, wsg); // Kergul Bloodaxe
    mgr->register_gossip_script(3890, wsg);  // Brakgul Deathbringer
    mgr->register_gossip_script(20273, ab); // Adam Eternum
    mgr->register_gossip_script(16694, ab); // Karen Wentworth
    mgr->register_gossip_script(20274, ab); // Keldor the Lost
    mgr->register_gossip_script(15007, ab); // Sir Malory Wheeler
    mgr->register_gossip_script(19855, ab); // Sir Maximus Adams
    mgr->register_gossip_script(19905, ab); // The Black Bride
    mgr->register_gossip_script(20120, ab); // Tolo
    mgr->register_gossip_script(15008, ab); // Lady Hoteshem
    mgr->register_gossip_script(857, ab);   // Donald Osgood
    mgr->register_gossip_script(907, ab);   // Keras Wolfheart
    mgr->register_gossip_script(12198, ab); // Martin Lindsev
    mgr->register_gossip_script(14990, ab); // Defilers Emissary
    mgr->register_gossip_script(15006, ab); // Deze Snowbane
    mgr->register_gossip_script(14991, ab); // League of Arathor Emissary
    mgr->register_gossip_script(347, av);   // Grizzle Halfmane
    mgr->register_gossip_script(19907, av); // Grumbol Grimhammer
    mgr->register_gossip_script(16695, av); // Gurak
    mgr->register_gossip_script(20271, av); // Haelga Slatefist
    mgr->register_gossip_script(20119, av); // Mahul
    mgr->register_gossip_script(19906, av); // Usha Eyegouge
    mgr->register_gossip_script(20276, av); // Wolf-Sister Maka
    mgr->register_gossip_script(7410, av);  // Thelman Slatefist
    mgr->register_gossip_script(12197, av); // Glordrum Steelbeard
    mgr->register_gossip_script(5118, av);  // Brogun Stoneshield
    mgr->register_gossip_script(15106, av); // Frostwolf Emissary
    mgr->register_gossip_script(15103, av); // Stormpike Emissary
    mgr->register_gossip_script(14942, av); // Kartra Bloodsnarl

   //cleanup:
   //removed Sandfury Soul Eater(hes a npc in Zul'Farrak and has noting to do whit the battleground masters)
   //added Warsong Emissary, Stormpike Emissary , League of Arathor Emissary
}
<commit_msg>* possible crash fix for AV battle masters.<commit_after>#include "StdAfx.h"
#include "Setup.h"

class SCRIPT_DECL WarsongGulchBattlemaster : public GossipScript
{
public:
    void GossipHello(Object* pObject, Player * plr, bool AutoSend)
    {
        GossipMenu *Menu;
        uint32 Team = plr->GetTeam();
        if(Team > 1) Team = 1;

        // Check if the player can be entered into the bg or not.
        if(plr->getLevel() < 10)
        {
            uint32 FactMessages[2] = { 7599, 7688 };

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
        }
        else
        {
            uint32 FactMessages[2] = { 7689, 7705 }; // need to find the second one

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
            Menu->AddItem( 0, "I would like to enter the battleground.", 1);
        }

        if(AutoSend)
            Menu->SendTo(plr);
    }

    void GossipSelectOption(Object* pObject, Player * plr, uint32 Id, uint32 IntId, const char * Code)
    {
        // Send battleground list.
		if(pObject->GetTypeId()!=TYPEID_UNIT)
			return;

        plr->GetSession()->SendBattlegroundList(((Creature*)pObject), 2);  // WSG = 2
    }

    void Destroy()
    {
        delete this;
    }
};

class SCRIPT_DECL ArathiBasinBattlemaster : public GossipScript
{
public:
    void GossipHello(Object* pObject, Player * plr, bool AutoSend)
    {
        GossipMenu *Menu;
        uint32 Team = plr->GetTeam();
        if(Team > 1) Team = 1;

        // Check if the player can be entered into the bg or not.
        if(plr->getLevel() < 20)
        {
            uint32 FactMessages[2] = { 7700, 7667 };

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
        }
        else
        {
            uint32 FactMessages[2] = { 7700, 7555 }; // need to find the second one

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
            Menu->AddItem( 0, "I would like to enter the battleground.", 1);
        }

        if(AutoSend)
            Menu->SendTo(plr);
    }

    void GossipSelectOption(Object* pObject, Player * plr, uint32 Id, uint32 IntId, const char * Code)
    {
		// Send battleground list.
		if(pObject->GetTypeId()!=TYPEID_UNIT)
			return;

		plr->GetSession()->SendBattlegroundList(((Creature*)pObject), 3);  // WSG = 2
    }

    void Destroy()
    {
        delete this;
    }
};

class SCRIPT_DECL AlteracValleyBattlemaster : public GossipScript
{
public:
    void GossipHello(Object* pObject, Player * plr, bool AutoSend)
	{
        GossipMenu *Menu;
        uint32 Team = plr->GetTeam();
        if(Team > 1) Team = 1;

        // Check if the player can be entered into the bg or not.
        if(plr->getLevel() < 60)
        {
            uint32 FactMessages[2] = { 7658, 7658 };

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
        }
        else
        {
            uint32 FactMessages[2] = { 7658, 7659 }; // need to find the second one

            // Send "you cannot enter" message.
            objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), FactMessages[Team], plr);
            Menu->AddItem( 0, "I would like to enter the battleground.", 1);
        }

        if(AutoSend)
            Menu->SendTo(plr);
    }

    void GossipSelectOption(Object* pObject, Player * plr, uint32 Id, uint32 IntId, const char * Code)
    {
		// Send battleground list.
		if(pObject->GetTypeId()!=TYPEID_UNIT)
			return;

		plr->GetSession()->SendBattlegroundList(((Creature*)pObject), 0);  // WSG = 2
    }

    void Destroy()
    {
        delete this;
    }
};

void SetupBattlemaster(ScriptMgr * mgr)
{
	GossipScript * wsg = (GossipScript*) new WarsongGulchBattlemaster;
	GossipScript * ab = (GossipScript*) new ArathiBasinBattlemaster;
	GossipScript * av = (GossipScript*) new AlteracValleyBattlemaster;

    /* Battlemaster List */
    mgr->register_gossip_script(19910, wsg); // Gargok
    mgr->register_gossip_script(15105, wsg); // Warsong Emissary
    mgr->register_gossip_script(20118, wsg); // Jihi
    mgr->register_gossip_script(16696, wsg); // Krukk
    mgr->register_gossip_script(2804, wsg);  // Kurden Bloodclaw
    mgr->register_gossip_script(20272, wsg); // Lylandor
    mgr->register_gossip_script(20269, wsg); // Montok Redhands
    mgr->register_gossip_script(19908, wsg); // Su'ura Swiftarrow
    mgr->register_gossip_script(15102, wsg); // Silverwing Emissary
    mgr->register_gossip_script(14981, wsg); // Elfarran
    mgr->register_gossip_script(14982, wsg); // Lylandris
    mgr->register_gossip_script(2302, wsg);  // Aethalas
    mgr->register_gossip_script(10360, wsg); // Kergul Bloodaxe
    mgr->register_gossip_script(3890, wsg);  // Brakgul Deathbringer
    mgr->register_gossip_script(20273, ab); // Adam Eternum
    mgr->register_gossip_script(16694, ab); // Karen Wentworth
    mgr->register_gossip_script(20274, ab); // Keldor the Lost
    mgr->register_gossip_script(15007, ab); // Sir Malory Wheeler
    mgr->register_gossip_script(19855, ab); // Sir Maximus Adams
    mgr->register_gossip_script(19905, ab); // The Black Bride
    mgr->register_gossip_script(20120, ab); // Tolo
    mgr->register_gossip_script(15008, ab); // Lady Hoteshem
    mgr->register_gossip_script(857, ab);   // Donald Osgood
    mgr->register_gossip_script(907, ab);   // Keras Wolfheart
    mgr->register_gossip_script(12198, ab); // Martin Lindsev
    mgr->register_gossip_script(14990, ab); // Defilers Emissary
    mgr->register_gossip_script(15006, ab); // Deze Snowbane
    mgr->register_gossip_script(14991, ab); // League of Arathor Emissary
    mgr->register_gossip_script(347, av);   // Grizzle Halfmane
    mgr->register_gossip_script(19907, av); // Grumbol Grimhammer
    mgr->register_gossip_script(16695, av); // Gurak
    mgr->register_gossip_script(20271, av); // Haelga Slatefist
    mgr->register_gossip_script(20119, av); // Mahul
    mgr->register_gossip_script(19906, av); // Usha Eyegouge
    mgr->register_gossip_script(20276, av); // Wolf-Sister Maka
    mgr->register_gossip_script(7410, av);  // Thelman Slatefist
    mgr->register_gossip_script(12197, av); // Glordrum Steelbeard
    mgr->register_gossip_script(5118, av);  // Brogun Stoneshield
    mgr->register_gossip_script(15106, av); // Frostwolf Emissary
    mgr->register_gossip_script(15103, av); // Stormpike Emissary
    mgr->register_gossip_script(14942, av); // Kartra Bloodsnarl

   //cleanup:
   //removed Sandfury Soul Eater(hes a npc in Zul'Farrak and has noting to do whit the battleground masters)
   //added Warsong Emissary, Stormpike Emissary , League of Arathor Emissary
}
<|endoftext|>


<commit_before>#include "dsa_common.h"

#include "outgoing_subscribe_stream.h"

#include <ctime>
#include "core/session.h"
#include "util/date_time.h"

namespace dsa {

static SubscribeOptions empty_subscribe_options(QosLevel::_0, -2);

OutgoingSubscribeStream::OutgoingSubscribeStream(ref_<Session> &&session,
                                                 const Path &path, uint32_t rid,
                                                 SubscribeOptions &&options)
    : MessageQueueStream(std::move(session), path, rid) {
  set_options(std::move(options));
}

void OutgoingSubscribeStream::destroy_impl() {
  if (_option_callback != nullptr) {
    _option_callback(*this, empty_subscribe_options);
    _option_callback = nullptr;
  };
}

void OutgoingSubscribeStream::check_queue_time(int64_t time) {
  if (_queue.size() <= 1) return;

  int64_t target_time = time - _max_queue_duration;
  for (auto it = _queue.begin(); it != _queue.end(); ++it) {
    if ((*it)->created_ts >= target_time) {
      // clear all the data from the begin of the queue
      _queue.erase(_queue.begin(), it);
      _current_queue_time = (*it)->created_ts;
      return;
    }
    _current_queue_size -= (*it)->size();
  }
  // all message before target time, but still need to keep the last one
  purge();
}
void OutgoingSubscribeStream::check_queue_size() {
  for (auto it = _queue.begin(); it != _queue.end(); ++it) {
    _current_queue_size -= (*it)->size();
    if (_current_queue_size <= _max_queue_size) {
      // clear all the data from the begin of the queue
      _queue.erase(_queue.begin(), ++it);
      if (it != _queue.end()) {
        _current_queue_time = (*it)->created_ts;
      }
      return;
    }
  }
}

void OutgoingSubscribeStream::set_options(SubscribeOptions &&options) {
  _options = std::move(options);
  _max_queue_size =
      _options.queue_size > 0 ? _options.queue_size : DEFAULT_MAX_QUEUE_SIZE;
  _max_queue_duration = _options.queue_duration > 0 ? _options.queue_duration
                                                    : DEFAULT_MAX_QUEUE_TIME;
  if (_max_queue_size < _current_queue_size) {
    check_queue_size();
  }
  auto current_time = std::time(nullptr);
  if (current_time - _max_queue_duration > _current_queue_time) {
    check_queue_time(current_time);
  }
}

void OutgoingSubscribeStream::receive_message(ref_<Message> &&message) {
  auto request_message =
      DOWN_CAST<const SubscribeRequestMessage *>(message.get());
  SubscribeOptions old_options = std::move(_options);
  set_options(request_message->get_subscribe_options());
  if (_option_callback != nullptr) {
    _option_callback(*this, old_options);
  }
}

void OutgoingSubscribeStream::update_response_status(MessageStatus status) {
  auto status_message = make_ref_<SubscribeResponseMessage>();
  status_message->set_status(status);
  send_message(std::move(status_message));
}
}
<commit_msg>avoid std::deque.erase<commit_after>#include "dsa_common.h"

#include "outgoing_subscribe_stream.h"

#include <ctime>
#include "core/session.h"
#include "util/date_time.h"

namespace dsa {

static SubscribeOptions empty_subscribe_options(QosLevel::_0, -2);

OutgoingSubscribeStream::OutgoingSubscribeStream(ref_<Session> &&session,
                                                 const Path &path, uint32_t rid,
                                                 SubscribeOptions &&options)
    : MessageQueueStream(std::move(session), path, rid) {
  set_options(std::move(options));
}

void OutgoingSubscribeStream::destroy_impl() {
  if (_option_callback != nullptr) {
    _option_callback(*this, empty_subscribe_options);
    _option_callback = nullptr;
  };
}

void OutgoingSubscribeStream::check_queue_time(int64_t time) {
  if (_queue.size() <= 1) return;

  int64_t target_time = time - _max_queue_duration;
  for (auto it = _queue.begin(); it != _queue.end(); ) {
    if ((*it)->created_ts >= target_time) {
      _current_queue_time = (*it)->created_ts;
      return;
    }
    _current_queue_size -= (*it)->size();
    ++it;
    _queue.pop_front();
  }
  // all message before target time, but still need to keep the last one
  purge();
}
void OutgoingSubscribeStream::check_queue_size() {
  for (auto it = _queue.begin(); it != _queue.end();) {
    _current_queue_size -= (*it)->size();
    ++it;
    _queue.pop_front();
    if (_current_queue_size <= _max_queue_size) {
      if (it != _queue.end()) {
        _current_queue_time = (*it)->created_ts;
      }
      return;
    }
  }
}

void OutgoingSubscribeStream::set_options(SubscribeOptions &&options) {
  _options = std::move(options);
  _max_queue_size =
      _options.queue_size > 0 ? _options.queue_size : DEFAULT_MAX_QUEUE_SIZE;
  _max_queue_duration = _options.queue_duration > 0 ? _options.queue_duration
                                                    : DEFAULT_MAX_QUEUE_TIME;
  if (_max_queue_size < _current_queue_size) {
    check_queue_size();
  }
  auto current_time = std::time(nullptr);
  if (current_time - _max_queue_duration > _current_queue_time) {
    check_queue_time(current_time);
  }
}

void OutgoingSubscribeStream::receive_message(ref_<Message> &&message) {
  auto request_message =
      DOWN_CAST<const SubscribeRequestMessage *>(message.get());
  SubscribeOptions old_options = std::move(_options);
  set_options(request_message->get_subscribe_options());
  if (_option_callback != nullptr) {
    _option_callback(*this, old_options);
  }
}

void OutgoingSubscribeStream::update_response_status(MessageStatus status) {
  auto status_message = make_ref_<SubscribeResponseMessage>();
  status_message->set_status(status);
  send_message(std::move(status_message));
}
}
<|endoftext|>