<commit_before>
#include <general/nmspc_iter.h>
#include <tools/common/log.h>
#include <tools/common/prof.h>
#include <tools/finite/opt-internal/report.h>
#include <tools/finite/opt_mps.h>

/* clang-format off */
void tools::finite::opt::internal::reports::print_bfgs_report(){
    if (tools::log->level() > spdlog::level::debug) return;
    if (bfgs_log.empty()) return;
    std::string format_hdr = "{:<52} {:<7} {:<7} {:<20} {:<12} {:<18} {:<18} {:<5} {:<7} {:<8} {:<8} {:<18} {:<18}";
    std::string format_num = "- {:<50} {:<7} {:<7} {:<20.15f} {:<12.8f} {:<18.15f} {:<18.15f} {:<5} {:<7} {:<8.2e} {:<8.2e} {:<18.3f} {:<18.3f}";
    tools::log->debug(format_hdr.c_str(),
                      "Optimization report",
                      "size",
                      "space",
                      "energy/L",
                      "log₁₀ var", // Special characters are counted properly in fmt 1.7.0
                      "overlap",
                      "norm",
                      "iter",
                      "counter",
                      "|Δf|",
                      "|∇f|∞",
                      "Elapsed time [ms]",
                      "Time per count [ms]");

    for(auto &entry : bfgs_log){
        tools::log->debug(format_num.c_str(),
        entry.description, entry.size,
        entry.space, entry.energy,
        std::log10(entry.variance),
        entry.overlap,entry.norm,
        entry.iter, entry.counter,
        entry.delta_f, entry.grad_max_norm,
        entry.time*1000,
        entry.time*1000.0/std::max(1.0,static_cast<double>(entry.counter)));
    }
    bfgs_log.clear();
}

void tools::finite::opt::internal::reports::print_eigs_report(){
    if (tools::log->level() > spdlog::level::debug) return;
    if (eigs_log.empty()) return;
    std::string format_hdr = "- {:<5} {:<20} {:<20} {:<20} {:<12} {:<12} {:<12} {:<6}";
    std::string format_num = "- {:<5} {:<20.15f} {:<20.15f} {:<20.8f} {:<12.3f} {:<12.3f} {:<12.3f} {:<6}";
    tools::log->debug(format_hdr.c_str(),
                       "nev",
                       "max <θ_i|θ>",
                       "min <θ_i|θ>",
                       "log₁₀(1-Σ|<θ_i|θ>|²)",  // Special characters are counted properly in fmt 1.7.0
                       "Eig Time[ms]",
                       "Ham Time[ms]",
                       "LU Time[ms]",
                       "Steps" );

    for(auto &entry : eigs_log){
        tools::log->debug(format_num.c_str(),
                          entry.nev,
                          entry.max_olap,
                          entry.min_olap,
                          entry.eps ,
                          entry.eig_time * 1000,
                          entry.ham_time * 1000,
                          entry.lu_time  * 1000,
                          entry.steps
                            );
    }
    eigs_log.clear();
}

void tools::finite::opt::internal::reports::print_time_report(){
    if (tools::log->level() > spdlog::level::trace) return;
    if(time_log.empty()) return;
    std::string format_hdr = "LBFGS Time report [ms] {:<10} {:<10} {:<10} {:<10} {:<10} {:<10} {:<10}";
    std::string format_num = "                       {:<10.3f} {:<10.3f} {:<10.3f} {:<10.3f} {:<10.3f} {:<10.3f} {:<10.3f}";
    tools::log->trace(format_hdr.c_str(),
                      "<ψ|H²|ψ>",
                      "<ψ|H|ψ>",
                      "H²|ψ>",
                      "H|ψ>",
                      "sum",
                      "step",
                      "l-bfgs");
    for(auto &entry : time_log){
    tools::log->trace(format_num.c_str(),
                     1000 * entry.vH2v,
                     1000 * entry.vHv,
                     1000 * entry.vH2,
                     1000 * entry.vH,
                     1000 *(entry.vH2v
                          + entry.vHv
                          + entry.vH2
                          + entry.vH),
                     1000 * entry.step,
                     1000 * entry.bfgs);
    }
    time_log.clear();
}

void tools::finite::opt::internal::reports::print_krylov_report(std::optional<size_t> max_entries){
    if (tools::log->level() > spdlog::level::debug) return;
    if (krylov_log.empty()) return;
    std::string format_hdr = "{:<52} {:<7} {:<4} {:<4} {:<8} {:<22} {:<22} {:<12} {:<18} {:<18} {:<5} {:<7} {:<18} {:<18}";
    std::string format_num = "- {:<50} {:<7} {:<4} {:<4} {:<8.2e} {:<22.15f} {:<22.15f} {:<12.8f} {:<18.15f} {:<18.15f} {:<5} {:<7} {:<18.3f} {:<18.3f}";
    tools::log->debug(format_hdr.c_str(),
                      "Optimization report",
                      "size",
                      "nev",
                      "ncv",
                      "tol",
                      "energy/L",
                      "eigval",
                      "log₁₀ var", // Special characters are counted properly in fmt 1.7.0
                      "overlap",
                      "norm",
                      "iter",
                      "counter",
                      "Elapsed time [ms]",
                      "Time per count [ms]");

    for(const auto &[idx,entry] : iter::enumerate(krylov_log)){
        if(max_entries and max_entries.value() <= idx) break;
        tools::log->debug(format_num.c_str(),
                          entry.description,
                          entry.size, entry.nev, entry.ncv, entry.tol,
                          entry.energy,entry.eigval,
                          std::log10(entry.variance),
                          entry.overlap,entry.norm,
                          entry.iter, entry.counter,
                          entry.time*1000,
                          entry.time*1000.0/std::max(1.0,static_cast<double>(entry.counter)));
    }
    krylov_log.clear();
}

/* clang-format on */
void tools::finite::opt::internal::reports::bfgs_add_entry(const std::string &description, long size, long space, double energy, double variance,
                                                           double overlap, double norm, double delta_f, double grad_norm, size_t iter, size_t counter,
                                                           double time) {
    if(tools::log->level() > spdlog::level::debug) return;
    bfgs_log.push_back({description, size, space, energy, variance, overlap, norm, delta_f, grad_norm, iter, counter, time});
}
void tools::finite::opt::internal::reports::bfgs_add_entry(const std::string &mode, const std::string &tag, const opt_mps &mps, std::optional<long> space) {
    if(tools::log->level() > spdlog::level::debug) return;
    if(not space) space = mps.get_tensor().size();
    std::string description = fmt::format("{:<8} {:<16} {}", mode, mps.get_name(), tag);
    bfgs_log.push_back(bfgs_entry{description, mps.get_tensor().size(), space.value(), mps.get_energy_per_site(), mps.get_variance(), mps.get_overlap(),
                                  mps.get_norm(), mps.get_delta_f(), mps.get_grad_norm(), mps.get_iter(), mps.get_counter(), mps.get_time()});
}

void tools::finite::opt::internal::reports::time_add_dir_entry() {
    if(tools::log->level() > spdlog::level::trace) return;
    time_log.push_back({tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_vH2v"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_vHv"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_vH2"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_vH"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_bfgs"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_step"]->get_last_interval()});
}
void tools::finite::opt::internal::reports::time_add_sub_entry() {
    if(tools::log->level() > spdlog::level::trace) return;
    time_log.push_back({tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_vH2v"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_vHv"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_vH2"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_vH"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_bfgs"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_step"]->get_last_interval()});
}
void tools::finite::opt::internal::reports::eigs_add_entry(long nev, double max_olap, double min_olap, double eps, double eig_time, double ham_time,
                                                           double lu_time, size_t steps) {
    if(tools::log->level() > spdlog::level::debug) return;
    eigs_log.push_back({nev, max_olap, min_olap, eps, eig_time, ham_time, lu_time, steps});
}

void tools::finite::opt::internal::reports::krylov_add_entry(const opt_mps &mps) {
    if(tools::log->level() > spdlog::level::debug) return;
    std::string description = fmt::format("{:<8} {:<24}", "krylov", mps.get_name());
    krylov_log.push_back(krylov_entry{description, mps.get_krylov_ritz(), mps.get_tensor().size(), mps.get_krylov_nev(), mps.get_krylov_ncv(), mps.get_energy_per_site(), mps.get_krylov_eigval(),
                                      mps.get_variance(), mps.get_overlap(), mps.get_norm(),mps.get_krylov_tol(), mps.get_iter(), mps.get_counter(), mps.get_time()});
}
<commit_msg>Add ritz to krylov report<commit_after>
#include <general/nmspc_iter.h>
#include <tools/common/log.h>
#include <tools/common/prof.h>
#include <tools/finite/opt-internal/report.h>
#include <tools/finite/opt_mps.h>

/* clang-format off */
void tools::finite::opt::internal::reports::print_bfgs_report(){
    if (tools::log->level() > spdlog::level::debug) return;
    if (bfgs_log.empty()) return;
    std::string format_hdr = "{:<52} {:<7} {:<7} {:<20} {:<12} {:<18} {:<18} {:<5} {:<7} {:<8} {:<8} {:<18} {:<18}";
    std::string format_num = "- {:<50} {:<7} {:<7} {:<20.15f} {:<12.8f} {:<18.15f} {:<18.15f} {:<5} {:<7} {:<8.2e} {:<8.2e} {:<18.3f} {:<18.3f}";
    tools::log->debug(format_hdr.c_str(),
                      "Optimization report",
                      "size",
                      "space",
                      "energy/L",
                      "log₁₀ var", // Special characters are counted properly in fmt 1.7.0
                      "overlap",
                      "norm",
                      "iter",
                      "counter",
                      "|Δf|",
                      "|∇f|∞",
                      "Elapsed time [ms]",
                      "Time per count [ms]");

    for(auto &entry : bfgs_log){
        tools::log->debug(format_num.c_str(),
        entry.description, entry.size,
        entry.space, entry.energy,
        std::log10(entry.variance),
        entry.overlap,entry.norm,
        entry.iter, entry.counter,
        entry.delta_f, entry.grad_max_norm,
        entry.time*1000,
        entry.time*1000.0/std::max(1.0,static_cast<double>(entry.counter)));
    }
    bfgs_log.clear();
}

void tools::finite::opt::internal::reports::print_eigs_report(){
    if (tools::log->level() > spdlog::level::debug) return;
    if (eigs_log.empty()) return;
    std::string format_hdr = "- {:<5} {:<20} {:<20} {:<20} {:<12} {:<12} {:<12} {:<6}";
    std::string format_num = "- {:<5} {:<20.15f} {:<20.15f} {:<20.8f} {:<12.3f} {:<12.3f} {:<12.3f} {:<6}";
    tools::log->debug(format_hdr.c_str(),
                       "nev",
                       "max <θ_i|θ>",
                       "min <θ_i|θ>",
                       "log₁₀(1-Σ|<θ_i|θ>|²)",  // Special characters are counted properly in fmt 1.7.0
                       "Eig Time[ms]",
                       "Ham Time[ms]",
                       "LU Time[ms]",
                       "Steps" );

    for(auto &entry : eigs_log){
        tools::log->debug(format_num.c_str(),
                          entry.nev,
                          entry.max_olap,
                          entry.min_olap,
                          entry.eps ,
                          entry.eig_time * 1000,
                          entry.ham_time * 1000,
                          entry.lu_time  * 1000,
                          entry.steps
                            );
    }
    eigs_log.clear();
}

void tools::finite::opt::internal::reports::print_time_report(){
    if (tools::log->level() > spdlog::level::trace) return;
    if(time_log.empty()) return;
    std::string format_hdr = "LBFGS Time report [ms] {:<10} {:<10} {:<10} {:<10} {:<10} {:<10} {:<10}";
    std::string format_num = "                       {:<10.3f} {:<10.3f} {:<10.3f} {:<10.3f} {:<10.3f} {:<10.3f} {:<10.3f}";
    tools::log->trace(format_hdr.c_str(),
                      "<ψ|H²|ψ>",
                      "<ψ|H|ψ>",
                      "H²|ψ>",
                      "H|ψ>",
                      "sum",
                      "step",
                      "l-bfgs");
    for(auto &entry : time_log){
    tools::log->trace(format_num.c_str(),
                     1000 * entry.vH2v,
                     1000 * entry.vHv,
                     1000 * entry.vH2,
                     1000 * entry.vH,
                     1000 *(entry.vH2v
                          + entry.vHv
                          + entry.vH2
                          + entry.vH),
                     1000 * entry.step,
                     1000 * entry.bfgs);
    }
    time_log.clear();
}

