<commit_before>/*! \file main.cpp
 *  \brief Program to run the grid code. */

#ifdef MPI_CHOLLA
#include <mpi.h>
#include "mpi_routines.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "global.h"
#include "grid3D.h"
#include "io.h"
#include "error_handling.h"

int main(int argc, char *argv[])
{
  // timing variables
  double start_total, stop_total, start_step, stop_step;
  #ifdef CPU_TIME
  double stop_init, init_min, init_max, init_avg;
  double start_bound, stop_bound, bound_min, bound_max, bound_avg;
  double start_hydro, stop_hydro, hydro_min, hydro_max, hydro_avg;
  double init, bound, hydro;
  init = bound = hydro = 0;
  #endif //CPU_TIME

  // start the total time
  start_total = get_time();

  /* Initialize MPI communication */
  #ifdef MPI_CHOLLA
  InitializeChollaMPI(&argc, &argv);
  #endif /*MPI_CHOLLA*/

  Real dti = 0; // inverse time step, 1.0 / dt

  // input parameter variables
  char *param_file;
  struct parameters P;
  int nfile = 0; // number of output files
  Real outtime = 0; // current output time

  // read in command line arguments
  if (argc != 2)
  {
    chprintf("usage: %s <parameter_file>\n", argv[0]);
    chexit(-1);
  } else {
    param_file = argv[1];
  }

  // create the grid
  Grid3D G;

  // read in the parameters
  parse_params (param_file, &P);
  // and output to screen
  chprintf ("Parameter values:  nx = %d, ny = %d, nz = %d, tout = %f, init = %s, boundaries = %d %d %d %d %d %d\n",
    P.nx, P.ny, P.nz, P.tout, P.init, P.xl_bcnd, P.xu_bcnd, P.yl_bcnd, P.yu_bcnd, P.zl_bcnd, P.zu_bcnd);
  if (strcmp(P.init, "Read_Grid") == 0  ) chprintf ("Input directory:  %s\n", P.indir);
  chprintf ("Output directory:  %s\n", P.outdir);

  //Create a Log file to output run-time messages
  Create_Log_File(P);

  // initialize the grid
  G.Initialize(&P);
  chprintf("Local number of grid cells: %d %d %d %d\n", G.H.nx_real, G.H.ny_real, G.H.nz_real, G.H.n_cells);

  char *message = (char*)malloc(50 * sizeof(char));
  sprintf(message, "Initializing Simulation" );
  Write_Message_To_Log_File( message );

  // Set initial conditions and calculate first dt
  chprintf("Setting initial conditions...\n");
  G.Set_Initial_Conditions(P);
  chprintf("Initial conditions set.\n");
  // set main variables for Read_Grid initial conditions
  if (strcmp(P.init, "Read_Grid") == 0) {
    dti = C_cfl / G.H.dt;
    outtime += G.H.t;
    nfile = P.nfile;
  }

  #ifdef DE
  chprintf("\nUsing Dual Energy Formalism:\n eta_1: %0.3f   eta_2: %0.4f\n", DE_ETA_1, DE_ETA_2 );
  sprintf(message, " eta_1: %0.3f   eta_2: %0.3f  ", DE_ETA_1, DE_ETA_2 );
  Write_Message_To_Log_File( message );
  #endif

  #ifdef CPU_TIME
  G.Timer.Initialize();
  #endif

  #ifdef GRAVITY
  G.Initialize_Gravity(&P);
  #endif

  #ifdef PARTICLES
  G.Initialize_Particles(&P);
  #endif

  #ifdef COSMOLOGY
  G.Initialize_Cosmology(&P);
  #endif

  #ifdef COOLING_GRACKLE
  G.Initialize_Grackle(&P);
  #endif

  #ifdef ANALYSIS
  G.Initialize_Analysis_Module(&P);
  if ( G.Analysis.Output_Now ) G.Compute_and_Output_Analysis(&P);
  #endif

  #ifdef GRAVITY
  // Get the gravitaional potential for the first timestep
  G.Compute_Gravitational_Potential( &P);
  #endif

  // Set boundary conditions (assign appropriate values to ghost cells) for hydro and potential
  chprintf("Setting boundary conditions...\n");
  G.Set_Boundary_Conditions_Grid(P);
  chprintf("Boundary conditions set.\n");

  #ifdef GRAVITY_ANALYTIC_COMP
  // add analytic component to gravity potential.
  G.Add_Analytic_Potential(&P);
  #endif

  #ifdef PARTICLES
  // Get the particles acceleration for the first timestep
  G.Get_Particles_Acceleration();
  #endif

  chprintf("Dimensions of each cell: dx = %f dy = %f dz = %f\n", G.H.dx, G.H.dy, G.H.dz);
  chprintf("Ratio of specific heats gamma = %f\n",gama);
  chprintf("Nstep = %d  Timestep = %f  Simulation time = %f\n", G.H.n_step, G.H.dt, G.H.t);

  #ifdef OUTPUT
  if (strcmp(P.init, "Read_Grid") != 0 || G.H.Output_Now ) {
    // write the initial conditions to file
    chprintf("Writing initial conditions to file...\n");
    #ifdef MPI_GPU
    cudaMemcpy(G.C.density, G.C.device,
             G.H.n_fields*G.H.n_cells*sizeof(Real), cudaMemcpyDeviceToHost);
    #endif
    WriteData(G, P, nfile);
  }
  // add one to the output file count
  nfile++;
  #endif //OUTPUT
  // increment the next output time
  outtime += P.outstep;

  #ifdef CPU_TIME
  stop_init = get_time();
  init = stop_init - start_total;
  #ifdef MPI_CHOLLA
  init_min = ReduceRealMin(init);
  init_max = ReduceRealMax(init);
  init_avg = ReduceRealAvg(init);
  chprintf("Init  min: %9.4f  max: %9.4f  avg: %9.4f\n", init_min, init_max, init_avg);
  #else
  printf("Init %9.4f\n", init);
  #endif //MPI_CHOLLA
  #endif //CPU_TIME

  // Evolve the grid, one timestep at a time
  chprintf("Starting calculations.\n");
  sprintf(message, "Starting calculations." );
  Write_Message_To_Log_File( message );
  while (G.H.t < P.tout)
  {
    // get the start time
    start_step = get_time();

    // calculate the timestep
    G.set_dt(dti);

    if (G.H.t + G.H.dt > outtime) G.H.dt = outtime - G.H.t;

    #ifdef PARTICLES
    //Advance the particles KDK( first step ): Velocities are updated by 0.5*dt and positions are updated by dt
    G.Advance_Particles( 1 );
    //Transfer the particles that moved outside the local domain
    G.Transfer_Particles_Boundaries(P);
    #endif

    // Advance the grid by one timestep
    dti = G.Update_Hydro_Grid();

    // update the simulation time ( t += dt )
    G.Update_Time();

    #ifdef GRAVITY
    //Compute Gravitational potential for next step
    G.Compute_Gravitational_Potential( &P);
    #endif

    // add one to the timestep count
    G.H.n_step++;

    //Set the Grid boundary conditions for next time step
    G.Set_Boundary_Conditions_Grid(P);

    #ifdef GRAVITY_ANALYTIC_COMP
    // add analytic component to gravity potential.
    G.Add_Analytic_Potential(&P);
    #endif

    #ifdef PARTICLES
    ///Advance the particles KDK( second step ): Velocities are updated by 0.5*dt using the Accelerations at the new positions
    G.Advance_Particles( 2 );
    #endif

    #ifdef PARTICLE_AGE
    //G.Cluster_Feedback();
    #endif

    #ifdef CPU_TIME
    G.Timer.Print_Times();
    #endif

    // get the time to compute the total timestep
    stop_step = get_time();
    stop_total = get_time();
    G.H.t_wall = stop_total-start_total;
    #ifdef MPI_CHOLLA
    G.H.t_wall = ReduceRealMax(G.H.t_wall);
    #endif
    chprintf("n_step: %d   sim time: %10.7f   sim timestep: %7.4e  timestep time = %9.3f ms   total time = %9.4f s\n\n",
      G.H.n_step, G.H.t, G.H.dt, (stop_step-start_step)*1000, G.H.t_wall);

    #ifdef OUTPUT_ALWAYS
    G.H.Output_Now = true;
    #endif

    #ifdef ANALYSIS
    if ( G.Analysis.Output_Now ) G.Compute_and_Output_Analysis(&P);
    #endif

    // if ( P.n_steps_output > 0 && G.H.n_step % P.n_steps_output == 0) G.H.Output_Now = true;

    if (G.H.t == outtime || G.H.Output_Now )
    {
      #ifdef OUTPUT
      /*output the grid data*/
      #ifdef MPI_GPU
      cudaMemcpy(G.C.density, G.C.device,
                 G.H.n_fields*G.H.n_cells*sizeof(Real), cudaMemcpyDeviceToHost);
      #endif
      WriteData(G, P, nfile);
      // add one to the output file count
      nfile++;
      #endif //OUTPUT
      // update to the next output time
      outtime += P.outstep;
    }

    #ifdef CPU_TIME
    G.Timer.n_steps += 1;
    #endif

    #ifdef N_STEPS_LIMIT
    // Exit the loop when reached the limit number of steps (optional)
    if ( G.H.n_step == N_STEPS_LIMIT) {
      #ifdef MPI_GPU
      cudaMemcpy(G.C.density, G.C.device,
                 G.H.n_fields*G.H.n_cells*sizeof(Real), cudaMemcpyDeviceToHost);
      #endif
      WriteData(G, P, nfile);
      break;
    }
    #endif

    #ifdef COSMOLOGY
    // Exit the loop when reached the last scale_factor output
    if ( G.Cosmo.exit_now ) {
      chprintf( "\nReached Last Cosmological Output: Ending Simulation\n");
      break;
    }
    #endif

  } /*end loop over timesteps*/

  #ifdef CPU_TIME
  // Print timing statistics
  G.Timer.Get_Average_Times();
  G.Timer.Print_Average_Times( P );
  #endif

  sprintf(message, "Simulation completed successfully." );
  Write_Message_To_Log_File( message );

  // free the grid
  G.Reset();

  #ifdef MPI_CHOLLA
  MPI_Finalize();
  #endif /*MPI_CHOLLA*/

  return 0;

}
<commit_msg>don't save when reaching last step<commit_after>/*! \file main.cpp
 *  \brief Program to run the grid code. */

#ifdef MPI_CHOLLA
#include <mpi.h>
#include "mpi_routines.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "global.h"
#include "grid3D.h"
#include "io.h"
#include "error_handling.h"

