<commit_before>// Copyright 2021 Nisaba Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "nisaba/scripts/brahmic/grammar.h"

#include "absl/strings/str_cat.h"
#include "nisaba/port/file_util.h"
#include "nisaba/port/status_macros.h"

namespace nisaba {
namespace brahmic {

absl::Status Grammar::Load() {
  const auto far_path = file::GetRunfilesResourcePath(far_file_path_);
  if (!far_path.ok()) return far_path.status();
  if (!grm_mgr_->LoadArchive(far_path.value())) {
    return absl::InternalError(absl::StrCat("Failed to load archive from \"",
                                            far_path.value(), "\""));
  }

  static const std::map<std::string, std::string>& lang_script_map =
      {{"bn", "Beng"}, {"gu", "Gujr"}, {"hi", "Deva"}, {"kn", "Knda"},
       {"ml", "Mlym"}, {"mr", "Deva"}, {"or", "Orya"}, {"pa", "Guru"},
       {"si", "Sinh"}, {"ta", "Taml"}, {"te", "Telu"}};

  if (grm_mgr_->GetFstMap()->count(fst_name_) == 0) {
    const auto entry = lang_script_map.find(absl::AsciiStrToLower(fst_name_));
    if (entry == lang_script_map.end()) {
      return absl::InternalError(absl::StrCat(
          "FST \"", fst_name_, "\" not found in lowercase"));
    }
    fst_name_ = absl::AsciiStrToUpper(entry->second);
    if (grm_mgr_->GetFstMap()->count(fst_name_) == 0) {
      return absl::InternalError(absl::StrCat(
          "FST \"", fst_name_, "\" not found in uppercase"));
    }
  }
  return absl::OkStatus();
}

absl::Status Grammar::Rewrite(absl::string_view input,
                              std::string *output) const {
  if (!grm_mgr_->RewriteBytes(fst_name_, input, output)) {
    return absl::InternalError(absl::StrCat(
        "Rewrite failed for \"", input, "\""));
  }
  return absl::OkStatus();
}

absl::Status Grammar::Accept(absl::string_view input) const {
  std::string output;
  if (!grm_mgr_->RewriteBytes(fst_name_, input, &output)) {
    return absl::InternalError(absl::StrCat(
        "Rewrite failed for \"", input, "\""));
  }
  return absl::OkStatus();
}

absl::Status Normalizer::Load() {
  RETURN_IF_ERROR(visual_norm_.Load());
  RETURN_IF_ERROR(wellformed_.Load());
  return absl::OkStatus();
}

absl::Status Normalizer::Rewrite(absl::string_view input,
                                 std::string *output) const {
  RETURN_IF_ERROR(NormalizeOnly(input, output));
  RETURN_IF_ERROR(wellformed_.Accept(*output));
  return absl::OkStatus();
}

absl::Status Normalizer::NormalizeOnly(absl::string_view input,
                                       std::string *output) const {
  return visual_norm_.Rewrite(input, output);
}

}  // namespace brahmic
}  // namespace nisaba
<commit_msg>Improve error message when the FST is not found in FAR (print FAR path).<commit_after>// Copyright 2021 Nisaba Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "nisaba/scripts/brahmic/grammar.h"

#include "absl/strings/str_cat.h"
#include "nisaba/port/file_util.h"
#include "nisaba/port/status_macros.h"

namespace nisaba {
namespace brahmic {

absl::Status Grammar::Load() {
  const auto far_path = file::GetRunfilesResourcePath(far_file_path_);
  if (!far_path.ok()) return far_path.status();
  if (!grm_mgr_->LoadArchive(far_path.value())) {
    return absl::InternalError(absl::StrCat("Failed to load archive from \"",
                                            far_path.value(), "\""));
  }

  static const std::map<std::string, std::string>& lang_script_map =
      {{"bn", "Beng"}, {"gu", "Gujr"}, {"hi", "Deva"}, {"kn", "Knda"},
       {"ml", "Mlym"}, {"mr", "Deva"}, {"or", "Orya"}, {"pa", "Guru"},
       {"si", "Sinh"}, {"ta", "Taml"}, {"te", "Telu"}};

  if (grm_mgr_->GetFstMap()->count(fst_name_) == 0) {
    const auto entry = lang_script_map.find(absl::AsciiStrToLower(fst_name_));
    if (entry == lang_script_map.end()) {
      return absl::InternalError(absl::StrCat(
          "FST \"", fst_name_, "\" not found in lowercase inside FAR \"",
          far_path.value(), "\""));
    }
    fst_name_ = absl::AsciiStrToUpper(entry->second);
    if (grm_mgr_->GetFstMap()->count(fst_name_) == 0) {
      return absl::InternalError(absl::StrCat(
          "FST \"", fst_name_, "\" not found in uppercase inside FAR \"",
          far_path.value(), "\""));
    }
  }
  return absl::OkStatus();
}

absl::Status Grammar::Rewrite(absl::string_view input,
                              std::string *output) const {
  if (!grm_mgr_->RewriteBytes(fst_name_, input, output)) {
    return absl::InternalError(absl::StrCat(
        "Rewrite failed for \"", input, "\""));
  }
  return absl::OkStatus();
}

absl::Status Grammar::Accept(absl::string_view input) const {
  std::string output;
  if (!grm_mgr_->RewriteBytes(fst_name_, input, &output)) {
    return absl::InternalError(absl::StrCat(
        "Rewrite failed for \"", input, "\""));
  }
  return absl::OkStatus();
}

absl::Status Normalizer::Load() {
  RETURN_IF_ERROR(visual_norm_.Load());
  RETURN_IF_ERROR(wellformed_.Load());
  return absl::OkStatus();
}

absl::Status Normalizer::Rewrite(absl::string_view input,
                                 std::string *output) const {
  RETURN_IF_ERROR(NormalizeOnly(input, output));
  RETURN_IF_ERROR(wellformed_.Accept(*output));
  return absl::OkStatus();
}

absl::Status Normalizer::NormalizeOnly(absl::string_view input,
                                       std::string *output) const {
  return visual_norm_.Rewrite(input, output);
}

}  // namespace brahmic
}  // namespace nisaba
<|endoftext|>


<commit_before>
#include "ntl.h"
#include "gf.cpp"
#include "gfp.cpp"
#include "gf2n.cpp"
#include "mat.cpp"
#include "vec.cpp"
#include "fft.cpp"

template<typename T>
class FFTUtest
{
public:

  void test_gcd1(GF<T> *gf)
  {
    SignedDoubleT<T> bezout[2];

    //not explicitely related to GF(97)
    assert(2 == gf->_extended_gcd(240, 46, NULL, NULL));
    assert(6 == gf->_extended_gcd(54, 24, NULL, NULL));
    assert(15 == gf->_extended_gcd(210, 45, NULL, NULL));
    //
    assert(1 == gf->_extended_gcd(97, 20, bezout, NULL));
    assert(bezout[0] == -7 && bezout[1] == 34);
    assert(gf->inv(20) == 34);
    //
    int i;
    for (i = 0;i < 100;i++) {
      T x = gf->weak_rand();
      assert(1 == gf->_extended_gcd(97, x, bezout, NULL));
      //std::cerr << bezout[0] << "*" << 97 << " " << bezout[1] << "*" << x << "=1\n";
      T y = gf->inv(x);
      //std::cerr << "inv(x)=" << y << "\n";
      if (bezout[1] < 0)
        bezout[1] = bezout[1] + gf->card();
      assert(bezout[1] == y);
    }
  }

  void test_gcd()
  {
    std::cout << "test_gcd\n";

    GFP<T> gf(97);
    test_gcd1(&gf);
  }

  /**
   * http://www.math.unm.edu/~loring/links/discrete_f05/remainder.pdf
   * http://gauss.math.luc.edu/greicius/Math201/Fall2012/Lectures/ChineseRemainderThm.article.pdf
   *
   * @param gf
   */
  void test_chinese_remainder()
  {
    std::cout << "test_chinese_remainder\n";

    GFP<T> gf5(5);

    T a[4];
    T n[4];
    T omega;

    a[0] = 4;
    n[0] = 107;
    a[1] = 2;
    n[1] = 74;
    omega = gf5._chinese_remainder(2, a, n);
    assert(omega == 5996);

    a[0] = 6;
    n[0] = 7;
    a[1] = 4;
    n[1] = 8;
    omega = gf5._chinese_remainder(2, a, n);
    assert(omega == 20);

    a[0] = 3;
    n[0] = 4;
    a[1] = 0;
    n[1] = 6;
    omega = gf5._chinese_remainder(2, a, n);
    //no solution XXX detect it
  }

  void test_quadratic_residues()
  {
    std::cout << "test_quadratic_residues\n";

    GFP<T> gf32(32);
    int i;
    for (i = 0;i < 32;i++) {
      assert(gf32.is_quadratic_residue(gf32.exp(i, 2)));
    }

    GFP<T> gf7(7);
    assert(gf7.is_quadratic_residue(2));
    assert(!gf7.is_quadratic_residue(5));

    GFP<T> gf8(8);
    assert(gf8.is_quadratic_residue(1));
    assert(!gf8.is_quadratic_residue(3));
  }

  void test_jacobi()
  {
    GFP<T> gf(3);

    assert(gf._jacobi(1001, 9907) == -1);
    assert(gf._jacobi(19, 45) == 1);
    assert(gf._jacobi(8, 21) == -1);
    assert(gf._jacobi(5, 21) == 1);
    assert(gf._jacobi(47, 221) == -1);
    assert(gf._jacobi(2, 221) == -1);
  }

  /**
   * convert a number into a vector of digits padded with zeros
   *
   * @param num
   *
   * @return
   */
  Vec<T> *_convert_string2vec(GF<T> *gf, int N, char num[])
  {
    int i;
    Vec<T> *vec = new Vec<T>(gf, N);
    int len = strlen(num);

    for (i = 0;i < len;i++) {
      vec->set(i, num[len - i - 1] - '0');
    }
    for (;i < N;i++) {
      vec->set(i, 0);
    }

    return vec;
  }

  char *_convert_vec2string(Vec<T> *vec)
  {
    int i;
    std::string s;
    int ignore_zeros = 1;

    for (i = vec->n-1;i >= 0;i--) {
      if (ignore_zeros) {
        if (vec->get(i) != 0)
          ignore_zeros = 0;
        else
          continue ;
      }
      s.append(1, vec->get(i) + '0');
    }

    return strdup(s.c_str());
  }

