<commit_before>#define DEBUG 1
/**
 * File    : F2.cpp
 * Author  : Kazune Takahashi
 * Created : 6/15/2020, 11:46:33 PM
 * 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/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
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>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- 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);
}

// ----- 2D, 3D, 4D vectors -----
// Referring to ymatsux-san's source code: https://atcoder.jp/contests/abc138/submissions/7018300

template <typename T>
vector<vector<T>> Make2DVector(size_t d0, size_t d1, T v = T{})
{
  return vector<vector<T>>(d0, vector<T>(d1, v));
}

template <typename T>
vector<vector<vector<T>>> Make3DVector(size_t d0, size_t d1, size_t d2, T v = T{})
{
  return vector<vector<vector<T>>>(d0, Make2DVector(d1, d2, v));
}

template <typename T>
vector<vector<vector<vector<T>>>> Make4DVector(size_t d0, size_t d1, size_t d2, size_t d3, T v = T{})
{
  return vector<vector<vector<vector<T>>>>(d0, Make3DVector(d1, d2, d3, v));
}

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

using Point = tuple<int, int>;

class Solve
{
  int H, W, K;
  vector<vector<int>> V;
  vector<set<Point>> Sx, Sy;
  int sx, sy, gx, gy;

public:
  Solve(int H, int W) : H{H}, W{W}, V{Make2DVector(H, W, Infty<int>())}, Sx(H), Sy(W)
  {
    cin >> K;
    cin >> sx >> sy >> gx >> gy;
    --sx;
    --sy;
    --gx;
    --gy;
    for (auto i{0}; i < H; ++i)
    {
      for (auto j{0}; j < W; ++j)
      {
        char c;
        cin >> c;
        if (c == '@')
        {
          V[i][j] = -1;
        }
        Sx[i].insert(Point{i, j});
        Sy[j].insert(Point{i, j});
      }
    }
  }

  void flush()
  {
    queue<Point> Q;
    Q.push(Point{sx, sy});
    ErasePoint(Point{sx, sy});
    V[sx][sy] = 0;
    while (!Q.empty())
    {
      auto p{Q.front()};
      int x, y;
      tie(x, y) = p;
      Q.pop();
#if DEBUG == 1
      cerr << "visiting: (" << x << ", " << y << ")" << endl;
#endif
      auto bfs = [&](auto b, auto e, bool const plus) {
        for (auto it{b}; it != e; (plus ? it++ : it--))
        {
          auto [nx, ny] = *it;
#if DEBUG == 1
          cerr << "considering: (" << nx << ", " << ny << ")" << endl;
#endif
          if (V[nx][ny] == -1)
          {
            e = b;
            break;
          }
          V[nx][ny] = V[x][y] + 1;
          Q.push(*it);
        }
        for (auto it{b}; it != e; ++it)
        {
          ErasePoint(*it);
        }
      };
      {
        auto b{Sx[x].lower_bound(Point{x, y})};
        auto e{Sx[x].upper_bound(Point{x + K + 1, y})};
        bfs(b, e, true);
      }
      {
        auto b{Sx[x].lower_bound(Point{x - K, y})};
        auto e{Sx[x].upper_bound(Point{x, y})};
        bfs(b, e, false);
      }
      {
        auto b{Sy[y].lower_bound(Point{x, y})};
        auto e{Sy[y].upper_bound(Point{x, y + K + 1})};
        bfs(b, e, true);
      }
      {
        auto b{Sy[y].lower_bound(Point{x, y - K})};
        auto e{Sy[y].upper_bound(Point{x, y})};
        bfs(b, e, false);
      }
    }
    auto ans{V[gx][gy]};
    if (ans == Infty<int>())
    {
      cout << -1 << endl;
    }
    else
    {
      cout << ans << endl;
    }
  }

private:
  void ErasePoint(Point const &p)
  {
    auto [x, y] = p;
    Sx[x].erase(Sx[x].find(p));
    Sy[y].erase(Sy[y].find(p));
  }
};

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

int main()
{
  int H, W;
  cin >> H >> W;
  Solve solve(H, W);
  solve.flush();
}
<commit_msg>tried F2.cpp to 'F'<commit_after>#define DEBUG 1
/**
 * File    : F2.cpp
 * Author  : Kazune Takahashi
 * Created : 6/15/2020, 11:46:33 PM
 * 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/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
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>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- 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);
}

// ----- 2D, 3D, 4D vectors -----
// Referring to ymatsux-san's source code: https://atcoder.jp/contests/abc138/submissions/7018300

template <typename T>
vector<vector<T>> Make2DVector(size_t d0, size_t d1, T v = T{})
{
  return vector<vector<T>>(d0, vector<T>(d1, v));
}

template <typename T>
vector<vector<vector<T>>> Make3DVector(size_t d0, size_t d1, size_t d2, T v = T{})
{
  return vector<vector<vector<T>>>(d0, Make2DVector(d1, d2, v));
}

template <typename T>
vector<vector<vector<vector<T>>>> Make4DVector(size_t d0, size_t d1, size_t d2, size_t d3, T v = T{})
{
  return vector<vector<vector<vector<T>>>>(d0, Make3DVector(d1, d2, d3, v));
}

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

using Point = tuple<int, int>;

class Solve
{
  int H, W, K;
  vector<vector<int>> V;
  int sx, sy, gx, gy;

public:
  Solve(int H, int W) : H{H}, W{W}, V{Make2DVector(H, W, Infty<int>())}
  {
    cin >> K;
    cin >> sx >> sy >> gx >> gy;
    --sx;
    --sy;
    --gx;
    --gy;
    for (auto i{0}; i < H; ++i)
    {
      for (auto j{0}; j < W; ++j)
      {
        char c;
        cin >> c;
        if (c == '@')
        {
          V[i][j] = -1;
        }
      }
    }
  }

  void flush()
  {
    queue<Point> Q;
    Q.push(Point{sx, sy});
    V[sx][sy] = 0;
    while (!Q.empty())
    {
      auto p{Q.front()};
      auto [x, y] = p;
      Q.pop();
      for (auto k{0}; k < 4; ++k)
      {
        for (auto i{1}; i <= K; ++i)
        {
          auto nx{x + dx[k] * i};
          auto ny{y + dy[k] * i};
          if (valid(nx, ny) && V[nx][ny] == Infty<int>())
          {
            V[nx][ny] = V[x][y] + 1;
            Q.push(Point{nx, ny});
          }
          else
          {
            break;
          }
        }
      }
    }
    auto ans{V[gx][gy]};
    if (ans == Infty<int>())
    {
      cout << -1 << endl;
    }
    else
    {
      cout << ans << endl;
    }
  }

private:
  bool valid(int x, int y)
  {
    return 0 <= x && x < H && 0 <= y && y < W && V[x][y] != -1;
  }
};

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

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


<commit_before>#include "Halide.h"

using namespace Halide;

void blur(std::string suffix, ImageParam input8, const int channels,
          bool vectorized) {
    Var x, y, c;
    Func input;
    input(x, y, c) = input8(clamp(x, input8.left(), input8.right()),
                            clamp(y, input8.top(), input8.bottom()), c);

    Func blur_x("blur_x");
    blur_x(x, y, c) = cast<uint8_t>(
        (input(x, y, c) + input(x + 1, y, c) + input(x + 2, y, c)) / 3);
    blur_x.output_buffer() .set_stride(0, input8.stride(0)) .set_stride(2, input8.stride(2)) .set_bounds(2, 0, channels);

    Func result("result");
    result(x, y, c) = cast<uint8_t>(
        (blur_x(x, y, c) + blur_x(x, y + 1, c) + blur_x(x, y + 2, c)) / 3);
    result.output_buffer()
        .set_stride(0, input8.stride(0))
        .set_stride(2, input8.stride(2))
        .set_bounds(2, 0, channels);

    result.bound(c, 0, channels);
    if (suffix == "_rs") {
        result.shader(x, y, c, DeviceAPI::Renderscript);
    } else {
        result.parallel(y);
    }
    if (vectorized) {
        result.vectorize(c);
    }

    std::vector<Argument> args;
    args.push_back(input8);
    std::string filename("generated_blur");
    result.compile_to_file(
        filename + (vectorized ? "_vectorized" : "") + suffix, args);
}

void copy(std::string suffix, ImageParam input8, const int channels,
          bool vectorized) {
    Var x, y, c;
    Func input;
    input(x, y, c) = input8(clamp(x, input8.left(), input8.right()),
                            clamp(y, input8.top(), input8.bottom()), c);

    Func result("result");
    result(x, y, c) = input(x, y, c);
    result.output_buffer()
        .set_stride(0, input8.stride(0))
        .set_stride(2, input8.stride(2))
        .set_bounds(2, 0, channels);

    result.bound(c, 0, channels);
    if (suffix == "_rs") {
        result.shader(x, y, c, DeviceAPI::Renderscript);
    } else {
        result.parallel(y);
    }
    if (vectorized) {
        result.vectorize(c);
    }

    std::vector<Argument> args;
    args.push_back(input8);
    std::string filename("generated_copy");
    result.compile_to_file(
        filename + (vectorized ? "_vectorized" : "") + suffix, args);
}

int main(int argc, char **argv) {
    const int channels = 4;

    ImageParam input_planar(UInt(8), 3, "input");
    input_planar.set_stride(0, 1).set_bounds(2, 0, channels);
    blur(argc > 1 ? argv[1] : "", input_planar, channels, false);
    copy(argc > 1 ? argv[1] : "", input_planar, channels, false);

    ImageParam input_interleaved(UInt(8), 3, "input");
    input_interleaved.set_stride(0, channels)
        .set_stride(2, 1)
        .set_bounds(2, 0, channels);
    blur(argc > 1 ? argv[1] : "", input_interleaved, channels, true);
    copy(argc > 1 ? argv[1] : "", input_interleaved, channels, true);

    std::cout << "Done!" << std::endl;
}<commit_msg>Fix cpu schedules in renderscript app<commit_after>#include "Halide.h"

using namespace Halide;

void blur(std::string suffix, ImageParam input8, const int channels,
          bool vectorized) {
    Var x, y, c;
    Func input;
    input(x, y, c) = input8(clamp(x, input8.left(), input8.right()),
                            clamp(y, input8.top(), input8.bottom()), c);

    Func blur_x("blur_x");
    blur_x(x, y, c) = cast<uint8_t>(
        (input(x, y, c) + input(x + 1, y, c) + input(x + 2, y, c)) / 3);

    Func result("result");
    result(x, y, c) = cast<uint8_t>(
        (blur_x(x, y, c) + blur_x(x, y + 1, c) + blur_x(x, y + 2, c)) / 3);

    result.output_buffer()
        .set_stride(0, channels)
        .set_stride(2, 1)
        .set_bounds(2, 0, channels);

    result.bound(c, 0, channels);
    if (suffix == "_rs") {
        result.shader(x, y, c, DeviceAPI::Renderscript);
        if (vectorized) {
            result.vectorize(c);
        }
    } else {
        Var yi;
        result
            .reorder(c, x, y).unroll(c)
            .split(y, y, yi, 8)
            .parallel(y);
        blur_x.store_at(result, y)
            .compute_at(result, yi)
            .reorder(c, x, y).unroll(c);
        if (vectorized) {
            result.vectorize(x, 16);
            blur_x.vectorize(x, 16);
        }
    }

    std::vector<Argument> args;
    args.push_back(input8);
    std::string filename("generated_blur");
    result.compile_to_file(
        filename + (vectorized ? "_vectorized" : "") + suffix, args);
}

void copy(std::string suffix, ImageParam input8, const int channels,
          bool vectorized) {
    Var x, y, c;
    Func input;
    input(x, y, c) = input8(clamp(x, input8.left(), input8.right()),
                            clamp(y, input8.top(), input8.bottom()), c);

    Func result("result");
    result(x, y, c) = input(x, y, c);
    result.output_buffer()
        .set_stride(0, channels)
        .set_stride(2, 1)
        .set_bounds(2, 0, channels);

    result.bound(c, 0, channels);
    if (suffix == "_rs") {
        result.shader(x, y, c, DeviceAPI::Renderscript);
        if (vectorized) {
            result.vectorize(c);
        }
    } else {
        Var xc;
        result.reorder(c, x, y)
            .parallel(y)
            .unroll(c);
        if (vectorized) {
            result.vectorize(x, 16);
        }
    }

    std::vector<Argument> args;
    args.push_back(input8);
    std::string filename("generated_copy");
    result.compile_to_file(
        filename + (vectorized ? "_vectorized" : "") + suffix, args);
}

int main(int argc, char **argv) {
    const int channels = 4;

    ImageParam input_planar(UInt(8), 3, "input");
    input_planar.set_stride(0, 1).set_bounds(2, 0, channels);
    blur(argc > 1 ? argv[1] : "", input_planar, channels, false);
    copy(argc > 1 ? argv[1] : "", input_planar, channels, false);

    ImageParam input_interleaved(UInt(8), 3, "input");
    input_interleaved.set_stride(0, channels)
        .set_stride(2, 1)
        .set_bounds(2, 0, channels);
    blur(argc > 1 ? argv[1] : "", input_interleaved, channels, true);
    copy(argc > 1 ? argv[1] : "", input_interleaved, channels, true);

    std::cout << "Done!" << std::endl;
}
<|endoftext|>


<commit_before>/*
 *  gucefCORE: GUCEF module providing O/S abstraction and generic solutions
 *  Copyright (C) 2002 - 2007.  Dinand Vanvelzen
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/*-------------------------------------------------------------------------//
//                                                                         //
//      INCLUDES                                                           //
//                                                                         //
//-------------------------------------------------------------------------*/

