<commit_before>#include "../tlang.h"
#include <taichi/util.h>
#include <taichi/visual/gui.h>
#include <taichi/system/profiler.h>
#include <taichi/visualization/particle_visualization.h>
#include <taichi/visual/texture.h>
#include "fem_interface.h"

TC_NAMESPACE_BEGIN

using namespace Tlang;

constexpr int dim = 3, n = 256;
constexpr int pre_and_post_smoothing = 3, bottom_smoothing = 200;
constexpr int mg_levels = 3;

auto mgpcg_poisson = []() {
  CoreState::set_trigger_gdb_when_crash(true);

  Program prog(Arch::x86_64);
  // prog.config.print_ir = true;
  prog.config.lazy_compilation = false;

  auto r = Vector(DataType::f32, mg_levels);
  auto z = Vector(DataType::f32, mg_levels);
  Global(x, f32);
  Global(p, f32);
  Global(Ap, f32);
  Global(alpha, f32);
  Global(beta, f32);
  Global(sum, f32);
  Global(phase, i32);

  int block_size = 8;

  bool block_soa = true;

  layout([&]() {
    auto ijk = Indices(0, 1, 2);
    std::function<void(Expr & expr)> place_scalar;

    SNode *block;
    if (block_soa) {
      block = &root.dense(ijk, n / block_size).bitmasked();  //.pointer();
      place_scalar = [&](Expr &s) { block->dense(ijk, block_size).place(s); };
    } else {
      place_scalar = [&](Expr &mat) {
        root.dense(ijk, n / block_size).dense(ijk, block_size).place(mat);
      };
    }

    place_scalar(x);
    place_scalar(p);
    place_scalar(Ap);
    place_scalar(r(0));
    place_scalar(z(0));
    for (int i = 1; i < mg_levels; i++) {
      root.dense(ijk, n / block_size)
          .bitmasked()
          .dense(ijk, block_size)
          .place(r(i), z(i));
    }
    root.place(alpha, beta, sum, phase);
  });

  Kernel(compute_Ap).def([&] {
    BlockDim(1024);
    Parallelize(8);
    Vectorize(block_size);
    For(Ap, [&](Expr i, Expr j, Expr k) {
      Ap[i, j, k] = 6.0f * p[i, j, k] - p[i - 1, j, k] - p[i + 1, j, k] -
                    p[i, j + 1, k] - p[i, j - 1, k] - p[i, j, k + 1] -
                    p[i, j, k - 1];
    });
  });

  Kernel(reduce_r).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      Atomic(sum[Expr(0)]) += r(0)[i, j, k] * r(0)[i, j, k];
    });
  });

  Kernel(reduce_zTr).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      Atomic(sum[Expr(0)]) += z(0)[i, j, k] * r(0)[i, j, k];
    });
  });

  Kernel(reduce_pAp).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      auto tmp = Var(0.0f);
      tmp += p[i, j, k] * Ap[i, j, k];
      Atomic(sum[Expr(0)]) += tmp;
    });
  });

  Kernel(update_x).def([&] {
    For(x, [&](Expr i, Expr j, Expr k) {
      x[i, j, k] += alpha[Expr(0)] * p[i, j, k];
    });
  });

  Kernel(update_r).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      r(0)[i, j, k] -= alpha[Expr(0)] * Ap[i, j, k];
    });
  });

  Kernel(update_p).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      p[i, j, k] = z(0)[i, j, k] + beta[Expr(0)] * p[i, j, k];
    });
  });

  int begin = n / 4, end = n * 3 / 4;
  for (int i = begin; i < end; i++) {
    for (int j = begin; j < end; j++) {
      for (int k = begin; k < end; k++) {
        r(0).val<float32>(i, j, k) =
            (i == n / 2) && (j == n / 2) && (k == n / 2);
      }
    }
  }

  std::vector<std::function<void()>> smoothers(mg_levels),
      restrictors(mg_levels - 1), prolongators(mg_levels - 1),
      clearer_z(mg_levels), clearer_r(mg_levels);

  for (int l = 0; l < mg_levels; l++) {
    if (l < mg_levels - 1) {
      prog.config.print_ir = true;
      restrictors[l] =
          kernel([&] {
            kernel_name(fmt::format("restrict_lv{}", l));
            Parallelize(8);
            Vectorize(1);
            For(r(l), [&](Expr i, Expr j, Expr k) {
              auto res =
                  Var(r(l)[i, j, k] - (6.0f * z(l)[i, j, k] -
                                       z(l)[i - 1, j, k] - z(l)[i + 1, j, k] -
                                       z(l)[i, j + 1, k] - z(l)[i, j - 1, k] -
                                       z(l)[i, j, k + 1] - z(l)[i, j, k - 1]));
              r(l + 1)[i / 2, j / 2, k / 2] += res * 0.5f;
            });
          })
              .func();
      prog.config.print_ir = false;
      prolongators[l] = kernel([&] {
                          kernel_name(fmt::format("prolongate_lv{}", l));
                          Parallelize(8);
                          Vectorize(1);
                          For(z(l), [&](Expr i, Expr j, Expr k) {
                            z(l)[i, j, k] += z(l + 1)[i / 2, j / 2, k / 2];
                          });
                        })
                            .func();
    }
    smoothers[l] =
        kernel([&] {
          kernel_name(fmt::format("smooth_lv{}", l));
          Parallelize(8);
          Vectorize(8);
          For(z(l), [&](Expr i, Expr j, Expr k) {
            auto ret = Var(z(l)[i, j, k]);
            If(((i + j + k) & 1) == phase[Expr(0)]).Then([&] {
              ret = (r(l)[i, j, k] + z(l)[i - 1, j, k] + z(l)[i + 1, j, k] +
                     z(l)[i, j + 1, k] + z(l)[i, j - 1, k] + z(l)[i, j, k + 1] +
                     z(l)[i, j, k - 1]) *
                    (1.0f / 6);
            });
            z(l)[i, j, k] = ret;
          });
        })
            .func();
    clearer_r[l] =
        kernel([&] {
          kernel_name(fmt::format("clear_r_lv{}", l));
          Parallelize(8);
          Vectorize(8);
          For(r(l), [&](Expr i, Expr j, Expr k) { r(l)[i, j, k] = 0.0f; });
        })
            .func();
    clearer_z[l] =
        kernel([&] {
          kernel_name(fmt::format("clear_z_lv{}", l));
          Parallelize(8);
          Vectorize(8);
          For(z(l), [&](Expr i, Expr j, Expr k) { z(l)[i, j, k] = 0.0f; });
        })
            .func();
  }

  // z = M^-1 r
  auto apply_preconditioner = [&] {
    clearer_z[0]();
    for (int l = 0; l < mg_levels - 1; l++) {
      for (int i = 0; i < (pre_and_post_smoothing << l); i++) {
        phase.val<int32>() = 0;
        smoothers[l]();
        phase.val<int32>() = 1;
        smoothers[l]();
      }
      clearer_z[l + 1]();
      clearer_r[l + 1]();
      restrictors[l]();
    }
    for (int i = 0; i < bottom_smoothing; i++) {
      phase.val<int32>() = 0;
      smoothers[mg_levels - 1]();
      phase.val<int32>() = 1;
      smoothers[mg_levels - 1]();
    }
    for (int l = mg_levels - 2; l >= 0; l--) {
      prolongators[l]();
      for (int i = 0; i < (pre_and_post_smoothing << l); i++) {
        phase.val<int32>() = 0;
        smoothers[l]();
        phase.val<int32>() = 1;
        smoothers[l]();
      }
    }
  };

  // r = b - Ax = b    since x = 0
  // p = r = r + 0 p
  apply_preconditioner();
  update_p();
  sum.val<float32>() = 0;
  reduce_zTr();
  auto old_zTr = sum.val<float32>();

  // CG
  auto t = Time::get_time();
  for (int i = 0; i < 40; i++) {
    TC_P(i);
    compute_Ap();
    sum.val<float32>() = 0;
    reduce_pAp();
    auto pAp = sum.val<float32>();
    // alpha = rTr / pTAp
    alpha.val<float32>() = old_zTr / pAp;
    TC_P(old_zTr);
    // TC_P(pAp);
    // TC_P(alpha.val<float32>());
    // x = x + alpha p
    update_x();
    // r = r - alpha Ap
    update_r();
    // return if |r| small
    // z = M^-1 r
    apply_preconditioner();
    sum.val<float32>() = 0;
    reduce_zTr();
    auto new_zTr = sum.val<float32>();
    TC_P(new_zTr);
    sum.val<float32>() = 0;
    reduce_r();
    auto rTr = sum.val<float32>();
    if (rTr < 1e-7f)
      break;
    // beta = new rTr / old rTr
    beta.val<float32>() = new_zTr / old_zTr;
    TC_P(beta.val<float32>());
    // p = z + beta p
    update_p();
    old_zTr = new_zTr;
  }
  TC_P(Time::get_time() - t);
  get_current_program().profiler_print();

  compute_Ap();
  auto residual = 0.0f;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      for (int k = 0; k < n; k++) {
        for (int d = 0; d < dim; d++) {
          // residual += std::abs(R[i][j][k][d] - Ap(d).val<float32>(i, j, k));
        }
      }
    }
  }
  TC_P(residual);
  // TC_P(difference_max);

  int gui_res = 512;
  GUI gui("MGPCG Poisson", Vector2i(gui_res + 200, gui_res), false);
  int gt = 0;
  int k = 0;
  gui.slider("z", k, 0, n - 1).slider("Ground truth", gt, 0, 1);

  int scale = gui_res / n;
  auto &canvas = gui.get_canvas();
  for (int frame = 1;; frame++) {
    for (int i = 0; i < gui_res - scale; i++) {
      for (int j = 0; j < gui_res - scale; j++) {
        real dx = x.val<float32>(i / scale, j / scale, k);
        canvas.img[i][j] = Vector4(0.5f) + Vector4(dx, dx, dx, 0) * 15.0f;
      }
    }
    gui.update();
  }
};
TC_REGISTER_TASK(mgpcg_poisson);

TC_NAMESPACE_END<commit_msg>mgpcg benchmark settings<commit_after>#include "../tlang.h"
#include <taichi/util.h>
#include <taichi/visual/gui.h>
#include <taichi/system/profiler.h>
#include <taichi/visualization/particle_visualization.h>
#include <taichi/visual/texture.h>
#include "fem_interface.h"

TC_NAMESPACE_BEGIN

using namespace Tlang;

constexpr int dim = 3, n = 256;
constexpr int pre_and_post_smoothing = 3, bottom_smoothing = 200;
constexpr int mg_levels = 3;