int main(int argc, char *argv[])
{
  // timing variables
  double start_total, stop_total, start_step, stop_step;
  #ifdef CPU_TIME
  double stop_init, init_min, init_max, init_avg;
  double start_bound, stop_bound, bound_min, bound_max, bound_avg;
  double start_hydro, stop_hydro, hydro_min, hydro_max, hydro_avg;
  double init, bound, hydro;
  init = bound = hydro = 0;
  #endif //CPU_TIME

  // start the total time
  start_total = get_time();

  /* Initialize MPI communication */
  #ifdef MPI_CHOLLA
  InitializeChollaMPI(&argc, &argv);
  #endif /*MPI_CHOLLA*/

  Real dti = 0; // inverse time step, 1.0 / dt

  // input parameter variables
  char *param_file;
  struct parameters P;
  int nfile = 0; // number of output files
  Real outtime = 0; // current output time

  // read in command line arguments
  if (argc != 2)
  {
    chprintf("usage: %s <parameter_file>\n", argv[0]);
    chexit(-1);
  } else {
    param_file = argv[1];
  }

  // create the grid
  Grid3D G;

  // read in the parameters
  parse_params (param_file, &P);
  // and output to screen
  chprintf ("Parameter values:  nx = %d, ny = %d, nz = %d, tout = %f, init = %s, boundaries = %d %d %d %d %d %d\n",
    P.nx, P.ny, P.nz, P.tout, P.init, P.xl_bcnd, P.xu_bcnd, P.yl_bcnd, P.yu_bcnd, P.zl_bcnd, P.zu_bcnd);
  if (strcmp(P.init, "Read_Grid") == 0  ) chprintf ("Input directory:  %s\n", P.indir);
  chprintf ("Output directory:  %s\n", P.outdir);

  //Create a Log file to output run-time messages
  Create_Log_File(P);

  // initialize the grid
  G.Initialize(&P);
  chprintf("Local number of grid cells: %d %d %d %d\n", G.H.nx_real, G.H.ny_real, G.H.nz_real, G.H.n_cells);

  char *message = (char*)malloc(50 * sizeof(char));
  sprintf(message, "Initializing Simulation" );
  Write_Message_To_Log_File( message );

  // Set initial conditions and calculate first dt
  chprintf("Setting initial conditions...\n");
  G.Set_Initial_Conditions(P);
  chprintf("Initial conditions set.\n");
  // set main variables for Read_Grid initial conditions
  if (strcmp(P.init, "Read_Grid") == 0) {
    dti = C_cfl / G.H.dt;
    outtime += G.H.t;
    nfile = P.nfile;
  }

  #ifdef DE
  chprintf("\nUsing Dual Energy Formalism:\n eta_1: %0.3f   eta_2: %0.4f\n", DE_ETA_1, DE_ETA_2 );
  sprintf(message, " eta_1: %0.3f   eta_2: %0.3f  ", DE_ETA_1, DE_ETA_2 );
  Write_Message_To_Log_File( message );
  #endif

  #ifdef CPU_TIME
  G.Timer.Initialize();
  #endif

  #ifdef GRAVITY
  G.Initialize_Gravity(&P);
  #endif

  #ifdef PARTICLES
  G.Initialize_Particles(&P);
  #endif

  #ifdef COSMOLOGY
  G.Initialize_Cosmology(&P);
  #endif

  #ifdef COOLING_GRACKLE
  G.Initialize_Grackle(&P);
  #endif

  #ifdef ANALYSIS
  G.Initialize_Analysis_Module(&P);
  if ( G.Analysis.Output_Now ) G.Compute_and_Output_Analysis(&P);
  #endif

  #ifdef GRAVITY
  // Get the gravitaional potential for the first timestep
  G.Compute_Gravitational_Potential( &P);
  #endif

  // Set boundary conditions (assign appropriate values to ghost cells) for hydro and potential
  chprintf("Setting boundary conditions...\n");
  G.Set_Boundary_Conditions_Grid(P);
  chprintf("Boundary conditions set.\n");

  #ifdef GRAVITY_ANALYTIC_COMP
  // add analytic component to gravity potential.
  G.Add_Analytic_Potential(&P);
  #endif

  #ifdef PARTICLES
  // Get the particles acceleration for the first timestep
  G.Get_Particles_Acceleration();
  #endif

  chprintf("Dimensions of each cell: dx = %f dy = %f dz = %f\n", G.H.dx, G.H.dy, G.H.dz);
  chprintf("Ratio of specific heats gamma = %f\n",gama);
  chprintf("Nstep = %d  Timestep = %f  Simulation time = %f\n", G.H.n_step, G.H.dt, G.H.t);

  #ifdef OUTPUT
  if (strcmp(P.init, "Read_Grid") != 0 || G.H.Output_Now ) {
    // write the initial conditions to file
    chprintf("Writing initial conditions to file...\n");
    #ifdef MPI_GPU
    cudaMemcpy(G.C.density, G.C.device,
             G.H.n_fields*G.H.n_cells*sizeof(Real), cudaMemcpyDeviceToHost);
    #endif
    WriteData(G, P, nfile);
  }
  // add one to the output file count
  nfile++;
  #endif //OUTPUT
  // increment the next output time
  outtime += P.outstep;

  #ifdef CPU_TIME
  stop_init = get_time();
  init = stop_init - start_total;
  #ifdef MPI_CHOLLA
  init_min = ReduceRealMin(init);
  init_max = ReduceRealMax(init);
  init_avg = ReduceRealAvg(init);
  chprintf("Init  min: %9.4f  max: %9.4f  avg: %9.4f\n", init_min, init_max, init_avg);
  #else
  printf("Init %9.4f\n", init);
  #endif //MPI_CHOLLA
  #endif //CPU_TIME

  // Evolve the grid, one timestep at a time
  chprintf("Starting calculations.\n");
  sprintf(message, "Starting calculations." );
  Write_Message_To_Log_File( message );
  while (G.H.t < P.tout)
  {
    // get the start time
    start_step = get_time();

    // calculate the timestep
    G.set_dt(dti);

    if (G.H.t + G.H.dt > outtime) G.H.dt = outtime - G.H.t;

    #ifdef PARTICLES
    //Advance the particles KDK( first step ): Velocities are updated by 0.5*dt and positions are updated by dt
    G.Advance_Particles( 1 );
    //Transfer the particles that moved outside the local domain
    G.Transfer_Particles_Boundaries(P);
    #endif

    // Advance the grid by one timestep
    dti = G.Update_Hydro_Grid();

    // update the simulation time ( t += dt )
    G.Update_Time();

    #ifdef GRAVITY
    //Compute Gravitational potential for next step
    G.Compute_Gravitational_Potential( &P);
    #endif

    // add one to the timestep count
    G.H.n_step++;

    //Set the Grid boundary conditions for next time step
    G.Set_Boundary_Conditions_Grid(P);

    #ifdef GRAVITY_ANALYTIC_COMP
    // add analytic component to gravity potential.
    G.Add_Analytic_Potential(&P);
    #endif

    #ifdef PARTICLES
    ///Advance the particles KDK( second step ): Velocities are updated by 0.5*dt using the Accelerations at the new positions
    G.Advance_Particles( 2 );
    #endif

    #ifdef PARTICLE_AGE
    //G.Cluster_Feedback();
    #endif

    #ifdef CPU_TIME
    G.Timer.Print_Times();
    #endif

    // get the time to compute the total timestep
    stop_step = get_time();
    stop_total = get_time();
    G.H.t_wall = stop_total-start_total;
    #ifdef MPI_CHOLLA
    G.H.t_wall = ReduceRealMax(G.H.t_wall);
    #endif
    chprintf("n_step: %d   sim time: %10.7f   sim timestep: %7.4e  timestep time = %9.3f ms   total time = %9.4f s\n\n",
      G.H.n_step, G.H.t, G.H.dt, (stop_step-start_step)*1000, G.H.t_wall);

    #ifdef OUTPUT_ALWAYS
    G.H.Output_Now = true;
    #endif

    #ifdef ANALYSIS
    if ( G.Analysis.Output_Now ) G.Compute_and_Output_Analysis(&P);
    #endif

    // if ( P.n_steps_output > 0 && G.H.n_step % P.n_steps_output == 0) G.H.Output_Now = true;

    if (G.H.t == outtime || G.H.Output_Now )
    {
      #ifdef OUTPUT
      /*output the grid data*/
      #ifdef MPI_GPU
      cudaMemcpy(G.C.density, G.C.device,
                 G.H.n_fields*G.H.n_cells*sizeof(Real), cudaMemcpyDeviceToHost);
      #endif
      WriteData(G, P, nfile);
      // add one to the output file count
      nfile++;
      #endif //OUTPUT
      // update to the next output time
      outtime += P.outstep;
    }

    #ifdef CPU_TIME
    G.Timer.n_steps += 1;
    #endif

    #ifdef N_STEPS_LIMIT
    // Exit the loop when reached the limit number of steps (optional)
    if ( G.H.n_step == N_STEPS_LIMIT) {
      #ifndef COSMOLOGY
      #ifdef MPI_GPU
      cudaMemcpy(G.C.density, G.C.device,
                 G.H.n_fields*G.H.n_cells*sizeof(Real), cudaMemcpyDeviceToHost);
      #endif
      WriteData(G, P, nfile);
      #endif //COSMOLOGY
      break;
    }
    #endif

    #ifdef COSMOLOGY
    // Exit the loop when reached the last scale_factor output
    if ( G.Cosmo.exit_now ) {
      chprintf( "\nReached Last Cosmological Output: Ending Simulation\n");
      break;
    }
    #endif

  } /*end loop over timesteps*/

  #ifdef CPU_TIME
  // Print timing statistics
  G.Timer.Get_Average_Times();
  G.Timer.Print_Average_Times( P );
  #endif

  sprintf(message, "Simulation completed successfully." );
  Write_Message_To_Log_File( message );

  // free the grid
  G.Reset();

  #ifdef MPI_CHOLLA
  MPI_Finalize();
  #endif /*MPI_CHOLLA*/

  return 0;

}
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <Refal2.h>

using namespace Refal2;

class CMyClass :
	public IVariablesBuilderListener,
	public IFunctionBuilderListener,
	public IScannerListener,
	public IParserListener
{
public:
	virtual void OnScannerError(const TScannerErrorCodes errorCode, char c);
	virtual void OnParserError(const TParserErrorCodes errorCode);
	virtual void OnFunctionBuilderError(const TFunctionBuilderErrorCodes errorCode);
	virtual void OnVariablesBuilderError(const TVariablesBuilderErrorCodes errorCode);
};

void CMyClass::OnScannerError(const TScannerErrorCodes errorCode, char c)
{
	static const char* errorText[] = {
		"SEC_UnexpectedControlSequence",
		"SEC_SymbolAfterPlus",
		"SEC_UnexpectedCharacter",
		"SEC_IllegalCharacterInLabelOrNumberBegin",
		"SEC_IllegalCharacterInLabel",
		"SEC_IllegalCharacterInNumber",
		"SEC_IllegalCharacterInQualifierNameBegin",
		"SEC_IllegalCharacterInQualifierName",
		"SEC_IllegalCharacterInStringAfterBackslash",
		"SEC_IllegalCharacterInStringInHexadecimal",
		"SEC_TryingAppendNullByteToString",
		"SEC_IllegalCharacterInStringInOctal",
		"SEC_UnclosedStringConstantAtTheEndOfFile",
		"SEC_UnclosedStringConstant",
		"SEC_UnclosedLabelOrNumberAtTheEndOfFile",
		"SEC_UnclosedLabelOrNumber",
		"SEC_UnclosedLabelAtTheEndOfFile",
		"SEC_UnclosedLabel",
		"SEC_UnclosedNumberAtTheEndOfFile",
		"SEC_UnclosedNumber",
		"SEC_UnclosedQualifierAtTheEndOfFile",
		"SEC_UnclosedQualifier",
		"SEC_UnexpectedEndOfFil"
	};

	std::cout << "ScannerError: " /*<< line << ": " << localOffset << ": "*/;
	/*if( c != '\0' ) {
		std::cout << c << ": ";
	}*/
	std::cout << errorText[errorCode] << "\n";
}

void CMyClass::OnParserError(const TParserErrorCodes errorCode)
{
	static const char* errorText[] = {
		"PEC_LineShouldBeginWithIdentifierOrSpace",
		"PEC_NewLineExpected",
		"PEC_UnexpectedLexemeAfterIdentifierInTheBeginningOfLine",
		"PEC_STUB"
	};

	std::cout << errorText[errorCode] << "\n";
}