  /**
   * Example taken from Pierre Meunier's book
   *
   * @param gf
   */
  void test_mul_bignum()
  {
    std::cout << "test_mul_bignum\n";

    GFP<T> gf(3); //just to do basic calculations

    int b = 10; //base
    int p = 14; //we could multiply integers of 2^p digits
    int max_digits = gf.__exp(2, p);
    //std::cerr << "p=" << p << " max_digits=" << max_digits << "\n";

    int n = p + 1;
    int N = gf.__exp(2, n);
    //std::cerr << "n=" << n << " N=" << N << "\n";

    //choose 2 prime numbers
    T a1 = 2;
    T a2 = 5;
    T p1 = a1 * gf._exp(2, 15) + 1;
    T p2 = a2 * gf._exp(2, 15) + 1;
    //std::cerr << "p1=" << p1 << " p2=" << p2 << "\n";
    assert(gf._solovay_strassen(p1));
    assert(gf._solovay_strassen(p2));

    //ensure their product is bounded (b-1)^2*2^(n-1) < m
    T m = p1 * p2;
    //check overflow
    assert(m/p1 == p2);
    //std::cerr << " m=" << m << "\n";
    assert(gf.__exp((b - 1), 2) * gf.__exp(p, 2) < m);

    assert(gf._jacobi(3, p1) == gf._jacobi(p1, 3));
    assert(gf._jacobi(p1, 3) == gf._jacobi(2, 3));
    assert(gf._jacobi(3, p2) == gf._jacobi(p2, 3));
    assert(gf._jacobi(p2, 3) == gf._jacobi(2, 3));
    assert(gf._jacobi(2, 3) == -1);
    //which means 3 is not a quadratic residue

    //therefore we can compute the roots of unity in GF_p1 and GF_p2
    T w1 = gf.__exp(3, a1);
    T w2 = gf.__exp(3, a2);
    //std::cerr << "w1=" << w1 << " w2=" << w2 << "\n";
    assert(w1 == 9);
    assert(w2 == 243);

    //find root of unity in GF_p1p2
    T _a[2];
    T _n[2];
    _a[0] = w1;
    _n[0] = p1;
    _a[1] = w2;
    _n[1] = p2;
    T w = gf._chinese_remainder(2, _a, _n);
    //std::cerr << " w=" << w << "\n";
    assert(w == 25559439);

    GFP<T> gf_m(m);
    FFT<T> fft(&gf_m, n, 25559439);

    //parse the big numbers
    char X[] = "1236548787985654354598651354984132468";
    char Y[] = "745211515185321545554545854598651354984132468";

    Vec<T> *_X = _convert_string2vec(&gf_m, N, X);
    //_X->dump();
    Vec<T> *_Y = _convert_string2vec(&gf_m, N, Y);
    //_Y->dump();

    Vec<T> *sfX = new Vec<T>(&gf_m, N);
    Vec<T> *sfY = new Vec<T>(&gf_m, N);
    Vec<T> *_XY = new Vec<T>(&gf_m, N);
    Vec<T> *sfXY = new Vec<T>(&gf_m, N);

    fft.fft(sfX, _X);
    fft.fft(sfY, _Y);

    for (int i = 0;i <= N-1;i++) {
      DoubleT<T> val = DoubleT<T>(sfX->get(i)) * sfY->get(i);
      _XY->set(i, val % m);
    }

    fft.ifft(sfXY, _XY);

    T inv_N = gf_m.inv(N);
    //std::cerr << "inv_N=" << inv_N << "\n";

#if 0
    for (int i = 0;i <= N-1;i++) {
      DoubleT<T> val = DoubleT<T>(sfXY->get(i)) * inv_N;
      sfXY->set(i, val % m);
    }
#endif

    //sfXY->dump();
    //exit(0);

    mpz_class z = 0;
    for (int i = 0;i <= N-1;i++) {
      mpz_class t, b;
      b = 10;
      mpz_pow_ui(t.get_mpz_t(), b.get_mpz_t(), i);
      z += ((sfXY->get(i) * inv_N) % m) * t;
    }

    std::cout << z << "\n";

    //char *s = _convert_vec2string(sfXY);
    //std::cout << s << "\n";

    //free(s);
    delete sfXY;
    delete _XY;
    delete sfX;
    delete sfY;
    delete _X;
    delete _Y;
  }

  void fft_utest_no_mul_bignum()
  {
    std::cout << "fft_utest\n";

    test_gcd();
    test_chinese_remainder();
    test_quadratic_residues();
    test_jacobi();
  }

  void fft_utest()
  {
    std::cout << "fft_utest\n";

    test_gcd();
    test_chinese_remainder();
    test_quadratic_residues();
    test_jacobi();
    test_mul_bignum();
  }
};

template class Mat<uint32_t>;
template class Vec<uint32_t>;
template class FFT<uint32_t>;

template class Mat<uint64_t>;
template class Vec<uint64_t>;
template class FFT<uint64_t>;

template class Mat<mpz_class>;
template class Vec<mpz_class>;

template class GF<uint32_t>;
template class GFP<uint32_t>;
template class GF2N<uint32_t>;

template class GF<uint64_t>;
template class GFP<uint64_t>;
template class GF2N<uint64_t>;

template class GF<mpz_class>;
template class GFP<mpz_class>;

void fft_utest()
{
  FFTUtest<uint32_t> fftutest_uint32;
  fftutest_uint32.fft_utest_no_mul_bignum();
  FFTUtest<uint64_t> fftutest_uint64;
  fftutest_uint64.fft_utest();
  FFTUtest<mpz_class> fftutest_mpz;
  fftutest_mpz.fft_utest_no_mul_bignum(); //too slow
}
<commit_msg>add unit test for mul<commit_after>
#include "ntl.h"
#include "gf.cpp"
#include "gfp.cpp"
#include "gf2n.cpp"
#include "mat.cpp"
#include "vec.cpp"
#include "fft.cpp"

template<typename T>
class FFTUtest
{
public:

  void test_gcd1(GF<T> *gf)
  {
    SignedDoubleT<T> bezout[2];

    //not explicitely related to GF(97)
    assert(2 == gf->_extended_gcd(240, 46, NULL, NULL));
    assert(6 == gf->_extended_gcd(54, 24, NULL, NULL));
    assert(15 == gf->_extended_gcd(210, 45, NULL, NULL));
    //
    assert(1 == gf->_extended_gcd(97, 20, bezout, NULL));
    assert(bezout[0] == -7 && bezout[1] == 34);
    assert(gf->inv(20) == 34);
    //
    int i;
    for (i = 0;i < 100;i++) {
      T x = gf->weak_rand();
      assert(1 == gf->_extended_gcd(97, x, bezout, NULL));
      //std::cerr << bezout[0] << "*" << 97 << " " << bezout[1] << "*" << x << "=1\n";
      T y = gf->inv(x);
      //std::cerr << "inv(x)=" << y << "\n";
      if (bezout[1] < 0)
        bezout[1] = bezout[1] + gf->card();
      assert(bezout[1] == y);
    }
  }

  void test_gcd()
  {
    std::cout << "test_gcd\n";

    GFP<T> gf(97);
    test_gcd1(&gf);
  }

  /**
   * http://www.math.unm.edu/~loring/links/discrete_f05/remainder.pdf
   * http://gauss.math.luc.edu/greicius/Math201/Fall2012/Lectures/ChineseRemainderThm.article.pdf
   *
   * @param gf
   */
  void test_chinese_remainder()
  {
    std::cout << "test_chinese_remainder\n";

    GFP<T> gf5(5);

    T a[4];
    T n[4];
    T omega;

    a[0] = 4;
    n[0] = 107;
    a[1] = 2;
    n[1] = 74;
    omega = gf5._chinese_remainder(2, a, n);
    assert(omega == 5996);

    a[0] = 6;
    n[0] = 7;
    a[1] = 4;
    n[1] = 8;
    omega = gf5._chinese_remainder(2, a, n);
    assert(omega == 20);

    a[0] = 3;
    n[0] = 4;
    a[1] = 0;
    n[1] = 6;
    omega = gf5._chinese_remainder(2, a, n);
    //no solution XXX detect it
  }

  void test_quadratic_residues()
  {
    std::cout << "test_quadratic_residues\n";

    GFP<T> gf32(32);
    int i;
    for (i = 0;i < 32;i++) {
      assert(gf32.is_quadratic_residue(gf32.exp(i, 2)));
    }

    GFP<T> gf7(7);
    assert(gf7.is_quadratic_residue(2));
    assert(!gf7.is_quadratic_residue(5));

    GFP<T> gf8(8);
    assert(gf8.is_quadratic_residue(1));
    assert(!gf8.is_quadratic_residue(3));
  }

  void test_jacobi()
  {
    GFP<T> gf(3);

    assert(gf._jacobi(1001, 9907) == -1);
    assert(gf._jacobi(19, 45) == 1);
    assert(gf._jacobi(8, 21) == -1);
    assert(gf._jacobi(5, 21) == 1);
    assert(gf._jacobi(47, 221) == -1);
    assert(gf._jacobi(2, 221) == -1);
  }

  /**
   * convert a number into a vector of digits padded with zeros
   *
   * @param num
   *
   * @return
   */
  Vec<T> *_convert_string2vec(GF<T> *gf, int N, char num[])
  {
    int i;
    Vec<T> *vec = new Vec<T>(gf, N);
    int len = strlen(num);

    for (i = 0;i < len;i++) {
      vec->set(i, num[len - i - 1] - '0');
    }
    for (;i < N;i++) {
      vec->set(i, 0);
    }

    return vec;
  }

