<commit_before>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <cassert>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/foreach.hh>

#include "kernel/userver.hh"

#include "object/urbi-exception.hh"

#include "scheduler/scheduler.hh"
#include "scheduler/job.hh"

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job (void* job)
  {
    static_cast<Job*>(job)->run();
  }

  void
  Scheduler::add_job (Job* job)
  {
    assert (job);
    assert (!libport::has (jobs_, job));
    assert (!libport::has (jobs_to_start_, job));
    jobs_to_start_.push_back (job);
  }

  libport::utime_t
  Scheduler::work ()
  {
#ifdef ENABLE_DEBUG_TRACES
    static int cycle = 0;
#endif
    ECHO ("======================================================== cycle "
	  << ++cycle);

    // Start new jobs
    to_start_.clear ();
    std::swap (to_start_, jobs_to_start_);
    foreach (Job* job, to_start_)
    {
      assert (job);
      ECHO ("will start job " << *job);
      // Job will start for a very short time and do a yield_front() to
      // be restarted below in the course of the regular cycle.
      assert (!current_job_);
      current_job_ = job;
      Coro_startCoro_ (self_, job->coro_get(), job, run_job);
      // We have to assume that a new job may have had side-effects.
      possible_side_effect_ = true;
    }

    // Start deferred jobs
    for (libport::utime_t current_time = ::urbiserver->getTime ();
	 !deferred_jobs_.empty();
	 deferred_jobs_.pop ())
    {
      deferred_job j = deferred_jobs_.top ();
      if (current_time < j.get<0>())
	break;
      jobs_.push_back (j.get<1> ());
    }

    // If something is going to happen, or if we have just started a
    // new job, add the list of jobs waiting for something to happen
    // on the pending jobs queue.
    if (!if_change_jobs_.empty() && (possible_side_effect_ || !jobs_.empty()))
    {
      foreach (Job* job, if_change_jobs_)
	jobs_.push_back (job);
      if_change_jobs_.clear ();
    }

    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    possible_side_effect_ = false;
    pending_.clear ();
    std::swap (pending_, jobs_);

    ECHO (pending_.size() << " jobs in the queue for this cycle");
    foreach (Job* job, pending_)
    {
      assert (job);
      assert (!job->terminated ());
      ECHO ("will resume job " << *job);
      possible_side_effect_ |= !job->side_effect_free_get ();
      Coro_switchTo_ (self_, job->coro_get ());
      possible_side_effect_ |= !job->side_effect_free_get ();
      ECHO ("back from job " << *job);
    }

    // Do we have some work to do now?
    if (!jobs_.empty ())
      return 0;

    // Do we have deferred jobs?
    if (!deferred_jobs_.empty ())
      return deferred_jobs_.top ().get<0> ();

    // Ok, let's say, we'll be called again in one hour.
    return ::urbiserver->getTime() + 3600000000LL;
  }

  void
  Scheduler::switch_back (Job* job)
  {
    // Switch back to the scheduler.
    assert (current_job_ == job);
    current_job_ = 0;
    Coro_switchTo_ (job->coro_get (), self_);
    // We regained control, we are again in the context of the job.
    assert (!current_job_);
    current_job_ = job;
    ECHO ("job " << *job << " resumed");
    // Check that we are not near exhausting the stack space.
    if (Coro_stackSpaceAlmostGone (job->coro_get ()))
      throw object::StackExhaustedError ("stack space exhausted");
    // Execute a deferred exception if any
    job->check_for_pending_exception ();
  }

  void
  Scheduler::resume_scheduler (Job* job)
  {
    // If the job has not terminated, put it at the back of the run queue
    // so that the run queue order is preserved between work cycles.
    if (!job->terminated ())
      jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_front (Job* job)
  {
    // Put the job in front of the queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    jobs_.push_front (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_until (Job* job, libport::utime_t deadline)
  {
    // Put the job in the deferred queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    deferred_jobs_.push (boost::make_tuple (deadline, job));
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_suspend (Job* job)
  {
    suspended_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_things_changed (Job* job)
  {
    if_change_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_job (Job* job)
  {
    // Suspended job may have been killed externally, in which case it
    // will not appear in the list of suspended jobs.

    if (libport::has (suspended_jobs_, job))
    {
      jobs_.push_back (job);
      suspended_jobs_.remove (job);
    }
  }

  void
  Scheduler::killall_jobs ()
  {
    ECHO ("killing all jobs!");

    // This implementation is quite inefficient because it will call
    // kill_job() for each job. But who cares? We are killing everyone
    // anyway.

    while (!jobs_to_start_.empty ())
      jobs_to_start_.pop_front ();

    while (!suspended_jobs_.empty ())
      kill_job (suspended_jobs_.front ());

    while (!if_change_jobs_.empty ())
      kill_job (if_change_jobs_.front ());

    while (!jobs_.empty ())
      kill_job (jobs_.front ());

    while (!deferred_jobs_.empty ())
      kill_job (deferred_jobs_.top ().get<1>());
  }

  void
  Scheduler::unschedule_job (Job* job)
  {
    assert (job);
    assert (job != current_job_);

    ECHO ("unscheduling job " << *job);

    // First of all, tell the job it has been terminated unless it has
    // been registered with us but not yet started.
    if (!libport::has (jobs_to_start_, job))
      job->terminate_now ();

    // Remove the job from the queues where it could be stored.
    jobs_to_start_.remove (job);
    jobs_.remove (job);
    suspended_jobs_.remove (job);
    if_change_jobs_.remove (job);

    // Remove it from live queues as well if the job is destroyed.
    to_start_.remove (job);
    pending_.remove (job);

    // We have no remove() on a priority queue, regenerate a queue without
    // this job.
    {
      deferred_jobs old_deferred;
      std::swap (old_deferred, deferred_jobs_);
      while (!old_deferred.empty ())
      {
	deferred_job j = old_deferred.top ();
	old_deferred.pop ();
	if (j.get<1>() != job)
	  deferred_jobs_.push (j);
      }
    }
  }

  void
  Scheduler::kill_job (Job* job)
  {
    assert (job != current_job_);

    ECHO ("deleting job " << *job);
    delete job;
  }

  bool operator> (const deferred_job& left, const deferred_job& right)
  {
    return left.get<0>() > right.get<0>();
  }

} // namespace scheduler
<commit_msg>We do not want to wait if we have a job to start in the next cycle<commit_after>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <cassert>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/foreach.hh>

#include "kernel/userver.hh"

#include "object/urbi-exception.hh"

#include "scheduler/scheduler.hh"
#include "scheduler/job.hh"

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job (void* job)
  {
    static_cast<Job*>(job)->run();
  }

  void
  Scheduler::add_job (Job* job)
  {
    assert (job);
    assert (!libport::has (jobs_, job));
    assert (!libport::has (jobs_to_start_, job));
    jobs_to_start_.push_back (job);
  }

  libport::utime_t
  Scheduler::work ()
  {
#ifdef ENABLE_DEBUG_TRACES
    static int cycle = 0;
#endif
    ECHO ("======================================================== cycle "
	  << ++cycle);

    // Start new jobs
    to_start_.clear ();
    std::swap (to_start_, jobs_to_start_);
    foreach (Job* job, to_start_)
    {
      assert (job);
      ECHO ("will start job " << *job);
      // Job will start for a very short time and do a yield_front() to
      // be restarted below in the course of the regular cycle.
      assert (!current_job_);
      current_job_ = job;
      Coro_startCoro_ (self_, job->coro_get(), job, run_job);
      // We have to assume that a new job may have had side-effects.
      possible_side_effect_ = true;
    }

    // Start deferred jobs
    for (libport::utime_t current_time = ::urbiserver->getTime ();
	 !deferred_jobs_.empty();
	 deferred_jobs_.pop ())
    {
      deferred_job j = deferred_jobs_.top ();
      if (current_time < j.get<0>())
	break;
      jobs_.push_back (j.get<1> ());
    }

    // If something is going to happen, or if we have just started a
    // new job, add the list of jobs waiting for something to happen
    // on the pending jobs queue.
    if (!if_change_jobs_.empty() && (possible_side_effect_ || !jobs_.empty()))
    {
      foreach (Job* job, if_change_jobs_)
	jobs_.push_back (job);
      if_change_jobs_.clear ();
    }

    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    possible_side_effect_ = false;
    pending_.clear ();
    std::swap (pending_, jobs_);

    ECHO (pending_.size() << " jobs in the queue for this cycle");
    foreach (Job* job, pending_)
    {
      assert (job);
      assert (!job->terminated ());
      ECHO ("will resume job " << *job);
      possible_side_effect_ |= !job->side_effect_free_get ();
      Coro_switchTo_ (self_, job->coro_get ());
      possible_side_effect_ |= !job->side_effect_free_get ();
      ECHO ("back from job " << *job);
    }

    // Do we have some work to do now?
    if (!jobs_.empty () || !jobs_to_start_.empty())
      return 0;

    // Do we have deferred jobs?
    if (!deferred_jobs_.empty ())
      return deferred_jobs_.top ().get<0> ();

    // Ok, let's say, we'll be called again in one hour.
    return ::urbiserver->getTime() + 3600000000LL;
  }

  void
  Scheduler::switch_back (Job* job)
  {
    // Switch back to the scheduler.
    assert (current_job_ == job);
    current_job_ = 0;
    Coro_switchTo_ (job->coro_get (), self_);
    // We regained control, we are again in the context of the job.
    assert (!current_job_);
    current_job_ = job;
    ECHO ("job " << *job << " resumed");
    // Check that we are not near exhausting the stack space.
    if (Coro_stackSpaceAlmostGone (job->coro_get ()))
      throw object::StackExhaustedError ("stack space exhausted");
    // Execute a deferred exception if any
    job->check_for_pending_exception ();
  }

  void
  Scheduler::resume_scheduler (Job* job)
  {
    // If the job has not terminated, put it at the back of the run queue
    // so that the run queue order is preserved between work cycles.
    if (!job->terminated ())
      jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_front (Job* job)
  {
    // Put the job in front of the queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    jobs_.push_front (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_until (Job* job, libport::utime_t deadline)
  {
    // Put the job in the deferred queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    deferred_jobs_.push (boost::make_tuple (deadline, job));
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_suspend (Job* job)
  {
    suspended_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_things_changed (Job* job)
  {
    if_change_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_job (Job* job)
  {
    // Suspended job may have been killed externally, in which case it
    // will not appear in the list of suspended jobs.

    if (libport::has (suspended_jobs_, job))
    {
      jobs_.push_back (job);
      suspended_jobs_.remove (job);
    }
  }

  void
  Scheduler::killall_jobs ()
  {
    ECHO ("killing all jobs!");

    // This implementation is quite inefficient because it will call
    // kill_job() for each job. But who cares? We are killing everyone
    // anyway.

    while (!jobs_to_start_.empty ())
      jobs_to_start_.pop_front ();

    while (!suspended_jobs_.empty ())
      kill_job (suspended_jobs_.front ());

    while (!if_change_jobs_.empty ())
      kill_job (if_change_jobs_.front ());

    while (!jobs_.empty ())
      kill_job (jobs_.front ());

    while (!deferred_jobs_.empty ())
      kill_job (deferred_jobs_.top ().get<1>());
  }

  void
  Scheduler::unschedule_job (Job* job)
  {
    assert (job);
    assert (job != current_job_);

    ECHO ("unscheduling job " << *job);

    // First of all, tell the job it has been terminated unless it has
    // been registered with us but not yet started.
    if (!libport::has (jobs_to_start_, job))
      job->terminate_now ();

    // Remove the job from the queues where it could be stored.
    jobs_to_start_.remove (job);
    jobs_.remove (job);
    suspended_jobs_.remove (job);
    if_change_jobs_.remove (job);

    // Remove it from live queues as well if the job is destroyed.
    to_start_.remove (job);
    pending_.remove (job);

    // We have no remove() on a priority queue, regenerate a queue without
    // this job.
    {
      deferred_jobs old_deferred;
      std::swap (old_deferred, deferred_jobs_);
      while (!old_deferred.empty ())
      {
	deferred_job j = old_deferred.top ();
	old_deferred.pop ();
	if (j.get<1>() != job)
	  deferred_jobs_.push (j);
      }
    }
  }

  void
  Scheduler::kill_job (Job* job)
  {
    assert (job != current_job_);

    ECHO ("deleting job " << *job);
    delete job;
  }

  bool operator> (const deferred_job& left, const deferred_job& right)
  {
    return left.get<0>() > right.get<0>();
  }

} // namespace scheduler
<|endoftext|>


<commit_before>#include "control.h"

int Curso::cantidad = 0;

void Control::Inicializador()
{
	U = new Universidad("Universidad de Costa Rica", "22334455", "San Pedro");

	Escuela* E1 = new Escuela("Ingles");
	Escuela* E2 = new Escuela("Matematicas");
	Escuela* E3 = new Escuela("Geologia");
	Escuela* E4 = new Escuela("Sociales");

	U->insertarEscuela(E1);
	U->insertarEscuela(E2);
	U->insertarEscuela(E3);
	U->insertarEscuela(E4);

	Curso* CU1 = new Curso("Programacion I", E1->getSiglaEscuela());
	Curso* CU2 = new Curso("Programacion II", E2->getSiglaEscuela());
	E1->insertarCurso(CU1);
	E2->insertarCurso(CU2);

	MenuPrincipal();
}

void Control::MenuPrincipal()
{
	Interfaz::vBienvenida();

	if (Interfaz::vDatosPrimeraVez(U) == 'S')
	{
		Interfaz::vIngresarNombre(U);
		Interfaz::vIngresarNumero(U);
		Interfaz::vIngresarDireccion(U);
	}

	bool end = false;

	do
	{
		char ans = Interfaz::vMenuPrincipal();

		switch (ans)
		{
		case '1':
		{
			MenuUniversidad();
			break;
		}
		case '2':
		{
			MenuEscuelas();
			break;
		}
		case '3':
		{
			MenuCursos();
			break;
		}
		case '4':
		{
			MenuProfesores();
			break;
		}
		case'5':
		{
			MenuEstudiantes();
			break;
		}
		case '6':
		{
			MenuAjustes();
			break;
		}
		case '7':
		{
			delete U;
			end = true;
			break;
		}
		default:
			break;
		}

	} while (end == false);
}

void Control::MenuUniversidad()
{
	bool end = false;

	do
	{
		char ans = Interfaz::vMenuUniversidad();

		switch (ans)
		{
		case '1':
		{
			Interfaz::vInfoUniversidad(U);
			break;
		}
		case '2': //Salir
		{
			end = true;
			break;
		}
		default:
			break;
		}

	} while (end == false);
}

void Control::MenuEscuelas()
{
	bool end = false;

	do
	{
		char ans = Interfaz::vMenuEscuelas();

		switch (ans)
		{
		case '1':
		{
			Interfaz::vInfoEscuelas(U, '1'); //Imprime solamente escuelas
			break;
		}
		case '2':
		{
			Interfaz::vInfoEscuelas(U, '2'); //Imprime escuelas con los cursos
			break;
		}
		case '3': // Salir
		{
			end = true;
			break;
		}
		default:
			break;
		}

	} while (end == false);
}

void Control::MenuCursos()
{
	bool end = false;

	do
	{
		char ans = Interfaz::vMenuCursos();

		switch (ans)
		{
		case '1':
		{
			Interfaz::vInfoCurso(U);
			break;
		}
		case '2':
		{
			Interfaz::vListaCursosEscuelaParticular(U);
			break;
		}
		case '3': //Salir
		{
			end = true;
			break;
		}
		default:
			break;
		}

	} while (end == false);
}

void Control::MenuAjustes()
{
	bool end = false;

	do
	{
		char opcion = Interfaz::vMenuAjustes(U);

		if (U->getNombre() == "Undefined")
		{
			switch (opcion)
			{
			case '1':
			{
				Interfaz::vIngresarNombre(U);
				break;
			}
			case '2':
			{
				Interfaz::vIngresarNumero(U);
				break;
			}
			case '3':
			{
				Interfaz::vIngresarDireccion(U);
				break;
			}
			case '4':
			{
				end = true;
				break;
			}
			default: break;

			}
		}
		else
		{

			switch (opcion)
			{
			case '1':
			{
				Interfaz::vIngresarNumero(U);
				break;
			}
			case '2':
			{
				Interfaz::vIngresarDireccion(U);
				break;
			}
			case '3':
			{
				Interfaz::vIngresaEscuela(U);
				break;
			}
			case '4':
			{
				Interfaz::vIngresaCurso(U);
				break;
			}
			case '5':
			{
				Interfaz::vEditarCurso(U);
				break;
			}
			case '6':
			{
				Interfaz::vEliminaCurso(U);
				break;
			}
			case '7':
			{
				end = true;
				break;
			}
			default: break;

			}
		}

	} while (end == false);
}

void Control::MenuProfesores()
{
	bool end = false;

	do
	{
		char opcion = Interfaz::vMenuProfesores();
		switch (opcion)
		{
		case '1':
		{
			break;
		}
		case'2':
		{
			break;
		}
		}
	} while (end == false);
}

void Control::MenuEstudiantes()
{
}

<commit_msg>arreglo la clase control para la posterior inclusion de las partes de los profesores y estudiantes<commit_after>#include "control.h"

int Curso::cantidad = 0; // variable que controla el codigo del curso

void Control::Inicializador()
{
	U = new Universidad("Universidad de Costa Rica", "22334455", "San Pedro");

	Escuela* E1 = new Escuela("Ingles");
	Escuela* E2 = new Escuela("Matematicas");
	Escuela* E3 = new Escuela("Geologia");
	Escuela* E4 = new Escuela("Sociales");

	U->insertarEscuela(E1);
	U->insertarEscuela(E2);
	U->insertarEscuela(E3);
	U->insertarEscuela(E4);

	Curso* CU1 = new Curso("Programacion I", E1->getSiglaEscuela());
	Curso* CU2 = new Curso("Programacion II", E2->getSiglaEscuela());
	E1->insertarCurso(CU1);
	E2->insertarCurso(CU2);

	MenuPrincipal();
}

void Control::MenuPrincipal()
{
	Interfaz::vBienvenida();

	if (Interfaz::vDatosPrimeraVez(U) == 'S')
	{
		Interfaz::vIngresarNombre(U);
		Interfaz::vIngresarNumero(U);
		Interfaz::vIngresarDireccion(U);
	}

	bool end = false;

	do
	{
		char ans = Interfaz::vMenuPrincipal();

		switch (ans)
		{
		case '1':
		{
			MenuUniversidad();
			break;
		}
		case '2':
		{
			MenuEscuelas();
			break;
		}
		case '3':
		{
			MenuCursos();
			break;
		}
		case '4':
		{
			MenuProfesores();
			break;
		}
		case'5':
		{
			MenuEstudiantes();
			break;
		}
		case '6':
		{
			MenuAjustes();
			break;
		}
		case '7':
		{
			delete U;
			end = true;
			break;
		}
		default:
			break;
		}

	} while (end == false);
}

void Control::MenuUniversidad()
{
	bool end = false;

	do
	{
		char ans = Interfaz::vMenuUniversidad();

		switch (ans)
		{
		case '1':
		{
			Interfaz::vInfoUniversidad(U);
			break;
		}
		case '2': //Salir
		{
			end = true;
			break;
		}
		default:
			break;
		}

	} while (end == false);
}

void Control::MenuEscuelas()
{
	bool end = false;

	do
	{
		char ans = Interfaz::vMenuEscuelas();

		switch (ans)
		{
		case '1':
		{
			Interfaz::vInfoEscuelas(U, '1'); //Imprime solamente escuelas
			break;
		}
		case '2':
		{
			Interfaz::vInfoEscuelas(U, '2'); //Imprime escuelas con los cursos
			break;
		}
		case '3': // Salir
		{
			end = true;
			break;
		}
		default:
			break;
		}

	} while (end == false);
}

void Control::MenuCursos()
{
	bool end = false;

	do
	{
		char ans = Interfaz::vMenuCursos();

		switch (ans)
		{
		case '1':
		{
			Interfaz::vInfoCurso(U);
			break;
		}
		case '2':
		{
			Interfaz::vListaCursosEscuelaParticular(U);
			break;
		}
		case '3': //Salir
		{
			end = true;
			break;
		}
		default:
			break;
		}

	} while (end == false);
}

void Control::MenuAjustes()
{
	bool end = false;

	do
	{
		char opcion = Interfaz::vMenuAjustes(U);

		if (U->getNombre() == "Undefined")
		{
			switch (opcion)
			{
			case '1':
			{
				Interfaz::vIngresarNombre(U);
				break;
			}
			case '2':
			{
				Interfaz::vIngresarNumero(U);
				break;
			}
			case '3':
			{
				Interfaz::vIngresarDireccion(U);
				break;
			}
			case '4':
			{
				end = true;
				break;
			}
			default: break;

			}
		}
		else
		{

			switch (opcion)
			{
			case '1':
			{
				Interfaz::vIngresarNumero(U);
				break;
			}
			case '2':
			{
				Interfaz::vIngresarDireccion(U);
				break;
			}
			case '3':
			{
				Interfaz::vIngresaEscuela(U);
				break;
			}
			case '4':
			{
				Interfaz::vIngresaCurso(U);
				break;
			}
			case '5':
			{
				Interfaz::vEditarCurso(U);
				break;
			}
			case '6':
			{
				Interfaz::vEliminaCurso(U);
				break;
			}
			case '7':
			{
				end = true;
				break;
			}
			default: break;

			}
		}

	} while (end == false);
}

void Control::MenuProfesores()
{
	bool end = false;

	do
	{
		char opcion = Interfaz::vMenuProfesores();
		switch (opcion)
		{
		case '1':
		{
			break;
		}
		case'2':
		{
			break;
		}
		}
	} while (end == false);
}

void Control::MenuEstudiantes()
{
}

<|endoftext|>


<commit_before>#include "yacas/platfileio.h"

#ifdef _WIN32
#define MAP_TO_WIN32_PATH_SEPARATOR
#endif // WIN32

static void MapPathSeparators(std::string& filename)
{
#ifdef MAP_TO_WIN32_PATH_SEPARATOR
    for (std::size_t i = 0; i < filename.size(); ++i)
        if (filename[i] == '/')
            filename[i] = '\\';
#endif
}

StdFileInput::StdFileInput(std::istream& stream, InputStatus& aStatus):
    LispInput(aStatus),
    _stream(stream)
{
}

StdFileInput::StdFileInput(LispLocalFile& file, InputStatus& aStatus):
    LispInput(aStatus),
    _stream(file.stream),
    _position(0),
    _cp_ready(false)
{
}

char32_t StdFileInput::Next()
{
    if (!_cp_ready)
        _get();

    if (EndOfStream())
        return std::char_traits<char32_t>::eof();

    _cp_ready = false;
    _position += 1;

    return _cp;
}

char32_t StdFileInput::Peek()
{
    if (EndOfStream())
        return std::char_traits<char32_t>::eof();

    if (!_cp_ready)
        _get();

    return _cp;
}

void StdFileInput::Rewind()
{
    _stream.seekg(0);
    _position = 0;
    _cp_ready = false;
}

bool StdFileInput::EndOfStream() const
{
    if (_stream.eof())
        return true;

    if (!_cp_ready)
        _get();

    return _stream.eof();
}

std::size_t StdFileInput::Position() const
{
    return _position;
}

void StdFileInput::SetPosition(std::size_t n)
{
    Rewind();

    for (std::size_t i = 0; i < n; ++i)
        Next();
}

void StdFileInput::_get() const
{
    char p[4];
    char* q = p;

    *q++ = _stream.get();

    while (!_stream.eof() && !utf8::is_valid(p, q))
        *q++ = _stream.get();

    if (_stream.eof())
        return;

    utf8::utf8to32(p, q, &_cp);
    _cp_ready = true;
}

std::string InternalFindFile(const std::string& fname, const std::vector<std::string>& dirs)
{
    std::string path(fname);

    MapPathSeparators(path);

    std::ifstream f(path);
    for (std::size_t i = 0; !f.good() && i < dirs.size(); ++i) {
        path = dirs[i] + fname;
        MapPathSeparators(path);
        f = std::move(std::ifstream(path));
    }

    if (!f.good())
        return "";

    return path;
}

LispLocalFile::LispLocalFile(
    LispEnvironment& environment,
    const std::string& fname,
    bool read,
    const std::vector<std::string>& dirs):
    environment(environment)
{
    std::string othername;

    if (read) {
        othername = fname;
        MapPathSeparators(othername);

        stream.open(othername, std::ios_base::in | std::ios_base::binary);

        for (std::size_t i = 0; !stream.is_open() && i < dirs.size(); ++i) {
            othername = dirs[i];
            othername += fname;
            MapPathSeparators(othername);
            stream.open(othername, std::ios_base::in | std::ios_base::binary);
        }
    } else {
        othername = fname;
        MapPathSeparators(othername);
        stream.open(othername, std::ios_base::out);
    }
}

LispLocalFile::~LispLocalFile()
{
    if (stream.is_open())
        stream.close();
}
<commit_msg>try to fix https://travis-ci.org/grzegorzmazur/yacas/jobs/345281609<commit_after>#include "yacas/platfileio.h"

#include <memory>

#ifdef _WIN32
#define MAP_TO_WIN32_PATH_SEPARATOR
#endif // WIN32

static void MapPathSeparators(std::string& filename)
{
#ifdef MAP_TO_WIN32_PATH_SEPARATOR
    for (std::size_t i = 0; i < filename.size(); ++i)
        if (filename[i] == '/')
            filename[i] = '\\';
#endif
}

StdFileInput::StdFileInput(std::istream& stream, InputStatus& aStatus):
    LispInput(aStatus),
    _stream(stream)
{
}

StdFileInput::StdFileInput(LispLocalFile& file, InputStatus& aStatus):
    LispInput(aStatus),
    _stream(file.stream),
    _position(0),
    _cp_ready(false)
{
}

char32_t StdFileInput::Next()
{
    if (!_cp_ready)
        _get();

    if (EndOfStream())
        return std::char_traits<char32_t>::eof();

    _cp_ready = false;
    _position += 1;

    return _cp;
}

char32_t StdFileInput::Peek()
{
    if (EndOfStream())
        return std::char_traits<char32_t>::eof();

    if (!_cp_ready)
        _get();

    return _cp;
}

void StdFileInput::Rewind()
{
    _stream.seekg(0);
    _position = 0;
    _cp_ready = false;
}

bool StdFileInput::EndOfStream() const
{
    if (_stream.eof())
        return true;

    if (!_cp_ready)
        _get();

    return _stream.eof();
}

std::size_t StdFileInput::Position() const
{
    return _position;
}

void StdFileInput::SetPosition(std::size_t n)
{
    Rewind();

    for (std::size_t i = 0; i < n; ++i)
        Next();
}

void StdFileInput::_get() const
{
    char p[4];
    char* q = p;

    *q++ = _stream.get();

    while (!_stream.eof() && !utf8::is_valid(p, q))
        *q++ = _stream.get();

    if (_stream.eof())
        return;

    utf8::utf8to32(p, q, &_cp);
    _cp_ready = true;
}

std::string InternalFindFile(const std::string& fname, const std::vector<std::string>& dirs)
{
    std::string path(fname);

    MapPathSeparators(path);

    std::unique_ptr<std::ifstream> f(new std::ifstream(path));
    for (std::size_t i = 0; !f->good() && i < dirs.size(); ++i) {
        path = dirs[i] + fname;
        MapPathSeparators(path);
        f.reset(new std::ifstream(path));
    }

    if (!f->good())
        return "";

    return path;
}

LispLocalFile::LispLocalFile(
    LispEnvironment& environment,
    const std::string& fname,
    bool read,
    const std::vector<std::string>& dirs):
    environment(environment)
{
    std::string othername;

    if (read) {
        othername = fname;
        MapPathSeparators(othername);

        stream.open(othername, std::ios_base::in | std::ios_base::binary);

        for (std::size_t i = 0; !stream.is_open() && i < dirs.size(); ++i) {
            othername = dirs[i];
            othername += fname;
            MapPathSeparators(othername);
            stream.open(othername, std::ios_base::in | std::ios_base::binary);
        }
    } else {
        othername = fname;
        MapPathSeparators(othername);
        stream.open(othername, std::ios_base::out);
    }
}

LispLocalFile::~LispLocalFile()
{
    if (stream.is_open())
        stream.close();
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: MasterPageObserver.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2004-08-04 08:54:55 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SD_VIEW_MASTER_PAGE_OBSERVER_HXX
#define SD_VIEW_MASTER_PAGE_OBSERVER_HXX

#include "tools/SdGlobalResourceContainer.hxx"
#include <osl/mutex.hxx>
#include <tools/link.hxx>
#include <memory>
#include <set>

class SdDrawDocument;
class String;

namespace sd {

/** This singleton observes all registered documents for changes in the used
    master pages and in turn informs its listeners about it.  One such
    listener is the master page selector control in the tool panel that
    shows the recently used master pages.
*/
class MasterPageObserver
    : public SdGlobalResource
{
public:
    typedef ::std::set<String> MasterPageNameSet;

    /** Return the single instance of this class.
    */
    static MasterPageObserver& Instance (void);

    /** The master page observer will listen to events of this document and
        detect changes of the use of master pages.
    */
    void RegisterDocument (SdDrawDocument& rDocument);

    /** The master page observer will stop to listen to events of this
        document.
    */
    void UnregisterDocument (SdDrawDocument& rDocument);

    /** Add a listener that is informed of master pages that are newly
        assigned to slides or become unassigned.
        @param rEventListener
            The event listener to call for future events.  Call
            RemoveEventListener() before the listener is destroyed.
    */
    void AddEventListener (const Link& rEventListener);

    /** Remove the given listener from the list of listeners.
        @param rEventListener
            After this method returns the given listener is not called back
            from this object.  Passing a listener that has not
            been registered before is safe and is silently ignored.
    */
    void RemoveEventListener (const Link& rEventListener);

    /** Return a set of the names of master pages for the given document.
        This convenience method exists because this set is part of the
        internal data structure and thus takes no time to create.
    */
    MasterPageNameSet GetMasterPageNames (SdDrawDocument& rDocument);

private:
    static ::osl::Mutex maMutex;

    class Implementation;
    ::std::auto_ptr<Implementation> mpImpl;

    MasterPageObserver (void);
    virtual ~MasterPageObserver (void);

    /// The copy constructor is not implemented.  Do not use!
    MasterPageObserver (const MasterPageObserver&);

    /// The assignment operator is not implemented.  Do not use!
    MasterPageObserver& operator= (const MasterPageObserver&);
};

/** Objects of this class are sent to listeners of the MasterPageObserver
    singleton when the list of master pages of one document has changed.
*/
class MasterPageObserverEvent
{
public:
    enum EventType {
        /// Master page already exists when document is registered.
        ET_MASTER_PAGE_EXISTS,
        /// Master page has been added to a document.
        ET_MASTER_PAGE_ADDED,
        /// Master page has been removed from to a document.
        ET_MASTER_PAGE_REMOVED
    };

    EventType meType;
    SdDrawDocument& mrDocument;
    const String& mrMasterPageName;

    MasterPageObserverEvent (
        EventType eType,
        SdDrawDocument& rDocument,
        const String& rMasterPageName)
        : meType(eType),
          mrDocument(rDocument),
          mrMasterPageName(rMasterPageName)
    {}

};

} // end of namespace sd

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.3.394); FILE MERGED 2005/09/05 13:22:42 rt 1.3.394.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: MasterPageObserver.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 05:08:05 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SD_VIEW_MASTER_PAGE_OBSERVER_HXX
#define SD_VIEW_MASTER_PAGE_OBSERVER_HXX

#include "tools/SdGlobalResourceContainer.hxx"
#include <osl/mutex.hxx>
#include <tools/link.hxx>
#include <memory>
#include <set>

class SdDrawDocument;
class String;

namespace sd {

/** This singleton observes all registered documents for changes in the used
    master pages and in turn informs its listeners about it.  One such
    listener is the master page selector control in the tool panel that
    shows the recently used master pages.
*/
class MasterPageObserver
    : public SdGlobalResource
{
public:
    typedef ::std::set<String> MasterPageNameSet;

    /** Return the single instance of this class.
    */
    static MasterPageObserver& Instance (void);

    /** The master page observer will listen to events of this document and
        detect changes of the use of master pages.
    */
    void RegisterDocument (SdDrawDocument& rDocument);

    /** The master page observer will stop to listen to events of this
        document.
    */
    void UnregisterDocument (SdDrawDocument& rDocument);

    /** Add a listener that is informed of master pages that are newly
        assigned to slides or become unassigned.
        @param rEventListener
            The event listener to call for future events.  Call
            RemoveEventListener() before the listener is destroyed.
    */
    void AddEventListener (const Link& rEventListener);

    /** Remove the given listener from the list of listeners.
        @param rEventListener
            After this method returns the given listener is not called back
            from this object.  Passing a listener that has not
            been registered before is safe and is silently ignored.
    */
    void RemoveEventListener (const Link& rEventListener);

    /** Return a set of the names of master pages for the given document.
        This convenience method exists because this set is part of the
        internal data structure and thus takes no time to create.
    */
    MasterPageNameSet GetMasterPageNames (SdDrawDocument& rDocument);

private:
    static ::osl::Mutex maMutex;

    class Implementation;
    ::std::auto_ptr<Implementation> mpImpl;

    MasterPageObserver (void);
    virtual ~MasterPageObserver (void);

    /// The copy constructor is not implemented.  Do not use!
    MasterPageObserver (const MasterPageObserver&);

    /// The assignment operator is not implemented.  Do not use!
    MasterPageObserver& operator= (const MasterPageObserver&);
};

/** Objects of this class are sent to listeners of the MasterPageObserver
    singleton when the list of master pages of one document has changed.
*/
class MasterPageObserverEvent
{
public:
    enum EventType {
        /// Master page already exists when document is registered.
        ET_MASTER_PAGE_EXISTS,
        /// Master page has been added to a document.
        ET_MASTER_PAGE_ADDED,
        /// Master page has been removed from to a document.
        ET_MASTER_PAGE_REMOVED
    };

    EventType meType;
    SdDrawDocument& mrDocument;
    const String& mrMasterPageName;

    MasterPageObserverEvent (
        EventType eType,
        SdDrawDocument& rDocument,
        const String& rMasterPageName)
        : meType(eType),
          mrDocument(rDocument),
          mrMasterPageName(rMasterPageName)
    {}

};

} // end of namespace sd

#endif
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxExtension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include <wx/extension/header.h>
#include <wx/extension/lexers.h>
#include <wx/extension/log.h>
#include <wx/extension/printing.h>
#include <wx/extension/tool.h>
#include "test.h"

#define TEST_FILE "./test.h"
#define TEST_BIN "./test.bin"

void wxExAppTestFixture::setUp()
{
  m_Grid = new wxExGrid(wxTheApp->GetTopWindow());
  m_ListView = new wxExListView(wxTheApp->GetTopWindow());
  m_Notebook = new wxExNotebook(wxTheApp->GetTopWindow(), NULL);
  m_STC = new wxExSTC(wxTheApp->GetTopWindow(), wxExFileName(TEST_FILE));
  m_STCShell = new wxExSTCShell(wxTheApp->GetTopWindow());
  m_SVN = new wxExSVN(SVN_INFO, TEST_FILE);
}

void wxExAppTestFixture::testConstructors()
{
}

void wxExAppTestFixture::testMethods()
{
  // test wxExApp
  CPPUNIT_ASSERT(wxConfigBase::Get() != NULL);
  CPPUNIT_ASSERT(wxExLexers::Get() != NULL);
  CPPUNIT_ASSERT(wxExPrinting::Get()->GetHtmlPrinter() != NULL);
  CPPUNIT_ASSERT(!wxExTool::Get()->GetToolInfo().empty());

  // test wxExGrid
  CPPUNIT_ASSERT(m_Grid->CreateGrid(5, 5));
  m_Grid->SetGridCellValue(wxGridCellCoords(0, 0), "test");
  m_Grid->SelectAll();
  CPPUNIT_ASSERT(!m_Grid->GetSelectedCellsValue().empty());
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test");
  m_Grid->SetCellsValue(wxGridCellCoords(0, 0), "test1\ttest2\ntest3\ttest4\n");
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test1");

  // test wxExListView
  m_ListView->SetSingleStyle(wxLC_REPORT); // wxLC_ICON);
  m_ListView->InsertColumn(wxExColumn("String", wxExColumn::COL_STRING));
  m_ListView->InsertColumn(wxExColumn("Number", wxExColumn::COL_INT));
  CPPUNIT_ASSERT(m_ListView->FindColumn("String") == 0);
  CPPUNIT_ASSERT(m_ListView->FindColumn("Number") == 1);
  wxExListItem item1(m_ListView, "c item"); ///< testing wxExListItem
  item1.Insert();
  wxExListItem item2(m_ListView, "b item"); ///< testing wxExListItem
  item2.Insert();
  wxExListItem item3(m_ListView, "a item"); ///< testing wxExListItem
  item3.Insert();
  m_ListView->SortColumn("String", SORT_ASCENDING);
  wxExListItem test(m_ListView, 0);
  CPPUNIT_ASSERT(test.GetColumnText("String") == "a item");

  // test wxExNotebook (parent should not be NULL)
  wxWindow* page1 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  wxWindow* page2 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page2, "key2") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") == NULL);
  CPPUNIT_ASSERT(m_Notebook->GetKeyByPage(page1) == "key1");
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("key1") == page1);
  CPPUNIT_ASSERT(m_Notebook->SetPageText("key1", "keyx", "hello"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == page1);
  CPPUNIT_ASSERT(m_Notebook->DeletePage("keyx"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == NULL);

  // test wxExSTC
  // do the same test as with wxExFile in base for a binary file
  CPPUNIT_ASSERT(m_STC->Open(wxExFileName(TEST_BIN)));
  CPPUNIT_ASSERT(m_STC->GetFlags() == 0);
  CPPUNIT_ASSERT(m_STC->GetMenuFlags() == wxExSTC::STC_MENU_DEFAULT);
  const wxCharBuffer& buffer = m_STC->GetTextRaw();
  wxLogMessage(buffer.data());
  CPPUNIT_ASSERT(buffer.length() == 40);
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StartRecord();
  CPPUNIT_ASSERT( m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StopRecord();
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded()); // still no macro

  // test wxExSTCShell
  m_STCShell->Prompt("test1");
  m_STCShell->Prompt("test2");
  m_STCShell->Prompt("test3");
  m_STCShell->Prompt("test4");
  // Prompting does not add a command to history.
  CPPUNIT_ASSERT(!m_STCShell->GetHistory().Contains("test4"));
  // Post 3 'a' chars to the shell, and check whether it comes in the history.
  wxKeyEvent event(wxEVT_CHAR);
  event.m_keyCode = 97; // one char 'a'
  wxPostEvent(m_STCShell, event);
  wxPostEvent(m_STCShell, event);
  wxPostEvent(m_STCShell, event);
  event.m_keyCode = WXK_RETURN;
  wxPostEvent(m_STCShell, event);
  // The event queue for shell is not yet processed, so next will assert anyway.
  //CPPUNIT_ASSERT(m_STCShell->GetHistory().Contains("aaa"));

  // test wxExSVN
//  CPPUNIT_ASSERT(m_SVN->Execute(NULL) == 0); // do not use a dialog
//  CPPUNIT_ASSERT(!m_SVN->GetOutput().empty());

  // test util
  CPPUNIT_ASSERT(wxExClipboardAdd("test"));
  CPPUNIT_ASSERT(wxExClipboardGet() == "test");
  CPPUNIT_ASSERT(wxExGetNumberOfLines("test\ntest\n") == 3);
  CPPUNIT_ASSERT(wxExGetLineNumberFromText("test on line: 1200") == 1200);

  // Only usefull if the lexers file was present
  if (wxExLexers::Get()->Count() > 0)
  {
    wxConfigBase::Get()->Write(_("Purpose"), "hello test");
    const wxExFileName fn(TEST_FILE);
    const wxString header = wxExHeader().Get(&fn);
    CPPUNIT_ASSERT(header.Contains("hello test"));
  }
  else
  {
    wxLogMessage("No lexers available");
  }

  CPPUNIT_ASSERT(wxExLog::Get()->Log("hello from wxExtension test"));
  CPPUNIT_ASSERT(!wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp"));
  CPPUNIT_ASSERT(wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp;*.txt"));
  CPPUNIT_ASSERT(wxExSkipWhiteSpace("t     es   t") == "t es t");
  CPPUNIT_ASSERT(!wxExTranslate("hello @PAGENUM@ from @PAGESCNT@", 1, 2).Contains("@"));
}

void wxExAppTestFixture::tearDown()
{
}

wxExTestSuite::wxExTestSuite()
  : CppUnit::TestSuite("wxExtension test suite")
{
  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testConstructors",
    &wxExAppTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testMethods",
    &wxExAppTestFixture::testMethods));
}
<commit_msg>updated tests<commit_after>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxExtension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include <wx/extension/header.h>
#include <wx/extension/lexers.h>
#include <wx/extension/log.h>
#include <wx/extension/printing.h>
#include <wx/extension/tool.h>
#include "test.h"

#define TEST_FILE "./test.h"
#define TEST_BIN "./test.bin"

void wxExAppTestFixture::setUp()
{
  m_Grid = new wxExGrid(wxTheApp->GetTopWindow());
  m_ListView = new wxExListView(wxTheApp->GetTopWindow());
  m_Notebook = new wxExNotebook(wxTheApp->GetTopWindow(), NULL);
  m_STC = new wxExSTC(wxTheApp->GetTopWindow(), wxExFileName(TEST_FILE));
  m_STCShell = new wxExSTCShell(wxTheApp->GetTopWindow());
  m_SVN = new wxExSVN(SVN_INFO, TEST_FILE);
}

void wxExAppTestFixture::testConstructors()
{
}

void wxExAppTestFixture::testMethods()
{
  // test global objects
  CPPUNIT_ASSERT(wxExFindReplaceData::Get() != NULL);
  CPPUNIT_ASSERT(wxExLexers::Get() != NULL);
  CPPUNIT_ASSERT(wxExLog::Get() != NULL);
  CPPUNIT_ASSERT(wxExPrinting::Get() != NULL);
  CPPUNIT_ASSERT(wxExTool::Get() != NULL);

  // test wxExGrid
  CPPUNIT_ASSERT(m_Grid->CreateGrid(5, 5));
  m_Grid->SetGridCellValue(wxGridCellCoords(0, 0), "test");
  m_Grid->SelectAll();
  CPPUNIT_ASSERT(!m_Grid->GetSelectedCellsValue().empty());
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test");
  m_Grid->SetCellsValue(wxGridCellCoords(0, 0), "test1\ttest2\ntest3\ttest4\n");
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test1");

  // test wxExListView
  m_ListView->SetSingleStyle(wxLC_REPORT); // wxLC_ICON);
  m_ListView->InsertColumn(wxExColumn("String", wxExColumn::COL_STRING));
  m_ListView->InsertColumn(wxExColumn("Number", wxExColumn::COL_INT));
  CPPUNIT_ASSERT(m_ListView->FindColumn("String") == 0);
  CPPUNIT_ASSERT(m_ListView->FindColumn("Number") == 1);
  wxExListItem item1(m_ListView, "c item"); ///< testing wxExListItem
  item1.Insert();
  wxExListItem item2(m_ListView, "b item"); ///< testing wxExListItem
  item2.Insert();
  wxExListItem item3(m_ListView, "a item"); ///< testing wxExListItem
  item3.Insert();
  m_ListView->SortColumn("String", SORT_ASCENDING);
  wxExListItem test(m_ListView, 0);
  CPPUNIT_ASSERT(test.GetColumnText("String") == "a item");

  // test wxExNotebook (parent should not be NULL)
  wxWindow* page1 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  wxWindow* page2 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page2, "key2") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") == NULL);
  CPPUNIT_ASSERT(m_Notebook->GetKeyByPage(page1) == "key1");
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("key1") == page1);
  CPPUNIT_ASSERT(m_Notebook->SetPageText("key1", "keyx", "hello"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == page1);
  CPPUNIT_ASSERT(m_Notebook->DeletePage("keyx"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == NULL);

  // test wxExSTC
  // do the same test as with wxExFile in base for a binary file
  CPPUNIT_ASSERT(m_STC->Open(wxExFileName(TEST_BIN)));
  CPPUNIT_ASSERT(m_STC->GetFlags() == 0);
  CPPUNIT_ASSERT(m_STC->GetMenuFlags() == wxExSTC::STC_MENU_DEFAULT);
  const wxCharBuffer& buffer = m_STC->GetTextRaw();
  wxLogMessage(buffer.data());
  CPPUNIT_ASSERT(buffer.length() == 40);
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StartRecord();
  CPPUNIT_ASSERT( m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StopRecord();
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded()); // still no macro

  // test wxExSTCShell
  m_STCShell->Prompt("test1");
  m_STCShell->Prompt("test2");
  m_STCShell->Prompt("test3");
  m_STCShell->Prompt("test4");
  // Prompting does not add a command to history.
  CPPUNIT_ASSERT(!m_STCShell->GetHistory().Contains("test4"));
  // Post 3 'a' chars to the shell, and check whether it comes in the history.
  wxKeyEvent event(wxEVT_CHAR);
  event.m_keyCode = 97; // one char 'a'
  wxPostEvent(m_STCShell, event);
  wxPostEvent(m_STCShell, event);
  wxPostEvent(m_STCShell, event);
  event.m_keyCode = WXK_RETURN;
  wxPostEvent(m_STCShell, event);
  // The event queue for shell is not yet processed, so next will assert anyway.
  //CPPUNIT_ASSERT(m_STCShell->GetHistory().Contains("aaa"));

  // test wxExSVN
//  CPPUNIT_ASSERT(m_SVN->Execute(NULL) == 0); // do not use a dialog
//  CPPUNIT_ASSERT(!m_SVN->GetOutput().empty());

  // test util
  CPPUNIT_ASSERT(wxExClipboardAdd("test"));
  CPPUNIT_ASSERT(wxExClipboardGet() == "test");
  CPPUNIT_ASSERT(wxExGetNumberOfLines("test\ntest\n") == 3);
  CPPUNIT_ASSERT(wxExGetLineNumberFromText("test on line: 1200") == 1200);

  // Only usefull if the lexers file was present
  if (wxExLexers::Get()->Count() > 0)
  {
    wxConfigBase::Get()->Write(_("Purpose"), "hello test");
    const wxExFileName fn(TEST_FILE);
    const wxString header = wxExHeader().Get(&fn);
    CPPUNIT_ASSERT(header.Contains("hello test"));
  }
  else
  {
    wxLogMessage("No lexers available");
  }

  CPPUNIT_ASSERT(wxExLog::Get()->Log("hello from wxExtension test"));
  CPPUNIT_ASSERT(!wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp"));
  CPPUNIT_ASSERT(wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp;*.txt"));
  CPPUNIT_ASSERT(wxExSkipWhiteSpace("t     es   t") == "t es t");
  CPPUNIT_ASSERT(!wxExTranslate("hello @PAGENUM@ from @PAGESCNT@", 1, 2).Contains("@"));
}

void wxExAppTestFixture::tearDown()
{
}

wxExTestSuite::wxExTestSuite()
  : CppUnit::TestSuite("wxExtension test suite")
{
  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testConstructors",
    &wxExAppTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testMethods",
    &wxExAppTestFixture::testMethods));
}
<|endoftext|>


<commit_before>// Open the two solution files named on standard input, find all
// variables they have in common, and output the Hilbert norms of the
// differences between them.

#include "libmesh.h"

#include "mesh.h"
#include "equation_systems.h"
#include "exact_solution.h"

unsigned int dim = 2; // This gets overridden by most mesh formats

int main(int argc, char** argv)
{
  LibMeshInit init(argc, argv);

  Mesh mesh1(dim), mesh2(dim);
  EquationSystems es1(mesh1), es2(mesh2);

  std::cout << "Usage: " << argv[0]
            << " coarsemesh coarsesolution finemesh finesolution" << std::endl;

  mesh1.read(argv[1]);
  std::cout << "Loaded coarse mesh " << argv[1] << std::endl;
  es1.read(argv[2], libMeshEnums::READ);
  std::cout << "Loaded coarse solution " << argv[2] << std::endl;
  mesh2.read(argv[3]);
  std::cout << "Loaded fine mesh " << argv[3] << std::endl;
  es2.read(argv[4], libMeshEnums::READ);
  std::cout << "Loaded fine solution " << argv[4] << std::endl;

  ExactSolution exact_sol(es1);
  exact_sol.attach_reference_solution(&es2);

  std::vector<std::string> sysnames;
  sysnames.reserve(es1.n_systems());

  for (unsigned int i = 0; i != es1.n_systems(); ++i)
    if (es2.has_system(es1.get_system(i).name()))
      sysnames.push_back(es1.get_system(i).name());

  for (unsigned int i = 0; i != sysnames.size(); ++i)
    {
      std::string sysname = sysnames[i];
      System &sys1 = es1.get_system(sysname);
      System &sys2 = es2.get_system(sysname);

      for (unsigned int j = 0; j != sys1.n_vars(); ++j)
        {
          std::string varname = sys1.variable_name(j);

          if (!sys2.has_variable(varname))
            continue;

          exact_sol.compute_error(sysname, varname);

          std::cout << "Errors in system " << sysname << ", variable " << varname << ":" << std::endl;
          std::cout << "L2 error: " << exact_sol.l2_error(sysname, varname) << std::endl;
          std::cout << "H1 error: " << exact_sol.h1_error(sysname, varname) << std::endl;
          std::cout << "H2 error: " << exact_sol.h2_error(sysname, varname) << std::endl;
        }
    }

  return 0.;
}
<commit_msg>return value warning on gcc-4.1 fixed.<commit_after>// Open the two solution files named on standard input, find all
// variables they have in common, and output the Hilbert norms of the
// differences between them.

#include "libmesh.h"

#include "mesh.h"
#include "equation_systems.h"
#include "exact_solution.h"

unsigned int dim = 2; // This gets overridden by most mesh formats

int main(int argc, char** argv)
{
  LibMeshInit init(argc, argv);

  Mesh mesh1(dim), mesh2(dim);
  EquationSystems es1(mesh1), es2(mesh2);

  std::cout << "Usage: " << argv[0]
            << " coarsemesh coarsesolution finemesh finesolution" << std::endl;

  mesh1.read(argv[1]);
  std::cout << "Loaded coarse mesh " << argv[1] << std::endl;
  es1.read(argv[2], libMeshEnums::READ);
  std::cout << "Loaded coarse solution " << argv[2] << std::endl;
  mesh2.read(argv[3]);
  std::cout << "Loaded fine mesh " << argv[3] << std::endl;
  es2.read(argv[4], libMeshEnums::READ);
  std::cout << "Loaded fine solution " << argv[4] << std::endl;

  ExactSolution exact_sol(es1);
  exact_sol.attach_reference_solution(&es2);

  std::vector<std::string> sysnames;
  sysnames.reserve(es1.n_systems());

  for (unsigned int i = 0; i != es1.n_systems(); ++i)
    if (es2.has_system(es1.get_system(i).name()))
      sysnames.push_back(es1.get_system(i).name());

  for (unsigned int i = 0; i != sysnames.size(); ++i)
    {
      std::string sysname = sysnames[i];
      System &sys1 = es1.get_system(sysname);
      System &sys2 = es2.get_system(sysname);

      for (unsigned int j = 0; j != sys1.n_vars(); ++j)
        {
          std::string varname = sys1.variable_name(j);

          if (!sys2.has_variable(varname))
            continue;

          exact_sol.compute_error(sysname, varname);

          std::cout << "Errors in system " << sysname << ", variable " << varname << ":" << std::endl;
          std::cout << "L2 error: " << exact_sol.l2_error(sysname, varname) << std::endl;
          std::cout << "H1 error: " << exact_sol.h1_error(sysname, varname) << std::endl;
          std::cout << "H2 error: " << exact_sol.h2_error(sysname, varname) << std::endl;
        }
    }

  return 0;
}
<|endoftext|>


<commit_before>/**
 * @file ProcessBus.hpp
 * @author Denis Kotov
 * @date 25 Jun 2017
 * @brief Contains ProcessBus class.
 * It is a broker pattern. Used to control registration
 * and connection of services
 * @copyright Denis Kotov, MIT License. Open source: https://github.com/redradist/Inter-Component-Communication.git
 */

#ifndef ICC_PROCESSBUS_HPP
#define ICC_PROCESSBUS_HPP

#include <algorithm>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>
#include <IComponent.hpp>
#include <helpers/hash_helpers.hpp>

namespace icc {

template<typename _T>
class Event;

namespace service {

template<typename _Interface>
class IClient;

template<typename _Interface>
class IService;

class ProcessBus
    : public virtual IComponent {
 public:
  using tKeyForClientList = std::pair<std::type_index, std::string>;
  using tListOfClients = std::unordered_map<void*, std::function<void*(void)>>;
  using tKeyForServiceList = std::type_index;
  using tServiceStorage = std::function<void*(void)>;
  using tListOfServices = std::unordered_map<std::string, tServiceStorage>;

 public:
  /**
   * This function is used for getting ProcessBus
   * It is used like Singleton pattern
   * @return ProcessBus
   */
  static ProcessBus &getBus();

 public:
  /**
   * This method is used for registering service
   * @tparam _Interface Interface for registration
   * @param _service Object of service for registration
   * @param _serviceName Name of service for registration
   */
  template<typename _Interface>
  void registerService(std::shared_ptr<IService<_Interface>> _service,
                       const std::string &_serviceName) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    invoke([=]() mutable {
      if (_service) {
        services_[tKeyForServiceList(typeid(_Interface))].
            emplace(_serviceName,
                    [_service]() mutable { return reinterpret_cast<void *>(&_service); });
        auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
        auto clients = clients_[clientsKey];
        for (auto client = clients.begin();
             client != clients.end();) {
          auto weak_client = *reinterpret_cast<std::weak_ptr<IClient<_Interface>>*>(client->second());
          if (auto _client = weak_client.lock()) {
            _client->connected(_service.get());
            ++client;
          } else {
            // NOTE(redra): Deleting client
            client = clients.erase(client);
          }
        }
      }
    });
  }

  /**
   * This method is used for unregistering service
   * @tparam _Interface Interface for unregistration
   * @param _service Object of service for unregistration
   * @param _serviceName Name of service for unregistration
   */
  template<typename _Interface>
  void unregisterService(std::shared_ptr<IService<_Interface>> _service,
                         const std::string &_serviceName) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    invoke([=] {
      if (_service) {
        services_[tKeyForServiceList(typeid(_Interface))].erase(_serviceName);
        auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
        auto clients = clients_[clientsKey];
        for (auto client = clients.begin();
             client != clients.end();) {
          auto weak_client = *reinterpret_cast<std::weak_ptr<IClient<_Interface>>*>(client->second());
          if (auto _client = weak_client.lock()) {
            _client->disconnected(nullptr);
            ++client;
          } else {
            // NOTE(redra): Deleting client
            client = clients.erase(client);
          }
        }
      }
    });
  }

  /**
   * This method is used for building client
   * (IClient<_Interface>) of IService<_Interface>
   * @tparam _Interface Interface for building client
   * @param _client Object of client waiting for building
   * @param _serviceName Name of service for building
   */
  template<typename _Interface>
  void buildClient(std::shared_ptr<IClient<_Interface>> _client,
                   const std::string &_serviceName) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    invoke([=] {
      if (_client) {
        auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
        std::weak_ptr<IClient<_Interface>> weak_client = _client;
        clients_[clientsKey].emplace(
            _client.get(),
            [weak_client]() mutable { return reinterpret_cast<void *>(&weak_client); });
        auto service = this->getService<_Interface>(_serviceName);
        if (service) {
          _client->connected(service.get());
        }
      }
    });
  }

  /**
   * This method is used for disassembling client
   * (IClient<_Interface>) of IService<_Interface>
   * @tparam _Interface Interface for building client
   * @param _client Object of client waiting for building
   * @param _serviceName Name of service for building
   */
  template<typename _Interface>
  void disassembleClient(IClient<_Interface> * _client,
                         const std::string &_serviceName) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    invoke([=] {
      if (_client) {
        auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
        clients_[clientsKey].erase(_client);
      }
    });
  }

 public:
  /**
   * This method is used to call method from IService<>
   * @tparam _Args Arguments types those is passed to external method
   * @tparam _Values Values types those is passed to external method
   * @param _callback Pointer to external method
   * @param _values Values passed into external method
   */
  template<typename _Interface,
           typename ... _Args,
           typename ... _Values>
  void call(const std::string &_serviceName,
            void(_Interface::*_callback)(_Args...), _Values ... _values) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    this->invoke([this, _serviceName, _callback, _values...]() mutable {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=]() mutable {
          (service.get()->*_callback)(_values...);
        });
      }
    });
  };

  /**
   * This method is used to call method from IService<>
   * @tparam _Params Arguments types for reply
   * @tparam _Args Arguments types for external method
   * @tparam _Values Values types those is passed to external method
   * @param _callback Pointer to external method
   * @param _reply Reply with some result from IService<>
   * @param _values Arguments passed into external method
   */
  template<typename _Interface,
           typename ... _Params,
           typename ... _Args,
           typename ... _Values>
  void call(const std::string &_serviceName,
            void(_Interface::*_callback)(std::function<void(_Params...)>, _Args...),
            std::function<void(_Params...)> _reply,
            _Values ... _values) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    this->invoke([this, _serviceName, _callback, _reply, _values...]() mutable {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        std::function<void(_Params ...)> _safeReply =
        [=](_Params ... params) {
          invoke([=] {
            _reply(params...);
          });
        };
        service->invoke([=]() mutable {
          (service.get()->*_callback)(_safeReply, _values...);
        });
      }
    });
  };

  /**
   * This method is used to subscribe on event from IService<>
   * @tparam _Client Client type in which located callback
   * @tparam _R Return value of Event<>
   * @tparam _Args Arguments of Event<>
   * @param _event Event for subscription
   * @param _callback Callback for subscription
   */
  template<typename _Interface,
           typename _Client,
           typename _R,
           typename ... _Args>
  void subscribe(std::shared_ptr<_Client> _client,
                 const std::string & _serviceName,
                 Event<_R(_Args...)> _Interface::*_event,
                 _R(_Client::*_callback)(_Args...)) {
    static_assert(std::is_base_of<IComponent, _Client>::value,
                  "IComponent is not a base class of _Client");
    invoke([this, _client, _serviceName, _event, _callback] {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=] {
          (service.get()->*_event).connect(_callback,
                                           _client);
        });
      }
    });
  };

  /**
   * This method is used to subscribe on event from IService<>
   * @tparam _Client Client type in which located callback
   * @tparam _R Return value of Event<>
   * @tparam _Args Arguments of Event<>
   * @param _event Event for subscription
   * @param _callback Callback for subscription
   */
  template<typename _Interface,
           typename _Client,
           typename _R,
           typename ... _Args>
  void subscribe(std::shared_ptr<IClient<_Interface>> _client,
                 const std::string & _serviceName,
                 Event<_R(_Args...)> _Interface::*_event,
                 _R(_Client::*_callback)(_Args...)) {
    static_assert(std::is_base_of<IClient<_Interface>, _Client>::value,
                  "IClient<_Interface> is not a base class of _Client");
    invoke([this, _client, _serviceName, _event, _callback] {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=] {
          (service.get()->*_event).connect(
              _callback,
              std::static_pointer_cast<_Client>(_client));
        });
      }
    });
  };

  /**
   * This method is used to unsubscribe on event from IService<>
   * @tparam _Client Client type in which located callback
   * @tparam _R Return value of Event<>
   * @tparam _Args Arguments of Event<>
   * @param _event Event for unsubscription
   * @param _callback Callback for unsubscription
   */
  template<typename _Interface,
           typename _Client,
           typename _R,
           typename ... _Args>
  void unsubscribe(std::shared_ptr<_Client> _client,
                   const std::string & _serviceName,
                   Event<_R(_Args...)> _Interface::*_event,
                   _R(_Client::*_callback)(_Args...)) {
    static_assert(std::is_base_of<IComponent, _Client>::value,
                  "IClient<_Interface> is not a base class of _Client");
    invoke([this, _client, _serviceName, _event, _callback] {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=] {
          (service.get()->*_event).disconnect(_callback,
                                              _client);
        });
      }
    });
  };

  /**
   * This method is used to unsubscribe on event from IService<>
   * @tparam _Client Client type in which located callback
   * @tparam _R Return value of Event<>
   * @tparam _Args Arguments of Event<>
   * @param _event Event for unsubscription
   * @param _callback Callback for unsubscription
   */
  template<typename _Interface,
           typename _Client,
           typename _R,
           typename ... _Args>
  void unsubscribe(std::shared_ptr<IClient<_Interface>> _client,
                   const std::string & _serviceName,
                   Event<_R(_Args...)> _Interface::*_event,
                   _R(_Client::*_callback)(_Args...)) {
    static_assert(std::is_base_of<IClient<_Interface>, _Client>::value,
                  "IClient<_Interface> is not a base class of _Client");
    invoke([this, _client, _serviceName, _event, _callback] {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=] {
          (service.get()->*_event).disconnect(
              _callback,
              std::static_pointer_cast<_Client>(_client));
        });
      }
    });
  };

 protected:
  /**
   * Helper function for finding service in ProcessBus tables
   * @tparam _Interface Interface type for searching
   * @param _serviceName Service name for searching
   * @return Service std::shared_ptr<IService<_Interface>>
   */
  template<typename _Interface>
  std::shared_ptr<IService<_Interface>>
  getService(const std::string &_serviceName) const {
    auto servicesIter = services_.find(std::type_index(typeid(_Interface)));
    if (services_.end() != servicesIter) {
      auto serviceIter = std::find_if(servicesIter->second.begin(),
                                      servicesIter->second.end(),
                                      [=](std::pair<std::string, std::function<void *(void)>> element) {
                                        return element.first == _serviceName;
                                      });
      if (servicesIter->second.end() != serviceIter) {
        return *reinterpret_cast<std::shared_ptr<IService<_Interface>> *>(
                                 serviceIter->second());
      }
    }
    return nullptr;
  }

 private:
  ProcessBus();
  ProcessBus(const ProcessBus &) = delete;
  ProcessBus & operator=(const ProcessBus &) = delete;
  ProcessBus(ProcessBus &&) = delete;
  ProcessBus & operator=(ProcessBus &&) = delete;
  virtual ~ProcessBus();

 private:
  std::thread thread_;
  std::unordered_map<tKeyForClientList, tListOfClients, icc::helpers::pair_hash> clients_;
  std::unordered_map<tKeyForServiceList, tListOfServices> services_;
};

}

}