#include <assert.h>

#ifndef GUCEF_CORE_DVCPPSTRINGUTILS_H
#include "dvcppstringutils.h"
#define GUCEF_CORE_DVCPPSTRINGUTILS_H
#endif /* GUCEF_CORE_DVCPPSTRINGUTILS_H ? */

#ifndef GUCEF_CORE_CIOACCESS_H
#include "CIOAccess.h"
#define GUCEF_CORE_CIOACCESS_H
#endif /* GUCEF_CORE_CIOACCESS_H ? */

#ifndef GUCEF_CORE_ESSENTIALS_H
#include "gucef_essentials.h"
#define GUCEF_CORE_ESSENTIALS_H
#endif /* GUCEF_CORE_ESSENTIALS_H ? */

#ifdef GUCEF_MSWIN_BUILD
#include <windows.h>
#include <wincon.h>          /* for COORD */
#include <conio.h>           /* need conio.h under WIN32 for clrscr() */
#endif /* GUCEF_MSWIN_BUILD ? */

#include "CMSWinConsoleLogger.h"

#ifdef GUCEF_MSWIN_BUILD
/*-------------------------------------------------------------------------//
//                                                                         //
//      NAMESPACE                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

namespace GUCEF {
namespace CORE {

/*-------------------------------------------------------------------------//
//                                                                         //
//      UTILITIES                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

CMSWinConsoleLogger::CMSWinConsoleLogger( void )
    : CIConsoleLogger()                          ,
      m_minimalLogLevel( LOGLEVEL_BELOW_NORMAL ) ,
      m_consoleFptr( NULL )                      ,
      m_formatForUiPurpose( false )
{GUCEF_TRACE;

    AllocConsole();

    /* reopen stout handle as console window output */
    m_consoleFptr = freopen( "CONOUT$", "wb", stdout );
}

/*-------------------------------------------------------------------------*/