void tools::finite::opt::internal::reports::print_krylov_report(std::optional<size_t> max_entries){
    if (tools::log->level() > spdlog::level::debug) return;
    if (krylov_log.empty()) return;
    std::string format_hdr = "{:<52} {:<7} {:<4} {:<4} {:<4} {:<8} {:<22} {:<22} {:<12} {:<18} {:<18} {:<5} {:<7} {:<18} {:<18}";
    std::string format_num = "- {:<50} {:<7} {:<4} {:<4} {:<4} {:<8.2e} {:<22.15f} {:<22.15f} {:<12.8f} {:<18.15f} {:<18.15f} {:<5} {:<7} {:<18.3f} {:<18.3f}";
    tools::log->debug(format_hdr.c_str(),
                      "Optimization report",
                      "size",
                      "ritz"
                      "nev",
                      "ncv",
                      "tol",
                      "energy/L",
                      "eigval",
                      "log₁₀ var", // Special characters are counted properly in fmt 1.7.0
                      "overlap",
                      "norm",
                      "iter",
                      "counter",
                      "Elapsed time [ms]",
                      "Time per count [ms]");

    for(const auto &[idx,entry] : iter::enumerate(krylov_log)){
        if(max_entries and max_entries.value() <= idx) break;
        tools::log->debug(format_num.c_str(),
                          entry.description,
                          entry.size, entry.ritz,entry.nev, entry.ncv, entry.tol,
                          entry.energy,entry.eigval,
                          std::log10(entry.variance),
                          entry.overlap,entry.norm,
                          entry.iter, entry.counter,
                          entry.time*1000,
                          entry.time*1000.0/std::max(1.0,static_cast<double>(entry.counter)));
    }
    krylov_log.clear();
}

/* clang-format on */
void tools::finite::opt::internal::reports::bfgs_add_entry(const std::string &description, long size, long space, double energy, double variance,
                                                           double overlap, double norm, double delta_f, double grad_norm, size_t iter, size_t counter,
                                                           double time) {
    if(tools::log->level() > spdlog::level::debug) return;
    bfgs_log.push_back({description, size, space, energy, variance, overlap, norm, delta_f, grad_norm, iter, counter, time});
}
void tools::finite::opt::internal::reports::bfgs_add_entry(const std::string &mode, const std::string &tag, const opt_mps &mps, std::optional<long> space) {
    if(tools::log->level() > spdlog::level::debug) return;
    if(not space) space = mps.get_tensor().size();
    std::string description = fmt::format("{:<8} {:<16} {}", mode, mps.get_name(), tag);
    bfgs_log.push_back(bfgs_entry{description, mps.get_tensor().size(), space.value(), mps.get_energy_per_site(), mps.get_variance(), mps.get_overlap(),
                                  mps.get_norm(), mps.get_delta_f(), mps.get_grad_norm(), mps.get_iter(), mps.get_counter(), mps.get_time()});
}

void tools::finite::opt::internal::reports::time_add_dir_entry() {
    if(tools::log->level() > spdlog::level::trace) return;
    time_log.push_back({tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_vH2v"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_vHv"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_vH2"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_vH"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_bfgs"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_dir_step"]->get_last_interval()});
}
void tools::finite::opt::internal::reports::time_add_sub_entry() {
    if(tools::log->level() > spdlog::level::trace) return;
    time_log.push_back({tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_vH2v"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_vHv"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_vH2"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_vH"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_bfgs"]->get_last_interval(),
                        tools::common::profile::prof[AlgorithmType::xDMRG]["t_opt_sub_step"]->get_last_interval()});
}
void tools::finite::opt::internal::reports::eigs_add_entry(long nev, double max_olap, double min_olap, double eps, double eig_time, double ham_time,
                                                           double lu_time, size_t steps) {
    if(tools::log->level() > spdlog::level::debug) return;
    eigs_log.push_back({nev, max_olap, min_olap, eps, eig_time, ham_time, lu_time, steps});
}

void tools::finite::opt::internal::reports::krylov_add_entry(const opt_mps &mps) {
    if(tools::log->level() > spdlog::level::debug) return;
    std::string description = fmt::format("{:<8} {:<24}", "krylov", mps.get_name());
    krylov_log.push_back(krylov_entry{description, mps.get_krylov_ritz(), mps.get_tensor().size(), mps.get_krylov_nev(), mps.get_krylov_ncv(), mps.get_energy_per_site(), mps.get_krylov_eigval(),
                                      mps.get_variance(), mps.get_overlap(), mps.get_norm(),mps.get_krylov_tol(), mps.get_iter(), mps.get_counter(), mps.get_time()});
}
<|endoftext|>


<commit_before>#include <powerset.hpp>

#include "helpers.hpp"

#include <vector>
#include <string>
#include <iterator>

#include "catch.hpp"

using iter::powerset;
using IntPermSet = std::multiset<std::multiset<int>>;

TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") {
  const std::vector<int> ns = {1, 2, 3};
  IntPermSet v;
  SECTION("Normal call") {
    for (auto&& st : powerset(ns)) {
      v.emplace(std::begin(st), std::end(st));
    }
  }
  SECTION("Pipe") {
    for (auto&& st : ns | powerset) {
      v.emplace(std::begin(st), std::end(st));
    }
  }

  const IntPermSet vc = {
    std::multiset<int>{}, {1}, {2}, {3},
      {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}};
  REQUIRE(v == vc);
}

TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") {
  const std::vector<int> ns = {};
  auto ps = powerset(ns);
  auto it = std::begin(ps);
  REQUIRE(std::begin(*it) == std::end(*it));  // it's empty
  ++it;
  REQUIRE(it == std::end(ps));
}

TEST_CASE("powerset: iterators can be compared", "[powerset]") {
  std::vector<int> ns = {1, 2};
  auto p = powerset(ns);
  {
    auto it = std::begin(p);
    REQUIRE(it == std::begin(p));
    REQUIRE_FALSE(it != std::begin(p));
    REQUIRE(it != std::end(p));
    REQUIRE_FALSE(it == std::end(p));
    ++it;
    REQUIRE_FALSE(it == std::begin(p));
    REQUIRE(it != std::begin(p));
    REQUIRE_FALSE(it == std::end(p));
    REQUIRE(it != std::end(p));
    ++it;
    ++it;
    ++it;
    REQUIRE(it == std::end(p));
  }

  ns.push_back(3);
  {
    auto it = std::begin(p);
    auto it2 = std::begin(p);
    std::advance(it, 4);
    std::advance(it2, 4);
    REQUIRE(it == it2);
    ++it2;
    REQUIRE(it != it2);
  }
}

TEST_CASE("powerset: iterator copy ctor is correct", "[powerset]") {
  // { {}, {1}, {2}, {1, 2} }
  std::vector<int> ns = {1, 2};
  auto p = powerset(ns);
  auto it = std::begin(p);
  auto it2(it);
  REQUIRE(it == it2);
  ++it2;
  REQUIRE(it != it2);
  REQUIRE(std::begin(*it) == std::end(*it));
}

TEST_CASE("powerset: binds to lvalues, moves rvalues", "[powerset]") {
  itertest::BasicIterable<int> bi{1, 2};
  SECTION("binds to lvalues") {
    powerset(bi);
    REQUIRE_FALSE(bi.was_moved_from());
  }
  SECTION("moves rvalues") {
    powerset(std::move(bi));
    REQUIRE(bi.was_moved_from());
  }
}

TEST_CASE("powerset: doesn't move or copy elements of iterable", "[powerset]") {
  constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}};
  for (auto&& st : powerset(arr)) {
    for (auto&& i : st) {
      (void)i;
    }
  }
}

TEST_CASE("powerset: iterator meets requirements", "[powerset]") {
  std::string s{"abc"};
  auto c = powerset(s);
  REQUIRE(itertest::IsIterator<decltype(std::begin(c))>::value);
  auto&& row = *std::begin(c);
  REQUIRE(itertest::IsIterator<decltype(std::begin(row))>::value);
}

template <typename T>
using ImpT = decltype(powerset(std::declval<T>()));
TEST_CASE("powerset: has correct ctor and assign ops", "[powerset]") {
  REQUIRE(itertest::IsMoveConstructibleOnly<ImpT<std::string&>>::value);
  REQUIRE(itertest::IsMoveConstructibleOnly<ImpT<std::string>>::value);
}
<commit_msg>Tests powerset with different begin and end<commit_after>#include <powerset.hpp>

#define CHAR_RANGE_DEFAULT_CONSTRUCTIBLE
#include "helpers.hpp"
#undef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE

#include <vector>
#include <string>
#include <iterator>

#include "catch.hpp"

using iter::powerset;
using IntPermSet = std::multiset<std::multiset<int>>;

TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") {
  const std::vector<int> ns = {1, 2, 3};
  IntPermSet v;
  SECTION("Normal call") {
    for (auto&& st : powerset(ns)) {
      v.emplace(std::begin(st), std::end(st));
    }
  }
  SECTION("Pipe") {
    for (auto&& st : ns | powerset) {
      v.emplace(std::begin(st), std::end(st));
    }
  }

  const IntPermSet vc = {
    std::multiset<int>{}, {1}, {2}, {3},
      {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}};
  REQUIRE(v == vc);
}

TEST_CASE("powerset: Works with different begin and end types",
    "[powerset]") {
  CharRange cr{'d'};
  using CharPermSet = std::multiset<std::vector<char>>;
  CharPermSet sc;
  for (auto&& v : powerset(cr)) {
    sc.emplace(std::begin(v), std::end(v));
  }
  const CharPermSet ans = {
    {},
    {'a'}, {'b'}, {'c'},
    {'a', 'b'}, {'a', 'c'}, {'b', 'c'},
    {'a', 'b', 'c'}};

  REQUIRE(ans == sc);
}

TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") {
  const std::vector<int> ns = {};
  auto ps = powerset(ns);
  auto it = std::begin(ps);
  REQUIRE(std::begin(*it) == std::end(*it));  // it's empty
  ++it;
  REQUIRE(it == std::end(ps));
}

TEST_CASE("powerset: iterators can be compared", "[powerset]") {
  std::vector<int> ns = {1, 2};
  auto p = powerset(ns);
  {
    auto it = std::begin(p);
    REQUIRE(it == std::begin(p));
    REQUIRE_FALSE(it != std::begin(p));
    REQUIRE(it != std::end(p));
    REQUIRE_FALSE(it == std::end(p));
    ++it;
    REQUIRE_FALSE(it == std::begin(p));
    REQUIRE(it != std::begin(p));
    REQUIRE_FALSE(it == std::end(p));
    REQUIRE(it != std::end(p));
    ++it;
    ++it;
    ++it;
    REQUIRE(it == std::end(p));
  }

  ns.push_back(3);
  {
    auto it = std::begin(p);
    auto it2 = std::begin(p);
    std::advance(it, 4);
    std::advance(it2, 4);
    REQUIRE(it == it2);
    ++it2;
    REQUIRE(it != it2);
  }
}

TEST_CASE("powerset: iterator copy ctor is correct", "[powerset]") {
  // { {}, {1}, {2}, {1, 2} }
  std::vector<int> ns = {1, 2};
  auto p = powerset(ns);
  auto it = std::begin(p);
  auto it2(it);
  REQUIRE(it == it2);
  ++it2;
  REQUIRE(it != it2);
  REQUIRE(std::begin(*it) == std::end(*it));
}

TEST_CASE("powerset: binds to lvalues, moves rvalues", "[powerset]") {
  itertest::BasicIterable<int> bi{1, 2};
  SECTION("binds to lvalues") {
    powerset(bi);
    REQUIRE_FALSE(bi.was_moved_from());
  }
  SECTION("moves rvalues") {
    powerset(std::move(bi));
    REQUIRE(bi.was_moved_from());
  }
}

TEST_CASE("powerset: doesn't move or copy elements of iterable", "[powerset]") {
  constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}};
  for (auto&& st : powerset(arr)) {
    for (auto&& i : st) {
      (void)i;
    }
  }
}

TEST_CASE("powerset: iterator meets requirements", "[powerset]") {
  std::string s{"abc"};
  auto c = powerset(s);
  REQUIRE(itertest::IsIterator<decltype(std::begin(c))>::value);
  auto&& row = *std::begin(c);
  REQUIRE(itertest::IsIterator<decltype(std::begin(row))>::value);
}

template <typename T>
using ImpT = decltype(powerset(std::declval<T>()));
TEST_CASE("powerset: has correct ctor and assign ops", "[powerset]") {
  REQUIRE(itertest::IsMoveConstructibleOnly<ImpT<std::string&>>::value);
  REQUIRE(itertest::IsMoveConstructibleOnly<ImpT<std::string>>::value);
}
<|endoftext|>


<commit_before>#pragma once

struct noncopyable {
    noncopyable() = default;
    noncopyable(const noncopyable&) = delete;
    noncopyable & operator=(const noncopyable&) = delete;
};
<commit_msg>Making noncopyable movable<commit_after>#pragma once

struct noncopyable {
    noncopyable() = default;
    noncopyable(noncopyable&&) = default;
    noncopyable& operator=(noncopyable&&) = default;

    noncopyable(const noncopyable&) = delete;
    noncopyable& operator=(const noncopyable&) = delete;
};
<|endoftext|>


<commit_before>//
// Copyright RIME Developers
// Distributed under the BSD License
//
// 2011-09-11 GONG Chen <chen.sst@gmail.com>
//
#include <rime/common.h>
#include <rime/composition.h>
#include <rime/context.h>
#include <rime/engine.h>
#include <rime/key_event.h>
#include <rime/key_table.h>
#include <rime/menu.h>
#include <rime/schema.h>
#include <rime/gear/selector.h>

