<commit_before>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Author: Radu Serban
// =============================================================================
//
// ChronoParallel test program for settling process of granular material.
//
// The global reference frame has Z up.
// All units SI (CGS, i.e., centimeter - gram - second)
//
// =============================================================================

#include <cmath>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <valarray>
#include <vector>

#include "chrono/ChConfig.h"
#include "chrono/core/ChTimer.h"
#include "chrono/utils/ChUtilsCreators.h"
#include "chrono/utils/ChUtilsGenerators.h"
#include "chrono/utils/ChUtilsInputOutput.h"

#include "chrono_parallel/physics/ChSystemParallel.h"

#ifdef CHRONO_OPENGL
#include "chrono_opengl/ChOpenGLWindow.h"
#endif

using namespace chrono;

// --------------------------------------------------------------------------

void TimingHeader() {
    printf("    TIME    |");
    printf("    STEP |");
    printf("   BROAD |");
    printf("  NARROW |");
    printf("  SOLVER |");
    printf("  UPDATE |");
    printf("# BODIES |");
    printf("# CONTACT|");
    printf(" # ITERS |");
    printf("   RESID |");
    printf("\n\n");
}

void TimingOutput(chrono::ChSystem* mSys) {
    double TIME = mSys->GetChTime();
    double STEP = mSys->GetTimerStep();
    double BROD = mSys->GetTimerCollisionBroad();
    double NARR = mSys->GetTimerCollisionNarrow();
    double SOLVER = mSys->GetTimerSolver();
    double UPDT = mSys->GetTimerUpdate();
    double RESID = 0;
    int REQ_ITS = 0;
    int BODS = mSys->GetNbodies();
    int CNTC = mSys->GetNcontacts();
    if (chrono::ChSystemParallel* parallel_sys = dynamic_cast<chrono::ChSystemParallel*>(mSys)) {
        RESID = ((chrono::ChIterativeSolverParallel*)(mSys->GetSolverSpeed()))->GetResidual();
        REQ_ITS = ((chrono::ChIterativeSolverParallel*)(mSys->GetSolverSpeed()))->GetTotalIterations();
    }

    printf("   %8.5f | %7.4f | %7.4f | %7.4f | %7.4f | %7.4f | %7d | %7d | %7d | %7.4f |\n", TIME, STEP, BROD, NARR, SOLVER,
        UPDT, BODS, CNTC, REQ_ITS, RESID);
}

// --------------------------------------------------------------------------

int main(int argc, char** argv) {
    int num_threads = 4;
    ChMaterialSurfaceBase::ContactMethod method = ChMaterialSurfaceBase::DEM;
    bool use_mat_properties = true;
    bool render = false;
    bool track_granule = false;

    // Get number of threads from arguments (if specified)
    if (argc > 1) {
        num_threads = std::stoi(argv[1]);
    }

    std::cout << "Requested number of threads: " << num_threads << std::endl;

    // ----------------
    // Model parameters
    // ----------------

    // Container dimensions
    double hdimX = 5.0;
    double hdimY = 0.25;
    double hdimZ = 0.5;
    double hthick = 0.25;

    // Granular material properties
    double radius_g = 0.006;
    int Id_g = 10000;
    double rho_g = 2500;
    double vol_g = (4.0 / 3) * CH_C_PI * radius_g * radius_g * radius_g;
    double mass_g = rho_g * vol_g;
    ChVector<> inertia_g = 0.4 * mass_g * radius_g * radius_g * ChVector<>(1, 1, 1);
    int num_layers = 10;

    // Terrain contact properties
    float friction_terrain = 0.9f;
    float restitution_terrain = 0.0f;
    float Y_terrain = 8e5f;
    float nu_terrain = 0.3f;
    float kn_terrain = 1.0e7f;
    float gn_terrain = 1.0e3f;
    float kt_terrain = 2.86e6f;
    float gt_terrain = 1.0e3f;
    float coh_pressure_terrain = 0e3f;
    float coh_force_terrain = (float)(CH_C_PI * radius_g * radius_g) * coh_pressure_terrain;

    // Estimates for number of bins for broad-phase
    int factor = 2;
    int binsX = (int)std::ceil(hdimX / radius_g) / factor;
    int binsY = (int)std::ceil(hdimY / radius_g) / factor;
    int binsZ = 1;
    std::cout << "Broad-phase bins: " << binsX << " x " << binsY << " x " << binsZ << std::endl;

    // --------------------------
    // Create the parallel system
    // --------------------------

    // Create system and set method-specific solver settings
    chrono::ChSystemParallel* system;

    switch (method) {
        case ChMaterialSurfaceBase::DEM: {
            ChSystemParallelDEM* sys = new ChSystemParallelDEM;
            sys->GetSettings()->solver.contact_force_model = ChSystemDEM::Hertz;
            sys->GetSettings()->solver.tangential_displ_mode = ChSystemDEM::TangentialDisplacementModel::OneStep;
            sys->GetSettings()->solver.use_material_properties = use_mat_properties;
            system = sys;

            break;
        }
        case ChMaterialSurfaceBase::DVI: {
            ChSystemParallelDVI* sys = new ChSystemParallelDVI;
            sys->GetSettings()->solver.solver_mode = SLIDING;
            sys->GetSettings()->solver.max_iteration_normal = 0;
            sys->GetSettings()->solver.max_iteration_sliding = 200;
            sys->GetSettings()->solver.max_iteration_spinning = 0;
            sys->GetSettings()->solver.alpha = 0;
            sys->GetSettings()->solver.contact_recovery_speed = -1;
            sys->GetSettings()->collision.collision_envelope = 0.1 * radius_g;
            sys->ChangeSolverType(APGD);
            system = sys;

            break;
        }
    }

    system->Set_G_acc(ChVector<>(0, 0, -9.81));
    system->GetSettings()->perform_thread_tuning = false;
    system->GetSettings()->solver.use_full_inertia_tensor = false;
    system->GetSettings()->solver.tolerance = 0.1;
    system->GetSettings()->solver.max_iteration_bilateral = 100;
    system->GetSettings()->collision.narrowphase_algorithm = NARROWPHASE_HYBRID_MPR;
    system->GetSettings()->collision.bins_per_axis = I3(binsX, binsY, binsZ);

    // Set number of threads
    system->SetParallelThreadNumber(num_threads);
    CHOMPfunctions::SetNumThreads(num_threads);

    // Sanity check: print number of threads in a parallel region
#pragma omp parallel
#pragma omp master
    { std::cout << "Actual number of OpenMP threads: " << omp_get_num_threads() << std::endl; }

    // ---------------------
    // Create terrain bodies
    // ---------------------

    // Create contact material for terrain
    std::shared_ptr<ChMaterialSurfaceBase> material_terrain;

    switch (method) {
        case ChMaterialSurfaceBase::DEM: {
            auto mat_ter = std::make_shared<ChMaterialSurfaceDEM>();
            mat_ter->SetFriction(friction_terrain);
            mat_ter->SetRestitution(restitution_terrain);
            mat_ter->SetYoungModulus(Y_terrain);
            mat_ter->SetPoissonRatio(nu_terrain);
            mat_ter->SetAdhesion(coh_force_terrain);
            mat_ter->SetKn(kn_terrain);
            mat_ter->SetGn(gn_terrain);
            mat_ter->SetKt(kt_terrain);
            mat_ter->SetGt(gt_terrain);

            material_terrain = mat_ter;

            break;
        }
        case ChMaterialSurfaceBase::DVI: {
            auto mat_ter = std::make_shared<ChMaterialSurface>();
            mat_ter->SetFriction(friction_terrain);
            mat_ter->SetRestitution(restitution_terrain);
            mat_ter->SetCohesion(coh_force_terrain);

            material_terrain = mat_ter;

            break;
        }
    }

    // Create container body
    auto container = std::shared_ptr<ChBody>(system->NewBody());
    system->AddBody(container);
    container->SetIdentifier(-1);
    container->SetMass(1);
    container->SetBodyFixed(true);
    container->SetCollide(true);
    container->SetMaterialSurface(material_terrain);

    container->GetCollisionModel()->ClearModel();
    // Bottom box
    utils::AddBoxGeometry(container.get(), ChVector<>(hdimX, hdimY, hthick), ChVector<>(0, 0, -hthick),
                          ChQuaternion<>(1, 0, 0, 0), true);
    // Front box
    utils::AddBoxGeometry(container.get(), ChVector<>(hthick, hdimY, hdimZ + hthick),
                          ChVector<>(hdimX + hthick, 0, hdimZ - hthick), ChQuaternion<>(1, 0, 0, 0), false);
    // Rear box
    utils::AddBoxGeometry(container.get(), ChVector<>(hthick, hdimY, hdimZ + hthick),
                          ChVector<>(-hdimX - hthick, 0, hdimZ - hthick), ChQuaternion<>(1, 0, 0, 0), false);
    // Left box
    utils::AddBoxGeometry(container.get(), ChVector<>(hdimX, hthick, hdimZ + hthick),
                          ChVector<>(0, hdimY + hthick, hdimZ - hthick), ChQuaternion<>(1, 0, 0, 0), false);
    // Right box
    utils::AddBoxGeometry(container.get(), ChVector<>(hdimX, hthick, hdimZ + hthick),
                          ChVector<>(0, -hdimY - hthick, hdimZ - hthick), ChQuaternion<>(1, 0, 0, 0), false);
    container->GetCollisionModel()->BuildModel();

    // ----------------
    // Create particles
    // ----------------

    // Create a particle generator and a mixture entirely made out of spheres
    utils::Generator gen(system);
    std::shared_ptr<utils::MixtureIngredient> m1 = gen.AddMixtureIngredient(utils::SPHERE, 1.0);
    m1->setDefaultMaterial(material_terrain);
    m1->setDefaultDensity(rho_g);
    m1->setDefaultSize(radius_g);

    // Set starting value for body identifiers
    gen.setBodyIdentifier(Id_g);

    // Create particles in layers until reaching the desired number of particles
    double r = 1.01 * radius_g;
    ChVector<> hdims(hdimX - r, hdimY - r, 0);
    ChVector<> center(0, 0, 2 * r);

    for (int il = 0; il < num_layers; il++) {
        gen.createObjectsBox(utils::POISSON_DISK, 2 * r, center, hdims);
        center.z += 2 * r;
    }

    unsigned int num_particles = gen.getTotalNumBodies();
    std::cout << "Generated particles:  " << num_particles << std::endl;

    // If tracking a granule (roughly in the "middle of the pack"),
    // grab a pointer to the tracked body and open an output file.
    std::shared_ptr<ChBody> granule;  // tracked granule
    std::ofstream outf;             // output file stream

    if (track_granule) {
        int id = Id_g + num_particles / 2;
        auto bodies = system->Get_bodylist();
        for (auto body = bodies->begin(); body != bodies->end(); ++body) {
            if ((*body)->GetIdentifier() == id) {
                granule = *body;
                break;
            }
        }

        outf.open("../settling_granule.dat", std::ios::out);
        outf.precision(7);
        outf << std::scientific;
    }

#ifdef CHRONO_OPENGL
    // -------------------------------
    // Create the visualization window
    // -------------------------------

    if (render) {
        opengl::ChOpenGLWindow& gl_window = opengl::ChOpenGLWindow::getInstance();
        gl_window.Initialize(1280, 720, "Settling test", system);
        gl_window.SetCamera(ChVector<>(0, -1, 0), ChVector<>(0, 0, 0), ChVector<>(0, 0, 1), 0.05f);
        gl_window.SetRenderMode(opengl::WIREFRAME);
    }
#endif

    // ---------------
    // Simulate system
    // ---------------

    ChTimer<double> timer;
    double cumm_sim_time = 0;

    double time_end = 0.4;
    double time_step = 1e-4;

    TimingHeader();
    while (system->GetChTime() < time_end) {
        ////timer.reset();
        ////timer.start();
        system->DoStepDynamics(time_step);
        TimingOutput(system);
        ////timer.stop();
        ////cumm_sim_time += timer();
        ////std::cout << std::fixed << std::setprecision(6) << system->GetChTime() << "  [" << timer.GetTimeSeconds() << "]"
        ////          << std::endl;

        if (track_granule) {
            assert(outf.is_open());
            assert(granule);
            const ChVector<>& pos = granule->GetPos();
            const ChVector<>& vel = granule->GetPos_dt();
            outf << system->GetChTime() << " ";
            outf << system->GetNbodies() << " " << system->GetNcontacts() << " ";
            outf << pos.x << " " << pos.y << " " << pos.z << " ";
            outf << vel.x << " " << vel.y << " " << vel.z;
            outf << std::endl << std::flush;
        }

#ifdef CHRONO_OPENGL
        if (render) {
            opengl::ChOpenGLWindow& gl_window = opengl::ChOpenGLWindow::getInstance();
            if (gl_window.Active()) {
                gl_window.Render();
            } else {
                return 1;
            }
        }
#endif
    }

    return 0;
}<commit_msg>Display cumulative timing information in test_PAR_settling<commit_after>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Author: Radu Serban
// =============================================================================
//
// ChronoParallel test program for settling process of granular material.
//
// The global reference frame has Z up.
// All units SI (CGS, i.e., centimeter - gram - second)
//
// =============================================================================