auto mgpcg_poisson = []() {
  CoreState::set_trigger_gdb_when_crash(true);

  Program prog(Arch::x86_64);
  // prog.config.print_ir = true;
  prog.config.lazy_compilation = false;

  auto r = Vector(DataType::f32, mg_levels);
  auto z = Vector(DataType::f32, mg_levels);
  Global(x, f32);
  Global(p, f32);
  Global(Ap, f32);
  Global(alpha, f32);
  Global(beta, f32);
  Global(sum, f32);
  Global(phase, i32);

  int block_size = 8;

  bool block_soa = true;

  layout([&]() {
    auto ijk = Indices(0, 1, 2);
    std::function<void(Expr & expr)> place_scalar;

    SNode *block;
    if (block_soa) {
      block = &root.dense(ijk, n / block_size).bitmasked();  //.pointer();
      place_scalar = [&](Expr &s) { block->dense(ijk, block_size).place(s); };
    } else {
      place_scalar = [&](Expr &mat) {
        root.dense(ijk, n / block_size).dense(ijk, block_size).place(mat);
      };
    }

    place_scalar(x);
    place_scalar(p);
    place_scalar(Ap);
    place_scalar(r(0));
    place_scalar(z(0));
    for (int i = 1; i < mg_levels; i++) {
      root.dense(ijk, n / block_size)
          .bitmasked()
          .dense(ijk, block_size)
          .place(r(i), z(i));
    }
    root.place(alpha, beta, sum, phase);
  });

  Kernel(compute_Ap).def([&] {
    BlockDim(1024);
    Parallelize(8);
    Vectorize(block_size);
    For(Ap, [&](Expr i, Expr j, Expr k) {
      Ap[i, j, k] = 6.0f * p[i, j, k] - p[i - 1, j, k] - p[i + 1, j, k] -
                    p[i, j + 1, k] - p[i, j - 1, k] - p[i, j, k + 1] -
                    p[i, j, k - 1];
    });
  });

  Kernel(reduce_r).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      Atomic(sum[Expr(0)]) += r(0)[i, j, k] * r(0)[i, j, k];
    });
  });

  Kernel(reduce_zTr).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      Atomic(sum[Expr(0)]) += z(0)[i, j, k] * r(0)[i, j, k];
    });
  });

  Kernel(reduce_pAp).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      auto tmp = Var(0.0f);
      tmp += p[i, j, k] * Ap[i, j, k];
      Atomic(sum[Expr(0)]) += tmp;
    });
  });

  Kernel(update_x).def([&] {
    For(x, [&](Expr i, Expr j, Expr k) {
      x[i, j, k] += alpha[Expr(0)] * p[i, j, k];
    });
  });

  Kernel(update_r).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      r(0)[i, j, k] -= alpha[Expr(0)] * Ap[i, j, k];
    });
  });

  Kernel(update_p).def([&] {
    For(p, [&](Expr i, Expr j, Expr k) {
      p[i, j, k] = z(0)[i, j, k] + beta[Expr(0)] * p[i, j, k];
    });
  });

  int begin = n / 4, end = n * 3 / 4;
  for (int i = begin; i < end; i++) {
    for (int j = begin; j < end; j++) {
      for (int k = begin; k < end; k++) {
        /*
        r(0).val<float32>(i, j, k) =
            (i == n / 2) && (j == n / 2) && (k == n / 2);
            */
        float x = (i - begin) * 2.0f / n;
        float y = (i - begin) * 2.0f / n;
        float z = (i - begin) * 2.0f / n;
        r(0).val<float32>(i, j, k) =
            sin(2 * pi  * x) * cos(2 * pi * y) * sin(2 * pi * z);
      }
    }
  }

  std::vector<std::function<void()>> smoothers(mg_levels),
      restrictors(mg_levels - 1), prolongators(mg_levels - 1),
      clearer_z(mg_levels), clearer_r(mg_levels);

  for (int l = 0; l < mg_levels; l++) {
    if (l < mg_levels - 1) {
      prog.config.print_ir = true;
      restrictors[l] =
          kernel([&] {
            kernel_name(fmt::format("restrict_lv{}", l));
            Parallelize(8);
            Vectorize(1);
            For(r(l), [&](Expr i, Expr j, Expr k) {
              auto res =
                  Var(r(l)[i, j, k] - (6.0f * z(l)[i, j, k] -
                                       z(l)[i - 1, j, k] - z(l)[i + 1, j, k] -
                                       z(l)[i, j + 1, k] - z(l)[i, j - 1, k] -
                                       z(l)[i, j, k + 1] - z(l)[i, j, k - 1]));
              r(l + 1)[i / 2, j / 2, k / 2] += res * 0.5f;
            });
          })
              .func();
      prog.config.print_ir = false;
      prolongators[l] = kernel([&] {
                          kernel_name(fmt::format("prolongate_lv{}", l));
                          Parallelize(8);
                          Vectorize(1);
                          For(z(l), [&](Expr i, Expr j, Expr k) {
                            z(l)[i, j, k] += z(l + 1)[i / 2, j / 2, k / 2];
                          });
                        })
                            .func();
    }
    smoothers[l] =
        kernel([&] {
          kernel_name(fmt::format("smooth_lv{}", l));
          Parallelize(8);
          Vectorize(8);
          For(z(l), [&](Expr i, Expr j, Expr k) {
            auto ret = Var(z(l)[i, j, k]);
            If(((i + j + k) & 1) == phase[Expr(0)]).Then([&] {
              ret = (r(l)[i, j, k] + z(l)[i - 1, j, k] + z(l)[i + 1, j, k] +
                     z(l)[i, j + 1, k] + z(l)[i, j - 1, k] + z(l)[i, j, k + 1] +
                     z(l)[i, j, k - 1]) *
                    (1.0f / 6);
            });
            z(l)[i, j, k] = ret;
          });
        })
            .func();
    clearer_r[l] =
        kernel([&] {
          kernel_name(fmt::format("clear_r_lv{}", l));
          Parallelize(8);
          Vectorize(8);
          For(r(l), [&](Expr i, Expr j, Expr k) { r(l)[i, j, k] = 0.0f; });
        })
            .func();
    clearer_z[l] =
        kernel([&] {
          kernel_name(fmt::format("clear_z_lv{}", l));
          Parallelize(8);
          Vectorize(8);
          For(z(l), [&](Expr i, Expr j, Expr k) { z(l)[i, j, k] = 0.0f; });
        })
            .func();
  }

  // z = M^-1 r
  auto apply_preconditioner = [&] {
    clearer_z[0]();
    for (int l = 0; l < mg_levels - 1; l++) {
      for (int i = 0; i < (pre_and_post_smoothing << l); i++) {
        phase.val<int32>() = 0;
        smoothers[l]();
        phase.val<int32>() = 1;
        smoothers[l]();
      }
      clearer_z[l + 1]();
      clearer_r[l + 1]();
      restrictors[l]();
    }
    for (int i = 0; i < bottom_smoothing; i++) {
      phase.val<int32>() = 0;
      smoothers[mg_levels - 1]();
      phase.val<int32>() = 1;
      smoothers[mg_levels - 1]();
    }
    for (int l = mg_levels - 2; l >= 0; l--) {
      prolongators[l]();
      for (int i = 0; i < (pre_and_post_smoothing << l); i++) {
        phase.val<int32>() = 0;
        smoothers[l]();
        phase.val<int32>() = 1;
        smoothers[l]();
      }
    }
  };

  // r = b - Ax = b    since x = 0
  // p = r = r + 0 p
  apply_preconditioner();
  update_p();
  sum.val<float32>() = 0;
  reduce_zTr();
  auto old_zTr = sum.val<float32>();

  // CG
  auto t = Time::get_time();
  for (int i = 0; i < 40; i++) {
    TC_P(i);
    compute_Ap();
    sum.val<float32>() = 0;
    reduce_pAp();
    auto pAp = sum.val<float32>();
    // alpha = rTr / pTAp
    alpha.val<float32>() = old_zTr / pAp;
    // TC_P(old_zTr);
    // TC_P(pAp);
    // TC_P(alpha.val<float32>());
    // x = x + alpha p
    update_x();
    // r = r - alpha Ap
    update_r();
    // return if |r| small
    // z = M^-1 r
    apply_preconditioner();
    sum.val<float32>() = 0;
    reduce_zTr();
    auto new_zTr = sum.val<float32>();
    // TC_P(new_zTr);
    sum.val<float32>() = 0;
    reduce_r();
    auto rTr = sum.val<float32>();
    TC_P(rTr);
    if (rTr < 1e-7f)
      break;
    // beta = new rTr / old rTr
    beta.val<float32>() = new_zTr / old_zTr;
    // TC_P(beta.val<float32>());
    // p = z + beta p
    update_p();
    old_zTr = new_zTr;
  }
  TC_P(Time::get_time() - t);
  get_current_program().profiler_print();

  compute_Ap();
  auto residual = 0.0f;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      for (int k = 0; k < n; k++) {
        for (int d = 0; d < dim; d++) {
          // residual += std::abs(R[i][j][k][d] - Ap(d).val<float32>(i, j, k));
        }
      }
    }
  }
  TC_P(residual);
  // TC_P(difference_max);

  int gui_res = 512;
  GUI gui("MGPCG Poisson", Vector2i(gui_res + 200, gui_res), false);
  int gt = 0;
  int k = 0;
  gui.slider("z", k, 0, n - 1).slider("Ground truth", gt, 0, 1);

  int scale = gui_res / n;
  auto &canvas = gui.get_canvas();
  for (int frame = 1;; frame++) {
    for (int i = 0; i < gui_res - scale; i++) {
      for (int j = 0; j < gui_res - scale; j++) {
        real dx = x.val<float32>(i / scale, j / scale, k);
        canvas.img[i][j] = Vector4(0.5f) + Vector4(dx, dx, dx, 0) * 0.01f;
      }
    }
    gui.update();
  }
};
TC_REGISTER_TASK(mgpcg_poisson);

TC_NAMESPACE_END<|endoftext|>


<commit_before>#ifndef __SERIALIZER_SEMANTIC_CHECKING_HPP__
#define __SERIALIZER_SEMANTIC_CHECKING_HPP__

#include "errors.hpp"
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <boost/crc.hpp>
#include "arch/arch.hpp"
#include "config/args.hpp"
#include "serializer/serializer.hpp"
#include "containers/two_level_array.hpp"

/* This is a thin wrapper around the log serializer that makes sure that the
serializer has the correct semantics. It must have exactly the same API as
the log serializer. */

//#define SERIALIZER_DEBUG_PRINT 1