void CMyClass::OnFunctionBuilderError(const Refal2::TFunctionBuilderErrorCodes errorCode)
{
	static const char* errorText[] = {
		"FBEC_ThereAreNoRulesInFunction",
		"FBEC_IllegalLeftBracketInLeftPart",
		"FBEC_IllegalRightBracketInLeftPart",
		"FBEC_RightParenDoesNotMatchLeftParen",
		"FBEC_RightBracketDoesNotMatchLeftBracket",
		"FBEC_UnclosedLeftParenInLeftPart",
		"FBEC_UnclosedLeftParenInRightPart",
		"FBEC_UnclosedLeftBracketInRightPart",
		"FBEC_IllegalQualifierInRightPart"
	};

	printf("CFunctionBuilder error: %s\n", errorText[errorCode]);
}

void CMyClass::OnVariablesBuilderError(const Refal2::TVariablesBuilderErrorCodes errorCode)
{
	static const char* errorText[] = {
		"VBEC_InvalidVatiableName",
		"VBEC_NoSuchTypeOfVariable",
		"VBEC_TypeOfVariableDoesNotMatch",
		"VBEC_NoSuchVariableInLeftPart"
	};

	printf("CVariablesBuilder error: %s\n", errorText[errorCode]);
}

int main(int argc, const char* argv[])
{
	try {
		const char* filename = "../tests/btest.ref";
		//const char* filename = "../tests/PROGRAM.REF";

		if( argc == 2 ) {
			filename = argv[1];
		}

		CMyClass ca;
		CParser parser( &ca );

		std::ifstream f( filename );
		if( !f.good() ) {
			std::cerr << "Can't open file\n";
			return 1;
		}

		while( true ) {
			int c = f.get();
			if( c == -1 ) {
				parser.AddEndOfFile();
				break;
			} else {
				parser.AddChar(c);
			}
		}

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

		if( parser.HasErrors() ) {
			std::cout << "Errors!\n\n";
			return 0;
		}

		COperationList program;
		for( int i = LabelTable.GetFirstLabel(); i != InvalidLabel;
			i = LabelTable.GetNextLabel( i ) )
		{
			CFunction& function = LabelTable.GetLabelFunction( i );
			if( function.IsParsed() ) {
				std::cout << "{START:" << LabelTable.GetLabelText( i ) << "}\n";
				PrintFunction( function );
				CFunctionCompiler compiler;
				compiler.Compile( &function );
				std::cout << "{END:" << LabelTable.GetLabelText( i ) << "}\n";
				COperationNode* operation = program.GetLast();
				compiler.Export( program );
				operation = operation == 0 ? program.GetFirst() : operation->Next();
				function.SetCompiled( operation );
			}
		}

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

		TLabel entryLabel = parser.GetEntryLabel();
		if( entryLabel == InvalidLabel ) {
			entryLabel = LabelTable.AddLabel( "go" );
		}
		assert( LabelTable.GetLabelFunction( entryLabel ).IsCompiled() );

		CUnitList fieldOfView;
		CUnitNode* errorCall = 0;
		TExecutionResult executionResult = COperationsExecuter::Run( entryLabel,
			fieldOfView, errorCall );

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

		switch( executionResult ) {
			case ER_OK:
				std::cout << "OK!\nFieldOfView: ";
				break;
			case ER_RecognitionImpossible:
				std::cout << "RecognitionImpossible!\nFieldOfView: ";
				break;
			case ER_CallEmptyFunction:
				std::cout << "CallEmptyFunction!\nFieldOfView: ";
				break;
			case ER_LostFunctionLabel:
				std::cout << "LostFunctionLabel!\nFieldOfView: ";
				break;
			case ER_WrongArgumentOfExternalFunction:
				std::cout << "WrongArgumentOfExternalFunction!\nFieldOfView: ";
				break;
			default:
				assert( false );
				break;
		}
		HandyPrintFieldOfView( fieldOfView );
	} catch( bool ) {
		return 1;
	}

	return 0;
}
<commit_msg>small changes in main.cpp<commit_after>#include <fstream>
#include <iostream>
#include <Refal2.h>

using namespace Refal2;

class CErrorProcessor :
	public IVariablesBuilderListener,
	public IFunctionBuilderListener,
	public IScannerListener,
	public IParserListener
{
public:
	virtual void OnScannerError( const TScannerErrorCodes errorCode, char c );
	virtual void OnParserError( const TParserErrorCodes errorCode );
	virtual void OnFunctionBuilderError(
		const TFunctionBuilderErrorCodes errorCode );
	virtual void OnVariablesBuilderError(
		const TVariablesBuilderErrorCodes errorCode );
};

void CErrorProcessor::OnScannerError( const TScannerErrorCodes errorCode,
	char c )
{
	static const char* errorText[] = {
		"SEC_UnexpectedControlSequence",
		"SEC_SymbolAfterPlus",
		"SEC_UnexpectedCharacter",
		"SEC_IllegalCharacterInLabelOrNumberBegin",
		"SEC_IllegalCharacterInLabel",
		"SEC_IllegalCharacterInNumber",
		"SEC_IllegalCharacterInQualifierNameBegin",
		"SEC_IllegalCharacterInQualifierName",
		"SEC_IllegalCharacterInStringAfterBackslash",
		"SEC_IllegalCharacterInStringInHexadecimal",
		"SEC_TryingAppendNullByteToString",
		"SEC_IllegalCharacterInStringInOctal",
		"SEC_UnclosedStringConstantAtTheEndOfFile",
		"SEC_UnclosedStringConstant",
		"SEC_UnclosedLabelOrNumberAtTheEndOfFile",
		"SEC_UnclosedLabelOrNumber",
		"SEC_UnclosedLabelAtTheEndOfFile",
		"SEC_UnclosedLabel",
		"SEC_UnclosedNumberAtTheEndOfFile",
		"SEC_UnclosedNumber",
		"SEC_UnclosedQualifierAtTheEndOfFile",
		"SEC_UnclosedQualifier",
		"SEC_UnexpectedEndOfFil"
	};
	/*std::cout << "ScannerError: " << line << ": " << localOffset << ": ";
	if( c != '\0' ) {
		std::cout << c << ": ";
	}*/
	std::cout << errorText[errorCode] << std::endl;
}

void CErrorProcessor::OnParserError( const TParserErrorCodes errorCode )
{
	static const char* errorText[] = {
		"PEC_LineShouldBeginWithIdentifierOrSpace",
		"PEC_NewLineExpected",
		"PEC_UnexpectedLexemeAfterIdentifierInTheBeginningOfLine",
		"PEC_STUB"
	};
	std::cout << errorText[errorCode] << std::endl;
}

void CErrorProcessor::OnFunctionBuilderError(
	const Refal2::TFunctionBuilderErrorCodes errorCode )
{
	static const char* errorText[] = {
		"FBEC_ThereAreNoRulesInFunction",
		"FBEC_IllegalLeftBracketInLeftPart",
		"FBEC_IllegalRightBracketInLeftPart",
		"FBEC_RightParenDoesNotMatchLeftParen",
		"FBEC_RightBracketDoesNotMatchLeftBracket",
		"FBEC_UnclosedLeftParenInLeftPart",
		"FBEC_UnclosedLeftParenInRightPart",
		"FBEC_UnclosedLeftBracketInRightPart",
		"FBEC_IllegalQualifierInRightPart"
	};
	std::cout << errorText[errorCode] << std::endl;
}

void CErrorProcessor::OnVariablesBuilderError(
	const Refal2::TVariablesBuilderErrorCodes errorCode )
{
	static const char* errorText[] = {
		"VBEC_InvalidVatiableName",
		"VBEC_NoSuchTypeOfVariable",
		"VBEC_TypeOfVariableDoesNotMatch",
		"VBEC_NoSuchVariableInLeftPart"
	};
	std::cout << errorText[errorCode] << std::endl;
}

int main( int argc, const char* argv[] )
{
	try {
		const char* filename = "../tests/btest.ref";

		if( argc == 2 ) {
			filename = argv[1];
		}

		CErrorProcessor errorProcessor;
		CParser parser( &errorProcessor );

		std::ifstream f( filename );
		if( !f.good() ) {
			std::cerr << "Can't open file\n";
			return 1;
		}

		while( true ) {
			int c = f.get();
			if( c == -1 ) {
				parser.AddEndOfFile();
				break;
			} else {
				parser.AddChar(c);
			}
		}

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

		if( parser.HasErrors() ) {
			std::cout << "Errors!\n\n";
			return 0;
		}

		COperationList program;
		for( int i = LabelTable.GetFirstLabel(); i != InvalidLabel;
			i = LabelTable.GetNextLabel( i ) )
		{
			CFunction& function = LabelTable.GetLabelFunction( i );
			if( function.IsParsed() ) {
				std::cout << "{START:" << LabelTable.GetLabelText( i ) << "}\n";
				PrintFunction( function );
				CFunctionCompiler compiler;
				compiler.Compile( &function );
				std::cout << "{END:" << LabelTable.GetLabelText( i ) << "}\n";
				COperationNode* operation = program.GetLast();
				compiler.Export( program );
				operation = operation == 0 ? program.GetFirst() : operation->Next();
				function.SetCompiled( operation );
			}
		}

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

		TLabel entryLabel = parser.GetEntryLabel();
		if( entryLabel == InvalidLabel ) {
			entryLabel = LabelTable.AddLabel( "go" );
		}
		assert( LabelTable.GetLabelFunction( entryLabel ).IsCompiled() );

		CUnitList fieldOfView;
		CUnitNode* errorCall = 0;
		TExecutionResult executionResult = COperationsExecuter::Run( entryLabel,
			fieldOfView, errorCall );

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

		switch( executionResult ) {
			case ER_OK:
				std::cout << "OK!\nFieldOfView: ";
				break;
			case ER_RecognitionImpossible:
				std::cout << "RecognitionImpossible!\nFieldOfView: ";
				break;
			case ER_CallEmptyFunction:
				std::cout << "CallEmptyFunction!\nFieldOfView: ";
				break;
			case ER_LostFunctionLabel:
				std::cout << "LostFunctionLabel!\nFieldOfView: ";
				break;
			case ER_WrongArgumentOfExternalFunction:
				std::cout << "WrongArgumentOfExternalFunction!\nFieldOfView: ";
				break;
			default:
				assert( false );
				break;
		}
		HandyPrintFieldOfView( fieldOfView );
	} catch( bool ) {
		return 1;
	}

	return 0;
}
<|endoftext|>


<commit_before>#include "readimage.h"
#include "gpudm.h"
#include "parseconfig.h"
#include "hyperspectral.h"

#include <iostream>
using namespace std;