#include <cmath>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <valarray>
#include <vector>

#include "chrono/ChConfig.h"
#include "chrono/core/ChTimer.h"
#include "chrono/utils/ChUtilsCreators.h"
#include "chrono/utils/ChUtilsGenerators.h"
#include "chrono/utils/ChUtilsInputOutput.h"

#include "chrono_parallel/physics/ChSystemParallel.h"

#ifdef CHRONO_OPENGL
#include "chrono_opengl/ChOpenGLWindow.h"
#endif

using namespace chrono;

// --------------------------------------------------------------------------

void TimingHeader() {
    printf("    TIME    |");
    printf("    STEP |");
    printf("   BROAD |");
    printf("  NARROW |");
    printf("  SOLVER |");
    printf("  UPDATE |");
    printf("# BODIES |");
    printf("# CONTACT|");
    printf(" # ITERS |");
    printf("   RESID |");
    printf("\n\n");
}

void TimingOutput(chrono::ChSystem* mSys) {
    double TIME = mSys->GetChTime();
    double STEP = mSys->GetTimerStep();
    double BROD = mSys->GetTimerCollisionBroad();
    double NARR = mSys->GetTimerCollisionNarrow();
    double SOLVER = mSys->GetTimerSolver();
    double UPDT = mSys->GetTimerUpdate();
    double RESID = 0;
    int REQ_ITS = 0;
    int BODS = mSys->GetNbodies();
    int CNTC = mSys->GetNcontacts();
    if (chrono::ChSystemParallel* parallel_sys = dynamic_cast<chrono::ChSystemParallel*>(mSys)) {
        RESID = ((chrono::ChIterativeSolverParallel*)(mSys->GetSolverSpeed()))->GetResidual();
        REQ_ITS = ((chrono::ChIterativeSolverParallel*)(mSys->GetSolverSpeed()))->GetTotalIterations();
    }

    printf("   %8.5f | %7.4f | %7.4f | %7.4f | %7.4f | %7.4f | %7d | %7d | %7d | %7.4f |\n", TIME, STEP, BROD, NARR, SOLVER,
        UPDT, BODS, CNTC, REQ_ITS, RESID);
}

// --------------------------------------------------------------------------

int main(int argc, char** argv) {
    int num_threads = 4;
    ChMaterialSurfaceBase::ContactMethod method = ChMaterialSurfaceBase::DEM;
    bool use_mat_properties = true;
    bool render = false;
    bool track_granule = false;

    // Get number of threads from arguments (if specified)
    if (argc > 1) {
        num_threads = std::stoi(argv[1]);
    }

    std::cout << "Requested number of threads: " << num_threads << std::endl;

    // ----------------
    // Model parameters
    // ----------------

    // Container dimensions
    double hdimX = 5.0;
    double hdimY = 0.25;
    double hdimZ = 0.5;
    double hthick = 0.25;

    // Granular material properties
    double radius_g = 0.006;
    int Id_g = 10000;
    double rho_g = 2500;
    double vol_g = (4.0 / 3) * CH_C_PI * radius_g * radius_g * radius_g;
    double mass_g = rho_g * vol_g;
    ChVector<> inertia_g = 0.4 * mass_g * radius_g * radius_g * ChVector<>(1, 1, 1);
    int num_layers = 10;

    // Terrain contact properties
    float friction_terrain = 0.9f;
    float restitution_terrain = 0.0f;
    float Y_terrain = 8e5f;
    float nu_terrain = 0.3f;
    float kn_terrain = 1.0e7f;
    float gn_terrain = 1.0e3f;
    float kt_terrain = 2.86e6f;
    float gt_terrain = 1.0e3f;
    float coh_pressure_terrain = 0e3f;
    float coh_force_terrain = (float)(CH_C_PI * radius_g * radius_g) * coh_pressure_terrain;

    // Estimates for number of bins for broad-phase
    int factor = 2;
    int binsX = (int)std::ceil(hdimX / radius_g) / factor;
    int binsY = (int)std::ceil(hdimY / radius_g) / factor;
    int binsZ = 1;
    std::cout << "Broad-phase bins: " << binsX << " x " << binsY << " x " << binsZ << std::endl;

    // --------------------------
    // Create the parallel system
    // --------------------------

    // Create system and set method-specific solver settings
    chrono::ChSystemParallel* system;

    switch (method) {
        case ChMaterialSurfaceBase::DEM: {
            ChSystemParallelDEM* sys = new ChSystemParallelDEM;
            sys->GetSettings()->solver.contact_force_model = ChSystemDEM::Hertz;
            sys->GetSettings()->solver.tangential_displ_mode = ChSystemDEM::TangentialDisplacementModel::OneStep;
            sys->GetSettings()->solver.use_material_properties = use_mat_properties;
            system = sys;

            break;
        }
        case ChMaterialSurfaceBase::DVI: {
            ChSystemParallelDVI* sys = new ChSystemParallelDVI;
            sys->GetSettings()->solver.solver_mode = SLIDING;
            sys->GetSettings()->solver.max_iteration_normal = 0;
            sys->GetSettings()->solver.max_iteration_sliding = 200;
            sys->GetSettings()->solver.max_iteration_spinning = 0;
            sys->GetSettings()->solver.alpha = 0;
            sys->GetSettings()->solver.contact_recovery_speed = -1;
            sys->GetSettings()->collision.collision_envelope = 0.1 * radius_g;
            sys->ChangeSolverType(APGD);
            system = sys;

            break;
        }
    }

    system->Set_G_acc(ChVector<>(0, 0, -9.81));
    system->GetSettings()->perform_thread_tuning = false;
    system->GetSettings()->solver.use_full_inertia_tensor = false;
    system->GetSettings()->solver.tolerance = 0.1;
    system->GetSettings()->solver.max_iteration_bilateral = 100;
    system->GetSettings()->collision.narrowphase_algorithm = NARROWPHASE_HYBRID_MPR;
    system->GetSettings()->collision.bins_per_axis = I3(binsX, binsY, binsZ);

    // Set number of threads
    system->SetParallelThreadNumber(num_threads);
    CHOMPfunctions::SetNumThreads(num_threads);

    // Sanity check: print number of threads in a parallel region
#pragma omp parallel
#pragma omp master
    { std::cout << "Actual number of OpenMP threads: " << omp_get_num_threads() << std::endl; }

    // ---------------------
    // Create terrain bodies
    // ---------------------

    // Create contact material for terrain
    std::shared_ptr<ChMaterialSurfaceBase> material_terrain;

    switch (method) {
        case ChMaterialSurfaceBase::DEM: {
            auto mat_ter = std::make_shared<ChMaterialSurfaceDEM>();
            mat_ter->SetFriction(friction_terrain);
            mat_ter->SetRestitution(restitution_terrain);
            mat_ter->SetYoungModulus(Y_terrain);
            mat_ter->SetPoissonRatio(nu_terrain);
            mat_ter->SetAdhesion(coh_force_terrain);
            mat_ter->SetKn(kn_terrain);
            mat_ter->SetGn(gn_terrain);
            mat_ter->SetKt(kt_terrain);
            mat_ter->SetGt(gt_terrain);

            material_terrain = mat_ter;

            break;
        }
        case ChMaterialSurfaceBase::DVI: {
            auto mat_ter = std::make_shared<ChMaterialSurface>();
            mat_ter->SetFriction(friction_terrain);
            mat_ter->SetRestitution(restitution_terrain);
            mat_ter->SetCohesion(coh_force_terrain);

            material_terrain = mat_ter;

            break;
        }
    }

    // Create container body
    auto container = std::shared_ptr<ChBody>(system->NewBody());
    system->AddBody(container);
    container->SetIdentifier(-1);
    container->SetMass(1);
    container->SetBodyFixed(true);
    container->SetCollide(true);
    container->SetMaterialSurface(material_terrain);

    container->GetCollisionModel()->ClearModel();
    // Bottom box
    utils::AddBoxGeometry(container.get(), ChVector<>(hdimX, hdimY, hthick), ChVector<>(0, 0, -hthick),
                          ChQuaternion<>(1, 0, 0, 0), true);
    // Front box
    utils::AddBoxGeometry(container.get(), ChVector<>(hthick, hdimY, hdimZ + hthick),
                          ChVector<>(hdimX + hthick, 0, hdimZ - hthick), ChQuaternion<>(1, 0, 0, 0), false);
    // Rear box
    utils::AddBoxGeometry(container.get(), ChVector<>(hthick, hdimY, hdimZ + hthick),
                          ChVector<>(-hdimX - hthick, 0, hdimZ - hthick), ChQuaternion<>(1, 0, 0, 0), false);
    // Left box
    utils::AddBoxGeometry(container.get(), ChVector<>(hdimX, hthick, hdimZ + hthick),
                          ChVector<>(0, hdimY + hthick, hdimZ - hthick), ChQuaternion<>(1, 0, 0, 0), false);
    // Right box
    utils::AddBoxGeometry(container.get(), ChVector<>(hdimX, hthick, hdimZ + hthick),
                          ChVector<>(0, -hdimY - hthick, hdimZ - hthick), ChQuaternion<>(1, 0, 0, 0), false);
    container->GetCollisionModel()->BuildModel();

    // ----------------
    // Create particles
    // ----------------

    // Create a particle generator and a mixture entirely made out of spheres
    utils::Generator gen(system);
    std::shared_ptr<utils::MixtureIngredient> m1 = gen.AddMixtureIngredient(utils::SPHERE, 1.0);
    m1->setDefaultMaterial(material_terrain);
    m1->setDefaultDensity(rho_g);
    m1->setDefaultSize(radius_g);

    // Set starting value for body identifiers
    gen.setBodyIdentifier(Id_g);

    // Create particles in layers until reaching the desired number of particles
    double r = 1.01 * radius_g;
    ChVector<> hdims(hdimX - r, hdimY - r, 0);
    ChVector<> center(0, 0, 2 * r);

    for (int il = 0; il < num_layers; il++) {
        gen.createObjectsBox(utils::POISSON_DISK, 2 * r, center, hdims);
        center.z += 2 * r;
    }

    unsigned int num_particles = gen.getTotalNumBodies();
    std::cout << "Generated particles:  " << num_particles << std::endl;

    // If tracking a granule (roughly in the "middle of the pack"),
    // grab a pointer to the tracked body and open an output file.
    std::shared_ptr<ChBody> granule;  // tracked granule
    std::ofstream outf;             // output file stream

    if (track_granule) {
        int id = Id_g + num_particles / 2;
        auto bodies = system->Get_bodylist();
        for (auto body = bodies->begin(); body != bodies->end(); ++body) {
            if ((*body)->GetIdentifier() == id) {
                granule = *body;
                break;
            }
        }

        outf.open("../settling_granule.dat", std::ios::out);
        outf.precision(7);
        outf << std::scientific;
    }

#ifdef CHRONO_OPENGL
    // -------------------------------
    // Create the visualization window
    // -------------------------------

    if (render) {
        opengl::ChOpenGLWindow& gl_window = opengl::ChOpenGLWindow::getInstance();
        gl_window.Initialize(1280, 720, "Settling test", system);
        gl_window.SetCamera(ChVector<>(0, -1, 0), ChVector<>(0, 0, 0), ChVector<>(0, 0, 1), 0.05f);
        gl_window.SetRenderMode(opengl::WIREFRAME);
    }
#endif

    // ---------------
    // Simulate system
    // ---------------

    double time_end = 0.4;
    double time_step = 1e-4;

    double cum_sim_time = 0;
    double cum_broad_time = 0;
    double cum_narrow_time = 0;
    double cum_solver_time = 0;
    double cum_update_time = 0;

    TimingHeader();

    while (system->GetChTime() < time_end) {
        system->DoStepDynamics(time_step);

        TimingOutput(system);

        cum_sim_time += system->GetTimerStep();
        cum_broad_time += system->GetTimerCollisionBroad();
        cum_narrow_time += system->GetTimerCollisionNarrow();
        cum_solver_time += system->GetTimerSolver();
        cum_update_time += system->GetTimerUpdate();

        if (track_granule) {
            assert(outf.is_open());
            assert(granule);
            const ChVector<>& pos = granule->GetPos();
            const ChVector<>& vel = granule->GetPos_dt();
            outf << system->GetChTime() << " ";
            outf << system->GetNbodies() << " " << system->GetNcontacts() << " ";
            outf << pos.x << " " << pos.y << " " << pos.z << " ";
            outf << vel.x << " " << vel.y << " " << vel.z;
            outf << std::endl << std::flush;
        }

#ifdef CHRONO_OPENGL
        if (render) {
            opengl::ChOpenGLWindow& gl_window = opengl::ChOpenGLWindow::getInstance();
            if (gl_window.Active()) {
                gl_window.Render();
            } else {
                return 1;
            }
        }
#endif
    }

    std::cout << std::endl;
    std::cout << "Simulation time: " << cum_sim_time << std::endl;
    std::cout << "    Broadphase:  " << cum_broad_time << std::endl;
    std::cout << "    Narrowphase: " << cum_narrow_time << std::endl;
    std::cout << "    Solver:      " << cum_solver_time << std::endl;
    std::cout << "    Update:      " << cum_update_time << std::endl;
    std::cout << std::endl;

    return 0;
}<|endoftext|>