CMSWinConsoleLogger::~CMSWinConsoleLogger()
{GUCEF_TRACE;

    CCoreGlobal::Instance()->GetLogManager().RemoveLogger( this );
    FlushLog();

    FreeConsole();
    fclose( m_consoleFptr );
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::SetFormatAsConsoleUI( bool formatForUiPurpose )
{GUCEF_TRACE;

    m_formatForUiPurpose = formatForUiPurpose;
}

/*-------------------------------------------------------------------------*/

bool
CMSWinConsoleLogger::GetFormatAsConsoleUI( void ) const
{GUCEF_TRACE;

    return m_formatForUiPurpose;
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::Log( const TLogMsgType logMsgType ,
                          const Int32 logLevel         ,
                          const CString& logMessage    ,
                          const UInt32 threadId        )
{GUCEF_TRACE;

    if ( !m_formatForUiPurpose )
    {
        if ( logLevel >= m_minimalLogLevel )
        {
            CString actualLogMsg( FormatStdLogMessage( logMsgType ,
                                                       logLevel   ,
                                                       logMessage ,
                                                       threadId   ) + "\n" );

            fprintf( stdout, actualLogMsg.C_String() );
        }
    }
    else
    {
        if ( logMsgType == CORE::CLogManager::LOG_CONSOLE )
        {
            CString actualLogMsg( logMessage + "\n" );
            fprintf( m_consoleFptr, actualLogMsg.C_String() );
        }
    }
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::LogWithoutFormatting( const TLogMsgType logMsgType ,
                                           const Int32 logLevel         ,
                                           const CString& logMessage    ,
                                           const UInt32 threadId        )
{GUCEF_TRACE;

    if ( !m_formatForUiPurpose )
    {
        if ( logLevel >= m_minimalLogLevel || m_formatForUiPurpose )
        {
            CString actualLogMsg( logMessage + "\n" );
            fprintf( m_consoleFptr, actualLogMsg.C_String() );
        }
    }
    else
    {
        if ( logMsgType == CORE::CLogManager::LOG_CONSOLE )
        {
            CString actualLogMsg( logMessage + "\n" );
            fprintf( m_consoleFptr, actualLogMsg.C_String() );
        }
    }
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::FlushLog( void )
{GUCEF_TRACE;

    fflush( m_consoleFptr );
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::SetMinimalLogLevel( const Int32 minimalLogLevel )
{GUCEF_TRACE;

    m_minimalLogLevel = minimalLogLevel;
}

/*-------------------------------------------------------------------------*/

Int32
CMSWinConsoleLogger::GetMinimalLogLevel( void ) const
{GUCEF_TRACE;

    return m_minimalLogLevel;
}

/*-------------------------------------------------------------------------//
//                                                                         //
//      NAMESPACE                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

}; /* namespace CORE */
}; /* namespace GUCEF */

/*-------------------------------------------------------------------------*/
#endif /* GUCEF_MSWIN_BUILD ? */
<commit_msg>Change MS console logger to no longer use printf which was needlessly costing performance plus could cause issues wrt log statement escaping<commit_after>/*
 *  gucefCORE: GUCEF module providing O/S abstraction and generic solutions
 *  Copyright (C) 2002 - 2007.  Dinand Vanvelzen
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/*-------------------------------------------------------------------------//
//                                                                         //
//      INCLUDES                                                           //
//                                                                         //
//-------------------------------------------------------------------------*/

#include <assert.h>

#ifndef GUCEF_CORE_DVCPPSTRINGUTILS_H
#include "dvcppstringutils.h"
#define GUCEF_CORE_DVCPPSTRINGUTILS_H
#endif /* GUCEF_CORE_DVCPPSTRINGUTILS_H ? */

#ifndef GUCEF_CORE_CIOACCESS_H
#include "CIOAccess.h"
#define GUCEF_CORE_CIOACCESS_H
#endif /* GUCEF_CORE_CIOACCESS_H ? */

#ifndef GUCEF_CORE_ESSENTIALS_H
#include "gucef_essentials.h"
#define GUCEF_CORE_ESSENTIALS_H
#endif /* GUCEF_CORE_ESSENTIALS_H ? */

#ifdef GUCEF_MSWIN_BUILD
#include <windows.h>
#include <wincon.h>          /* for COORD */
#include <conio.h>           /* need conio.h under WIN32 for clrscr() */
#endif /* GUCEF_MSWIN_BUILD ? */

#include "CMSWinConsoleLogger.h"

#ifdef GUCEF_MSWIN_BUILD
/*-------------------------------------------------------------------------//
//                                                                         //
//      NAMESPACE                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

namespace GUCEF {
namespace CORE {

/*-------------------------------------------------------------------------//
//                                                                         //
//      UTILITIES                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

CMSWinConsoleLogger::CMSWinConsoleLogger( void )
    : CIConsoleLogger()                          ,
      m_minimalLogLevel( LOGLEVEL_BELOW_NORMAL ) ,
      m_consoleFptr( NULL )                      ,
      m_formatForUiPurpose( false )
{GUCEF_TRACE;

    AllocConsole();

    /* reopen stout handle as console window output */
    m_consoleFptr = freopen( "CONOUT$", "wb", stdout );
}

/*-------------------------------------------------------------------------*/

CMSWinConsoleLogger::~CMSWinConsoleLogger()
{GUCEF_TRACE;

    CCoreGlobal::Instance()->GetLogManager().RemoveLogger( this );
    FlushLog();

    FreeConsole();
    fclose( m_consoleFptr );
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::SetFormatAsConsoleUI( bool formatForUiPurpose )
{GUCEF_TRACE;

    m_formatForUiPurpose = formatForUiPurpose;
}

/*-------------------------------------------------------------------------*/

bool
CMSWinConsoleLogger::GetFormatAsConsoleUI( void ) const
{GUCEF_TRACE;

    return m_formatForUiPurpose;
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::Log( const TLogMsgType logMsgType ,
                          const Int32 logLevel         ,
                          const CString& logMessage    ,
                          const UInt32 threadId        )
{GUCEF_TRACE;

    if ( !m_formatForUiPurpose )
    {
        if ( logLevel >= m_minimalLogLevel )
        {
            CString actualLogMsg( FormatStdLogMessage( logMsgType ,
                                                       logLevel   ,
                                                       logMessage ,
                                                       threadId   ) + "\n" );

            fwrite( actualLogMsg.C_String(), actualLogMsg.Length(), 1, stdout );
            fwrite( "\n", 1, 1, stdout );
        }
    }
    else
    {
        if ( logMsgType == CORE::CLogManager::LOG_CONSOLE )
        {
            fwrite( logMessage.C_String(), logMessage.Length(), 1, m_consoleFptr );
            fwrite( "\n", 1, 1, m_consoleFptr );
        }
    }
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::LogWithoutFormatting( const TLogMsgType logMsgType ,
                                           const Int32 logLevel         ,
                                           const CString& logMessage    ,
                                           const UInt32 threadId        )
{GUCEF_TRACE;

    if ( !m_formatForUiPurpose )
    {
        if ( logLevel >= m_minimalLogLevel || m_formatForUiPurpose )
        {
            CString actualLogMsg( logMessage + "\n" );
            fprintf( m_consoleFptr, actualLogMsg.C_String() );
        }
    }
    else
    {
        if ( logMsgType == CORE::CLogManager::LOG_CONSOLE )
        {
            CString actualLogMsg( logMessage + "\n" );
            fprintf( m_consoleFptr, actualLogMsg.C_String() );
        }
    }
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::FlushLog( void )
{GUCEF_TRACE;

    fflush( m_consoleFptr );
}

/*-------------------------------------------------------------------------*/

void
CMSWinConsoleLogger::SetMinimalLogLevel( const Int32 minimalLogLevel )
{GUCEF_TRACE;

    m_minimalLogLevel = minimalLogLevel;
}

/*-------------------------------------------------------------------------*/

Int32
CMSWinConsoleLogger::GetMinimalLogLevel( void ) const
{GUCEF_TRACE;

    return m_minimalLogLevel;
}

/*-------------------------------------------------------------------------//
//                                                                         //
//      NAMESPACE                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

}; /* namespace CORE */
}; /* namespace GUCEF */

/*-------------------------------------------------------------------------*/
#endif /* GUCEF_MSWIN_BUILD ? */
<|endoftext|>


<commit_before>/* logs_test.cc                                 -*- C++ -*-
   Rémi Attab (remi.attab@gmail.com), 02 May 2014
   FreeBSD-style copyright and disclaimer apply

   Tests for log
*/

#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK

#include "service/logs.h"

#include <boost/test/unit_test.hpp>

using namespace std;
using namespace Datacratic;

extern Logging::Category a;
static Logging::Category c("c", "a");
Logging::Category a("a");
static Logging::Category b("b", "a");

BOOST_AUTO_TEST_CASE(blah)
{
    Logging::Category d("d", "a");
    Logging::Category e("e", "d");

    BOOST_CHECK(a.isEnabled());
    BOOST_CHECK(b.isEnabled());
    BOOST_CHECK(c.isEnabled());
    BOOST_CHECK(d.isEnabled());
    BOOST_CHECK(e.isEnabled());

    BOOST_CHECK(!!a.getWriter());
    BOOST_CHECK(!!b.getWriter());
    BOOST_CHECK(!!c.getWriter());
    BOOST_CHECK(!!d.getWriter());
    BOOST_CHECK(!!e.getWriter());

    Logging::Category::root().deactivate();
    BOOST_CHECK(!a.isEnabled());
    BOOST_CHECK(!b.isEnabled());
    BOOST_CHECK(!c.isEnabled());
    BOOST_CHECK(!d.isEnabled());
    BOOST_CHECK(!e.isEnabled());
}
<commit_msg>fixed include path<commit_after>/* logs_test.cc                                 -*- C++ -*-
   Rémi Attab (remi.attab@gmail.com), 02 May 2014
   FreeBSD-style copyright and disclaimer apply

   Tests for log
*/

#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK

#include "soa/service/logs.h"

#include <boost/test/unit_test.hpp>

using namespace std;
using namespace Datacratic;

extern Logging::Category a;
static Logging::Category c("c", "a");
Logging::Category a("a");
static Logging::Category b("b", "a");

BOOST_AUTO_TEST_CASE(blah)
{
    Logging::Category d("d", "a");
    Logging::Category e("e", "d");

    BOOST_CHECK(a.isEnabled());
    BOOST_CHECK(b.isEnabled());
    BOOST_CHECK(c.isEnabled());
    BOOST_CHECK(d.isEnabled());
    BOOST_CHECK(e.isEnabled());

    BOOST_CHECK(!!a.getWriter());
    BOOST_CHECK(!!b.getWriter());
    BOOST_CHECK(!!c.getWriter());
    BOOST_CHECK(!!d.getWriter());
    BOOST_CHECK(!!e.getWriter());

    Logging::Category::root().deactivate();
    BOOST_CHECK(!a.isEnabled());
    BOOST_CHECK(!b.isEnabled());
    BOOST_CHECK(!c.isEnabled());
    BOOST_CHECK(!d.isEnabled());
    BOOST_CHECK(!e.isEnabled());
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <comphelper/proxyaggregation.hxx>
#include <com/sun/star/reflection/ProxyFactory.hpp>

//.............................................................................
namespace comphelper
{
//.............................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::reflection;

    //=========================================================================
    //= OProxyAggregation
    //=========================================================================
    //-------------------------------------------------------------------------
    OProxyAggregation::OProxyAggregation( const Reference< XComponentContext >& _rxContext )
        :m_xContext( _rxContext )
    {
    }

    //-------------------------------------------------------------------------
    void OProxyAggregation::baseAggregateProxyFor( const Reference< XInterface >& _rxComponent, oslInterlockedCount& _rRefCount,
            ::cppu::OWeakObject& _rDelegator )
    {
        // first a factory for the proxy
        Reference< XProxyFactory > xFactory = ProxyFactory::create( m_xContext );

        // then the proxy itself
        { // i36686 OJ: achieve the desctruction of the tempoary -> otherwise it leads to _rRefCount -= 2
            m_xProxyAggregate = xFactory->createProxy( _rxComponent );
        }
        if ( m_xProxyAggregate.is() )
            m_xProxyAggregate->queryAggregation( ::getCppuType( &m_xProxyTypeAccess ) ) >>= m_xProxyTypeAccess;

        // aggregate the proxy
        osl_atomic_increment( &_rRefCount );
        if ( m_xProxyAggregate.is() )
        {
            // At this point in time, the proxy has a ref count of exactly two - in m_xControlContextProxy,
            // and in m_xProxyTypeAccess.
            // Remember to _not_ reset these members unless the delegator of the proxy has been reset, too!
            m_xProxyAggregate->setDelegator( _rDelegator );
        }
        osl_atomic_decrement( &_rRefCount );
    }

    //-------------------------------------------------------------------------
    Any SAL_CALL OProxyAggregation::queryAggregation( const Type& _rType ) throw (RuntimeException)
    {
        return m_xProxyAggregate.is() ? m_xProxyAggregate->queryAggregation( _rType ) : Any();
    }

    //-------------------------------------------------------------------------
    Sequence< Type > SAL_CALL OProxyAggregation::getTypes(  ) throw (RuntimeException)
    {
        Sequence< Type > aTypes;
        if ( m_xProxyAggregate.is() )
        {
            if ( m_xProxyTypeAccess.is() )
                aTypes = m_xProxyTypeAccess->getTypes();
        }
        return aTypes;
    }

    //-------------------------------------------------------------------------
    OProxyAggregation::~OProxyAggregation()
    {
        if ( m_xProxyAggregate.is() )
            m_xProxyAggregate->setDelegator( NULL );
        m_xProxyAggregate.clear();
        m_xProxyTypeAccess.clear();
            // this should remove the _two_only_ "real" references (means not delegated to
            // ourself) to this proxy, and thus delete it
    }

    //=========================================================================
    //= OComponentProxyAggregationHelper
    //=========================================================================
    //-------------------------------------------------------------------------
    OComponentProxyAggregationHelper::OComponentProxyAggregationHelper( const Reference< XComponentContext >& _rxContext,
        ::cppu::OBroadcastHelper& _rBHelper )
        :OProxyAggregation( _rxContext )
        ,m_rBHelper( _rBHelper )
    {
        OSL_ENSURE( _rxContext.is(), "OComponentProxyAggregationHelper::OComponentProxyAggregationHelper: invalid arguments!" );
    }

    //-------------------------------------------------------------------------
    void OComponentProxyAggregationHelper::componentAggregateProxyFor(
        const Reference< XComponent >& _rxComponent, oslInterlockedCount& _rRefCount,
        ::cppu::OWeakObject& _rDelegator )
    {
        OSL_ENSURE( _rxComponent.is(), "OComponentProxyAggregationHelper::componentAggregateProxyFor: invalid inner component!" );
        m_xInner = _rxComponent;

        // aggregate a proxy for the object
        baseAggregateProxyFor( m_xInner.get(), _rRefCount, _rDelegator );

        // add as event listener to the inner context, because we want to be notified of disposals
        osl_atomic_increment( &_rRefCount );
        {
            if ( m_xInner.is() )
                m_xInner->addEventListener( this );
        }
        osl_atomic_decrement( &_rRefCount );
    }

    //-------------------------------------------------------------------------
    Any SAL_CALL OComponentProxyAggregationHelper::queryInterface( const Type& _rType ) throw (RuntimeException)
    {
        Any aReturn( BASE::queryInterface( _rType ) );
        if ( !aReturn.hasValue() )
            aReturn = OProxyAggregation::queryAggregation( _rType );
        return aReturn;
    }

    //-------------------------------------------------------------------------
    IMPLEMENT_FORWARD_XTYPEPROVIDER2( OComponentProxyAggregationHelper, BASE, OProxyAggregation )

    //-------------------------------------------------------------------------
    OComponentProxyAggregationHelper::~OComponentProxyAggregationHelper( )
    {
        OSL_ENSURE( m_rBHelper.bDisposed, "OComponentProxyAggregationHelper::~OComponentProxyAggregationHelper: you should dispose your derived class in the dtor, if necessary!" );
            // if this asserts, add the following to your derived class dtor:
            //
            // if ( !m_rBHelper.bDisposed )
            // {
            //   acquire(); // to prevent duplicate dtor calls
            //   dispose();
            // }

        m_xInner.clear();
    }

    //-------------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregationHelper::disposing( const EventObject& _rSource ) throw (RuntimeException)
    {
        if ( _rSource.Source == m_xInner )
        {   // it's our inner context which is dying -> dispose ourself
            if ( !m_rBHelper.bDisposed && !m_rBHelper.bInDispose )
            {   // (if necessary only, of course)
                dispose();
            }
        }
    }

    //-------------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregationHelper::dispose() throw( RuntimeException )
    {
        ::osl::MutexGuard aGuard( m_rBHelper.rMutex );

        // dispose our inner context
        // before we do this, remove ourself as listener - else in disposing( EventObject ), we
        // would dispose ourself a second time
        Reference< XComponent > xComp( m_xInner, UNO_QUERY );
        if ( xComp.is() )
        {
            xComp->removeEventListener( this );
            xComp->dispose();
            xComp.clear();
        }
    }

    //=========================================================================
    //= OComponentProxyAggregation
    //=========================================================================
    //-------------------------------------------------------------------------
    OComponentProxyAggregation::OComponentProxyAggregation( const Reference< XComponentContext >& _rxContext,
            const Reference< XComponent >& _rxComponent )
        :OComponentProxyAggregation_CBase( m_aMutex )
        ,OComponentProxyAggregationHelper( _rxContext, rBHelper )
    {
        OSL_ENSURE( _rxComponent.is(), "OComponentProxyAggregation::OComponentProxyAggregation: accessible is no XComponent!" );
        if ( _rxComponent.is() )
            componentAggregateProxyFor( _rxComponent, m_refCount, *this );
    }

    //-------------------------------------------------------------------------
    OComponentProxyAggregation::~OComponentProxyAggregation()
    {
        implEnsureDisposeInDtor( );
    }

    //-------------------------------------------------------------------------
    IMPLEMENT_FORWARD_XINTERFACE2( OComponentProxyAggregation, OComponentProxyAggregation_CBase, OComponentProxyAggregationHelper )

    //-------------------------------------------------------------------------
    IMPLEMENT_GET_IMPLEMENTATION_ID( OComponentProxyAggregation )

    //-------------------------------------------------------------------------
    Sequence< Type > SAL_CALL OComponentProxyAggregation::getTypes(  ) throw (RuntimeException)
    {
        Sequence< Type > aTypes( OComponentProxyAggregationHelper::getTypes() );

        // append XComponent, coming from OComponentProxyAggregation_CBase
        sal_Int32 nLen = aTypes.getLength();
        aTypes.realloc( nLen + 1 );
        aTypes[ nLen ] = ::getCppuType( static_cast< Reference< XComponent >* >( NULL ) );

        return aTypes;
    }

    //-------------------------------------------------------------------------
    void OComponentProxyAggregation::implEnsureDisposeInDtor( )
    {
        if ( !rBHelper.bDisposed )
        {
            acquire();  // to prevent duplicate dtor calls
            dispose();
        }
    }

    //--------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregation::disposing( const EventObject& _rSource ) throw (RuntimeException)
    {
        // simly disambiguate - this is necessary for MSVC to distinguish
        // "disposing( EventObject )" from "disposing()"
        OComponentProxyAggregationHelper::disposing( _rSource );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregation::disposing()  throw (RuntimeException)
    {
        // call the dispose-functionality of the base, which will dispose our aggregated component
        OComponentProxyAggregationHelper::dispose();
    }

    //--------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregation::dispose() throw( RuntimeException )
    {
        // simply disambiguate
        OComponentProxyAggregation_CBase::dispose();
    }

//.............................................................................
}   // namespace comphelper
//.............................................................................

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Related rhbz#928568: Detect aggregators listening at themselves<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "sal/config.h"

#include <cassert>

#include <comphelper/proxyaggregation.hxx>
#include <com/sun/star/reflection/ProxyFactory.hpp>

//.............................................................................
namespace comphelper
{
//.............................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::reflection;

    //=========================================================================
    //= OProxyAggregation
    //=========================================================================
    //-------------------------------------------------------------------------
    OProxyAggregation::OProxyAggregation( const Reference< XComponentContext >& _rxContext )
        :m_xContext( _rxContext )
    {
    }

    //-------------------------------------------------------------------------
    void OProxyAggregation::baseAggregateProxyFor( const Reference< XInterface >& _rxComponent, oslInterlockedCount& _rRefCount,
            ::cppu::OWeakObject& _rDelegator )
    {
        // first a factory for the proxy
        Reference< XProxyFactory > xFactory = ProxyFactory::create( m_xContext );

        // then the proxy itself
        { // i36686 OJ: achieve the desctruction of the tempoary -> otherwise it leads to _rRefCount -= 2
            m_xProxyAggregate = xFactory->createProxy( _rxComponent );
        }
        if ( m_xProxyAggregate.is() )
            m_xProxyAggregate->queryAggregation( ::getCppuType( &m_xProxyTypeAccess ) ) >>= m_xProxyTypeAccess;

        // aggregate the proxy
        osl_atomic_increment( &_rRefCount );
        if ( m_xProxyAggregate.is() )
        {
            // At this point in time, the proxy has a ref count of exactly two - in m_xControlContextProxy,
            // and in m_xProxyTypeAccess.
            // Remember to _not_ reset these members unless the delegator of the proxy has been reset, too!
            m_xProxyAggregate->setDelegator( _rDelegator );
        }
        osl_atomic_decrement( &_rRefCount );
    }

    //-------------------------------------------------------------------------
    Any SAL_CALL OProxyAggregation::queryAggregation( const Type& _rType ) throw (RuntimeException)
    {
        return m_xProxyAggregate.is() ? m_xProxyAggregate->queryAggregation( _rType ) : Any();
    }

    //-------------------------------------------------------------------------
    Sequence< Type > SAL_CALL OProxyAggregation::getTypes(  ) throw (RuntimeException)
    {
        Sequence< Type > aTypes;
        if ( m_xProxyAggregate.is() )
        {
            if ( m_xProxyTypeAccess.is() )
                aTypes = m_xProxyTypeAccess->getTypes();
        }
        return aTypes;
    }

    //-------------------------------------------------------------------------
    OProxyAggregation::~OProxyAggregation()
    {
        if ( m_xProxyAggregate.is() )
            m_xProxyAggregate->setDelegator( NULL );
        m_xProxyAggregate.clear();
        m_xProxyTypeAccess.clear();
            // this should remove the _two_only_ "real" references (means not delegated to
            // ourself) to this proxy, and thus delete it
    }

    //=========================================================================
    //= OComponentProxyAggregationHelper
    //=========================================================================
    //-------------------------------------------------------------------------
    OComponentProxyAggregationHelper::OComponentProxyAggregationHelper( const Reference< XComponentContext >& _rxContext,
        ::cppu::OBroadcastHelper& _rBHelper )
        :OProxyAggregation( _rxContext )
        ,m_rBHelper( _rBHelper )
    {
        OSL_ENSURE( _rxContext.is(), "OComponentProxyAggregationHelper::OComponentProxyAggregationHelper: invalid arguments!" );
    }

    //-------------------------------------------------------------------------
    void OComponentProxyAggregationHelper::componentAggregateProxyFor(
        const Reference< XComponent >& _rxComponent, oslInterlockedCount& _rRefCount,
        ::cppu::OWeakObject& _rDelegator )
    {
        OSL_ENSURE( _rxComponent.is(), "OComponentProxyAggregationHelper::componentAggregateProxyFor: invalid inner component!" );
        m_xInner = _rxComponent;

        // aggregate a proxy for the object
        baseAggregateProxyFor( m_xInner.get(), _rRefCount, _rDelegator );

        // add as event listener to the inner context, because we want to be notified of disposals
        osl_atomic_increment( &_rRefCount );
        {
            if ( m_xInner.is() )
                m_xInner->addEventListener( this );
        }
        osl_atomic_decrement( &_rRefCount );
    }

    //-------------------------------------------------------------------------
    Any SAL_CALL OComponentProxyAggregationHelper::queryInterface( const Type& _rType ) throw (RuntimeException)
    {
        Any aReturn( BASE::queryInterface( _rType ) );
        if ( !aReturn.hasValue() )
            aReturn = OProxyAggregation::queryAggregation( _rType );
        return aReturn;
    }

    //-------------------------------------------------------------------------
    IMPLEMENT_FORWARD_XTYPEPROVIDER2( OComponentProxyAggregationHelper, BASE, OProxyAggregation )

    //-------------------------------------------------------------------------
    OComponentProxyAggregationHelper::~OComponentProxyAggregationHelper( )
    {
        OSL_ENSURE( m_rBHelper.bDisposed, "OComponentProxyAggregationHelper::~OComponentProxyAggregationHelper: you should dispose your derived class in the dtor, if necessary!" );
            // if this asserts, add the following to your derived class dtor:
            //
            // if ( !m_rBHelper.bDisposed )
            // {
            //   acquire(); // to prevent duplicate dtor calls
            //   dispose();
            // }

        m_xInner.clear();
    }

    //-------------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregationHelper::disposing( const EventObject& _rSource ) throw (RuntimeException)
    {
        if ( _rSource.Source == m_xInner )
        {   // it's our inner context which is dying -> dispose ourself
            if ( !m_rBHelper.bDisposed && !m_rBHelper.bInDispose )
            {   // (if necessary only, of course)
                dispose();
            }
        }
    }

    //-------------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregationHelper::dispose() throw( RuntimeException )
    {
        ::osl::MutexGuard aGuard( m_rBHelper.rMutex );

        // dispose our inner context
        // before we do this, remove ourself as listener - else in disposing( EventObject ), we
        // would dispose ourself a second time
        Reference< XComponent > xComp( m_xInner, UNO_QUERY );
        if ( xComp.is() )
        {
            xComp->removeEventListener( this );
            xComp->dispose();
            xComp.clear();
        }
    }

    //=========================================================================
    //= OComponentProxyAggregation
    //=========================================================================
    //-------------------------------------------------------------------------
    OComponentProxyAggregation::OComponentProxyAggregation( const Reference< XComponentContext >& _rxContext,
            const Reference< XComponent >& _rxComponent )
        :OComponentProxyAggregation_CBase( m_aMutex )
        ,OComponentProxyAggregationHelper( _rxContext, rBHelper )
    {
        OSL_ENSURE( _rxComponent.is(), "OComponentProxyAggregation::OComponentProxyAggregation: accessible is no XComponent!" );
        if ( _rxComponent.is() )
            componentAggregateProxyFor( _rxComponent, m_refCount, *this );
    }

    //-------------------------------------------------------------------------
    OComponentProxyAggregation::~OComponentProxyAggregation()
    {
        implEnsureDisposeInDtor( );
    }

    //-------------------------------------------------------------------------
    IMPLEMENT_FORWARD_XINTERFACE2( OComponentProxyAggregation, OComponentProxyAggregation_CBase, OComponentProxyAggregationHelper )

    //-------------------------------------------------------------------------
    IMPLEMENT_GET_IMPLEMENTATION_ID( OComponentProxyAggregation )

    //-------------------------------------------------------------------------
    Sequence< Type > SAL_CALL OComponentProxyAggregation::getTypes(  ) throw (RuntimeException)
    {
        Sequence< Type > aTypes( OComponentProxyAggregationHelper::getTypes() );

        // append XComponent, coming from OComponentProxyAggregation_CBase
        sal_Int32 nLen = aTypes.getLength();
        aTypes.realloc( nLen + 1 );
        aTypes[ nLen ] = ::getCppuType( static_cast< Reference< XComponent >* >( NULL ) );

        return aTypes;
    }

    //-------------------------------------------------------------------------
    void OComponentProxyAggregation::implEnsureDisposeInDtor( )
    {
        if ( !rBHelper.bDisposed )
        {
            acquire();  // to prevent duplicate dtor calls
            dispose();
        }
    }

    //--------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregation::disposing( const EventObject& _rSource ) throw (RuntimeException)
    {
        // Simply disambiguate---this is necessary for MSVC to distinguish
        // "disposing(EventObject)" from "disposing()"; but it is also a good
        // place to check for recursive calls that would be caused by an object
        // being registered as an XEventListener at itself (cf. rhbz#928568):
        assert(_rSource.Source != static_cast< cppu::OWeakObject * >(this));
        OComponentProxyAggregationHelper::disposing( _rSource );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregation::disposing()  throw (RuntimeException)
    {
        // call the dispose-functionality of the base, which will dispose our aggregated component
        OComponentProxyAggregationHelper::dispose();
    }

    //--------------------------------------------------------------------
    void SAL_CALL OComponentProxyAggregation::dispose() throw( RuntimeException )
    {
        // simply disambiguate
        OComponentProxyAggregation_CBase::dispose();
    }

//.............................................................................
}   // namespace comphelper
//.............................................................................

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include <algorithm>
#include <iostream>
#include <limits>
#include <sstream>
#include <vector>

#include <platform/cb_malloc.h>

#include "configuration.h"

#ifdef AUTOCONF_BUILD
#include "generated_configuration.cc"
#endif

#define STATWRITER_NAMESPACE config
#include "statwriter.h"
#undef STATWRITER_NAMESPACE

Configuration::Configuration() {
    initialize();
}

std::string Configuration::getString(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return std::string();
    }
    if (iter->second.datatype != DT_STRING) {
        throw std::invalid_argument("Configuration::getString: key (which is " +
                        std::to_string(iter->second.datatype) +
                        ") is not DT_STRING");
    }

    if (iter->second.val.v_string) {
        return std::string(iter->second.val.v_string);
    }
    return std::string();
}

bool Configuration::getBool(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return false;
    }
    if (iter->second.datatype != DT_BOOL) {
        throw std::invalid_argument("Configuration::getBool: key (which is " +
                        std::to_string(iter->second.datatype) +
                        ") is not DT_BOOL");
    }
    return iter->second.val.v_bool;
}

float Configuration::getFloat(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return 0;
    }
    if (iter->second.datatype != DT_FLOAT) {
        throw std::invalid_argument("Configuration::getFloat: key (which is " +
                        std::to_string(iter->second.datatype) +
                        ") is not DT_FLOAT");
    }
    return iter->second.val.v_float;
}

size_t Configuration::getInteger(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return 0;
    }
    if (iter->second.datatype != DT_SIZE) {
        throw std::invalid_argument("Configuration::getInteger: key (which is " +
                        std::to_string(iter->second.datatype) +
                        ") is not DT_SIZE");
    }
    return iter->second.val.v_size;
}

ssize_t Configuration::getSignedInteger(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return 0;
    }
    if (iter->second.datatype != DT_SSIZE) {
        throw std::invalid_argument("Configuration::getSignedInteger: key "
                        "(which is " + std::to_string(iter->second.datatype) +
                        ") is not DT_SSIZE");
    }
    return iter->second.val.v_ssize;
}

std::ostream& operator <<(std::ostream &out, const Configuration &config) {
    LockHolder lh(config.mutex);
    for (const auto& attribute : config.attributes) {
        std::stringstream line;
        line << attribute.first.c_str();
        line << " = [";
        switch (attribute.second.datatype) {
        case DT_BOOL:
            if (attribute.second.val.v_bool) {
                line << "true";
            } else {
                line << "false";
            }
            break;
        case DT_STRING:
            line << attribute.second.val.v_string;
            break;
        case DT_SIZE:
            line << attribute.second.val.v_size;
            break;
        case DT_SSIZE:
            line << attribute.second.val.v_ssize;
            break;
        case DT_FLOAT:
            line << attribute.second.val.v_float;
            break;
        case DT_CONFIGFILE:
            continue;
        default:
            // ignore
            ;
        }
        line << "]" << std::endl;
        out << line.str();
    }

    return out;
}

void Configuration::setParameter(const std::string &key, bool value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);
        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateBool(key, value);
            }
        }
        attributes[key].datatype = DT_BOOL;
        attributes[key].val.v_bool = value;
        copy = attributes[key].changeListener;
    }

    for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
        (*iter)->booleanValueChanged(key, value);
    }
}

