<commit_before>#define DEBUG 1
/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 6/22/2020, 1:47:51 AM
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::integer::gcd; // for C++14 or for cpp_int
using boost::integer::lcm; // for C++14 or for cpp_int
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
bool ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
    return true;
  }
  return false;
}
template <typename T>
bool ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
    return true;
  }
  return false;
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
// ----- for C++17 -----
template <typename T, typename enable_if<is_integral<T>::value>::type * = nullptr>
size_t popcount(T x) { return bitset<64>(x).count(); }
size_t popcount(string const &S) { return bitset<200010>{S}.count(); }
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- Solve -----

class Solve
{
  int N, K, C;
  string S;
  vector<int> X, Y;

public:
  Solve(int N) : N{N}
  {
    cin >> K >> C >> S;
  }

  void flush()
  {
    X = make_table();
    reverse(S.begin(), S.end());
    Y = make_table();
#if DEBUG == 1
    for (auto e : X)
    {
      cerr << e << " ";
    }
    cerr << endl;
    for (auto e : Y)
    {
      cerr << e << " ";
    }
    cerr << endl;
#endif
    reverse(Y.begin(), Y.end());
    reverse(S.begin(), S.end());
    for (auto e : make_ans())
    {
      cout << e + 1 << endl;
    }
  }

private:
  vector<int> make_ans()
  {
    vector<int> ans;
    int ind{1};
    for (auto i{0}; i < N; ++i)
    {
      if (S[i] == 'o')
      {
        if (X[ind - 1] + Y[ind + 1] < K)
        {
          ans.push_back(i);
        }
        ++ind;
      }
    }
    return ans;
  }

  vector<int> make_table()
  {
    int cnt{0};
    for (auto c : S)
    {
      if (c == 'o')
      {
        ++cnt;
      }
    }
    vector<int> ans(cnt + 2, 0);
    int ind{1};
    int now{0};
    int dist{C + 1};
    for (auto c : S)
    {
      if (c == 'o')
      {
        if (dist > C)
        {
          ++now;
          dist = 0;
        }
        else
        {
          ++dist;
        }
        ans[ind] = now;
        ++ind;
      }
      else
      {
        ++dist;
      }
    }
    ans[ind] = now;
    return ans;
  }
};

// ----- main() -----

int main()
{
  int N;
  cin >> N;
  Solve solve(N);
  solve.flush();
}
<commit_msg>tried E.cpp to 'E'<commit_after>#define DEBUG 1
/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 6/22/2020, 1:47:51 AM
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::integer::gcd; // for C++14 or for cpp_int
using boost::integer::lcm; // for C++14 or for cpp_int
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
bool ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
    return true;
  }
  return false;
}
template <typename T>
bool ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
    return true;
  }
  return false;
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
// ----- for C++17 -----
template <typename T, typename enable_if<is_integral<T>::value>::type * = nullptr>
size_t popcount(T x) { return bitset<64>(x).count(); }
size_t popcount(string const &S) { return bitset<200010>{S}.count(); }
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- Solve -----

class Solve
{
  int N, K, C;
  string S;
  vector<int> X, Y;

public:
  Solve(int N) : N{N}
  {
    cin >> K >> C >> S;
  }

  void flush()
  {
    X = make_table();
    reverse(S.begin(), S.end());
    Y = make_table();
    reverse(Y.begin(), Y.end());
    reverse(S.begin(), S.end());
#if DEBUG == 1
    for (auto e : X)
    {
      cerr << e << " ";
    }
    cerr << endl;
    for (auto e : Y)
    {
      cerr << e << " ";
    }
    cerr << endl;
#endif
    for (auto e : make_ans())
    {
      cout << e + 1 << endl;
    }
  }

private:
  vector<int> make_ans()
  {
    vector<int> ans;
    int ind{1};
    for (auto i{0}; i < N; ++i)
    {
      if (S[i] == 'o')
      {
        if (X[ind - 1] + Y[ind + 1] < K)
        {
          ans.push_back(i);
        }
        ++ind;
      }
    }
    return ans;
  }

  vector<int> make_table()
  {
    int cnt{0};
    for (auto c : S)
    {
      if (c == 'o')
      {
        ++cnt;
      }
    }
    vector<int> ans(cnt + 2, 0);
    int ind{1};
    int now{0};
    int dist{C + 1};
    for (auto c : S)
    {
      if (c == 'o')
      {
        if (dist > C)
        {
          ++now;
          dist = 0;
        }
        else
        {
          ++dist;
        }
        ans[ind] = now;
        ++ind;
      }
      else
      {
        ++dist;
      }
    }
    ans[ind] = now;
    return ans;
  }
};

// ----- main() -----

int main()
{
  int N;
  cin >> N;
  Solve solve(N);
  solve.flush();
}
<|endoftext|>


<commit_before>#include <glog/logging.h>

#include <list>
#include <map>

#include <process/clock.hpp>
#include <process/pid.hpp>
#include <process/process.hpp>
#include <process/time.hpp>
#include <process/timeout.hpp>

#include <stout/duration.hpp>
#include <stout/foreach.hpp>
#include <stout/lambda.hpp>
#include <stout/try.hpp>
#include <stout/unreachable.hpp>

#include "event_loop.hpp"
#include "synchronized.hpp"

using std::list;
using std::map;