namespace rime {

Selector::Selector(const Ticket& ticket) : Processor(ticket) {
}

ProcessResult Selector::ProcessKeyEvent(const KeyEvent& key_event) {
  if (key_event.release() || key_event.alt())
    return kNoop;
  Context* ctx = engine_->context();
  if (ctx->composition().empty())
    return kNoop;
  Segment& current_segment(ctx->composition().back());
  if (!current_segment.menu || current_segment.HasTag("raw"))
    return kNoop;
  int ch = key_event.keycode();
  if (ch == XK_Prior || ch == XK_KP_Prior) {
    PageUp(ctx);
    return kAccepted;
  }
  if (ch == XK_Next || ch == XK_KP_Next) {
    PageDown(ctx);
    return kAccepted;
  }
  if (ch == XK_Up || ch == XK_KP_Up) {
    if (ctx->get_option("_horizontal")) {
      PageUp(ctx);
    } else {
      CursorUp(ctx);
    }
    return kAccepted;
  }
  if (ch == XK_Down || ch == XK_KP_Down) {
    if (ctx->get_option("_horizontal")) {
      PageDown(ctx);
    } else {
      CursorDown(ctx);
    }
    return kAccepted;
  }
  if (ch == XK_Left || ch == XK_KP_Left) {
    if (!key_event.ctrl() &&
        !key_event.shift() &&
        ctx->caret_pos() == ctx->input().length() &&
        ctx->get_option("_horizontal") &&
        CursorUp(ctx)) {
      return kAccepted;
    }
    return kNoop;
  }
  if (ch == XK_Right || ch == XK_KP_Right) {
    if (!key_event.ctrl() &&
        !key_event.shift() &&
        ctx->caret_pos() == ctx->input().length() &&
        ctx->get_option("_horizontal")) {
      CursorDown(ctx);
      return kAccepted;
    }
    return kNoop;
  }
  if (ch == XK_Home || ch == XK_KP_Home) {
    return Home(ctx) ? kAccepted : kNoop;
  }
  if (ch == XK_End || ch == XK_KP_End) {
    return End(ctx) ? kAccepted : kNoop;
  }
  int index = -1;
  const string& select_keys(engine_->schema()->select_keys());
  if (!select_keys.empty() &&
      !key_event.ctrl() &&
      ch >= 0x20 && ch < 0x7f) {
    size_t pos = select_keys.find((char)ch);
    if (pos != string::npos) {
      index = static_cast<int>(pos);
    }
  }
  else if (ch >= XK_0 && ch <= XK_9)
    index = ((ch - XK_0) + 9) % 10;
  else if (ch >= XK_KP_0 && ch <= XK_KP_9)
    index = ((ch - XK_KP_0) + 9) % 10;
  if (index >= 0) {
    SelectCandidateAt(ctx, index);
    return kAccepted;
  }
  // not handled
  return kNoop;
}

bool Selector::PageUp(Context* ctx) {
  Composition& comp = ctx->composition();
  if (comp.empty())
    return false;
  int page_size = engine_->schema()->page_size();
  int selected_index = comp.back().selected_index;
  int index = selected_index < page_size ? 0 : selected_index - page_size;
  comp.back().selected_index = index;
  comp.back().tags.insert("paging");
  return true;
}

bool Selector::PageDown(Context* ctx) {
  Composition& comp = ctx->composition();
  if (comp.empty() || !comp.back().menu)
    return false;
  int page_size = engine_->schema()->page_size();
  int index = comp.back().selected_index + page_size;
  int page_start = (index / page_size) * page_size;
  int candidate_count = comp.back().menu->Prepare(page_start + page_size);
  if (candidate_count <= page_start) {
    bool page_down_cycle = engine_->schema()->page_down_cycle();
    if (page_down_cycle) {// Cycle back to page 1 if true
      index = 0;
    } else {
      return false;
    }
  } else if (index >= candidate_count) {
    index = candidate_count - 1;
  }
  comp.back().selected_index = index;
  comp.back().tags.insert("paging");
  return true;

}

bool Selector::CursorUp(Context* ctx) {
  Composition& comp = ctx->composition();
  if (comp.empty())
    return false;
  int index = comp.back().selected_index;
  if (index <= 0)
    return false;
  comp.back().selected_index = index - 1;
  comp.back().tags.insert("paging");
  return true;
}

bool Selector::CursorDown(Context* ctx) {
  Composition& comp = ctx->composition();
  if (comp.empty() || !comp.back().menu)
    return false;
  int index = comp.back().selected_index + 1;
  int candidate_count = comp.back().menu->Prepare(index + 1);
  if (candidate_count <= index)
    return false;
  comp.back().selected_index = index;
  comp.back().tags.insert("paging");
  return true;
}

bool Selector::Home(Context* ctx) {
  if (ctx->composition().empty())
    return false;
  Segment& seg(ctx->composition().back());
  if (seg.selected_index > 0) {
    seg.selected_index = 0;
    return true;
  }
  return false;
}

bool Selector::End(Context* ctx) {
  if (ctx->caret_pos() < ctx->input().length()) {
    // navigator should handle this
    return false;
  }
  // this is cool:
  return Home(ctx);
}

bool Selector::SelectCandidateAt(Context* ctx, int index) {
  Composition& comp = ctx->composition();
  if (comp.empty())
    return false;
  int page_size = engine_->schema()->page_size();
  if (index >= page_size)
    return false;
  int selected_index = comp.back().selected_index;
  int page_start = (selected_index / page_size) * page_size;
  return ctx->Select(page_start + index);
}

}  // namespace rime
<commit_msg>feat(selector): support vertical UI<commit_after>//
// Copyright RIME Developers
// Distributed under the BSD License
//
// 2011-09-11 GONG Chen <chen.sst@gmail.com>
//
#include <rime/common.h>
#include <rime/composition.h>
#include <rime/context.h>
#include <rime/engine.h>
#include <rime/key_event.h>
#include <rime/key_table.h>
#include <rime/menu.h>
#include <rime/schema.h>
#include <rime/gear/selector.h>

namespace rime {

Selector::Selector(const Ticket& ticket) : Processor(ticket) {
}

ProcessResult Selector::ProcessKeyEvent(const KeyEvent& key_event) {
  if (key_event.release() || key_event.alt())
    return kNoop;
  Context* ctx = engine_->context();
  if (ctx->composition().empty())
    return kNoop;
  Segment& current_segment(ctx->composition().back());
  if (!current_segment.menu || current_segment.HasTag("raw"))
    return kNoop;
  int ch = key_event.keycode();
  if (ch == XK_Prior || ch == XK_KP_Prior) {
    PageUp(ctx);
    return kAccepted;
  }
  if (ch == XK_Next || ch == XK_KP_Next) {
    PageDown(ctx);
    return kAccepted;
  }
  if (ch == XK_Up || ch == XK_KP_Up) {
    if (ctx->get_option("_horizontal")) {
      PageUp(ctx);
    } else {
      CursorUp(ctx);
    }
    return kAccepted;
  }
  if (ch == XK_Down || ch == XK_KP_Down) {
    if (ctx->get_option("_horizontal")) {
      PageDown(ctx);
    } else {
      CursorDown(ctx);
    }
    return kAccepted;
  }
  if (ch == XK_Left || ch == XK_KP_Left) {
    if (!key_event.ctrl() &&
        !key_event.shift() &&
        ctx->caret_pos() == ctx->input().length()) {
      if (ctx->get_option("_horizontal") &&
          CursorUp(ctx)) {
        return kAccepted;
      }
      if (ctx->get_option("_vertical")) {
        CursorDown(ctx);
        return kAccepted;
      }
    }
    return kNoop;
  }
  if (ch == XK_Right || ch == XK_KP_Right) {
    if (!key_event.ctrl() &&
        !key_event.shift() &&
        ctx->caret_pos() == ctx->input().length()) {
      if (ctx->get_option("_horizontal")) {
        CursorDown(ctx);
        return kAccepted;
      }
      if (ctx->get_option("_vertical") &&
          CursorUp(ctx)) {
        return kAccepted;
      }
    }
    return kNoop;
  }
  if (ch == XK_Home || ch == XK_KP_Home) {
    return Home(ctx) ? kAccepted : kNoop;
  }
  if (ch == XK_End || ch == XK_KP_End) {
    return End(ctx) ? kAccepted : kNoop;
  }
  int index = -1;
  const string& select_keys(engine_->schema()->select_keys());
  if (!select_keys.empty() &&
      !key_event.ctrl() &&
      ch >= 0x20 && ch < 0x7f) {
    size_t pos = select_keys.find((char)ch);
    if (pos != string::npos) {
      index = static_cast<int>(pos);
    }
  }
  else if (ch >= XK_0 && ch <= XK_9)
    index = ((ch - XK_0) + 9) % 10;
  else if (ch >= XK_KP_0 && ch <= XK_KP_9)
    index = ((ch - XK_KP_0) + 9) % 10;
  if (index >= 0) {
    SelectCandidateAt(ctx, index);
    return kAccepted;
  }
  // not handled
  return kNoop;
}

bool Selector::PageUp(Context* ctx) {
  Composition& comp = ctx->composition();
  if (comp.empty())
    return false;
  int page_size = engine_->schema()->page_size();
  int selected_index = comp.back().selected_index;
  int index = selected_index < page_size ? 0 : selected_index - page_size;
  comp.back().selected_index = index;
  comp.back().tags.insert("paging");
  return true;
}

bool Selector::PageDown(Context* ctx) {
  Composition& comp = ctx->composition();
  if (comp.empty() || !comp.back().menu)
    return false;
  int page_size = engine_->schema()->page_size();
  int index = comp.back().selected_index + page_size;
  int page_start = (index / page_size) * page_size;
  int candidate_count = comp.back().menu->Prepare(page_start + page_size);
  if (candidate_count <= page_start) {
    bool page_down_cycle = engine_->schema()->page_down_cycle();
    if (page_down_cycle) {// Cycle back to page 1 if true
      index = 0;
    } else {
      return false;
    }
  } else if (index >= candidate_count) {
    index = candidate_count - 1;
  }
  comp.back().selected_index = index;
  comp.back().tags.insert("paging");
  return true;

}

bool Selector::CursorUp(Context* ctx) {
  Composition& comp = ctx->composition();
  if (comp.empty())
    return false;
  int index = comp.back().selected_index;
  if (index <= 0)
    return false;
  comp.back().selected_index = index - 1;
  comp.back().tags.insert("paging");
  return true;
}

bool Selector::CursorDown(Context* ctx) {
  Composition& comp = ctx->composition();
  if (comp.empty() || !comp.back().menu)
    return false;
  int index = comp.back().selected_index + 1;
  int candidate_count = comp.back().menu->Prepare(index + 1);
  if (candidate_count <= index)
    return false;
  comp.back().selected_index = index;
  comp.back().tags.insert("paging");
  return true;
}

bool Selector::Home(Context* ctx) {
  if (ctx->composition().empty())
    return false;
  Segment& seg(ctx->composition().back());
  if (seg.selected_index > 0) {
    seg.selected_index = 0;
    return true;
  }
  return false;
}

bool Selector::End(Context* ctx) {
  if (ctx->caret_pos() < ctx->input().length()) {
    // navigator should handle this
    return false;
  }
  // this is cool:
  return Home(ctx);
}

bool Selector::SelectCandidateAt(Context* ctx, int index) {
  Composition& comp = ctx->composition();
  if (comp.empty())
    return false;
  int page_size = engine_->schema()->page_size();
  if (index >= page_size)
    return false;
  int selected_index = comp.back().selected_index;
  int page_start = (selected_index / page_size) * page_size;
  return ctx->Select(page_start + index);
}

}  // namespace rime
<|endoftext|>


<commit_before>/*
 * MarketControl.cpp
 *
 *  Created on: Jun 11, 2017
 *      Author: ondra
 */

#include "marketControl.h"

#include <couchit/couchDB.h>
#include <couchit/exception.h>
#include <couchit/query.h>
#include <imtjson/rpc.h>
#include "../common/config.h"