<commit_before>/*!
 * \author ddubois
 * \date 15-Aug-18.
 */

#include <miniz_zip.h>
#include <easylogging++.h>

#include "zip_folder_accessor.hpp"

namespace nova {
    zip_folder_accessor::zip_folder_accessor(const std::experimental::filesystem::path &folder)
        : folder_accessor_base(folder) {
        const auto folder_string = folder.string();
        if(!mz_zip_reader_init_file(&zip_archive, folder_string.c_str(), 0)) {
            LOG(DEBUG) << "Could not open zip archive " << folder_string;
            throw resource_not_found_error(folder_string);
        }
    }

    zip_folder_accessor::~zip_folder_accessor() {
        mz_zip_reader_end(&zip_archive);
    }

    bool zip_folder_accessor::does_resource_exist(const fs::path &resource_path) {
        const auto resource_string = resource_path.string();
        const auto existence_maybe = does_resource_exist_in_map(resource_string);
        if(existence_maybe) {
            return existence_maybe.value();
        }

        int32_t ret_val = mz_zip_reader_locate_file(&zip_archive, resource_string.c_str(), "", 0);
        if(ret_val != -1) {
            // resource found!
            resource_indexes.emplace(resource_string, ret_val);
            resource_existance.emplace(resource_string, true);
            return true;

        } else {
            // resource not found
            resource_existance.emplace(resource_string, false);
            return false;
        }
    }

    std::vector<uint8_t> zip_folder_accessor::read_resource(const fs::path &resource_path) {
        std::string resource_string = resource_path.string();
        if(!does_resource_exist(resource_path)) {
            LOG(DEBUG) << "Resource at path " << resource_string << " does not exist";
            throw resource_not_found_error(resource_string);
        }

        uint32_t file_idx = resource_indexes.at(resource_string);

        mz_zip_archive_file_stat file_stat = {};
        mz_bool has_file_stat = mz_zip_reader_file_stat(&zip_archive, file_idx, &file_stat);
        if(!has_file_stat) {
            mz_zip_error err_code = mz_zip_get_last_error(&zip_archive);
            std::string err = mz_zip_get_error_string(err_code);

            LOG(DEBUG) << "Could not get information for file " << resource_string << ": " << err;
            throw resource_not_found_error(resource_string);
        }

        std::vector<uint8_t> resource_buffer(file_stat.m_uncomp_size);

        mz_bool file_extracted = mz_zip_reader_extract_to_mem(&zip_archive, file_idx, resource_buffer.data(), resource_buffer.size(), 0);
        if(!file_extracted) {
            mz_zip_error err_code = mz_zip_get_last_error(&zip_archive);
            std::string err = mz_zip_get_error_string(err_code);

            LOG(DEBUG) << "Could not extract file " << resource_string << ": " << err;
            throw resource_not_found_error(resource_string);
        }

        return resource_buffer;
    }
}<commit_msg>Converted zip_folder_accessor to nova logger<commit_after>/*!
 * \author ddubois
 * \date 15-Aug-18.
 */

#include <miniz_zip.h>

#include "zip_folder_accessor.hpp"
#include "../util/logger.hpp"

namespace nova {
    zip_folder_accessor::zip_folder_accessor(const std::experimental::filesystem::path &folder)
        : folder_accessor_base(folder) {
        const auto folder_string = folder.string();
        if(!mz_zip_reader_init_file(&zip_archive, folder_string.c_str(), 0)) {
            logger::instance.log(log_level::DEBUG, "Could not open zip archive " + folder_string);
            throw resource_not_found_error(folder_string);
        }
    }

    zip_folder_accessor::~zip_folder_accessor() {
        mz_zip_reader_end(&zip_archive);
    }

    bool zip_folder_accessor::does_resource_exist(const fs::path &resource_path) {
        const auto resource_string = resource_path.string();
        const auto existence_maybe = does_resource_exist_in_map(resource_string);
        if(existence_maybe) {
            return existence_maybe.value();
        }

        int32_t ret_val = mz_zip_reader_locate_file(&zip_archive, resource_string.c_str(), "", 0);
        if(ret_val != -1) {
            // resource found!
            resource_indexes.emplace(resource_string, ret_val);
            resource_existance.emplace(resource_string, true);
            return true;

        } else {
            // resource not found
            resource_existance.emplace(resource_string, false);
            return false;
        }
    }

    std::vector<uint8_t> zip_folder_accessor::read_resource(const fs::path &resource_path) {
        std::string resource_string = resource_path.string();
        if(!does_resource_exist(resource_path)) {
            logger::instance.log(log_level::DEBUG, "Resource at path " + resource_string + " does not exist");
            throw resource_not_found_error(resource_string);
        }

        uint32_t file_idx = resource_indexes.at(resource_string);

        mz_zip_archive_file_stat file_stat = {};
        mz_bool has_file_stat = mz_zip_reader_file_stat(&zip_archive, file_idx, &file_stat);
        if(!has_file_stat) {
            mz_zip_error err_code = mz_zip_get_last_error(&zip_archive);
            std::string err = mz_zip_get_error_string(err_code);

            logger::instance.log(log_level::DEBUG, "Could not get information for file " + resource_string + ": " + err);
            throw resource_not_found_error(resource_string);
        }

        std::vector<uint8_t> resource_buffer(file_stat.m_uncomp_size);

        mz_bool file_extracted = mz_zip_reader_extract_to_mem(&zip_archive, file_idx, resource_buffer.data(), resource_buffer.size(), 0);
        if(!file_extracted) {
            mz_zip_error err_code = mz_zip_get_last_error(&zip_archive);
            std::string err = mz_zip_get_error_string(err_code);

            logger::instance.log(log_level::DEBUG, "Could not extract file " + resource_string + ": " + err);
            throw resource_not_found_error(resource_string);
        }

        return resource_buffer;
    }
}<|endoftext|>


<commit_before>#pragma once

#include <array>
#include <memory>
#include <cstring>
#include <type_traits>
#include <typeinfo>
#include <typeindex>
#include <cassert>
#include <sstream>
#include <string>

namespace detail { namespace static_any {

// Pointer to administrative function, function that will by type-specific, and will be able to perform all the required operations
enum class operation_t { query_type, query_size, copy, move, destroy };

using function_ptr_t = void(*)(operation_t operation, void* this_ptr, void* other_ptr);

template<typename _T>
static void operation(operation_t operation, void* ptr1, void* ptr2)
{
    _T* this_ptr = reinterpret_cast<_T*>(ptr1);

    switch(operation)
    {
        case operation_t::query_type:
        {
            *reinterpret_cast<const std::type_info**>(ptr1) = &typeid(_T);
            break;
        }
        case operation_t::query_size:
        {
            *reinterpret_cast<std::size_t*>(ptr1) = sizeof(_T);
            break;
        }
        case operation_t::copy:
        {
            _T* other_ptr = reinterpret_cast<_T*>(ptr2);
            assert(this_ptr);
            assert(other_ptr);
            new(this_ptr)_T(*other_ptr);
            break;
        }
        case operation_t::move:
        {    _T* other_ptr = reinterpret_cast<_T*>(ptr2);
            assert(this_ptr);
            assert(other_ptr);
            new(this_ptr)_T(std::move(*other_ptr));
            break;
        }
        case operation_t::destroy:
        {    assert(this_ptr);
            this_ptr->~_T();
            break;
        }
    }
}

template<typename _T>
static function_ptr_t get_function_for_type()
{
    return &static_any::operation<std::remove_cv_t<std::remove_reference_t<_T>>>;
}

}}

template <std::size_t _N>
struct static_any
{
    typedef std::size_t size_type;

    static_any() = default;

    ~static_any()
    {
        destroy();
    }

    template<typename _T>
    static_any(_T&& v)
    {
        copy_or_move(std::forward<_T>(v));
    }

    template<std::size_t _M>
    static_any(const static_any<_M>& another)
    {
        copy_or_move_from_another(std::forward<static_any<_M>>(another));
    }

    template<std::size_t _M>
    static_any(static_any<_M>& another)
    {
        copy_or_move_from_another(std::forward<static_any<_M>>(another));
    }

    template<std::size_t _M>
    static_any(static_any<_M>&& another)
    {
        copy_or_move_from_another(std::forward<static_any<_M>>(another));
    }

    static_any& operator=(const static_any& another)
    {
        assign_from_another(another);
        return *this;
    }

    static_any& operator=(static_any& another)
    {
        assign_from_another(another);
        return *this;
    }

    static_any& operator=(static_any&& another)
    {
        assign_from_another(another);
        return *this;
    }

    template<std::size_t _M>
    static_any& operator=(const static_any<_M>& another)
    {
        assign_from_another(another);
        return *this;
    }

    template<std::size_t _M>
    static_any& operator=(static_any<_M>& another)
    {
        assign_from_another(another);
        return *this;
    }

    template<std::size_t _M>
    static_any& operator=(static_any<_M>&& another)
    {
        assign_from_another(another);
        return *this;
    }

    template <typename _T>
    static_any& operator=(const _T& t)
    {
        assign(std::forward<_T>(t));
        return *this;
    }

    template <typename _T>
    static_any& operator=(_T&& t)
    {
        assign(std::forward<_T>(t));
        return *this;
    }

    inline void reset() { destroy(); }

    template<typename _T>
    inline const _T& get() const;

    template<typename _T>
    inline _T& get();

    template <typename _T>
    bool has() const
    {
        if (function_ == detail::static_any::get_function_for_type<_T>())
        {
            return true;
        }
        else if (function_)
        {
            // need to try another, possibly more costly way, as we may compare types across DLL boundaries
            return std::type_index(typeid(_T)) == std::type_index(query_type());
        }
        return false;
    }

    const std::type_info& type() const
    {
        if (empty())
            return typeid(void);
        else
            return query_type();
    }

    bool empty() const { return function_ == nullptr; }

    size_type size() const
    {
        if (empty())
            return 0;
        else
            return query_size();
    }

    static constexpr size_type capacity() { return _N; }

    // Initializes with object of type T, created in-place with specified constructor params
    template<typename _T, typename... Args>
    void emplace(Args&&... args)
    {
        destroy();
        new(buff_.data()) _T(std::forward<Args>(args)...);
        function_ = detail::static_any::get_function_for_type<_T>();
    }

private:
    using operation_t = detail::static_any::operation_t;
    using function_ptr_t = detail::static_any::function_ptr_t;