  /**
   * Example taken from Pierre Meunier's book
   *
   * @param gf
   */
  void test_mul_bignum()
  {
    std::cout << "test_mul_bignum\n";

    GFP<T> gf(3); //just to do basic calculations

    int b = 10; //base
    int p = 14; //we could multiply integers of 2^p digits
    int max_digits = gf.__exp(2, p);
    //std::cerr << "p=" << p << " max_digits=" << max_digits << "\n";

    int n = p + 1;
    int N = gf.__exp(2, n);
    //std::cerr << "n=" << n << " N=" << N << "\n";

    //choose 2 prime numbers
    T a1 = 2;
    T a2 = 5;
    T p1 = a1 * gf._exp(2, 15) + 1;
    T p2 = a2 * gf._exp(2, 15) + 1;
    //std::cerr << "p1=" << p1 << " p2=" << p2 << "\n";
    assert(gf._solovay_strassen(p1));
    assert(gf._solovay_strassen(p2));

    //ensure their product is bounded (b-1)^2*2^(n-1) < m
    T m = p1 * p2;
    //check overflow
    assert(m/p1 == p2);
    //std::cerr << " m=" << m << "\n";
    assert(gf.__exp((b - 1), 2) * gf.__exp(p, 2) < m);

    assert(gf._jacobi(3, p1) == gf._jacobi(p1, 3));
    assert(gf._jacobi(p1, 3) == gf._jacobi(2, 3));
    assert(gf._jacobi(3, p2) == gf._jacobi(p2, 3));
    assert(gf._jacobi(p2, 3) == gf._jacobi(2, 3));
    assert(gf._jacobi(2, 3) == -1);
    //which means 3 is not a quadratic residue

    //therefore we can compute the roots of unity in GF_p1 and GF_p2
    T w1 = gf.__exp(3, a1);
    T w2 = gf.__exp(3, a2);
    //std::cerr << "w1=" << w1 << " w2=" << w2 << "\n";
    assert(w1 == 9);
    assert(w2 == 243);

    //find root of unity in GF_p1p2
    T _a[2];
    T _n[2];
    _a[0] = w1;
    _n[0] = p1;
    _a[1] = w2;
    _n[1] = p2;
    T w = gf._chinese_remainder(2, _a, _n);
    //std::cerr << " w=" << w << "\n";
    assert(w == 25559439);

    GFP<T> gf_m(m);
    FFT<T> fft(&gf_m, n, 25559439);

    //parse the big numbers
    char X[] = "1236548787985654354598651354984132468";
    char Y[] = "745211515185321545554545854598651354984132468";

    Vec<T> *_X = _convert_string2vec(&gf_m, N, X);
    //_X->dump();
    Vec<T> *_Y = _convert_string2vec(&gf_m, N, Y);
    //_Y->dump();

    Vec<T> *sfX = new Vec<T>(&gf_m, N);
    Vec<T> *sfY = new Vec<T>(&gf_m, N);
    Vec<T> *_XY = new Vec<T>(&gf_m, N);
    Vec<T> *sfXY = new Vec<T>(&gf_m, N);

    fft.fft(sfX, _X);
    fft.fft(sfY, _Y);

    for (int i = 0;i <= N-1;i++) {
      DoubleT<T> val = DoubleT<T>(sfX->get(i)) * sfY->get(i);
      _XY->set(i, val % m);
    }

    fft.ifft(sfXY, _XY);

    T inv_N = gf_m.inv(N);
    //std::cerr << "inv_N=" << inv_N << "\n";

    //carry propagation
    mpz_class z = 0;
    for (int i = 0;i <= N-1;i++) {
      mpz_class t, b;
      b = 10;
      mpz_pow_ui(t.get_mpz_t(), b.get_mpz_t(), i);
      z += ((sfXY->get(i) * inv_N) % m) * t;
    }

    //std::cout << z << "\n";
    assert(z.get_str() == "921490395895362412399910100421159322712298564831565484737491129935640058571771024");

    delete sfXY;
    delete _XY;
    delete sfX;
    delete sfY;
    delete _X;
    delete _Y;
  }

  void fft_utest_no_mul_bignum()
  {
    std::cout << "fft_utest\n";

    test_gcd();
    test_chinese_remainder();
    test_quadratic_residues();
    test_jacobi();
  }

  void fft_utest()
  {
    std::cout << "fft_utest\n";

    test_gcd();
    test_chinese_remainder();
    test_quadratic_residues();
    test_jacobi();
    test_mul_bignum();
  }
};

template class Mat<uint32_t>;
template class Vec<uint32_t>;
template class FFT<uint32_t>;

template class Mat<uint64_t>;
template class Vec<uint64_t>;
template class FFT<uint64_t>;

template class Mat<mpz_class>;
template class Vec<mpz_class>;

template class GF<uint32_t>;
template class GFP<uint32_t>;
template class GF2N<uint32_t>;

template class GF<uint64_t>;
template class GFP<uint64_t>;
template class GF2N<uint64_t>;

template class GF<mpz_class>;
template class GFP<mpz_class>;

void fft_utest()
{
  FFTUtest<uint32_t> fftutest_uint32;
  fftutest_uint32.fft_utest_no_mul_bignum();
  FFTUtest<uint64_t> fftutest_uint64;
  fftutest_uint64.fft_utest();
  FFTUtest<mpz_class> fftutest_mpz;
  fftutest_mpz.fft_utest_no_mul_bignum(); //too slow
}
<|endoftext|>


<commit_before>#include <Windows.h>
#include "dbg_thunk.h"

namespace vscode {

	void* thunk_create(intptr_t dbg, intptr_t hook)
	{
		static unsigned char sc[] = {
#if defined(_M_X64)
			0x57,                                                       // push rdi
			0x50,                                                       // push rax
			0x48, 0x83, 0xec, 0x28,                                     // sub rsp, 40
			0x48, 0x8b, 0xfc,                                           // mov rdi, rsp
			0x4c, 0x8b, 0xc2,                                           // mov r8, rdx
			0x48, 0x8b, 0xd1,                                           // mov rdx, rcx
			0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rcx, dbg
			0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, hook
			0xff, 0xd0,                                                 // call rax
			0x48, 0x83, 0xc4, 0x28,                                     // add rsp, 40
			0x58,                                                       // pop rax
			0x5f,                                                       // pop rdi
			0xc3,                                                       // ret
#else
			0xff, 0x74, 0x24, 0x08,       // push [esp+8]
			0xff, 0x74, 0x24, 0x08,       // push [esp+8]
			0x68, 0x00, 0x00, 0x00, 0x00, // push dbg
			0xe8, 0x00, 0x00, 0x00, 0x00, // call hook
			0x83, 0xc4, 0x0c,             // add esp, 12
			0xc3,                         // ret

#endif
		};
		LPVOID shellcode = VirtualAllocEx(GetCurrentProcess(), NULL, sizeof(sc), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		if (!shellcode) {
			return 0;
		}
#if defined(_M_X64)
		memcpy(sc + 17, &dbg, sizeof(dbg));
		memcpy(sc + 27, &hook, sizeof(hook));
#else
		memcpy(sc + 9, &dbg, sizeof(dbg));
		hook = hook - ((intptr_t)shellcode + 18);
		memcpy(sc + 14, &hook, sizeof(hook));
#endif
		SIZE_T written = 0;
		BOOL ok = WriteProcessMemory(GetCurrentProcess(), shellcode, &sc, sizeof(sc), &written);
		if (!ok || written != sizeof(sc)) {
			thunk_destory(shellcode);
			return 0;
		}
		return shellcode;
	}

	void thunk_destory(void* shellcode)
	{
		if (shellcode) {
			VirtualFreeEx(GetCurrentProcess(), shellcode, 0, MEM_RELEASE);
		}
	}
}
<commit_msg>这个没必要，似乎<commit_after>#include <Windows.h>
#include "dbg_thunk.h"

namespace vscode {