int main(int argc, char *argv[]){
	if (argc < 3){
		cout << "Usage: " << argv[0] << " infilename outfilename" << endl;
		exit(1);
	}

	readConfigFile("configfile.xml");

	//read image to BIL-interleaved float-array
	char *filename = argv[1];
	size_t offset;
	HyspexHeader header;
	readHeader(filename, &header);

	ImageSubset subset;
	subset.startSamp = 0;
	subset.endSamp = header.samples;
	subset.startLine = 0;
	subset.endLine = header.lines;

	float *data = new float[header.lines*header.samples*header.bands];
	readImage(filename, &header, subset, data);

	float *wlens = new float[header.bands];
	for (int i=0; i < header.bands; i++){
		wlens[i] = header.wlens[i];
	}

	int lines = header.lines;
	int bands = bands;
	int samples = header.samples;

	//prepare gpudm arrays
	GPUDMParams params;
	gpudm_initialize(&params, samples, bands, wlens);

	//prepare output arrays
	float *res_530 = new float[samples*lines*params.lsq_w530->fitting_numEndmembers];
	float *res_700 = new float[samples*lines*params.lsq_w700->fitting_numEndmembers];

	for (int i=0; i < lines; i++){
		float *lineRefl = data + i*samples*bands;
		gpudm_fit_reflectance(&params, lineRefl);

		//result from interval around 500 nm
		float *res_line_530 = res_530 + samples*params.lsq_w530->fitting_numEndmembers*i;
		gpudm_download_530res(&params, res_line_530);

		//result from interval around 700 nm
		float *res_line_700 = res_700 + samples*params.lsq_w700->fitting_numEndmembers*i;
		gpudm_download_700res(&params, res_line_700);
	}

	//write results to hyperspectral files
	Hyperspectral *hyp530res = new Hyperspectral(res_530, lines, samples, params.lsq_w530->fitting_numEndmembers, BIL);
	hyp530res->writeToFile(string(argv[2]) + "_530res");

	Hyperspectral *hyp700res = new Hyperspectral(res_700, lines, samples, params.lsq_w700->fitting_numEndmembers, BIL);
	hyp700res->writeToFile(string(argv[2]) + "_700res");

	delete [] res_530;
	delete [] res_700;
	delete [] data;

	delete hyp530res;
	delete hyp700res;

	gpudm_free(&params);
}
<commit_msg>Changed main.cpp example to be slightly saner.<commit_after>#include "readimage.h"
#include "gpudm.h"
#include "parseconfig.h"
#include "hyperspectral.h"

#include <iostream>
using namespace std;

int main(int argc, char *argv[]){
	if (argc < 3){
		cout << "Usage: " << argv[0] << " infilename outfilename" << endl;
		exit(1);
	}

	readConfigFile("configfile.xml");

	//read image to BIL-interleaved float-array
	char *filename = argv[1];
	size_t offset;
	HyspexHeader header;
	readHeader(filename, &header);

	ImageSubset subset;
	subset.startSamp = 0;
	subset.endSamp = header.samples;
	subset.startLine = 0;
	subset.endLine = header.lines;

	float *data = new float[header.lines*header.samples*header.bands];
	readImage(filename, &header, subset, data);

	float *wlens = new float[header.bands];
	for (int i=0; i < header.bands; i++){
		wlens[i] = header.wlens[i];
	}

	int lines = header.lines;
	int bands = header.bands;
	int samples = 1600;

	//prepare gpudm arrays
	GPUDMParams params;
	gpudm_initialize(&params, samples, bands, wlens);

	//prepare output arrays
	float *res_530 = new float[samples*lines*params.lsq_w530->fitting_numEndmembers];
	float *res_700 = new float[samples*lines*params.lsq_w700->fitting_numEndmembers];

	for (int i=0; i < lines; i++){
		float *lineReflOrig = data + i*header.samples*bands;
		float *lineRefl = new float[samples*bands]();
		for (int j=0; j < samples; j++){
			for (int k=0; k < bands; k++){
				lineRefl[k*samples + j] = lineReflOrig[k*header.samples + j];
			}
		}

		gpudm_fit_reflectance(&params, lineRefl);

		//result from interval around 500 nm
		float *res_line_530 = res_530 + samples*params.lsq_w530->fitting_numEndmembers*i;
		gpudm_download_530res(&params, res_line_530);

		//result from interval around 700 nm
		float *res_line_700 = res_700 + samples*params.lsq_w700->fitting_numEndmembers*i;
		gpudm_download_700res(&params, res_line_700);
		delete [] lineRefl;
	}

	//write results to hyperspectral files
	Hyperspectral *hyp530res = new Hyperspectral(res_530, lines, samples, params.lsq_w530->fitting_numEndmembers, BIL);
	hyp530res->writeToFile(string(argv[2]) + "_530res");

	Hyperspectral *hyp700res = new Hyperspectral(res_700, lines, samples, params.lsq_w700->fitting_numEndmembers, BIL);
	hyp700res->writeToFile(string(argv[2]) + "_700res");

	delete [] res_530;
	delete [] res_700;
	delete [] data;

	delete hyp530res;
	delete hyp700res;

	gpudm_free(&params);
}
<|endoftext|>


<commit_before>#include "particle.hpp"
#include "scene.hpp"
#include <SFML/Graphics.hpp>
#include <string>
#include <iostream>
#include <sstream>
int main()
{
    SmokeShape shape_ref;
    shape_ref.m_Shape.setRadius(10.f);

    Scene scene;

	sf::Font font;
	font.loadFromFile("menu_font.ttf");

    sf::Text text;
    text.setPosition({50.f,90.f});
	text.setFont(font);

	SceneNode &node1 =scene.getRootNode();

    ParticleEmitter<SmokeShape> p(shape_ref, node1, 1000);
    p.setFrequency(60);
//    p.setPosition({400.f, 300.f});
    sf::RenderWindow window({800,600}, "toto");

    sf::Clock clock;
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed) window.close();
        }
        std::ostringstream stream;
        stream << p.getNumberOfParticles();
        text.setString("Particules : " + stream.str());

        node1.setPosition(window.mapPixelToCoords(sf::Mouse::getPosition(window)));

        p.update(clock.getElapsedTime());
        clock.restart();
        window.clear(sf::Color::Cyan);
        window.draw(scene);
        window.draw(text);
        window.display();
    }

    return 0;
}

//#include "cpp_std_11.hpp"
//
//#include <SFML/Graphics.hpp>
//#include <iostream>
//#include "gamescreenstate.hpp"
//#include "menuscreenstate.hpp"
//#include "screenstack.hpp"
//#include "resourcemanager.hpp"
//
//
//int main(int argc, char** argv)
//{
//	sf::RenderWindow window;
//	sf::String window_title = "Ludum Dare 35";
//	sf::VideoMode window_mode (800,600);
//
//	window.create(window_mode, window_title);
//	window.setFramerateLimit(60);
//
//
//	ScreenStack screenStack;
//	screenStack.registerState(ScreenState::Menu, make_unique<MenuScreenState>());
////	screenStack.registerState(ScreenState::Game, make_unique<GameScreenState>());
//
////	screenStack.pushState(ScreenState::Game);
//	screenStack.pushState(ScreenState::Menu);
//	sf::Event event;
//	sf::Clock clock;
//
//	while (window.isOpen()) {
//	    while (window.pollEvent(event)) {
//	        if (event.type == sf::Event::Closed)
//                window.close();
//            else
//				//menu_screen_state.event(window, event);
//                screenStack.onEvent(window, event);
//	    }
//
//	    window.clear();
//	    screenStack.onDraw(window);
//		//menu_screen_state.render(window);
//	    window.display();
//		//screenStack.window_update(window);
//		screenStack.onUpdate(clock.getElapsedTime());
//		//menu_screen_state.update(clock.getElapsedTime());
//        clock.restart();
//
//	}
//}
<commit_msg>Restore previous main.cpp.<commit_after>#include "cpp_std_11.hpp"

#include <SFML/Graphics.hpp>
#include <iostream>
#include "gamescreenstate.hpp"
#include "menuscreenstate.hpp"
#include "screenstack.hpp"
#include "resourcemanager.hpp"

int main(int argc, char** argv)
{
	sf::RenderWindow window;
	sf::String window_title = "Ludum Dare 35";
	sf::VideoMode window_mode (800,600);

	window.create(window_mode, window_title);
	window.setFramerateLimit(60);

	ScreenStack screenStack;
	screenStack.registerState(ScreenState::Menu, make_unique<MenuScreenState>());
//	screenStack.registerState(ScreenState::Game, make_unique<GameScreenState>());

//	screenStack.pushState(ScreenState::Game);
	screenStack.pushState(ScreenState::Menu);
	sf::Event event;
	sf::Clock clock;

	while (window.isOpen()) {
	    while (window.pollEvent(event)) {
	        if (event.type == sf::Event::Closed)
                window.close();
            else
				//menu_screen_state.event(window, event);
                screenStack.onEvent(window, event);
	    }

	    window.clear();
	    screenStack.onDraw(window);
		//menu_screen_state.render(window);
	    window.display();
		//screenStack.window_update(window);
		screenStack.onUpdate(clock.getElapsedTime());
		//menu_screen_state.update(clock.getElapsedTime());
        clock.restart();

	}
}
<|endoftext|>


<commit_before>#include <iostream>
#include <memory>
#include "DataLoader.h"

int test0 () {
  DataLoader *loader = new DataLoader();
  loader->e = 10;
  int e = loader->e;
  int r = loader->loadCSV();
  cout << e + r << endl;
  return 0;
}

int test1 () {
  std::unique_ptr <DataLoader> loader(new DataLoader());
  loader->e = 100;
  int r = loader->loadCSV();
  cout << loader->e + r << endl;
  return 0;
}

int test2 () {
  std::unique_ptr <DataLoader> loader(new DataLoader());
  std::unique_ptr <string> fname(new string("/Users/daiki/GitHubRepos/sandbox/hellocpp/android_names.txt"));
  // &fname: アドレス番地が見れる
  // *fname: 格納されているものが見れる
  cout << &fname << endl;
  cout << *fname << endl;
  loader->loadText(fname->c_str());
  return 0;
}

int main() {
  cout << "Hello, World!\n" << endl;
  test2();
  return 0;
}<commit_msg>こうやっても書ける<commit_after>#include <iostream>
#include <memory>
#include "DataLoader.h"

int test0 () {
  DataLoader *loader = new DataLoader();
  loader->e = 10;
  int e = loader->e;
  int r = loader->loadCSV();
  cout << e + r << endl;
  return 0;
}

int test1 () {
  std::unique_ptr <DataLoader> loader(new DataLoader());
  loader->e = 100;
  int r = loader->loadCSV();
  cout << loader->e + r << endl;
  return 0;
}

int test2 () {
  std::unique_ptr <DataLoader> loader(new DataLoader());
  std::unique_ptr <string> fname(new string("/Users/daiki/GitHubRepos/sandbox/hellocpp/android_names.txt"));
  std::string fn = "/Users/daiki/GitHubRepos/sandbox/hellocpp/android_names.txt";
  // &fname: アドレス番地が見れる
  // *fname: 格納されているものが見れる
  cout << &fn << endl;
  cout << fn << endl;
  //loader->loadText(fname->c_str());
  loader->loadText(fn);
  return 0;
}

int main() {
  cout << "Hello, World!\n" << endl;
  test2();
  return 0;
}<|endoftext|>


<commit_before>// BUG: this whole thing depends on the specifics of how the clang version I
// am using emits llvm bitcode for the hacky RMC protocol.
// We rely on how basic blocks get named, on the labels forcing things
// into their own basic blocks, and probably will rely on this block
// having one predecessor and one successor. We could probably even
// force those to be empty without too much work by adding more labels...

#include <llvm/Pass.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/InlineAsm.h>
#include <llvm/IR/CFG.h>
#include <llvm/IR/InstIterator.h>

#include <llvm/ADT/ArrayRef.h>

#include <llvm/Transforms/Utils/BasicBlockUtils.h>
#include <llvm/Support/raw_ostream.h>

#include <ostream>
#include <fstream>
#include <iostream>
#include <map>
#include <set>