#endif //ICC_PROCESSBUS_HPP
<commit_msg>Chnaged main function in Process Bus<commit_after>/**
 * @file ProcessBus.hpp
 * @author Denis Kotov
 * @date 25 Jun 2017
 * @brief Contains ProcessBus class.
 * It is a broker pattern. Used to control registration
 * and connection of services
 * @copyright Denis Kotov, MIT License. Open source: https://github.com/redradist/Inter-Component-Communication.git
 */

#ifndef ICC_PROCESSBUS_HPP
#define ICC_PROCESSBUS_HPP

#include <algorithm>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>
#include <IComponent.hpp>
#include <helpers/hash_helpers.hpp>

namespace icc {

template<typename _T>
class Event;

namespace service {

template<typename _Interface>
class IClient;

template<typename _Interface>
class IService;

class ProcessBus
    : public virtual IComponent {
 public:
  using tKeyForClientList = std::pair<std::type_index, std::string>;
  using tListOfClients = std::unordered_map<void*, std::function<void*(void)>>;
  using tKeyForServiceList = std::type_index;
  using tServiceStorage = std::function<void*(void)>;
  using tListOfServices = std::unordered_map<std::string, tServiceStorage>;

 public:
  /**
   * This function is used for getting ProcessBus
   * It is used like Singleton pattern
   * @return ProcessBus
   */
  static ProcessBus &getBus();

 public:
  /**
   * This method is used for registering service
   * @tparam _Interface Interface for registration
   * @param _service Object of service for registration
   * @param _serviceName Name of service for registration
   */
  template<typename _Interface>
  void registerService(std::shared_ptr<IService<_Interface>> _service,
                       const std::string &_serviceName) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    invoke([=]() mutable {
      if (_service) {
        services_[tKeyForServiceList(typeid(_Interface))].
            emplace(_serviceName,
                    [_service]() mutable { return reinterpret_cast<void *>(&_service); });
        auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
        auto clients = clients_[clientsKey];
        for (auto client = clients.begin();
             client != clients.end();) {
          auto weak_client = *reinterpret_cast<std::weak_ptr<IClient<_Interface>>*>(client->second());
          if (auto _client = weak_client.lock()) {
            _client->connected(_service.get());
            ++client;
          } else {
            // NOTE(redra): Deleting client
            client = clients.erase(client);
          }
        }
      }
    });
  }