	void* thunk_create(intptr_t dbg, intptr_t hook)
	{
		static unsigned char sc[] = {
#if defined(_M_X64)
			0x57,                                                       // push rdi
			0x50,                                                       // push rax
			0x48, 0x83, 0xec, 0x28,                                     // sub rsp, 40
			0x4c, 0x8b, 0xc2,                                           // mov r8, rdx
			0x48, 0x8b, 0xd1,                                           // mov rdx, rcx
			0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rcx, dbg
			0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, hook
			0xff, 0xd0,                                                 // call rax
			0x48, 0x83, 0xc4, 0x28,                                     // add rsp, 40
			0x58,                                                       // pop rax
			0x5f,                                                       // pop rdi
			0xc3,                                                       // ret
#else
			0xff, 0x74, 0x24, 0x08,       // push [esp+8]
			0xff, 0x74, 0x24, 0x08,       // push [esp+8]
			0x68, 0x00, 0x00, 0x00, 0x00, // push dbg
			0xe8, 0x00, 0x00, 0x00, 0x00, // call hook
			0x83, 0xc4, 0x0c,             // add esp, 12
			0xc3,                         // ret

#endif
		};
		LPVOID shellcode = VirtualAllocEx(GetCurrentProcess(), NULL, sizeof(sc), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		if (!shellcode) {
			return 0;
		}
#if defined(_M_X64)
		memcpy(sc + 14, &dbg, sizeof(dbg));
		memcpy(sc + 24, &hook, sizeof(hook));
#else
		memcpy(sc + 9, &dbg, sizeof(dbg));
		hook = hook - ((intptr_t)shellcode + 18);
		memcpy(sc + 14, &hook, sizeof(hook));
#endif
		SIZE_T written = 0;
		BOOL ok = WriteProcessMemory(GetCurrentProcess(), shellcode, &sc, sizeof(sc), &written);
		if (!ok || written != sizeof(sc)) {
			thunk_destory(shellcode);
			return 0;
		}
		return shellcode;
	}

	void thunk_destory(void* shellcode)
	{
		if (shellcode) {
			VirtualFreeEx(GetCurrentProcess(), shellcode, 0, MEM_RELEASE);
		}
	}
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2010 Collabora Ltd. <info@collabora.co.uk>
      @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>

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

    This 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 Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "approverdaemon.h"
#include "tpkdeapproverfactory.h"

#include <KAboutData>
#include <KLocale>
#include <KComponentData>
#include <KDEDModule>

#include <TelepathyQt4/Types>
#include <TelepathyQt4/Debug>
#include <TelepathyQt4/ClientRegistrar>
#include <TelepathyQt4/Channel>
#include <TelepathyQt4/TextChannel>
#include <TelepathyQt4/IncomingFileTransferChannel>

class TpKDEApproverModule : public KDEDModule
{
public:
    TpKDEApproverModule(QObject *parent, const QVariantList & args)
        : KDEDModule(parent)
    {
        Q_UNUSED(args);

        Tp::registerTypes();
        Tp::enableDebug(true);
        Tp::enableWarnings(true);

        Tp::AccountFactoryPtr accountFactory =
            Tp::AccountFactory::create(QDBusConnection::sessionBus());
        Tp::ConnectionFactoryPtr connectionFactory =
            Tp::ConnectionFactory::create(QDBusConnection::sessionBus());

        Tp::ChannelFactoryPtr channelFactory =
            Tp::ChannelFactory::create(QDBusConnection::sessionBus());
        channelFactory->addCommonFeatures(Tp::Channel::FeatureCore);
        channelFactory->addFeaturesForTextChats(Tp::Features()
                                                    << Tp::TextChannel::FeatureCore
                                                    << Tp::TextChannel::FeatureMessageQueue);
        channelFactory->addFeaturesForIncomingFileTransfers(
                Tp::IncomingFileTransferChannel::FeatureCore);

        Tp::ContactFactoryPtr contactFactory =
            Tp::ContactFactory::create(Tp::Features()
                                        << Tp::Contact::FeatureAlias
                                        << Tp::Contact::FeatureAvatarData);

        m_registrar = Tp::ClientRegistrar::create(accountFactory, connectionFactory,
                                                  channelFactory, contactFactory);
        m_registrar->registerClient(Tp::SharedPtr<ApproverDaemon>(new ApproverDaemon()),
                                    "telepathy_kde_approver");
    }

    static inline KAboutData aboutData()
    {
        KAboutData aboutData("telepathy_kde_approver", 0, KLocalizedString(), "0.1",
                             KLocalizedString(), KAboutData::License_LGPL,
                             ki18n("(C) 2010, Collabora Ltd."));
        aboutData.addAuthor(ki18nc("@info:credit", "George Kiagiadakis"),
                            KLocalizedString(), "george.kiagiadakis@collabora.co.uk");
        return aboutData;
    }

private:
    Tp::ClientRegistrarPtr m_registrar;
};

K_PLUGIN_FACTORY_DEFINITION(TpKDEApproverFactory, registerPlugin<TpKDEApproverModule>();)
K_EXPORT_PLUGIN(TpKDEApproverFactory(TpKDEApproverModule::aboutData()))
<commit_msg>Rename DBus service<commit_after>/*
    Copyright (C) 2010 Collabora Ltd. <info@collabora.co.uk>
      @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>

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

    This 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 Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "approverdaemon.h"
#include "tpkdeapproverfactory.h"

#include <KAboutData>
#include <KLocale>
#include <KComponentData>
#include <KDEDModule>

#include <TelepathyQt4/Types>
#include <TelepathyQt4/Debug>
#include <TelepathyQt4/ClientRegistrar>
#include <TelepathyQt4/Channel>
#include <TelepathyQt4/TextChannel>
#include <TelepathyQt4/IncomingFileTransferChannel>

class TpKDEApproverModule : public KDEDModule
{
public:
    TpKDEApproverModule(QObject *parent, const QVariantList & args)
        : KDEDModule(parent)
    {
        Q_UNUSED(args);

        Tp::registerTypes();
        Tp::enableDebug(true);
        Tp::enableWarnings(true);

        Tp::AccountFactoryPtr accountFactory =
            Tp::AccountFactory::create(QDBusConnection::sessionBus());
        Tp::ConnectionFactoryPtr connectionFactory =
            Tp::ConnectionFactory::create(QDBusConnection::sessionBus());

        Tp::ChannelFactoryPtr channelFactory =
            Tp::ChannelFactory::create(QDBusConnection::sessionBus());
        channelFactory->addCommonFeatures(Tp::Channel::FeatureCore);
        channelFactory->addFeaturesForTextChats(Tp::Features()
                                                    << Tp::TextChannel::FeatureCore
                                                    << Tp::TextChannel::FeatureMessageQueue);
        channelFactory->addFeaturesForIncomingFileTransfers(
                Tp::IncomingFileTransferChannel::FeatureCore);

        Tp::ContactFactoryPtr contactFactory =
            Tp::ContactFactory::create(Tp::Features()
                                        << Tp::Contact::FeatureAlias
                                        << Tp::Contact::FeatureAvatarData);

        m_registrar = Tp::ClientRegistrar::create(accountFactory, connectionFactory,
                                                  channelFactory, contactFactory);
        m_registrar->registerClient(Tp::SharedPtr<ApproverDaemon>(new ApproverDaemon()),
                                    "KDE.Approver");
    }

    static inline KAboutData aboutData()
    {
        KAboutData aboutData("telepathy_kde_approver", 0, KLocalizedString(), "0.1",
                             KLocalizedString(), KAboutData::License_LGPL,
                             ki18n("(C) 2010, Collabora Ltd."));
        aboutData.addAuthor(ki18nc("@info:credit", "George Kiagiadakis"),
                            KLocalizedString(), "george.kiagiadakis@collabora.co.uk");
        return aboutData;
    }

private:
    Tp::ClientRegistrarPtr m_registrar;
};

K_PLUGIN_FACTORY_DEFINITION(TpKDEApproverFactory, registerPlugin<TpKDEApproverModule>();)
K_EXPORT_PLUGIN(TpKDEApproverFactory(TpKDEApproverModule::aboutData()))
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <limits>
#include <algorithm>
#include "util/name_generator.h"

namespace lean {
name name_generator::next() {
    if (m_next_idx == std::numeric_limits<unsigned>::max()) {
        // avoid overflow
        m_prefix   = name(m_prefix, m_next_idx);
        m_next_idx = 0;
    }
    name r(m_prefix, m_next_idx);
    m_next_idx++;
    return r;
}

void swap(name_generator & a, name_generator & b) {
    swap(a.m_prefix, b.m_prefix);
    std::swap(a.m_next_idx, b.m_next_idx);
}

DECL_UDATA(name_generator)
static int mk_name_generator(lua_State * L) { return push_name_generator(L, name_generator(to_name_ext(L, 1))); }
static int name_generator_next(lua_State * L) { return push_name(L, to_name_generator(L, 1).next()); }
static int name_generator_prefix(lua_State * L) { return push_name(L, to_name_generator(L, 1).prefix()); }
static int name_generator_mk_child(lua_State * L) { return push_name_generator(L, to_name_generator(L, 1).mk_child()); }
static const struct luaL_Reg name_generator_m[] = {
    {"__gc",     name_generator_gc}, // never throws
    {"next",     safe_function<name_generator_next>},
    {"prefix",   safe_function<name_generator_prefix>},
    {"mk_child", safe_function<name_generator_mk_child>},
    {0, 0}
};

void open_name_generator(lua_State * L) {
    luaL_newmetatable(L, name_generator_mt);
    lua_pushvalue(L, -1);
    lua_setfield(L, -2, "__index");
    setfuncs(L, name_generator_m, 0);

    SET_GLOBAL_FUN(mk_name_generator,   "name_generator");
    SET_GLOBAL_FUN(name_generator_pred, "is_name_generator");
}
}
<commit_msg>feat(util/name_generator): allow name generator to be created without providing any argument in the Lua API<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <limits>
#include <algorithm>
#include "util/name_generator.h"

namespace lean {
name name_generator::next() {
    if (m_next_idx == std::numeric_limits<unsigned>::max()) {
        // avoid overflow
        m_prefix   = name(m_prefix, m_next_idx);
        m_next_idx = 0;
    }
    name r(m_prefix, m_next_idx);
    m_next_idx++;
    return r;
}

void swap(name_generator & a, name_generator & b) {
    swap(a.m_prefix, b.m_prefix);
    std::swap(a.m_next_idx, b.m_next_idx);
}

DECL_UDATA(name_generator)
static name g_tmp_prefix = name::mk_internal_unique_name();
static int mk_name_generator(lua_State * L) {
    if (lua_gettop(L) == 0)
        return push_name_generator(L, name_generator(g_tmp_prefix));
    else
        return push_name_generator(L, name_generator(to_name_ext(L, 1)));
}
static int name_generator_next(lua_State * L) { return push_name(L, to_name_generator(L, 1).next()); }
static int name_generator_prefix(lua_State * L) { return push_name(L, to_name_generator(L, 1).prefix()); }
static int name_generator_mk_child(lua_State * L) { return push_name_generator(L, to_name_generator(L, 1).mk_child()); }
static const struct luaL_Reg name_generator_m[] = {
    {"__gc",     name_generator_gc}, // never throws
    {"next",     safe_function<name_generator_next>},
    {"prefix",   safe_function<name_generator_prefix>},
    {"mk_child", safe_function<name_generator_mk_child>},
    {0, 0}
};

void open_name_generator(lua_State * L) {
    luaL_newmetatable(L, name_generator_mt);
    lua_pushvalue(L, -1);
    lua_setfield(L, -2, "__index");
    setfuncs(L, name_generator_m, 0);

    SET_GLOBAL_FUN(mk_name_generator,   "name_generator");
    SET_GLOBAL_FUN(name_generator_pred, "is_name_generator");
}
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "TitleAnalyzer.h"

#include <regex>

namespace medialibrary
{

namespace utils
{

namespace title
{

#define SEPARATORS "(\\.|-|_|\\+)"

std::string sanitize( const std::string& fileName )
{
    static const struct {
        std::regex pattern;
        const char* substitute;
    } replacePatterns[] =
    {
        // A small subset of patterns that need to be matched between separators
        // *excluding* spaces, but keeping the separators for now
        {
            std::regex{
                SEPARATORS
                "("
                    "MEMENTO"
                ")"
                SEPARATORS,
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            "$1$3"
        },
        // A small subset of patterns to remove that contain separators, and
        // that we want to match using those separators. For instance, "5.1"
        // would be changed to "5 1", and we don't want to remove a potentially
        // relevent string by assuming there was a dot before.
        {
            std::regex{
                "((\\b|" SEPARATORS ")"
                    "("
                        "5\\.1|Web(\\.|-)DL|HD.TS|AT-X|LOST-UGM|BD"
                    ")"
                "(\\b|" SEPARATORS "))|"
                // Attempt to match most <foo>-Raws anime teams
                "(\\[[a-z]+-raws\\])",
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            ""
        },
        // Drop the extension:
        {
            std::regex{ "\\.[[:alnum:]]{2,4}$" },
            ""
        },
        {
            // File size, which we need to handle before removing a potential dot
            // We do not use \b before the size pattern to avoid considering
            // <something>.<number>.<nummber>GB as a size, we want a clean
            // <something unrelated><numerator>.<denominator><unit> pattern
            std::regex{
                "(\\s|-|_)(\\d{1,4}(\\.\\d{1,3})?(MB|GB))\\b",
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            ""
        },

        // Replace '.' separating words by a space.
        // This is done before removing most of the common patterns, so the
        // word boundaries are still present
        {
            std::regex{ "(\\s|\\b|\\(|\\[|^)" SEPARATORS "(\\b|\\s|\\)|\\]|$)" },
            " "
        },
        {
            // Since this pattern ends with a '!', we can't use it with the other
            // list of patterns that are bound by `\b`. `\b` implies that the
            // current caracter is an alphanumerical character, which isn't the
            // case of '!'
            std::regex{
                "\\bPuyaSubs!",
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            ""
        },
        {
            std::regex{
                "\\b("

                // Various patterns:
                "xvid|h264|dvd|rip|divx|x264|hdtv|aac|webrip|"
                "bluray|bdrip|brrip|dvdrip|ac3|HDTC|x265|h265|mp4|mkv|10\\s?bit(s)?|"
                "avi|HDRip|HEVC|YUV420P10|FLAC|"

                // Try to match most resolutions in one go:
                "([0-9]{3,4}(p|i))|"
                // And catch some hardcoded ones if specified without <number><p/i>
                "((7680|4096|4520|3840|2560|2048|2160|1920|1728|1280|720|460)"
                "x"
                "(4320|3072|2540|2160|1536|1440|1080|720|420|360|320))|"

                // Language/subs
                "(VOST( )?([a-z]{2})?)|"

                // Various TV channels
                "HBO|AMC|TX|"
                // AT-X contains a separator, so see above

                // Usually found team names:
                "ETTV|ETHD|DTOne|1337x|xrg|evo|yify|HorribleSubs|Eclipse|"
                "JiyuuNoFansub|ROVERS|YTS(\\s[A-Z]{2,})?|AMZN|RARBG|anoXmous(_){0,2}|"
                "BOKUTOX"
                // Ohys-Raws contains a separator so it's found in the corresponding
                // special rule above

                ")\\b",
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            ""
        },
        // Trim spaces in parenthesis/brackets:
        {
            std::regex{
                "(\\(|\\[)\\s+|"    // Spaces after an opening ( or [
                "\\s+(\\)|\\])"     // Spaces before a closing ) or ]
            },
            "$1$2"
        },
        // In case some of the removed patterns were enclosed in [] or (), remove
        // the empty pairs now
        {
            std::regex{ "(\\(\\)|\\[\\])" },
            ""
        },
        // Now that we removed many elements, re-remove the separators since the
        // word boundaries have changed
        {
            std::regex{ "(\\s|\\b|\\(|\\[|^)" SEPARATORS "(\\b|\\s|\\)|\\]|$)" },
            " "
        },
        {
            // Trim the output. Leading & trailing spaces have no group so they will be
            // replaced by an empty string, any multiple space will be replaced by the
            // first group, which is a single space
            std::regex{ "^\\s+|\\s+$|"      // leading/trailing spaces: removed
                        "(\\s)\\s+"         // multiple spaces: merged into 1
            },
            "$1"
        },
    };
    auto res = fileName;
    for ( const auto& r : replacePatterns )
        res = std::regex_replace( res, r.pattern, r.substitute );

    // If we remove the entire content, it probably means we've been too greedy
    // Return
    if ( res.empty() == true )
        return fileName;

    return res;
}

}

}

}
<commit_msg>TitleAnalyzer: Handle some teams in a case sensitive way<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "TitleAnalyzer.h"

#include <regex>

namespace medialibrary
{

namespace utils
{

namespace title
{

#define SEPARATORS "(\\.|-|_|\\+)"

std::string sanitize( const std::string& fileName )
{
    static const struct {
        std::regex pattern;
        const char* substitute;
    } replacePatterns[] =
    {
        // A small subset of patterns that need to be matched between separators
        // *excluding* spaces, but keeping the separators for now
        {
            std::regex{
                SEPARATORS
                "("
                    "MEMENTO"
                ")"
                SEPARATORS,
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            "$1$3"
        },
        // Some specific patterns that we want to match in a case sensitive way, and
        // between specific separators
        {
            std::regex{
                "(\\b|" SEPARATORS ")"
                "("
                    "MeGusta|CRiMSON|Eclipse"
                ")"
                "(\\b|" SEPARATORS ")",
                std::regex_constants::ECMAScript
            },
            ""
        },
        // A small subset of patterns to remove that contain separators, and
        // that we want to match using those separators. For instance, "5.1"
        // would be changed to "5 1", and we don't want to remove a potentially
        // relevent string by assuming there was a dot before.
        {
            std::regex{
                "((\\b|" SEPARATORS ")"
                    "("
                        "5\\.1|Web(\\.|-)DL|HD.TS|AT-X|LOST-UGM|BD"
                    ")"
                "(\\b|" SEPARATORS "))|"
                // Attempt to match most <foo>-Raws anime teams
                "(\\[[a-z]+-raws\\])",
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            ""
        },
        // Drop the extension:
        {
            std::regex{ "\\.[[:alnum:]]{2,4}$" },
            ""
        },
        {
            // File size, which we need to handle before removing a potential dot
            // We do not use \b before the size pattern to avoid considering
            // <something>.<number>.<nummber>GB as a size, we want a clean
            // <something unrelated><numerator>.<denominator><unit> pattern
            std::regex{
                "(\\s|-|_)(\\d{1,4}(\\.\\d{1,3})?(MB|GB))\\b",
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            ""
        },

        // Replace '.' separating words by a space.
        // This is done before removing most of the common patterns, so the
        // word boundaries are still present
        {
            std::regex{ "(\\s|\\b|\\(|\\[|^)" SEPARATORS "(\\b|\\s|\\)|\\]|$)" },
            " "
        },
        {
            // Since this pattern ends with a '!', we can't use it with the other
            // list of patterns that are bound by `\b`. `\b` implies that the
            // current caracter is an alphanumerical character, which isn't the
            // case of '!'
            std::regex{
                "\\bPuyaSubs!",
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            ""
        },
        {
            std::regex{
                "\\b("

                // Various patterns:
                "xvid|h264|dvd|rip|divx|x264|hdtv|aac|webrip|"
                "bluray|bdrip|brrip|dvdrip|ac3|HDTC|x265|h265|mp4|mkv|10\\s?bit(s)?|"
                "avi|HDRip|HEVC|YUV420P10|FLAC|"

                // Try to match most resolutions in one go:
                "([0-9]{3,4}(p|i))|"
                // And catch some hardcoded ones if specified without <number><p/i>
                "((7680|4096|4520|3840|2560|2048|2160|1920|1728|1280|720|460)"
                "x"
                "(4320|3072|2540|2160|1536|1440|1080|720|420|360|320))|"

                // Language/subs
                "(VOST( )?([a-z]{2})?)|"

                // Various TV channels
                "HBO|AMC|TX|"
                // AT-X contains a separator, so see above

                // Usually found team names:
                "ETTV|ETHD|DTOne|1337x|xrg|evo|yify|HorribleSubs|"
                "JiyuuNoFansub|ROVERS|YTS(\\s[A-Z]{2,})?|AMZN|RARBG|anoXmous(_){0,2}|"
                "BOKUTOX"
                // Ohys-Raws contains a separator so it's found in the corresponding
                // special rule above

                ")\\b",
                std::regex_constants::icase | std::regex_constants::ECMAScript
            },
            ""
        },
        // Trim spaces in parenthesis/brackets:
        {
            std::regex{
                "(\\(|\\[)\\s+|"    // Spaces after an opening ( or [
                "\\s+(\\)|\\])"     // Spaces before a closing ) or ]
            },
            "$1$2"
        },
        // In case some of the removed patterns were enclosed in [] or (), remove
        // the empty pairs now
        {
            std::regex{ "(\\(\\)|\\[\\])" },
            ""
        },
        // Now that we removed many elements, re-remove the separators since the
        // word boundaries have changed
        {
            std::regex{ "(\\s|\\b|\\(|\\[|^)" SEPARATORS "(\\b|\\s|\\)|\\]|$)" },
            " "
        },
        {
            // Trim the output. Leading & trailing spaces have no group so they will be
            // replaced by an empty string, any multiple space will be replaced by the
            // first group, which is a single space
            std::regex{ "^\\s+|\\s+$|"      // leading/trailing spaces: removed
                        "(\\s)\\s+"         // multiple spaces: merged into 1
            },
            "$1"
        },
    };
    auto res = fileName;
    for ( const auto& r : replacePatterns )
        res = std::regex_replace( res, r.pattern, r.substitute );

    // If we remove the entire content, it probably means we've been too greedy
    // Return
    if ( res.empty() == true )
        return fileName;

    return res;
}

}

}

}
<|endoftext|>


<commit_before>#include "vast/segment_manager.h"

#include "vast/fs/fstream.h"
#include "vast/fs/operations.h"
#include "vast/segment.h"
#include "vast/logger.h"

namespace vast {

segment_manager::segment_manager(size_t capacity, std::string const& dir)
  : cache_(capacity, [&](ze::uuid const& id) { return on_miss(id); })
  , dir_(dir)
{
  LOG(verbose, archive)
    << "spawning segment manager @" << id() << " with capacity " << capacity;

  if (! fs::exists(dir_))
  {
    LOG(info, archive)
      << "segment manager @" << id() << " creates new directory " << dir_;
    fs::mkdir(dir_);
  }
  else
  {
    LOG(info, archive)
      << "segment manager @" << id() << " scans directory " << dir_;
    scan(dir_);
    if (segment_files_.empty())
      LOG(info, archive)
        << "segment manager @" << id() << " did not find any segments";
  }

  using namespace cppa;
  init_state = (
      on_arg_match >> [=](segment const& s)
      {
        auto t = tuple_cast<segment>(self->last_dequeued());
        assert(t.valid());
        store_segment(*t);
        reply(atom("segment"), atom("ack"), s.id());
      },
      on(atom("all ids")) >> [=]
      {
        std::vector<ze::uuid> ids;
        for (auto& f : segment_files_)
          ids.push_back(f.first);
        reply(atom("ids"), std::move(ids));
      },
      on(atom("retrieve"), arg_match) >> [=](ze::uuid const& id)
      {
        LOG(debug, archive)
          << "segment manager @" << self->id() << " retrieves segment " << id;
        self->last_sender() << cache_.retrieve(id);
      },
      on(atom("shutdown")) >> [=]
      {
        segment_files_.clear();
        cache_.clear();
        self->quit();
        LOG(verbose, archive) << "segment manager @" << id() << " terminated";
      });
}

void segment_manager::scan(fs::path const& directory)
{
  fs::each_dir_entry(
      dir_,
      [&](fs::path const& p)
      {
        if (fs::is_directory(p))
          scan(p);
        else
        {
          LOG(verbose, archive)
            << "segment manager @" << id() << " found segment " << p;
          segment_files_.emplace(p.filename().string(), p);
        }
      });
}

void segment_manager::store_segment(cppa::cow_tuple<segment> t)
{
  auto& s = cppa::get<0>(t);

  // A segment should not have been recorded twice.
  assert(segment_files_.find(s.id()) == segment_files_.end());

  auto path = dir_ / s.id().to_string();
  segment_files_.emplace(s.id(), path);
  {
    fs::ofstream file(path, std::ios::binary | std::ios::out);
    ze::serialization::stream_oarchive oa(file);
    oa << s;
  }

  LOG(verbose, archive)
    << "segment manager @" << id() << " wrote segment to " << path;
  cache_.insert(s.id(), t);
}

cppa::cow_tuple<segment> segment_manager::on_miss(ze::uuid const& id)
{
  DBG(archive)
    << "segment manager @" << cppa::self->id()
    << " experienced cache miss for segment " << id;
  assert(segment_files_.find(id) != segment_files_.end());

  fs::ifstream file(dir_ / id.to_string(), std::ios::binary | std::ios::in);
  ze::serialization::stream_iarchive ia(file);
  segment s;
  ia >> s;

  return std::move(s);
}

} // namespace vast
<commit_msg>Get rid of unnecessary self's.<commit_after>#include "vast/segment_manager.h"

#include "vast/fs/fstream.h"
#include "vast/fs/operations.h"
#include "vast/segment.h"
#include "vast/logger.h"

namespace vast {

segment_manager::segment_manager(size_t capacity, std::string const& dir)
  : cache_(capacity, [&](ze::uuid const& id) { return on_miss(id); })
  , dir_(dir)
{
  LOG(verbose, archive)
    << "spawning segment manager @" << id() << " with capacity " << capacity;

  if (! fs::exists(dir_))
  {
    LOG(info, archive)
      << "segment manager @" << id() << " creates new directory " << dir_;
    fs::mkdir(dir_);
  }
  else
  {
    LOG(info, archive)
      << "segment manager @" << id() << " scans directory " << dir_;

    scan(dir_);
    if (segment_files_.empty())
      LOG(info, archive)
        << "segment manager @" << id() << " did not find any segments";
  }

  using namespace cppa;
  init_state = (
      on_arg_match >> [=](segment const& s)
      {
        auto t = tuple_cast<segment>(last_dequeued());
        assert(t.valid());
        store_segment(*t);
        reply(atom("segment"), atom("ack"), s.id());
      },
      on(atom("all ids")) >> [=]
      {
        std::vector<ze::uuid> ids;
        for (auto& f : segment_files_)
          ids.push_back(f.first);
        reply(atom("ids"), std::move(ids));
      },
      on(atom("retrieve"), arg_match) >> [=](ze::uuid const& id)
      {
        LOG(debug, archive)
          << "segment manager @" << id() << " retrieves segment " << id;

        last_sender() << cache_.retrieve(id);
      },
      on(atom("shutdown")) >> [=]
      {
        segment_files_.clear();
        cache_.clear();
        quit();
        LOG(verbose, archive) << "segment manager @" << id() << " terminated";
      });
}

void segment_manager::scan(fs::path const& directory)
{
  fs::each_dir_entry(
      dir_,
      [&](fs::path const& p)
      {
        if (fs::is_directory(p))
          scan(p);
        else
        {
          LOG(verbose, archive)
            << "segment manager @" << id() << " found segment " << p;
          segment_files_.emplace(p.filename().string(), p);
        }
      });
}

void segment_manager::store_segment(cppa::cow_tuple<segment> t)
{
  auto& s = cppa::get<0>(t);

  // A segment should not have been recorded twice.
  assert(segment_files_.find(s.id()) == segment_files_.end());

  auto path = dir_ / s.id().to_string();
  segment_files_.emplace(s.id(), path);
  {
    fs::ofstream file(path, std::ios::binary | std::ios::out);
    ze::serialization::stream_oarchive oa(file);
    oa << s;
  }

  LOG(verbose, archive)
    << "segment manager @" << id() << " wrote segment to " << path;
  cache_.insert(s.id(), t);
}

cppa::cow_tuple<segment> segment_manager::on_miss(ze::uuid const& id)
{
  DBG(archive)
    << "segment manager @" << id()
    << " experienced cache miss for segment " << id;
  assert(segment_files_.find(id) != segment_files_.end());

  fs::ifstream file(dir_ / id.to_string(), std::ios::binary | std::ios::in);
  ze::serialization::stream_iarchive ia(file);
  segment s;
  ia >> s;

  return std::move(s);
}

} // namespace vast
<|endoftext|>


<commit_before>#include "vrpn_to_mqtt_client.h"
#include <iostream>
#include <chrono>
#include <functional>
#include <mutex>

namespace vrpn_to_mqtt_client
{
  /*
    Constructor.  Make sure that we attempt to connection to the VRPN server here.
  */
  VrpnToMqttClient::VrpnToMqttClient(std::string host, std::string port, std::string mqtt_host, std::string mqtt_port, std::string mqtt_channel)
  {
      this->mqtt_channel = mqtt_channel;
      full_host_name = host + ":" + port;

      /*
        These are the banned names.  Eventually, I should lift this part
        out of the function.
      */
      banned.insert(std::string("VRPN Control"));

      std::cout << "Connecting to server at: " << full_host_name << std::endl;
      vrpn_connection = std::shared_ptr<vrpn_Connection>(vrpn_get_connection_by_name(full_host_name.c_str()));

      /*
        Make sure that we're connected to the server.
      */
      if(!vrpn_connection->connected())
      {
        std::cout << "Couldn't connect to server!" << std::endl;
        assert(vrpn_connection->connected());
      }

      std::cout << "Connected to server!" << std::endl;

      this->mqtt_client = std::make_shared<mqtt_client::MQTTClient>(mqtt_host, std::stoi(mqtt_port));
      this->mqtt_client->start();
  }

  /*
    Destructor.  Not much to do here.  Just loop through all the trackers and
    "unregister" the change handles (i.e., callbacks).
  */
  VrpnToMqttClient::~VrpnToMqttClient()
  {
    for (VrpnToMqttClient::TrackerMap::iterator it = current_trackers.begin(); it != current_trackers.end(); ++it)
    {
      it->second->tracker->unregister_change_handler(this, &VrpnToMqttClient::handle_pose);
    }
  }

  void VrpnToMqttClient::main_loop()
  {

    /*
      Call the VRPN main loop and check if the connection is okay.
    */
    vrpn_connection->mainloop();

    if(!vrpn_connection->doing_okay())
    {
      std::cout << "Warning: VRPN connection unstable!" << std::endl;
    }

    /*
      Make sure that the connection is still connected.
    */
    if(!vrpn_connection->connected())
    {
      std::cout << "Error: VRPN connection disconnected!" << std::endl;
    }

    /*
      Update all currently registered trackers.
    */
    for (VrpnToMqttClient::TrackerMap::iterator it = current_trackers.begin(); it != current_trackers.end(); ++it)
    {
      it->second->tracker->mainloop();
    }
  }

  void VrpnToMqttClient::prune_unresponsive_clients()
  {
    // Get the current time
    auto current_time = std::chrono::high_resolution_clock::now();
    // std::vector<std::string> to_remove;

    for (VrpnToMqttClient::TrackerMap::iterator it = current_trackers.begin(); it != current_trackers.end(); ++it)
    {
      auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - it->second->time_since_last_message);

      if(time_elapsed.count() > timeout_millis)
      {
        //If tracker has timed out, remove it from the message
        //TODO: Make this cleaner.
        // to_remove.push_back(it->first);
        // banned.insert(it->first); // Make sure that we can't retrack these

        // Basically,1 don't send data if we're not tracking this anymore
        if(message.count(it->first) != 0) // Only erase if it's actually in the message
        {
          std::cout << "Vicon tracker no longer getting data for: " << it->first << std::endl;
          message.erase(it->first);
        }
      }
    }

    // // Make sure that these timed-out trackers are removed from current trackers.
    // for(auto it = to_remove.begin(); it != to_remove.end(); ++it)
    // {
    //   current_trackers.erase(*it);
    // }
  }