void Configuration::setParameter(const std::string &key, size_t value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);
        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateSize(key, value);
            }
        }
        attributes[key].datatype = DT_SIZE;
        if (key.compare("cache_size") == 0) {
            attributes["max_size"].val.v_size = value;
        } else {
            attributes[key].val.v_size = value;
        }

        copy = attributes[key].changeListener;
    }

    for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
        (*iter)->sizeValueChanged(key, value);
    }
}

void Configuration::setParameter(const std::string &key, ssize_t value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);
        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateSSize(key, value);
            }
        }
        attributes[key].datatype = DT_SSIZE;
        if (key.compare("cache_size") == 0) {
            attributes["max_size"].val.v_ssize = value;
        } else {
            attributes[key].val.v_ssize = value;
        }

        copy = attributes[key].changeListener;
    }

    for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
        (*iter)->sizeValueChanged(key, value);
    }
}

void Configuration::setParameter(const std::string &key, float value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);

        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateFloat(key, value);
            }
        }

        attributes[key].datatype = DT_FLOAT;
        attributes[key].val.v_float = value;
        copy = attributes[key].changeListener;
    }

    for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
        (*iter)->floatValueChanged(key, value);
    }
}

void Configuration::setParameter(const std::string &key,
                                 const std::string &value) {
    if (value.length() == 0) {
        setParameter(key, (const char *)NULL);
    } else {
        setParameter(key, value.c_str());
    }
}