namespace quark {

MarketControl::MarketControl(Value cfg, StrViewA dbname)
	:ordersDb(initCouchDBConfig(cfg,dbname,"-orders"))
	,tradesDb(initCouchDBConfig(cfg,dbname,"-trades"))
	,posDb(initCouchDBConfig(cfg,dbname,"-positions"))
	,orderControl(ordersDb)
{

}

static void notImpl(RpcRequest req) {
	req.setError(501,"Not implemented yet!");
}

bool MarketControl::testDatabase() {
	CouchDB::PConnection conn = ordersDb.getConnection("");
	try {
		ordersDb.requestGET(conn,nullptr,0);
		return true;
	} catch (const couchit::RequestError &e) {
		if (e.getCode() == 404) return false;
		throw;
	}
}

Value MarketControl::getMarketStatus()  {

	Value err = ordersDb.get("error",CouchDB::flgNullIfMissing);
	if (err == nullptr) {
		return Object("marketStatus","ok");
	} else {
		return Object("marketStatus","stopped")
				("reason",err);
	}

}

Value MarketControl::initRpc(RpcServer& rpcServer) {

	PMarketControl me = this;
	rpcServer.add("Order.create", me, &MarketControl::rpcOrderCreate);
	rpcServer.add("Order.modify", me, &MarketControl::rpcOrderUpdate);
	rpcServer.add("Order.cancel", me, &MarketControl::rpcOrderCancel);
	rpcServer.add("Order.get", me, &MarketControl::rpcOrderGet);
	rpcServer.add("Stream.orders",  me, &MarketControl::rpcStreamOrders);
	rpcServer.add("Stream.trades", me, &MarketControl::rpcStreamTrades);
	rpcServer.add("Stream.orderbook", me, &MarketControl::rpcStreamOrderbook);
	rpcServer.add("Stream.positions", me, &MarketControl::rpcStreamPositions);
	rpcServer.add("Stream.lastId", me, &MarketControl::rpcStreamLastId);
	rpcServer.add("Status.get", me, &MarketControl::rpcStatusGet);
	rpcServer.add("Status.clear", me, &MarketControl::rpcStatusClear);
	rpcServer.add("Orderbook.get",me, &MarketControl::rpcOrderbookGet);

	return getMarketStatus();

}

void MarketControl::rpcOrderCreate(RpcRequest rq) {
	static Value chkargs (json::array,{Object("%","any")});
	if (!rq.checkArgs(chkargs)) return rq.setArgError();
	Value args = rq.getArgs();
	try {
		rq.setResult(orderControl.create(args[0]));
	} catch (ValidatonError &e) {
		rq.setError(400,"Validation failed", e.getError());
	}
}

void MarketControl::rpcOrderUpdate(RpcRequest rq) {
	static Value chkargs1 = {"string",Object("%","any")};
	static Value chkargs2 = {"string",Object("%","any"), "string"};
	Value args = rq.getArgs();
	try {
		if (rq.checkArgs(chkargs1)) {
			rq.setResult(orderControl.modify(args[0],args[1],json::undefined));
		} else if (rq.checkArgs(chkargs2)) {
			rq.setResult(orderControl.modify(args[0],args[1],args[2]));
		} else {
			rq.setArgError();
		}
	} catch (ValidatonError &e) {
		rq.setError(400,"Validation failed", e.getError());
	} catch (OrderNotFoundError &e) {
		rq.setError(404,"Order not found");
	} catch (ConflictError &e) {
		rq.setError(409,"Conflict",e.getActualDoc());
	}
}

void MarketControl::rpcOrderCancel(RpcRequest rq) {
	static Value chkargs (json::array,{"string"});
	if (!rq.checkArgs(chkargs)) return rq.setArgError();
	Value args = rq.getArgs();
	try {
		rq.setResult(orderControl.cancel(args[0]));
	} catch (OrderNotFoundError &e) {
		rq.setError(404,"Order not found");
	}
}

void MarketControl::rpcOrderGet(RpcRequest rq) {
	static Value chkargs (json::array,{"string"});
	if (!rq.checkArgs(chkargs)) return rq.setArgError();
	Value args = rq.getArgs();
	try {
		rq.setResult(orderControl.getOrder(args[0]));
	} catch (const couchit::RequestError &e) {
		rq.setError(404,"Order not found");
	}
}

class MarketControl::BasicFeed: public FeedControl {
public:
	BasicFeed(couchit::CouchDB &db,
			  Value since,
			  RpcRequest rq,
			  String streamName)
				:FeedControl(db,since),rq(rq),streamName(streamName) {

	}
	virtual void init() override {
	}
	~BasicFeed() {
		stop();
	}

protected:
	RpcRequest rq;
	String streamName;
};

class MarketControl::OrderFeed: public BasicFeed {
public:
	using BasicFeed::BasicFeed;
	virtual void init() override {
		static couchit::View initView("_design/index/_view/queue",couchit::View::includeDocs|couchit::View::update);
		initialView = &initView;
		feed.setFilter(couchit::Filter("index/stream",couchit::Filter::includeDocs));
	}
	virtual void onEvent(Value seqNum, Value doc) override {
		rq.sendNotify(streamName,{seqNum.toString(),
				Object(doc)
				("id",doc["_id"])
				("_id",undefined)});
	}

};

class MarketControl::TradesFeed: public BasicFeed {
public:
	using BasicFeed::BasicFeed;
	virtual void init() override {
		feed.setFilter(couchit::Filter("trades/stream",couchit::Filter::includeDocs));
	}
	virtual void onEvent(Value seqNum, Value doc) override {
		rq.sendNotify(streamName,{seqNum.toString(),
				Object(doc)
				("id",doc["_id"])
				("_id",undefined)
				("_rev",undefined)
		});
	}

};

class MarketControl::PosFeed: public BasicFeed {
public:
	using BasicFeed::BasicFeed;
	virtual void init() override {
		feed.setFilter(couchit::Filter("positions/stream",couchit::Filter::includeDocs));
	}
	virtual void onEvent(Value seqNum, Value doc) override {
		rq.sendNotify(streamName,{seqNum.toString(),
				Object(doc)
				("user",doc["_id"].getString().substr(2))
				("_id",undefined)
				("_rev",undefined)
		});
	}
};

class MarketControl::OrderbookFeed: public BasicFeed {
public:
	using BasicFeed::BasicFeed;
	virtual void init() override {
		static couchit::View initView("_design/index/_view/orderbook",couchit::View::includeDocs|couchit::View::update);
		this->initialView = &initView;
		feed.setFilter(couchit::Filter("index/orders",couchit::Filter::includeDocs));
	}
	virtual void onEvent(Value seqNum, Value doc) override {
		sendNotify(rq, streamName, doc, seqNum.toString());
	}
	static void sendNotify(RpcRequest &rq, StrViewA streamName, Value doc, Value seq) {
		Object ntf;
		bool finished = doc["finished"].getBool();
		rq.sendNotify(streamName,{seq,{doc["_id"],doc["dir"],doc["limitPrice"],finished?Value(0):doc["size"]}});
	}

};

void MarketControl::rpcStreamOrders(RpcRequest rq) {
	static Value turnOffArgs = Value(json::array,{false});
	static Value turnOnArgs = {true,{"string","optional"} };
	if (rq.checkArgs(turnOffArgs)) {

		ordersFeed = nullptr;
		rq.setResult(true);

	} else if (rq.checkArgs(turnOnArgs)) {
		Value since = rq.getArgs()[1];
		ordersFeed = new OrderFeed(ordersDb, since, rq, "order");
		ordersFeed->start();
		rq.setResult(true);

	} else {
		rq.setArgError();
	}
}

void MarketControl::rpcStreamTrades(RpcRequest rq) {
	static Value turnOffArgs = Value(json::array,{false});
	static Value turnOnArgs = {true,{"string","optional"} };
	if (rq.checkArgs(turnOffArgs)) {

		tradesFeed = nullptr;
		rq.setResult(true);

	} else if (rq.checkArgs(turnOnArgs)) {
		Value since = rq.getArgs()[1];
		tradesFeed = new TradesFeed(tradesDb, since, rq, "trade");
		tradesFeed->start();
		rq.setResult(true);

	} else {
		rq.setArgError();
	}
}

void MarketControl::rpcStreamPositions(RpcRequest rq) {
	static Value turnOffArgs = Value(json::array,{false});
	static Value turnOnArgs = {true,{"string","optional"} };
	if (rq.checkArgs(turnOffArgs)) {

		posFeed = nullptr;
		rq.setResult(true);

	} else if (rq.checkArgs(turnOnArgs)) {
		Value since = rq.getArgs()[1];
		posFeed = new PosFeed(posDb, since, rq, "position");
		posFeed->start();
		rq.setResult(true);

	} else {
		rq.setArgError();
	}
}

void MarketControl::rpcStreamOrderbook(RpcRequest rq) {
	static Value turnOffArgs = Value(json::array,{false});
	static Value turnOnArgs = {true,{"string","optional"} };
	if (rq.checkArgs(turnOffArgs)) {

		orderbookFeed = nullptr;
		rq.setResult(true);

	} else if (rq.checkArgs(turnOnArgs)) {
		Value since = rq.getArgs()[1];
		orderbookFeed = new OrderbookFeed(ordersDb, since, rq, "orderbook");
		orderbookFeed->start();
		rq.setResult(true);
	} else {
		rq.setArgError();
	}
}

void MarketControl::FeedControl::stop() {

	if (!stopped) {
		feed.cancelWait();
		thr.join();
		stopped = true;
	}
}

void MarketControl::FeedControl::start() {
	bool initWait = false;
	using namespace couchit;
	std::condition_variable initWaitCond;
	std::mutex lock;

	thr = std::thread([&]{

		init();

		{
		std::unique_lock<std::mutex> _(lock);
		initWait = true;
		initWaitCond.notify_all();
		}

		Value lastDoc;
		if (!since.defined() && initialView != nullptr)
		{
			Query q = db.createQuery(*initialView);
			Result r = q.exec();
			for (Row rw : r) {
				onEvent(r.getUpdateSeq(),rw.doc);
				lastDoc = rw.doc;
			}
			since = r.getUpdateSeq();
		}

		if (since.defined())
			feed.since(since);
		try {
			feed >> [&](ChangedDoc x) {
				if (x.doc == lastDoc) return true;
				lastDoc = json::undefined;
				onEvent(x.seqId, x.doc);
				return true;
			};
		} catch (couchit::CanceledException &) {

		}
	});

	std::unique_lock<std::mutex> _(lock);
	initWaitCond.wait(_,[&]{return initWait;});
	stopped = false;
}

MarketControl::FeedControl::FeedControl(CouchDB& db, Value since)
	:feed(db.createChangesFeed()),  since(since), db(db), stopped(true)
{
	feed.setTimeout(-1);
	feed.includeDocs(true);
}

void MarketControl::rpcStreamLastId(RpcRequest rq) {
	if (!rq.checkArgs(json::array)) return rq.setArgError();

	rq.setResult(Object("orders",ordersDb.getLastSeqNumber())
					   ("trades",tradesDb.getLastSeqNumber())
					   ("positions",posDb.getLastSeqNumber())
			);

}

void quark::MarketControl::rpcStatusGet(RpcRequest rq) {
	rq.setResult(getMarketStatus());
}

void quark::MarketControl::rpcStatusClear(RpcRequest rq) {
	couchit::Document doc = ordersDb.get("error");
	doc.setDeleted();
	ordersDb.put(doc);
	rq.setResult(getMarketStatus());
}

void quark::MarketControl::rpcOrderbookGet(RpcRequest rq) {
	couchit::View orderbookView("_design/index/_view/orderbook",couchit::View::update);
	couchit::Result res = ordersDb.createQuery(orderbookView).exec();
	Array out;
	for (couchit::Row rw : res) {
		out.push_back({rw["id"],rw.key[0], rw.key[1], rw.value});
	}
	rq.setResult(out);
}

}

/* namespace quark */

<commit_msg>fix filter name<commit_after>/*
 * MarketControl.cpp
 *
 *  Created on: Jun 11, 2017
 *      Author: ondra
 */

#include "marketControl.h"

#include <couchit/couchDB.h>
#include <couchit/exception.h>
#include <couchit/query.h>
#include <imtjson/rpc.h>
#include "../common/config.h"