  /**
   * This method is used for unregistering service
   * @tparam _Interface Interface for unregistration
   * @param _service Object of service for unregistration
   * @param _serviceName Name of service for unregistration
   */
  template<typename _Interface>
  void unregisterService(std::shared_ptr<IService<_Interface>> _service,
                         const std::string &_serviceName) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    invoke([=] {
      if (_service) {
        services_[tKeyForServiceList(typeid(_Interface))].erase(_serviceName);
        auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
        auto clients = clients_[clientsKey];
        for (auto client = clients.begin();
             client != clients.end();) {
          auto weak_client = *reinterpret_cast<std::weak_ptr<IClient<_Interface>>*>(client->second());
          if (auto _client = weak_client.lock()) {
            _client->disconnected(nullptr);
            ++client;
          } else {
            // NOTE(redra): Deleting client
            client = clients.erase(client);
          }
        }
      }
    });
  }

  /**
   * This method is used for building client
   * (IClient<_Interface>) of IService<_Interface>
   * @tparam _Interface Interface for building client
   * @param _client Object of client waiting for building
   * @param _serviceName Name of service for building
   */
  template<typename _Interface>
  void buildClient(std::shared_ptr<IClient<_Interface>> _client,
                   const std::string &_serviceName) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    invoke([=] {
      if (_client) {
        auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
        std::weak_ptr<IClient<_Interface>> weak_client = _client;
        clients_[clientsKey].emplace(
            _client.get(),
            [weak_client]() mutable { return reinterpret_cast<void *>(&weak_client); });
        auto service = this->getService<_Interface>(_serviceName);
        if (service) {
          _client->connected(service.get());
        }
      }
    });
  }

  /**
   * This method is used for disassembling client
   * (IClient<_Interface>) of IService<_Interface>
   * @tparam _Interface Interface for building client
   * @param _client Object of client waiting for building
   * @param _serviceName Name of service for building
   */
  template<typename _Interface>
  void disassembleClient(IClient<_Interface> * _client,
                         const std::string &_serviceName) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    invoke([=] {
      if (_client) {
        auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
        clients_[clientsKey].erase(_client);
      }
    });
  }

 public:
  /**
   * This method is used to call method from IService<>
   * @tparam _Args Arguments types those is passed to external method
   * @tparam _Values Values types those is passed to external method
   * @param _callback Pointer to external method
   * @param _values Values passed into external method
   */
  template<typename _Interface,
           typename ... _Args,
           typename ... _Values>
  void call(const std::string &_serviceName,
            void(_Interface::*_callback)(_Args...), _Values ... _values) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    push([this, _serviceName, _callback, _values...]() mutable {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=]() mutable {
          (service.get()->*_callback)(_values...);
        });
      }
    });
  };

  /**
   * This method is used to call method from IService<>
   * @tparam _Params Arguments types for reply
   * @tparam _Args Arguments types for external method
   * @tparam _Values Values types those is passed to external method
   * @param _callback Pointer to external method
   * @param _reply Reply with some result from IService<>
   * @param _values Arguments passed into external method
   */
  template<typename _Interface,
           typename ... _Params,
           typename ... _Args,
           typename ... _Values>
  void call(const std::string &_serviceName,
            void(_Interface::*_callback)(std::function<void(_Params...)>, _Args...),
            std::function<void(_Params...)> _reply,
            _Values ... _values) {
    static_assert(std::is_abstract<_Interface>::value,
                  "_Interface is not an abstract class");
    push([this, _serviceName, _callback, _reply, _values...]() mutable {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        std::function<void(_Params ...)> _safeReply =
        [=](_Params ... params) {
          push([=] {
            _reply(params...);
          });
        };
        service->invoke([=]() mutable {
          (service.get()->*_callback)(_safeReply, _values...);
        });
      }
    });
  };

  /**
   * This method is used to subscribe on event from IService<>
   * @tparam _Client Client type in which located callback
   * @tparam _R Return value of Event<>
   * @tparam _Args Arguments of Event<>
   * @param _event Event for subscription
   * @param _callback Callback for subscription
   */
  template<typename _Interface,
           typename _Client,
           typename _R,
           typename ... _Args>
  void subscribe(std::shared_ptr<_Client> _client,
                 const std::string & _serviceName,
                 Event<_R(_Args...)> _Interface::*_event,
                 _R(_Client::*_callback)(_Args...)) {
    static_assert(std::is_base_of<IComponent, _Client>::value,
                  "IComponent is not a base class of _Client");
    invoke([this, _client, _serviceName, _event, _callback] {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=] {
          (service.get()->*_event).connect(_callback,
                                           _client);
        });
      }
    });
  };

  /**
   * This method is used to subscribe on event from IService<>
   * @tparam _Client Client type in which located callback
   * @tparam _R Return value of Event<>
   * @tparam _Args Arguments of Event<>
   * @param _event Event for subscription
   * @param _callback Callback for subscription
   */
  template<typename _Interface,
           typename _Client,
           typename _R,
           typename ... _Args>
  void subscribe(std::shared_ptr<IClient<_Interface>> _client,
                 const std::string & _serviceName,
                 Event<_R(_Args...)> _Interface::*_event,
                 _R(_Client::*_callback)(_Args...)) {
    static_assert(std::is_base_of<IClient<_Interface>, _Client>::value,
                  "IClient<_Interface> is not a base class of _Client");
    invoke([this, _client, _serviceName, _event, _callback] {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=] {
          (service.get()->*_event).connect(
              _callback,
              std::static_pointer_cast<_Client>(_client));
        });
      }
    });
  };

  /**
   * This method is used to unsubscribe on event from IService<>
   * @tparam _Client Client type in which located callback
   * @tparam _R Return value of Event<>
   * @tparam _Args Arguments of Event<>
   * @param _event Event for unsubscription
   * @param _callback Callback for unsubscription
   */
  template<typename _Interface,
           typename _Client,
           typename _R,
           typename ... _Args>
  void unsubscribe(std::shared_ptr<_Client> _client,
                   const std::string & _serviceName,
                   Event<_R(_Args...)> _Interface::*_event,
                   _R(_Client::*_callback)(_Args...)) {
    static_assert(std::is_base_of<IComponent, _Client>::value,
                  "IClient<_Interface> is not a base class of _Client");
    invoke([this, _client, _serviceName, _event, _callback] {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=] {
          (service.get()->*_event).disconnect(_callback,
                                              _client);
        });
      }
    });
  };

  /**
   * This method is used to unsubscribe on event from IService<>
   * @tparam _Client Client type in which located callback
   * @tparam _R Return value of Event<>
   * @tparam _Args Arguments of Event<>
   * @param _event Event for unsubscription
   * @param _callback Callback for unsubscription
   */
  template<typename _Interface,
           typename _Client,
           typename _R,
           typename ... _Args>
  void unsubscribe(std::shared_ptr<IClient<_Interface>> _client,
                   const std::string & _serviceName,
                   Event<_R(_Args...)> _Interface::*_event,
                   _R(_Client::*_callback)(_Args...)) {
    static_assert(std::is_base_of<IClient<_Interface>, _Client>::value,
                  "IClient<_Interface> is not a base class of _Client");
    invoke([this, _client, _serviceName, _event, _callback] {
      auto service = this->getService<_Interface>(_serviceName);
      if (service) {
        service->invoke([=] {
          (service.get()->*_event).disconnect(
              _callback,
              std::static_pointer_cast<_Client>(_client));
        });
      }
    });
  };

 protected:
  /**
   * Helper function for finding service in ProcessBus tables
   * @tparam _Interface Interface type for searching
   * @param _serviceName Service name for searching
   * @return Service std::shared_ptr<IService<_Interface>>
   */
  template<typename _Interface>
  std::shared_ptr<IService<_Interface>>
  getService(const std::string &_serviceName) const {
    auto servicesIter = services_.find(std::type_index(typeid(_Interface)));
    if (services_.end() != servicesIter) {
      auto serviceIter = std::find_if(servicesIter->second.begin(),
                                      servicesIter->second.end(),
                                      [=](std::pair<std::string, std::function<void *(void)>> element) {
                                        return element.first == _serviceName;
                                      });
      if (servicesIter->second.end() != serviceIter) {
        return *reinterpret_cast<std::shared_ptr<IService<_Interface>> *>(
                                 serviceIter->second());
      }
    }
    return nullptr;
  }

 private:
  ProcessBus();
  ProcessBus(const ProcessBus &) = delete;
  ProcessBus & operator=(const ProcessBus &) = delete;
  ProcessBus(ProcessBus &&) = delete;
  ProcessBus & operator=(ProcessBus &&) = delete;
  virtual ~ProcessBus();

 private:
  std::thread thread_;
  std::unordered_map<tKeyForClientList, tListOfClients, icc::helpers::pair_hash> clients_;
  std::unordered_map<tKeyForServiceList, tListOfServices> services_;
};

}

}