// TODO (rntz) fix this for new serializer interface
template<class inner_serializer_t>
class semantic_checking_serializer_t :
    public serializer_t
{
private:
    inner_serializer_t inner_serializer;

    typedef uint32_t crc_t;

    struct block_info_t {
        enum state_t {
            state_unknown,
            state_deleted,
            state_have_crc
        } state;
        crc_t crc;

        // For compatibility with two_level_array_t
        block_info_t() : state(state_unknown) {}
        operator bool() { return state != state_unknown; }
    };

    two_level_array_t<block_info_t, MAX_BLOCK_ID> blocks;

    crc_t compute_crc(const void *buf) {
        boost::crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc_computer;
        // We need to not crc BLOCK_META_DATA_SIZE because it's
        // internal to the serializer.
        crc_computer.process_bytes(buf, get_block_size().value());
        return crc_computer.checksum();
    }

    int last_write_started, last_write_callbacked;

private:
    struct persisted_block_info_t {
        block_id_t block_id;
        block_info_t block_info;
    };
    int semantic_fd;

public:
    typedef typename inner_serializer_t::private_dynamic_config_t private_dynamic_config_t;
    typedef typename inner_serializer_t::dynamic_config_t dynamic_config_t;
    typedef typename inner_serializer_t::static_config_t static_config_t;

public:

    static void create(dynamic_config_t *config, private_dynamic_config_t *private_config, static_config_t *static_config) {
        inner_serializer_t::create(config, private_config, static_config);
    }

    semantic_checking_serializer_t(dynamic_config_t *config, private_dynamic_config_t *private_config)
        : inner_serializer(config, private_config),
          last_write_started(0), last_write_callbacked(0),
          semantic_fd(-1)
        {
            semantic_fd = open(private_config->semantic_filename.c_str(),
                O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
            if (semantic_fd == INVALID_FD)
                fail_due_to_user_error("Inaccessible semantic checking file: \"%s\": %s", private_config->semantic_filename.c_str(), strerror(errno));

            // fill up the blocks from the semantic checking file
            int res = -1;
            do {
                persisted_block_info_t buf;
                res = read(semantic_fd, &buf, sizeof(buf));
                guarantee_err(res != -1, "Could not read from the semantic checker file");
                if(res == sizeof(persisted_block_info_t)) {
                    blocks.set(buf.block_id.value, buf.block_info);
                }
            } while(res == sizeof(persisted_block_info_t));
        }

    ~semantic_checking_serializer_t() {
        close(semantic_fd);
    }

    typedef typename inner_serializer_t::check_callback_t check_callback_t;
    static void check_existing(const char *db_path, check_callback_t *cb) {
        inner_serializer_t::check_existing(db_path, cb);
    }

public:
    void *malloc() {
        return inner_serializer.malloc();
    }

    void *clone(void *data) {
        return inner_serializer.clone(data);
    }

    void free(void *ptr) {
        inner_serializer.free(ptr);
    }

    file_t::account_t *make_io_account(int priority, int outstanding_requests_limit = UNLIMITED_OUTSTANDING_REQUESTS) {
        return inner_serializer.make_io_account(priority, outstanding_requests_limit);
    }

public:
    /* For reads, we check to make sure that the data we get back in the read is
    consistent with what was last written there. */

    struct reader_t :
        public read_callback_t
    {
        semantic_checking_serializer_t *parent;
        block_id_t block_id;
        void *buf;
        block_info_t expected_block_state;
        read_callback_t *callback;

        reader_t(semantic_checking_serializer_t *parent, block_id_t block_id, void *buf, block_info_t expected_block_state)
            : parent(parent), block_id(block_id), buf(buf), expected_block_state(expected_block_state) {}

        void on_serializer_read() {
            /* Make sure that the value that the serializer returned was valid */

            crc_t actual_crc = parent->compute_crc(buf);

            switch (expected_block_state.state) {
                case block_info_t::state_unknown: {
                    /* We don't know what this block was supposed to contain, so we can't do any
                    verification */
                    break;
                }

                case block_info_t::state_deleted: {
                    unreachable("Cache asked for a deleted block, and serializer didn't complain.");
                }

                case block_info_t::state_have_crc: {
#ifdef SERIALIZER_DEBUG_PRINT
                    printf("Read %ld: %u\n", block_id, actual_crc);
#endif
                    guarantee(expected_block_state.crc == actual_crc, "Serializer returned bad value for block ID %u", block_id.value);
                    break;
                }
                default:
                    unreachable();
            }

            if (callback) callback->on_serializer_read();
            delete this;
        }
    };

    bool do_read(block_id_t block_id, void *buf, file_t::account_t *io_account, read_callback_t *callback) {
#ifdef SERIALIZER_DEBUG_PRINT
        printf("Reading %ld\n", block_id);
#endif
        reader_t *reader = new reader_t(this, block_id, buf, blocks.get(block_id.value));
        reader->callback = NULL;
        if (inner_serializer.do_read(block_id, buf, io_account, reader)) {
            reader->on_serializer_read();
            return true;
        } else {
            reader->callback = callback;
            return false;
        }
    }

    ser_transaction_id_t get_current_transaction_id(block_id_t block_id, const void* buf) {
        // TODO: Implement some checking for this operation
        return inner_serializer.get_current_transaction_id(block_id, buf);
    }

public:
    /* For writes, we make sure that the writes come back in the same order that
    we send them to the serializer. */

    struct writer_t :
        public write_txn_callback_t
    {
        semantic_checking_serializer_t *parent;
        int version;
        write_txn_callback_t *callback;

        writer_t(semantic_checking_serializer_t *parent, int version)
            : parent(parent), version(version) {}

        void on_serializer_write_txn() {
            guarantee(parent->last_write_callbacked == version-1, "Serializer completed writes in the wrong order.");
            parent->last_write_callbacked = version;
            if (callback) callback->on_serializer_write_txn();
            delete this;
       }
    };

    bool do_write(write_t *writes, int num_writes, file_t::account_t *io_account, write_txn_callback_t *callback, write_tid_callback_t *tid_callback = NULL) {
        for (int i = 0; i < num_writes; i++) {

            if (!writes[i].buf_specified) continue;

            block_info_t b;
            memset(&b, 0, sizeof(b));  // make valgrind happy
            if (writes[i].buf) {
                b.state = block_info_t::state_have_crc;
                b.crc = compute_crc(writes[i].buf);
#ifdef SERIALIZER_DEBUG_PRINT
                printf("Writing %ld: %u\n", writes[i].block_id, b.crc);
#endif
            } else {
                b.state = block_info_t::state_deleted;
#ifdef SERIALIZER_DEBUG_PRINT
                printf("Deleting %ld\n", writes[i].block_id);
#endif
            }
            blocks.set(writes[i].block_id.value, b);

            // Add the block to the semantic checker file
            persisted_block_info_t buf;
#ifdef VALGRIND
            memset(&buf, 0, sizeof(buf));  // make valgrind happy
#endif
            buf.block_id = writes[i].block_id;
            buf.block_info = b;
            int res = write(semantic_fd, &buf, sizeof(buf));
            guarantee_err(res == sizeof(buf), "Could not write data to semantic checker file");
        }

        writer_t *writer = new writer_t(this, ++last_write_started);
        writer->callback = NULL;
        if (inner_serializer.do_write(writes, num_writes, io_account, writer, tid_callback)) {
            writer->on_serializer_write_txn();
            return true;
        } else {
            writer->callback = callback;
            return false;
        }
    }

public:
    block_size_t get_block_size() {
        return inner_serializer.get_block_size();
    }

    block_id_t max_block_id() {
        return inner_serializer.max_block_id();
    }

    bool block_in_use(block_id_t id) {
        bool in_use = inner_serializer.block_in_use(id);
        switch (blocks.get(id.value).state) {
            case block_info_t::state_unknown: break;
            case block_info_t::state_deleted: rassert(!in_use); break;
            case block_info_t::state_have_crc: rassert(in_use); break;
            default: unreachable();
        }
        return in_use;
    }

    repli_timestamp_t get_recency(block_id_t id) {
        return inner_serializer.get_recency(id);
    }

    bool register_read_ahead_cb(read_ahead_callback_t *cb) {
        // Ignore this, it might make the checking ineffective...
    }
    bool unregister_read_ahead_cb(read_ahead_callback_t *cb) {
        return false;
    }

public:
    struct shutdown_callback_t {
        virtual void on_serializer_shutdown(semantic_checking_serializer_t *) = 0;
        virtual ~shutdown_callback_t() {}
    };
    bool shutdown(shutdown_callback_t *cb) {
        shutdown_callback = cb;
        return inner_serializer.shutdown(this);
    }
private:
    shutdown_callback_t *shutdown_callback;
    void on_serializer_shutdown(inner_serializer_t *ser) {
        if (shutdown_callback) shutdown_callback->on_serializer_shutdown(this);
    }

public:
    typedef typename inner_serializer_t::gc_disable_callback_t gc_disable_callback_t;
    bool disable_gc(gc_disable_callback_t *cb) {
        return inner_serializer.disable_gc(cb);
    }
    bool enable_gc() {
        return inner_serializer.enable_gc();
    }

};

#endif /* __SERIALIZER_SEMANTIC_CHECKING_HPP__ */
<commit_msg>serializer/semantic_checking.hpp: add TODO<commit_after>#ifndef __SERIALIZER_SEMANTIC_CHECKING_HPP__
#define __SERIALIZER_SEMANTIC_CHECKING_HPP__

#include "errors.hpp"
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <boost/crc.hpp>
#include "arch/arch.hpp"
#include "config/args.hpp"
#include "serializer/serializer.hpp"
#include "containers/two_level_array.hpp"

/* This is a thin wrapper around the log serializer that makes sure that the
serializer has the correct semantics. It must have exactly the same API as
the log serializer. */

//#define SERIALIZER_DEBUG_PRINT 1

// TODO make this just an interface and move implementation into semantic_checking.tcc, then use
// tim's template hack to instantiate as necessary in a .cc file.

// TODO (rntz) fix this for new serializer interface
template<class inner_serializer_t>
class semantic_checking_serializer_t :
    public serializer_t
{
private:
    inner_serializer_t inner_serializer;

    typedef uint32_t crc_t;

    struct block_info_t {
        enum state_t {
            state_unknown,
            state_deleted,
            state_have_crc
        } state;
        crc_t crc;

        // For compatibility with two_level_array_t
        block_info_t() : state(state_unknown) {}
        operator bool() { return state != state_unknown; }
    };

    two_level_array_t<block_info_t, MAX_BLOCK_ID> blocks;

    crc_t compute_crc(const void *buf) {
        boost::crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc_computer;
        // We need to not crc BLOCK_META_DATA_SIZE because it's
        // internal to the serializer.
        crc_computer.process_bytes(buf, get_block_size().value());
        return crc_computer.checksum();
    }

    int last_write_started, last_write_callbacked;

private:
    struct persisted_block_info_t {
        block_id_t block_id;
        block_info_t block_info;
    };
    int semantic_fd;

public:
    typedef typename inner_serializer_t::private_dynamic_config_t private_dynamic_config_t;
    typedef typename inner_serializer_t::dynamic_config_t dynamic_config_t;
    typedef typename inner_serializer_t::static_config_t static_config_t;

public:

    static void create(dynamic_config_t *config, private_dynamic_config_t *private_config, static_config_t *static_config) {
        inner_serializer_t::create(config, private_config, static_config);
    }

    semantic_checking_serializer_t(dynamic_config_t *config, private_dynamic_config_t *private_config)
        : inner_serializer(config, private_config),
          last_write_started(0), last_write_callbacked(0),
          semantic_fd(-1)
        {
            semantic_fd = open(private_config->semantic_filename.c_str(),
                O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
            if (semantic_fd == INVALID_FD)
                fail_due_to_user_error("Inaccessible semantic checking file: \"%s\": %s", private_config->semantic_filename.c_str(), strerror(errno));

            // fill up the blocks from the semantic checking file
            int res = -1;
            do {
                persisted_block_info_t buf;
                res = read(semantic_fd, &buf, sizeof(buf));
                guarantee_err(res != -1, "Could not read from the semantic checker file");
                if(res == sizeof(persisted_block_info_t)) {
                    blocks.set(buf.block_id.value, buf.block_info);
                }
            } while(res == sizeof(persisted_block_info_t));
        }

    ~semantic_checking_serializer_t() {
        close(semantic_fd);
    }

    typedef typename inner_serializer_t::check_callback_t check_callback_t;
    static void check_existing(const char *db_path, check_callback_t *cb) {
        inner_serializer_t::check_existing(db_path, cb);
    }

public:
    void *malloc() {
        return inner_serializer.malloc();
    }

    void *clone(void *data) {
        return inner_serializer.clone(data);
    }

    void free(void *ptr) {
        inner_serializer.free(ptr);
    }

    file_t::account_t *make_io_account(int priority, int outstanding_requests_limit = UNLIMITED_OUTSTANDING_REQUESTS) {
        return inner_serializer.make_io_account(priority, outstanding_requests_limit);
    }

public:
    /* For reads, we check to make sure that the data we get back in the read is
    consistent with what was last written there. */

    struct reader_t :
        public read_callback_t
    {
        semantic_checking_serializer_t *parent;
        block_id_t block_id;
        void *buf;
        block_info_t expected_block_state;
        read_callback_t *callback;

        reader_t(semantic_checking_serializer_t *parent, block_id_t block_id, void *buf, block_info_t expected_block_state)
            : parent(parent), block_id(block_id), buf(buf), expected_block_state(expected_block_state) {}

        void on_serializer_read() {
            /* Make sure that the value that the serializer returned was valid */

            crc_t actual_crc = parent->compute_crc(buf);

            switch (expected_block_state.state) {
                case block_info_t::state_unknown: {
                    /* We don't know what this block was supposed to contain, so we can't do any
                    verification */
                    break;
                }

                case block_info_t::state_deleted: {
                    unreachable("Cache asked for a deleted block, and serializer didn't complain.");
                }

                case block_info_t::state_have_crc: {
#ifdef SERIALIZER_DEBUG_PRINT
                    printf("Read %ld: %u\n", block_id, actual_crc);
#endif
                    guarantee(expected_block_state.crc == actual_crc, "Serializer returned bad value for block ID %u", block_id.value);
                    break;
                }
                default:
                    unreachable();
            }

            if (callback) callback->on_serializer_read();
            delete this;
        }
    };

    bool do_read(block_id_t block_id, void *buf, file_t::account_t *io_account, read_callback_t *callback) {
#ifdef SERIALIZER_DEBUG_PRINT
        printf("Reading %ld\n", block_id);
#endif
        reader_t *reader = new reader_t(this, block_id, buf, blocks.get(block_id.value));
        reader->callback = NULL;
        if (inner_serializer.do_read(block_id, buf, io_account, reader)) {
            reader->on_serializer_read();
            return true;
        } else {
            reader->callback = callback;
            return false;
        }
    }

    ser_transaction_id_t get_current_transaction_id(block_id_t block_id, const void* buf) {
        // TODO: Implement some checking for this operation
        return inner_serializer.get_current_transaction_id(block_id, buf);
    }

public:
    /* For writes, we make sure that the writes come back in the same order that
    we send them to the serializer. */

    struct writer_t :
        public write_txn_callback_t
    {
        semantic_checking_serializer_t *parent;
        int version;
        write_txn_callback_t *callback;

        writer_t(semantic_checking_serializer_t *parent, int version)
            : parent(parent), version(version) {}

        void on_serializer_write_txn() {
            guarantee(parent->last_write_callbacked == version-1, "Serializer completed writes in the wrong order.");
            parent->last_write_callbacked = version;
            if (callback) callback->on_serializer_write_txn();
            delete this;
       }
    };

    bool do_write(write_t *writes, int num_writes, file_t::account_t *io_account, write_txn_callback_t *callback, write_tid_callback_t *tid_callback = NULL) {
        for (int i = 0; i < num_writes; i++) {

            if (!writes[i].buf_specified) continue;

            block_info_t b;
            memset(&b, 0, sizeof(b));  // make valgrind happy
            if (writes[i].buf) {
                b.state = block_info_t::state_have_crc;
                b.crc = compute_crc(writes[i].buf);
#ifdef SERIALIZER_DEBUG_PRINT
                printf("Writing %ld: %u\n", writes[i].block_id, b.crc);
#endif
            } else {
                b.state = block_info_t::state_deleted;
#ifdef SERIALIZER_DEBUG_PRINT
                printf("Deleting %ld\n", writes[i].block_id);
#endif
            }
            blocks.set(writes[i].block_id.value, b);

            // Add the block to the semantic checker file
            persisted_block_info_t buf;
#ifdef VALGRIND
            memset(&buf, 0, sizeof(buf));  // make valgrind happy
#endif
            buf.block_id = writes[i].block_id;
            buf.block_info = b;
            int res = write(semantic_fd, &buf, sizeof(buf));
            guarantee_err(res == sizeof(buf), "Could not write data to semantic checker file");
        }

        writer_t *writer = new writer_t(this, ++last_write_started);
        writer->callback = NULL;
        if (inner_serializer.do_write(writes, num_writes, io_account, writer, tid_callback)) {
            writer->on_serializer_write_txn();
            return true;
        } else {
            writer->callback = callback;
            return false;
        }
    }

public:
    block_size_t get_block_size() {
        return inner_serializer.get_block_size();
    }

    block_id_t max_block_id() {
        return inner_serializer.max_block_id();
    }

    bool block_in_use(block_id_t id) {
        bool in_use = inner_serializer.block_in_use(id);
        switch (blocks.get(id.value).state) {
            case block_info_t::state_unknown: break;
            case block_info_t::state_deleted: rassert(!in_use); break;
            case block_info_t::state_have_crc: rassert(in_use); break;
            default: unreachable();
        }
        return in_use;
    }

    repli_timestamp_t get_recency(block_id_t id) {
        return inner_serializer.get_recency(id);
    }

    bool register_read_ahead_cb(read_ahead_callback_t *cb) {
        // Ignore this, it might make the checking ineffective...
    }
    bool unregister_read_ahead_cb(read_ahead_callback_t *cb) {
        return false;
    }

public:
    struct shutdown_callback_t {
        virtual void on_serializer_shutdown(semantic_checking_serializer_t *) = 0;
        virtual ~shutdown_callback_t() {}
    };
    bool shutdown(shutdown_callback_t *cb) {
        shutdown_callback = cb;
        return inner_serializer.shutdown(this);
    }
private:
    shutdown_callback_t *shutdown_callback;
    void on_serializer_shutdown(inner_serializer_t *ser) {
        if (shutdown_callback) shutdown_callback->on_serializer_shutdown(this);
    }

public:
    typedef typename inner_serializer_t::gc_disable_callback_t gc_disable_callback_t;
    bool disable_gc(gc_disable_callback_t *cb) {
        return inner_serializer.disable_gc(cb);
    }
    bool enable_gc() {
        return inner_serializer.enable_gc();
    }

};

#endif /* __SERIALIZER_SEMANTIC_CHECKING_HPP__ */
<|endoftext|>


<commit_before>/*
  This file is part of the KDE project

  Copyright (C) 2004 Michael Brade <brade@kde.org>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; see the file COPYING.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.

  In addition, as a special exception, the copyright holders give
  permission to link the code of this program with any edition of
  the Qt library by Trolltech AS, Norway (or with modified versions
  of Qt that use the same license as Qt), and distribute linked
  combinations including the two.  You must obey the GNU General
  Public License in all respects for all of the code used other than
  Qt.  If you modify this file, you may extend this exception to
  your version of the file, but you are not obligated to do so.  If
  you do not wish to do so, delete this exception statement from
  your version.
*/

#include "knotetip.h"
#include "knotes_part_p.h"

#include <QAbstractEventDispatcher>
#include <QApplication>
#include <QBoxLayout>
#include <QTextEdit>
#include <QToolTip>

KNoteTip::KNoteTip( QListWidget *parent )
  : QFrame( 0, Qt::WX11BypassWM |   // this will make Seli happy >:-P
            Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WStyle_Tool | Qt::WStyle_StaysOnTop ),
    mFilter( false ),
    mView( parent ),
    mNoteIVI( 0 ),
    mPreview( new QTextEdit( this ) )
{
  mPreview->setReadOnly( true );
  mPreview->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
  mPreview->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );

  QBoxLayout *layout = new QVBoxLayout( this );
  layout->addWidget( mPreview );
  layout->setMargin( 1 );
  setPalette( QToolTip::palette() );
  setFrameStyle( QFrame::Plain );
  hide();
}

KNoteTip::~KNoteTip()
{
  delete mPreview;
  mPreview = 0;
}

void KNoteTip::setNote( KNotesIconViewItem *item )
{
  if ( mNoteIVI == item ) {
    return;
  }

  mNoteIVI = item;
  if ( !mNoteIVI ) {
    QAbstractEventDispatcher::instance()->unregisterTimers(this);
    if ( isVisible() ) {
      setFilter( false );
      hide();
    }
  } else {
    Journal *journal = item->journal();
    mPreview->setAcceptRichText( journal->customProperty( "KNotes", "RichText" ) == "true" );

    QColor fg( journal->customProperty( "KNotes", "FgColor" ) );
    QColor bg( journal->customProperty( "KNotes", "BgColor" ) );
    setColor( fg, bg );

    mPreview->setText( journal->description() );
    //mPreview->zoomTo( 8 );
    mPreview->sync();

    mPreview->document()->adjustSize ();
    int w = int( mPreview->document ()->size().width() );
    int h = int( mPreview->document ()->size().height() );
    while ( w > 60 && h == mPreview->heightForWidth( w - 20 ) ) {
      w -= 20;
    }

    QRect desk = KGlobalSettings::desktopGeometry( mView->visualItemRect( mNoteIVI ).center() );
    resize( w, qMin( h, desk.height() / 2 - 20 ) );

    hide();
    QAbstractEventDispatcher::instance()->unregisterTimers( this );
    setFilter( true );
    startTimer( 600 );  // delay showing the tooltip for 0.7 sec
  }
}

// protected, virtual methods

void KNoteTip::resizeEvent( QResizeEvent *ev )
{
  QFrame::resizeEvent( ev );
  reposition();
}

void KNoteTip::timerEvent( QTimerEvent * )
{
  QAbstractEventDispatcher::instance()->unregisterTimers( this );

  if ( !isVisible() ) {
    startTimer( 15000 ); // show the tooltip for 15 sec
    reposition();
    show();
  } else {
    setFilter( false );
    hide();
  }
}

bool KNoteTip::eventFilter( QObject *, QEvent *e )
{
  switch ( e->type() ) {
  case QEvent::Leave:
  case QEvent::MouseButtonPress:
  case QEvent::MouseButtonRelease:
  case QEvent::KeyPress:
  case QEvent::KeyRelease:
  case QEvent::FocusIn:
  case QEvent::FocusOut:
  case QEvent::Wheel:
    QAbstractEventDispatcher::instance()->unregisterTimers(this);
    setFilter( false );
    hide();
  default:
    break;
  }

  return false;
}

// private stuff

void KNoteTip::setColor( const QColor &fg, const QColor &bg )
{
  QPalette newpalette = palette();
  newpalette.setColor( QPalette::Background, bg );
  newpalette.setColor( QPalette::Foreground, fg );
  newpalette.setColor( QPalette::Base, bg ); // text background
  newpalette.setColor( QPalette::Text, fg ); // text color
  newpalette.setColor( QPalette::Button, bg );

  // the shadow
  newpalette.setColor( QPalette::Midlight, bg.light(110) );
  newpalette.setColor( QPalette::Shadow, bg.dark(116) );
  newpalette.setColor( QPalette::Light, bg.light(180) );
  newpalette.setColor( QPalette::Dark, bg.dark(108) );
  setPalette( newpalette );

  // set the text color
  mPreview->setColor( fg );
}

void KNoteTip::setFilter( bool enable )
{
  if ( enable == mFilter ) {
    return;
  }

  if ( enable ) {
    qApp->installEventFilter( this );
    QApplication::setGlobalMouseTracking( true );
  } else {
    QApplication::setGlobalMouseTracking( false );
    qApp->removeEventFilter( this );
  }

  mFilter = enable;
}

void KNoteTip::reposition()
{
  if ( !mNoteIVI ) {
    return;
  }

  QRect rect = mView->visualItemRect( mNoteIVI );
  QPoint off = mView->mapFromParent( mView->viewport()->mapToGlobal( QPoint( 0, 0 ) ) );
  rect.translate( off.x(), off.y() );

  QPoint pos = rect.center();
  // should the tooltip be shown to the left or to the right of the ivi?
  QRect desk = KGlobalSettings::desktopGeometry( pos );
  if ( rect.center().x() + width() > desk.right() ) {
    // to the left
    if ( pos.x() - width() < 0 ) {
      pos.setX( 0 );
    } else {
      pos.setX( pos.x() - width() );
    }
  }

  // should the tooltip be shown above or below the ivi ?
  if ( rect.bottom() + height() > desk.bottom() ) {
    // above
    pos.setY( rect.top() - height() );
  } else {
    pos.setY( rect.bottom() );
  }
  move( pos );
  update();
}
<commit_msg>--deprecated<commit_after>/*
  This file is part of the KDE project

  Copyright (C) 2004 Michael Brade <brade@kde.org>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; see the file COPYING.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.

  In addition, as a special exception, the copyright holders give
  permission to link the code of this program with any edition of
  the Qt library by Trolltech AS, Norway (or with modified versions
  of Qt that use the same license as Qt), and distribute linked
  combinations including the two.  You must obey the GNU General
  Public License in all respects for all of the code used other than
  Qt.  If you modify this file, you may extend this exception to
  your version of the file, but you are not obligated to do so.  If
  you do not wish to do so, delete this exception statement from
  your version.
*/

#include "knotetip.h"
#include "knotes_part_p.h"

#include <QAbstractEventDispatcher>
#include <QApplication>
#include <QBoxLayout>
#include <QTextEdit>
#include <QToolTip>

KNoteTip::KNoteTip( QListWidget *parent )
  : QFrame( 0, Qt::WX11BypassWM |   // this will make Seli happy >:-P
            Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WStyle_Tool | Qt::WStyle_StaysOnTop ),
    mFilter( false ),
    mView( parent ),
    mNoteIVI( 0 ),
    mPreview( new QTextEdit( this ) )
{
  mPreview->setReadOnly( true );
  mPreview->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
  mPreview->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );

  QBoxLayout *layout = new QVBoxLayout( this );
  layout->addWidget( mPreview );
  layout->setMargin( 1 );
  setPalette( QToolTip::palette() );
  setFrameStyle( QFrame::Plain );
  hide();
}