void Configuration::setParameter(const std::string &key, const char *value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);
        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateString(key, value);
            }
        }

        if (attributes.find(key) != attributes.end() && attributes[key].datatype
                                                        == DT_STRING) {
            cb_free((void*) attributes[key].val.v_string);
        }
        attributes[key].datatype = DT_STRING;
        attributes[key].val.v_string = NULL;
        if (value != NULL) {
            attributes[key].val.v_string = cb_strdup(value);
        }

        copy = attributes[key].changeListener;
    }

    for (const auto& item : copy) {
        item->stringValueChanged(key, value);
    }
}

void Configuration::addValueChangedListener(const std::string &key,
                                            ValueChangedListener *val) {
    LockHolder lh(mutex);
    if (attributes.find(key) != attributes.end()) {
        attributes[key].changeListener.push_back(val);
    }
}

ValueChangedValidator *Configuration::setValueValidator(const std::string &key,
                                            ValueChangedValidator *validator) {
    ValueChangedValidator *ret = nullptr;
    LockHolder lh(mutex);
    if (attributes.find(key) != attributes.end()) {
        ret = attributes[key].validator;
        attributes[key].validator = validator;
    }

    return ret;
}

void Configuration::addStats(ADD_STAT add_stat, const void *c) const {
    LockHolder lh(mutex);
    for (const auto& attribute :  attributes) {
        std::stringstream value;
        switch (attribute.second.datatype) {
        case DT_BOOL:
            value << std::boolalpha << attribute.second.val.v_bool << std::noboolalpha;
            break;
        case DT_STRING:
            value << attribute.second.val.v_string;
            break;
        case DT_SIZE:
            value << attribute.second.val.v_size;
            break;
        case DT_SSIZE:
            value << attribute.second.val.v_ssize;
            break;
        case DT_FLOAT:
            value << attribute.second.val.v_float;
            break;
        case DT_CONFIGFILE:
        default:
            // ignore
            ;
        }

        std::stringstream key;
        key << "ep_" << attribute.first;
        std::string k = key.str();
        add_casted_stat(k.c_str(), value.str().data(), add_stat, c);
    }
}