using namespace llvm;

namespace {
#if 0 // I hate you, emacs. Is there a better way to work around this?
}
#endif

/* To do bogus data dependencies, we will emit inline assembly
  instructions. This is sort of tasteless; we should add an intrinsic;
  but it means we don't need to modify llvm. This is what the
  instruction should look like (probably the constraints aren't
  right?):

  %2 = call i32 asm sideeffect "eor $0, $0;", "=r,0"(i32 %1) #2, !srcloc !11

  Also for ctrlisb we do:
  call void asm sideeffect "cmp $0, $0;beq 1f;1: isb", "r,~{memory}"(i32 %1) #2, !srcloc !4

  And for dmb:
  call void asm sideeffect "dmb", "~{memory}"() #2, !srcloc !5

  We can probably do a bogus inline asm on x86 to prevent reordering:
  %2 = call i32 asm sideeffect "", "=r,r,0,~{dirflag},~{fpsr},~{flags}"(i32 %1, i32 %0) #3, !srcloc !9

  What about this makes the right value come out:
    =r specifies an output parameter and the 0 says that that input parameter
    is paired with param 0.

  Hm. Does this *actually* work?? What does "sideeffect" actually mean
  for asm and do we need it.

  --
  Should we emit dmb directly, or try to use llvm's fences?
*/

//// Some auxillary data structures
enum RMCEdgeType {
  VisbilityEdge,
  ExecutionEdge
};

raw_ostream& operator<<(raw_ostream& os, const RMCEdgeType& t) {
  switch (t) {
    case VisbilityEdge:
      os << "v";
      break;
    case ExecutionEdge:
      os << "x";
      break;
    default:
      os << "?";
      break;
  }
  return os;
}

// Info about an RMC edge
struct RMCEdge {
  RMCEdgeType edgeType;
  BasicBlock *src;
  BasicBlock *dst;

  bool operator<(const RMCEdge& rhs) const {
    return std::tie(edgeType, src, dst)
      < std::tie(rhs.edgeType, rhs.src, rhs.dst);
  }

  void print(raw_ostream &os) const {
    // substr(5) is to drop "_rmc_" from the front
    os << src->getName().substr(5) << " -" << edgeType <<
      "-> " << dst->getName().substr(5);
  }
};

raw_ostream& operator<<(raw_ostream& os, const RMCEdge& e) {
  e.print(os);
  return os;
}

// Information for a node in the RMC graph.
struct Block {
  Block(BasicBlock *p_bb) : bb(p_bb), stores(0), loads(0), RMWs(0), calls(0) {}
  void operator=(const Block &) LLVM_DELETED_FUNCTION;
  Block(const Block &) LLVM_DELETED_FUNCTION;
  Block(Block &&) = default; // move constructor!

  BasicBlock *bb;

  // Some basic info about what sort of instructions live in the block
  int stores;
  int loads;
  int RMWs;
  int calls;

  // Edges in the graph.
  // XXX: Would we be better off storing this some other way?
  // a <ptr, type> pair?
  // And should we store v edges in x
  SmallPtrSet<Block *, 2> execEdges;
  SmallPtrSet<Block *, 2> visEdges;
};

// Code to find all simple paths between two basic blocks.
// Could generalize more to graphs if we wanted, but I don't right
// now.
typedef std::vector<BasicBlock *> Path;
typedef SmallVector<Path, 2> PathList;
typedef SmallPtrSet<BasicBlock *, 8> GreySet;

PathList findAllSimplePaths_(GreySet *grey, BasicBlock *src, BasicBlock *dst) {
  PathList paths;
  if (grey->count(src)) return paths;
  if (src == dst) {
    Path path;
    path.push_back(dst);
    paths.push_back(std::move(path));
    return paths;
  }

  grey->insert(src);

  // Go search all the successors
  for (auto i = succ_begin(src), e = succ_end(src); i != e; i++) {
    PathList subpaths = findAllSimplePaths_(grey, *i, dst);
    std::move(subpaths.begin(), subpaths.end(), back_inserter(paths));
  }

  // Add our step to all of the vectors
  for (auto & path : paths) {
    path.push_back(src);
  }

  // Remove it from the set of things we've seen. We might come
  // through here again.
  // We can't really do any sort of memoization, since in a cyclic
  // graph the possible simple paths depend not just on what node we
  // are on, but our previous path (to avoid looping).
  grey->erase(src);

  return paths;
}

PathList findAllSimplePaths(BasicBlock *src, BasicBlock *dst) {
  GreySet grey;
  return findAllSimplePaths_(&grey, src, dst);
}

void dumpPaths(const PathList &paths) {
  for (auto & path : paths) {
    for (auto block : path) {
      errs() << block->getName() << " <- ";
    }
    errs() << "\n";
  }
}

// XXX: This is the wrong way to do this!
bool targetARM = true;
bool targetx86 = false;

// Some llvm nonsense. I should probably find a way to clean this up.
// do we put ~{dirflag},~{fpsr},~{flags} for the x86 ones? don't think so.
Instruction *makeSync(Value *dummy) {
  LLVMContext &C = dummy->getContext();
  FunctionType *f_ty = FunctionType::get(FunctionType::getVoidTy(C), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "dmb", "~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "msync", "~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "sync");
}
Instruction *makeLwsync(Value *dummy) {
  LLVMContext &C = dummy->getContext();
  FunctionType *f_ty = FunctionType::get(FunctionType::getVoidTy(C), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "dmb", "~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "", "~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "lwsync");
}
Instruction *makeCtrlIsync(Value *v) {
  LLVMContext &C = v->getContext();
  FunctionType *f_ty =
    FunctionType::get(FunctionType::getVoidTy(C), v->getType(), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "cmp $0, $0;beq 1f;1: isb", "r,~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "", "r,~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "ctrlisync");
}
// We also need to add a thing for fake data deps, which is more annoying.

//// Actual code for the pass
class RMCPass : public FunctionPass {
private:
  std::vector<Block> blocks_;
  DenseMap<BasicBlock *, Block *> bb2block_;

public:
  static char ID;
  RMCPass() : FunctionPass(ID) {

  }
  ~RMCPass() { }
  std::vector<RMCEdge> findEdges(Function &F);
  void buildGraph(std::vector<RMCEdge> &edges, Function &F);
  virtual bool runOnFunction(Function &F);
};

bool nameMatches(StringRef blockName, StringRef target) {
  StringRef name = "_rmc_" + target.str() + "_";
  if (!blockName.startswith(name)) return false;
  // Now make sure the rest is an int
  APInt dummy;
  return !blockName.drop_front(name.size()).getAsInteger(10, dummy);
}

StringRef getStringArg(Value *v) {
  const Value *g = cast<Constant>(v)->stripPointerCasts();
  const Constant *ptr = cast<GlobalVariable>(g)->getInitializer();
  StringRef str = cast<ConstantDataSequential>(ptr)->getAsString();
  // Drop the '\0' at the end
  return str.drop_back();
}

std::vector<RMCEdge> RMCPass::findEdges(Function &F) {
  std::vector<RMCEdge> edges;

  for (inst_iterator is = inst_begin(F), ie = inst_end(F); is != ie;) {
    // Grab the instruction and advance the iterator at the start, since
    // we might delete the instruction.
    Instruction *i = &*is;
    is++;

    CallInst *load = dyn_cast<CallInst>(i);
    if (!load) continue;
    Function *target = load->getCalledFunction();
    // We look for calls to the bogus function
    // __rmc_edge_register, pull out the information about them,
    // and delete the calls.
    if (!target || target->getName() != "__rmc_edge_register") continue;

    // Pull out what the operands have to be.
    // We just assert if something is wrong, which is not great UX.
    bool isVisibility = cast<ConstantInt>(load->getOperand(0))
      ->getValue().getBoolValue();
    RMCEdgeType edgeType = isVisibility ? VisbilityEdge : ExecutionEdge;
    StringRef srcName = getStringArg(load->getOperand(1));
    StringRef dstName = getStringArg(load->getOperand(2));

    // Since multiple blocks can have the same tag, we search for
    // them by name.
    // We could make this more efficient by building maps but I don't think
    // it is going to matter.
    for (auto & src : F) {
      if (!nameMatches(src.getName(), srcName)) continue;
      for (auto & dst : F) {
        if (!nameMatches(dst.getName(), dstName)) continue;

        edges.push_back({edgeType, &src, &dst});
      }
    }

    // Delete the bogus call.
    i->eraseFromParent();
  }

  return edges;
}

void analyzeBlock(Block &info) {
  for (auto & i : *info.bb) {
    if (isa<LoadInst>(i)) {
      info.loads++;
    } else if (isa<StoreInst>(i)) {
      info.stores++;
    // What else counts as a call? I'm counting fences I guess.
    } else if (isa<CallInst>(i) || isa<FenceInst>(i)) {
      info.calls++;
    } else if (isa<AtomicCmpXchgInst>(i) || isa<AtomicRMWInst>(i)) {
      info.RMWs++;
    }
  }
}

void RMCPass::buildGraph(std::vector<RMCEdge> &edges, Function &F) {
  // First, collect all the basic blocks with edges attached to them
  SmallPtrSet<BasicBlock *, 8> basicBlocks;
  for (auto & edge : edges) {
    basicBlocks.insert(edge.src);
    basicBlocks.insert(edge.dst);
  }

  // Now, make the vector of blocks and a mapping from BasicBlock *.
  blocks_.reserve(basicBlocks.size());
  for (auto bb : basicBlocks) {
    blocks_.emplace_back(bb);
    bb2block_[bb] = &blocks_.back();
  }

  // Analyze the instructions in blocks to see what sort of actions
  // they peform.
  for (auto & block : blocks_) {
    analyzeBlock(block);
  }

  // Build our list of edges into a more explicit graph
  for (auto & edge : edges) {
    Block *src = bb2block_[edge.src];
    Block *dst = bb2block_[edge.dst];
    if (edge.edgeType == VisbilityEdge) {
      src->visEdges.insert(dst);
    } else {
      src->execEdges.insert(dst);
    }
  }
}

bool RMCPass::runOnFunction(Function &F) {
  auto edges = findEdges(F);

  for (auto & edge : edges) {
    errs() << "Found an edge: " << edge << "\n";
  }

  buildGraph(edges, F);
  bool changed = !edges.empty();

  // Clear our data structures to save memory, make things clean for
  // future runs.
  blocks_.clear();
  bb2block_.clear();

  return changed;
}

char RMCPass::ID = 0;
RegisterPass<RMCPass> X("rmc-pass", "RMC");
}
<commit_msg>Add a data structure to track cuts that we add.<commit_after>// BUG: this whole thing depends on the specifics of how the clang version I
// am using emits llvm bitcode for the hacky RMC protocol.
// We rely on how basic blocks get named, on the labels forcing things
// into their own basic blocks, and probably will rely on this block
// having one predecessor and one successor. We could probably even
// force those to be empty without too much work by adding more labels...

#include <llvm/Pass.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/InlineAsm.h>
#include <llvm/IR/CFG.h>
#include <llvm/IR/InstIterator.h>

#include <llvm/ADT/ArrayRef.h>

#include <llvm/Transforms/Utils/BasicBlockUtils.h>
#include <llvm/Support/raw_ostream.h>

#include <ostream>
#include <fstream>
#include <iostream>
#include <map>
#include <set>

using namespace llvm;

namespace {
#if 0 // I hate you, emacs. Is there a better way to work around this?
}
#endif