KNoteTip::~KNoteTip()
{
  delete mPreview;
  mPreview = 0;
}

void KNoteTip::setNote( KNotesIconViewItem *item )
{
  if ( mNoteIVI == item ) {
    return;
  }

  mNoteIVI = item;
  if ( !mNoteIVI ) {
    QAbstractEventDispatcher::instance()->unregisterTimers(this);
    if ( isVisible() ) {
      setFilter( false );
      hide();
    }
  } else {
    Journal *journal = item->journal();
    mPreview->setAcceptRichText( journal->customProperty( "KNotes", "RichText" ) == "true" );

    QColor fg( journal->customProperty( "KNotes", "FgColor" ) );
    QColor bg( journal->customProperty( "KNotes", "BgColor" ) );
    setColor( fg, bg );

    mPreview->setText( journal->description() );
    //mPreview->zoomTo( 8 );
    //mPreview->sync(); this is deprecated in Qt4, but there is no replacement

    mPreview->document()->adjustSize ();
    int w = int( mPreview->document ()->size().width() );
    int h = int( mPreview->document ()->size().height() );
    while ( w > 60 && h == mPreview->heightForWidth( w - 20 ) ) {
      w -= 20;
    }

    QRect desk = KGlobalSettings::desktopGeometry( mView->visualItemRect( mNoteIVI ).center() );
    resize( w, qMin( h, desk.height() / 2 - 20 ) );

    hide();
    QAbstractEventDispatcher::instance()->unregisterTimers( this );
    setFilter( true );
    startTimer( 600 );  // delay showing the tooltip for 0.7 sec
  }
}