    template <typename _T>
    void copy_or_move(_T&& t)
    {
        static_assert(capacity() >= sizeof(_T), "_T is too big to be copied to static_any");
        assert(function_ == nullptr);

        using NonConstT = std::remove_cv_t<std::remove_reference_t<_T>>;
        NonConstT* non_const_t = const_cast<NonConstT*>(&t);

        try {
            call_copy_or_move<_T&&>(buff_.data(), non_const_t);
        }
        catch(...) {
            throw;
        }

        function_ = detail::static_any::get_function_for_type<_T>();
    }

    template <typename _T>
    void assign(_T&& t)
    {
        static_assert(capacity() >= sizeof(_T), "_T is too big to be copied to static_any");

        using NonConstT = std::remove_cv_t<std::remove_reference_t<_T>>;
        NonConstT* non_const_t = const_cast<NonConstT*>(&t);

        std::array<char, _N> buff;

        try {
            call_copy_or_move<_T&&>(buff.data(), non_const_t);
        }
        catch(...) {
            throw;
        }

        destroy();
        assert(function_ == nullptr);

        function_ = detail::static_any::get_function_for_type<_T>();
        buff_ = buff;
    }

    template <typename _RefT>
    std::enable_if_t<std::is_rvalue_reference<_RefT>::value>
    call_copy_or_move(void* this_void_ptr, void* other_void_ptr)
    {
        detail::static_any::get_function_for_type<_RefT>()(operation_t::move, this_void_ptr, other_void_ptr);
    }

    template <typename _RefT>
    std::enable_if_t<!std::is_rvalue_reference<_RefT>::value>
    call_copy_or_move(void* this_void_ptr, void* other_void_ptr)
    {
        detail::static_any::get_function_for_type<_RefT>()(operation_t::copy, this_void_ptr, other_void_ptr);
    }

    const std::type_info& query_type() const
    {
        assert(function_ != nullptr);
        const std::type_info* ti ;
        function_(operation_t::query_type, &ti, nullptr);
        return *ti;
    }

    size_type query_size() const
    {
        assert(function_ != nullptr);
        std::size_t size;
        function_(operation_t::query_size, &size, nullptr);
        return size;
    }

    void destroy()
    {
        if (function_)
        {
            void* not_used = nullptr;
            function_(operation_t::destroy, buff_.data(), not_used);
            function_ = nullptr;
        }
    }

    template<typename _T>
    const _T* as() const
    {
        return reinterpret_cast<const _T*>(buff_.data());
    }

    template<typename _T>
    _T* as()
    {
        return reinterpret_cast<_T*>(buff_.data());
    }

    template <typename _RefT>
    std::enable_if_t<std::is_rvalue_reference<_RefT>::value>
    call_copy_or_move(const function_ptr_t& function, void* this_void_ptr, void* other_void_ptr)
    {
        function(operation_t::move, this_void_ptr, other_void_ptr);
    }

    template <typename _RefT>
    std::enable_if_t<!std::is_rvalue_reference<_RefT>::value>
    call_copy_or_move(const function_ptr_t& function, void* this_void_ptr, void* other_void_ptr)
    {
        function(operation_t::copy, this_void_ptr, other_void_ptr);
    }

    template<std::size_t _M,
             typename _X=std::enable_if_t<_M <= _N>>
    void copy_or_move_from_another(static_any<_M>&& another)
    {
        assert(function_ == nullptr);

        if (another.function_ == nullptr)
            return;

        void* other_data = reinterpret_cast<void*>(const_cast<char*>(another.buff_.data()));

        try {
            call_copy_or_move<static_any<_M>&&>(another.function_, buff_.data(), other_data);
        }
        catch(...) {
            throw;
        }

        function_= another.function_;
    }

    template<std::size_t _M,
             typename _X=std::enable_if_t<_M <= _N>>
    void assign_from_another(const static_any<_M>& another)
    {
        if (another.function_ == nullptr)
            return;

        void* other_data = reinterpret_cast<void*>(const_cast<char*>(another.buff_.data()));
        std::array<char, _N> buff;

        try {
            another.function_(operation_t::copy, buff.data(), other_data);
        }
        catch(...) {
            throw;
        }

        destroy();

        function_= another.function_;
        buff_ = buff;
    }

    std::array<char, _N> buff_;
    function_ptr_t function_ = nullptr;

    template<std::size_t _S>
    friend struct static_any;

    template<typename _ValueT, std::size_t _S>
    friend _ValueT* any_cast(static_any<_S>*);

    template<typename _ValueT, std::size_t _S>
    friend _ValueT& any_cast(static_any<_S>&);
};

struct bad_any_cast : public std::bad_cast
{
    bad_any_cast(const std::type_info& from,
                 const std::type_info& to)
    : from_(from),
      to_(to)
    {
        std::ostringstream oss;
        oss << "failed conversion using any_cast: stored type "
            << from.name()
            << ", trying to cast to "
            << to.name();
        reason_ = oss.str();
    }

    const std::type_info& stored_type() const { return from_; }
    const std::type_info& target_type() const { return to_; }

    virtual const char* what() const throw()
    {
        return reason_.c_str();
    }

private:
    const std::type_info& from_;
    const std::type_info& to_;
    std::string reason_;
};

template <typename _ValueT,
          std::size_t _S>
inline _ValueT* any_cast(static_any<_S>* a)
{
    if (!a->template has<_ValueT>())
        return nullptr;

    return a->template as<_ValueT>();
}

template <typename _ValueT,
          std::size_t _S>
inline const _ValueT* any_cast(const static_any<_S>* a)
{
    return any_cast<const _ValueT>(const_cast<static_any<_S>*>(a));
}

template <typename _ValueT,
          std::size_t _S>
inline _ValueT& any_cast(static_any<_S>& a)
{
    if (!a.template has<_ValueT>())
        throw bad_any_cast(a.type(), typeid(_ValueT));

    return *a.template as<_ValueT>();
}

template <typename _ValueT,
          std::size_t _S>
inline const _ValueT& any_cast(const static_any<_S>& a)
{
    return any_cast<const _ValueT>(const_cast<static_any<_S>&>(a));
}

template <std::size_t _S>
template <typename _T>
const _T& static_any<_S>::get() const
{
    return any_cast<_T>(*this);
}

template <std::size_t _S>
template <typename _T>
_T& static_any<_S>::get()
{
    return any_cast<_T>(*this);
}

template <std::size_t _N>
struct static_any_t
{
    typedef std::size_t size_type;

    static constexpr size_type capacity() { return _N; }

    static_any_t() = default;
    static_any_t(const static_any_t&) = default;

    template <typename _ValueT>
    static_any_t(_ValueT&& t)
    {
        copy(std::forward<_ValueT>(t));
    }

    template <typename _ValueT>
    static_any_t& operator=(_ValueT&& t)
    {
        copy(std::forward<_ValueT>(t));
        return *this;
    }

    template <typename _ValueT>
    _ValueT& get() { return *reinterpret_cast<_ValueT*>(buff_.data()); }

    template <typename _ValueT>
    const _ValueT& get() const { return *reinterpret_cast<const _ValueT*>(buff_.data()); }

private:
    template <typename _ValueT>
    void copy(_ValueT&& t)
    {
#if __GNUC__ >= 5
        static_assert(std::is_trivially_copyable<_ValueT>::value, "_ValueT is not trivially copyable");
#endif
        static_assert(capacity() >= sizeof(_ValueT), "_ValueT is too big to be copied to static_any");

        std::memcpy(buff_.data(), (char*)&t, sizeof(_ValueT));
    }

    std::array<char, _N> buff_;
};
<commit_msg>Cleanup<commit_after>#pragma once

#include <array>
#include <memory>
#include <cstring>
#include <type_traits>
#include <typeinfo>
#include <typeindex>
#include <cassert>
#include <sstream>
#include <string>

namespace detail { namespace static_any {

// Pointer to administrative function, function that will by type-specific, and will be able to perform all the required operations
enum class operation_t { query_type, query_size, copy, move, destroy };

using function_ptr_t = void(*)(operation_t operation, void* this_ptr, void* other_ptr);

template<typename _T>
static void operation(operation_t operation, void* ptr1, void* ptr2)
{
    _T* this_ptr = reinterpret_cast<_T*>(ptr1);

    switch(operation)
    {
        case operation_t::query_type:
        {
            *reinterpret_cast<const std::type_info**>(ptr1) = &typeid(_T);
            break;
        }
        case operation_t::query_size:
        {
            *reinterpret_cast<std::size_t*>(ptr1) = sizeof(_T);
            break;
        }
        case operation_t::copy:
        {
            _T* other_ptr = reinterpret_cast<_T*>(ptr2);
            assert(this_ptr);
            assert(other_ptr);
            new(this_ptr)_T(*other_ptr);
            break;
        }
        case operation_t::move:
        {    _T* other_ptr = reinterpret_cast<_T*>(ptr2);
            assert(this_ptr);
            assert(other_ptr);
            new(this_ptr)_T(std::move(*other_ptr));
            break;
        }
        case operation_t::destroy:
        {    assert(this_ptr);
            this_ptr->~_T();
            break;
        }
    }
}

template<typename _T>
static function_ptr_t get_function_for_type()
{
    return &static_any::operation<std::remove_cv_t<std::remove_reference_t<_T>>>;
}

}}

template <std::size_t _N>
struct static_any
{
    typedef std::size_t size_type;

    static_any() = default;

    ~static_any()
    {
        destroy();
    }

    template<typename _T>
    static_any(_T&& v)
    {
        copy_or_move(std::forward<_T>(v));
    }

    template<std::size_t _M>
    static_any(const static_any<_M>& another)
    {
        copy_or_move_from_another(another);
    }

    template<std::size_t _M>
    static_any(static_any<_M>& another)
    {
        copy_or_move_from_another(std::forward<static_any<_M>>(another));
    }

    template<std::size_t _M>
    static_any(static_any<_M>&& another)
    {
        copy_or_move_from_another(std::forward<static_any<_M>>(another));
    }

    static_any& operator=(const static_any& another)
    {
        assign_from_another(another);
        return *this;
    }

    static_any& operator=(static_any& another)
    {
        assign_from_another(another);
        return *this;
    }

    static_any& operator=(static_any&& another)
    {
        assign_from_another(another);
        return *this;
    }

    template<std::size_t _M>
    static_any& operator=(const static_any<_M>& another)
    {
        assign_from_another(another);
        return *this;
    }

    template<std::size_t _M>
    static_any& operator=(static_any<_M>& another)
    {
        assign_from_another(another);
        return *this;
    }

    template<std::size_t _M>
    static_any& operator=(static_any<_M>&& another)
    {
        assign_from_another(another);
        return *this;
    }

    template <typename _T>
    static_any& operator=(const _T& t)
    {
        assign(std::forward<_T>(t));
        return *this;
    }

    template <typename _T>
    static_any& operator=(_T&& t)
    {
        assign(std::forward<_T>(t));
        return *this;
    }

    inline void reset() { destroy(); }

    template<typename _T>
    inline const _T& get() const;

    template<typename _T>
    inline _T& get();

    template <typename _T>
    bool has() const
    {
        if (function_ == detail::static_any::get_function_for_type<_T>())
        {
            return true;
        }
        else if (function_)
        {
            // need to try another, possibly more costly way, as we may compare types across DLL boundaries
            return std::type_index(typeid(_T)) == std::type_index(query_type());
        }
        return false;
    }

    const std::type_info& type() const
    {
        if (empty())
            return typeid(void);
        else
            return query_type();
    }

    bool empty() const { return function_ == nullptr; }

    size_type size() const
    {
        if (empty())
            return 0;
        else
            return query_size();
    }

    static constexpr size_type capacity() { return _N; }

    // Initializes with object of type T, created in-place with specified constructor params
    template<typename _T, typename... Args>
    void emplace(Args&&... args)
    {
        destroy();
        new(buff_.data()) _T(std::forward<Args>(args)...);
        function_ = detail::static_any::get_function_for_type<_T>();
    }

private:
    using operation_t = detail::static_any::operation_t;
    using function_ptr_t = detail::static_any::function_ptr_t;