namespace quark {

MarketControl::MarketControl(Value cfg, StrViewA dbname)
	:ordersDb(initCouchDBConfig(cfg,dbname,"-orders"))
	,tradesDb(initCouchDBConfig(cfg,dbname,"-trades"))
	,posDb(initCouchDBConfig(cfg,dbname,"-positions"))
	,orderControl(ordersDb)
{

}

static void notImpl(RpcRequest req) {
	req.setError(501,"Not implemented yet!");
}

bool MarketControl::testDatabase() {
	CouchDB::PConnection conn = ordersDb.getConnection("");
	try {
		ordersDb.requestGET(conn,nullptr,0);
		return true;
	} catch (const couchit::RequestError &e) {
		if (e.getCode() == 404) return false;
		throw;
	}
}

Value MarketControl::getMarketStatus()  {

	Value err = ordersDb.get("error",CouchDB::flgNullIfMissing);
	if (err == nullptr) {
		return Object("marketStatus","ok");
	} else {
		return Object("marketStatus","stopped")
				("reason",err);
	}

}

Value MarketControl::initRpc(RpcServer& rpcServer) {

	PMarketControl me = this;
	rpcServer.add("Order.create", me, &MarketControl::rpcOrderCreate);
	rpcServer.add("Order.modify", me, &MarketControl::rpcOrderUpdate);
	rpcServer.add("Order.cancel", me, &MarketControl::rpcOrderCancel);
	rpcServer.add("Order.get", me, &MarketControl::rpcOrderGet);
	rpcServer.add("Stream.orders",  me, &MarketControl::rpcStreamOrders);
	rpcServer.add("Stream.trades", me, &MarketControl::rpcStreamTrades);
	rpcServer.add("Stream.orderbook", me, &MarketControl::rpcStreamOrderbook);
	rpcServer.add("Stream.positions", me, &MarketControl::rpcStreamPositions);
	rpcServer.add("Stream.lastId", me, &MarketControl::rpcStreamLastId);
	rpcServer.add("Status.get", me, &MarketControl::rpcStatusGet);
	rpcServer.add("Status.clear", me, &MarketControl::rpcStatusClear);
	rpcServer.add("Orderbook.get",me, &MarketControl::rpcOrderbookGet);

	return getMarketStatus();

}

void MarketControl::rpcOrderCreate(RpcRequest rq) {
	static Value chkargs (json::array,{Object("%","any")});
	if (!rq.checkArgs(chkargs)) return rq.setArgError();
	Value args = rq.getArgs();
	try {
		rq.setResult(orderControl.create(args[0]));
	} catch (ValidatonError &e) {
		rq.setError(400,"Validation failed", e.getError());
	}
}

void MarketControl::rpcOrderUpdate(RpcRequest rq) {
	static Value chkargs1 = {"string",Object("%","any")};
	static Value chkargs2 = {"string",Object("%","any"), "string"};
	Value args = rq.getArgs();
	try {
		if (rq.checkArgs(chkargs1)) {
			rq.setResult(orderControl.modify(args[0],args[1],json::undefined));
		} else if (rq.checkArgs(chkargs2)) {
			rq.setResult(orderControl.modify(args[0],args[1],args[2]));
		} else {
			rq.setArgError();
		}
	} catch (ValidatonError &e) {
		rq.setError(400,"Validation failed", e.getError());
	} catch (OrderNotFoundError &e) {
		rq.setError(404,"Order not found");
	} catch (ConflictError &e) {
		rq.setError(409,"Conflict",e.getActualDoc());
	}
}

void MarketControl::rpcOrderCancel(RpcRequest rq) {
	static Value chkargs (json::array,{"string"});
	if (!rq.checkArgs(chkargs)) return rq.setArgError();
	Value args = rq.getArgs();
	try {
		rq.setResult(orderControl.cancel(args[0]));
	} catch (OrderNotFoundError &e) {
		rq.setError(404,"Order not found");
	}
}

void MarketControl::rpcOrderGet(RpcRequest rq) {
	static Value chkargs (json::array,{"string"});
	if (!rq.checkArgs(chkargs)) return rq.setArgError();
	Value args = rq.getArgs();
	try {
		rq.setResult(orderControl.getOrder(args[0]));
	} catch (const couchit::RequestError &e) {
		rq.setError(404,"Order not found");
	}
}

class MarketControl::BasicFeed: public FeedControl {
public:
	BasicFeed(couchit::CouchDB &db,
			  Value since,
			  RpcRequest rq,
			  String streamName)
				:FeedControl(db,since),rq(rq),streamName(streamName) {

	}
	virtual void init() override {
	}
	~BasicFeed() {
		stop();
	}

protected:
	RpcRequest rq;
	String streamName;
};

class MarketControl::OrderFeed: public BasicFeed {
public:
	using BasicFeed::BasicFeed;
	virtual void init() override {
		static couchit::View initView("_design/index/_view/queue",couchit::View::includeDocs|couchit::View::update);
		initialView = &initView;
		feed.setFilter(couchit::Filter("index/stream",couchit::Filter::includeDocs));
	}
	virtual void onEvent(Value seqNum, Value doc) override {
		rq.sendNotify(streamName,{seqNum.toString(),
				Object(doc)
				("id",doc["_id"])
				("_id",undefined)});
	}

};

class MarketControl::TradesFeed: public BasicFeed {
public:
	using BasicFeed::BasicFeed;
	virtual void init() override {
		feed.setFilter(couchit::Filter("trades/stream",couchit::Filter::includeDocs));
	}
	virtual void onEvent(Value seqNum, Value doc) override {
		rq.sendNotify(streamName,{seqNum.toString(),
				Object(doc)
				("id",doc["_id"])
				("_id",undefined)
				("_rev",undefined)
		});
	}

};

class MarketControl::PosFeed: public BasicFeed {
public:
	using BasicFeed::BasicFeed;
	virtual void init() override {
		feed.setFilter(couchit::Filter("positions/stream",couchit::Filter::includeDocs));
	}
	virtual void onEvent(Value seqNum, Value doc) override {
		rq.sendNotify(streamName,{seqNum.toString(),
				Object(doc)
				("user",doc["_id"].getString().substr(2))
				("_id",undefined)
				("_rev",undefined)
		});
	}
};

class MarketControl::OrderbookFeed: public BasicFeed {
public:
	using BasicFeed::BasicFeed;
	virtual void init() override {
		static couchit::View initView("_design/index/_view/orderbook",couchit::View::includeDocs|couchit::View::update);
		this->initialView = &initView;
		feed.setFilter(couchit::Filter("index/orderbook",couchit::Filter::includeDocs));
	}
	virtual void onEvent(Value seqNum, Value doc) override {
		sendNotify(rq, streamName, doc, seqNum.toString());
	}
	static void sendNotify(RpcRequest &rq, StrViewA streamName, Value doc, Value seq) {
		Object ntf;
		bool finished = doc["finished"].getBool();
		rq.sendNotify(streamName,{seq,{doc["_id"],doc["dir"],doc["limitPrice"],finished?Value(0):doc["size"]}});
	}

};

void MarketControl::rpcStreamOrders(RpcRequest rq) {
	static Value turnOffArgs = Value(json::array,{false});
	static Value turnOnArgs = {true,{"string","optional"} };
	if (rq.checkArgs(turnOffArgs)) {

		ordersFeed = nullptr;
		rq.setResult(true);

	} else if (rq.checkArgs(turnOnArgs)) {
		Value since = rq.getArgs()[1];
		ordersFeed = new OrderFeed(ordersDb, since, rq, "order");
		ordersFeed->start();
		rq.setResult(true);

	} else {
		rq.setArgError();
	}
}

void MarketControl::rpcStreamTrades(RpcRequest rq) {
	static Value turnOffArgs = Value(json::array,{false});
	static Value turnOnArgs = {true,{"string","optional"} };
	if (rq.checkArgs(turnOffArgs)) {

		tradesFeed = nullptr;
		rq.setResult(true);

	} else if (rq.checkArgs(turnOnArgs)) {
		Value since = rq.getArgs()[1];
		tradesFeed = new TradesFeed(tradesDb, since, rq, "trade");
		tradesFeed->start();
		rq.setResult(true);

	} else {
		rq.setArgError();
	}
}

void MarketControl::rpcStreamPositions(RpcRequest rq) {
	static Value turnOffArgs = Value(json::array,{false});
	static Value turnOnArgs = {true,{"string","optional"} };
	if (rq.checkArgs(turnOffArgs)) {

		posFeed = nullptr;
		rq.setResult(true);

	} else if (rq.checkArgs(turnOnArgs)) {
		Value since = rq.getArgs()[1];
		posFeed = new PosFeed(posDb, since, rq, "position");
		posFeed->start();
		rq.setResult(true);

	} else {
		rq.setArgError();
	}
}

void MarketControl::rpcStreamOrderbook(RpcRequest rq) {
	static Value turnOffArgs = Value(json::array,{false});
	static Value turnOnArgs = {true,{"string","optional"} };
	if (rq.checkArgs(turnOffArgs)) {

		orderbookFeed = nullptr;
		rq.setResult(true);

	} else if (rq.checkArgs(turnOnArgs)) {
		Value since = rq.getArgs()[1];
		orderbookFeed = new OrderbookFeed(ordersDb, since, rq, "orderbook");
		orderbookFeed->start();
		rq.setResult(true);
	} else {
		rq.setArgError();
	}
}

void MarketControl::FeedControl::stop() {

	if (!stopped) {
		feed.cancelWait();
		thr.join();
		stopped = true;
	}
}

void MarketControl::FeedControl::start() {
	bool initWait = false;
	using namespace couchit;
	std::condition_variable initWaitCond;
	std::mutex lock;

	thr = std::thread([&]{

		init();

		{
		std::unique_lock<std::mutex> _(lock);
		initWait = true;
		initWaitCond.notify_all();
		}

		Value lastDoc;
		if (!since.defined() && initialView != nullptr)
		{
			Query q = db.createQuery(*initialView);
			Result r = q.exec();
			for (Row rw : r) {
				onEvent(r.getUpdateSeq(),rw.doc);
				lastDoc = rw.doc;
			}
			since = r.getUpdateSeq();
		}

		if (since.defined())
			feed.since(since);
		try {
			feed >> [&](ChangedDoc x) {
				if (x.doc == lastDoc) return true;
				lastDoc = json::undefined;
				onEvent(x.seqId, x.doc);
				return true;
			};
		} catch (couchit::CanceledException &) {

		}
	});

	std::unique_lock<std::mutex> _(lock);
	initWaitCond.wait(_,[&]{return initWait;});
	stopped = false;
}

MarketControl::FeedControl::FeedControl(CouchDB& db, Value since)
	:feed(db.createChangesFeed()),  since(since), db(db), stopped(true)
{
	feed.setTimeout(-1);
	feed.includeDocs(true);
}

void MarketControl::rpcStreamLastId(RpcRequest rq) {
	if (!rq.checkArgs(json::array)) return rq.setArgError();

	rq.setResult(Object("orders",ordersDb.getLastSeqNumber())
					   ("trades",tradesDb.getLastSeqNumber())
					   ("positions",posDb.getLastSeqNumber())
			);

}

void quark::MarketControl::rpcStatusGet(RpcRequest rq) {
	rq.setResult(getMarketStatus());
}

void quark::MarketControl::rpcStatusClear(RpcRequest rq) {
	couchit::Document doc = ordersDb.get("error");
	doc.setDeleted();
	ordersDb.put(doc);
	rq.setResult(getMarketStatus());
}

void quark::MarketControl::rpcOrderbookGet(RpcRequest rq) {
	couchit::View orderbookView("_design/index/_view/orderbook",couchit::View::update);
	couchit::Result res = ordersDb.createQuery(orderbookView).exec();
	Array out;
	for (couchit::Row rw : res) {
		out.push_back({rw["id"],rw.key[0], rw.key[1], rw.value});
	}
	rq.setResult(out);
}

}

/* namespace quark */

<|endoftext|>


<commit_before><commit_msg>Localization: update raw ptr to shared_ptr<commit_after><|endoftext|>


<commit_before>/*
 * ModSecurity, http://www.modsecurity.org/
 * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * 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
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address security@modsecurity.org.
 *
 */

#include "unit/unit_test.h"

#include <string.h>

#include <sstream>
#include <string>

#include "common/colors.h"
#include "src/utils.h"