// protected, virtual methods

void KNoteTip::resizeEvent( QResizeEvent *ev )
{
  QFrame::resizeEvent( ev );
  reposition();
}

void KNoteTip::timerEvent( QTimerEvent * )
{
  QAbstractEventDispatcher::instance()->unregisterTimers( this );

  if ( !isVisible() ) {
    startTimer( 15000 ); // show the tooltip for 15 sec
    reposition();
    show();
  } else {
    setFilter( false );
    hide();
  }
}

bool KNoteTip::eventFilter( QObject *, QEvent *e )
{
  switch ( e->type() ) {
  case QEvent::Leave:
  case QEvent::MouseButtonPress:
  case QEvent::MouseButtonRelease:
  case QEvent::KeyPress:
  case QEvent::KeyRelease:
  case QEvent::FocusIn:
  case QEvent::FocusOut:
  case QEvent::Wheel:
    QAbstractEventDispatcher::instance()->unregisterTimers(this);
    setFilter( false );
    hide();
  default:
    break;
  }

  return false;
}

// private stuff

void KNoteTip::setColor( const QColor &fg, const QColor &bg )
{
  QPalette newpalette = palette();
  newpalette.setColor( QPalette::Background, bg );
  newpalette.setColor( QPalette::Foreground, fg );
  newpalette.setColor( QPalette::Base, bg ); // text background
  newpalette.setColor( QPalette::Text, fg ); // text color
  newpalette.setColor( QPalette::Button, bg );

  // the shadow
  newpalette.setColor( QPalette::Midlight, bg.light(110) );
  newpalette.setColor( QPalette::Shadow, bg.dark(116) );
  newpalette.setColor( QPalette::Light, bg.light(180) );
  newpalette.setColor( QPalette::Dark, bg.dark(108) );
  setPalette( newpalette );

  // set the text color
  mPreview->setTextColor( fg );
}

void KNoteTip::setFilter( bool enable )
{
  if ( enable == mFilter ) {
    return;
  }

  if ( enable ) {
    qApp->installEventFilter( this );
    setMouseTracking( true );
  } else {
    setMouseTracking( false );
    qApp->removeEventFilter( this );
  }

  mFilter = enable;
}

void KNoteTip::reposition()
{
  if ( !mNoteIVI ) {
    return;
  }

  QRect rect = mView->visualItemRect( mNoteIVI );
  QPoint off = mView->mapFromParent( mView->viewport()->mapToGlobal( QPoint( 0, 0 ) ) );
  rect.translate( off.x(), off.y() );

  QPoint pos = rect.center();
  // should the tooltip be shown to the left or to the right of the ivi?
  QRect desk = KGlobalSettings::desktopGeometry( pos );
  if ( rect.center().x() + width() > desk.right() ) {
    // to the left
    if ( pos.x() - width() < 0 ) {
      pos.setX( 0 );
    } else {
      pos.setX( pos.x() - width() );
    }
  }

  // should the tooltip be shown above or below the ivi ?
  if ( rect.bottom() + height() > desk.bottom() ) {
    // above
    pos.setY( rect.top() - height() );
  } else {
    pos.setY( rect.bottom() );
  }
  move( pos );
  update();
}
<|endoftext|>