  void VrpnToMqttClient::check_for_new_trackers()
  {
    int i = 0;

    /*
      The purpose of this block is to check for new trackers and register them.  If the new tracker is not in the
      list of current trackers or in the banned, then we add it to the trackers that are currently
      being tracked.
    */
    while(vrpn_connection->sender_name(i) != NULL)
    {
      if(current_trackers.count(vrpn_connection->sender_name(i)) == 0 && banned.count(vrpn_connection->sender_name(i)) == 0)
      {
        std::cout << "Found a new tracker: " << vrpn_connection->sender_name(i) << std::endl;

        // Make shared and register the change handler for the pose
        std::shared_ptr<tracker_data_t> data = std::make_shared<tracker_data_t>();
        data->name = std::make_shared<std::string>(vrpn_connection->sender_name(i));
        data->tracker = std::make_shared<vrpn_Tracker_Remote>(data->name->c_str(), vrpn_connection.get());
        data->time_since_last_message = std::chrono::high_resolution_clock::now();
        data->tracker->shutup = true; // Turn off messages from tracker
        data->message = &this->message;
        data->message_mutex = &this->message_mutex;

        //TODO: Should probably provide 'this' as context.  I have no idea why unregister_change_handler works
        // here...
        data->tracker.get()->register_change_handler(data.get(), &VrpnToMqttClient::handle_pose);

        // Put the new name/tracker pair into the map
        current_trackers.insert(std::make_pair(
          vrpn_connection->sender_name(i),
          data
        ));
      }

      ++i;
    }
  }