/**
 * Internal container of an engine parameter.
 */
class ConfigItem: public config_item {
public:
    ConfigItem(const char *theKey, config_datatype theDatatype) :
                                                                holder(NULL) {
        key = theKey;
        datatype = theDatatype;
        value.dt_string = &holder;
    }

private:
    char *holder;
};

bool Configuration::parseConfiguration(const char *str,
                                       SERVER_HANDLE_V1* sapi) {
    std::vector<ConfigItem *> config;

    for (const auto& attribute : attributes) {
        config.push_back(new ConfigItem(attribute.first.c_str(),
                                        attribute.second.datatype));
    }

    // we don't have a good support for alias yet...
    config.push_back(new ConfigItem("cache_size", DT_SIZE));

    // And add support for config files...
    config.push_back(new ConfigItem("config_file", DT_CONFIGFILE));

    const int nelem = config.size();
    std::vector<config_item> items(nelem + 1);
    for (int ii = 0; ii < nelem; ++ii) {
        items[ii].key = config[ii]->key;
        items[ii].datatype = config[ii]->datatype;
        items[ii].value.dt_string = config[ii]->value.dt_string;
    }

    bool ret = sapi->core->parse_config(str, items.data(), stderr) == 0;
    for (int ii = 0; ii < nelem; ++ii) {
        if (items[ii].found) {
            if (ret) {
                switch (items[ii].datatype) {
                case DT_STRING:
                    setParameter(items[ii].key, *(items[ii].value.dt_string));
                    break;
                case DT_SIZE:
                    setParameter(items[ii].key, *items[ii].value.dt_size);
                    break;
                case DT_SSIZE:
                    setParameter(items[ii].key,
                                 (ssize_t)*items[ii].value.dt_ssize);
                    break;
                case DT_BOOL:
                    setParameter(items[ii].key, *items[ii].value.dt_bool);
                    break;
                case DT_FLOAT:
                    setParameter(items[ii].key, *items[ii].value.dt_float);
                    break;
                case DT_CONFIGFILE:
                    throw std::logic_error("Configuration::parseConfiguration: "
                            "Unexpected DT_CONFIGFILE element after parse_config");
                    break;
                }
            }

            if (items[ii].datatype == DT_STRING) {
                cb_free(*items[ii].value.dt_string);
            }
        }
    }

    for (const auto& configItem : config) {
        delete configItem;
    }

    return ret;
}