<commit_before>/*
 *  This file is part of Poedit (http://www.poedit.net)
 *
 *  Copyright (C) 2013 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

#include "transmem.h"

#include "catalog.h"
#include "errors.h"

#include <wx/stdpaths.h>
#include <wx/utils.h>
#include <wx/dir.h>
#include <Wx/filename.h>

#include <mutex>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/name_generator.hpp>
#include <boost/uuid/string_generator.hpp>

#include <Lucene.h>
#include <LuceneException.h>
#include <MMapDirectory.h>
#include <StandardAnalyzer.h>
#include <IndexWriter.h>
#include <IndexSearcher.h>
#include <IndexReader.h>
#include <Document.h>
#include <Field.h>
#include <StringUtils.h>
#include <TermQuery.h>
#include <BooleanQuery.h>
#include <PhraseQuery.h>
#include <Term.h>
#include <ScoreDoc.h>
#include <TopDocs.h>
#include <StringReader.h>
#include <TokenStream.h>
#include <TermAttribute.h>

using namespace Lucene;

#define CATCH_AND_RETHROW_EXCEPTION                                 \
    catch (LuceneException& e)                                      \
    {                                                               \
        throw Exception(wxString::Format("%s (%d)",                 \
                        e.getError(), (int)e.getType()));           \
    }                                                               \
    catch (std::exception& e)                                       \
    {                                                               \
        throw Exception(e.what());                                  \
    }

// ----------------------------------------------------------------
// TranslationMemoryImpl
// ----------------------------------------------------------------

class TranslationMemoryImpl
{
public:
    static const int DEFAULT_MAXHITS = 10;

    typedef TranslationMemory::Results Results;

    TranslationMemoryImpl()
        : m_dir(newLucene<MMapDirectory>(GetDatabaseDir())),
          m_analyzer(newLucene<StandardAnalyzer>(LuceneVersion::LUCENE_CURRENT))
    {}

    bool Search(const std::wstring& lang,
                const std::wstring& source,
                Results& results,
                int maxHits = -1);

    std::shared_ptr<TranslationMemory::Writer> CreateWriter();

    void GetStats(long& numDocs, long& fileSize);

private:
    static std::wstring GetDatabaseDir();
    IndexReaderPtr Reader();
    SearcherPtr Searcher();

private:
    DirectoryPtr     m_dir;
    AnalyzerPtr      m_analyzer;
    IndexReaderPtr   m_reader;
    std::mutex       m_readerMutex;
};

std::wstring TranslationMemoryImpl::GetDatabaseDir()
{
    wxString data;
#if defined(__UNIX__) && !defined(__WXMAC__)
    if ( !wxGetEnv("XDG_DATA_HOME", &data) )
        data = wxGetHomeDir() + "/.local/share";
    data += "/poedit";
#else
    data = wxStandardPaths::Get().GetUserDataDir();
#endif
    data += wxFILE_SEP_PATH;
    data += "TranslationMemory";

    // ensure the directory exists:
    wxFileName::Mkdir(data, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);

    return data.ToStdWstring();
}

IndexReaderPtr TranslationMemoryImpl::Reader()
{
    std::lock_guard<std::mutex> guard(m_readerMutex);
    if ( m_reader )
        m_reader = m_reader->reopen();
    else
        m_reader = IndexReader::open(m_dir, true);
    return m_reader;
}

namespace
{

void PerformSearch(IndexSearcherPtr searcher,
                   const std::wstring& lang,
                   QueryPtr query,
                   TranslationMemory::Results& results, int maxHits)
{
    // TODO: use short form of the language too (cs vs cs_CZ), boost the
    //       full form in the query
    auto langQ = newLucene<TermQuery>(newLucene<Term>(L"lang", lang));
    auto fullQuery = newLucene<BooleanQuery>();
    fullQuery->add(langQ, BooleanClause::MUST);
    fullQuery->add(query, BooleanClause::MUST);

    auto hits = searcher->search(fullQuery, maxHits);
    for (int i = 0; i < hits->scoreDocs.size(); i++)
    {
        DocumentPtr doc = searcher->doc(hits->scoreDocs[i]->doc);
        auto t = doc->get(L"trans");
        if (std::find(results.begin(), results.end(), t) == results.end())
            results.push_back(t);
    }
}

} // anonymous namespace

bool TranslationMemoryImpl::Search(const std::wstring& lang,
                                   const std::wstring& source,
                                   Results& results,
                                   int maxHits)
{
    try
    {
        if (maxHits <= 0)
            maxHits = DEFAULT_MAXHITS;

        results.clear();

        Lucene::String fieldName(L"source");
        auto boolQ = newLucene<BooleanQuery>();
        auto phraseQ = newLucene<PhraseQuery>();

        auto stream = m_analyzer->tokenStream(fieldName, newLucene<StringReader>(source));
        while (stream->incrementToken())
        {
            auto word = stream->getAttribute<TermAttribute>()->term();
            auto term = newLucene<Term>(fieldName, word);
            boolQ->add(newLucene<TermQuery>(term), BooleanClause::SHOULD);
            phraseQ->add(term);
        }

        auto searcher = newLucene<IndexSearcher>(Reader());

        PerformSearch(searcher, lang, phraseQ, results, maxHits);
        maxHits -= results.size();
        if (maxHits > 0)
            PerformSearch(searcher, lang, boolQ, results, maxHits);

        return !results.empty();
    }
    catch (LuceneException&)
    {
        return false;
    }
}

void TranslationMemoryImpl::GetStats(long& numDocs, long& fileSize)
{
    try
    {
        auto reader = Reader();
        numDocs = reader->numDocs();
        fileSize = wxDir::GetTotalSize(GetDatabaseDir()).GetValue();
    }
    CATCH_AND_RETHROW_EXCEPTION
}

// ----------------------------------------------------------------
// TranslationMemoryWriterImpl
// ----------------------------------------------------------------

class TranslationMemoryWriterImpl : public TranslationMemory::Writer
{
public:
    TranslationMemoryWriterImpl(DirectoryPtr dir, AnalyzerPtr analyzer)
    {
        m_writer = newLucene<IndexWriter>(dir, analyzer, IndexWriter::MaxFieldLengthLIMITED);
    }

    ~TranslationMemoryWriterImpl()
    {
        if (m_writer)
            m_writer->rollback();
    }

    virtual void Commit()
    {
        try
        {
            m_writer->close();
            m_writer.reset();
        }
        CATCH_AND_RETHROW_EXCEPTION
    }

    virtual void Insert(const std::wstring& lang,
                        const std::wstring& source,
                        const std::wstring& trans)
    {
        if (lang.empty())
            return;

        // Compute unique ID for the translation:

        static const boost::uuids::uuid s_namespace =
          boost::uuids::string_generator()("6e3f73c5-333f-4171-9d43-954c372a8a02");
        boost::uuids::name_generator gen(s_namespace);

        std::wstring itemId(L"en"); // TODO: srclang
        itemId += lang;
        itemId += source;
        itemId += trans;

        const std::wstring itemUUID = boost::uuids::to_wstring(gen(itemId));

        try
        {
            // Then add a new document:
            auto doc = newLucene<Document>();

            doc->add(newLucene<Field>(L"uuid", itemUUID,
                                      Field::STORE_YES, Field::INDEX_NOT_ANALYZED));
            doc->add(newLucene<Field>(L"srclang", L"en",
                                      Field::STORE_YES, Field::INDEX_NOT_ANALYZED));
            doc->add(newLucene<Field>(L"lang", lang,
                                      Field::STORE_YES, Field::INDEX_NOT_ANALYZED));
            doc->add(newLucene<Field>(L"source", source,
                                      Field::STORE_YES, Field::INDEX_ANALYZED));
            doc->add(newLucene<Field>(L"trans", trans,
                                      Field::STORE_YES, Field::INDEX_NOT_ANALYZED));

            m_writer->updateDocument(newLucene<Term>(L"uuid", itemUUID), doc);
        }
        CATCH_AND_RETHROW_EXCEPTION
    }

    virtual void Insert(const Catalog &cat)
    {
        const std::string lang = cat.GetLanguage().Code();
        if (lang.empty())
            return;
        const std::wstring wlang(lang.begin(), lang.end());

        int cnt = cat.GetCount();
        for (int i = 0; i < cnt; i++)
        {
            const CatalogItem& item = cat[i];

            // ignore translations with errors in them
            if (item.GetValidity() == CatalogItem::Val_Invalid)
                continue;

            // can't handle plurals yet (TODO?)
            if (item.HasPlural())
                continue;

            // ignore untranslated or unfinished translations
            if (item.IsFuzzy() || !item.IsTranslated())
                continue;

            // Note that dt.IsModified() is intentionally not checked - we
            // want to save old entries in the TM too, so that we harvest as
            // much useful translations as we can.

            Insert(wlang, item.GetString(), item.GetTranslation());
        }
    }

private:
    IndexWriterPtr m_writer;
};

std::shared_ptr<TranslationMemory::Writer> TranslationMemoryImpl::CreateWriter()
{
    try
    {
        return std::make_shared<TranslationMemoryWriterImpl>(m_dir, m_analyzer);
    }
    CATCH_AND_RETHROW_EXCEPTION
}

// ----------------------------------------------------------------
// Singleton management
// ----------------------------------------------------------------

TranslationMemory *TranslationMemory::ms_instance = nullptr;

TranslationMemory& TranslationMemory::Get()
{
    if (!ms_instance)
    {
        try
        {
            ms_instance = new TranslationMemory;
        }
        CATCH_AND_RETHROW_EXCEPTION
    }
    return *ms_instance;
}

void TranslationMemory::CleanUp()
{
    if (ms_instance)
    {
        delete ms_instance;
        ms_instance = nullptr;
    }
}

TranslationMemory::TranslationMemory() : m_impl(new TranslationMemoryImpl) {}
TranslationMemory::~TranslationMemory() { delete m_impl; }

// ----------------------------------------------------------------
// public API
// ----------------------------------------------------------------

bool TranslationMemory::Search(const std::wstring& lang,
                               const std::wstring& source,
                               Results& results,
                               int maxHits)
{
    return m_impl->Search(lang, source, results, maxHits);
}

std::shared_ptr<TranslationMemory::Writer> TranslationMemory::CreateWriter()
{
    return m_impl->CreateWriter();
}

void TranslationMemory::GetStats(long& numDocs, long& fileSize)
{
    m_impl->GetStats(numDocs, fileSize);
}<commit_msg>Fix TM directory creation: create just the parent dir.<commit_after>/*
 *  This file is part of Poedit (http://www.poedit.net)
 *
 *  Copyright (C) 2013 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

#include "transmem.h"

#include "catalog.h"
#include "errors.h"

#include <wx/stdpaths.h>
#include <wx/utils.h>
#include <wx/dir.h>
#include <Wx/filename.h>

#include <mutex>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/name_generator.hpp>
#include <boost/uuid/string_generator.hpp>

#include <Lucene.h>
#include <LuceneException.h>
#include <MMapDirectory.h>
#include <StandardAnalyzer.h>
#include <IndexWriter.h>
#include <IndexSearcher.h>
#include <IndexReader.h>
#include <Document.h>
#include <Field.h>
#include <StringUtils.h>
#include <TermQuery.h>
#include <BooleanQuery.h>
#include <PhraseQuery.h>
#include <Term.h>
#include <ScoreDoc.h>
#include <TopDocs.h>
#include <StringReader.h>
#include <TokenStream.h>
#include <TermAttribute.h>

using namespace Lucene;

#define CATCH_AND_RETHROW_EXCEPTION                                 \
    catch (LuceneException& e)                                      \
    {                                                               \
        throw Exception(wxString::Format("%s (%d)",                 \
                        e.getError(), (int)e.getType()));           \
    }                                                               \
    catch (std::exception& e)                                       \
    {                                                               \
        throw Exception(e.what());                                  \
    }

// ----------------------------------------------------------------
// TranslationMemoryImpl
// ----------------------------------------------------------------

class TranslationMemoryImpl
{
public:
    static const int DEFAULT_MAXHITS = 10;

    typedef TranslationMemory::Results Results;

    TranslationMemoryImpl()
        : m_dir(newLucene<MMapDirectory>(GetDatabaseDir())),
          m_analyzer(newLucene<StandardAnalyzer>(LuceneVersion::LUCENE_CURRENT))
    {}

    bool Search(const std::wstring& lang,
                const std::wstring& source,
                Results& results,
                int maxHits = -1);

    std::shared_ptr<TranslationMemory::Writer> CreateWriter();

    void GetStats(long& numDocs, long& fileSize);

private:
    static std::wstring GetDatabaseDir();
    IndexReaderPtr Reader();
    SearcherPtr Searcher();

private:
    DirectoryPtr     m_dir;
    AnalyzerPtr      m_analyzer;
    IndexReaderPtr   m_reader;
    std::mutex       m_readerMutex;
};

std::wstring TranslationMemoryImpl::GetDatabaseDir()
{
    wxString data;
#if defined(__UNIX__) && !defined(__WXMAC__)
    if ( !wxGetEnv("XDG_DATA_HOME", &data) )
        data = wxGetHomeDir() + "/.local/share";
    data += "/poedit";
#else
    data = wxStandardPaths::Get().GetUserDataDir();
#endif

    // ensure the parent directory exists:
    wxFileName::Mkdir(data, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);

    data += wxFILE_SEP_PATH;
    data += "TranslationMemory";

    return data.ToStdWstring();
}

IndexReaderPtr TranslationMemoryImpl::Reader()
{
    std::lock_guard<std::mutex> guard(m_readerMutex);
    if ( m_reader )
        m_reader = m_reader->reopen();
    else
        m_reader = IndexReader::open(m_dir, true);
    return m_reader;
}

namespace
{

void PerformSearch(IndexSearcherPtr searcher,
                   const std::wstring& lang,
                   QueryPtr query,
                   TranslationMemory::Results& results, int maxHits)
{
    // TODO: use short form of the language too (cs vs cs_CZ), boost the
    //       full form in the query
    auto langQ = newLucene<TermQuery>(newLucene<Term>(L"lang", lang));
    auto fullQuery = newLucene<BooleanQuery>();
    fullQuery->add(langQ, BooleanClause::MUST);
    fullQuery->add(query, BooleanClause::MUST);

    auto hits = searcher->search(fullQuery, maxHits);
    for (int i = 0; i < hits->scoreDocs.size(); i++)
    {
        DocumentPtr doc = searcher->doc(hits->scoreDocs[i]->doc);
        auto t = doc->get(L"trans");
        if (std::find(results.begin(), results.end(), t) == results.end())
            results.push_back(t);
    }
}

} // anonymous namespace

bool TranslationMemoryImpl::Search(const std::wstring& lang,
                                   const std::wstring& source,
                                   Results& results,
                                   int maxHits)
{
    try
    {
        if (maxHits <= 0)
            maxHits = DEFAULT_MAXHITS;

        results.clear();

        Lucene::String fieldName(L"source");
        auto boolQ = newLucene<BooleanQuery>();
        auto phraseQ = newLucene<PhraseQuery>();

        auto stream = m_analyzer->tokenStream(fieldName, newLucene<StringReader>(source));
        while (stream->incrementToken())
        {
            auto word = stream->getAttribute<TermAttribute>()->term();
            auto term = newLucene<Term>(fieldName, word);
            boolQ->add(newLucene<TermQuery>(term), BooleanClause::SHOULD);
            phraseQ->add(term);
        }

        auto searcher = newLucene<IndexSearcher>(Reader());

        PerformSearch(searcher, lang, phraseQ, results, maxHits);
        maxHits -= results.size();
        if (maxHits > 0)
            PerformSearch(searcher, lang, boolQ, results, maxHits);

        return !results.empty();
    }
    catch (LuceneException&)
    {
        return false;
    }
}

void TranslationMemoryImpl::GetStats(long& numDocs, long& fileSize)
{
    try
    {
        auto reader = Reader();
        numDocs = reader->numDocs();
        fileSize = wxDir::GetTotalSize(GetDatabaseDir()).GetValue();
    }
    CATCH_AND_RETHROW_EXCEPTION
}

// ----------------------------------------------------------------
// TranslationMemoryWriterImpl
// ----------------------------------------------------------------

class TranslationMemoryWriterImpl : public TranslationMemory::Writer
{
public:
    TranslationMemoryWriterImpl(DirectoryPtr dir, AnalyzerPtr analyzer)
    {
        m_writer = newLucene<IndexWriter>(dir, analyzer, IndexWriter::MaxFieldLengthLIMITED);
    }

    ~TranslationMemoryWriterImpl()
    {
        if (m_writer)
            m_writer->rollback();
    }

    virtual void Commit()
    {
        try
        {
            m_writer->close();
            m_writer.reset();
        }
        CATCH_AND_RETHROW_EXCEPTION
    }

    virtual void Insert(const std::wstring& lang,
                        const std::wstring& source,
                        const std::wstring& trans)
    {
        if (lang.empty())
            return;

        // Compute unique ID for the translation:

        static const boost::uuids::uuid s_namespace =
          boost::uuids::string_generator()("6e3f73c5-333f-4171-9d43-954c372a8a02");
        boost::uuids::name_generator gen(s_namespace);

        std::wstring itemId(L"en"); // TODO: srclang
        itemId += lang;
        itemId += source;
        itemId += trans;

        const std::wstring itemUUID = boost::uuids::to_wstring(gen(itemId));

        try
        {
            // Then add a new document:
            auto doc = newLucene<Document>();

            doc->add(newLucene<Field>(L"uuid", itemUUID,
                                      Field::STORE_YES, Field::INDEX_NOT_ANALYZED));
            doc->add(newLucene<Field>(L"srclang", L"en",
                                      Field::STORE_YES, Field::INDEX_NOT_ANALYZED));
            doc->add(newLucene<Field>(L"lang", lang,
                                      Field::STORE_YES, Field::INDEX_NOT_ANALYZED));
            doc->add(newLucene<Field>(L"source", source,
                                      Field::STORE_YES, Field::INDEX_ANALYZED));
            doc->add(newLucene<Field>(L"trans", trans,
                                      Field::STORE_YES, Field::INDEX_NOT_ANALYZED));

            m_writer->updateDocument(newLucene<Term>(L"uuid", itemUUID), doc);
        }
        CATCH_AND_RETHROW_EXCEPTION
    }

    virtual void Insert(const Catalog &cat)
    {
        const std::string lang = cat.GetLanguage().Code();
        if (lang.empty())
            return;
        const std::wstring wlang(lang.begin(), lang.end());

        int cnt = cat.GetCount();
        for (int i = 0; i < cnt; i++)
        {
            const CatalogItem& item = cat[i];

            // ignore translations with errors in them
            if (item.GetValidity() == CatalogItem::Val_Invalid)
                continue;

            // can't handle plurals yet (TODO?)
            if (item.HasPlural())
                continue;

            // ignore untranslated or unfinished translations
            if (item.IsFuzzy() || !item.IsTranslated())
                continue;

            // Note that dt.IsModified() is intentionally not checked - we
            // want to save old entries in the TM too, so that we harvest as
            // much useful translations as we can.

            Insert(wlang, item.GetString(), item.GetTranslation());
        }
    }

private:
    IndexWriterPtr m_writer;
};

std::shared_ptr<TranslationMemory::Writer> TranslationMemoryImpl::CreateWriter()
{
    try
    {
        return std::make_shared<TranslationMemoryWriterImpl>(m_dir, m_analyzer);
    }
    CATCH_AND_RETHROW_EXCEPTION
}

// ----------------------------------------------------------------
// Singleton management
// ----------------------------------------------------------------

TranslationMemory *TranslationMemory::ms_instance = nullptr;

TranslationMemory& TranslationMemory::Get()
{
    if (!ms_instance)
    {
        try
        {
            ms_instance = new TranslationMemory;
        }
        CATCH_AND_RETHROW_EXCEPTION
    }
    return *ms_instance;
}

void TranslationMemory::CleanUp()
{
    if (ms_instance)
    {
        delete ms_instance;
        ms_instance = nullptr;
    }
}

TranslationMemory::TranslationMemory() : m_impl(new TranslationMemoryImpl) {}
TranslationMemory::~TranslationMemory() { delete m_impl; }

// ----------------------------------------------------------------
// public API
// ----------------------------------------------------------------

bool TranslationMemory::Search(const std::wstring& lang,
                               const std::wstring& source,
                               Results& results,
                               int maxHits)
{
    return m_impl->Search(lang, source, results, maxHits);
}

std::shared_ptr<TranslationMemory::Writer> TranslationMemory::CreateWriter()
{
    return m_impl->CreateWriter();
}

void TranslationMemory::GetStats(long& numDocs, long& fileSize)
{
    m_impl->GetStats(numDocs, fileSize);
}<|endoftext|>


<commit_before>
#include <list>
#include <sstream>

#include "flame/base.h"

#include "pyflame.h"

#define NO_IMPORT_ARRAY
#define PY_ARRAY_UNIQUE_SYMBOL FLAME_PyArray_API
#include <numpy/ndarrayobject.h>

/** Translate python list of tuples to Config
 *
 *  [(K,V)]   -> Config
 *    float   -> double
 *    str     -> string
 *    [[()]]    -> vector<Config>  (recurse)
 *    ndarray -> vector<double>
 *    TODO: [0.0]   -> vector<double>
 */