  void VrpnToMqttClient::publish_mqtt_data()
  {
    //std::cout << message.dump(4) << std::endl;
    mqtt_client->async_publish(mqtt_channel, message.dump());
  }

  /*
    Will be the method through which all messages are handled.  Basically,
    this method just needs to aggregate
  */
  void VRPN_CALLBACK VrpnToMqttClient::handle_pose(void * user_data, const vrpn_TRACKERCB tracker_data)
  {
    tracker_data_t* data = static_cast<tracker_data_t*>(user_data);

    // TODO: Add timestamp to message

    (data->time_since_last_message) = std::chrono::high_resolution_clock::now();

    data->message_mutex->lock();
    (*data->message)[data->name->c_str()]["x"] = tracker_data.pos[0]*1;
    (*data->message)[data->name->c_str()]["y"] = tracker_data.pos[1];
    (*data->message)[data->name->c_str()]["z"] = tracker_data.pos[2]*1;

    double qx = tracker_data.quat[0]*1;
    double qy = tracker_data.quat[1];
    double qz = tracker_data.quat[2]*1;
    double qw = tracker_data.quat[3];

    (*data->message)[data->name->c_str()]["theta"] = std::atan2(2.0f*(qw*qz + qx*qy), 1.0f - 2.0f*(qy*qy + qz*qz));

    // (*data->message)[data->name->c_str()]["theta"] += M_PI;
    // (*data->message)[data->name->c_str()]["theta"] = std::atan2(std::sin((*data->message)[data->name->c_str()]["theta"]), std::cos((*data->message)[data->name->c_str()]["theta"]))

    if((*data->message)[data->name->c_str()]["powerData"] == NULL)
    {
      (*data->message)[data->name->c_str()]["powerData"] = -1;
    }

    if((*data->message)[data->name->c_str()]["charging"] == NULL)
    {
      (*data->message)[data->name->c_str()]["charging"] = -1;
    }
    data->message_mutex->unlock();
  }
}
<commit_msg>Think I fixed it...<commit_after>#include "vrpn_to_mqtt_client.h"
#include <iostream>
#include <chrono>
#include <functional>
#include <mutex>

namespace vrpn_to_mqtt_client
{
  /*
    Constructor.  Make sure that we attempt to connection to the VRPN server here.
  */
  VrpnToMqttClient::VrpnToMqttClient(std::string host, std::string port, std::string mqtt_host, std::string mqtt_port, std::string mqtt_channel)
  {
      this->mqtt_channel = mqtt_channel;
      full_host_name = host + ":" + port;

      /*
        These are the banned names.  Eventually, I should lift this part
        out of the function.
      */
      banned.insert(std::string("VRPN Control"));

      std::cout << "Connecting to server at: " << full_host_name << std::endl;
      vrpn_connection = std::shared_ptr<vrpn_Connection>(vrpn_get_connection_by_name(full_host_name.c_str()));

      /*
        Make sure that we're connected to the server.
      */
      if(!vrpn_connection->connected())
      {
        std::cout << "Couldn't connect to server!" << std::endl;
        assert(vrpn_connection->connected());
      }

      std::cout << "Connected to server!" << std::endl;

      this->mqtt_client = std::make_shared<mqtt_client::MQTTClient>(mqtt_host, std::stoi(mqtt_port));
      this->mqtt_client->start();
  }