#endif //ICC_PROCESSBUS_HPP
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/vespalib/util/random.h>
#include <vespa/searchlib/docstore/logdatastore.h>
#include <vespa/searchlib/index/dummyfileheadercontext.h>
#include <vespa/searchlib/transactionlog/nosyncproxy.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/threadstackexecutor.h>
#include <vespa/vespalib/data/databuffer.h>

using namespace search;
using search::index::DummyFileHeaderContext;

class Test : public vespalib::TestApp {
private:
    struct Blob {
        ssize_t sz;
        char *buf;
        Blob(size_t s) : sz(s), buf(s == 0 ? 0 : new char[s]) {}
    };
    typedef std::map<uint32_t, uint32_t> Map;

    void makeBlobs();
    void cleanBlobs();
    void checkBlobs(const IDataStore &datastore, const Map &lidToBlobMap);

    template <typename DS>
    void testDIO();

    std::string _dir;
    std::vector<Blob> _blobs;
    vespalib::RandomGen _randomgenerator;

public:
    int Main() override {
        TEST_INIT("big_logdatastore_test");

        if (_argc > 0) {
            DummyFileHeaderContext::setCreator(_argv[0]);
        }
        makeBlobs();

        _dir = "logged";
        TEST_DO(testDIO<LogDataStore>());

        cleanBlobs();

        TEST_DONE();
    }