    template <typename _T>
    void copy_or_move(_T&& t)
    {
        static_assert(capacity() >= sizeof(_T), "_T is too big to be copied to static_any");
        assert(function_ == nullptr);

        using NonConstT = std::remove_cv_t<std::remove_reference_t<_T>>;
        NonConstT* non_const_t = const_cast<NonConstT*>(&t);

        try {
            call_copy_or_move<_T&&>(buff_.data(), non_const_t);
        }
        catch(...) {
            throw;
        }

        function_ = detail::static_any::get_function_for_type<_T>();
    }

    template <typename _T>
    void assign(_T&& t)
    {
        static_assert(capacity() >= sizeof(_T), "_T is too big to be copied to static_any");

        using NonConstT = std::remove_cv_t<std::remove_reference_t<_T>>;
        NonConstT* non_const_t = const_cast<NonConstT*>(&t);

        std::array<char, _N> buff;

        try {
            call_copy_or_move<_T&&>(buff.data(), non_const_t);
        }
        catch(...) {
            throw;
        }

        destroy();
        assert(function_ == nullptr);

        function_ = detail::static_any::get_function_for_type<_T>();
        buff_ = buff;
    }

    template <typename _RefT>
    std::enable_if_t<std::is_rvalue_reference<_RefT>::value>
    call_copy_or_move(void* this_void_ptr, void* other_void_ptr)
    {
        detail::static_any::get_function_for_type<_RefT>()(operation_t::move, this_void_ptr, other_void_ptr);
    }

    template <typename _RefT>
    std::enable_if_t<!std::is_rvalue_reference<_RefT>::value>
    call_copy_or_move(void* this_void_ptr, void* other_void_ptr)
    {
        detail::static_any::get_function_for_type<_RefT>()(operation_t::copy, this_void_ptr, other_void_ptr);
    }

    const std::type_info& query_type() const
    {
        assert(function_ != nullptr);
        const std::type_info* ti ;
        function_(operation_t::query_type, &ti, nullptr);
        return *ti;
    }

    size_type query_size() const
    {
        assert(function_ != nullptr);
        std::size_t size;
        function_(operation_t::query_size, &size, nullptr);
        return size;
    }

    void destroy()
    {
        if (function_)
        {
            void* not_used = nullptr;
            function_(operation_t::destroy, buff_.data(), not_used);
            function_ = nullptr;
        }
    }

    template<typename _T>
    const _T* as() const
    {
        return reinterpret_cast<const _T*>(buff_.data());
    }

    template<typename _T>
    _T* as()
    {
        return reinterpret_cast<_T*>(buff_.data());
    }

    template <typename _RefT>
    std::enable_if_t<std::is_rvalue_reference<_RefT>::value>
    call_copy_or_move(const function_ptr_t& function, void* this_void_ptr, void* other_void_ptr)
    {
        function(operation_t::move, this_void_ptr, other_void_ptr);
    }

    template <typename _RefT>
    std::enable_if_t<!std::is_rvalue_reference<_RefT>::value>
    call_copy_or_move(const function_ptr_t& function, void* this_void_ptr, void* other_void_ptr)
    {
        function(operation_t::copy, this_void_ptr, other_void_ptr);
    }

    template<std::size_t _M,
             typename _X=std::enable_if_t<_M <= _N>>
    void copy_or_move_from_another(static_any<_M>&& another)
    {
        assert(function_ == nullptr);

        if (another.function_ == nullptr)
            return;

        void* other_data = reinterpret_cast<void*>(const_cast<char*>(another.buff_.data()));

        try {
            call_copy_or_move<static_any<_M>&&>(another.function_, buff_.data(), other_data);
        }
        catch(...) {
            throw;
        }

        function_= another.function_;
    }

    template<std::size_t _M,
             typename _X=std::enable_if_t<_M <= _N>>
    void assign_from_another(const static_any<_M>& another)
    {
        if (another.function_ == nullptr)
            return;

        void* other_data = reinterpret_cast<void*>(const_cast<char*>(another.buff_.data()));
        std::array<char, _N> buff;

        try {
            another.function_(operation_t::copy, buff.data(), other_data);
        }
        catch(...) {
            throw;
        }

        destroy();

        function_= another.function_;
        buff_ = buff;
    }

    std::array<char, _N> buff_;
    function_ptr_t function_ = nullptr;

    template<std::size_t _S>
    friend struct static_any;

    template<typename _ValueT, std::size_t _S>
    friend _ValueT* any_cast(static_any<_S>*);

    template<typename _ValueT, std::size_t _S>
    friend _ValueT& any_cast(static_any<_S>&);
};

struct bad_any_cast : public std::bad_cast
{
    bad_any_cast(const std::type_info& from,
                 const std::type_info& to)
    : from_(from),
      to_(to)
    {
        std::ostringstream oss;
        oss << "failed conversion using any_cast: stored type "
            << from.name()
            << ", trying to cast to "
            << to.name();
        reason_ = oss.str();
    }

    const std::type_info& stored_type() const { return from_; }
    const std::type_info& target_type() const { return to_; }

    virtual const char* what() const throw()
    {
        return reason_.c_str();
    }

private:
    const std::type_info& from_;
    const std::type_info& to_;
    std::string reason_;
};

template <typename _ValueT,
          std::size_t _S>
inline _ValueT* any_cast(static_any<_S>* a)
{
    if (!a->template has<_ValueT>())
        return nullptr;

    return a->template as<_ValueT>();
}

template <typename _ValueT,
          std::size_t _S>
inline const _ValueT* any_cast(const static_any<_S>* a)
{
    return any_cast<const _ValueT>(const_cast<static_any<_S>*>(a));
}

template <typename _ValueT,
          std::size_t _S>
inline _ValueT& any_cast(static_any<_S>& a)
{
    if (!a.template has<_ValueT>())
        throw bad_any_cast(a.type(), typeid(_ValueT));

    return *a.template as<_ValueT>();
}

template <typename _ValueT,
          std::size_t _S>
inline const _ValueT& any_cast(const static_any<_S>& a)
{
    return any_cast<const _ValueT>(const_cast<static_any<_S>&>(a));
}

template <std::size_t _S>
template <typename _T>
const _T& static_any<_S>::get() const
{
    return any_cast<_T>(*this);
}

template <std::size_t _S>
template <typename _T>
_T& static_any<_S>::get()
{
    return any_cast<_T>(*this);
}

template <std::size_t _N>
struct static_any_t
{
    typedef std::size_t size_type;

    static constexpr size_type capacity() { return _N; }

    static_any_t() = default;
    static_any_t(const static_any_t&) = default;

    template <typename _ValueT>
    static_any_t(_ValueT&& t)
    {
        copy(std::forward<_ValueT>(t));
    }

    template <typename _ValueT>
    static_any_t& operator=(_ValueT&& t)
    {
        copy(std::forward<_ValueT>(t));
        return *this;
    }

    template <typename _ValueT>
    _ValueT& get() { return *reinterpret_cast<_ValueT*>(buff_.data()); }

    template <typename _ValueT>
    const _ValueT& get() const { return *reinterpret_cast<const _ValueT*>(buff_.data()); }

private:
    template <typename _ValueT>
    void copy(_ValueT&& t)
    {
#if __GNUC__ >= 5
        static_assert(std::is_trivially_copyable<_ValueT>::value, "_ValueT is not trivially copyable");
#endif
        static_assert(capacity() >= sizeof(_ValueT), "_ValueT is too big to be copied to static_any");

        std::memcpy(buff_.data(), (char*)&t, sizeof(_ValueT));
    }

    std::array<char, _N> buff_;
};
<|endoftext|>


<commit_before>#ifndef ANY_HPP
# define ANY_HPP

#include <algorithm>

#include <cassert>

#include <iostream>

#include <stdexcept>

#include <typeinfo>

#include <type_traits>

#include <utility>

namespace generic
{

class any
{
public:
  any() : content(nullptr) { }

  explicit any(any const& other)
    : content(other.content ? other.content->clone() : nullptr)
  {
  }

  explicit any(any&& other) { *this = std::move(other); }

  template<typename ValueType>
  any(ValueType&& value)
    : content(new holder<typename std::remove_reference<ValueType>::type>(
        std::forward<ValueType>(value)))
  {
  }

  ~any() { delete content; }

public: // modifiers

  void swap(any& other) { std::swap(content, other.content); }

  any& operator=(any const& rhs)
  {
    return *this = any(rhs);
  }

  any& operator=(any&& rhs)
  {
    content = rhs.content;
    rhs.content = nullptr;

    return *this;
  }

  template<typename ValueType>
  any& operator=(ValueType&& rhs)
  {
    return *this = any(std::forward<ValueType>(rhs));
  }

public: // queries

  explicit operator bool() const { return content; }

  std::type_info const& type() const
  {
    return content ? content->type() : typeid(void);
  }

private: // types

  struct placeholder
  {
    placeholder() = default;

    placeholder(placeholder const&) = delete;

    virtual ~placeholder() { }

    virtual placeholder* clone() const = 0;

    virtual std::type_info const& type() const = 0;

    placeholder& operator=(placeholder const&) = delete;
  };

  template<typename ValueType, typename = void>
  struct holder : public placeholder
  {
  public: // constructor
    template <class T>
    holder(T&& value) : held(std::forward<T>(value)) { }

    placeholder* clone() const final { throw std::invalid_argument(""); }

  public: // queries
    std::type_info const& type() const { return typeid(ValueType); }

  public:
    ValueType held;
  };

  template<typename ValueType>
  struct holder<
    ValueType,
    typename std::enable_if<
      std::is_copy_constructible<ValueType>::value
    >::type
  > : public placeholder
  {
  public: // constructor
    template <class T>
    holder(T&& value) : held(std::forward<T>(value)) { }

    placeholder* clone() const final { return new holder<ValueType>(held); }

  public: // queries
    std::type_info const& type() const { return typeid(ValueType); }

  public:
    ValueType held;
  };

private: // representation

  template<typename ValueType>
  friend ValueType* any_cast(any*);

  template<typename ValueType>
  friend ValueType* unsafe_any_cast(any *);

  placeholder* content;
};

template<typename ValueType>
inline ValueType* unsafe_any_cast(any* operand)
{
  return &static_cast<any::holder<ValueType>*>(operand->content)->held;
}

template<typename ValueType>
inline ValueType const* unsafe_any_cast(any const* operand)
{
  return unsafe_any_cast<ValueType>(const_cast<any*>(operand));
}

template<typename ValueType>
inline ValueType* any_cast(any* operand)
{
  return operand && (operand->type() == typeid(ValueType))
    ? &static_cast<any::holder<ValueType>*>(operand->content)->held
    : nullptr;
}

template<typename ValueType>
inline ValueType const* any_cast(any const* operand)
{
  return any_cast<ValueType>(const_cast<any*>(operand));
}

template<typename ValueType>
inline ValueType any_cast(any& operand)
{
  typedef typename std::remove_reference<ValueType>::type nonref;

#ifndef NDEBUG
  nonref* result(any_cast<nonref>(&operand));

  if (!result)
  {
    throw std::bad_cast();
  }
  // else do nothing

  return *result;
#else
  return *unsafe_any_cast<nonref>(&operand);
#endif // NDEBUG
}

template<typename ValueType>
inline ValueType any_cast(any const& operand)
{
  typedef typename std::remove_reference<ValueType>::type nonref;

  return any_cast<nonref const&>(const_cast<any&>(operand));
}

}

#endif // ANY_HPP
<commit_msg>some fixes<commit_after>#ifndef ANY_HPP
# define ANY_HPP

#include <algorithm>

#include <cassert>

#include <iostream>

#include <stdexcept>

#include <typeinfo>

#include <type_traits>

#include <utility>

namespace generic
{

class any
{
public:
  any() : content(nullptr) { }

  explicit any(any const& other)
    : content(other.content ? other.content->clone() : nullptr)
  {
  }

  explicit any(any&& other) { *this = std::move(other); }

  template<typename ValueType>
  any(ValueType&& value)
    : content(new holder<typename std::remove_reference<ValueType>::type>(
        std::forward<ValueType>(value)))
  {
  }

  ~any() { delete content; }

public: // modifiers

  void swap(any& other) { std::swap(content, other.content); }

  any& operator=(any const& rhs)
  {
    return *this = any(rhs);
  }