namespace process {

// We store the timers in a map of lists indexed by the timeout of the
// timer so that we can have two timers that have the same timeout. We
// exploit that the map is SORTED!
static map<Time, list<Timer>>* timers = new map<Time, list<Timer>>();
static synchronizable(timers) = SYNCHRONIZED_INITIALIZER_RECURSIVE;

// We namespace the clock related variables to keep them well
// named. In the future we'll probably want to associate a clock with
// a specific ProcessManager/SocketManager instance pair, so this will
// likely change.
namespace clock {

map<ProcessBase*, Time>* currents = new map<ProcessBase*, Time>();

// TODO(dhamon): These static non-POD instances should be replaced by pointers
// or functions.
Time initial = Time::epoch();
Time current = Time::epoch();

Duration advanced = Duration::zero();

bool paused = false;

// For supporting Clock::settled(), false if we're not currently
// settling (or we're not paused), true if we're currently attempting
// to settle (and we're paused).
bool settling = false;

// Lambda function to invoke when timers have expired.
lambda::function<void(const list<Timer>&)>* callback =
    new lambda::function<void(const list<Timer>&)>();

// Helper for determining the duration until the next timer elapses,
// or None if no timers are pending. Note that we don't manipulate
// 'timer's directly so that it's clear from the callsite that the use
// of 'timers' is within a 'synchronized' block.
//
// TODO(benh): Create a generic 'Timer's abstraction which hides this
// and more away (i.e., all manipulations of 'timers' below).
Option<Duration> next(const map<Time, list<Timer>>& timers)
{
  if (!timers.empty()) {
    // Determine when the next "tick" should occur.
    Duration duration = (timers.begin()->first - Clock::now());

    // Force a duration of 0 seconds (i.e., fire timers now) if the
    // clock is paused and the duration is greater than 0 since we
    // want to handle timers right away.
    if (Clock::paused() && duration > Seconds(0)) {
      return Seconds(0);
    }

    return duration;
  }

  return None();
}

} // namespace clock {

void tick()
{
  list<Timer> timedout;

  synchronized (timers) {
    Time now = Clock::now();

    VLOG(3) << "Handling timers up to " << now;

    foreachkey (const Time& timeout, *timers) {
      if (timeout > now) {
        break;
      }

      VLOG(3) << "Have timeout(s) at " << timeout;

      // Need to toggle 'settling' so that we don't prematurely say
      // we're settled until after the timers are executed below,
      // outside of the critical section.
      if (clock::paused) {
        clock::settling = true;
      }

      foreach (const Timer& timer, (*timers)[timeout]) {
        timedout.push_back(timer);
      }
    }

    // Now erase the range of timers that timed out.
    timers->erase(timers->begin(), timers->upper_bound(now));

    // Okay, so the timeout for the next timer should not have fired.
    CHECK(timers->empty() || (timers->begin()->first > now));

    // Schedule another "tick" if necessary.
    Option<Duration> duration = clock::next(*timers);
    if (duration.isSome()) {
      EventLoop::delay(duration.get(), &tick);
    }
  }

  (*clock::callback)(timedout);

  // Mark 'settling' as false since there are not any more timers
  // that will expire before the paused time and we've finished
  // executing expired timers.
  synchronized (timers) {
    if (clock::paused &&
        (timers->size() == 0 ||
         timers->begin()->first > clock::current)) {
      VLOG(3) << "Clock has settled";
      clock::settling = false;
    }
  }
}

void Clock::initialize(lambda::function<void(const list<Timer>&)>&& callback)
{
  (*clock::callback) = callback;
}

Time Clock::now()
{
  return now(__process__);
}

Time Clock::now(ProcessBase* process)
{
  synchronized (timers) {
    if (Clock::paused()) {
      if (process != NULL) {
        if (clock::currents->count(process) != 0) {
          return (*clock::currents)[process];
        } else {
          return (*clock::currents)[process] = clock::initial;
        }
      } else {
        return clock::current;
      }
    }
  }

  double d = EventLoop::time();
  Try<Time> time = Time::create(d); // Compensates for clock::advanced.

  // TODO(xujyan): Move CHECK_SOME to libprocess and add CHECK_SOME
  // here.
  if (time.isError()) {
    LOG(FATAL) << "Failed to create a Time from " << d << ": "
               << time.error();
  }
  return time.get();
}

Timer Clock::timer(
    const Duration& duration,
    const lambda::function<void(void)>& thunk)
{
  static uint64_t id = 1; // Start at 1 since Timer() instances use id 0.

  // Assumes Clock::now() does Clock::now(__process__).
  Timeout timeout = Timeout::in(duration);

  UPID pid = __process__ != NULL ? __process__->self() : UPID();

  Timer timer(__sync_fetch_and_add(&id, 1), timeout, pid, thunk);

  VLOG(3) << "Created a timer for " << pid << " in " << stringify(duration)
          << " in the future (" << timeout.time() << ")";

  // Add the timer.
  synchronized (timers) {
    if (timers->size() == 0 ||
        timer.timeout().time() < timers->begin()->first) {
      // Need to interrupt the loop to update/set timer repeat.

      (*timers)[timer.timeout().time()].push_back(timer);

      // Schedule another "tick" if necessary.
      Option<Duration> duration = clock::next(*timers);
      if (duration.isSome()) {
        EventLoop::delay(duration.get(), &tick);
      }
    } else {
      // Timer repeat is adequate, just add the timeout.
      CHECK(timers->size() >= 1);
      (*timers)[timer.timeout().time()].push_back(timer);
    }
  }

  return timer;
}

bool Clock::cancel(const Timer& timer)
{
  bool canceled = false;
  synchronized (timers) {
    // Check if the timeout is still pending, and if so, erase it. In
    // addition, erase an empty list if we just removed the last
    // timeout.
    Time time = timer.timeout().time();
    if (timers->count(time) > 0) {
      canceled = true;
      (*timers)[time].remove(timer);
      if ((*timers)[time].empty()) {
        timers->erase(time);
      }
    }
  }

  return canceled;
}

void Clock::pause()
{
  process::initialize(); // To make sure the event loop is ready.

  synchronized (timers) {
    if (!clock::paused) {
      clock::initial = clock::current = now();
      clock::paused = true;
      VLOG(2) << "Clock paused at " << clock::initial;
    }
  }

  // Note that after pausing the clock an existing event loop delay
  // might still fire (invoking tick), but since paused == true no
  // "time" will actually have passed, so no timer will actually fire.
}

bool Clock::paused()
{
  return clock::paused;
}

void Clock::resume()
{
  process::initialize(); // To make sure the event loop is ready.

  synchronized (timers) {
    if (clock::paused) {
      VLOG(2) << "Clock resumed at " << clock::current;

      clock::paused = false;
      clock::settling = false;
      clock::currents->clear();

      // Schedule another "tick" if necessary.
      Option<Duration> duration = clock::next(*timers);
      if (duration.isSome()) {
        EventLoop::delay(duration.get(), &tick);
      }
    }
  }
}

void Clock::advance(const Duration& duration)
{
  synchronized (timers) {
    if (clock::paused) {
      clock::advanced += duration;
      clock::current += duration;

      VLOG(2) << "Clock advanced ("  << duration << ") to " << clock::current;

      // Schedule another "tick" if necessary.
      Option<Duration> duration = clock::next(*timers);
      if (duration.isSome()) {
        EventLoop::delay(duration.get(), &tick);
      }
    }
  }
}

void Clock::advance(ProcessBase* process, const Duration& duration)
{
  synchronized (timers) {
    if (clock::paused) {
      Time current = now(process);
      current += duration;
      (*clock::currents)[process] = current;
      VLOG(2) << "Clock of " << process->self() << " advanced (" << duration
              << ") to " << current;
    }
  }
}

void Clock::update(const Time& time)
{
  synchronized (timers) {
    if (clock::paused) {
      if (clock::current < time) {
        clock::advanced += (time - clock::current);
        clock::current = Time(time);
        VLOG(2) << "Clock updated to " << clock::current;

        // Schedule another "tick" if necessary.
        Option<Duration> duration = clock::next(*timers);
        if (duration.isSome()) {
          EventLoop::delay(duration.get(), &tick);
        }
      }
    }
  }
}

void Clock::update(ProcessBase* process, const Time& time, Update update)
{
  synchronized (timers) {
    if (clock::paused) {
      if (now(process) < time || update == Clock::FORCE) {
        VLOG(2) << "Clock of " << process->self() << " updated to " << time;
        (*clock::currents)[process] = Time(time);
      }
    }
  }
}

void Clock::order(ProcessBase* from, ProcessBase* to)
{
  VLOG(2) << "Clock of " << to->self() << " being updated to " << from->self();
  update(to, now(from));
}

bool Clock::settled()
{
  synchronized (timers) {
    CHECK(clock::paused);

    if (clock::settling) {
      VLOG(3) << "Clock still not settled";
      return false;
    } else if (timers->size() == 0 ||
               timers->begin()->first > clock::current) {
      VLOG(3) << "Clock is settled";
      return true;
    }

    VLOG(3) << "Clock is not settled";
    return false;
  }

  UNREACHABLE();
}

// TODO(benh): Introduce a Clock::time(seconds) that replaces this
// function for getting a 'Time' value.
Try<Time> Time::create(double seconds)
{
  Try<Duration> duration = Duration::create(seconds);
  if (duration.isSome()) {
    // In production code, clock::advanced will always be zero!
    return Time(duration.get() + clock::advanced);
  } else {
    return Error("Argument too large for Time: " + duration.error());
  }
}

} // namespace process {
<commit_msg>Remove more non-pod statics from clock<commit_after>#include <glog/logging.h>

#include <list>
#include <map>

#include <process/clock.hpp>
#include <process/pid.hpp>
#include <process/process.hpp>
#include <process/time.hpp>
#include <process/timeout.hpp>

#include <stout/duration.hpp>
#include <stout/foreach.hpp>
#include <stout/lambda.hpp>
#include <stout/try.hpp>
#include <stout/unreachable.hpp>

#include "event_loop.hpp"
#include "synchronized.hpp"

using std::list;
using std::map;