namespace modsecurity_test {

std::string string_to_hex(const std::string& input) {
    static const char* const lut = "0123456789ABCDEF";
    size_t len = input.length();

    std::string output;
    output.reserve(2 * len);
    for (size_t i = 0; i < len; ++i) {
        const unsigned char c = input[i];
        output.push_back(lut[c >> 4]);
        output.push_back(lut[c & 15]);
    }
    return output;
}

void replaceAll(std::string *s, const std::string &search,
    const char replace) {
    for (size_t pos = 0; ; pos += 0) {
        pos = s->find(search, pos);
        if (pos == std::string::npos) {
            break;
        }
        s->erase(pos, search.length());
        s->insert(pos, &replace, 1);
    }
}

std::string UnitTest::print() {
    std::stringstream i;

    i << KRED << "Test failed." << RESET;
    i << " From: " << this->filename << std::endl;
    i << "{" << std::endl;
    i << "  \"ret\": \"" << this->ret << "\"" << std::endl;
    i << "  \"type\": \"" << this->type << "\"" << std::endl;
    i << "  \"name\": \"" << this->name << "\"" << std::endl;
    i << "  \"input\": \"" << this->input << "\"" << std::endl;
    i << "  \"param\": \"" << this->param << "\"" << std::endl;
    i << "  \"output\": \"" << this->output << "\"" << std::endl;
    i << "}" << std::endl;
    if (this->ret != this->obtained) {
        i << "Expecting: \"" << this->ret << "\" - returned: \"";
        i << this->obtained << "\"" << std::endl;
    }
    if (this->output != this->obtainedOutput) {
        i << "Expecting: \"" << modsecurity::toHexIfNeeded(this->output);
        i << "\" - returned: \"";
        i << modsecurity::toHexIfNeeded(this->obtainedOutput) << "\"";
        i << std::endl;
    }

    return i.str();
}

UnitTest *UnitTest::from_yajl_node(yajl_val &node) {
    size_t num_tests = node->u.object.len;
    UnitTest *u = new UnitTest();

    for (int i = 0; i < num_tests; i++) {
        const char *key = node->u.object.keys[ i ];
        yajl_val val = node->u.object.values[ i ];

        if (strcmp(key, "param") == 0) {
           u->param = YAJL_GET_STRING(val);
        } else if (strcmp(key, "input") == 0) {
           u->input = YAJL_GET_STRING(val);
           /*
            * Converting \\u0000 to \0 due to the following gcc bug:
            * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53690
            *
            */
           replaceAll(&(u->input), "\\0", '\0');
           replaceAll(&(u->input), "\\xe4", '\xe4');
           replaceAll(&(u->input), "\\x03", '\x03');
           replaceAll(&(u->input), "\\xbf", '\xbf');
           replaceAll(&(u->input), "\\xc9", '\xc9');
           replaceAll(&(u->input), "\\x3b", '\x3b');
           replaceAll(&(u->input), "\\xFF", '\xff');
           replaceAll(&(u->input), "\\u0000", '\0');
           replaceAll(&(u->input), "\\u0001", '\u0001');
           replaceAll(&(u->input), "\\u0002", '\u0002');
           replaceAll(&(u->input), "\\u0003", '\u0003');
           replaceAll(&(u->input), "\\u0004", '\u0004');
           replaceAll(&(u->input), "\\u0005", '\u0005');
           replaceAll(&(u->input), "\\u0006", '\u0006');
           replaceAll(&(u->input), "\\u0007", '\u0007');
           replaceAll(&(u->input), "\\b", '\b');
        } else if (strcmp(key, "name") == 0) {
           u->name = YAJL_GET_STRING(val);
        } else if (strcmp(key, "type") == 0) {
           u->type = YAJL_GET_STRING(val);
        } else if (strcmp(key, "ret") == 0) {
           u->ret = YAJL_GET_INTEGER(val);
        } else if (strcmp(key, "output") == 0) {
           u->output = std::string(YAJL_GET_STRING(val));
           /*
            * Converting \\u0000 to \0 due to the following gcc bug:
            * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53690
            *
            */
           // FIXME: Really? replace the hex chars in a smart fashion.
           replaceAll(&(u->output), "\\x00", '\0');
           replaceAll(&(u->output), "\\u0000", '\0');
           replaceAll(&(u->output), "\\xe4", '\xe4');
           replaceAll(&(u->output), "\\x03", '\x03');
           replaceAll(&(u->output), "\\x04", '\x04');
           replaceAll(&(u->output), "\\x07", '\x07');
           replaceAll(&(u->output), "\\x09", '\x09');
           replaceAll(&(u->output), "\\xbf", '\xbf');
           replaceAll(&(u->output), "\\xc9", '\xc9');
           replaceAll(&(u->output), "\\x3b", '\x3b');
           replaceAll(&(u->output), "\\xFF", '\xff');
           replaceAll(&(u->output), "\\0", '\0');
           replaceAll(&(u->output), "\\x90", '\x90');
           replaceAll(&(u->output), "\\x14", '\x14');
           replaceAll(&(u->output), "\\x82", '\x82');
           replaceAll(&(u->output), "\\x9a", '\x9a');
           replaceAll(&(u->output), "\\xbc", '\xbc');
           replaceAll(&(u->output), "\\xfe", '\xfe');
           replaceAll(&(u->output), "\\x89", '\x89');
           replaceAll(&(u->output), "\\xa0", '\xa0');
           replaceAll(&(u->output), "\\xa2", '\xa2');
           replaceAll(&(u->output), "\\xa6", '\xa6');
           replaceAll(&(u->output), "\\xab", '\xab');
           replaceAll(&(u->output), "\\xd4", '\xd4');
           replaceAll(&(u->output), "\\x1d", '\x1d');
           replaceAll(&(u->output), "\\x8c", '\x8c');
           replaceAll(&(u->output), "\\xd9", '\xd9');
           replaceAll(&(u->output), "\\x8f", '\x8f');
           replaceAll(&(u->output), "\\xb2", '\xb2');
           replaceAll(&(u->output), "\\xe9", '\xe9');
           replaceAll(&(u->output), "\\x9e", '\x9e');
           replaceAll(&(u->output), "\\x80", '\x80');
           replaceAll(&(u->output), "\\x98", '\x98');
           replaceAll(&(u->output), "\\xec", '\xec');
           replaceAll(&(u->output), "\\xf8", '\xf8');
           replaceAll(&(u->output), "\\xc1", '\xc1');
           replaceAll(&(u->output), "\\xc3", '\xc3');
           replaceAll(&(u->output), "\\x83", '\x83');
           replaceAll(&(u->output), "\\xaa", '\xaa');
           replaceAll(&(u->output), "\\xa5", '\xa5');
           replaceAll(&(u->output), "\\xb5", '\xb5');
           replaceAll(&(u->output), "\\xd1", '\xd1');
           replaceAll(&(u->output), "\\xde", '\xde');
           replaceAll(&(u->output), "\\xea", '\xea');
           replaceAll(&(u->output), "\\xe6", '\xe6');
           replaceAll(&(u->output), "\\xe7", '\xe7');
           replaceAll(&(u->output), "\\xd3", '\xd3');
           replaceAll(&(u->output), "\\xb4", '\xb4');
           replaceAll(&(u->output), "\\xdf", '\xdf');
           replaceAll(&(u->output), "\\xaf", '\xaf');
           replaceAll(&(u->output), "\\x01", '\x01');
           replaceAll(&(u->output), "\\x16", '\x16');
           replaceAll(&(u->output), "\\x0b", '\x0b');
           replaceAll(&(u->output), "\\x1f", '\x1f');
           replaceAll(&(u->output), "\\x83", '\x83');
           replaceAll(&(u->output), "\\xd2", '\xd2');
        }
    }

    return u;
}

}  // namespace modsecurity_test
<commit_msg>test: Using regexp to transform binary representation into binary blobs<commit_after>/*
 * ModSecurity, http://www.modsecurity.org/
 * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * 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
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address security@modsecurity.org.
 *
 */

#include "unit/unit_test.h"

#include <string.h>

#include <sstream>
#include <string>
#include <iostream>
#include <iterator>
#include <regex>
#include <string>

#include "common/colors.h"
#include "src/utils.h"

namespace modsecurity_test {

std::string string_to_hex(const std::string& input) {
    static const char* const lut = "0123456789ABCDEF";
    size_t len = input.length();

    std::string output;
    output.reserve(2 * len);
    for (size_t i = 0; i < len; ++i) {
        const unsigned char c = input[i];
        output.push_back(lut[c >> 4]);
        output.push_back(lut[c & 15]);
    }
    return output;
}

void replaceAll(std::string *s, const std::string &search,
    const char replace) {
    for (size_t pos = 0; ; pos += 0) {
        pos = s->find(search, pos);
        if (pos == std::string::npos) {
            break;
        }
        s->erase(pos, search.length());
        s->insert(pos, &replace, 1);
    }
}

std::string UnitTest::print() {
    std::stringstream i;

    i << KRED << "Test failed." << RESET;
    i << " From: " << this->filename << std::endl;
    i << "{" << std::endl;
    i << "  \"ret\": \"" << this->ret << "\"" << std::endl;
    i << "  \"type\": \"" << this->type << "\"" << std::endl;
    i << "  \"name\": \"" << this->name << "\"" << std::endl;
    i << "  \"input\": \"" << this->input << "\"" << std::endl;
    i << "  \"param\": \"" << this->param << "\"" << std::endl;
    i << "  \"output\": \"" << this->output << "\"" << std::endl;
    i << "}" << std::endl;
    if (this->ret != this->obtained) {
        i << "Expecting: \"" << this->ret << "\" - returned: \"";
        i << this->obtained << "\"" << std::endl;
    }
    if (this->output != this->obtainedOutput) {
        i << "Expecting: \"" << modsecurity::toHexIfNeeded(this->output);
        i << "\" - returned: \"";
        i << modsecurity::toHexIfNeeded(this->obtainedOutput) << "\"";
        i << std::endl;
    }

    return i.str();
}

UnitTest *UnitTest::from_yajl_node(yajl_val &node) {
    size_t num_tests = node->u.object.len;
    UnitTest *u = new UnitTest();

    for (int i = 0; i < num_tests; i++) {
        const char *key = node->u.object.keys[ i ];
        yajl_val val = node->u.object.values[ i ];

        if (strcmp(key, "param") == 0) {
           u->param = YAJL_GET_STRING(val);
        } else if (strcmp(key, "input") == 0) {
           u->input = YAJL_GET_STRING(val);
           /*
            * Converting \\u0000 to \0 due to the following gcc bug:
            * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53690
            *
            */
           replaceAll(&(u->input), "\\0", '\0');
           replaceAll(&(u->input), "\\xe4", '\xe4');
           replaceAll(&(u->input), "\\x03", '\x03');
           replaceAll(&(u->input), "\\xbf", '\xbf');
           replaceAll(&(u->input), "\\xc9", '\xc9');
           replaceAll(&(u->input), "\\x3b", '\x3b');
           replaceAll(&(u->input), "\\xFF", '\xff');
           replaceAll(&(u->input), "\\u0000", '\0');
           replaceAll(&(u->input), "\\u0001", '\u0001');
           replaceAll(&(u->input), "\\u0002", '\u0002');
           replaceAll(&(u->input), "\\u0003", '\u0003');
           replaceAll(&(u->input), "\\u0004", '\u0004');
           replaceAll(&(u->input), "\\u0005", '\u0005');
           replaceAll(&(u->input), "\\u0006", '\u0006');
           replaceAll(&(u->input), "\\u0007", '\u0007');
           replaceAll(&(u->input), "\\b", '\b');
        } else if (strcmp(key, "name") == 0) {
           u->name = YAJL_GET_STRING(val);
        } else if (strcmp(key, "type") == 0) {
           u->type = YAJL_GET_STRING(val);
        } else if (strcmp(key, "ret") == 0) {
           u->ret = YAJL_GET_INTEGER(val);
        } else if (strcmp(key, "output") == 0) {
           u->output = std::string(YAJL_GET_STRING(val));
           std::string *in = &u->output;
           /*
            * Converting \\u0000 to \0 due to the following gcc bug:
            * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53690
            *
            */
            std::regex re("\\\\x([a-z0-9A-Z]{2})");
            std::smatch match;
            while (std::regex_search(*in, match, re) && match.size() > 1) {
                unsigned int p;
                std::string toBeReplaced = match.str();
                toBeReplaced.erase(0, 2);
                sscanf(toBeReplaced.c_str(), "%x", &p);
                replaceAll(in, match.str(), p);
            }
           replaceAll(&(u->output), "\\u0000", '\0');
           replaceAll(&(u->output), "\\0", '\0');
        }
    }

    return u;
}

}  // namespace modsecurity_test
<|endoftext|>


<commit_before>#include "view/SceneView.h"

#include <OgreRoot.h>
#include <OgreViewport.h>
#include <OgreConfigFile.h>
#include <OgreEntity.h>
#include <OgreWindowEventUtilities.h>

SceneView::SceneView()
    : camera(NULL),
    sceneManager(NULL),
    renderWindow(NULL) {
}

SceneView::~SceneView(void) {
    Ogre::Root* root = Ogre::Root::getSingletonPtr();
    delete root;
}

bool SceneView::initialize(std::string resourceConfigPath, std::string pluginConfigPath) {
    Ogre::Root* root = new Ogre::Root(pluginConfigPath);

    this->loadResourceConfig(resourceConfigPath);
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    if(!root->restoreConfig() && !root->showConfigDialog()) {
        return false;
    }

    renderWindow = root->initialise(
        true, // auto-create the render window now
        "Rally Sport Racing Game");

    sceneManager = root->createSceneManager(Ogre::ST_GENERIC); // Todo: Research a good scene manager

    camera = this->addCamera("MainCamera");
    Ogre::Viewport* viewport = this->addViewport(camera);
    camera->setAspectRatio(Ogre::Real(viewport->getActualWidth()) / Ogre::Real(viewport->getActualHeight()));

    // TODO: Fix this to follow car...
    camera->setPosition(Ogre::Vector3(0, 0, 80));
    camera->lookAt(Ogre::Vector3(0, 0, -300));

    // TODO: Implement separate scene loading (how do we do with lights?)
    Ogre::Entity* ogreHead = sceneManager->createEntity("Head", "ogrehead.mesh");
    Ogre::SceneNode* headNode = sceneManager->getRootSceneNode()->createChildSceneNode();
    headNode->attachObject(ogreHead);
    sceneManager->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
    Ogre::Light* light = sceneManager->createLight("MainLight");
    light->setPosition(20, 80, 50);
}

Ogre::Viewport* SceneView::addViewport(Ogre::Camera* followedCamera) {
    Ogre::Viewport* viewport = renderWindow->addViewport(camera);
    viewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0));

    return viewport;
}

Ogre::Camera* SceneView::addCamera(Ogre::String cameraName) {
    // Setup camera to match viewport
    Ogre::Camera* camera = sceneManager->createCamera(cameraName);
    camera->setNearClipDistance(5);

    return camera;
}

void SceneView::loadResourceConfig(Ogre::String resourceConfigPath) {
    Ogre::ResourceGroupManager& resourceGroupManager = Ogre::ResourceGroupManager::getSingleton();

    Ogre::ConfigFile resourceConfig;
    resourceConfig.load(resourceConfigPath);

    for(Ogre::ConfigFile::SectionIterator sectionIterator = resourceConfig.getSectionIterator();
            sectionIterator.hasMoreElements();
            sectionIterator.moveNext()) {
        Ogre::ConfigFile::SettingsMultiMap* settings = sectionIterator.peekNextValue();

        // Now load all the resources for this resource group
        for(Ogre::ConfigFile::SettingsMultiMap::iterator resource = settings->begin();
                resource != settings->end();
                ++resource) {
            resourceGroupManager.addResourceLocation(
                resource->second, // filename of directory
                resource->first, // resource type
                sectionIterator.peekNextKey()); // resource group
        }
    }
}