Configuration::~Configuration() {
    for (const auto& attribute : attributes) {
        for (const auto& listener : attribute.second.changeListener) {
            delete listener;
        }

        delete attribute.second.validator;
        if (attribute.second.datatype == DT_STRING) {
            cb_free((void*) attribute.second.val.v_string);
        }
    }
}
<commit_msg>MB-22653: Remove manual memory management in the Configuration class<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include <algorithm>
#include <iostream>
#include <limits>
#include <sstream>
#include <vector>

#include <platform/cb_malloc.h>

#include "configuration.h"

#ifdef AUTOCONF_BUILD
#include "generated_configuration.cc"
#endif

#define STATWRITER_NAMESPACE config
#include "statwriter.h"
#undef STATWRITER_NAMESPACE

Configuration::Configuration() {
    initialize();
}

std::string Configuration::getString(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return std::string();
    }
    if (iter->second.datatype != DT_STRING) {
        throw std::invalid_argument("Configuration::getString: key (which is " +
                        std::to_string(iter->second.datatype) +
                        ") is not DT_STRING");
    }

    if (iter->second.val.v_string) {
        return std::string(iter->second.val.v_string);
    }
    return std::string();
}

bool Configuration::getBool(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return false;
    }
    if (iter->second.datatype != DT_BOOL) {
        throw std::invalid_argument("Configuration::getBool: key (which is " +
                        std::to_string(iter->second.datatype) +
                        ") is not DT_BOOL");
    }
    return iter->second.val.v_bool;
}

float Configuration::getFloat(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return 0;
    }
    if (iter->second.datatype != DT_FLOAT) {
        throw std::invalid_argument("Configuration::getFloat: key (which is " +
                        std::to_string(iter->second.datatype) +
                        ") is not DT_FLOAT");
    }
    return iter->second.val.v_float;
}

size_t Configuration::getInteger(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return 0;
    }
    if (iter->second.datatype != DT_SIZE) {
        throw std::invalid_argument("Configuration::getInteger: key (which is " +
                        std::to_string(iter->second.datatype) +
                        ") is not DT_SIZE");
    }
    return iter->second.val.v_size;
}