    Test() : _dir(""), _blobs(), _randomgenerator(42) {}
};

TEST_APPHOOK(Test);

void
Test::makeBlobs()
{
    _randomgenerator.setSeed(42);
    _blobs.push_back(Blob(0));
    size_t usemem = 444222111;
    while (usemem > 0) {
        size_t sizeclass = 6 + _randomgenerator.nextUint32() % 20;
        size_t blobsize = _randomgenerator.nextUint32() % (1<<sizeclass);
        if (blobsize > usemem) blobsize = usemem;
        _blobs.push_back(Blob(blobsize));
        char *p = _blobs.back().buf;
        for (size_t j=0; j < blobsize; ++j) {
            *p++ = _randomgenerator.nextUint32();
        }
        usemem -= blobsize;
    }
}

void
Test::cleanBlobs()
{
    printf("count %lu blobs sizes:", _blobs.size());
    while (_blobs.size() > 0) {
        char *p = _blobs.back().buf;
        printf(" %lu", _blobs.back().sz);
        delete[] p;
        _blobs.pop_back();
    }
    printf("\n");
}

void
Test::checkBlobs(const IDataStore &datastore,
                 const Map &lidToBlobMap)
{
    for (Map::const_iterator it = lidToBlobMap.begin();
         it != lidToBlobMap.end();
         ++it)
    {
        uint32_t lid = it->first;
        uint32_t bno = it->second;
        vespalib::DataBuffer got;
        EXPECT_EQUAL(datastore.read(lid, got), _blobs[bno].sz);
        EXPECT_TRUE(memcmp(got.getData(), _blobs[bno].buf, _blobs[bno].sz) == 0);
    }
}