bool SceneView::renderFrame() {
    Ogre::WindowEventUtilities::messagePump();

    if(renderWindow->isClosed())  {
        return false;
    } else {
        Ogre::Root& root = Ogre::Root::getSingleton();
        if(!root.renderOneFrame()) {
            return false;
        }
    }
    return true;
}
<commit_msg>Fixed potential bug where resources were loaded before a render context should have existed.<commit_after>#include "view/SceneView.h"

#include <OgreRoot.h>
#include <OgreViewport.h>
#include <OgreConfigFile.h>
#include <OgreEntity.h>
#include <OgreWindowEventUtilities.h>

SceneView::SceneView()
    : camera(NULL),
    sceneManager(NULL),
    renderWindow(NULL) {
}

SceneView::~SceneView(void) {
    Ogre::Root* root = Ogre::Root::getSingletonPtr();
    delete root;
}

bool SceneView::initialize(std::string resourceConfigPath, std::string pluginConfigPath) {
    Ogre::Root* root = new Ogre::Root(pluginConfigPath);

    this->loadResourceConfig(resourceConfigPath);
    // (The actual precaching is done below, once there is a render context)

    if(!root->restoreConfig() && !root->showConfigDialog()) {
        return false;
    }

    renderWindow = root->initialise(
        true, // auto-create the render window now
        "Rally Sport Racing Game");

    sceneManager = root->createSceneManager(Ogre::ST_GENERIC); // Todo: Research a good scene manager

    // This should be done after creating a scene manager, so that there is a render context (GL/D3D)
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    camera = this->addCamera("MainCamera");
    Ogre::Viewport* viewport = this->addViewport(camera);
    camera->setAspectRatio(Ogre::Real(viewport->getActualWidth()) / Ogre::Real(viewport->getActualHeight()));

    // TODO: Fix this to follow car...
    camera->setPosition(Ogre::Vector3(0, 0, 80));
    camera->lookAt(Ogre::Vector3(0, 0, -300));

    // TODO: Implement separate scene loading (how do we do with lights?)
    Ogre::Entity* ogreHead = sceneManager->createEntity("Head", "ogrehead.mesh");
    Ogre::SceneNode* headNode = sceneManager->getRootSceneNode()->createChildSceneNode();
    headNode->attachObject(ogreHead);
    sceneManager->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
    Ogre::Light* light = sceneManager->createLight("MainLight");
    light->setPosition(20, 80, 50);
}

Ogre::Viewport* SceneView::addViewport(Ogre::Camera* followedCamera) {
    Ogre::Viewport* viewport = renderWindow->addViewport(camera);
    viewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0));

    return viewport;
}

Ogre::Camera* SceneView::addCamera(Ogre::String cameraName) {
    // Setup camera to match viewport
    Ogre::Camera* camera = sceneManager->createCamera(cameraName);
    camera->setNearClipDistance(5);

    return camera;
}

void SceneView::loadResourceConfig(Ogre::String resourceConfigPath) {
    Ogre::ResourceGroupManager& resourceGroupManager = Ogre::ResourceGroupManager::getSingleton();

    Ogre::ConfigFile resourceConfig;
    resourceConfig.load(resourceConfigPath);

    for(Ogre::ConfigFile::SectionIterator sectionIterator = resourceConfig.getSectionIterator();
            sectionIterator.hasMoreElements();
            sectionIterator.moveNext()) {
        Ogre::ConfigFile::SettingsMultiMap* settings = sectionIterator.peekNextValue();

        // Now load all the resources for this resource group
        for(Ogre::ConfigFile::SettingsMultiMap::iterator resource = settings->begin();
                resource != settings->end();
                ++resource) {
            resourceGroupManager.addResourceLocation(
                resource->second, // filename of directory
                resource->first, // resource type
                sectionIterator.peekNextKey()); // resource group
        }
    }
}

bool SceneView::renderFrame() {
    Ogre::WindowEventUtilities::messagePump();

    if(renderWindow->isClosed())  {
        return false;
    } else {
        Ogre::Root& root = Ogre::Root::getSingleton();
        if(!root.renderOneFrame()) {
            return false;
        }
    }
    return true;
}
<|endoftext|>


<commit_before>#include "StateCollision.h"
#include "Graphics.h"
#include "input/Input.h"
#include "render/Text.h"

using WalrusRPG::Box;
using WalrusRPG::States::StateCollision;
using WalrusRPG::Utils::Rect;
using namespace WalrusRPG::Graphics;
using namespace WalrusRPG::Input;

namespace AABB
{
		// returns true if the boxes are colliding (velocities are not used)
	bool AABBCheck(Box b1, Box b2)
	{
	    return !(b1.x + b1.w <= b2.x || b1.x >= b2.x + b2.w || b1.y + b1.h <= b2.y || b1.y >= b2.y + b2.h);
	}

}

StateCollision::StateCollision()
:p(40, 40, 8, 8, 0, 0), target(p), map{0}, cam(0,0)
{
	srand(4);
	for (int i = 0; i < 10; ++i)
	{
		map[rand()%20][rand()%20] = 1;
		map[rand()%20][rand()%20] = 2;
		map[rand()%20][rand()%20] = 3;
		map[rand()%20][rand()%20] = 4;
		map[rand()%20][rand()%20] = 5;
	}
}

StateCollision::~StateCollision()
{

}

namespace
{
	bool tilemap_collision(char map[20][20], const Box&& object)
	{
		int left_tile = object.x / 16;
		int right_tile = (object.x+object.w-1) / 16;
		int top_tile = object.y / 16;
		int bottom_tile = (object.y + object.h-1) / 16;

		if(left_tile < 0) left_tile = 0;
		if(right_tile > 19) right_tile = 19;
		if(top_tile < 0) top_tile = 0;
		if(bottom_tile > 19) bottom_tile = 19;

		for(int i=left_tile; i<=right_tile; i++)
		{
		    for(int j=top_tile; j<=bottom_tile; j++)
		    {
		        char t = map[j][i];
		        if(t)
		        {
		        	if(t == 1 && AABB::AABBCheck(object, Box(16.*i, 16.*j, 16., 16., 0, 0)))
		            	return true;
		        	if(t == 2 && AABB::AABBCheck(object, Box(16.*i, 16.*j, 16., 8., 0, 0)))
		        		return true;
		        	if(t == 3 && AABB::AABBCheck(object, Box(16.*i, 16.*j+8, 16., 8., 0, 0)))
		        		return true;
		        	if(t == 4 && AABB::AABBCheck(object, Box(16.*i, 16.*j, 8., 16., 0, 0)))
		        		return true;
		        	if(t == 5 && AABB::AABBCheck(object, Box(16.*i+8, 16.*j, 8., 16., 0, 0)))
		        		return true;
		        }
		    }
		}
		return false;
	}
}

void StateCollision::update(unsigned dt)
{
	collided_top = false;
	collided_left = false;
	collided_bottom = false;
	collided_right = false;
	p.vx = 0;
	p.vy = 0;
	if(key_down(Key::K_LEFT))
		p.vx = -2. * dt;
	if(key_down(Key::K_RIGHT))
		p.vx = 2. * dt;
	if(key_down(Key::K_UP))
		p.vy = -2. * dt;
	if(key_down(Key::K_DOWN))
		p.vy = 2. * dt;

	float x_sigma = p.vx < 0. ? -1. : 1.;
	float vx = 0.;
	while(vx != p.vx)
	{
		float add = (std::fabs(vx + x_sigma) > std::fabs(p.vx)) ? (x_sigma * std::fabs(p.vx - vx)) : x_sigma;
		if(tilemap_collision(map, Box(p.x + vx + add, p.y, p.w, p.h, 0, 0)))
			break;
		vx += add;
	}
	p.x += vx;

	float y_sigma = p.vy < 0. ? -1. : 1.;
	float vy = 0;
	while(vy != p.vy)
	{
		float add = (std::fabs(vy + y_sigma) > std::fabs(p.vy)) ? (y_sigma * std::fabs(p.vy - vy)) : y_sigma;
		if(tilemap_collision(map, Box(p.x, p.y + vy + add, p.w, p.h, 0, 0)))
			break;
		vy += add;
	}
	p.y += vy;

	cam.set_center_x(p.x + p.w/2);
	cam.set_center_y(p.y + p.h/2);
}

void StateCollision::render(unsigned dt)
{
	fill(Black);
	Pixel a(Red);

	put_rectangle({static_cast<signed>(p.x)-cam.get_x(), static_cast<signed>(p.y)-cam.get_y(), static_cast<unsigned>(p.w), static_cast<unsigned>(p.h)}, a);
	for (int y = 0; y < 20; ++y)
	{
		for (int x = 0; x < 20; ++x)
		{
			if(map[y][x])
			{
				switch(map[y][x])
				{
					case 1:
					put_rectangle({x*16-cam.get_x(), y*16-cam.get_y(), 16, 16}, LightGray);
					break;
					case 2:
					put_rectangle({x*16-cam.get_x(), y*16-cam.get_y(), 16, 8}, Gray);
					break;
					case 3:
					put_rectangle({x*16-cam.get_x(), y*16-cam.get_y()+8, 16, 8}, DarkGray);
					break;
					case 4:
					put_rectangle({x*16-cam.get_x(), y*16-cam.get_y(), 8, 16}, Cyan);
					break;
					case 5:
					put_rectangle({x*16-cam.get_x()+8, y*16-cam.get_y(), 8, 16}, Blue);
					break;
				}

			}
		}
	}

	Text::print_format(0, 8, "x = %f", p.x);
	Text::print_format(0, 16, "y = %f", p.y);
	Text::print_format(0, 24, "vx = %f", p.vx);
	Text::print_format(0, 32, "vy = %f", p.vy);

}<commit_msg>Nspire : math functions not included<commit_after>#include "StateCollision.h"
#include "Graphics.h"
#include "input/Input.h"
#include "render/Text.h"
#include <cmath>

using WalrusRPG::Box;
using WalrusRPG::States::StateCollision;
using WalrusRPG::Utils::Rect;
using namespace WalrusRPG::Graphics;
using namespace WalrusRPG::Input;

namespace AABB
{
		// returns true if the boxes are colliding (velocities are not used)
	bool AABBCheck(Box b1, Box b2)
	{
	    return !(b1.x + b1.w <= b2.x || b1.x >= b2.x + b2.w || b1.y + b1.h <= b2.y || b1.y >= b2.y + b2.h);
	}

}

StateCollision::StateCollision()
:p(40, 40, 8, 8, 0, 0), target(p), map{0}, cam(0,0)
{
	srand(4);
	for (int i = 0; i < 10; ++i)
	{
		map[rand()%20][rand()%20] = 1;
		map[rand()%20][rand()%20] = 2;
		map[rand()%20][rand()%20] = 3;
		map[rand()%20][rand()%20] = 4;
		map[rand()%20][rand()%20] = 5;
	}
}

StateCollision::~StateCollision()
{

}

namespace
{
	bool tilemap_collision(char map[20][20], const Box&& object)
	{
		int left_tile = object.x / 16;
		int right_tile = (object.x+object.w-1) / 16;
		int top_tile = object.y / 16;
		int bottom_tile = (object.y + object.h-1) / 16;

		if(left_tile < 0) left_tile = 0;
		if(right_tile > 19) right_tile = 19;
		if(top_tile < 0) top_tile = 0;
		if(bottom_tile > 19) bottom_tile = 19;

		for(int i=left_tile; i<=right_tile; i++)
		{
		    for(int j=top_tile; j<=bottom_tile; j++)
		    {
		        char t = map[j][i];
		        if(t)
		        {
		        	if(t == 1 && AABB::AABBCheck(object, Box(16.*i, 16.*j, 16., 16., 0, 0)))
		            	return true;
		        	if(t == 2 && AABB::AABBCheck(object, Box(16.*i, 16.*j, 16., 8., 0, 0)))
		        		return true;
		        	if(t == 3 && AABB::AABBCheck(object, Box(16.*i, 16.*j+8, 16., 8., 0, 0)))
		        		return true;
		        	if(t == 4 && AABB::AABBCheck(object, Box(16.*i, 16.*j, 8., 16., 0, 0)))
		        		return true;
		        	if(t == 5 && AABB::AABBCheck(object, Box(16.*i+8, 16.*j, 8., 16., 0, 0)))
		        		return true;
		        }
		    }
		}
		return false;
	}
}

void StateCollision::update(unsigned dt)
{
	collided_top = false;
	collided_left = false;
	collided_bottom = false;
	collided_right = false;
	p.vx = 0;
	p.vy = 0;
	if(key_down(Key::K_LEFT))
		p.vx = -2. * dt;
	if(key_down(Key::K_RIGHT))
		p.vx = 2. * dt;
	if(key_down(Key::K_UP))
		p.vy = -2. * dt;
	if(key_down(Key::K_DOWN))
		p.vy = 2. * dt;

	float x_sigma = p.vx < 0. ? -1. : 1.;
	float vx = 0.;
	while(vx != p.vx)
	{
		float add = (std::fabs(vx + x_sigma) > std::fabs(p.vx)) ? (x_sigma * std::fabs(p.vx - vx)) : x_sigma;
		if(tilemap_collision(map, Box(p.x + vx + add, p.y, p.w, p.h, 0, 0)))
			break;
		vx += add;
	}
	p.x += vx;

	float y_sigma = p.vy < 0. ? -1. : 1.;
	float vy = 0;
	while(vy != p.vy)
	{
		float add = (std::fabs(vy + y_sigma) > std::fabs(p.vy)) ? (y_sigma * std::fabs(p.vy - vy)) : y_sigma;
		if(tilemap_collision(map, Box(p.x, p.y + vy + add, p.w, p.h, 0, 0)))
			break;
		vy += add;
	}
	p.y += vy;

	cam.set_center_x(p.x + p.w/2);
	cam.set_center_y(p.y + p.h/2);
}