  any& operator=(any&& rhs)
  {
    content = rhs.content;
    rhs.content = nullptr;

    return *this;
  }

  template<typename ValueType>
  any& operator=(ValueType&& rhs)
  {
    return *this = any(std::forward<ValueType>(rhs));
  }

public: // queries

  explicit operator bool() const { return content; }

  std::type_info const& type() const
  {
    return content ? content->type() : typeid(void);
  }

private: // types

  struct placeholder
  {
    placeholder() = default;

    placeholder(placeholder const&) = delete;

    virtual ~placeholder() { }

    placeholder& operator=(placeholder const&) = delete;

    virtual placeholder* clone() const = 0;

    virtual std::type_info const& type() const = 0;
  };

  template<typename ValueType, typename = void>
  struct holder : public placeholder
  {
  public: // constructor
    template <class T>
    holder(T&& value) : held(std::forward<T>(value)) { }

    placeholder* clone() const final { throw std::invalid_argument(""); }

  public: // queries
    std::type_info const& type() const { return typeid(ValueType); }

  public:
    ValueType held;
  };

  template<typename ValueType>
  struct holder<
    ValueType,
    typename std::enable_if<
      std::is_copy_constructible<ValueType>::value
    >::type
  > : public placeholder
  {
  public: // constructor
    template <class T>
    holder(T&& value) : held(std::forward<T>(value)) { }

    placeholder* clone() const final { return new holder<ValueType>(held); }

  public: // queries
    std::type_info const& type() const { return typeid(ValueType); }

  public:
    ValueType held;
  };

private: // representation

  template<typename ValueType>
  friend ValueType* any_cast(any*);

  template<typename ValueType>
  friend ValueType* unsafe_any_cast(any *);

  placeholder* content;
};

template<typename ValueType>
inline ValueType* unsafe_any_cast(any* const operand)
{
  return &static_cast<any::holder<ValueType>*>(operand->content)->held;
}

template<typename ValueType>
inline ValueType const* unsafe_any_cast(any const* const operand)
{
  return unsafe_any_cast<ValueType>(const_cast<any*>(operand));
}

template<typename ValueType>
inline ValueType* any_cast(any* const operand)
{
  return operand && (operand->type() == typeid(ValueType))
    ? &static_cast<any::holder<ValueType>*>(operand->content)->held
    : nullptr;
}

template<typename ValueType>
inline ValueType const* any_cast(any const* const operand)
{
  return any_cast<ValueType>(const_cast<any*>(operand));
}

template<typename ValueType>
inline ValueType any_cast(any& operand)
{
  typedef typename std::remove_reference<ValueType>::type nonref;

#ifndef NDEBUG
  nonref* result(any_cast<nonref>(&operand));

  if (!result)
  {
    throw std::bad_cast();
  }
  // else do nothing

  return *result;
#else
  return *unsafe_any_cast<nonref>(&operand);
#endif // NDEBUG
}

template<typename ValueType>
inline ValueType any_cast(any const& operand)
{
  typedef typename std::remove_reference<ValueType>::type nonref;

  return any_cast<nonref const&>(const_cast<any&>(operand));
}

}

#endif // ANY_HPP
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if !defined(MEMORYMANAGERIMPL_HEADER_GUARD_1357924680)
#define MEMORYMANAGERIMPL_HEADER_GUARD_1357924680

// Base include file.  Must be first.
#include <new>

#include <xalanc/Include/PlatformDefinitions.hpp>

#include <xercesc/framework/MemoryManager.hpp>

#if defined(XALAN_WINDOWS)
#include <windows.h>
#include <stdexcept>
#include <stdlib.h>

class XalanMemoryManagerImpl : public XALAN_CPP_NAMESPACE_QUALIFIER MemoryManagerType
{
public:

    XalanMemoryManagerImpl( DWORD defSize = 0 ) :
	    m_heapHandle(NULL)
	{
		m_heapHandle = HeapCreate(	HEAP_NO_SERIALIZE,
		                            0, // dwInitialSize
		                            defSize);

        if( m_heapHandle == NULL )
		{
            XALAN_USING_STD(runtime_error)

            char buffer[20];
            buffer[0] = 0;

            _ultoa( GetLastError(), buffer, 10);

            throw runtime_error(buffer);
		}
	}

	virtual void*
	allocate( size_t size )
    {
        LPVOID ptr = HeapAlloc(
                        m_heapHandle,   //HANDLE hHeap
                        0,              //DWORD dwFlags
                        size            //SIZE_T dwBytes
                        );

        if( ptr == 0)
        {
            XALAN_USING_STD(bad_alloc)

            throw bad_alloc();
        }

        return ptr;
    }

	virtual void
	deallocate(  void* 	pDataPointer  )
	{
        if ( 0 == HeapFree(
                        m_heapHandle,   //HANDLE hHeap,
                        0,              //DWORD dwFlags,
                        pDataPointer ) )//*LPVOID lpMem
        {
            XALAN_USING_STD(bad_alloc)

            throw bad_alloc();
        }
    }

    MemoryManager*
    getExceptionMemoryManager()
    {
        return this;
    }

    virtual
	~XalanMemoryManagerImpl()
	{
       if( 0 == HeapDestroy(m_heapHandle) )
       {
            XALAN_USING_STD(runtime_error)

            char buffer[20];
            buffer[0] = 0;

            _ultoa( GetLastError(), buffer, 10);

            throw runtime_error(buffer);
       }
	}

private:

    // Not implemented
	XalanMemoryManagerImpl&
	operator=(const XalanMemoryManagerImpl&);

	XalanMemoryManagerImpl(const XalanMemoryManagerImpl&);

	//Data
	HANDLE  m_heapHandle;
};

#else

class XalanMemoryManagerImpl : public XALAN_CPP_NAMESPACE_QUALIFIER MemoryManagerType
{
public:

    virtual
	~XalanMemoryManagerImpl()
	{
	}

	virtual void*
	allocate( size_t 	size )
	{
	    void* memptr = ::operator new(size);

	    if (memptr != NULL)
	    {
	        return memptr;
	    }

		XALAN_USING_STD(bad_alloc)

		throw bad_alloc();
	}
	virtual void
	deallocate(  void* 		pDataPointer  )
	{
		operator delete(pDataPointer);
	}
};

#endif

#endif  // MEMORYMANAGERIMPL_HEADER_GUARD_1357924680
<commit_msg>Changes for compatibility with the updated Xerces-C MemoryManager class.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if !defined(MEMORYMANAGERIMPL_HEADER_GUARD_1357924680)
#define MEMORYMANAGERIMPL_HEADER_GUARD_1357924680

// Base include file.  Must be first.
#include <new>

#include <xalanc/Include/PlatformDefinitions.hpp>

#include <xercesc/framework/MemoryManager.hpp>

#if defined(XALAN_WINDOWS)
#include <windows.h>
#include <stdexcept>
#include <stdlib.h>

class XalanMemoryManagerImpl : public XALAN_CPP_NAMESPACE_QUALIFIER MemoryManagerType
{
public:

    XalanMemoryManagerImpl( DWORD defSize = 0 ) :
	    m_heapHandle(NULL)
	{
		m_heapHandle = HeapCreate(	HEAP_NO_SERIALIZE,
		                            0, // dwInitialSize
		                            defSize);

        if( m_heapHandle == NULL )
		{
            XALAN_USING_STD(runtime_error)

            char buffer[20];
            buffer[0] = 0;

            _ultoa( GetLastError(), buffer, 10);

            throw runtime_error(buffer);
		}
	}

	virtual void*
	allocate( size_t size )
    {
        LPVOID ptr = HeapAlloc(
                        m_heapHandle,   //HANDLE hHeap
                        0,              //DWORD dwFlags
                        size            //SIZE_T dwBytes
                        );

        if( ptr == 0)
        {
            XALAN_USING_STD(bad_alloc)

            throw bad_alloc();
        }

        return ptr;
    }

	virtual void
	deallocate(  void* 	pDataPointer  )
	{
        if ( 0 == HeapFree(
                        m_heapHandle,   //HANDLE hHeap,
                        0,              //DWORD dwFlags,
                        pDataPointer ) )//*LPVOID lpMem
        {
            XALAN_USING_STD(bad_alloc)

            throw bad_alloc();
        }
    }

    MemoryManager*
    getExceptionMemoryManager()
    {
        return this;
    }

    virtual
	~XalanMemoryManagerImpl()
	{
       if( 0 == HeapDestroy(m_heapHandle) )
       {
            XALAN_USING_STD(runtime_error)

            char buffer[20];
            buffer[0] = 0;

            _ultoa( GetLastError(), buffer, 10);

            throw runtime_error(buffer);
       }
	}

private:

    // Not implemented
	XalanMemoryManagerImpl&
	operator=(const XalanMemoryManagerImpl&);

	XalanMemoryManagerImpl(const XalanMemoryManagerImpl&);

	//Data
	HANDLE  m_heapHandle;
};

#else

class XalanMemoryManagerImpl : public XALAN_CPP_NAMESPACE_QUALIFIER MemoryManagerType
{
public:

    virtual
	~XalanMemoryManagerImpl()
	{
	}

	virtual void*
	allocate( size_t 	size )
	{
	    void* memptr = ::operator new(size);

	    if (memptr != NULL)
	    {
	        return memptr;
	    }

		XALAN_USING_STD(bad_alloc)

		throw bad_alloc();
	}
	virtual void
	deallocate(  void* 		pDataPointer  )
	{
		operator delete(pDataPointer);
	}

    MemoryManager*
    getExceptionMemoryManager()
    {
        return this;
    }
};

#endif

#endif  // MEMORYMANAGERIMPL_HEADER_GUARD_1357924680
<|endoftext|>


<commit_before>//
//  CRTC6845.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 31/07/2017.
//  Copyright © 2017 Thomas Harte. All rights reserved.
//

#ifndef CRTC6845_hpp
#define CRTC6845_hpp

#include "../../ClockReceiver/ClockReceiver.hpp"

#include <cstdint>
#include <cstdio>

namespace Motorola {
namespace CRTC {

struct BusState {
	bool display_enable;
	bool hsync;
	bool vsync;
	bool cursor;
	uint16_t refresh_address;
	uint16_t row_address;
};

class BusHandler {
	public:
		/*!
			Performs the first phase of a 6845 bus cycle; this is the phase in which it is intended that
			systems using the 6845 respect the bus state and produce pixels, sync or whatever they require.
		*/
		void perform_bus_cycle_phase1(const BusState &) {}