namespace process {

// We store the timers in a map of lists indexed by the timeout of the
// timer so that we can have two timers that have the same timeout. We
// exploit that the map is SORTED!
static map<Time, list<Timer>>* timers = new map<Time, list<Timer>>();
static synchronizable(timers) = SYNCHRONIZED_INITIALIZER_RECURSIVE;

// We namespace the clock related variables to keep them well
// named. In the future we'll probably want to associate a clock with
// a specific ProcessManager/SocketManager instance pair, so this will
// likely change.
namespace clock {

map<ProcessBase*, Time>* currents = new map<ProcessBase*, Time>();

Time* initial = new Time(Time::epoch());
Time* current = new Time(Time::epoch());

Duration* advanced = new Duration(Duration::zero());

bool paused = false;

// For supporting Clock::settled(), false if we're not currently
// settling (or we're not paused), true if we're currently attempting
// to settle (and we're paused).
bool settling = false;

// Lambda function to invoke when timers have expired.
lambda::function<void(const list<Timer>&)>* callback =
    new lambda::function<void(const list<Timer>&)>();

// Helper for determining the duration until the next timer elapses,
// or None if no timers are pending. Note that we don't manipulate
// 'timer's directly so that it's clear from the callsite that the use
// of 'timers' is within a 'synchronized' block.
//
// TODO(benh): Create a generic 'Timer's abstraction which hides this
// and more away (i.e., all manipulations of 'timers' below).
Option<Duration> next(const map<Time, list<Timer>>& timers)
{
  if (!timers.empty()) {
    // Determine when the next "tick" should occur.
    Duration duration = (timers.begin()->first - Clock::now());

    // Force a duration of 0 seconds (i.e., fire timers now) if the
    // clock is paused and the duration is greater than 0 since we
    // want to handle timers right away.
    if (Clock::paused() && duration > Seconds(0)) {
      return Seconds(0);
    }

    return duration;
  }

  return None();
}

} // namespace clock {

void tick()
{
  list<Timer> timedout;

  synchronized (timers) {
    Time now = Clock::now();

    VLOG(3) << "Handling timers up to " << now;

    foreachkey (const Time& timeout, *timers) {
      if (timeout > now) {
        break;
      }

      VLOG(3) << "Have timeout(s) at " << timeout;

      // Need to toggle 'settling' so that we don't prematurely say
      // we're settled until after the timers are executed below,
      // outside of the critical section.
      if (clock::paused) {
        clock::settling = true;
      }

      foreach (const Timer& timer, (*timers)[timeout]) {
        timedout.push_back(timer);
      }
    }

    // Now erase the range of timers that timed out.
    timers->erase(timers->begin(), timers->upper_bound(now));

    // Okay, so the timeout for the next timer should not have fired.
    CHECK(timers->empty() || (timers->begin()->first > now));

    // Schedule another "tick" if necessary.
    Option<Duration> duration = clock::next(*timers);
    if (duration.isSome()) {
      EventLoop::delay(duration.get(), &tick);
    }
  }

  (*clock::callback)(timedout);

  // Mark 'settling' as false since there are not any more timers
  // that will expire before the paused time and we've finished
  // executing expired timers.
  synchronized (timers) {
    if (clock::paused &&
        (timers->size() == 0 ||
         timers->begin()->first > *clock::current)) {
      VLOG(3) << "Clock has settled";
      clock::settling = false;
    }
  }
}

void Clock::initialize(lambda::function<void(const list<Timer>&)>&& callback)
{
  (*clock::callback) = callback;
}

Time Clock::now()
{
  return now(__process__);
}

Time Clock::now(ProcessBase* process)
{
  synchronized (timers) {
    if (Clock::paused()) {
      if (process != NULL) {
        if (clock::currents->count(process) != 0) {
          return (*clock::currents)[process];
        } else {
          return (*clock::currents)[process] = *clock::initial;
        }
      } else {
        return *clock::current;
      }
    }
  }

  double d = EventLoop::time();
  Try<Time> time = Time::create(d); // Compensates for clock::advanced.

  // TODO(xujyan): Move CHECK_SOME to libprocess and add CHECK_SOME
  // here.
  if (time.isError()) {
    LOG(FATAL) << "Failed to create a Time from " << d << ": "
               << time.error();
  }
  return time.get();
}

Timer Clock::timer(
    const Duration& duration,
    const lambda::function<void(void)>& thunk)
{
  static uint64_t id = 1; // Start at 1 since Timer() instances use id 0.

  // Assumes Clock::now() does Clock::now(__process__).
  Timeout timeout = Timeout::in(duration);

  UPID pid = __process__ != NULL ? __process__->self() : UPID();

  Timer timer(__sync_fetch_and_add(&id, 1), timeout, pid, thunk);

  VLOG(3) << "Created a timer for " << pid << " in " << stringify(duration)
          << " in the future (" << timeout.time() << ")";

  // Add the timer.
  synchronized (timers) {
    if (timers->size() == 0 ||
        timer.timeout().time() < timers->begin()->first) {
      // Need to interrupt the loop to update/set timer repeat.

      (*timers)[timer.timeout().time()].push_back(timer);

      // Schedule another "tick" if necessary.
      Option<Duration> duration = clock::next(*timers);
      if (duration.isSome()) {
        EventLoop::delay(duration.get(), &tick);
      }
    } else {
      // Timer repeat is adequate, just add the timeout.
      CHECK(timers->size() >= 1);
      (*timers)[timer.timeout().time()].push_back(timer);
    }
  }

  return timer;
}

bool Clock::cancel(const Timer& timer)
{
  bool canceled = false;
  synchronized (timers) {
    // Check if the timeout is still pending, and if so, erase it. In
    // addition, erase an empty list if we just removed the last
    // timeout.
    Time time = timer.timeout().time();
    if (timers->count(time) > 0) {
      canceled = true;
      (*timers)[time].remove(timer);
      if ((*timers)[time].empty()) {
        timers->erase(time);
      }
    }
  }

  return canceled;
}

void Clock::pause()
{
  process::initialize(); // To make sure the event loop is ready.

  synchronized (timers) {
    if (!clock::paused) {
      *clock::initial = *clock::current = now();
      clock::paused = true;
      VLOG(2) << "Clock paused at " << clock::initial;
    }
  }

  // Note that after pausing the clock an existing event loop delay
  // might still fire (invoking tick), but since paused == true no
  // "time" will actually have passed, so no timer will actually fire.
}

bool Clock::paused()
{
  return clock::paused;
}

void Clock::resume()
{
  process::initialize(); // To make sure the event loop is ready.

  synchronized (timers) {
    if (clock::paused) {
      VLOG(2) << "Clock resumed at " << clock::current;

      clock::paused = false;
      clock::settling = false;
      clock::currents->clear();

      // Schedule another "tick" if necessary.
      Option<Duration> duration = clock::next(*timers);
      if (duration.isSome()) {
        EventLoop::delay(duration.get(), &tick);
      }
    }
  }
}

void Clock::advance(const Duration& duration)
{
  synchronized (timers) {
    if (clock::paused) {
      *clock::advanced += duration;
      *clock::current += duration;

      VLOG(2) << "Clock advanced ("  << duration << ") to " << clock::current;

      // Schedule another "tick" if necessary.
      Option<Duration> duration = clock::next(*timers);
      if (duration.isSome()) {
        EventLoop::delay(duration.get(), &tick);
      }
    }
  }
}

void Clock::advance(ProcessBase* process, const Duration& duration)
{
  synchronized (timers) {
    if (clock::paused) {
      Time current = now(process);
      current += duration;
      (*clock::currents)[process] = current;
      VLOG(2) << "Clock of " << process->self() << " advanced (" << duration
              << ") to " << current;
    }
  }
}

void Clock::update(const Time& time)
{
  synchronized (timers) {
    if (clock::paused) {
      if (*clock::current < time) {
        *clock::advanced += (time - *clock::current);
        *clock::current = Time(time);
        VLOG(2) << "Clock updated to " << clock::current;

        // Schedule another "tick" if necessary.
        Option<Duration> duration = clock::next(*timers);
        if (duration.isSome()) {
          EventLoop::delay(duration.get(), &tick);
        }
      }
    }
  }
}

void Clock::update(ProcessBase* process, const Time& time, Update update)
{
  synchronized (timers) {
    if (clock::paused) {
      if (now(process) < time || update == Clock::FORCE) {
        VLOG(2) << "Clock of " << process->self() << " updated to " << time;
        (*clock::currents)[process] = Time(time);
      }
    }
  }
}

void Clock::order(ProcessBase* from, ProcessBase* to)
{
  VLOG(2) << "Clock of " << to->self() << " being updated to " << from->self();
  update(to, now(from));
}

bool Clock::settled()
{
  synchronized (timers) {
    CHECK(clock::paused);

    if (clock::settling) {
      VLOG(3) << "Clock still not settled";
      return false;
    } else if (timers->size() == 0 ||
               timers->begin()->first > *clock::current) {
      VLOG(3) << "Clock is settled";
      return true;
    }

    VLOG(3) << "Clock is not settled";
    return false;
  }

  UNREACHABLE();
}

// TODO(benh): Introduce a Clock::time(seconds) that replaces this
// function for getting a 'Time' value.
Try<Time> Time::create(double seconds)
{
  Try<Duration> duration = Duration::create(seconds);
  if (duration.isSome()) {
    // In production code, clock::advanced will always be zero!
    return Time(duration.get() + *clock::advanced);
  } else {
    return Error("Argument too large for Time: " + duration.error());
  }
}

} // namespace process {
<|endoftext|>