void StateCollision::render(unsigned dt)
{
	fill(Black);
	Pixel a(Red);

	put_rectangle({static_cast<signed>(p.x)-cam.get_x(), static_cast<signed>(p.y)-cam.get_y(), static_cast<unsigned>(p.w), static_cast<unsigned>(p.h)}, a);
	for (int y = 0; y < 20; ++y)
	{
		for (int x = 0; x < 20; ++x)
		{
			if(map[y][x])
			{
				switch(map[y][x])
				{
					case 1:
					put_rectangle({x*16-cam.get_x(), y*16-cam.get_y(), 16, 16}, LightGray);
					break;
					case 2:
					put_rectangle({x*16-cam.get_x(), y*16-cam.get_y(), 16, 8}, Gray);
					break;
					case 3:
					put_rectangle({x*16-cam.get_x(), y*16-cam.get_y()+8, 16, 8}, DarkGray);
					break;
					case 4:
					put_rectangle({x*16-cam.get_x(), y*16-cam.get_y(), 8, 16}, Cyan);
					break;
					case 5:
					put_rectangle({x*16-cam.get_x()+8, y*16-cam.get_y(), 8, 16}, Blue);
					break;
				}

			}
		}
	}

	Text::print_format(0, 8, "x = %f", p.x);
	Text::print_format(0, 16, "y = %f", p.y);
	Text::print_format(0, 24, "vx = %f", p.vx);
	Text::print_format(0, 32, "vy = %f", p.vy);

}<|endoftext|>


<commit_before>#include "space.h"
#include "display.h"
#include "window.h"
#include "tree.h"
#include "border.h"

extern kwm_screen KWMScreen;
extern kwm_focus KWMFocus;
extern kwm_toggles KWMToggles;

bool GetTagForCurrentSpace(std::string &Tag)
{
    if(KWMScreen.Current && IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        space_info *Space = &KWMScreen.Current->Space[KWMScreen.Current->ActiveSpace];
        if(Space->Mode == SpaceModeBSP)
        {
            Tag = "[bsp]";
            return true;
        }
        else if(Space->Mode == SpaceModeFloating)
        {
            Tag = "[float]";
            return true;
        }

        tree_node *Node = Space->RootNode;
        bool FoundFocusedWindow = false;
        int FocusedIndex = 0;
        int NumberOfWindows = 0;

        if(Node && KWMFocus.Window)
        {
            FocusedIndex = 1;
            NumberOfWindows = 1;

            if(Node->WindowID == KWMFocus.Window->WID)
                FoundFocusedWindow = true;

            while(Node->RightChild)
            {
                if(Node->WindowID == KWMFocus.Window->WID)
                    FoundFocusedWindow = true;

                if(!FoundFocusedWindow)
                    ++FocusedIndex;

                ++NumberOfWindows;

                Node = Node->RightChild;
            }

            if(Node->WindowID == KWMFocus.Window->WID)
                FoundFocusedWindow = true;
        }

        if(FoundFocusedWindow)
            Tag = "[" + std::to_string(FocusedIndex) + "/" + std::to_string(NumberOfWindows) + "]";
        else
            Tag = "[" + std::to_string(NumberOfWindows) + "]";

        return true;
    }

    return false;
}

bool IsActiveSpaceFloating()
{
    return KWMScreen.Current && IsSpaceFloating(KWMScreen.Current->ActiveSpace);
}

bool IsSpaceFloating(int SpaceID)
{
    bool Result = false;

    if(IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        std::map<int, space_info>::iterator It = KWMScreen.Current->Space.find(SpaceID);
        if(It != KWMScreen.Current->Space.end())
            Result = KWMScreen.Current->Space[SpaceID].Mode == SpaceModeFloating;
    }

    return Result;
}

bool IsSpaceInitializedForScreen(screen_info *Screen)
{
    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);
    if(It == Screen->Space.end())
        return false;
    else
        return It->second.Initialized;
}

bool DoesSpaceExistInMapOfScreen(screen_info *Screen)
{
    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);
    if(It == Screen->Space.end())
        return false;
    else
        return It->second.RootNode != NULL && It->second.Initialized;
}

bool IsSpaceTransitionInProgress()
{
    int CurrentSpace = CGSGetActiveSpace(CGSDefaultConnection);
    CFStringRef Identifier = CGSCopyManagedDisplayForSpace(CGSDefaultConnection, CurrentSpace);
    bool Result = CGSManagedDisplayIsAnimating(CGSDefaultConnection, (CFStringRef)Identifier);
    if(Result)
    {
        DEBUG("IsSpaceTransitionInProgress() Space transition detected")
        KWMScreen.UpdateSpace = true;
        ClearFocusedWindow();
        ClearMarkedWindow();
    }

    return Result;
}

bool IsSpaceSystemOrFullscreen()
{
    bool Result = false;

    if(IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        bool Result = CGSSpaceGetType(CGSDefaultConnection, KWMScreen.Current->ActiveSpace) != CGSSpaceTypeUser;
        if(Result)
            DEBUG("IsSpaceSystemOrFullscreen() Space is not user created")
    }

    return Result;
}

void FloatFocusedSpace()
{
    if(KWMScreen.Current &&
       IsSpaceInitializedForScreen(KWMScreen.Current) &&
       KWMToggles.EnableTilingMode &&
       !IsSpaceTransitionInProgress() &&
       !IsSpaceSystemOrFullscreen() &&
       FilterWindowList(KWMScreen.Current))
    {
        space_info *Space = &KWMScreen.Current->Space[KWMScreen.Current->ActiveSpace];
        DestroyNodeTree(Space->RootNode, Space->Mode);
        Space->RootNode = NULL;
        Space->Mode = SpaceModeFloating;
        ClearFocusedWindow();
    }
}

void TileFocusedSpace(space_tiling_option Mode)
{
    if(KWMScreen.Current &&
       IsSpaceInitializedForScreen(KWMScreen.Current) &&
       KWMToggles.EnableTilingMode &&
       !IsSpaceTransitionInProgress() &&
       !IsSpaceSystemOrFullscreen() &&
       FilterWindowList(KWMScreen.Current))
    {
        space_info *Space = &KWMScreen.Current->Space[KWMScreen.Current->ActiveSpace];
        if(Space->Mode == Mode)
            return;

        DestroyNodeTree(Space->RootNode, Space->Mode);
        Space->RootNode = NULL;

        Space->Mode = Mode;
        std::vector<window_info*> WindowsOnDisplay = GetAllWindowsOnDisplay(KWMScreen.Current->ID);
        CreateWindowNodeTree(KWMScreen.Current, &WindowsOnDisplay);
    }
}

void ToggleFocusedSpaceFloating()
{
    if(KWMScreen.Current && IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        if(!IsSpaceFloating(KWMScreen.Current->ActiveSpace))
            FloatFocusedSpace();
        else
            TileFocusedSpace(SpaceModeBSP);
    }
}
<commit_msg>#fixed #121 - properly assign tag of newly created spaces<commit_after>#include "space.h"
#include "display.h"
#include "window.h"
#include "tree.h"
#include "border.h"

extern kwm_screen KWMScreen;
extern kwm_focus KWMFocus;
extern kwm_toggles KWMToggles;
extern kwm_mode KWMMode;

bool GetTagForCurrentSpace(std::string &Tag)
{
    if(KWMScreen.Current && IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        space_info *Space = &KWMScreen.Current->Space[KWMScreen.Current->ActiveSpace];
        if(Space->Mode == SpaceModeBSP)
        {
            Tag = "[bsp]";
            return true;
        }
        else if(Space->Mode == SpaceModeFloating)
        {
            Tag = "[float]";
            return true;
        }

        tree_node *Node = Space->RootNode;
        bool FoundFocusedWindow = false;
        int FocusedIndex = 0;
        int NumberOfWindows = 0;

        if(Node && KWMFocus.Window)
        {
            FocusedIndex = 1;
            NumberOfWindows = 1;

            if(Node->WindowID == KWMFocus.Window->WID)
                FoundFocusedWindow = true;

            while(Node->RightChild)
            {
                if(Node->WindowID == KWMFocus.Window->WID)
                    FoundFocusedWindow = true;

                if(!FoundFocusedWindow)
                    ++FocusedIndex;

                ++NumberOfWindows;

                Node = Node->RightChild;
            }

            if(Node->WindowID == KWMFocus.Window->WID)
                FoundFocusedWindow = true;
        }

        if(FoundFocusedWindow)
            Tag = "[" + std::to_string(FocusedIndex) + "/" + std::to_string(NumberOfWindows) + "]";
        else
            Tag = "[" + std::to_string(NumberOfWindows) + "]";

        return true;
    }
    else
    {
        if(KWMMode.Space == SpaceModeBSP)
            Tag = "[bsp]";
        else if(KWMMode.Space == SpaceModeFloating)
            Tag = "[float]";
        else if(KWMMode.Space == SpaceModeMonocle)
            Tag = "[monocle]";

        return true;
    }

    return false;
}

bool IsActiveSpaceFloating()
{
    return KWMScreen.Current && IsSpaceFloating(KWMScreen.Current->ActiveSpace);
}

bool IsSpaceFloating(int SpaceID)
{
    bool Result = false;

    if(IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        std::map<int, space_info>::iterator It = KWMScreen.Current->Space.find(SpaceID);
        if(It != KWMScreen.Current->Space.end())
            Result = KWMScreen.Current->Space[SpaceID].Mode == SpaceModeFloating;
    }

    return Result;
}

bool IsSpaceInitializedForScreen(screen_info *Screen)
{
    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);
    if(It == Screen->Space.end())
        return false;
    else
        return It->second.Initialized;
}

bool DoesSpaceExistInMapOfScreen(screen_info *Screen)
{
    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);
    if(It == Screen->Space.end())
        return false;
    else
        return It->second.RootNode != NULL && It->second.Initialized;
}

bool IsSpaceTransitionInProgress()
{
    int CurrentSpace = CGSGetActiveSpace(CGSDefaultConnection);
    CFStringRef Identifier = CGSCopyManagedDisplayForSpace(CGSDefaultConnection, CurrentSpace);
    bool Result = CGSManagedDisplayIsAnimating(CGSDefaultConnection, (CFStringRef)Identifier);
    if(Result)
    {
        DEBUG("IsSpaceTransitionInProgress() Space transition detected")
        KWMScreen.UpdateSpace = true;
        ClearFocusedWindow();
        ClearMarkedWindow();
    }

    return Result;
}

bool IsSpaceSystemOrFullscreen()
{
    bool Result = false;

    if(IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        bool Result = CGSSpaceGetType(CGSDefaultConnection, KWMScreen.Current->ActiveSpace) != CGSSpaceTypeUser;
        if(Result)
            DEBUG("IsSpaceSystemOrFullscreen() Space is not user created")
    }

    return Result;
}

void FloatFocusedSpace()
{
    if(KWMScreen.Current &&
       IsSpaceInitializedForScreen(KWMScreen.Current) &&
       KWMToggles.EnableTilingMode &&
       !IsSpaceTransitionInProgress() &&
       !IsSpaceSystemOrFullscreen() &&
       FilterWindowList(KWMScreen.Current))
    {
        space_info *Space = &KWMScreen.Current->Space[KWMScreen.Current->ActiveSpace];
        DestroyNodeTree(Space->RootNode, Space->Mode);
        Space->RootNode = NULL;
        Space->Mode = SpaceModeFloating;
        ClearFocusedWindow();
    }
}

void TileFocusedSpace(space_tiling_option Mode)
{
    if(KWMScreen.Current &&
       IsSpaceInitializedForScreen(KWMScreen.Current) &&
       KWMToggles.EnableTilingMode &&
       !IsSpaceTransitionInProgress() &&
       !IsSpaceSystemOrFullscreen() &&
       FilterWindowList(KWMScreen.Current))
    {
        space_info *Space = &KWMScreen.Current->Space[KWMScreen.Current->ActiveSpace];
        if(Space->Mode == Mode)
            return;

        DestroyNodeTree(Space->RootNode, Space->Mode);
        Space->RootNode = NULL;

        Space->Mode = Mode;
        std::vector<window_info*> WindowsOnDisplay = GetAllWindowsOnDisplay(KWMScreen.Current->ID);
        CreateWindowNodeTree(KWMScreen.Current, &WindowsOnDisplay);
    }
}

void ToggleFocusedSpaceFloating()
{
    if(KWMScreen.Current && IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        if(!IsSpaceFloating(KWMScreen.Current->ActiveSpace))
            FloatFocusedSpace();
        else
            TileFocusedSpace(SpaceModeBSP);
    }
}
<|endoftext|>