/* To do bogus data dependencies, we will emit inline assembly
  instructions. This is sort of tasteless; we should add an intrinsic;
  but it means we don't need to modify llvm. This is what the
  instruction should look like (probably the constraints aren't
  right?):

  %2 = call i32 asm sideeffect "eor $0, $0;", "=r,0"(i32 %1) #2, !srcloc !11

  Also for ctrlisb we do:
  call void asm sideeffect "cmp $0, $0;beq 1f;1: isb", "r,~{memory}"(i32 %1) #2, !srcloc !4

  And for dmb:
  call void asm sideeffect "dmb", "~{memory}"() #2, !srcloc !5

  We can probably do a bogus inline asm on x86 to prevent reordering:
  %2 = call i32 asm sideeffect "", "=r,r,0,~{dirflag},~{fpsr},~{flags}"(i32 %1, i32 %0) #3, !srcloc !9

  What about this makes the right value come out:
    =r specifies an output parameter and the 0 says that that input parameter
    is paired with param 0.

  Hm. Does this *actually* work?? What does "sideeffect" actually mean
  for asm and do we need it.

  --
  Should we emit dmb directly, or try to use llvm's fences?
*/

//// Some auxillary data structures
enum RMCEdgeType {
  VisbilityEdge,
  ExecutionEdge
};

raw_ostream& operator<<(raw_ostream& os, const RMCEdgeType& t) {
  switch (t) {
    case VisbilityEdge:
      os << "v";
      break;
    case ExecutionEdge:
      os << "x";
      break;
    default:
      os << "?";
      break;
  }
  return os;
}

// Info about an RMC edge
struct RMCEdge {
  RMCEdgeType edgeType;
  BasicBlock *src;
  BasicBlock *dst;

  bool operator<(const RMCEdge& rhs) const {
    return std::tie(edgeType, src, dst)
      < std::tie(rhs.edgeType, rhs.src, rhs.dst);
  }

  void print(raw_ostream &os) const {
    // substr(5) is to drop "_rmc_" from the front
    os << src->getName().substr(5) << " -" << edgeType <<
      "-> " << dst->getName().substr(5);
  }
};

raw_ostream& operator<<(raw_ostream& os, const RMCEdge& e) {
  e.print(os);
  return os;
}

// Information for a node in the RMC graph.
struct Block {
  Block(BasicBlock *p_bb) : bb(p_bb), stores(0), loads(0), RMWs(0), calls(0) {}
  void operator=(const Block &) LLVM_DELETED_FUNCTION;
  Block(const Block &) LLVM_DELETED_FUNCTION;
  Block(Block &&) = default; // move constructor!

  BasicBlock *bb;

  // Some basic info about what sort of instructions live in the block
  int stores;
  int loads;
  int RMWs;
  int calls;

  // Edges in the graph.
  // XXX: Would we be better off storing this some other way?
  // a <ptr, type> pair?
  // And should we store v edges in x
  SmallPtrSet<Block *, 2> execEdges;
  SmallPtrSet<Block *, 2> visEdges;
};

enum CutType {
  CutNone,
  CutCtrlIsync, // needs to be paired with a dep
  CutLwsync,
  CutSync
};
struct EdgeCut {
  EdgeCut() : type(CutNone), front(false), read(nullptr) {}
  CutType type;
  bool front;
  Value *read;
};

// Code to find all simple paths between two basic blocks.
// Could generalize more to graphs if we wanted, but I don't right
// now.
typedef std::vector<BasicBlock *> Path;
typedef SmallVector<Path, 2> PathList;
typedef SmallPtrSet<BasicBlock *, 8> GreySet;

PathList findAllSimplePaths_(GreySet *grey, BasicBlock *src, BasicBlock *dst) {
  PathList paths;
  if (grey->count(src)) return paths;
  if (src == dst) {
    Path path;
    path.push_back(dst);
    paths.push_back(std::move(path));
    return paths;
  }

  grey->insert(src);

  // Go search all the successors
  for (auto i = succ_begin(src), e = succ_end(src); i != e; i++) {
    PathList subpaths = findAllSimplePaths_(grey, *i, dst);
    std::move(subpaths.begin(), subpaths.end(), back_inserter(paths));
  }

  // Add our step to all of the vectors
  for (auto & path : paths) {
    path.push_back(src);
  }

  // Remove it from the set of things we've seen. We might come
  // through here again.
  // We can't really do any sort of memoization, since in a cyclic
  // graph the possible simple paths depend not just on what node we
  // are on, but our previous path (to avoid looping).
  grey->erase(src);

  return paths;
}

PathList findAllSimplePaths(BasicBlock *src, BasicBlock *dst) {
  GreySet grey;
  return findAllSimplePaths_(&grey, src, dst);
}

void dumpPaths(const PathList &paths) {
  for (auto & path : paths) {
    for (auto block : path) {
      errs() << block->getName() << " <- ";
    }
    errs() << "\n";
  }
}

// XXX: This is the wrong way to do this!
bool targetARM = true;
bool targetx86 = false;

// Some llvm nonsense. I should probably find a way to clean this up.
// do we put ~{dirflag},~{fpsr},~{flags} for the x86 ones? don't think so.
Instruction *makeSync(Value *dummy) {
  LLVMContext &C = dummy->getContext();
  FunctionType *f_ty = FunctionType::get(FunctionType::getVoidTy(C), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "dmb", "~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "msync", "~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "sync");
}
Instruction *makeLwsync(Value *dummy) {
  LLVMContext &C = dummy->getContext();
  FunctionType *f_ty = FunctionType::get(FunctionType::getVoidTy(C), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "dmb", "~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "", "~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "lwsync");
}
Instruction *makeCtrlIsync(Value *v) {
  LLVMContext &C = v->getContext();
  FunctionType *f_ty =
    FunctionType::get(FunctionType::getVoidTy(C), v->getType(), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "cmp $0, $0;beq 1f;1: isb", "r,~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "", "r,~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "ctrlisync");
}
// We also need to add a thing for fake data deps, which is more annoying.

//// Actual code for the pass
class RMCPass : public FunctionPass {
private:
  std::vector<Block> blocks_;
  DenseMap<BasicBlock *, Block *> bb2block_;
  DenseMap<BasicBlock *, EdgeCut> cuts_;

public:
  static char ID;
  RMCPass() : FunctionPass(ID) {

  }
  ~RMCPass() { }
  std::vector<RMCEdge> findEdges(Function &F);
  void buildGraph(std::vector<RMCEdge> &edges, Function &F);
  virtual bool runOnFunction(Function &F);
};

bool nameMatches(StringRef blockName, StringRef target) {
  StringRef name = "_rmc_" + target.str() + "_";
  if (!blockName.startswith(name)) return false;
  // Now make sure the rest is an int
  APInt dummy;
  return !blockName.drop_front(name.size()).getAsInteger(10, dummy);
}

StringRef getStringArg(Value *v) {
  const Value *g = cast<Constant>(v)->stripPointerCasts();
  const Constant *ptr = cast<GlobalVariable>(g)->getInitializer();
  StringRef str = cast<ConstantDataSequential>(ptr)->getAsString();
  // Drop the '\0' at the end
  return str.drop_back();
}

std::vector<RMCEdge> RMCPass::findEdges(Function &F) {
  std::vector<RMCEdge> edges;

  for (inst_iterator is = inst_begin(F), ie = inst_end(F); is != ie;) {
    // Grab the instruction and advance the iterator at the start, since
    // we might delete the instruction.
    Instruction *i = &*is;
    is++;

    CallInst *load = dyn_cast<CallInst>(i);
    if (!load) continue;
    Function *target = load->getCalledFunction();
    // We look for calls to the bogus function
    // __rmc_edge_register, pull out the information about them,
    // and delete the calls.
    if (!target || target->getName() != "__rmc_edge_register") continue;

    // Pull out what the operands have to be.
    // We just assert if something is wrong, which is not great UX.
    bool isVisibility = cast<ConstantInt>(load->getOperand(0))
      ->getValue().getBoolValue();
    RMCEdgeType edgeType = isVisibility ? VisbilityEdge : ExecutionEdge;
    StringRef srcName = getStringArg(load->getOperand(1));
    StringRef dstName = getStringArg(load->getOperand(2));

    // Since multiple blocks can have the same tag, we search for
    // them by name.
    // We could make this more efficient by building maps but I don't think
    // it is going to matter.
    for (auto & src : F) {
      if (!nameMatches(src.getName(), srcName)) continue;
      for (auto & dst : F) {
        if (!nameMatches(dst.getName(), dstName)) continue;

        edges.push_back({edgeType, &src, &dst});
      }
    }

    // Delete the bogus call.
    i->eraseFromParent();
  }

  return edges;
}

void analyzeBlock(Block &info) {
  for (auto & i : *info.bb) {
    if (isa<LoadInst>(i)) {
      info.loads++;
    } else if (isa<StoreInst>(i)) {
      info.stores++;
    // What else counts as a call? I'm counting fences I guess.
    } else if (isa<CallInst>(i) || isa<FenceInst>(i)) {
      info.calls++;
    } else if (isa<AtomicCmpXchgInst>(i) || isa<AtomicRMWInst>(i)) {
      info.RMWs++;
    }
  }
}

void RMCPass::buildGraph(std::vector<RMCEdge> &edges, Function &F) {
  // First, collect all the basic blocks with edges attached to them
  SmallPtrSet<BasicBlock *, 8> basicBlocks;
  for (auto & edge : edges) {
    basicBlocks.insert(edge.src);
    basicBlocks.insert(edge.dst);
  }

  // Now, make the vector of blocks and a mapping from BasicBlock *.
  blocks_.reserve(basicBlocks.size());
  for (auto bb : basicBlocks) {
    blocks_.emplace_back(bb);
    bb2block_[bb] = &blocks_.back();
  }

  // Analyze the instructions in blocks to see what sort of actions
  // they peform.
  for (auto & block : blocks_) {
    analyzeBlock(block);
  }

  // Build our list of edges into a more explicit graph
  for (auto & edge : edges) {
    Block *src = bb2block_[edge.src];
    Block *dst = bb2block_[edge.dst];
    if (edge.edgeType == VisbilityEdge) {
      src->visEdges.insert(dst);
    } else {
      src->execEdges.insert(dst);
    }
  }
}

bool RMCPass::runOnFunction(Function &F) {
  auto edges = findEdges(F);

  for (auto & edge : edges) {
    errs() << "Found an edge: " << edge << "\n";
  }

  buildGraph(edges, F);
  bool changed = !edges.empty();

  // Clear our data structures to save memory, make things clean for
  // future runs.
  blocks_.clear();
  bb2block_.clear();
  cuts_.clear();

  return changed;
}

char RMCPass::ID = 0;
RegisterPass<RMCPass> X("rmc-pass", "RMC");
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Teragon Audio. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "TestRunner.h"
#include "PluginParameters.h"

using namespace teragon;

////////////////////////////////////////////////////////////////////////////////
// Observers
////////////////////////////////////////////////////////////////////////////////

class TestAsyncObserver : public PluginParameterObserver {
public:
  TestAsyncObserver() {}
#if ENABLE_MULTITHREADED
  bool isRealtimePriority() const { return true; }
#endif
  void onParameterUpdated(const PluginParameter* parameter) {
  }
private:
};

static bool testUpdatesReceivedOnBothThreads() {
  return true;
}