<commit_before>/*
 * SourceIndex.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/libclang/SourceIndex.hpp>

#include <boost/foreach.hpp>

#include <core/FilePath.hpp>
#include <core/PerformanceTimer.hpp>

#include <core/system/ProcessArgs.hpp>

#include <core/libclang/LibClang.hpp>
#include <core/libclang/UnsavedFiles.hpp>

namespace rstudio {
namespace core {
namespace libclang {

bool SourceIndex::isSourceFile(const FilePath& filePath)
{
   std::string ex = filePath.extensionLowerCase();
   return (ex == ".h" || ex == ".hh" || ex == ".hpp" ||
           ex == ".c" || ex == ".cc" || ex == ".cpp" ||
           ex == ".m" || ex == ".mm");
}

bool SourceIndex::isSourceFile(const std::string& filename)
{
   return isSourceFile(FilePath(filename));
}

SourceIndex::SourceIndex(CompilationDatabase compilationDB, int verbose)
{
   verbose_ = verbose;
   index_ = clang().createIndex(0, (verbose_ > 0) ? 1 : 0);
   compilationDB_ = compilationDB;
}

SourceIndex::~SourceIndex()
{
   try
   {
      // remove all
      removeAllTranslationUnits();

      // dispose the index
      if (index_ != NULL)
         clang().disposeIndex(index_);
   }
   catch(...)
   {
   }
}

unsigned SourceIndex::getGlobalOptions() const
{
   return clang().CXIndex_getGlobalOptions(index_);
}

void SourceIndex::setGlobalOptions(unsigned options)
{
   clang().CXIndex_setGlobalOptions(index_, options);
}

void SourceIndex::removeTranslationUnit(const std::string& filename)
{
   TranslationUnits::iterator it = translationUnits_.find(filename);
   if (it != translationUnits_.end())
   {
      if (verbose_ > 0)
         std::cerr << "CLANG REMOVE INDEX: " << it->first << std::endl;
      clang().disposeTranslationUnit(it->second.tu);
      translationUnits_.erase(it->first);
   }
}

void SourceIndex::removeAllTranslationUnits()
{
   for(TranslationUnits::const_iterator it = translationUnits_.begin();
       it != translationUnits_.end(); ++it)
   {
      if (verbose_ > 0)
         std::cerr << "CLANG REMOVE INDEX: " << it->first << std::endl;

      clang().disposeTranslationUnit(it->second.tu);
   }

   translationUnits_.clear();
}

void SourceIndex::primeEditorTranslationUnit(const std::string& filename)
{
   // if we have no record of this translation unit then do a first pass
   if (translationUnits_.find(filename) == translationUnits_.end())
      getTranslationUnit(filename);
}

void SourceIndex::reprimeEditorTranslationUnit(const std::string& filename)
{
   // if we have already indexed this translation unit then re-index it
   if (translationUnits_.find(filename) != translationUnits_.end())
      getTranslationUnit(filename);
}

std::map<std::string,TranslationUnit>
                           SourceIndex::getIndexedTranslationUnits()
{
   std::map<std::string,TranslationUnit> units;
   BOOST_FOREACH(TranslationUnits::value_type& t, translationUnits_)
   {
      TranslationUnit unit(t.first, t.second.tu, &unsavedFiles_);
      units.insert(std::make_pair(t.first, unit));
   }
   return units;
}

TranslationUnit SourceIndex::getTranslationUnit(const std::string& filename,
                                                bool alwaysReparse)
{
   FilePath filePath(filename);

   boost::scoped_ptr<core::PerformanceTimer> pTimer;
   if (verbose_ > 0)
   {
      std::cerr << "CLANG INDEXING: " << filePath.absolutePath() << std::endl;
      pTimer.reset(new core::PerformanceTimer(filePath.filename()));
   }

   // get the arguments and last write time for this file
   std::vector<std::string> args;
   if (compilationDB_.compileArgsForTranslationUnit)
   {
      args = compilationDB_.compileArgsForTranslationUnit(filename, true);
      if (args.empty())
         return TranslationUnit();
   }
   std::time_t lastWriteTime = filePath.lastWriteTime();

   // look it up
   TranslationUnits::iterator it = translationUnits_.find(filename);

   // check for various incremental processing scenarios
   if (it != translationUnits_.end())
   {
      // alias record
      StoredTranslationUnit& stored = it->second;

      // already up to date?
      if (!alwaysReparse &&
          (args == stored.compileArgs) &&
          (lastWriteTime == stored.lastWriteTime))
      {
         if (verbose_ > 0)
            std::cerr << "  (Index already up to date)" << std::endl;
         return TranslationUnit(filename, stored.tu, &unsavedFiles_);
      }

      // just needs reparse?
      else if (args == stored.compileArgs)
      {
         if (verbose_ > 0)
         {
            std::string reason = alwaysReparse ?
                                       "(Forced reparse)" :
                                       "(File changed on disk, reparsing)";

            std::cerr << "  " << reason << std::endl;
         }

         int ret = clang().reparseTranslationUnit(
                                stored.tu,
                                unsavedFiles().numUnsavedFiles(),
                                unsavedFiles().unsavedFilesArray(),
                                clang().defaultReparseOptions(stored.tu));

         if (ret == 0)
         {
            // update last write time
            stored.lastWriteTime = lastWriteTime;

            // return it
            return TranslationUnit(filename, stored.tu, &unsavedFiles_);
         }
         else
         {
            LOG_ERROR_MESSAGE("Error re-parsing translation unit " + filename);
         }
      }
   }

   // if we got this far then there either was no existing translation
   // unit or we require a full rebuild. in all cases remove any existing
   // translation unit we have
   removeTranslationUnit(filename);

   // add verbose output if requested
   if (verbose_ >= 2)
     args.push_back("-v");

   // get the args in the fashion libclang expects (char**)
   core::system::ProcessArgs argsArray(args);

   if (verbose_ > 0)
      std::cerr << "  (Creating new index)" << std::endl;

   // create a new translation unit from the file
   CXTranslationUnit tu = clang().parseTranslationUnit(
                         index_,
                         filename.c_str(),
                         argsArray.args(),
                         argsArray.argCount(),
                         unsavedFiles().unsavedFilesArray(),
                         unsavedFiles().numUnsavedFiles(),
                         clang().defaultEditingTranslationUnitOptions());

   // save and return it if we succeeded
   if (tu != NULL)
   {
      translationUnits_[filename] = StoredTranslationUnit(args,
                                                          lastWriteTime,
                                                          tu);

      TranslationUnit unit(filename, tu, &unsavedFiles_);
      if (verbose_ > 0)
         unit.printResourceUsage(std::cerr, false);
      return unit;
   }
   else
   {
      LOG_ERROR_MESSAGE("Error parsing translation unit " + filename);
      return TranslationUnit();
   }
}

Cursor SourceIndex::referencedCursorForFileLocation(const FileLocation &loc)
{
   // get the translation unit
   std::string filename = loc.filePath.absolutePath();
   TranslationUnit tu = getTranslationUnit(filename, true);
   if (tu.empty())
      return Cursor();

   // get the cursor
   Cursor cursor = tu.getCursor(filename, loc.line, loc.column);
   if (!cursor.isValid())
      return Cursor();

   // follow reference if we need to
   if (cursor.isReference() || cursor.isExpression())
   {
      cursor = cursor.getReferenced();
      if (!cursor.isValid())
         return Cursor();
   }

   // return the cursor that points to the definition
   return cursor;
}

} // namespace libclang
} // namespace core
} // namespace rstudio

<commit_msg>create common function for applying changes to default clang translation unit options<commit_after>/*
 * SourceIndex.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/libclang/SourceIndex.hpp>

#include <boost/foreach.hpp>

#include <core/FilePath.hpp>
#include <core/PerformanceTimer.hpp>

#include <core/system/ProcessArgs.hpp>

#include <core/libclang/LibClang.hpp>
#include <core/libclang/UnsavedFiles.hpp>

namespace rstudio {
namespace core {
namespace libclang {

namespace {

inline unsigned applyTranslationUnitOptions(unsigned defaultOptions)
{
   // for now just reflect back the defaults
   return defaultOptions;
}

} // anonymous namespace

bool SourceIndex::isSourceFile(const FilePath& filePath)
{
   std::string ex = filePath.extensionLowerCase();
   return (ex == ".h" || ex == ".hh" || ex == ".hpp" ||
           ex == ".c" || ex == ".cc" || ex == ".cpp" ||
           ex == ".m" || ex == ".mm");
}

bool SourceIndex::isSourceFile(const std::string& filename)
{
   return isSourceFile(FilePath(filename));
}

SourceIndex::SourceIndex(CompilationDatabase compilationDB, int verbose)
{
   verbose_ = verbose;
   index_ = clang().createIndex(0, (verbose_ > 0) ? 1 : 0);
   compilationDB_ = compilationDB;
}

SourceIndex::~SourceIndex()
{
   try
   {
      // remove all
      removeAllTranslationUnits();

      // dispose the index
      if (index_ != NULL)
         clang().disposeIndex(index_);
   }
   catch(...)
   {
   }
}

unsigned SourceIndex::getGlobalOptions() const
{
   return clang().CXIndex_getGlobalOptions(index_);
}

void SourceIndex::setGlobalOptions(unsigned options)
{
   clang().CXIndex_setGlobalOptions(index_, options);
}

void SourceIndex::removeTranslationUnit(const std::string& filename)
{
   TranslationUnits::iterator it = translationUnits_.find(filename);
   if (it != translationUnits_.end())
   {
      if (verbose_ > 0)
         std::cerr << "CLANG REMOVE INDEX: " << it->first << std::endl;
      clang().disposeTranslationUnit(it->second.tu);
      translationUnits_.erase(it->first);
   }
}

void SourceIndex::removeAllTranslationUnits()
{
   for(TranslationUnits::const_iterator it = translationUnits_.begin();
       it != translationUnits_.end(); ++it)
   {
      if (verbose_ > 0)
         std::cerr << "CLANG REMOVE INDEX: " << it->first << std::endl;

      clang().disposeTranslationUnit(it->second.tu);
   }

   translationUnits_.clear();
}

void SourceIndex::primeEditorTranslationUnit(const std::string& filename)
{
   // if we have no record of this translation unit then do a first pass
   if (translationUnits_.find(filename) == translationUnits_.end())
      getTranslationUnit(filename);
}

void SourceIndex::reprimeEditorTranslationUnit(const std::string& filename)
{
   // if we have already indexed this translation unit then re-index it
   if (translationUnits_.find(filename) != translationUnits_.end())
      getTranslationUnit(filename);
}

std::map<std::string,TranslationUnit>
                           SourceIndex::getIndexedTranslationUnits()
{
   std::map<std::string,TranslationUnit> units;
   BOOST_FOREACH(TranslationUnits::value_type& t, translationUnits_)
   {
      TranslationUnit unit(t.first, t.second.tu, &unsavedFiles_);
      units.insert(std::make_pair(t.first, unit));
   }
   return units;
}

TranslationUnit SourceIndex::getTranslationUnit(const std::string& filename,
                                                bool alwaysReparse)
{
   FilePath filePath(filename);

   boost::scoped_ptr<core::PerformanceTimer> pTimer;
   if (verbose_ > 0)
   {
      std::cerr << "CLANG INDEXING: " << filePath.absolutePath() << std::endl;
      pTimer.reset(new core::PerformanceTimer(filePath.filename()));
   }

   // get the arguments and last write time for this file
   std::vector<std::string> args;
   if (compilationDB_.compileArgsForTranslationUnit)
   {
      args = compilationDB_.compileArgsForTranslationUnit(filename, true);
      if (args.empty())
         return TranslationUnit();
   }
   std::time_t lastWriteTime = filePath.lastWriteTime();

   // look it up
   TranslationUnits::iterator it = translationUnits_.find(filename);

   // check for various incremental processing scenarios
   if (it != translationUnits_.end())
   {
      // alias record
      StoredTranslationUnit& stored = it->second;

      // already up to date?
      if (!alwaysReparse &&
          (args == stored.compileArgs) &&
          (lastWriteTime == stored.lastWriteTime))
      {
         if (verbose_ > 0)
            std::cerr << "  (Index already up to date)" << std::endl;
         return TranslationUnit(filename, stored.tu, &unsavedFiles_);
      }

      // just needs reparse?
      else if (args == stored.compileArgs)
      {
         if (verbose_ > 0)
         {
            std::string reason = alwaysReparse ?
                                       "(Forced reparse)" :
                                       "(File changed on disk, reparsing)";

            std::cerr << "  " << reason << std::endl;
         }

         unsigned options = applyTranslationUnitOptions(
                                    clang().defaultReparseOptions(stored.tu));
         int ret = clang().reparseTranslationUnit(
                                stored.tu,
                                unsavedFiles().numUnsavedFiles(),
                                unsavedFiles().unsavedFilesArray(),
                                options);

         if (ret == 0)
         {
            // update last write time
            stored.lastWriteTime = lastWriteTime;

            // return it
            return TranslationUnit(filename, stored.tu, &unsavedFiles_);
         }
         else
         {
            LOG_ERROR_MESSAGE("Error re-parsing translation unit " + filename);
         }
      }
   }

   // if we got this far then there either was no existing translation
   // unit or we require a full rebuild. in all cases remove any existing
   // translation unit we have
   removeTranslationUnit(filename);

   // add verbose output if requested
   if (verbose_ >= 2)
     args.push_back("-v");

   // get the args in the fashion libclang expects (char**)
   core::system::ProcessArgs argsArray(args);

   if (verbose_ > 0)
      std::cerr << "  (Creating new index)" << std::endl;

   // create a new translation unit from the file
   unsigned options = applyTranslationUnitOptions(
                           clang().defaultEditingTranslationUnitOptions());
   CXTranslationUnit tu = clang().parseTranslationUnit(
                         index_,
                         filename.c_str(),
                         argsArray.args(),
                         argsArray.argCount(),
                         unsavedFiles().unsavedFilesArray(),
                         unsavedFiles().numUnsavedFiles(),
                         options);

   // save and return it if we succeeded
   if (tu != NULL)
   {
      translationUnits_[filename] = StoredTranslationUnit(args,
                                                          lastWriteTime,
                                                          tu);

      TranslationUnit unit(filename, tu, &unsavedFiles_);
      if (verbose_ > 0)
         unit.printResourceUsage(std::cerr, false);
      return unit;
   }
   else
   {
      LOG_ERROR_MESSAGE("Error parsing translation unit " + filename);
      return TranslationUnit();
   }
}

Cursor SourceIndex::referencedCursorForFileLocation(const FileLocation &loc)
{
   // get the translation unit
   std::string filename = loc.filePath.absolutePath();
   TranslationUnit tu = getTranslationUnit(filename, true);
   if (tu.empty())
      return Cursor();

   // get the cursor
   Cursor cursor = tu.getCursor(filename, loc.line, loc.column);
   if (!cursor.isValid())
      return Cursor();

   // follow reference if we need to
   if (cursor.isReference() || cursor.isExpression())
   {
      cursor = cursor.getReferenced();
      if (!cursor.isValid())
         return Cursor();
   }

   // return the cursor that points to the definition
   return cursor;
}

} // namespace libclang
} // namespace core
} // namespace rstudio

<|endoftext|>


<commit_before>/*
 * DesktopMainWindow.cpp
 *
 * Copyright (C) 2009-17 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopMainWindow.hpp"

#include <algorithm>

#include <QDebug>
#include <QToolBar>
#include <QWebEnginePage>
#include <QWebChannel>
#include <QWebEngineScript>
#include <QWebEngineScriptCollection>

#include <boost/bind.hpp>
#include <boost/format.hpp>

#include <core/FilePath.hpp>
#include <core/FileSerializer.hpp>
#include <core/system/System.hpp>

#include "DesktopGwtCallback.hpp"
#include "DesktopMenuCallback.hpp"
#include "DesktopWebView.hpp"
#include "DesktopOptions.hpp"
#include "DesktopSlotBinders.hpp"
#include "DesktopUtils.hpp"
#include "DesktopSessionLauncher.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace desktop {

MainWindow::MainWindow(QUrl url) :
      GwtWindow(false, false, QString(), url, nullptr),
      menuCallback_(this),
      gwtCallback_(this, this),
      pSessionLauncher_(nullptr),
      pCurrentSessionProcess_(nullptr)
{
   quitConfirmed_ = false;
   pToolbar_->setVisible(false);

   // create web channel and bind GWT callbacks
   auto* channel = new QWebChannel(this);
   channel->registerObject(QStringLiteral("desktop"), &gwtCallback_);
   channel->registerObject(QStringLiteral("desktopInfo"), &desktopInfo());
   channel->registerObject(QStringLiteral("desktopMenuCallback"), &menuCallback_);
   webPage()->setWebChannel(channel);

   // load qwebchannel.js
   QFile webChannelJsFile(QStringLiteral(":/qtwebchannel/qwebchannel.js"));
   if (!webChannelJsFile.open(QFile::ReadOnly))
      qDebug() << "Failed to open qwebchannel.js!";

   QString webChannelJs = QString::fromUtf8(webChannelJsFile.readAll());
   webChannelJsFile.close();

   // append our WebChannel initialization code
   const char* webChannelInit =
         "new QWebChannel(qt.webChannelTransport, function(channel) {"
         "   for (var key in channel.objects) {"
         "      window[key] = channel.objects[key];"
         "   }"
         "});";

   webChannelJs.append(QString::fromUtf8(webChannelInit));

   QWebEngineScript script;
   script.setName(QStringLiteral("qwebchannel"));
   script.setInjectionPoint(QWebEngineScript::DocumentCreation);
   script.setWorldId(QWebEngineScript::MainWorld);
   script.setSourceCode(webChannelJs);
   webPage()->scripts().insert(script);

   // Dummy menu bar to deal with the fact that
   // the real menu bar isn't ready until well
   // after startup.
   auto* pMainMenuStub = new QMenuBar(this);
   pMainMenuStub->addMenu(QString::fromUtf8("File"));
   pMainMenuStub->addMenu(QString::fromUtf8("Edit"));
   pMainMenuStub->addMenu(QString::fromUtf8("Code"));
   pMainMenuStub->addMenu(QString::fromUtf8("View"));
   pMainMenuStub->addMenu(QString::fromUtf8("Plots"));
   pMainMenuStub->addMenu(QString::fromUtf8("Session"));
   pMainMenuStub->addMenu(QString::fromUtf8("Build"));
   pMainMenuStub->addMenu(QString::fromUtf8("Debug"));
   pMainMenuStub->addMenu(QString::fromUtf8("Profile"));
   pMainMenuStub->addMenu(QString::fromUtf8("Tools"));
   pMainMenuStub->addMenu(QString::fromUtf8("Help"));
   setMenuBar(pMainMenuStub);

   connect(&menuCallback_, SIGNAL(menuBarCompleted(QMenuBar*)),
           this, SLOT(setMenuBar(QMenuBar*)));
   connect(&menuCallback_, SIGNAL(commandInvoked(QString)),
           this, SLOT(invokeCommand(QString)));

   connect(&menuCallback_, SIGNAL(zoomIn()), this, SLOT(zoomIn()));
   connect(&menuCallback_, SIGNAL(zoomOut()), this, SLOT(zoomOut()));

   connect(&gwtCallback_, SIGNAL(workbenchInitialized()),
           this, SIGNAL(firstWorkbenchInitialized()));
   connect(&gwtCallback_, SIGNAL(workbenchInitialized()),
           this, SLOT(onWorkbenchInitialized()));

   connect(webView(), SIGNAL(onCloseWindowShortcut()),
           this, SLOT(onCloseWindowShortcut()));

   connect(qApp, SIGNAL(commitDataRequest(QSessionManager&)),
           this, SLOT(commitDataRequest(QSessionManager&)),
           Qt::DirectConnection);

   setWindowIcon(QIcon(QString::fromUtf8(":/icons/RStudio.ico")));

   setWindowTitle(QString::fromUtf8("RStudio"));

#ifdef Q_OS_MAC
   auto* pDefaultMenu = new QMenuBar();
   pDefaultMenu->addMenu(new WindowMenu());
#endif

   desktop::enableFullscreenMode(this, true);

   //setContentsMargins(10000, 0, -10000, 0);
   setStyleSheet(QString::fromUtf8("QMainWindow { background: #e1e2e5; } QMenuBar { color: #000000; }"));
}

QString MainWindow::getSumatraPdfExePath()
{
   return desktopInfo().getSumatraPdfExePath();
}

void MainWindow::launchSession(bool reload)
{
   Error error = pSessionLauncher_->launchNextSession(reload);
   if (error)
   {
      LOG_ERROR(error);

      showMessageBox(QMessageBox::Critical,
                     this,
                     QString::fromUtf8("RStudio"),
                     QString::fromUtf8("The R session failed to start."));

      quit();
   }
}

void MainWindow::launchRStudio(const std::vector<std::string> &args,
                               const std::string& initialDir)
{
    pAppLauncher_->launchRStudio(args, initialDir);
}

void MainWindow::onCloseWindowShortcut()
{
   webPage()->runJavaScript(
            QStringLiteral("window.desktopHooks.isCommandEnabled('closeSourceDoc')"),
            [&](QVariant closeSourceDocEnabled)
   {
      if (!closeSourceDocEnabled.toBool())
         close();
   });
}

void MainWindow::onWorkbenchInitialized()
{
   //QTimer::singleShot(300, this, SLOT(resetMargins()));

   // reset state (in case this occurred in response to a manual reload
   // or reload for a new project context)
   quitConfirmed_ = false;

   webPage()->runJavaScript(
            QStringLiteral("window.desktopHooks.getActiveProjectDir()"),
            [&](QVariant qProjectDir)
   {
      QString projectDir = qProjectDir.toString();

      if (projectDir.length() > 0)
         setWindowTitle(projectDir + QString::fromUtf8(" - RStudio"));
      else
         setWindowTitle(QString::fromUtf8("RStudio"));

      avoidMoveCursorIfNecessary();
   });
}

void MainWindow::resetMargins()
{
   setContentsMargins(0, 0, 0, 0);
}

// this notification occurs when windows or X11 is shutting
// down -- in this case we want to be a good citizen and just
// exit right away so we notify the gwt callback that a legit
// quit and exit is on the way and we set the quitConfirmed_
// flag so no prompting occurs (note that source documents
// have already been auto-saved so will be restored next time
// the current project context is opened)
void MainWindow::commitDataRequest(QSessionManager &manager)
{
   gwtCallback_.setPendingQuit(PendingQuitAndExit);
   quitConfirmed_ = true;
}

void MainWindow::loadUrl(const QUrl& url)
{
   webView()->setBaseUrl(url);
   webView()->load(url);
}

void MainWindow::quit()
{
   quitConfirmed_ = true;
   close();
}

void MainWindow::invokeCommand(QString commandId)
{
   QString command =
         QString::fromUtf8("window.desktopHooks.invokeCommand('") +
         commandId +
         QString::fromUtf8("');");

   webPage()->runJavaScript(command);
}

void MainWindow::closeEvent(QCloseEvent* pEvent)
{
   if (!webPage())
   {
       pEvent->accept();
       return;
   }

   webPage()->runJavaScript(
            QStringLiteral("!!window.desktopHooks"),
            [&](QVariant hasQuitR) {

      if (quitConfirmed_ ||
          !hasQuitR.toBool() ||
          pCurrentSessionProcess_ == nullptr ||
          pCurrentSessionProcess_->state() != QProcess::Running)
      {
         pEvent->accept();
      }
      else
      {
         webPage()->runJavaScript(
                  QStringLiteral("window.desktopHooks.quitR()"),
                  [&](QVariant ignored)
         {
            pEvent->ignore();
         });
      }
   });
}

double MainWindow::getZoomLevel()
{
   return options().zoomLevel();
}

void MainWindow::setZoomLevel(double zoomLevel)
{
   options().setZoomLevel(zoomLevel);
}

void MainWindow::setMenuBar(QMenuBar *pMenubar)
{
   delete menuBar();
   this->QMainWindow::setMenuBar(pMenubar);
}

void MainWindow::openFileInRStudio(QString path)
{
   QFileInfo fileInfo(path);
   if (!fileInfo.isAbsolute() || !fileInfo.exists() || !fileInfo.isFile())
      return;

   path = path.replace(QString::fromUtf8("\\"), QString::fromUtf8("\\\\"))
         .replace(QString::fromUtf8("\""), QString::fromUtf8("\\\""))
         .replace(QString::fromUtf8("\n"), QString::fromUtf8("\\n"));

   webView()->page()->runJavaScript(
            QString::fromUtf8("window.desktopHooks.openFile(\"") + path + QString::fromUtf8("\")"));
}

void MainWindow::onPdfViewerClosed(QString pdfPath)
{
   webView()->page()->runJavaScript(
            QString::fromUtf8("window.synctexNotifyPdfViewerClosed(\"") +
            pdfPath + QString::fromUtf8("\")"));
}

void MainWindow::onPdfViewerSyncSource(QString srcFile, int line, int column)
{
   boost::format fmt("window.desktopSynctexInverseSearch(\"%1%\", %2%, %3%)");
   std::string js = boost::str(fmt % srcFile.toStdString() % line % column);
   webView()->page()->runJavaScript(QString::fromStdString(js));
}

void MainWindow::onLicenseLost(QString licenseMessage)
{
   webView()->page()->runJavaScript(
            QString::fromUtf8("window.desktopHooks.licenseLost('") + licenseMessage +
            QString::fromUtf8("');"));
}

// private interface for SessionLauncher

void MainWindow::setSessionLauncher(SessionLauncher* pSessionLauncher)
{
   pSessionLauncher_ = pSessionLauncher;
}

void MainWindow::setSessionProcess(QProcess* pSessionProcess)
{
   pCurrentSessionProcess_ = pSessionProcess;
}

void MainWindow::setAppLauncher(ApplicationLaunch *pAppLauncher)
{
    pAppLauncher_ = pAppLauncher;
}

// allow SessionLauncher to collect restart requests from GwtCallback
int MainWindow::collectPendingQuitRequest()
{
   return gwtCallback_.collectPendingQuitRequest();
}

bool MainWindow::desktopHooksAvailable()
{
   return desktopInfo().desktopHooksAvailable();
}

void MainWindow::onActivated()
{
   // TODO: this should only be invoked if we have VCS active + in a project
//   if (desktopHooksAvailable())
//      invokeCommand(QString::fromUtf8("vcsRefreshNoError"));
}

} // namespace desktop
} // namespace rstudio
<commit_msg>Mac main menu missing Help menu<commit_after>/*
 * DesktopMainWindow.cpp
 *
 * Copyright (C) 2009-17 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopMainWindow.hpp"

#include <algorithm>

#include <QDebug>
#include <QToolBar>
#include <QWebEnginePage>
#include <QWebChannel>
#include <QWebEngineScript>
#include <QWebEngineScriptCollection>

#include <boost/bind.hpp>
#include <boost/format.hpp>

#include <core/FilePath.hpp>
#include <core/FileSerializer.hpp>
#include <core/system/System.hpp>

#include "DesktopGwtCallback.hpp"
#include "DesktopMenuCallback.hpp"
#include "DesktopWebView.hpp"
#include "DesktopOptions.hpp"
#include "DesktopSlotBinders.hpp"
#include "DesktopUtils.hpp"
#include "DesktopSessionLauncher.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace desktop {

MainWindow::MainWindow(QUrl url) :
      GwtWindow(false, false, QString(), url, nullptr),
      menuCallback_(this),
      gwtCallback_(this, this),
      pSessionLauncher_(nullptr),
      pCurrentSessionProcess_(nullptr)
{
   quitConfirmed_ = false;
   pToolbar_->setVisible(false);

   // create web channel and bind GWT callbacks
   auto* channel = new QWebChannel(this);
   channel->registerObject(QStringLiteral("desktop"), &gwtCallback_);
   channel->registerObject(QStringLiteral("desktopInfo"), &desktopInfo());
   channel->registerObject(QStringLiteral("desktopMenuCallback"), &menuCallback_);
   webPage()->setWebChannel(channel);

   // load qwebchannel.js
   QFile webChannelJsFile(QStringLiteral(":/qtwebchannel/qwebchannel.js"));
   if (!webChannelJsFile.open(QFile::ReadOnly))
      qDebug() << "Failed to open qwebchannel.js!";

   QString webChannelJs = QString::fromUtf8(webChannelJsFile.readAll());
   webChannelJsFile.close();

   // append our WebChannel initialization code
   const char* webChannelInit =
         "new QWebChannel(qt.webChannelTransport, function(channel) {"
         "   for (var key in channel.objects) {"
         "      window[key] = channel.objects[key];"
         "   }"
         "});";

   webChannelJs.append(QString::fromUtf8(webChannelInit));

   QWebEngineScript script;
   script.setName(QStringLiteral("qwebchannel"));
   script.setInjectionPoint(QWebEngineScript::DocumentCreation);
   script.setWorldId(QWebEngineScript::MainWorld);
   script.setSourceCode(webChannelJs);
   webPage()->scripts().insert(script);

   // Dummy menu bar to deal with the fact that
   // the real menu bar isn't ready until well
   // after startup.
#ifndef Q_OS_MAC
   auto* pMainMenuStub = new QMenuBar(this);
   pMainMenuStub->addMenu(QString::fromUtf8("File"));
   pMainMenuStub->addMenu(QString::fromUtf8("Edit"));
   pMainMenuStub->addMenu(QString::fromUtf8("Code"));
   pMainMenuStub->addMenu(QString::fromUtf8("View"));
   pMainMenuStub->addMenu(QString::fromUtf8("Plots"));
   pMainMenuStub->addMenu(QString::fromUtf8("Session"));
   pMainMenuStub->addMenu(QString::fromUtf8("Build"));
   pMainMenuStub->addMenu(QString::fromUtf8("Debug"));
   pMainMenuStub->addMenu(QString::fromUtf8("Profile"));
   pMainMenuStub->addMenu(QString::fromUtf8("Tools"));
   pMainMenuStub->addMenu(QString::fromUtf8("Help"));
   setMenuBar(pMainMenuStub);
#endif

   connect(&menuCallback_, SIGNAL(menuBarCompleted(QMenuBar*)),
           this, SLOT(setMenuBar(QMenuBar*)));
   connect(&menuCallback_, SIGNAL(commandInvoked(QString)),
           this, SLOT(invokeCommand(QString)));

   connect(&menuCallback_, SIGNAL(zoomIn()), this, SLOT(zoomIn()));
   connect(&menuCallback_, SIGNAL(zoomOut()), this, SLOT(zoomOut()));

   connect(&gwtCallback_, SIGNAL(workbenchInitialized()),
           this, SIGNAL(firstWorkbenchInitialized()));
   connect(&gwtCallback_, SIGNAL(workbenchInitialized()),
           this, SLOT(onWorkbenchInitialized()));

   connect(webView(), SIGNAL(onCloseWindowShortcut()),
           this, SLOT(onCloseWindowShortcut()));

   connect(qApp, SIGNAL(commitDataRequest(QSessionManager&)),
           this, SLOT(commitDataRequest(QSessionManager&)),
           Qt::DirectConnection);

   setWindowIcon(QIcon(QString::fromUtf8(":/icons/RStudio.ico")));

   setWindowTitle(QString::fromUtf8("RStudio"));

#ifdef Q_OS_MAC
   auto* pDefaultMenu = new QMenuBar();
   pDefaultMenu->addMenu(new WindowMenu());
#endif

   desktop::enableFullscreenMode(this, true);

   //setContentsMargins(10000, 0, -10000, 0);
   setStyleSheet(QString::fromUtf8("QMainWindow { background: #e1e2e5; } QMenuBar { color: #000000; }"));
}

QString MainWindow::getSumatraPdfExePath()
{
   return desktopInfo().getSumatraPdfExePath();
}

void MainWindow::launchSession(bool reload)
{
   Error error = pSessionLauncher_->launchNextSession(reload);
   if (error)
   {
      LOG_ERROR(error);

      showMessageBox(QMessageBox::Critical,
                     this,
                     QString::fromUtf8("RStudio"),
                     QString::fromUtf8("The R session failed to start."));

      quit();
   }
}

void MainWindow::launchRStudio(const std::vector<std::string> &args,
                               const std::string& initialDir)
{
    pAppLauncher_->launchRStudio(args, initialDir);
}

void MainWindow::onCloseWindowShortcut()
{
   webPage()->runJavaScript(
            QStringLiteral("window.desktopHooks.isCommandEnabled('closeSourceDoc')"),
            [&](QVariant closeSourceDocEnabled)
   {
      if (!closeSourceDocEnabled.toBool())
         close();
   });
}

void MainWindow::onWorkbenchInitialized()
{
   //QTimer::singleShot(300, this, SLOT(resetMargins()));

   // reset state (in case this occurred in response to a manual reload
   // or reload for a new project context)
   quitConfirmed_ = false;

   webPage()->runJavaScript(
            QStringLiteral("window.desktopHooks.getActiveProjectDir()"),
            [&](QVariant qProjectDir)
   {
      QString projectDir = qProjectDir.toString();

      if (projectDir.length() > 0)
         setWindowTitle(projectDir + QString::fromUtf8(" - RStudio"));
      else
         setWindowTitle(QString::fromUtf8("RStudio"));

      avoidMoveCursorIfNecessary();
   });
}

void MainWindow::resetMargins()
{
   setContentsMargins(0, 0, 0, 0);
}

// this notification occurs when windows or X11 is shutting
// down -- in this case we want to be a good citizen and just
// exit right away so we notify the gwt callback that a legit
// quit and exit is on the way and we set the quitConfirmed_
// flag so no prompting occurs (note that source documents
// have already been auto-saved so will be restored next time
// the current project context is opened)
void MainWindow::commitDataRequest(QSessionManager &manager)
{
   gwtCallback_.setPendingQuit(PendingQuitAndExit);
   quitConfirmed_ = true;
}

void MainWindow::loadUrl(const QUrl& url)
{
   webView()->setBaseUrl(url);
   webView()->load(url);
}

void MainWindow::quit()
{
   quitConfirmed_ = true;
   close();
}

void MainWindow::invokeCommand(QString commandId)
{
   QString command =
         QString::fromUtf8("window.desktopHooks.invokeCommand('") +
         commandId +
         QString::fromUtf8("');");

   webPage()->runJavaScript(command);
}

void MainWindow::closeEvent(QCloseEvent* pEvent)
{
   if (!webPage())
   {
       pEvent->accept();
       return;
   }

   webPage()->runJavaScript(
            QStringLiteral("!!window.desktopHooks"),
            [&](QVariant hasQuitR) {

      if (quitConfirmed_ ||
          !hasQuitR.toBool() ||
          pCurrentSessionProcess_ == nullptr ||
          pCurrentSessionProcess_->state() != QProcess::Running)
      {
         pEvent->accept();
      }
      else
      {
         webPage()->runJavaScript(
                  QStringLiteral("window.desktopHooks.quitR()"),
                  [&](QVariant ignored)
         {
            pEvent->ignore();
         });
      }
   });
}

double MainWindow::getZoomLevel()
{
   return options().zoomLevel();
}

void MainWindow::setZoomLevel(double zoomLevel)
{
   options().setZoomLevel(zoomLevel);
}

void MainWindow::setMenuBar(QMenuBar *pMenubar)
{
   delete menuBar();
   this->QMainWindow::setMenuBar(pMenubar);
}

void MainWindow::openFileInRStudio(QString path)
{
   QFileInfo fileInfo(path);
   if (!fileInfo.isAbsolute() || !fileInfo.exists() || !fileInfo.isFile())
      return;

   path = path.replace(QString::fromUtf8("\\"), QString::fromUtf8("\\\\"))
         .replace(QString::fromUtf8("\""), QString::fromUtf8("\\\""))
         .replace(QString::fromUtf8("\n"), QString::fromUtf8("\\n"));

   webView()->page()->runJavaScript(
            QString::fromUtf8("window.desktopHooks.openFile(\"") + path + QString::fromUtf8("\")"));
}

void MainWindow::onPdfViewerClosed(QString pdfPath)
{
   webView()->page()->runJavaScript(
            QString::fromUtf8("window.synctexNotifyPdfViewerClosed(\"") +
            pdfPath + QString::fromUtf8("\")"));
}

void MainWindow::onPdfViewerSyncSource(QString srcFile, int line, int column)
{
   boost::format fmt("window.desktopSynctexInverseSearch(\"%1%\", %2%, %3%)");
   std::string js = boost::str(fmt % srcFile.toStdString() % line % column);
   webView()->page()->runJavaScript(QString::fromStdString(js));
}

void MainWindow::onLicenseLost(QString licenseMessage)
{
   webView()->page()->runJavaScript(
            QString::fromUtf8("window.desktopHooks.licenseLost('") + licenseMessage +
            QString::fromUtf8("');"));
}

// private interface for SessionLauncher

void MainWindow::setSessionLauncher(SessionLauncher* pSessionLauncher)
{
   pSessionLauncher_ = pSessionLauncher;
}

void MainWindow::setSessionProcess(QProcess* pSessionProcess)
{
   pCurrentSessionProcess_ = pSessionProcess;
}

void MainWindow::setAppLauncher(ApplicationLaunch *pAppLauncher)
{
    pAppLauncher_ = pAppLauncher;
}

// allow SessionLauncher to collect restart requests from GwtCallback
int MainWindow::collectPendingQuitRequest()
{
   return gwtCallback_.collectPendingQuitRequest();
}

bool MainWindow::desktopHooksAvailable()
{
   return desktopInfo().desktopHooksAvailable();
}

void MainWindow::onActivated()
{
   // TODO: this should only be invoked if we have VCS active + in a project
//   if (desktopHooksAvailable())
//      invokeCommand(QString::fromUtf8("vcsRefreshNoError"));
}

} // namespace desktop
} // namespace rstudio
<|endoftext|>


<commit_before>#include "ScopeSymbolTable.h"
#include "SemanticError.h"
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE( ScopeSymbolTableTest )

BOOST_AUTO_TEST_CASE( TestSymbolTableAddsAndThenGets ) {
	ScopeSymbolTable table;
	Type* type = new Type;
	table.add("bilbo", type);

	BOOST_REQUIRE(table.find("bilbo") == type);

	delete type;
}

BOOST_AUTO_TEST_CASE( TestSymbolTableAddInLastStackWillGet ) {
	ScopeSymbolTable table;
	Type* type = new Type;
	table.add("bilbo", type);
	table.pushScope();

	BOOST_REQUIRE(table.find("bilbo") == type);

	delete type;
}

BOOST_AUTO_TEST_CASE( TestSymbolTableNotAddedGetsEmptyOptional) {
	ScopeSymbolTable table;
	boost::optional<Type*> type;

	type = table.find("bilbo");
	BOOST_CHECK(!type);
}

BOOST_AUTO_TEST_CASE( TestSymbolTableAddTwiceThrowsSemanticError ) {
	ScopeSymbolTable table;
	Type* type = new Type;

	table.add("bilbo", type);
	try {
		table.add("bilbo", type);
		BOOST_CHECK_MESSAGE(false, "No exception thrown");
	} catch(SemanticError* e) {
		BOOST_CHECK(e->code == SYMBOL_ALREADY_DEFINED);
		delete e;
	}

	delete type;
}

BOOST_AUTO_TEST_CASE( TestSymbolTableAddInNewScopeStillThrowsSemanticError ) {
	ScopeSymbolTable table;
	Type* type = new Type;

	table.add("bilbo", type);
	table.pushScope();
	try {
		table.add("bilbo", type);
		BOOST_CHECK_MESSAGE(false, "No exception thrown");
	} catch(SemanticError* e) {
		BOOST_CHECK(e->code == SYMBOL_ALREADY_DEFINED);
		delete e;
	}

	delete type;
}

BOOST_AUTO_TEST_CASE( TestSymbolTableAddInNewScopeNotSetOncePopped ) {
	ScopeSymbolTable table;
	boost::optional<Type*> optionaltype;
	Type* type = new Type;

	table.pushScope();
	table.add("bilbo", type);
	table.popScope();
	optionaltype = table.find("bilbo");
	BOOST_CHECK(!optionaltype);

	delete type;
}

BOOST_AUTO_TEST_CASE( TestPushPopEmptyScopeGoesOK ) {
	ScopeSymbolTable table;

	table.pushScope();
	table.popScope();
}

BOOST_AUTO_TEST_CASE( TestSymbolsAddedByType ) {
	ScopeSymbolTable table;
	Type* simple = new Type;
	simple->typedata._class.shadow = 0;
	simple->alias = NULL;
	simple->typedata._class.classname = "MyClass";
	Type* aliased = new Type;
	aliased->alias = "myClass";
	Type* shadowed = new Type;
	shadowed->alias = NULL;
	shadowed->typedata._class.classname = "MyClass";
	shadowed->typedata._class.shadow = 3;

	table.add(simple);
	table.add(aliased);
	table.add(shadowed);

	BOOST_CHECK(simple == table.find("MyClass"));
	BOOST_CHECK(aliased == table.find("myClass"));
	BOOST_CHECK(shadowed == table.find("$$$MyClass"));

	delete simple;
	delete aliased;
	delete shadowed;
}

BOOST_AUTO_TEST_CASE( TestGetSymbolByType ) {
	ScopeSymbolTable table;
	Type* simplep = new Type;
	Type* shadowedp = new Type;

	table.add("MyClass", simplep);
	table.add("$$$MyClass", shadowedp);

	Type* simple = new Type;
	simple->alias = NULL;
	simple->typedata._class.shadow = 0;
	simple->typedata._class.classname = "MyClass";
	Type* shadowed = new Type;
	shadowed->alias = NULL;
	shadowed->typedata._class.classname = "MyClass";
	shadowed->typedata._class.shadow = 3;

	BOOST_CHECK(simplep == table.find(simple));
	BOOST_CHECK(shadowedp == table.find(shadowed));

	delete simple;
	delete shadowed;
	delete simplep;
	delete shadowedp;
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Fixing memory test problems<commit_after>#include "ScopeSymbolTable.h"
#include "SemanticError.h"
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE( ScopeSymbolTableTest )

BOOST_AUTO_TEST_CASE( TestSymbolTableAddsAndThenGets ) {
	ScopeSymbolTable table;
	Type type;
	type.type = TYPE_CLASS;
	table.add("bilbo", &type);

	BOOST_REQUIRE(table.find("bilbo") == &type);
}

BOOST_AUTO_TEST_CASE( TestSymbolTableAddInLastStackWillGet ) {
	ScopeSymbolTable table;
	Type type;
	type.type = TYPE_CLASS;
	table.add("bilbo", &type);
	table.pushScope();

	BOOST_REQUIRE(table.find("bilbo") == &type);

}

BOOST_AUTO_TEST_CASE( TestSymbolTableNotAddedGetsEmptyOptional) {
	ScopeSymbolTable table;
	boost::optional<Type*> type;

	type = table.find("bilbo");
	BOOST_CHECK(!type);
}

BOOST_AUTO_TEST_CASE( TestSymbolTableAddTwiceThrowsSemanticError ) {
	ScopeSymbolTable table;
	Type type;
	type.type = TYPE_CLASS;

	table.add("bilbo", &type);
	try {
		table.add("bilbo", &type);
		BOOST_CHECK_MESSAGE(false, "No exception thrown");
	} catch(SemanticError* e) {
		BOOST_CHECK(e->code == SYMBOL_ALREADY_DEFINED);
		delete e;
	}

}

BOOST_AUTO_TEST_CASE( TestSymbolTableAddInNewScopeStillThrowsSemanticError ) {
	ScopeSymbolTable table;
	Type type;
	type.type = TYPE_CLASS;

	table.add("bilbo", &type);
	table.pushScope();
	try {
		table.add("bilbo", &type);
		BOOST_CHECK_MESSAGE(false, "No exception thrown");
	} catch(SemanticError* e) {
		BOOST_CHECK(e->code == SYMBOL_ALREADY_DEFINED);
		delete e;
	}

}

BOOST_AUTO_TEST_CASE( TestSymbolTableAddInNewScopeNotSetOncePopped ) {
	ScopeSymbolTable table;
	boost::optional<Type*> optionaltype;
	Type type;
	type.type = TYPE_CLASS;

	table.pushScope();
	table.add("bilbo", &type);
	table.popScope();
	optionaltype = table.find("bilbo");
	BOOST_CHECK(!optionaltype);
}

BOOST_AUTO_TEST_CASE( TestPushPopEmptyScopeGoesOK ) {
	ScopeSymbolTable table;

	table.pushScope();
	table.popScope();
}

BOOST_AUTO_TEST_CASE( TestSymbolsAddedByType ) {
	ScopeSymbolTable table;
	Type simple;
	simple.type = TYPE_CLASS;
	simple.typedata._class.shadow = 0;
	simple.alias = NULL;
	simple.typedata._class.classname = "MyClass";
	Type aliased;
	aliased.type = TYPE_CLASS;
	aliased.alias = "myClass";
	Type shadowed;
	shadowed.type = TYPE_CLASS;
	shadowed.alias = NULL;
	shadowed.typedata._class.classname = "MyClass";
	shadowed.typedata._class.shadow = 3;

	table.add(&simple);
	table.add(&aliased);
	table.add(&shadowed);

	BOOST_CHECK(&simple == table.find("MyClass"));
	BOOST_CHECK(&aliased == table.find("myClass"));
	BOOST_CHECK(&shadowed == table.find("$$$MyClass"));
}

BOOST_AUTO_TEST_CASE( TestGetSymbolByType ) {
	ScopeSymbolTable table;
	Type simplep;
	simplep.type = TYPE_CLASS;
	Type shadowedp;
	shadowedp.type = TYPE_CLASS;

	table.add("MyClass", &simplep);
	table.add("$$$MyClass", &shadowedp);

	Type simple;
	simple.type = TYPE_CLASS;
	simple.alias = NULL;
	simple.typedata._class.shadow = 0;
	simple.typedata._class.classname = "MyClass";
	Type shadowed;
	shadowed.type = TYPE_CLASS;
	shadowed.alias = NULL;
	shadowed.typedata._class.classname = "MyClass";
	shadowed.typedata._class.shadow = 3;

	BOOST_CHECK(&simplep == table.find(&simple));
	BOOST_CHECK(&shadowedp == table.find(&shadowed));
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>