void List2Config(Config& ret, PyObject *list, unsigned depth)
{
    if(depth>3)
        throw std::runtime_error("too deep for Dict2Config");

    PyRef<> iter(PyObject_GetIter(list));
    while(true) {
        PyObject *item = PyIter_Next(iter.py());
        if(!item) break;
        PyRef<> itemref(item);
        const char *kname;
        PyObject *value;
        if(!PyArg_ParseTuple(item, "sO", &kname, &value))
            throw std::runtime_error("list item is not a tuple?");

        if(PyArray_Check(value)) { // array as vector<double>
            PyRef<> arr(PyArray_ContiguousFromAny(value, NPY_DOUBLE, 0, 2));
            double *buf = (double*)PyArray_DATA(arr.py());
            std::vector<double> temp(PyArray_SIZE(arr.py()));
            std::copy(buf, buf+temp.size(), temp.begin());

            ret.swap<std::vector<double> >(kname, temp);

        } else if(PyNumber_Check(value)) { // scalar as double
            PyRef<> dval(PyNumber_Float(value));
            double val = PyFloat_AsDouble(dval.py());
            ret.set<double>(kname, val);

        } else if(PyUnicode_Check(value) || (PY_MAJOR_VERSION < 3 && PyBytes_Check(value))) { // string
            PyRef<> valref(value, borrow());
            PyCString sval(valref);
            const char *val = sval.c_str();

            ret.set<std::string>(kname, val);

        } else if(PySequence_Check(value)) { // list of dict
            Py_ssize_t N = PySequence_Size(value);

            Config::vector_t output;
            output.reserve(N);

            for(Py_ssize_t i=0; i<N; i++) {
                PyObject *elem = PySequence_GetItem(value, i);
                assert(elem);

                PyRef<> list;
                if(PyDict_Check(elem)) {
                    list.reset(PyMapping_Items(elem));
                    elem = list.py();
                }
                if(!PyList_Check(elem)) {
                    PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(elem);
                    throw std::invalid_argument(SB()<<"lists must contain only dict or list of tuples, not "<<valuetype->tp_name);
                }

                output.push_back(ret.new_scope());

                List2Config(output.back(), elem, depth+1); // inheirt parent scope
            }

            ret.set<Config::vector_t>(kname, output);

        } else {
            PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(value);
            throw std::invalid_argument(SB()<<"Must be a dict, not "<<valuetype->tp_name);
        }
    }
}

namespace {

PyObject* pydirname(PyObject *obj)
{
    if(!obj) return NULL;

    PyRef<> ospath(PyImport_ImportModule("os.path"));
    return PyObject_CallMethod(ospath.py(), "dirname", "O", obj);
}

struct confval : public boost::static_visitor<PyRef<> >
{
    PyRef<> operator()(double v) const
    {
        return PyRef<>(PyFloat_FromDouble(v));
    }

    PyRef<> operator()(const std::string& v) const
    {
        return PyRef<>(PyString_FromString(v.c_str()));
    }

    PyRef<> operator()(const std::vector<double>& v) const
    {
        npy_intp dims[]  = {(npy_intp)v.size()};
        PyRef<> obj(PyArray_SimpleNew(1, dims, NPY_DOUBLE));
        std::copy(v.begin(), v.end(), (double*)PyArray_DATA(obj.py()));
        return obj;
    }

    PyRef<> operator()(const Config::vector_t& v) const
    {
        PyRef<> L(PyList_New(v.size()));

        for(size_t i=0, N=v.size(); i<N; i++)
        {
            PyList_SetItem(L.py(), i, conf2dict(&v[i]));
        }
        return L;
    }
};

} // namespace

PyObject* conf2dict(const Config *conf)
{
    PyRef<> list(PyList_New(0));

    for(Config::const_iterator it=conf->begin(), end=conf->end();
        it!=end; ++it)
    {
        PyRef<> val(boost::apply_visitor(confval(), it->second));
        PyRef<> tup(Py_BuildValue("sO", it->first.c_str(), val.py()));
        if(PyList_Append(list.py(), tup.py()))
            throw std::runtime_error("Failed to insert into dictionary from conf2dict");
    }

    return list.releasePy();
}

Config* list2conf(PyObject *dict)
{
    if(!PyList_Check(dict))
        throw std::invalid_argument("Not a list");
    std::auto_ptr<Config> conf(new Config);
    List2Config(*conf, dict);
    return conf.release();
}

PyObject* PyGLPSPrint(PyObject *, PyObject *args)
{
    try {
        PyObject *inp;
        if(!PyArg_ParseTuple(args, "O", &inp))
            return NULL;

        PyRef<> list;
        if(PyDict_Check(inp)) {
            list.reset(PyMapping_Items(inp));
            inp = list.py();
        }
        if(!PyList_Check(inp))
            return PyErr_Format(PyExc_ValueError, "argument must be dict or list of tuples");

        Config conf;
        List2Config(conf, inp);
        std::ostringstream strm;
        GLPSPrint(strm, conf);
        return PyString_FromString(strm.str().c_str());
    }CATCH()
}

#ifndef PY_SSIZE_T_CLEAN
#error the following assumes ssize_t is used
#endif

Config* PyGLPSParse2Config(PyObject *, PyObject *args, PyObject *kws)
{
    PyObject *conf = NULL, *extra_defs = Py_None;
    const char *path = NULL;
    const char *pnames[] = {"config", "path", "extra", NULL};
    if(!PyArg_ParseTupleAndKeywords(args, kws, "O|zO", (char**)pnames, &conf, &path, &extra_defs))
        return NULL;

    GLPSParser parser;

    if(extra_defs==Py_None) {
        // no-op
    } else if(PyDict_Check(extra_defs)) {
        PyObject *key, *value;
        Py_ssize_t pos = 0;

        while(PyDict_Next(extra_defs, &pos, &key, &value)) {
            PyRef<> keyx(key, borrow());
            PyCString keystr(keyx);

            Config::value_t curval;

            if(PyNumber_Check(value)) {
                PyRef<> pyf(PyNumber_Float(value));
                curval = PyFloat_AsDouble(pyf.py());

            } else if(PyString_Check(value)) {
                PyRef<> valuex(value, borrow());
                PyCString valstr(valuex);

                curval = valstr.c_str();

            } else {
                PyErr_SetString(PyExc_ValueError, "extra {} can contain only numbers or strings");
                return NULL;
            }

            parser.setVar(keystr.c_str(), curval);
        }
    } else {
        PyErr_SetString(PyExc_ValueError, "'extra' must be a dict");
        return NULL;
    }

    PyGetBuf buf;
    std::auto_ptr<Config> C;

    PyRef<> listref;

    if(PyObject_HasAttrString(conf, "read")) { // file-like
        PyCString pyname;

        if(!path && PyObject_HasAttrString(conf, "name")) {
            path = pyname.c_str(pydirname(PyObject_GetAttrString(conf, "name")));
        }

        PyRef<> pybytes(PyObject_CallMethod(conf, "read", ""));
        if(!buf.get(pybytes.py())) {
            PyErr_SetString(PyExc_TypeError, "read() must return a buffer");
            return NULL;
        }
        C.reset(parser.parse_byte((const char*)buf.data(), buf.size(), path));

    } else if(buf.get(conf)) {
        C.reset(parser.parse_byte((const char*)buf.data(), buf.size(), path));

#if PY_MAJOR_VERSION >= 3
    } else if(PyUnicode_Check(conf)) { // py3 str (aka unicode) doesn't implement buffer iface
        PyCString buf;
        const char *cbuf = buf.c_str(conf);

        C.reset(parser.parse_byte(cbuf, strlen(cbuf), path));
#endif

    } else {
        if(PyDict_Check(conf)) {
            listref.reset(PyMapping_Items(conf));
            conf = listref.py();
        }
        if(PyList_Check(conf)) {
            C.reset(list2conf(conf));

        } else {
            throw std::invalid_argument("'config' must be dict, list of tuples, or byte buffer");
        }
    }

    return C.release();
}