int runMultithreadedTests();
int runMultithreadedTests() {
  ADD_TEST("UpdatesReceivedOnBothThreads", testUpdatesReceivedOnBothThreads());

  return 0;
}
<commit_msg>Add basic multithreading test observers<commit_after>/*
 * Copyright (c) 2013 Teragon Audio. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "TestRunner.h"
#include "PluginParameters.h"

#if ENABLE_MULTITHREADED

using namespace teragon;

////////////////////////////////////////////////////////////////////////////////
// Observers
////////////////////////////////////////////////////////////////////////////////

class TestCounterObserver : public PluginParameterObserver {
public:
  TestCounterObserver(bool isRealtime) : PluginParameterObserver(),
    realtime(isRealtime), count(0) {}
  virtual ~TestCounterObserver() {}
  int getCount() const { return count; }
  virtual bool isRealtimePriority() const { return realtime; }
  void onParameterUpdated(const PluginParameter* parameter) {
    count++;
  }
private:
  const bool realtime;
  int count;
};

class TestAsyncObserver : public TestCounterObserver {
public:
  TestAsyncObserver() : TestCounterObserver(false) {}
  virtual ~TestAsyncObserver() {}
};

class TestRealtimeObserver : public TestCounterObserver {
public:
  TestRealtimeObserver() : TestCounterObserver(true) {}
  virtual ~TestRealtimeObserver() {}
};

////////////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////////////

static bool testUpdatesReceivedOnBothThreads() {
  PluginParameterSet p;
  return true;
}

////////////////////////////////////////////////////////////////////////////////
// Run test suite
////////////////////////////////////////////////////////////////////////////////

void runMultithreadedTests();
void runMultithreadedTests() {
  ADD_TEST("UpdatesReceivedOnBothThreads", testUpdatesReceivedOnBothThreads());
}

#endif // #if ENABLE_MULTITHREADED
<|endoftext|>


<commit_before>/**
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include <iostream>
#include <vector>
#include <cstring>
#include <dlfcn.h>
#include <string>
#import <Cocoa/Cocoa.h>
#include "host.h"
#include "log.h"

namespace kroll
{
	OSXHost::OSXHost(int _argc, const char **_argv) : Host(_argc,_argv)
	{
		SetupLog(_argc,_argv,[NSString stringWithFormat:@"%s/run.log",this->GetApplicationHome().c_str()]);

		char *p = getenv("KR_PLUGINS");
		if (p)
		{
			FileUtils::Tokenize(p, this->module_paths, ":");
		}
	}

	OSXHost::~OSXHost()
	{
		CloseLog();
	}

	int OSXHost::Run()
	{
		TRACE(@PRODUCT_NAME" Kroll Running (OSX)...");
		this->AddModuleProvider(this);
		this->LoadModules();

		[NSApp run];
		return 0;
	}

	Module* OSXHost::CreateModule(std::string& path)
	{
		std::cout << "Creating module " << path << std::endl;

		void* lib_handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
		if (!lib_handle)
		{
			std::cerr << "Error load module: " << path << std::endl;
			return 0;
		}

		// get the module factory
		ModuleCreator* create = (ModuleCreator*)dlsym(lib_handle, "CreateModule");
		if (!create)
		{
			std::cerr << "Error load create entry from module: " << path << std::endl;
			return 0;
		}

		return create(this,FileUtils::GetDirectory(path));
	}
}

@interface KrollMainThreadCaller : NSObject
{
	SharedPtr<kroll::BoundMethod> method;
	SharedPtr<kroll::Value> result;
	kroll::ValueList args;
}
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)method args:(SharedPtr<ValueList>)args;
- (void)call;
- (SharedPtr<kroll::Value>)getResult;
@end

@implementation KrollMainThreadCaller
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)m args:(SharedPtr<ValueList>)a
{
	self = [super init];
	if (self)
	{
		method = m;
		args = a;
		result = NULL;
	}
	return self;
}
- (void)dealloc
{
	[super dealloc];
}
- (SharedPtr<kroll::Value>)getResult
{
	return result;
}
- (void)call
{
	result->assign(method->Call(args));
}
@end

namespace ti
{
	SharedValue OSXHost::InvokeMethodOnMainThread(SharedBoundMethod method,
	                                              const ValueList& args)
	{
		KrollMainThreadCaller *caller = [[KrollMainThreadCaller alloc] initWithBoundMethod:method args:args];
		[caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:YES];
		SharedValue result = [caller getResult];
		[caller release];
		return result;
	}
}

<commit_msg>Build fixes for osx<commit_after>/**
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include <iostream>
#include <vector>
#include <cstring>
#include <dlfcn.h>
#include <string>
#import <Cocoa/Cocoa.h>
#include "host.h"
#include "log.h"

namespace kroll
{
	OSXHost::OSXHost(int _argc, const char **_argv) : Host(_argc,_argv)
	{
		SetupLog(_argc,_argv,[NSString stringWithFormat:@"%s/run.log",this->GetApplicationHome().c_str()]);

		char *p = getenv("KR_PLUGINS");
		if (p)
		{
			FileUtils::Tokenize(p, this->module_paths, ":");
		}
	}

	OSXHost::~OSXHost()
	{
		CloseLog();
	}

	int OSXHost::Run()
	{
		TRACE(@PRODUCT_NAME" Kroll Running (OSX)...");
		this->AddModuleProvider(this);
		this->LoadModules();

		[NSApp run];
		return 0;
	}

	Module* OSXHost::CreateModule(std::string& path)
	{
		std::cout << "Creating module " << path << std::endl;

		void* lib_handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
		if (!lib_handle)
		{
			std::cerr << "Error load module: " << path << std::endl;
			return 0;
		}

		// get the module factory
		ModuleCreator* create = (ModuleCreator*)dlsym(lib_handle, "CreateModule");
		if (!create)
		{
			std::cerr << "Error load create entry from module: " << path << std::endl;
			return 0;
		}

		return create(this,FileUtils::GetDirectory(path));
	}
}

@interface KrollMainThreadCaller : NSObject
{
	SharedPtr<kroll::BoundMethod> *method;
	SharedPtr<kroll::Value> *result;
	const kroll::ValueList* args;
}
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)method args:(const ValueList*)args;
- (void)call;
- (SharedPtr<kroll::Value>)getResult;
@end

@implementation KrollMainThreadCaller
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)m args:(const ValueList*)a
{
	self = [super init];
	if (self)
	{
		method = new SharedPtr<kroll::BoundMethod>(m);
		args = a;
		result = new SharedPtr<kroll::Value>();
	}
	return self;
}
- (void)dealloc
{
	delete method;
	delete result;
	[super dealloc];
}
- (SharedPtr<kroll::Value>)getResult
{
	return *result;
}
- (void)call
{
	result->assign((*method)->Call(*args));
}
@end

namespace ti
{
	SharedValue OSXHost::InvokeMethodOnMainThread(SharedBoundMethod method,
	                                              const ValueList& args)
	{
		KrollMainThreadCaller *caller = [[KrollMainThreadCaller alloc] initWithBoundMethod:method args:&args];
		[caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:YES];
		SharedValue result = [caller getResult];
		[caller release];
		return result;
	}
}

<|endoftext|>


<commit_before>
/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Tests for the Solidity optimizer.
 */

#include <string>
#include <tuple>
#include <boost/test/unit_test.hpp>
#include <boost/lexical_cast.hpp>
#include <test/solidityExecutionFramework.h>

using namespace std;

namespace dev
{
namespace solidity
{
namespace test
{

class OptimizerTestFramework: public ExecutionFramework
{
public:
	OptimizerTestFramework() { }
	/// Compiles the source code with and without optimizing.
	void compileBothVersions(unsigned _expectedSizeDecrease, std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") {
		m_optimize = false;
		bytes nonOptimizedBytecode = compileAndRun(_sourceCode, _value, _contractName);
		m_nonOptimizedContract = m_contractAddress;
		m_optimize = true;
		bytes optimizedBytecode = compileAndRun(_sourceCode, _value, _contractName);
		int sizeDiff = nonOptimizedBytecode.size() - optimizedBytecode.size();
		BOOST_CHECK_MESSAGE(sizeDiff == int(_expectedSizeDecrease), "Bytecode shrank by "
							+ boost::lexical_cast<string>(sizeDiff) + " bytes, expected: "
							+ boost::lexical_cast<string>(_expectedSizeDecrease));
		m_optimizedContract = m_contractAddress;
	}

	template <class... Args>
	void compareVersions(std::string _sig, Args const&... _arguments)
	{
		m_contractAddress = m_nonOptimizedContract;
		bytes nonOptimizedOutput = callContractFunction(_sig, _arguments...);
		m_contractAddress = m_optimizedContract;
		bytes optimizedOutput = callContractFunction(_sig, _arguments...);
		BOOST_CHECK_MESSAGE(nonOptimizedOutput == optimizedOutput, "Computed values do not match."
							"\nNon-Optimized: " + toHex(nonOptimizedOutput) +
							"\nOptimized:     " + toHex(optimizedOutput));
	}

protected:
	Address m_optimizedContract;
	Address m_nonOptimizedContract;
};

BOOST_FIXTURE_TEST_SUITE(SolidityOptimizer, OptimizerTestFramework)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = R"(
		contract test {
			function f(uint a) returns (uint b) {
				return a;
			}
		})";
	compileBothVersions(29, sourceCode);
	compareVersions("f(uint256)", u256(7));
}

BOOST_AUTO_TEST_CASE(large_integers)
{
	char const* sourceCode = R"(
		contract test {
			function f() returns (uint a, uint b) {
				a = 0x234234872642837426347000000;
				b = 0x10000000000000000000000002;
			}
		})";
	compileBothVersions(53, sourceCode);
	compareVersions("f()");
}

BOOST_AUTO_TEST_CASE(invariants)
{
	char const* sourceCode = R"(
		contract test {
			function f(int a) returns (int b) {
				return int(0) | (int(1) * (int(0) ^ (0 + a)));
			}
		})";
	compileBothVersions(53, sourceCode);
	compareVersions("f(uint256)", u256(0x12334664));
}

BOOST_AUTO_TEST_CASE(unused_expressions)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			function f() returns (uint a, uint b) {
				10 + 20;
				data;
			}
		})";
	compileBothVersions(36, sourceCode);
	compareVersions("f()");
}

BOOST_AUTO_TEST_CASE(constant_folding_both_sides)
{
	// if constants involving the same associative and commutative operator are applied from both
	// sides, the operator should be applied only once, because the expression compiler pushes
	// literals as late as possible
	char const* sourceCode = R"(
		contract test {
			function f(uint x) returns (uint y) {
				return 98 ^ (7 * ((1 | (x | 1000)) * 40) ^ 102);
			}
		})";
	compileBothVersions(56, sourceCode);
	compareVersions("f(uint256)");
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces
<commit_msg>adjusting byte difference in optimizer large integers test<commit_after>
/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Tests for the Solidity optimizer.
 */

#include <string>
#include <tuple>
#include <boost/test/unit_test.hpp>
#include <boost/lexical_cast.hpp>
#include <test/solidityExecutionFramework.h>

using namespace std;

namespace dev
{
namespace solidity
{
namespace test
{

class OptimizerTestFramework: public ExecutionFramework
{
public:
	OptimizerTestFramework() { }
	/// Compiles the source code with and without optimizing.
	void compileBothVersions(unsigned _expectedSizeDecrease, std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") {
		m_optimize = false;
		bytes nonOptimizedBytecode = compileAndRun(_sourceCode, _value, _contractName);
		m_nonOptimizedContract = m_contractAddress;
		m_optimize = true;
		bytes optimizedBytecode = compileAndRun(_sourceCode, _value, _contractName);
		int sizeDiff = nonOptimizedBytecode.size() - optimizedBytecode.size();
		BOOST_CHECK_MESSAGE(sizeDiff == int(_expectedSizeDecrease), "Bytecode shrank by "
							+ boost::lexical_cast<string>(sizeDiff) + " bytes, expected: "
							+ boost::lexical_cast<string>(_expectedSizeDecrease));
		m_optimizedContract = m_contractAddress;
	}