  /*
    Destructor.  Not much to do here.  Just loop through all the trackers and
    "unregister" the change handles (i.e., callbacks).
  */
  VrpnToMqttClient::~VrpnToMqttClient()
  {
    for (VrpnToMqttClient::TrackerMap::iterator it = current_trackers.begin(); it != current_trackers.end(); ++it)
    {
      it->second->tracker->unregister_change_handler(this, &VrpnToMqttClient::handle_pose);
    }
  }

  void VrpnToMqttClient::main_loop()
  {

    /*
      Call the VRPN main loop and check if the connection is okay.
    */
    vrpn_connection->mainloop();

    if(!vrpn_connection->doing_okay())
    {
      std::cout << "Warning: VRPN connection unstable!" << std::endl;
    }

    /*
      Make sure that the connection is still connected.
    */
    if(!vrpn_connection->connected())
    {
      std::cout << "Error: VRPN connection disconnected!" << std::endl;
    }

    /*
      Update all currently registered trackers.
    */
    for (VrpnToMqttClient::TrackerMap::iterator it = current_trackers.begin(); it != current_trackers.end(); ++it)
    {
      it->second->tracker->mainloop();
    }
  }

  void VrpnToMqttClient::prune_unresponsive_clients()
  {
    // Get the current time
    auto current_time = std::chrono::high_resolution_clock::now();
    // std::vector<std::string> to_remove;

    for (VrpnToMqttClient::TrackerMap::iterator it = current_trackers.begin(); it != current_trackers.end(); ++it)
    {
      auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - it->second->time_since_last_message);

      if(time_elapsed.count() > timeout_millis)
      {
        //If tracker has timed out, remove it from the message
        //TODO: Make this cleaner.
        // to_remove.push_back(it->first);
        // banned.insert(it->first); // Make sure that we can't retrack these

        // Basically,1 don't send data if we're not tracking this anymore
        if(message.count(it->first) != 0) // Only erase if it's actually in the message
        {
          std::cout << "Vicon tracker no longer getting data for: " << it->first << std::endl;
          message.erase(it->first);
        }
      }
    }

    // // Make sure that these timed-out trackers are removed from current trackers.
    // for(auto it = to_remove.begin(); it != to_remove.end(); ++it)
    // {
    //   current_trackers.erase(*it);
    // }
  }

  void VrpnToMqttClient::check_for_new_trackers()
  {
    int i = 0;

    /*
      The purpose of this block is to check for new trackers and register them.  If the new tracker is not in the
      list of current trackers or in the banned, then we add it to the trackers that are currently
      being tracked.
    */
    while(vrpn_connection->sender_name(i) != NULL)
    {
      if(current_trackers.count(vrpn_connection->sender_name(i)) == 0 && banned.count(vrpn_connection->sender_name(i)) == 0)
      {
        std::cout << "Found a new tracker: " << vrpn_connection->sender_name(i) << std::endl;

        // Make shared and register the change handler for the pose
        std::shared_ptr<tracker_data_t> data = std::make_shared<tracker_data_t>();
        data->name = std::make_shared<std::string>(vrpn_connection->sender_name(i));
        data->tracker = std::make_shared<vrpn_Tracker_Remote>(data->name->c_str(), vrpn_connection.get());
        data->time_since_last_message = std::chrono::high_resolution_clock::now();
        data->tracker->shutup = true; // Turn off messages from tracker
        data->message = &this->message;
        data->message_mutex = &this->message_mutex;

        this->message_mutex.lock();
        this->message[*data->name]["x"] = -1;
        this->message[*data->name]["y"] = -1;
        this->message[*data->name]["z"] = -1;
        this->message[*data->name]["theta"] = -1;
        this->message[*data->name]["powerData"] = -1;
        this->message[*data->name]["charging"] = -1;
        this->message_mutex.unlock();
        //TODO: Should probably provide 'this' as context.  I have no idea why unregister_change_handler works
        // here...
        data->tracker.get()->register_change_handler(data.get(), &VrpnToMqttClient::handle_pose);

        // Put the new name/tracker pair into the map
        current_trackers.insert(std::make_pair(
          vrpn_connection->sender_name(i),
          data
        ));
      }

      ++i;
    }
  }

  void VrpnToMqttClient::publish_mqtt_data()
  {
    //std::cout << message.dump(4) << std::endl;
    mqtt_client->async_publish(mqtt_channel, message.dump());
  }