struct DioTune
{
    TuneFileSummary tuning;
    DioTune() {
        tuning._seqRead.setWantDirectIO();
        tuning._write.setWantDirectIO();
        tuning._randRead.setWantDirectIO();
    }
};

template <typename DS>
struct factory {};

template <>
struct factory<LogDataStore> : DioTune
{
    DummyFileHeaderContext _fileHeaderContext;
    LogDataStore::Config   _config;
    vespalib::ThreadStackExecutor _executor;
    transactionlog::NoSyncProxy _noTlSyncer;
    LogDataStore _datastore;
    factory(std::string dir);
    ~factory();
    IDataStore & operator() () { return _datastore; }

};

factory<LogDataStore>::factory(std::string dir)
    : DioTune(),
      _fileHeaderContext(),
      _config(),
      _executor(_config.getNumThreads(), 128*1024),
      _noTlSyncer(),
      _datastore(_executor, dir, _config, GrowStrategy(), tuning, _fileHeaderContext, _noTlSyncer, NULL)
{}

factory<LogDataStore>::~factory() {}

template <typename DS>
void
Test::testDIO()
{
    uint64_t serial = 0;

    FastOS_File::EmptyDirectory(_dir.c_str());
    FastOS_File::RemoveDirectory(_dir.c_str());
    EXPECT_TRUE(FastOS_File::MakeDirectory(_dir.c_str()));

    Map lidToBlobMap;
    vespalib::DataBuffer buf;
    {
        factory<DS> ds(_dir);
        for (uint32_t lid=0; lid<15; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        uint64_t flushToken = ds().initFlush(serial);
        ds().flush(flushToken);
        for (uint32_t lid=10; lid<30; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        checkBlobs(ds(), lidToBlobMap);
        flushToken = ds().initFlush(serial);
        ds().flush(flushToken);
        checkBlobs(ds(), lidToBlobMap);
    }
    {
        factory<DS> ds(_dir);
        checkBlobs(ds(), lidToBlobMap);

        for (uint32_t lid=3; lid<8; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        for (uint32_t lid=23; lid<28; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        for (uint32_t lid=100033; lid<100088; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        checkBlobs(ds(), lidToBlobMap);

        ds().remove(++serial, 1);
        lidToBlobMap[1] = 0;
        ds().remove(++serial, 11);
        lidToBlobMap[11] = 0;
        ds().remove(++serial, 21);
        lidToBlobMap[21] = 0;
        ds().remove(++serial, 31);
        lidToBlobMap[31] = 0;

        checkBlobs(ds(), lidToBlobMap);
        uint64_t flushToken = ds().initFlush(serial);
        ds().flush(flushToken);
        checkBlobs(ds(), lidToBlobMap);
    }
    {
        factory<DS> ds(_dir);

        ASSERT_TRUE(ds().read(1, buf) <= 0);
        ASSERT_TRUE(ds().read(11, buf) <= 0);
        ASSERT_TRUE(ds().read(21, buf) <= 0);
        ASSERT_TRUE(ds().read(31, buf) <= 0);

        checkBlobs(ds(), lidToBlobMap);
        uint64_t flushToken = ds().initFlush(serial);
        ds().flush(flushToken);
    }
    {
        factory<DS> ds(_dir);
        checkBlobs(ds(), lidToBlobMap);

        for (uint32_t lid=1234567; lid < 1234999; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        checkBlobs(ds(), lidToBlobMap);
        uint64_t flushToken = ds().initFlush(22);
        ds().flush(flushToken);
        checkBlobs(ds(), lidToBlobMap);
    }
    {
        factory<DS> ds(_dir);
        checkBlobs(ds(), lidToBlobMap);
    }
    FastOS_File::EmptyDirectory(_dir.c_str());
    FastOS_File::RemoveDirectory(_dir.c_str());
    TEST_FLUSH();
}
<commit_msg>Deinline destructors++<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/vespalib/util/random.h>
#include <vespa/searchlib/docstore/logdatastore.h>
#include <vespa/searchlib/index/dummyfileheadercontext.h>
#include <vespa/searchlib/transactionlog/nosyncproxy.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/threadstackexecutor.h>
#include <vespa/vespalib/data/databuffer.h>

using namespace search;
using search::index::DummyFileHeaderContext;

class Test : public vespalib::TestApp {
private:
    struct Blob {
        ssize_t sz;
        char *buf;
        Blob(size_t s) : sz(s), buf(s == 0 ? 0 : new char[s]) {}
    };
    typedef std::map<uint32_t, uint32_t> Map;

    void makeBlobs();
    void cleanBlobs();
    void checkBlobs(const IDataStore &datastore, const Map &lidToBlobMap);

    template <typename DS>
    void testDIO();

    std::string _dir;
    std::vector<Blob> _blobs;
    vespalib::RandomGen _randomgenerator;

public:
    int Main() override {
        TEST_INIT("big_logdatastore_test");

        if (_argc > 0) {
            DummyFileHeaderContext::setCreator(_argv[0]);
        }
        makeBlobs();

        _dir = "logged";
        TEST_DO(testDIO<LogDataStore>());

        cleanBlobs();

        TEST_DONE();
    }

    Test() : _dir(""), _blobs(), _randomgenerator(42) {}
    ~Test() {}
};

TEST_APPHOOK(Test);

void
Test::makeBlobs()
{
    _randomgenerator.setSeed(42);
    _blobs.push_back(Blob(0));
    size_t usemem = 444222111;
    while (usemem > 0) {
        size_t sizeclass = 6 + _randomgenerator.nextUint32() % 20;
        size_t blobsize = _randomgenerator.nextUint32() % (1<<sizeclass);
        if (blobsize > usemem) blobsize = usemem;
        _blobs.push_back(Blob(blobsize));
        char *p = _blobs.back().buf;
        for (size_t j=0; j < blobsize; ++j) {
            *p++ = _randomgenerator.nextUint32();
        }
        usemem -= blobsize;
    }
}

void
Test::cleanBlobs()
{
    printf("count %lu blobs sizes:", _blobs.size());
    while (_blobs.size() > 0) {
        char *p = _blobs.back().buf;
        printf(" %lu", _blobs.back().sz);
        delete[] p;
        _blobs.pop_back();
    }
    printf("\n");
}

void
Test::checkBlobs(const IDataStore &datastore,
                 const Map &lidToBlobMap)
{
    for (Map::const_iterator it = lidToBlobMap.begin();
         it != lidToBlobMap.end();
         ++it)
    {
        uint32_t lid = it->first;
        uint32_t bno = it->second;
        vespalib::DataBuffer got;
        EXPECT_EQUAL(datastore.read(lid, got), _blobs[bno].sz);
        EXPECT_TRUE(memcmp(got.getData(), _blobs[bno].buf, _blobs[bno].sz) == 0);
    }
}

struct DioTune
{
    TuneFileSummary tuning;
    DioTune() {
        tuning._seqRead.setWantDirectIO();
        tuning._write.setWantDirectIO();
        tuning._randRead.setWantDirectIO();
    }
};

template <typename DS>
struct factory {};

template <>
struct factory<LogDataStore> : DioTune
{
    DummyFileHeaderContext _fileHeaderContext;
    LogDataStore::Config   _config;
    vespalib::ThreadStackExecutor _executor;
    transactionlog::NoSyncProxy _noTlSyncer;
    LogDataStore _datastore;
    factory(std::string dir);
    ~factory();
    IDataStore & operator() () { return _datastore; }

};

factory<LogDataStore>::factory(std::string dir)
    : DioTune(),
      _fileHeaderContext(),
      _config(),
      _executor(_config.getNumThreads(), 128*1024),
      _noTlSyncer(),
      _datastore(_executor, dir, _config, GrowStrategy(), tuning, _fileHeaderContext, _noTlSyncer, NULL)
{}

factory<LogDataStore>::~factory() {}

template <typename DS>
void
Test::testDIO()
{
    uint64_t serial = 0;

    FastOS_File::EmptyDirectory(_dir.c_str());
    FastOS_File::RemoveDirectory(_dir.c_str());
    EXPECT_TRUE(FastOS_File::MakeDirectory(_dir.c_str()));

    Map lidToBlobMap;
    vespalib::DataBuffer buf;
    {
        factory<DS> ds(_dir);
        for (uint32_t lid=0; lid<15; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        uint64_t flushToken = ds().initFlush(serial);
        ds().flush(flushToken);
        for (uint32_t lid=10; lid<30; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        checkBlobs(ds(), lidToBlobMap);
        flushToken = ds().initFlush(serial);
        ds().flush(flushToken);
        checkBlobs(ds(), lidToBlobMap);
    }
    {
        factory<DS> ds(_dir);
        checkBlobs(ds(), lidToBlobMap);

        for (uint32_t lid=3; lid<8; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        for (uint32_t lid=23; lid<28; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        for (uint32_t lid=100033; lid<100088; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        checkBlobs(ds(), lidToBlobMap);

        ds().remove(++serial, 1);
        lidToBlobMap[1] = 0;
        ds().remove(++serial, 11);
        lidToBlobMap[11] = 0;
        ds().remove(++serial, 21);
        lidToBlobMap[21] = 0;
        ds().remove(++serial, 31);
        lidToBlobMap[31] = 0;

        checkBlobs(ds(), lidToBlobMap);
        uint64_t flushToken = ds().initFlush(serial);
        ds().flush(flushToken);
        checkBlobs(ds(), lidToBlobMap);
    }
    {
        factory<DS> ds(_dir);

        ASSERT_TRUE(ds().read(1, buf) <= 0);
        ASSERT_TRUE(ds().read(11, buf) <= 0);
        ASSERT_TRUE(ds().read(21, buf) <= 0);
        ASSERT_TRUE(ds().read(31, buf) <= 0);

        checkBlobs(ds(), lidToBlobMap);
        uint64_t flushToken = ds().initFlush(serial);
        ds().flush(flushToken);
    }
    {
        factory<DS> ds(_dir);
        checkBlobs(ds(), lidToBlobMap);

        for (uint32_t lid=1234567; lid < 1234999; ++lid) {
            uint32_t blobno = _randomgenerator.nextUint32() % _blobs.size();
            lidToBlobMap[lid] = blobno;
            ds().write(++serial, lid, _blobs[blobno].buf, _blobs[blobno].sz);
        }
        checkBlobs(ds(), lidToBlobMap);
        uint64_t flushToken = ds().initFlush(22);
        ds().flush(flushToken);
        checkBlobs(ds(), lidToBlobMap);
    }
    {
        factory<DS> ds(_dir);
        checkBlobs(ds(), lidToBlobMap);
    }
    FastOS_File::EmptyDirectory(_dir.c_str());
    FastOS_File::RemoveDirectory(_dir.c_str());
    TEST_FLUSH();
}
<|endoftext|>