ssize_t Configuration::getSignedInteger(const std::string &key) const {
    LockHolder lh(mutex);

    const auto iter = attributes.find(key);
    if (iter == attributes.end()) {
        return 0;
    }
    if (iter->second.datatype != DT_SSIZE) {
        throw std::invalid_argument("Configuration::getSignedInteger: key "
                        "(which is " + std::to_string(iter->second.datatype) +
                        ") is not DT_SSIZE");
    }
    return iter->second.val.v_ssize;
}

std::ostream& operator <<(std::ostream &out, const Configuration &config) {
    LockHolder lh(config.mutex);
    for (const auto& attribute : config.attributes) {
        std::stringstream line;
        line << attribute.first.c_str();
        line << " = [";
        switch (attribute.second.datatype) {
        case DT_BOOL:
            if (attribute.second.val.v_bool) {
                line << "true";
            } else {
                line << "false";
            }
            break;
        case DT_STRING:
            line << attribute.second.val.v_string;
            break;
        case DT_SIZE:
            line << attribute.second.val.v_size;
            break;
        case DT_SSIZE:
            line << attribute.second.val.v_ssize;
            break;
        case DT_FLOAT:
            line << attribute.second.val.v_float;
            break;
        case DT_CONFIGFILE:
            continue;
        default:
            // ignore
            ;
        }
        line << "]" << std::endl;
        out << line.str();
    }

    return out;
}

void Configuration::setParameter(const std::string &key, bool value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);
        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateBool(key, value);
            }
        }
        attributes[key].datatype = DT_BOOL;
        attributes[key].val.v_bool = value;
        copy = attributes[key].changeListener;
    }

    for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
        (*iter)->booleanValueChanged(key, value);
    }
}

void Configuration::setParameter(const std::string &key, size_t value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);
        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateSize(key, value);
            }
        }
        attributes[key].datatype = DT_SIZE;
        if (key.compare("cache_size") == 0) {
            attributes["max_size"].val.v_size = value;
        } else {
            attributes[key].val.v_size = value;
        }

        copy = attributes[key].changeListener;
    }

    for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
        (*iter)->sizeValueChanged(key, value);
    }
}

void Configuration::setParameter(const std::string &key, ssize_t value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);
        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateSSize(key, value);
            }
        }
        attributes[key].datatype = DT_SSIZE;
        if (key.compare("cache_size") == 0) {
            attributes["max_size"].val.v_ssize = value;
        } else {
            attributes[key].val.v_ssize = value;
        }

        copy = attributes[key].changeListener;
    }

    for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
        (*iter)->sizeValueChanged(key, value);
    }
}

void Configuration::setParameter(const std::string &key, float value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);

        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateFloat(key, value);
            }
        }

        attributes[key].datatype = DT_FLOAT;
        attributes[key].val.v_float = value;
        copy = attributes[key].changeListener;
    }

    for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
        (*iter)->floatValueChanged(key, value);
    }
}

void Configuration::setParameter(const std::string &key,
                                 const std::string &value) {
    if (value.length() == 0) {
        setParameter(key, (const char *)NULL);
    } else {
        setParameter(key, value.c_str());
    }
}

void Configuration::setParameter(const std::string &key, const char *value) {
    std::vector<ValueChangedListener*> copy;
    {
        std::lock_guard<std::mutex> lh(mutex);
        auto validator = attributes.find(key);
        if (validator != attributes.end()) {
            if (validator->second.validator != NULL) {
                validator->second.validator->validateString(key, value);
            }
        }

        if (attributes.find(key) != attributes.end() && attributes[key].datatype
                                                        == DT_STRING) {
            cb_free((void*) attributes[key].val.v_string);
        }
        attributes[key].datatype = DT_STRING;
        attributes[key].val.v_string = NULL;
        if (value != NULL) {
            attributes[key].val.v_string = cb_strdup(value);
        }

        copy = attributes[key].changeListener;
    }

    for (const auto& item : copy) {
        item->stringValueChanged(key, value);
    }
}

void Configuration::addValueChangedListener(const std::string &key,
                                            ValueChangedListener *val) {
    LockHolder lh(mutex);
    if (attributes.find(key) != attributes.end()) {
        attributes[key].changeListener.push_back(val);
    }
}

ValueChangedValidator *Configuration::setValueValidator(const std::string &key,
                                            ValueChangedValidator *validator) {
    ValueChangedValidator *ret = nullptr;
    LockHolder lh(mutex);
    if (attributes.find(key) != attributes.end()) {
        ret = attributes[key].validator;
        attributes[key].validator = validator;
    }

    return ret;
}

void Configuration::addStats(ADD_STAT add_stat, const void *c) const {
    LockHolder lh(mutex);
    for (const auto& attribute :  attributes) {
        std::stringstream value;
        switch (attribute.second.datatype) {
        case DT_BOOL:
            value << std::boolalpha << attribute.second.val.v_bool << std::noboolalpha;
            break;
        case DT_STRING:
            value << attribute.second.val.v_string;
            break;
        case DT_SIZE:
            value << attribute.second.val.v_size;
            break;
        case DT_SSIZE:
            value << attribute.second.val.v_ssize;
            break;
        case DT_FLOAT:
            value << attribute.second.val.v_float;
            break;
        case DT_CONFIGFILE:
        default:
            // ignore
            ;
        }

        std::stringstream key;
        key << "ep_" << attribute.first;
        std::string k = key.str();
        add_casted_stat(k.c_str(), value.str().data(), add_stat, c);
    }
}

/**
 * Internal container of an engine parameter.
 */
class ConfigItem: public config_item {
public:
    ConfigItem(const char *theKey, config_datatype theDatatype) :
                                                                holder(NULL) {
        key = theKey;
        datatype = theDatatype;
        value.dt_string = &holder;
    }

private:
    char *holder;
};

bool Configuration::parseConfiguration(const char *str,
                                       SERVER_HANDLE_V1* sapi) {
    std::vector<std::unique_ptr<ConfigItem> > config;

    for (const auto& attribute : attributes) {
        config.push_back(std::make_unique<ConfigItem>(attribute.first.c_str(),
                                                      attribute.second.datatype));
    }

    // we don't have a good support for alias yet...
    config.push_back(std::make_unique<ConfigItem>("cache_size", DT_SIZE));

    // And add support for config files...
    config.push_back(std::make_unique<ConfigItem>("config_file", DT_CONFIGFILE));

    const int nelem = config.size();
    std::vector<config_item> items(nelem + 1);
    for (int ii = 0; ii < nelem; ++ii) {
        items[ii].key = config[ii]->key;
        items[ii].datatype = config[ii]->datatype;
        items[ii].value.dt_string = config[ii]->value.dt_string;
    }

    bool ret = sapi->core->parse_config(str, items.data(), stderr) == 0;
    for (int ii = 0; ii < nelem; ++ii) {
        if (items[ii].found) {
            if (ret) {
                switch (items[ii].datatype) {
                case DT_STRING:
                    setParameter(items[ii].key, *(items[ii].value.dt_string));
                    break;
                case DT_SIZE:
                    setParameter(items[ii].key, *items[ii].value.dt_size);
                    break;
                case DT_SSIZE:
                    setParameter(items[ii].key,
                                 (ssize_t)*items[ii].value.dt_ssize);
                    break;
                case DT_BOOL:
                    setParameter(items[ii].key, *items[ii].value.dt_bool);
                    break;
                case DT_FLOAT:
                    setParameter(items[ii].key, *items[ii].value.dt_float);
                    break;
                case DT_CONFIGFILE:
                    throw std::logic_error("Configuration::parseConfiguration: "
                            "Unexpected DT_CONFIGFILE element after parse_config");
                    break;
                }
            }

            if (items[ii].datatype == DT_STRING) {
                cb_free(*items[ii].value.dt_string);
            }
        }
    }

    return ret;
}

Configuration::~Configuration() {
    for (const auto& attribute : attributes) {
        for (const auto& listener : attribute.second.changeListener) {
            delete listener;
        }

        delete attribute.second.validator;
        if (attribute.second.datatype == DT_STRING) {
            cb_free((void*) attribute.second.val.v_string);
        }
    }
}
<|endoftext|>