	template <class... Args>
	void compareVersions(std::string _sig, Args const&... _arguments)
	{
		m_contractAddress = m_nonOptimizedContract;
		bytes nonOptimizedOutput = callContractFunction(_sig, _arguments...);
		m_contractAddress = m_optimizedContract;
		bytes optimizedOutput = callContractFunction(_sig, _arguments...);
		BOOST_CHECK_MESSAGE(nonOptimizedOutput == optimizedOutput, "Computed values do not match."
							"\nNon-Optimized: " + toHex(nonOptimizedOutput) +
							"\nOptimized:     " + toHex(optimizedOutput));
	}

protected:
	Address m_optimizedContract;
	Address m_nonOptimizedContract;
};

BOOST_FIXTURE_TEST_SUITE(SolidityOptimizer, OptimizerTestFramework)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = R"(
		contract test {
			function f(uint a) returns (uint b) {
				return a;
			}
		})";
	compileBothVersions(29, sourceCode);
	compareVersions("f(uint256)", u256(7));
}

BOOST_AUTO_TEST_CASE(large_integers)
{
	char const* sourceCode = R"(
		contract test {
			function f() returns (uint a, uint b) {
				a = 0x234234872642837426347000000;
				b = 0x10000000000000000000000002;
			}
		})";
	compileBothVersions(58, sourceCode);
	compareVersions("f()");
}

BOOST_AUTO_TEST_CASE(invariants)
{
	char const* sourceCode = R"(
		contract test {
			function f(int a) returns (int b) {
				return int(0) | (int(1) * (int(0) ^ (0 + a)));
			}
		})";
	compileBothVersions(53, sourceCode);
	compareVersions("f(uint256)", u256(0x12334664));
}

BOOST_AUTO_TEST_CASE(unused_expressions)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			function f() returns (uint a, uint b) {
				10 + 20;
				data;
			}
		})";
	compileBothVersions(36, sourceCode);
	compareVersions("f()");
}

BOOST_AUTO_TEST_CASE(constant_folding_both_sides)
{
	// if constants involving the same associative and commutative operator are applied from both
	// sides, the operator should be applied only once, because the expression compiler pushes
	// literals as late as possible
	char const* sourceCode = R"(
		contract test {
			function f(uint x) returns (uint y) {
				return 98 ^ (7 * ((1 | (x | 1000)) * 40) ^ 102);
			}
		})";
	compileBothVersions(56, sourceCode);
	compareVersions("f(uint256)");
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces
<|endoftext|>


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

#pragma once
#ifndef FS_COMMON_HPP
#define FS_COMMON_HPP

#include <memory>
#include <string>
#include <delegate>
#include <vector>
#include "path.hpp"
#include <hw/block_device.hpp>

namespace fs {

  // Generic structure for directory entries
  struct Dirent;

  /**
   * @brief Type used as a building block to represent buffers
   * within the filesystem subsystem
   */
  using buffer_t = std::shared_ptr<uint8_t>;

  /** Container types **/
  using dirvector = std::vector<Dirent>;
  using dirvec_t  = std::shared_ptr<dirvector>;

  /** Pointer types **/
  using Path_ptr = std::shared_ptr<Path>;

  /** ID types **/
  using Device_id = hw::Block_device::Device_id;

  /** Entity types for dirents **/
  enum Enttype {
    FILE,
    DIR,
    /** FAT puts disk labels in the root directory, hence: */
    VOLUME_ID,
    SYM_LINK,

    INVALID_ENTITY
  };

  /** Error type **/
  struct error_t
  {
    enum token_t {
      NO_ERR = 0,
      E_IO, // general I/O error
      E_MNT,

      E_NOENT,
      E_NOTDIR,
      E_NOTFILE
    }; //< enum token_t

    /**
     * @brief Constructor
     *
     * @param tk:  An error token
     * @param rsn: The reason for the error
     */
    error_t(const token_t tk, const std::string& rsn)
      : token_{tk}
      , reason_{rsn}
    {}

    /**
     * @brief Get a human-readable description of the token
     *
     * @return Description of the token as a {std::string}
     */
    const std::string& token() const noexcept;

    /**
     * @brief Get an explanation for error
     */
    const std::string& reason() const noexcept
    { return reason_; }

    /**
     * @brief Get a {std::string} representation of this type
     *
     * Format "description: reason"
     *
     * @return {std::string} representation of this type
     */
    std::string to_string() const
    { return token() + ": " + reason(); }

    /**
     * @brief Check if the object of this type represents
     * an error
     *
     * @return true if its an error, false otherwise
     */
    operator bool () const noexcept
    { return token_ not_eq NO_ERR; }

  private:
    token_t     token_;
    std::string reason_;
  }; //< struct error_t

  /**
   * @brief Type used for buffers within the filesystem
   * subsystem
   */
  struct Buffer
  {
    Buffer(const error_t& e, buffer_t b, const uint64_t l)
      : err_    {e}
      , buffer_ {b}
      , len_    {l}
    {}

    /**
     * @brief Check if an object of this type is in a valid
     * state
     *
     * @return true if valid, false otherwise
     */
    bool is_valid() const noexcept
    { return (buffer_ not_eq nullptr) and (not err_); }

    /**
     * @brief Coerce an object of this type to a bool
     */
    operator bool () const noexcept
    { return is_valid(); }

    /// retrieve error status
    error_t error() const noexcept
    { return err_; }

    /**
     * @brief Get the starting address of the underlying data buffer
     *
     * @return The starting address of the underlying data buffer
     */
    uint8_t* data() noexcept
    { return buffer_.get(); }

    /**
     * @brief Get the size/length of the buffer
     *
     * @return The size/length of the buffer
     */
    size_t   size() const noexcept
    { return len_; }

    /**
     * @brief Get a {std::string} representation of this type
     *
     * @return A {std::string} representation of this type
     */
    std::string to_string() const noexcept
    { return std::string{reinterpret_cast<char*>(buffer_.get()), size()}; }

  private:
    error_t  err_;
    buffer_t buffer_;
    uint64_t len_;
  }; //< struct Buffer

  /** @var no_error: Always returns boolean false when used in expressions */
  extern error_t no_error;

    /** Async function types **/
  using on_init_func  = delegate<void(error_t)>;
  using on_ls_func    = delegate<void(error_t, dirvec_t)>;
  using on_read_func  = delegate<void(error_t, buffer_t, uint64_t)>;
  using on_stat_func  = delegate<void(error_t, const Dirent&)>;

  struct List {
    error_t  error;
    dirvec_t entries;
    auto begin() { return entries->begin(); }
    auto end() { return entries->end(); }
    auto cbegin() { return entries->cbegin(); }
    auto cend() { return entries->cend(); }

  };

} //< namespace fs

#endif //< FS_ERROR_HPP
<commit_msg>fs: corrected #endif comment<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once
#ifndef FS_COMMON_HPP
#define FS_COMMON_HPP

#include <memory>
#include <string>
#include <delegate>
#include <vector>
#include "path.hpp"
#include <hw/block_device.hpp>

namespace fs {

  // Generic structure for directory entries
  struct Dirent;

  /**
   * @brief Type used as a building block to represent buffers
   * within the filesystem subsystem
   */
  using buffer_t = std::shared_ptr<uint8_t>;

  /** Container types **/
  using dirvector = std::vector<Dirent>;
  using dirvec_t  = std::shared_ptr<dirvector>;

  /** Pointer types **/
  using Path_ptr = std::shared_ptr<Path>;

  /** ID types **/
  using Device_id = hw::Block_device::Device_id;

  /** Entity types for dirents **/
  enum Enttype {
    FILE,
    DIR,
    /** FAT puts disk labels in the root directory, hence: */
    VOLUME_ID,
    SYM_LINK,

    INVALID_ENTITY
  };

  /** Error type **/
  struct error_t
  {
    enum token_t {
      NO_ERR = 0,
      E_IO, // general I/O error
      E_MNT,

      E_NOENT,
      E_NOTDIR,
      E_NOTFILE
    }; //< enum token_t

    /**
     * @brief Constructor
     *
     * @param tk:  An error token
     * @param rsn: The reason for the error
     */
    error_t(const token_t tk, const std::string& rsn)
      : token_{tk}
      , reason_{rsn}
    {}

    /**
     * @brief Get a human-readable description of the token
     *
     * @return Description of the token as a {std::string}
     */
    const std::string& token() const noexcept;

    /**
     * @brief Get an explanation for error
     */
    const std::string& reason() const noexcept
    { return reason_; }

    /**
     * @brief Get a {std::string} representation of this type
     *
     * Format "description: reason"
     *
     * @return {std::string} representation of this type
     */
    std::string to_string() const
    { return token() + ": " + reason(); }

    /**
     * @brief Check if the object of this type represents
     * an error
     *
     * @return true if its an error, false otherwise
     */
    operator bool () const noexcept
    { return token_ not_eq NO_ERR; }

  private:
    token_t     token_;
    std::string reason_;
  }; //< struct error_t

  /**
   * @brief Type used for buffers within the filesystem
   * subsystem
   */
  struct Buffer
  {
    Buffer(const error_t& e, buffer_t b, const uint64_t l)
      : err_    {e}
      , buffer_ {b}
      , len_    {l}
    {}

    /**
     * @brief Check if an object of this type is in a valid
     * state
     *
     * @return true if valid, false otherwise
     */
    bool is_valid() const noexcept
    { return (buffer_ not_eq nullptr) and (not err_); }

    /**
     * @brief Coerce an object of this type to a bool
     */
    operator bool () const noexcept
    { return is_valid(); }

    /// retrieve error status
    error_t error() const noexcept
    { return err_; }

    /**
     * @brief Get the starting address of the underlying data buffer
     *
     * @return The starting address of the underlying data buffer
     */
    uint8_t* data() noexcept
    { return buffer_.get(); }

    /**
     * @brief Get the size/length of the buffer
     *
     * @return The size/length of the buffer
     */
    size_t   size() const noexcept
    { return len_; }

    /**
     * @brief Get a {std::string} representation of this type
     *
     * @return A {std::string} representation of this type
     */
    std::string to_string() const noexcept
    { return std::string{reinterpret_cast<char*>(buffer_.get()), size()}; }

  private:
    error_t  err_;
    buffer_t buffer_;
    uint64_t len_;
  }; //< struct Buffer

  /** @var no_error: Always returns boolean false when used in expressions */
  extern error_t no_error;

    /** Async function types **/
  using on_init_func  = delegate<void(error_t)>;
  using on_ls_func    = delegate<void(error_t, dirvec_t)>;
  using on_read_func  = delegate<void(error_t, buffer_t, uint64_t)>;
  using on_stat_func  = delegate<void(error_t, const Dirent&)>;

  struct List {
    error_t  error;
    dirvec_t entries;
    auto begin() { return entries->begin(); }
    auto end() { return entries->end(); }
    auto cbegin() { return entries->cbegin(); }
    auto cend() { return entries->cend(); }

  };

} //< namespace fs

#endif //< FS_COMMON_HPP
<|endoftext|>