		/*!
			Performs the second phase of a 6845 bus cycle. Some bus state — including sync — is updated
			directly after phase 1 and hence is visible to an observer during phase 2. Handlers may therefore
			implement @c perform_bus_cycle_phase2 to be notified of the availability of that state without
			having to wait until the next cycle has begun.
		*/
		void perform_bus_cycle_phase2(const BusState &) {}
};

enum Personality {
	HD6845S,	// Type 0 in CPC parlance. Zero-width HSYNC available, no status, programmable VSYNC length.
	UM6845R,	// Type 1 in CPC parlance. Status register, fixed-length VSYNC.
	MC6845,		// Type 2. No status register, fixed-length VSYNC, no zero-length HSYNC.
	AMS40226	// Type 3. Status is get register, fixed-length VSYNC, no zero-length HSYNC.
};

// TODO UM6845R and R12/R13; see http://www.cpcwiki.eu/index.php/CRTC#CRTC_Differences

template <class T> class CRTC6845 {
	public:

		CRTC6845(Personality p, T &bus_handler) noexcept :
			personality_(p), bus_handler_(bus_handler), status_(0) {}

		void select_register(uint8_t r) {
			selected_register_ = r;
		}

		uint8_t get_status() const {
			switch(personality_) {
				case UM6845R:	return status_ | (bus_state_.vsync ? 0x20 : 0x00);
				case AMS40226:	return get_register();
				default:		return 0xff;
			}
			return 0xff;
		}

		uint8_t get_register() const {
			if(selected_register_ == 31) status_ &= ~0x80;
			if(selected_register_ == 16 || selected_register_ == 17) status_ &= ~0x40;

			if(personality_ == UM6845R && selected_register_ == 31) return dummy_register_;
			if(selected_register_ < 12 || selected_register_ > 17) return 0xff;
			return registers_[selected_register_];
		}

		void set_register(uint8_t value) {
			static uint8_t masks[] = {
				0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f,
				0xff, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff
			};

			if(selected_register_ < 16) {
				registers_[selected_register_] = value & masks[selected_register_];
			}
			if(selected_register_ == 31 && personality_ == UM6845R) {
				dummy_register_ = value;
			}
		}

		void trigger_light_pen() {
			registers_[17] = bus_state_.refresh_address & 0xff;
			registers_[16] = bus_state_.refresh_address >> 8;
			status_ |= 0x40;
		}

		void run_for(Cycles cycles) {
			int cyles_remaining = cycles.as_int();
			while(cyles_remaining--) {
				// check for end of visible characters
				if(character_counter_ == registers_[1]) {
					// TODO: consider skew in character_is_visible_. Or maybe defer until perform_bus_cycle?
					character_is_visible_ = false;
					end_of_line_address_ = bus_state_.refresh_address;
				}

				perform_bus_cycle_phase1();
				bus_state_.refresh_address = (bus_state_.refresh_address + 1) & 0x3fff;

				// check for end-of-line
				if(character_counter_ == registers_[0]) {
					character_counter_ = 0;
					do_end_of_line();
					character_is_visible_ = true;
				} else {
					// increment counter
					character_counter_++;
				}

				// check for start of horizontal sync
				if(character_counter_ == registers_[2]) {
					hsync_counter_ = 0;
					bus_state_.hsync = true;
				}

				// check for end of horizontal sync; note that a sync time of zero will result in an immediate
				// cancellation of the plan to perform sync
				if(bus_state_.hsync) {
					switch(personality_) {
						case HD6845S:
						case UM6845R:
							bus_state_.hsync = hsync_counter_ != (registers_[3] & 15);
							hsync_counter_ = (hsync_counter_ + 1) & 15;
						break;
						default:
							hsync_counter_ = (hsync_counter_ + 1) & 15;
							bus_state_.hsync = hsync_counter_ != (registers_[3] & 15);
						break;
					}
				}

				perform_bus_cycle_phase2();
			}
		}

		const BusState &get_bus_state() const {
			return bus_state_;
		}

	private:
		inline void perform_bus_cycle_phase1() {
			bus_state_.display_enable = character_is_visible_ && line_is_visible_;
			bus_handler_.perform_bus_cycle_phase1(bus_state_);
		}

		inline void perform_bus_cycle_phase2() {
			bus_state_.display_enable = character_is_visible_ && line_is_visible_;
			bus_handler_.perform_bus_cycle_phase2(bus_state_);
		}

		inline void do_end_of_line() {
			// check for end of vertical sync
			if(bus_state_.vsync) {
				vsync_counter_ = (vsync_counter_ + 1) & 15;
				switch(personality_) {
					case HD6845S:
					case AMS40226:
						bus_state_.vsync = vsync_counter_ != (registers_[3] >> 4);
					break;
					default:
						bus_state_.vsync = vsync_counter_ != 0;
					break;
				}
			}

			if(is_in_adjustment_period_) {
				line_counter_++;
				if(line_counter_ == registers_[5]) {
					is_in_adjustment_period_ = false;
					do_end_of_frame();
				}
			} else {
				// advance vertical counter
				if(bus_state_.row_address == registers_[9]) {
					bus_state_.row_address = 0;
					line_address_ = end_of_line_address_;

					// check for entry into the overflow area
					if(line_counter_ == registers_[4]) {
						if(registers_[5]) {
							line_counter_ = 0;
							is_in_adjustment_period_ = true;
						} else {
							do_end_of_frame();
						}
					} else {
						line_counter_ = (line_counter_ + 1) & 0x7f;

						// check for start of vertical sync
						if(line_counter_ == registers_[7]) {
							bus_state_.vsync = true;
							vsync_counter_ = 0;
						}

						// check for end of visible lines
						if(line_counter_ == registers_[6]) {
							line_is_visible_ = false;
						}
					}
				} else {
					bus_state_.row_address = (bus_state_.row_address + 1) & 0x1f;
				}
			}

			bus_state_.refresh_address = line_address_;
			character_counter_ = 0;
			character_is_visible_ = (registers_[1] != 0);
		}

		inline void do_end_of_frame() {
			line_counter_ = 0;
			line_is_visible_ = true;
			line_address_ = (uint16_t)((registers_[12] << 8) | registers_[13]);
			bus_state_.refresh_address = line_address_;
		}

		Personality personality_;
		T &bus_handler_;
		BusState bus_state_;

		uint8_t registers_[18];
		uint8_t dummy_register_;
		int selected_register_;

		uint8_t character_counter_;
		uint8_t line_counter_;

		bool character_is_visible_, line_is_visible_;

		int hsync_counter_;
		int vsync_counter_;
		bool is_in_adjustment_period_;

		uint16_t line_address_;
		uint16_t end_of_line_address_;
		uint8_t status_;
};

}
}

#endif /* CRTC6845_hpp */
<commit_msg>Improved comments.<commit_after>//
//  CRTC6845.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 31/07/2017.
//  Copyright © 2017 Thomas Harte. All rights reserved.
//

#ifndef CRTC6845_hpp
#define CRTC6845_hpp

#include "../../ClockReceiver/ClockReceiver.hpp"

#include <cstdint>
#include <cstdio>

namespace Motorola {
namespace CRTC {

struct BusState {
	bool display_enable;
	bool hsync;
	bool vsync;
	bool cursor;
	uint16_t refresh_address;
	uint16_t row_address;
};

class BusHandler {
	public:
		/*!
			Performs the first phase of a 6845 bus cycle; this is the phase in which it is intended that
			systems using the 6845 respect the bus state and produce pixels, sync or whatever they require.
		*/
		void perform_bus_cycle_phase1(const BusState &) {}

		/*!
			Performs the second phase of a 6845 bus cycle. Some bus state — including sync — is updated
			directly after phase 1 and hence is visible to an observer during phase 2. Handlers may therefore
			implement @c perform_bus_cycle_phase2 to be notified of the availability of that state without
			having to wait until the next cycle has begun.
		*/
		void perform_bus_cycle_phase2(const BusState &) {}
};

enum Personality {
	HD6845S,	// Type 0 in CPC parlance. Zero-width HSYNC available, no status, programmable VSYNC length.
	UM6845R,	// Type 1 in CPC parlance. Status register, fixed-length VSYNC.
	MC6845,		// Type 2. No status register, fixed-length VSYNC, no zero-length HSYNC.
	AMS40226	// Type 3. Status is get register, fixed-length VSYNC, no zero-length HSYNC.
};

// TODO UM6845R and R12/R13; see http://www.cpcwiki.eu/index.php/CRTC#CRTC_Differences

template <class T> class CRTC6845 {
	public:

		CRTC6845(Personality p, T &bus_handler) noexcept :
			personality_(p), bus_handler_(bus_handler), status_(0) {}

		void select_register(uint8_t r) {
			selected_register_ = r;
		}

		uint8_t get_status() const {
			switch(personality_) {
				case UM6845R:	return status_ | (bus_state_.vsync ? 0x20 : 0x00);
				case AMS40226:	return get_register();
				default:		return 0xff;
			}
			return 0xff;
		}

		uint8_t get_register() const {
			if(selected_register_ == 31) status_ &= ~0x80;
			if(selected_register_ == 16 || selected_register_ == 17) status_ &= ~0x40;

			if(personality_ == UM6845R && selected_register_ == 31) return dummy_register_;
			if(selected_register_ < 12 || selected_register_ > 17) return 0xff;
			return registers_[selected_register_];
		}

		void set_register(uint8_t value) {
			static uint8_t masks[] = {
				0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f,
				0xff, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff
			};

			if(selected_register_ < 16) {
				registers_[selected_register_] = value & masks[selected_register_];
			}
			if(selected_register_ == 31 && personality_ == UM6845R) {
				dummy_register_ = value;
			}
		}

		void trigger_light_pen() {
			registers_[17] = bus_state_.refresh_address & 0xff;
			registers_[16] = bus_state_.refresh_address >> 8;
			status_ |= 0x40;
		}

		void run_for(Cycles cycles) {
			int cyles_remaining = cycles.as_int();
			while(cyles_remaining--) {
				// check for end of visible characters
				if(character_counter_ == registers_[1]) {
					// TODO: consider skew in character_is_visible_. Or maybe defer until perform_bus_cycle?
					character_is_visible_ = false;
					end_of_line_address_ = bus_state_.refresh_address;
				}

				perform_bus_cycle_phase1();
				bus_state_.refresh_address = (bus_state_.refresh_address + 1) & 0x3fff;

				// check for end-of-line
				if(character_counter_ == registers_[0]) {
					character_counter_ = 0;
					do_end_of_line();
					character_is_visible_ = true;
				} else {
					// increment counter
					character_counter_++;
				}

				// check for start of horizontal sync
				if(character_counter_ == registers_[2]) {
					hsync_counter_ = 0;
					bus_state_.hsync = true;
				}

				// check for end of horizontal sync; note that a sync time of zero will result in an immediate
				// cancellation of the plan to perform sync if this is an HD6845S or UM6845R; otherwise zero
				// will end up counting as 16 as it won't be checked until after overflow.
				if(bus_state_.hsync) {
					switch(personality_) {
						case HD6845S:
						case UM6845R:
							bus_state_.hsync = hsync_counter_ != (registers_[3] & 15);
							hsync_counter_ = (hsync_counter_ + 1) & 15;
						break;
						default:
							hsync_counter_ = (hsync_counter_ + 1) & 15;
							bus_state_.hsync = hsync_counter_ != (registers_[3] & 15);
						break;
					}
				}

				perform_bus_cycle_phase2();
			}
		}

		const BusState &get_bus_state() const {
			return bus_state_;
		}

	private:
		inline void perform_bus_cycle_phase1() {
			bus_state_.display_enable = character_is_visible_ && line_is_visible_;
			bus_handler_.perform_bus_cycle_phase1(bus_state_);
		}

		inline void perform_bus_cycle_phase2() {
			bus_state_.display_enable = character_is_visible_ && line_is_visible_;
			bus_handler_.perform_bus_cycle_phase2(bus_state_);
		}

		inline void do_end_of_line() {
			// check for end of vertical sync
			if(bus_state_.vsync) {
				vsync_counter_ = (vsync_counter_ + 1) & 15;
				// on the UM6845R and AMS40226, honour the programmed vertical sync time; on the other CRTCs
				// always use a vertical sync count of 16.
				switch(personality_) {
					case HD6845S:
					case AMS40226:
						bus_state_.vsync = vsync_counter_ != (registers_[3] >> 4);
					break;
					default:
						bus_state_.vsync = vsync_counter_ != 0;
					break;
				}
			}

			if(is_in_adjustment_period_) {
				line_counter_++;
				if(line_counter_ == registers_[5]) {
					is_in_adjustment_period_ = false;
					do_end_of_frame();
				}
			} else {
				// advance vertical counter
				if(bus_state_.row_address == registers_[9]) {
					bus_state_.row_address = 0;
					line_address_ = end_of_line_address_;

					// check for entry into the overflow area
					if(line_counter_ == registers_[4]) {
						if(registers_[5]) {
							line_counter_ = 0;
							is_in_adjustment_period_ = true;
						} else {
							do_end_of_frame();
						}
					} else {
						line_counter_ = (line_counter_ + 1) & 0x7f;

						// check for start of vertical sync
						if(line_counter_ == registers_[7]) {
							bus_state_.vsync = true;
							vsync_counter_ = 0;
						}

						// check for end of visible lines
						if(line_counter_ == registers_[6]) {
							line_is_visible_ = false;
						}
					}
				} else {
					bus_state_.row_address = (bus_state_.row_address + 1) & 0x1f;
				}
			}

			bus_state_.refresh_address = line_address_;
			character_counter_ = 0;
			character_is_visible_ = (registers_[1] != 0);
		}

		inline void do_end_of_frame() {
			line_counter_ = 0;
			line_is_visible_ = true;
			line_address_ = (uint16_t)((registers_[12] << 8) | registers_[13]);
			bus_state_.refresh_address = line_address_;
		}

		Personality personality_;
		T &bus_handler_;
		BusState bus_state_;

		uint8_t registers_[18];
		uint8_t dummy_register_;
		int selected_register_;

		uint8_t character_counter_;
		uint8_t line_counter_;

		bool character_is_visible_, line_is_visible_;

		int hsync_counter_;
		int vsync_counter_;
		bool is_in_adjustment_period_;

		uint16_t line_address_;
		uint16_t end_of_line_address_;
		uint8_t status_;
};

}
}

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


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "DebugOperatorNew.h"