  /*
    Will be the method through which all messages are handled.  Basically,
    this method just needs to aggregate
  */
  void VRPN_CALLBACK VrpnToMqttClient::handle_pose(void * user_data, const vrpn_TRACKERCB tracker_data)
  {
    tracker_data_t* data = static_cast<tracker_data_t*>(user_data);

    // TODO: Add timestamp to message

    (data->time_since_last_message) = std::chrono::high_resolution_clock::now();

    data->message_mutex->lock();
    (*data->message)[data->name->c_str()]["x"] = tracker_data.pos[0]*1;
    (*data->message)[data->name->c_str()]["y"] = tracker_data.pos[1];
    (*data->message)[data->name->c_str()]["z"] = tracker_data.pos[2]*1;

    double qx = tracker_data.quat[0]*1;
    double qy = tracker_data.quat[1];
    double qz = tracker_data.quat[2]*1;
    double qw = tracker_data.quat[3];

    (*data->message)[data->name->c_str()]["theta"] = std::atan2(2.0f*(qw*qz + qx*qy), 1.0f - 2.0f*(qy*qy + qz*qz));

    // (*data->message)[data->name->c_str()]["theta"] += M_PI;
    // (*data->message)[data->name->c_str()]["theta"] = std::atan2(std::sin((*data->message)[data->name->c_str()]["theta"]), std::cos((*data->message)[data->name->c_str()]["theta"]))

    std::cout << *data->message << std::endl;
    data->message_mutex->unlock();
  }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <functional>
#include <utility>
#include <stdexcept>

#include "config.hpp"
#include "vfs.hpp"
#include "game.hpp"

GameManager::GameManager()
: m_song("/data/songs/testsong")
{
    m_width = 800;
    m_height = 600;
    m_fullscreen = false;
    m_title = "OpenRhythm";

    m_window = std::make_unique<ORCore::Window>(m_width, m_height, m_fullscreen, m_title);
    m_context = std::make_unique<ORCore::Context>(3, 2, 0);
    m_eventManager = std::make_unique<ORCore::EventManager>();
    m_eventPump = std::make_unique<ORCore::EventPumpSDL2>(m_eventManager.get());
    m_running = true;

    m_logger = spdlog::get("default");

    m_window->make_current(m_context.get());

    //VFS.AddLoader(new ttvfs::DiskLoader);

    //
    // AppPath gets mounted on osx
    // BasePath gets mounted and overwrites any files similar to those in AppPath (data)
    // HomePath gets mounted and overwrites any files similar to those in BasePath (configs)
    // std::cout << ORCore::GetBasePath() << std::endl;
#if OSX_APP_BUNDLE
    ORCore::mount(ORCore::GetAppPath(), "");
#endif
    ORCore::mount(ORCore::GetBasePath(), "/bob");
    std::vector<std::string> paths = ORCore::resolveSystemPath("/bob");
    for (auto &i: paths) {
        auto bob = ORCore::sysGetPathContents(i);
        std::cout << i << " " << bob.size() << std::endl;
    }
    //VFS.Mount( ORCore::GetBasePath().c_str(), "" );
    //VFS.Mount( ORCore::GetHomePath().c_str(), "" );

    //ORCore::mount( "./data", "data" );

    m_song.add(ORGame::TrackType::Guitar, ORGame::Difficulty::Expert);
    m_song.load();

    //std::cout << "Song: " << (m_song.length() / 1000) / 60 << " minutes long" << std::endl;

    //ORCore::Track *track = m_song.getTrack( ORCore::TrackType::Guitar, ORCore::Difficulty::Expert );
    //std::cout << "Song: loaded track for " << ORCore::TrackNameForType( track->info().type ) << std::endl;

    m_tempoTrack = m_song.get_tempo_track();

    //std::vector<ORCore::TrackNote*> v = track->get_notes_in_frame(0, 10000);

    //std::cout << "Song: " << v.size() << " notes in first 10 seconds, first note is " << NoteNameForType(v[0]->type()) << std::endl;

    if(!gladLoadGL())
    {
        throw std::runtime_error("Error: GLAD failed to load.");
    }

    m_lis.handler = std::bind(&GameManager::event_handler, this, std::placeholders::_1);
    m_lis.mask = ORCore::EventType::EventAll;

    m_eventManager->add_listener(m_lis);

    m_fpsTime = 0.0;

    m_ss = std::cout.precision();

    glGenVertexArrays(1, &m_vao);
    glBindVertexArray(m_vao);

    ORCore::ShaderInfo vertInfo {GL_VERTEX_SHADER, "./data/shaders/main.vs"};
    ORCore::ShaderInfo fragInfo {GL_FRAGMENT_SHADER, "./data/shaders/main.fs"};

    ORCore::Shader vertShader(vertInfo);
    ORCore::Shader fragShader(fragInfo);

    m_program = std::make_unique<ORCore::ShaderProgram>(&vertShader, &fragShader);

    m_program->check_error();
    m_program->use();
    m_orthoID = m_program->uniform_attribute("ortho");

    m_texture = std::make_unique<ORCore::Texture>("data/icon.png", m_program.get());

    std::cout << (m_width / 37) * (m_height / 37) << std::endl;

    m_ortho = glm::ortho(0.0f, static_cast<float>(m_width), static_cast<float>(m_height), 0.0f, -1.0f, 1.0f);

    m_program->set_uniform(m_orthoID, m_ortho);

    glClearColor(0.5, 0.5, 0.5, 1.0);
}

GameManager::~GameManager()
{

    glDeleteVertexArrays(1, &m_vao);
    m_window->make_current(nullptr);

}

void GameManager::start()
{

    while (m_running)
    {
        m_fpsTime += m_clock.tick();
        m_eventPump->process();

        update();
        render();

        m_window->flip();
        if (m_fpsTime >= 2.0) {
            std::cout.precision (5);
            std::cout << "FPS: " << m_clock.get_fps() << std::endl;
            std::cout << "Song Time: " << m_songTime << std::endl;
            std::cout.precision (m_ss);
            m_fpsTime = 0;
        }
    }
}

void GameManager::resize(int width, int height)
{
    m_width = width;
    m_height = height;
    glViewport(0, 0, m_width, m_height);
    m_ortho = glm::ortho(0.0f, static_cast<float>(m_width), static_cast<float>(m_height), 0.0f, -1.0f, 1.0f);
    m_program->set_uniform(m_orthoID, m_ortho);

    for (auto &mesh : m_meshes) {
        mesh.translate((m_width/2.0f)-256, (m_height/2.0f) - 4); // center the line on the screen
    }
}

bool GameManager::event_handler(const ORCore::Event &event)
{
    switch(event.type) {
        case ORCore::Quit: {
            m_running = false;
            break;
        }
        case ORCore::MouseMove: {
            auto ev = ORCore::event_cast<ORCore::MouseMoveEvent>(event);
            std::cout << "mouse x: " << ev.x << " mouse y" << ev.y << std::endl;
            m_mouseX = ev.x;
            m_mouseY = ev.y;
            break;
        }
        case ORCore::WindowSized: {
            auto ev = ORCore::event_cast<ORCore::WindowSizeEvent>(event);
            resize(ev.width, ev.height);
            break;
        }
        default:
            break;
    }
    return true;
}

void GameManager::handle_song()
{
}

void GameManager::update()
{
    for (auto &mesh : m_meshes) {
        mesh.update();
    }
}

void GameManager::prep_render_bars()
{
    m_songTime = m_clock.get_current_time();
    m_barsForRender = m_tempoTrack->get_events(m_songTime, m_songTime+2.5, ORGame::EventType::Bar);
    for (size_t i = 0; i < m_barsForRender.size(); i++) {
        float z = (m_barsForRender[i].bar->time - m_songTime) * 225.0;
        if (i >= m_meshes.size()) {
            m_meshes.emplace_back(m_program.get(), m_texture.get());
        }
        m_meshes[i].scale(512.0f, 4.0f);
        m_meshes[i].translate((m_width/2.0f)-256, 100 + z); // center the line on the screen
    }
    // while (m_barsForRender.size() < m_meshes.size()) {
    //     m_meshes.pop_back();
    // }
}

void GameManager::render()
{
    prep_render_bars();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    m_program->use();
    for (auto &mesh : m_meshes) {
        mesh.render();
    }

}
<commit_msg>9c857dfdd99a0ec97e7e2dc4f30f6706ecf7bd71 changes that slipped through.<commit_after>#include <iostream>
#include <functional>
#include <utility>
#include <stdexcept>

#include "config.hpp"
#include "vfs.hpp"
#include "game.hpp"

GameManager::GameManager()
: m_song("/data/songs/testsong")
{
    m_width = 800;
    m_height = 600;
    m_fullscreen = false;
    m_title = "OpenRhythm";

    m_window = std::make_unique<ORCore::Window>(m_width, m_height, m_fullscreen, m_title);
    m_context = std::make_unique<ORCore::Context>(3, 2, 0);
    m_eventManager = std::make_unique<ORCore::EventManager>();
    m_eventPump = std::make_unique<ORCore::EventPumpSDL2>(m_eventManager.get());
    m_running = true;

    m_logger = spdlog::get("default");

    m_window->make_current(m_context.get());

    //VFS.AddLoader(new ttvfs::DiskLoader);

    //
    // AppPath gets mounted on osx
    // BasePath gets mounted and overwrites any files similar to those in AppPath (data)
    // HomePath gets mounted and overwrites any files similar to those in BasePath (configs)
    // std::cout << ORCore::GetBasePath() << std::endl;
#if OSX_APP_BUNDLE
    ORCore::mount(ORCore::GetAppPath(), "");
#endif
    ORCore::mount(ORCore::GetBasePath(), "/bob");
    std::vector<std::string> paths = ORCore::resolveSystemPath("/bob");
    for (auto &i: paths) {
        auto bob = ORCore::sysGetPathContents(i);
        std::cout << i << " " << bob.size() << std::endl;
    }
    //VFS.Mount( ORCore::GetBasePath().c_str(), "" );
    //VFS.Mount( ORCore::GetHomePath().c_str(), "" );

    //ORCore::mount( "./data", "data" );

    m_song.add(ORGame::TrackType::Guitar, ORGame::Difficulty::Expert);
    m_song.load();

    //std::cout << "Song: " << (m_song.length() / 1000) / 60 << " minutes long" << std::endl;

    //ORCore::Track *track = m_song.getTrack( ORCore::TrackType::Guitar, ORCore::Difficulty::Expert );
    //std::cout << "Song: loaded track for " << ORCore::TrackNameForType( track->info().type ) << std::endl;

    m_tempoTrack = m_song.get_tempo_track();

    //std::vector<ORCore::TrackNote*> v = track->get_notes_in_frame(0, 10000);

    //std::cout << "Song: " << v.size() << " notes in first 10 seconds, first note is " << NoteNameForType(v[0]->type()) << std::endl;

    if(!gladLoadGL())
    {
        throw std::runtime_error("Error: GLAD failed to load.");
    }

    m_lis.handler = std::bind(&GameManager::event_handler, this, std::placeholders::_1);
    m_lis.mask = ORCore::EventType::EventAll;

    m_eventManager->add_listener(m_lis);

    m_fpsTime = 0.0;

    m_ss = std::cout.precision();

    glGenVertexArrays(1, &m_vao);
    glBindVertexArray(m_vao);

    ORCore::ShaderInfo vertInfo {GL_VERTEX_SHADER, "./data/shaders/main.vs"};
    ORCore::ShaderInfo fragInfo {GL_FRAGMENT_SHADER, "./data/shaders/main.fs"};

    ORCore::Shader vertShader(vertInfo);
    ORCore::Shader fragShader(fragInfo);

    m_program = std::make_unique<ORCore::ShaderProgram>(&vertShader, &fragShader);

    m_program->check_error();
    m_program->use();
    m_orthoID = m_program->uniform_attribute("ortho");

    m_texture = std::make_unique<ORCore::Texture>("data/icon.png", m_program.get());

    std::cout << (m_width / 37) * (m_height / 37) << std::endl;

    m_ortho = glm::ortho(0.0f, static_cast<float>(m_width), static_cast<float>(m_height), 0.0f, -1.0f, 1.0f);

    m_program->set_uniform(m_orthoID, m_ortho);

    glClearColor(0.5, 0.5, 0.5, 1.0);
}

GameManager::~GameManager()
{

    glDeleteVertexArrays(1, &m_vao);
    m_window->make_current(nullptr);

}

void GameManager::start()
{

    while (m_running)
    {
        m_fpsTime += m_clock.tick();
        m_eventPump->process();

        update();
        render();

        m_window->flip();
        if (m_fpsTime >= 2.0) {
            std::cout.precision (5);
            std::cout << "FPS: " << m_clock.get_fps() << std::endl;
            std::cout << "Song Time: " << m_songTime << std::endl;
            std::cout.precision (m_ss);
            m_fpsTime = 0;
        }
    }
}

void GameManager::resize(int width, int height)
{
    m_width = width;
    m_height = height;
    glViewport(0, 0, m_width, m_height);
    m_ortho = glm::ortho(0.0f, static_cast<float>(m_width), static_cast<float>(m_height), 0.0f, -1.0f, 1.0f);
    m_program->set_uniform(m_orthoID, m_ortho);

    for (auto &mesh : m_meshes) {
        mesh.translate((m_width/2.0f)-256, (m_height/2.0f) - 4); // center the line on the screen
    }
}

bool GameManager::event_handler(const ORCore::Event &event)
{
    switch(event.type) {
        case ORCore::Quit: {
            m_running = false;
            break;
        }
        case ORCore::MouseMove: {
            auto ev = ORCore::event_cast<ORCore::MouseMoveEvent>(event);
            std::cout << "mouse x: " << ev.x << " mouse y" << ev.y << std::endl;
            m_mouseX = ev.x;
            m_mouseY = ev.y;
            break;
        }
        case ORCore::WindowSize: {
            auto ev = ORCore::event_cast<ORCore::WindowSizeEvent>(event);
            resize(ev.width, ev.height);
            break;
        }
        default:
            break;
    }
    return true;
}

void GameManager::handle_song()
{
}

void GameManager::update()
{
    for (auto &mesh : m_meshes) {
        mesh.update();
    }
}

void GameManager::prep_render_bars()
{
    m_songTime = m_clock.get_current_time();
    m_barsForRender = m_tempoTrack->get_events(m_songTime, m_songTime+2.5, ORGame::EventType::Bar);
    for (size_t i = 0; i < m_barsForRender.size(); i++) {
        float z = (m_barsForRender[i].bar->time - m_songTime) * 225.0;
        if (i >= m_meshes.size()) {
            m_meshes.emplace_back(m_program.get(), m_texture.get());
        }
        m_meshes[i].scale(512.0f, 4.0f);
        m_meshes[i].translate((m_width/2.0f)-256, 100 + z); // center the line on the screen
    }
    // while (m_barsForRender.size() < m_meshes.size()) {
    //     m_meshes.pop_back();
    // }
}

void GameManager::render()
{
    prep_render_bars();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    m_program->use();
    for (auto &mesh : m_meshes) {
        mesh.render();
    }

}
<|endoftext|>