PyObject* PyGLPSParse(PyObject *unused, PyObject *args, PyObject *kws)
{
    try{
        return conf2dict(PyGLPSParse2Config(unused, args, kws));
    }CATCH()
}
<commit_msg>python ref. leak<commit_after>
#include <list>
#include <sstream>

#include "flame/base.h"

#include "pyflame.h"

#define NO_IMPORT_ARRAY
#define PY_ARRAY_UNIQUE_SYMBOL FLAME_PyArray_API
#include <numpy/ndarrayobject.h>

/** Translate python list of tuples to Config
 *
 *  [(K,V)]   -> Config
 *    float   -> double
 *    str     -> string
 *    [[()]]    -> vector<Config>  (recurse)
 *    ndarray -> vector<double>
 *    TODO: [0.0]   -> vector<double>
 */
void List2Config(Config& ret, PyObject *list, unsigned depth)
{
    if(depth>3)
        throw std::runtime_error("too deep for Dict2Config");

    PyRef<> iter(PyObject_GetIter(list));
    while(true) {
        PyObject *item = PyIter_Next(iter.py());
        if(!item) break;
        PyRef<> itemref(item);
        const char *kname;
        PyObject *value;
        if(!PyArg_ParseTuple(item, "sO", &kname, &value))
            throw std::runtime_error("list item is not a tuple?");

        if(PyArray_Check(value)) { // array as vector<double>
            PyRef<> arr(PyArray_ContiguousFromAny(value, NPY_DOUBLE, 0, 2));
            double *buf = (double*)PyArray_DATA(arr.py());
            std::vector<double> temp(PyArray_SIZE(arr.py()));
            std::copy(buf, buf+temp.size(), temp.begin());

            ret.swap<std::vector<double> >(kname, temp);

        } else if(PyNumber_Check(value)) { // scalar as double
            PyRef<> dval(PyNumber_Float(value));
            double val = PyFloat_AsDouble(dval.py());
            ret.set<double>(kname, val);

        } else if(PyUnicode_Check(value) || (PY_MAJOR_VERSION < 3 && PyBytes_Check(value))) { // string
            PyRef<> valref(value, borrow());
            PyCString sval(valref);
            const char *val = sval.c_str();

            ret.set<std::string>(kname, val);

        } else if(PySequence_Check(value)) { // list of dict
            Py_ssize_t N = PySequence_Size(value);

            Config::vector_t output;
            output.reserve(N);

            for(Py_ssize_t i=0; i<N; i++) {
                PyRef<> elem(PySequence_GetItem(value, i));

                if(PyDict_Check(elem.py())) {
                    elem.reset(PyMapping_Items(elem.py()));
                }
                if(!PyList_Check(elem.py())) {
                    PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(elem.py());
                    throw std::invalid_argument(SB()<<"lists must contain only dict or list of tuples, not "<<valuetype->tp_name);
                }

                output.push_back(ret.new_scope());

                List2Config(output.back(), elem.py(), depth+1); // inheirt parent scope
            }

            ret.set<Config::vector_t>(kname, output);

        } else {
            PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(value);
            throw std::invalid_argument(SB()<<"Must be a dict, not "<<valuetype->tp_name);
        }
    }
}

namespace {

PyObject* pydirname(PyObject *obj)
{
    if(!obj) return NULL;

    PyRef<> ospath(PyImport_ImportModule("os.path"));
    return PyObject_CallMethod(ospath.py(), "dirname", "O", obj);
}

struct confval : public boost::static_visitor<PyRef<> >
{
    PyRef<> operator()(double v) const
    {
        return PyRef<>(PyFloat_FromDouble(v));
    }

    PyRef<> operator()(const std::string& v) const
    {
        return PyRef<>(PyString_FromString(v.c_str()));
    }

    PyRef<> operator()(const std::vector<double>& v) const
    {
        npy_intp dims[]  = {(npy_intp)v.size()};
        PyRef<> obj(PyArray_SimpleNew(1, dims, NPY_DOUBLE));
        std::copy(v.begin(), v.end(), (double*)PyArray_DATA(obj.py()));
        return obj;
    }

    PyRef<> operator()(const Config::vector_t& v) const
    {
        PyRef<> L(PyList_New(v.size()));

        for(size_t i=0, N=v.size(); i<N; i++)
        {
            PyList_SetItem(L.py(), i, conf2dict(&v[i]));
        }
        return L;
    }
};

} // namespace

PyObject* conf2dict(const Config *conf)
{
    PyRef<> list(PyList_New(0));

    for(Config::const_iterator it=conf->begin(), end=conf->end();
        it!=end; ++it)
    {
        PyRef<> val(boost::apply_visitor(confval(), it->second));
        PyRef<> tup(Py_BuildValue("sO", it->first.c_str(), val.py()));
        if(PyList_Append(list.py(), tup.py()))
            throw std::runtime_error("Failed to insert into dictionary from conf2dict");
    }

    return list.releasePy();
}

Config* list2conf(PyObject *dict)
{
    if(!PyList_Check(dict))
        throw std::invalid_argument("Not a list");
    std::auto_ptr<Config> conf(new Config);
    List2Config(*conf, dict);
    return conf.release();
}

PyObject* PyGLPSPrint(PyObject *, PyObject *args)
{
    try {
        PyObject *inp;
        if(!PyArg_ParseTuple(args, "O", &inp))
            return NULL;

        PyRef<> list;
        if(PyDict_Check(inp)) {
            list.reset(PyMapping_Items(inp));
            inp = list.py();
        }
        if(!PyList_Check(inp))
            return PyErr_Format(PyExc_ValueError, "argument must be dict or list of tuples");

        Config conf;
        List2Config(conf, inp);
        std::ostringstream strm;
        GLPSPrint(strm, conf);
        return PyString_FromString(strm.str().c_str());
    }CATCH()
}

#ifndef PY_SSIZE_T_CLEAN
#error the following assumes ssize_t is used
#endif

Config* PyGLPSParse2Config(PyObject *, PyObject *args, PyObject *kws)
{
    PyObject *conf = NULL, *extra_defs = Py_None;
    const char *path = NULL;
    const char *pnames[] = {"config", "path", "extra", NULL};
    if(!PyArg_ParseTupleAndKeywords(args, kws, "O|zO", (char**)pnames, &conf, &path, &extra_defs))
        return NULL;

    GLPSParser parser;

    if(extra_defs==Py_None) {
        // no-op
    } else if(PyDict_Check(extra_defs)) {
        PyObject *key, *value;
        Py_ssize_t pos = 0;

        while(PyDict_Next(extra_defs, &pos, &key, &value)) {
            PyRef<> keyx(key, borrow());
            PyCString keystr(keyx);

            Config::value_t curval;

            if(PyNumber_Check(value)) {
                PyRef<> pyf(PyNumber_Float(value));
                curval = PyFloat_AsDouble(pyf.py());

            } else if(PyString_Check(value)) {
                PyRef<> valuex(value, borrow());
                PyCString valstr(valuex);

                curval = valstr.c_str();

            } else {
                PyErr_SetString(PyExc_ValueError, "extra {} can contain only numbers or strings");
                return NULL;
            }

            parser.setVar(keystr.c_str(), curval);
        }
    } else {
        PyErr_SetString(PyExc_ValueError, "'extra' must be a dict");
        return NULL;
    }

    PyGetBuf buf;
    std::auto_ptr<Config> C;

    PyRef<> listref;

    if(PyObject_HasAttrString(conf, "read")) { // file-like
        PyCString pyname;

        if(!path && PyObject_HasAttrString(conf, "name")) {
            path = pyname.c_str(pydirname(PyObject_GetAttrString(conf, "name")));
        }

        PyRef<> pybytes(PyObject_CallMethod(conf, "read", ""));
        if(!buf.get(pybytes.py())) {
            PyErr_SetString(PyExc_TypeError, "read() must return a buffer");
            return NULL;
        }
        C.reset(parser.parse_byte((const char*)buf.data(), buf.size(), path));

    } else if(buf.get(conf)) {
        C.reset(parser.parse_byte((const char*)buf.data(), buf.size(), path));

#if PY_MAJOR_VERSION >= 3
    } else if(PyUnicode_Check(conf)) { // py3 str (aka unicode) doesn't implement buffer iface
        PyCString buf;
        const char *cbuf = buf.c_str(conf);

        C.reset(parser.parse_byte(cbuf, strlen(cbuf), path));
#endif

    } else {
        if(PyDict_Check(conf)) {
            listref.reset(PyMapping_Items(conf));
            conf = listref.py();
        }
        if(PyList_Check(conf)) {
            C.reset(list2conf(conf));

        } else {
            throw std::invalid_argument("'config' must be dict, list of tuples, or byte buffer");
        }
    }

    return C.release();
}

PyObject* PyGLPSParse(PyObject *unused, PyObject *args, PyObject *kws)
{
    try{
        return conf2dict(PyGLPSParse2Config(unused, args, kws));
    }CATCH()
}
<|endoftext|>


<commit_before>#include "mainwindow/mainWindow.h"
#include "thirdparty/windowsmodernstyle.h"

#include <QtCore/QtPlugin>
#include <QtGui/QApplication>

using namespace qReal;

int main(int argc, char *argv[])
{
	QApplication app(argc, argv);

	QTranslator appTranslator;
	if (app.arguments().count() <= 1 || app.arguments().at(1) != "--no-locale") {
		appTranslator.load(":/qrgui_" + QLocale::system().name());
		app.installTranslator(&appTranslator);
	}

#ifndef NO_STYLE_WINDOWSMODERN
	app.setStyle(new WindowsModernStyle());
#endif

	MainWindow window;
	if (window.isVisible())
		return app.exec();
	else  // The window decided to not show itself, exiting now.
		return 0;
}
<commit_msg>jenkins: error<commit_after>#include "mainwindow/mainWindow.h"
#include "thirdparty/windowsmodernstyle.h"

#include <QtCore/QtPlugin>
#include <QtGui/QApplication>

using namespace qReal;

int main(int argc, char *argv[])
{
	int ERROR = trololo;

	QApplication app(argc, argv);

	QTranslator appTranslator;
	if (app.arguments().count() <= 1 || app.arguments().at(1) != "--no-locale") {
		appTranslator.load(":/qrgui_" + QLocale::system().name());
		app.installTranslator(&appTranslator);
	}

#ifndef NO_STYLE_WINDOWSMODERN
	app.setStyle(new WindowsModernStyle());
#endif

	MainWindow window;
	if (window.isVisible())
		return app.exec();
	else  // The window decided to not show itself, exiting now.
		return 0;
}
<|endoftext|>


<commit_before><commit_msg>add unit tests for operators<commit_after><|endoftext|>