#include "UiConsoleManager.h"
#include "ui_ConsoleWidget.h"
#include "ConsoleProxyWidget.h"
#include "ConsoleAPI.h"

#include "UiAPI.h"
#include "UiProxyWidget.h"
#include "UiGraphicsView.h"
#include "EventManager.h"
#include "Framework.h"

#include <QGraphicsView>
#include <QString>
#include <QRegExp>
#include <QRectF>

#include "MemoryLeakCheck.h"

UiConsoleManager::UiConsoleManager(Foundation::Framework *fw) :
    framework(fw),
    graphicsView(fw->Ui()->GraphicsView()),
    consoleUi(0),
    consoleWidget(0),
    proxyWidget(0),
    visible(false),
    commandHistoryIndex(-1)
{
    if (framework->IsHeadless())
        return;

    consoleUi = new Ui::ConsoleWidget();
    consoleWidget = new QWidget();

    // Init internals
    consoleUi->setupUi(consoleWidget);

    proxyWidget = framework->Ui()->AddWidgetToScene(consoleWidget);
    proxyWidget->setMinimumHeight(0);
    proxyWidget->setGeometry(QRect(0, 0, graphicsView->width(), 0));
    proxyWidget->setOpacity(0.8); ///<\todo Read opacity from config?
    proxyWidget->setZValue(20000);

    connect(framework->Ui()->GraphicsView(), SIGNAL(sceneRectChanged(const QRectF&)), SLOT(AdjustToSceneRect(const QRectF&)));

    // Init animation
    slideAnimation.setTargetObject(proxyWidget);
    slideAnimation.setPropertyName("geometry");
    slideAnimation.setDuration(300);  ///<\todo Read animation speed from config?

    connect(consoleUi->ConsoleInputArea, SIGNAL(returnPressed()), SLOT(HandleInput()));

    consoleUi->ConsoleInputArea->installEventFilter(this);
}

UiConsoleManager::~UiConsoleManager()
{
    // consoleWidget gets deleted by the scene it is in currently
    if (consoleUi)
        SAFE_DELETE(consoleUi);
}

void UiConsoleManager::PrintToConsole(const QString &text)
{
    if (framework->IsHeadless())
        return;
    QString html = Qt::escape(text);
    DecorateString(html);
    consoleUi->ConsoleTextArea->appendHtml(html);
}

void UiConsoleManager::ToggleConsole()
{
    if (framework->IsHeadless())
        return;
    if (!graphicsView)
        return;

    QGraphicsScene *current_scene = proxyWidget->scene();
    if (!current_scene)
        return;

    visible = !visible;
    int current_height = graphicsView->height()*0.5;
    if (visible)
    {
        slideAnimation.setStartValue(QRect(0, 0, graphicsView->width(), 0));
        slideAnimation.setEndValue(QRect(0, 0, graphicsView->width(), current_height));
        // Not bringing to front, works in UiProxyWidgets, hmm...
        current_scene->setActiveWindow(proxyWidget);
        current_scene->setFocusItem(proxyWidget, Qt::ActiveWindowFocusReason);
        consoleUi->ConsoleInputArea->setFocus(Qt::MouseFocusReason);
        proxyWidget->show();
    }
    else
    {
        slideAnimation.setStartValue(QRect(0, 0, graphicsView->width(), current_height));
        slideAnimation.setEndValue(QRect(0, 0, graphicsView->width(), 0));
        proxyWidget->hide();
    }

    slideAnimation.start();
}

void UiConsoleManager::HandleInput()
{
    if (framework->IsHeadless())
        return;

    QString cmd = consoleUi->ConsoleInputArea->text();
    framework->Console()->ExecuteCommand(cmd);
    consoleUi->ConsoleInputArea->clear();

    commandHistory.push_front(cmd);
}

void UiConsoleManager::AdjustToSceneRect(const QRectF& rect)
{
    if (visible)
    {
        QRectF new_size = rect;
        new_size.setHeight(rect.height() * 0.5); ///<\todo Read height from config?
        proxyWidget->setGeometry(new_size);
    }
    else
    {
        proxyWidget->hide();
    }
}

bool UiConsoleManager::eventFilter(QObject *obj, QEvent *e)
{
    if (e->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = dynamic_cast<QKeyEvent*>(e);
        if (keyEvent)
        {
//            if (keyEvent->isAutoRepeat())
//                return true;

            switch(keyEvent->key())
            {
            case Qt::Key_Up:
            {
                if (commandHistoryIndex+1 < commandHistory.size())
                    consoleUi->ConsoleInputArea->setText(commandHistory[++commandHistoryIndex]);
                return true;
            }
            case Qt::Key_Down:
            {
                --commandHistoryIndex;
                if (commandHistoryIndex < 0)
                    commandHistoryIndex = -1;

                if (commandHistoryIndex == -1)
                    consoleUi->ConsoleInputArea->clear(); // Putty-like behavior: clear line edit.
                else if (commandHistoryIndex > -1 && commandHistoryIndex < commandHistory.size()-1)
                        consoleUi->ConsoleInputArea->setText(commandHistory[commandHistoryIndex]);
                return true;
            }
            ///\todo Autocompletion/suggestion
            //case Qt::Key_Tab:
            default:
                return QObject::eventFilter(obj, e);
            }
        }
    }

    return QObject::eventFilter(obj, e);
}

void UiConsoleManager::DecorateString(QString &str)
{
    // Make all timestamp + module name blocks white
    int block_end_index = str.indexOf("]");
    if (block_end_index != -1)
    {
        QString span_start("");
        QString span_end("");
        block_end_index += span_start.length() + 1;
        str.insert(0, "");
        str.insert(block_end_index, "");
        block_end_index += span_end.length();
    }
    else
        block_end_index = 0;

    QRegExp regexp;
    regexp.setPattern(".*Debug:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Notice:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Warning:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Error:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Critical:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Fatal:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }
}
<commit_msg>Fix erroneous signal-slot connection.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "DebugOperatorNew.h"

#include "UiConsoleManager.h"
#include "ui_ConsoleWidget.h"
#include "ConsoleProxyWidget.h"
#include "ConsoleAPI.h"

#include "UiAPI.h"
#include "UiProxyWidget.h"
#include "UiGraphicsView.h"
#include "EventManager.h"
#include "Framework.h"

#include <QGraphicsView>
#include <QString>
#include <QRegExp>
#include <QRectF>

#include "MemoryLeakCheck.h"

UiConsoleManager::UiConsoleManager(Foundation::Framework *fw) :
    framework(fw),
    graphicsView(fw->Ui()->GraphicsView()),
    consoleUi(0),
    consoleWidget(0),
    proxyWidget(0),
    visible(false),
    commandHistoryIndex(-1)
{
    if (framework->IsHeadless())
        return;

    consoleUi = new Ui::ConsoleWidget();
    consoleWidget = new QWidget();

    // Init internals
    consoleUi->setupUi(consoleWidget);

    proxyWidget = framework->Ui()->AddWidgetToScene(consoleWidget);
    proxyWidget->setMinimumHeight(0);
    proxyWidget->setGeometry(QRect(0, 0, graphicsView->width(), 0));
    /// \todo Opacity has no effect atm.
    proxyWidget->setOpacity(0.8); ///<\todo Read opacity from config?
    proxyWidget->setZValue(20000);

    connect(framework->Ui()->GraphicsScene(), SIGNAL(sceneRectChanged(const QRectF&)), SLOT(AdjustToSceneRect(const QRectF&)));

    // Init animation
    slideAnimation.setTargetObject(proxyWidget);
    slideAnimation.setPropertyName("geometry");
    slideAnimation.setDuration(300);  ///<\todo Read animation speed from config?

    connect(consoleUi->ConsoleInputArea, SIGNAL(returnPressed()), SLOT(HandleInput()));

    consoleUi->ConsoleInputArea->installEventFilter(this);
}

UiConsoleManager::~UiConsoleManager()
{
    // consoleWidget gets deleted by the scene it is in currently
    if (consoleUi)
        SAFE_DELETE(consoleUi);
}

void UiConsoleManager::PrintToConsole(const QString &text)
{
    if (framework->IsHeadless())
        return;
    QString html = Qt::escape(text);
    DecorateString(html);
    consoleUi->ConsoleTextArea->appendHtml(html);
}

void UiConsoleManager::ToggleConsole()
{
    if (framework->IsHeadless())
        return;
    if (!graphicsView)
        return;

    QGraphicsScene *current_scene = proxyWidget->scene();
    if (!current_scene)
        return;

    visible = !visible;
    int current_height = graphicsView->height()*0.5;
    if (visible)
    {
        slideAnimation.setStartValue(QRect(0, 0, graphicsView->width(), 0));
        slideAnimation.setEndValue(QRect(0, 0, graphicsView->width(), current_height));
        // Not bringing to front, works in UiProxyWidgets, hmm...
        current_scene->setActiveWindow(proxyWidget);
        current_scene->setFocusItem(proxyWidget, Qt::ActiveWindowFocusReason);
        consoleUi->ConsoleInputArea->setFocus(Qt::MouseFocusReason);
        proxyWidget->show();
    }
    else
    {
        slideAnimation.setStartValue(QRect(0, 0, graphicsView->width(), current_height));
        slideAnimation.setEndValue(QRect(0, 0, graphicsView->width(), 0));
        proxyWidget->hide();
    }

    slideAnimation.start();
}

void UiConsoleManager::HandleInput()
{
    if (framework->IsHeadless())
        return;

    QString cmd = consoleUi->ConsoleInputArea->text();
    framework->Console()->ExecuteCommand(cmd);
    consoleUi->ConsoleInputArea->clear();

    commandHistory.push_front(cmd);
}

void UiConsoleManager::AdjustToSceneRect(const QRectF& rect)
{
    if (visible)
    {
        QRectF new_size = rect;
        new_size.setHeight(rect.height() * 0.5); ///<\todo Read height from config?
        proxyWidget->setGeometry(new_size);
    }
    else
    {
        proxyWidget->hide();
    }
}

bool UiConsoleManager::eventFilter(QObject *obj, QEvent *e)
{
    if (e->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = dynamic_cast<QKeyEvent*>(e);
        if (keyEvent)
        {
//            if (keyEvent->isAutoRepeat())
//                return true;

            switch(keyEvent->key())
            {
            case Qt::Key_Up:
            {
                if (commandHistoryIndex+1 < commandHistory.size())
                    consoleUi->ConsoleInputArea->setText(commandHistory[++commandHistoryIndex]);
                return true;
            }
            case Qt::Key_Down:
            {
                --commandHistoryIndex;
                if (commandHistoryIndex < 0)
                    commandHistoryIndex = -1;

                if (commandHistoryIndex == -1)
                    consoleUi->ConsoleInputArea->clear(); // Putty-like behavior: clear line edit.
                else if (commandHistoryIndex > -1 && commandHistoryIndex < commandHistory.size()-1)
                        consoleUi->ConsoleInputArea->setText(commandHistory[commandHistoryIndex]);
                return true;
            }
            ///\todo Autocompletion/suggestion
            //case Qt::Key_Tab:
            default:
                return QObject::eventFilter(obj, e);
            }
        }
    }

    return QObject::eventFilter(obj, e);
}

void UiConsoleManager::DecorateString(QString &str)
{
    // Make all timestamp + module name blocks white
    int block_end_index = str.indexOf("]");
    if (block_end_index != -1)
    {
        QString span_start("");
        QString span_end("");
        block_end_index += span_start.length() + 1;
        str.insert(0, "");
        str.insert(block_end_index, "");
        block_end_index += span_end.length();
    }
    else
        block_end_index = 0;

    QRegExp regexp;
    regexp.setPattern(".*Debug:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Notice:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Warning:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Error:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Critical:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }

    regexp.setPattern(".*Fatal:.*");
    if (regexp.exactMatch(str))
    {
        str.insert(block_end_index, "");
        str.push_back("");
        return;
    }
}
<|endoftext|>