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

#include <iostream>
#include <string>
#include <vector>
#include <exception>
#include <fstream>
#include <iomanip>
#include <limits>
#include <algorithm>

#include <configuration.hpp>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <SNR.hpp>
#include <utils.hpp>
#include <Timer.hpp>

void initializeDeviceMemoryD(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * input, cl::Buffer * input_d, cl::Buffer * outputSNR_d, const uint64_t outputSNR_size, cl::Buffer * outputSample_d, const uint64_t outputSample_size);

int main(int argc, char * argv[]) {
  bool reinitializeDeviceMemory = true;
  bool DMsSamples = false;
  bool bestMode = false;
  unsigned int padding = 0;
  unsigned int nrIterations = 0;
  unsigned int clPlatformID = 0;
  unsigned int clDeviceID = 0;
  unsigned int minThreads = 0;
  unsigned int maxItems = 0;
  unsigned int maxThreads = 0;
  double bestGBs = 0.0;
  AstroData::Observation observation;
  SNR::snrConf conf;
  SNR::snrConf bestConf;
  cl::Event event;

  try {
    isa::utils::ArgumentList args(argc, argv);
    DMsSamples = args.getSwitch("-dms_samples");
    bool samplesDMs = args.getSwitch("-samples_dms");
    if ( (DMsSamples && samplesDMs) || (!DMsSamples && !samplesDMs) ) {
      std::cerr << "-dms_samples and -samples_dms are mutually exclusive." << std::endl;
      return 1;
    }
    nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
    clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
    clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
    bestMode = args.getSwitch("-best");
    padding = args.getSwitchArgument< unsigned int >("-padding");
    minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
    maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
    conf.setSubbandDedispersion(args.getSwitch("-subband"));
    observation.setNrSynthesizedBeams(args.getSwitchArgument< unsigned int >("-beams"));
    observation.setNrSamplesPerBatch(args.getSwitchArgument< unsigned int >("-samples"));
    if ( conf.getSubbandDedispersion() ) {
      observation.setDMRange(args.getSwitchArgument< unsigned int >("-subbanding_dms"), 0.0f, 0.0f, true);
    } else {
      observation.setDMRange(1, 0.0f, 0.0f, true);
    }
    observation.setDMRange(args.getSwitchArgument< unsigned int >("-dms"), 0.0, 0.0);
  } catch ( isa::utils::EmptyCommandLine & err ) {
    std::cerr << argv[0] << " [-best] [-dms_samples | -samples_dms] -iterations ... -opencl_platform ... -opencl_device ... -padding ... -min_threads ... -max_threads ... -max_items ... [-subband] -beams ... -dms ... -samples ..." << std::endl;
    std::cerr << "\t -subband : -subbanding_dms ..." << std::endl;
    return 1;
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  // Initialize OpenCL
  cl::Context clContext;
  std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
  std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
  std::vector< std::vector< cl::CommandQueue > > * clQueues = 0;

  // Allocate memory
  std::vector< inputDataType > input;
  cl::Buffer input_d, outputSNR_d, outputSample_d;

  if ( DMsSamples ) {
    input.resize(observation.getNrSynthesizedBeams() * observation.getNrDMs(true) * observation.getNrDMs() * observation.getNrSamplesPerBatch(false, padding / sizeof(inputDataType)));
  } else {
    input.resize(observation.getNrSynthesizedBeams() * observation.getNrSamplesPerBatch() * observation.getNrDMs(true) * observation.getNrDMs(false, padding / sizeof(inputDataType)));
  }

  srand(time(0));
  for ( unsigned int beam = 0; beam < observation.getNrSynthesizedBeams(); beam++ ) {
    if ( DMsSamples ) {
      for ( unsigned int subbandDM = 0; subbandDM < observation.getNrDMs(true); subbandDM++ ) {
        for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
          for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
            input[(beam * observation.getNrDMs(true) * observation.getNrDMs() * observation.getNrSamplesPerBatch(false, padding / sizeof(inputDataType))) + (subbandDM * observation.getNrDMs() * observation.getNrSamplesPerBatch(false, padding / sizeof(inputDataType))) + (dm * observation.getNrSamplesPerBatch(false, padding / sizeof(inputDataType))) + sample] = static_cast< inputDataType >(rand() % 10);
          }
        }
      }
    } else {
      for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
        for ( unsigned int subbandDM = 0; subbandDM < observation.getNrDMs(true); subbandDM++ ) {
          for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
            input[(beam * observation.getNrSamplesPerBatch() * observation.getNrDMs(true) * observation.getNrDMs(false, padding / sizeof(inputDataType))) + (sample * observation.getNrDMs(true) * observation.getNrDMs(false, padding / sizeof(inputDataType))) + (subbandDM * observation.getNrDMs(false, padding / sizeof(inputDataType))) + dm] = static_cast< inputDataType >(rand() % 10);
          }
        }
      }
    }
  }

  if ( !bestMode ) {
    std::cout << std::fixed << std::endl;
    std::cout << "# nrBeams nrDMs nrSamples *configuration* GB/s time stdDeviation COV" << std::endl << std::endl;
  }

  for ( unsigned int threads = minThreads; threads <= maxThreads; ) {
    conf.setNrThreadsD0(threads);
    if ( DMsSamples ) {
      threads *= 2;
    } else {
      threads++;
    }
    for ( unsigned int itemsPerThread = 1; itemsPerThread <= maxItems; itemsPerThread++ ) {
      if ( DMsSamples ) {
        if ( ((itemsPerThread * 5) + 8) > maxItems ) {
          break;
        }
        if ( (observation.getNrSamplesPerBatch() % itemsPerThread) != 0 ) {
          continue;
        }
      } else {
        if ( ((itemsPerThread * 5) + 3) > maxItems ) {
          break;
        }
        if ( observation.getNrDMs() % ( itemsPerThread * conf.getNrThreadsD0()) != 0 ) {
          continue;
        }
      }
      conf.setNrItemsD0(itemsPerThread);

      // Generate kernel
      double gbs = isa::utils::giga((observation.getNrSynthesizedBeams() * static_cast< uint64_t >(observation.getNrDMs(true) * observation.getNrDMs()) * observation.getNrSamplesPerBatch() * sizeof(inputDataType)) + (observation.getNrSynthesizedBeams() * static_cast< uint64_t >(observation.getNrDMs(true) * observation.getNrDMs()) * sizeof(float)) + (observation.getNrSynthesizedBeams() * static_cast< uint64_t >(observation.getNrDMs(true) * observation.getNrDMs()) * sizeof(unsigned int)));
      cl::Kernel * kernel;
      isa::utils::Timer timer;
      std::string * code;
      if ( DMsSamples ) {
        code = SNR::getSNRDMsSamplesOpenCL< inputDataType >(conf, inputDataName, observation, observation.getNrSamplesPerBatch(), padding);
      } else {
        code = SNR::getSNRSamplesDMsOpenCL< inputDataType >(conf, inputDataName, observation, observation.getNrSamplesPerBatch(), padding);
      }

      if ( reinitializeDeviceMemory ) {
        delete clQueues;
        clQueues = new std::vector< std::vector< cl::CommandQueue > >();
        isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
        try {
          initializeDeviceMemoryD(clContext, &(clQueues->at(clDeviceID)[0]), &input, &input_d, &outputSNR_d, observation.getNrSynthesizedBeams() * isa::utils::pad(observation.getNrDMs(true) * observation.getNrDMs(), padding / sizeof(float)) * sizeof(float), &outputSample_d, observation.getNrSynthesizedBeams() * isa::utils::pad(observation.getNrDMs(true) * observation.getNrDMs(), padding / sizeof(unsigned int)) * sizeof(unsigned int));
        } catch ( cl::Error & err ) {
          return -1;
        }
        reinitializeDeviceMemory = false;
      }
      try {
        if ( DMsSamples ) {
          kernel = isa::OpenCL::compile("snrDMsSamples" + std::to_string(observation.getNrSamplesPerBatch()), *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
        } else {
          kernel = isa::OpenCL::compile("snrSamplesDMs" + std::to_string(observation.getNrDMs(true) * observation.getNrDMs()), *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
        }
      } catch ( isa::OpenCL::OpenCLError & err ) {
        std::cerr << err.what() << std::endl;
        delete code;
        break;
      }
      delete code;

      cl::NDRange global, local;
      if ( DMsSamples ) {
        global = cl::NDRange(conf.getNrThreadsD0(), observation.getNrDMs(true) * observation.getNrDMs(), observation.getNrSynthesizedBeams());
        local = cl::NDRange(conf.getNrThreadsD0(), 1, 1);
      } else {
        global = cl::NDRange((observation.getNrDMs(true) * observation.getNrDMs()) / conf.getNrItemsD0(), observation.getNrSynthesizedBeams());
        local = cl::NDRange(conf.getNrThreadsD0(), 1);
      }

      kernel->setArg(0, input_d);
      kernel->setArg(1, outputSNR_d);
      kernel->setArg(2, outputSample_d);

      try {
        // Warm-up run
        clQueues->at(clDeviceID)[0].finish();
        clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
        event.wait();
        // Tuning runs
        for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
          timer.start();
          clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
          event.wait();
          timer.stop();
        }
      } catch ( cl::Error & err ) {
        std::cerr << "OpenCL error kernel execution (";
        std::cerr << conf.print();
        std::cerr << "): " << std::to_string(err.err()) << "." << std::endl;
        delete kernel;
        if ( err.err() == -4 || err.err() == -61 ) {
          return -1;
        }
        reinitializeDeviceMemory = true;
        break;
      }
      delete kernel;

      if ( (gbs / timer.getAverageTime()) > bestGBs ) {
        bestGBs = gbs / timer.getAverageTime();
        bestConf = conf;
      }
      if ( !bestMode ) {
        std::cout << observation.getNrSynthesizedBeams() << " " << observation.getNrDMs(true) * observation.getNrDMs() << " " << observation.getNrSamplesPerBatch() << " ";
        std::cout << conf.print() << " ";
        std::cout << std::setprecision(3);
        std::cout << gbs / timer.getAverageTime() << " ";
        std::cout << std::setprecision(6);
        std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " " << timer.getCoefficientOfVariation() << std::endl;
      }
    }
  }

  if ( bestMode ) {
    std::cout << observation.getNrDMs(true) * observation.getNrDMs() << " " << observation.getNrSamplesPerBatch() << " " << bestConf.print() << std::endl;
  } else {
    std::cout << std::endl;
  }

  return 0;
}

void initializeDeviceMemoryD(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * input, cl::Buffer * input_d, cl::Buffer * outputSNR_d, const uint64_t outputSNR_size, cl::Buffer * outputSample_d, const uint64_t outputSample_size) {
  try {
    *input_d = cl::Buffer(clContext, CL_MEM_READ_WRITE, input->size() * sizeof(inputDataType), 0, 0);
    *outputSNR_d = cl::Buffer(clContext, CL_MEM_WRITE_ONLY, outputSNR_size, 0, 0);
    *outputSample_d = cl::Buffer(clContext, CL_MEM_WRITE_ONLY, outputSample_size, 0, 0);
    clQueue->enqueueWriteBuffer(*input_d, CL_FALSE, 0, input->size() * sizeof(inputDataType), reinterpret_cast< void * >(input->data()));
    clQueue->finish();
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error: " << std::to_string(err.err()) << "." << std::endl;
    throw;
  }
}

<commit_msg>Avoid configurations with more workers than work.<commit_after>// Copyright 2017 Netherlands Institute for Radio Astronomy (ASTRON)
// Copyright 2017 Netherlands eScience Center
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include <string>
#include <vector>
#include <exception>
#include <fstream>
#include <iomanip>
#include <limits>
#include <algorithm>

#include <configuration.hpp>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <SNR.hpp>
#include <utils.hpp>
#include <Timer.hpp>

void initializeDeviceMemoryD(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * input, cl::Buffer * input_d, cl::Buffer * outputSNR_d, const uint64_t outputSNR_size, cl::Buffer * outputSample_d, const uint64_t outputSample_size);

int main(int argc, char * argv[]) {
  bool reinitializeDeviceMemory = true;
  bool DMsSamples = false;
  bool bestMode = false;
  unsigned int padding = 0;
  unsigned int nrIterations = 0;
  unsigned int clPlatformID = 0;
  unsigned int clDeviceID = 0;
  unsigned int minThreads = 0;
  unsigned int maxItems = 0;
  unsigned int maxThreads = 0;
  double bestGBs = 0.0;
  AstroData::Observation observation;
  SNR::snrConf conf;
  SNR::snrConf bestConf;
  cl::Event event;

  try {
    isa::utils::ArgumentList args(argc, argv);
    DMsSamples = args.getSwitch("-dms_samples");
    bool samplesDMs = args.getSwitch("-samples_dms");
    if ( (DMsSamples && samplesDMs) || (!DMsSamples && !samplesDMs) ) {
      std::cerr << "-dms_samples and -samples_dms are mutually exclusive." << std::endl;
      return 1;
    }
    nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
    clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
    clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
    bestMode = args.getSwitch("-best");
    padding = args.getSwitchArgument< unsigned int >("-padding");
    minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
    maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
    conf.setSubbandDedispersion(args.getSwitch("-subband"));
    observation.setNrSynthesizedBeams(args.getSwitchArgument< unsigned int >("-beams"));
    observation.setNrSamplesPerBatch(args.getSwitchArgument< unsigned int >("-samples"));
    if ( conf.getSubbandDedispersion() ) {
      observation.setDMRange(args.getSwitchArgument< unsigned int >("-subbanding_dms"), 0.0f, 0.0f, true);
    } else {
      observation.setDMRange(1, 0.0f, 0.0f, true);
    }
    observation.setDMRange(args.getSwitchArgument< unsigned int >("-dms"), 0.0, 0.0);
  } catch ( isa::utils::EmptyCommandLine & err ) {
    std::cerr << argv[0] << " [-best] [-dms_samples | -samples_dms] -iterations ... -opencl_platform ... -opencl_device ... -padding ... -min_threads ... -max_threads ... -max_items ... [-subband] -beams ... -dms ... -samples ..." << std::endl;
    std::cerr << "\t -subband : -subbanding_dms ..." << std::endl;
    return 1;
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  // Initialize OpenCL
  cl::Context clContext;
  std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
  std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
  std::vector< std::vector< cl::CommandQueue > > * clQueues = 0;

  // Allocate memory
  std::vector< inputDataType > input;
  cl::Buffer input_d, outputSNR_d, outputSample_d;

  if ( DMsSamples ) {
    input.resize(observation.getNrSynthesizedBeams() * observation.getNrDMs(true) * observation.getNrDMs() * observation.getNrSamplesPerBatch(false, padding / sizeof(inputDataType)));
  } else {
    input.resize(observation.getNrSynthesizedBeams() * observation.getNrSamplesPerBatch() * observation.getNrDMs(true) * observation.getNrDMs(false, padding / sizeof(inputDataType)));
  }

  srand(time(0));
  for ( unsigned int beam = 0; beam < observation.getNrSynthesizedBeams(); beam++ ) {
    if ( DMsSamples ) {
      for ( unsigned int subbandDM = 0; subbandDM < observation.getNrDMs(true); subbandDM++ ) {
        for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
          for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
            input[(beam * observation.getNrDMs(true) * observation.getNrDMs() * observation.getNrSamplesPerBatch(false, padding / sizeof(inputDataType))) + (subbandDM * observation.getNrDMs() * observation.getNrSamplesPerBatch(false, padding / sizeof(inputDataType))) + (dm * observation.getNrSamplesPerBatch(false, padding / sizeof(inputDataType))) + sample] = static_cast< inputDataType >(rand() % 10);
          }
        }
      }
    } else {
      for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
        for ( unsigned int subbandDM = 0; subbandDM < observation.getNrDMs(true); subbandDM++ ) {
          for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
            input[(beam * observation.getNrSamplesPerBatch() * observation.getNrDMs(true) * observation.getNrDMs(false, padding / sizeof(inputDataType))) + (sample * observation.getNrDMs(true) * observation.getNrDMs(false, padding / sizeof(inputDataType))) + (subbandDM * observation.getNrDMs(false, padding / sizeof(inputDataType))) + dm] = static_cast< inputDataType >(rand() % 10);
          }
        }
      }
    }
  }

  if ( !bestMode ) {
    std::cout << std::fixed << std::endl;
    std::cout << "# nrBeams nrDMs nrSamples *configuration* GB/s time stdDeviation COV" << std::endl << std::endl;
  }

  for ( unsigned int threads = minThreads; threads <= maxThreads; ) {
    conf.setNrThreadsD0(threads);
    if ( DMsSamples ) {
      threads *= 2;
    } else {
      threads++;
    }
    for ( unsigned int itemsPerThread = 1; itemsPerThread <= maxItems; itemsPerThread++ ) {
      if ( DMsSamples ) {
        if ( ((itemsPerThread * 5) + 8) > maxItems ) {
          break;
        }
        if ( (observation.getNrSamplesPerBatch() % itemsPerThread) != 0 ) {
          continue;
        }
      } else {
        if ( ((itemsPerThread * 5) + 3) > maxItems ) {
          break;
        }
        if ( observation.getNrDMs() % ( itemsPerThread * conf.getNrThreadsD0()) != 0 ) {
          continue;
        }
      }
      conf.setNrItemsD0(itemsPerThread);
      if ( conf.getNrItemsD0() * conf.getNrItemsD0() > observation.getNrSamplesPerBatch() )
      {
        continue;
      }

      // Generate kernel
      double gbs = isa::utils::giga((observation.getNrSynthesizedBeams() * static_cast< uint64_t >(observation.getNrDMs(true) * observation.getNrDMs()) * observation.getNrSamplesPerBatch() * sizeof(inputDataType)) + (observation.getNrSynthesizedBeams() * static_cast< uint64_t >(observation.getNrDMs(true) * observation.getNrDMs()) * sizeof(float)) + (observation.getNrSynthesizedBeams() * static_cast< uint64_t >(observation.getNrDMs(true) * observation.getNrDMs()) * sizeof(unsigned int)));
      cl::Kernel * kernel;
      isa::utils::Timer timer;
      std::string * code;
      if ( DMsSamples ) {
        code = SNR::getSNRDMsSamplesOpenCL< inputDataType >(conf, inputDataName, observation, observation.getNrSamplesPerBatch(), padding);
      } else {
        code = SNR::getSNRSamplesDMsOpenCL< inputDataType >(conf, inputDataName, observation, observation.getNrSamplesPerBatch(), padding);
      }

      if ( reinitializeDeviceMemory ) {
        delete clQueues;
        clQueues = new std::vector< std::vector< cl::CommandQueue > >();
        isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
        try {
          initializeDeviceMemoryD(clContext, &(clQueues->at(clDeviceID)[0]), &input, &input_d, &outputSNR_d, observation.getNrSynthesizedBeams() * isa::utils::pad(observation.getNrDMs(true) * observation.getNrDMs(), padding / sizeof(float)) * sizeof(float), &outputSample_d, observation.getNrSynthesizedBeams() * isa::utils::pad(observation.getNrDMs(true) * observation.getNrDMs(), padding / sizeof(unsigned int)) * sizeof(unsigned int));
        } catch ( cl::Error & err ) {
          return -1;
        }
        reinitializeDeviceMemory = false;
      }
      try {
        if ( DMsSamples ) {
          kernel = isa::OpenCL::compile("snrDMsSamples" + std::to_string(observation.getNrSamplesPerBatch()), *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
        } else {
          kernel = isa::OpenCL::compile("snrSamplesDMs" + std::to_string(observation.getNrDMs(true) * observation.getNrDMs()), *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
        }
      } catch ( isa::OpenCL::OpenCLError & err ) {
        std::cerr << err.what() << std::endl;
        delete code;
        break;
      }
      delete code;

      cl::NDRange global, local;
      if ( DMsSamples ) {
        global = cl::NDRange(conf.getNrThreadsD0(), observation.getNrDMs(true) * observation.getNrDMs(), observation.getNrSynthesizedBeams());
        local = cl::NDRange(conf.getNrThreadsD0(), 1, 1);
      } else {
        global = cl::NDRange((observation.getNrDMs(true) * observation.getNrDMs()) / conf.getNrItemsD0(), observation.getNrSynthesizedBeams());
        local = cl::NDRange(conf.getNrThreadsD0(), 1);
      }

      kernel->setArg(0, input_d);
      kernel->setArg(1, outputSNR_d);
      kernel->setArg(2, outputSample_d);

      try {
        // Warm-up run
        clQueues->at(clDeviceID)[0].finish();
        clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
        event.wait();
        // Tuning runs
        for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
          timer.start();
          clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
          event.wait();
          timer.stop();
        }
      } catch ( cl::Error & err ) {
        std::cerr << "OpenCL error kernel execution (";
        std::cerr << conf.print();
        std::cerr << "): " << std::to_string(err.err()) << "." << std::endl;
        delete kernel;
        if ( err.err() == -4 || err.err() == -61 ) {
          return -1;
        }
        reinitializeDeviceMemory = true;
        break;
      }
      delete kernel;

      if ( (gbs / timer.getAverageTime()) > bestGBs ) {
        bestGBs = gbs / timer.getAverageTime();
        bestConf = conf;
      }
      if ( !bestMode ) {
        std::cout << observation.getNrSynthesizedBeams() << " " << observation.getNrDMs(true) * observation.getNrDMs() << " " << observation.getNrSamplesPerBatch() << " ";
        std::cout << conf.print() << " ";
        std::cout << std::setprecision(3);
        std::cout << gbs / timer.getAverageTime() << " ";
        std::cout << std::setprecision(6);
        std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " " << timer.getCoefficientOfVariation() << std::endl;
      }
    }
  }

  if ( bestMode ) {
    std::cout << observation.getNrDMs(true) * observation.getNrDMs() << " " << observation.getNrSamplesPerBatch() << " " << bestConf.print() << std::endl;
  } else {
    std::cout << std::endl;
  }

  return 0;
}

void initializeDeviceMemoryD(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * input, cl::Buffer * input_d, cl::Buffer * outputSNR_d, const uint64_t outputSNR_size, cl::Buffer * outputSample_d, const uint64_t outputSample_size) {
  try {
    *input_d = cl::Buffer(clContext, CL_MEM_READ_WRITE, input->size() * sizeof(inputDataType), 0, 0);
    *outputSNR_d = cl::Buffer(clContext, CL_MEM_WRITE_ONLY, outputSNR_size, 0, 0);
    *outputSample_d = cl::Buffer(clContext, CL_MEM_WRITE_ONLY, outputSample_size, 0, 0);
    clQueue->enqueueWriteBuffer(*input_d, CL_FALSE, 0, input->size() * sizeof(inputDataType), reinterpret_cast< void * >(input->data()));
    clQueue->finish();
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error: " << std::to_string(err.err()) << "." << std::endl;
    throw;
  }
}

<|endoftext|>


<commit_before>#pragma ident "$Id$"

/**
 * @file SP3Stream.hpp
 * File stream for SP3 format files
 */

#ifndef GPSTK_SP3STREAM_HPP
#define GPSTK_SP3STREAM_HPP

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

#include "DayTime.hpp"
#include "FFTextStream.hpp"

namespace gpstk
{
   /** @addtogroup SP3ephem */
   //@{

      /**
       * This class provides access to SP3 files.
       *
       * @sa gpstk::SP3Header and gpstk::SP3Data for more information.
       * @sa sp3_test.cpp for an example.
       */
   class SP3Stream : public FFTextStream
   {
   public:
      SP3Stream() : buffer(std::string()) {}

         /** Constructor
          * Opens file \a fn using ios::openmode \a mode.
          */
      SP3Stream(const char* fn, std::ios::openmode mode=std::ios::in)
            : FFTextStream(fn, mode) {}

         /// destructor
      virtual ~SP3Stream() {}

      DayTime currentEpoch;   ///< Time from last epoch record read
      std::string buffer;     ///< Last line read, not yet processed
   };

   //@}

}  // namespace

#endif
<commit_msg>correcting ref to test code<commit_after>#pragma ident "$Id$"

/**
 * @file SP3Stream.hpp
 * File stream for SP3 format files
 */

#ifndef GPSTK_SP3STREAM_HPP
#define GPSTK_SP3STREAM_HPP

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

#include "DayTime.hpp"
#include "FFTextStream.hpp"

namespace gpstk
{
   /** @addtogroup SP3ephem */
   //@{

      /**
       * This class provides access to SP3 files.
       *
       * @sa gpstk::SP3Header and gpstk::SP3Data for more information.
       * @sa petest.cpp for an example.
       */
   class SP3Stream : public FFTextStream
   {
   public:
      SP3Stream() : buffer(std::string()) {}

         /** Constructor
          * Opens file \a fn using ios::openmode \a mode.
          */
      SP3Stream(const char* fn, std::ios::openmode mode=std::ios::in)
            : FFTextStream(fn, mode) {}

         /// destructor
      virtual ~SP3Stream() {}

      DayTime currentEpoch;   ///< Time from last epoch record read
      std::string buffer;     ///< Last line read, not yet processed
   };

   //@}

}  // namespace

#endif
<|endoftext|>


<commit_before>// Sh: A GPU metaprogramming language.
//
// Copyright 2003-2005 Serious Hack Inc.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must
// not claim that you wrote the original software. If you use this
// software in a product, an acknowledgment in the product documentation
// would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must
// not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef WIN32
# include <ltdl.h>
# include <dirent.h>
# define LOCAL_BACKEND_DIRNAME ".shbackends"
#else
# include <windows.h>
#endif

#include <algorithm>
#include <cctype>

#include "ShBackend.hpp"
#include "ShProgram.hpp"
#include "ShDebug.hpp"
#include "ShInternals.hpp"
#include "ShTransformer.hpp"
#include "ShSyntax.hpp"

namespace SH {

using namespace std;

ShBackend::BackendMap* ShBackend::m_instantiated_backends = 0;
ShBackend::BackendSet* ShBackend::m_selected_backends = 0;
ShBackend::LibraryMap* ShBackend::m_loaded_libraries = 0;
bool ShBackend::m_done_init = false;
bool ShBackend::m_all_backends_loaded = false;

ShBackendCode::~ShBackendCode()
{
}

ShBackendSet::~ShBackendSet()
{
}

// A default implementation of ShBackendSet, usable for any backends
// that don't involve special linking.
class ShTrivialBackendSet : public ShBackendSet {
public:
  ShTrivialBackendSet(const ShProgramSet& s,
                      const ShBackendPtr& backend);

  virtual ~ShTrivialBackendSet();

  virtual void link();

  virtual void bind();
  virtual void unbind();

protected:
  list<ShBackendCodePtr> m_code;
};

typedef ShPointer<ShTrivialBackendSet> ShTrivialBackendSetPtr;
typedef ShPointer<const ShTrivialBackendSet> ShTrivialBackendSetCPtr;

ShTrivialBackendSet::ShTrivialBackendSet(const ShProgramSet& s,
                                         const ShBackendPtr& backend)
{
  for (ShProgramSet::const_iterator I = s.begin(); I != s.end(); ++I) {
    m_code.push_back((*I)->code(backend));
  }
}

ShTrivialBackendSet::~ShTrivialBackendSet()
{
}

void ShTrivialBackendSet::link()
{
}

void ShTrivialBackendSet::bind()
{
  for (list<ShBackendCodePtr>::iterator I = m_code.begin(); I != m_code.end(); ++I) {
    (*I)->bind();
  }
}

void ShTrivialBackendSet::unbind()
{
  // TODO: This may not quite have the correct semantics
  for (list<ShBackendCodePtr>::iterator I = m_code.begin(); I != m_code.end(); ++I) {
    (*I)->unbind();
  }
}

ShBackend::ShBackend()
{
}

ShBackend::~ShBackend()
{
  string backend_name = name();
  m_instantiated_backends->erase(backend_name);

#ifndef WIN32
  if (!lt_dlclose((*m_loaded_libraries)[backend_name])) {
    SH_DEBUG_ERROR("Could not unload the " << backend_name << " library: " << lt_dlerror());
  }
#else
  if (!FreeLibrary((HMODULE)(*m_loaded_libraries)[backend_name])) {
    SH_DEBUG_ERROR("Could not unload the " << backend_name << " library.");
  }
#endif

  m_loaded_libraries->erase(backend_name);
  m_selected_backends->erase(backend_name);
}

ShBackendSetPtr ShBackend::generate_set(const ShProgramSet& s)
{
  return new ShTrivialBackendSet(s, this);
}

string ShBackend::lookup_filename(const string& name)
{
  init();
  string libname;

#ifndef WIN32
  libname = name + ".so";
#else
  libname = name;
# ifdef SH_DEBUG
    libname += "_DEBUG";
# endif
  libname += ".DLL";
#endif

  return libname;
}

bool ShBackend::load_library(const string& filename)
{
  init();

  if (filename.empty()) return false;

#ifndef WIN32
  unsigned extension_pos = filename.rfind(".so");
  unsigned filename_pos = filename.rfind("/") + 1;
#else
  string uc_filename(filename);
  std::transform(filename.begin(), filename.end(), uc_filename.begin(), toupper);
  unsigned extension_pos = uc_filename.rfind("_DEBUG.DLL");
  if (uc_filename.npos == extension_pos) extension_pos = uc_filename.rfind(".DLL");
  unsigned filename_pos = uc_filename.rfind("\\") + 1;
#endif

  string backend_name = filename.substr(filename_pos, extension_pos - filename_pos);
  if (m_loaded_libraries->find(backend_name) != m_loaded_libraries->end()) {
    return true; // already loaded
  }

#ifndef WIN32
  LibraryHandle module = lt_dlopenext(filename.c_str());
#else
  LibraryHandle module = LoadLibrary(filename.c_str());
#endif

  if (module) {
    (*m_loaded_libraries)[backend_name] = module;
    return true;
  } else {
    SH_DEBUG_WARN("Could not open " << filename);
    return false;
  }
}

void ShBackend::load_libraries(const string& directory)
{
#ifndef WIN32
  DIR* dirp = opendir(directory.c_str());
  if (dirp) {
    // Go through all files in lib/sh/
    for (struct dirent* entry = readdir(dirp); entry != 0; entry = readdir(dirp)) {
      string filename(entry->d_name);
      unsigned extension_pos = filename.rfind(".so");
      if ((filename.find("libsh") == 0) && ((filename.size() - 3) == extension_pos)) {
        load_library(directory + "/" + filename);
      }
    }
    closedir(dirp);
  }
#else
  string filenames = directory + "\\libsh*.dll";
  WIN32_FIND_DATA find_data;

  HANDLE file_handle = FindFirstFile(filenames.c_str(), &find_data);
  while (file_handle != INVALID_HANDLE_VALUE) {
    load_library(string(find_data.cFileName));
	if (!FindNextFile(file_handle, &find_data)) break;
  }
  FindClose(file_handle);
#endif /* WIN32 */
}

ShBackendPtr ShBackend::instantiate_backend(const string& backend_name)
{
  init();
  ShBackend* backend = 0;

  if (m_instantiated_backends->find(backend_name) != m_instantiated_backends->end()) {
    return (*m_instantiated_backends)[backend_name];
  }

  LibraryHandle module = (*m_loaded_libraries)[backend_name];
  string init_function_name = "shBackend_" + backend_name + "_instantiate";

  typedef ShBackend* EntryPoint();
#ifndef WIN32
  EntryPoint* instantiate = (EntryPoint*)lt_dlsym(module, init_function_name.c_str());
#else
  EntryPoint* instantiate = (EntryPoint*)GetProcAddress((HMODULE)module, init_function_name.c_str());
#endif

  if (instantiate) {
    backend = (*instantiate)();
  } else {
    SH_DEBUG_ERROR("Could not find " << init_function_name);
  }

  if (backend) {
    (*m_instantiated_backends)[backend_name] = backend;
  }

  return backend;
}

bool ShBackend::use_backend(const string& name)
{
  init();
  const string backend_name = "libsh" + name;
  m_selected_backends->insert(backend_name);
  return load_library(lookup_filename(backend_name));
}

void ShBackend::clear_backends()
{
  init();
  m_selected_backends->clear();
}

int ShBackend::target_cost(const string& backend_name, const string& target)
{
  init();
  int cost = 0;

  string init_function_name = "shBackend_" + backend_name + "_target_cost";
  LibraryHandle module = (*m_loaded_libraries)[backend_name];
  SH_DEBUG_ASSERT(module); // library not loaded

  typedef int EntryPoint(const string&);
#ifndef WIN32
  EntryPoint* func = (EntryPoint*)lt_dlsym(module, init_function_name.c_str());
#else
  EntryPoint* func = (EntryPoint*)GetProcAddress((HMODULE)module, init_function_name.c_str());
#endif

  if (func) {
     cost = (*func)(target);
  } else {
    SH_DEBUG_ERROR("Could not find " << init_function_name);
  }

  return cost;
}

ShPointer<ShBackend> ShBackend::get_backend(const string& target)
{
  init();

  if ((0 == m_selected_backends->size()) && (!m_all_backends_loaded)) {
    // Load all installed backend libraries
#ifndef WIN32
    load_libraries(string(getenv("HOME")) + "/" + LOCAL_BACKEND_DIRNAME);
    load_libraries(string(SH_INSTALL_PREFIX) + "/lib/sh");
#else
    load_libraries(string("."));
    load_libraries(string("C:\\windows\\system32"));
#endif
    m_all_backends_loaded = true;
  }

  // Look in all loaded libraries for the backend with the lowest cost
  string best_backend = "";
  int lowest_cost = -1;
  for (LibraryMap::iterator i = m_loaded_libraries->begin();
       i != m_loaded_libraries->end(); i++) {
    string backend_name = i->first;
    if ((m_selected_backends->size() > 0) &&
	m_selected_backends->find(backend_name) == m_selected_backends->end()) {
      continue; // this backend is not currently in use
    }

    int cost = target_cost(backend_name, target);
    if (0 == cost) continue; // not supported by this backend

    if ((lowest_cost < 0) || (cost < lowest_cost)) {
      lowest_cost = cost;
      best_backend = backend_name;
      if (1 == cost) break; // we won't find a better one
    }
  }

  if (lowest_cost > 0) {
    return instantiate_backend(best_backend);
  } else {
    cerr << "Could not find a backend that supports the '" << target << "' target." << endl;
    if (m_selected_backends->size() > 0) {
      cerr << "Try removing all shUseBackend() and shSetBackend() calls to search all installed backends." << endl;
    }
    return 0;
  }
}

void ShBackend::init()
{
  if (m_done_init) return;

  m_instantiated_backends = new BackendMap();
  m_selected_backends = new BackendSet();
  m_loaded_libraries = new LibraryMap();

#ifndef WIN32
  if (lt_dlinit()) {
    SH_DEBUG_ERROR("Error initializing ltdl: " << lt_dlerror());
  }

  string userpath(getenv("HOME"));
  userpath += "/";
  userpath += LOCAL_BACKEND_DIRNAME;
  if (lt_dladdsearchdir(userpath.c_str())) {
    SH_DEBUG_ERROR("Could not add " + userpath + " to search dir: " << lt_dlerror());
  }

  string searchpath(SH_INSTALL_PREFIX);
  searchpath += "/lib/sh";
  if (lt_dladdsearchdir(searchpath.c_str())) {
    SH_DEBUG_ERROR("Could not add " + searchpath + " to search dir: " << lt_dlerror());
  }
#endif /* WIN32 */

  m_done_init = true;
}

void ShBackend::unbind_all_programs()
{
  while (ShContext::current()->begin_bound() != ShContext::current()->end_bound()) {
    shUnbind(ShContext::current()->begin_bound()->second);
  }
}

void ShBackend::unbind_all_backends()
{
  init();
  for (BackendMap::iterator i = m_instantiated_backends->begin();
       i != m_instantiated_backends->end(); i++) {
    i->second->unbind_all_programs();
  }
}

}
<commit_msg>Fix the previous EOL screw-up<commit_after>// Sh: A GPU metaprogramming language.
//
// Copyright 2003-2005 Serious Hack Inc.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must
// not claim that you wrote the original software. If you use this
// software in a product, an acknowledgment in the product documentation
// would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must
// not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef WIN32
# include <ltdl.h>
# include <dirent.h>
# define LOCAL_BACKEND_DIRNAME ".shbackends"
#else
# include <windows.h>
#endif

#include <algorithm>
#include <cctype>

#include "ShBackend.hpp"
#include "ShProgram.hpp"
#include "ShDebug.hpp"
#include "ShInternals.hpp"
#include "ShTransformer.hpp"
#include "ShSyntax.hpp"

namespace SH {

using namespace std;

ShBackend::BackendMap* ShBackend::m_instantiated_backends = 0;
ShBackend::BackendSet* ShBackend::m_selected_backends = 0;
ShBackend::LibraryMap* ShBackend::m_loaded_libraries = 0;
bool ShBackend::m_done_init = false;
bool ShBackend::m_all_backends_loaded = false;

ShBackendCode::~ShBackendCode()
{
}

ShBackendSet::~ShBackendSet()
{
}

// A default implementation of ShBackendSet, usable for any backends
// that don't involve special linking.
class ShTrivialBackendSet : public ShBackendSet {
public:
  ShTrivialBackendSet(const ShProgramSet& s,
                      const ShBackendPtr& backend);

  virtual ~ShTrivialBackendSet();

  virtual void link();

  virtual void bind();
  virtual void unbind();

protected:
  list<ShBackendCodePtr> m_code;
};

typedef ShPointer<ShTrivialBackendSet> ShTrivialBackendSetPtr;
typedef ShPointer<const ShTrivialBackendSet> ShTrivialBackendSetCPtr;

ShTrivialBackendSet::ShTrivialBackendSet(const ShProgramSet& s,
                                         const ShBackendPtr& backend)
{
  for (ShProgramSet::const_iterator I = s.begin(); I != s.end(); ++I) {
    m_code.push_back((*I)->code(backend));
  }
}

ShTrivialBackendSet::~ShTrivialBackendSet()
{
}

void ShTrivialBackendSet::link()
{
}

void ShTrivialBackendSet::bind()
{
  for (list<ShBackendCodePtr>::iterator I = m_code.begin(); I != m_code.end(); ++I) {
    (*I)->bind();
  }
}

void ShTrivialBackendSet::unbind()
{
  // TODO: This may not quite have the correct semantics
  for (list<ShBackendCodePtr>::iterator I = m_code.begin(); I != m_code.end(); ++I) {
    (*I)->unbind();
  }
}

ShBackend::ShBackend()
{
}

ShBackend::~ShBackend()
{
  string backend_name = name();
  m_instantiated_backends->erase(backend_name);

#ifndef WIN32
  if (!lt_dlclose((*m_loaded_libraries)[backend_name])) {
    SH_DEBUG_ERROR("Could not unload the " << backend_name << " library: " << lt_dlerror());
  }
#else
  if (!FreeLibrary((HMODULE)(*m_loaded_libraries)[backend_name])) {
    SH_DEBUG_ERROR("Could not unload the " << backend_name << " library.");
  }
#endif

  m_loaded_libraries->erase(backend_name);
  m_selected_backends->erase(backend_name);
}

ShBackendSetPtr ShBackend::generate_set(const ShProgramSet& s)
{
  return new ShTrivialBackendSet(s, this);
}

string ShBackend::lookup_filename(const string& name)
{
  init();
  string libname;

#ifndef WIN32
  libname = name + ".so";
#else
  libname = name;
# ifdef SH_DEBUG
    libname += "_DEBUG";
# endif
  libname += ".DLL";
#endif

  return libname;
}

bool ShBackend::load_library(const string& filename)
{
  init();

  if (filename.empty()) return false;

#ifndef WIN32
  unsigned extension_pos = filename.rfind(".so");
  unsigned filename_pos = filename.rfind("/") + 1;
#else
  string uc_filename(filename);
  std::transform(filename.begin(), filename.end(), uc_filename.begin(), toupper);
  unsigned extension_pos = uc_filename.rfind("_DEBUG.DLL");
  if (uc_filename.npos == extension_pos) extension_pos = uc_filename.rfind(".DLL");
  unsigned filename_pos = uc_filename.rfind("\\") + 1;
#endif

  string backend_name = filename.substr(filename_pos, extension_pos - filename_pos);
  if (m_loaded_libraries->find(backend_name) != m_loaded_libraries->end()) {
    return true; // already loaded
  }

#ifndef WIN32
  LibraryHandle module = lt_dlopenext(filename.c_str());
#else
  LibraryHandle module = LoadLibrary(filename.c_str());
#endif

  if (module) {
    (*m_loaded_libraries)[backend_name] = module;
    return true;
  } else {
    SH_DEBUG_WARN("Could not open " << filename);
    return false;
  }
}

void ShBackend::load_libraries(const string& directory)
{
#ifndef WIN32
  DIR* dirp = opendir(directory.c_str());
  if (dirp) {
    // Go through all files in lib/sh/
    for (struct dirent* entry = readdir(dirp); entry != 0; entry = readdir(dirp)) {
      string filename(entry->d_name);
      unsigned extension_pos = filename.rfind(".so");
      if ((filename.find("libsh") == 0) && ((filename.size() - 3) == extension_pos)) {
        load_library(directory + "/" + filename);
      }
    }
    closedir(dirp);
  }
#else
  string filenames = directory + "\\libsh*.dll";
  WIN32_FIND_DATA find_data;

  HANDLE file_handle = FindFirstFile(filenames.c_str(), &find_data);
  while (file_handle != INVALID_HANDLE_VALUE) {
    load_library(string(find_data.cFileName));
	if (!FindNextFile(file_handle, &find_data)) break;
  }
  FindClose(file_handle);
#endif /* WIN32 */
}

ShBackendPtr ShBackend::instantiate_backend(const string& backend_name)
{
  init();
  ShBackend* backend = 0;

  if (m_instantiated_backends->find(backend_name) != m_instantiated_backends->end()) {
    return (*m_instantiated_backends)[backend_name];
  }

  LibraryHandle module = (*m_loaded_libraries)[backend_name];
  string init_function_name = "shBackend_" + backend_name + "_instantiate";

  typedef ShBackend* EntryPoint();
#ifndef WIN32
  EntryPoint* instantiate = (EntryPoint*)lt_dlsym(module, init_function_name.c_str());
#else
  EntryPoint* instantiate = (EntryPoint*)GetProcAddress((HMODULE)module, init_function_name.c_str());
#endif

  if (instantiate) {
    backend = (*instantiate)();
  } else {
    SH_DEBUG_ERROR("Could not find " << init_function_name);
  }

  if (backend) {
    (*m_instantiated_backends)[backend_name] = backend;
  }

  return backend;
}

bool ShBackend::use_backend(const string& name)
{
  init();
  const string backend_name = "libsh" + name;
  m_selected_backends->insert(backend_name);
  return load_library(lookup_filename(backend_name));
}

void ShBackend::clear_backends()
{
  init();
  m_selected_backends->clear();
}

int ShBackend::target_cost(const string& backend_name, const string& target)
{
  init();
  int cost = 0;

  string init_function_name = "shBackend_" + backend_name + "_target_cost";
  LibraryHandle module = (*m_loaded_libraries)[backend_name];
  SH_DEBUG_ASSERT(module); // library not loaded

  typedef int EntryPoint(const string&);
#ifndef WIN32
  EntryPoint* func = (EntryPoint*)lt_dlsym(module, init_function_name.c_str());
#else
  EntryPoint* func = (EntryPoint*)GetProcAddress((HMODULE)module, init_function_name.c_str());
#endif

  if (func) {
     cost = (*func)(target);
  } else {
    SH_DEBUG_ERROR("Could not find " << init_function_name);
  }

  return cost;
}

ShPointer<ShBackend> ShBackend::get_backend(const string& target)
{
  init();

  if ((0 == m_selected_backends->size()) && (!m_all_backends_loaded)) {
    // Load all installed backend libraries
#ifndef WIN32
    load_libraries(string(getenv("HOME")) + "/" + LOCAL_BACKEND_DIRNAME);
    load_libraries(string(SH_INSTALL_PREFIX) + "/lib/sh");
#else
    load_libraries(string("."));
    load_libraries(string("C:\\windows\\system32")); // TODO: go through the path instead
#endif
    m_all_backends_loaded = true;
  }

  // Look in all loaded libraries for the backend with the lowest cost
  string best_backend = "";
  int lowest_cost = -1;
  for (LibraryMap::iterator i = m_loaded_libraries->begin();
       i != m_loaded_libraries->end(); i++) {
    string backend_name = i->first;
    if ((m_selected_backends->size() > 0) &&
	m_selected_backends->find(backend_name) == m_selected_backends->end()) {
      continue; // this backend is not currently in use
    }

    int cost = target_cost(backend_name, target);
    if (0 == cost) continue; // not supported by this backend

    if ((lowest_cost < 0) || (cost < lowest_cost)) {
      lowest_cost = cost;
      best_backend = backend_name;
      if (1 == cost) break; // we won't find a better one
    }
  }

  if (lowest_cost > 0) {
    return instantiate_backend(best_backend);
  } else {
    cerr << "Could not find a backend that supports the '" << target << "' target." << endl;
    if (m_selected_backends->size() > 0) {
      cerr << "Try removing all shUseBackend() and shSetBackend() calls to search all installed backends." << endl;
    }
    return 0;
  }
}

void ShBackend::init()
{
  if (m_done_init) return;

  m_instantiated_backends = new BackendMap();
  m_selected_backends = new BackendSet();
  m_loaded_libraries = new LibraryMap();

#ifndef WIN32
  if (lt_dlinit()) {
    SH_DEBUG_ERROR("Error initializing ltdl: " << lt_dlerror());
  }

  string userpath(getenv("HOME"));
  userpath += "/";
  userpath += LOCAL_BACKEND_DIRNAME;
  if (lt_dladdsearchdir(userpath.c_str())) {
    SH_DEBUG_ERROR("Could not add " + userpath + " to search dir: " << lt_dlerror());
  }

  string searchpath(SH_INSTALL_PREFIX);
  searchpath += "/lib/sh";
  if (lt_dladdsearchdir(searchpath.c_str())) {
    SH_DEBUG_ERROR("Could not add " + searchpath + " to search dir: " << lt_dlerror());
  }
#endif /* WIN32 */

  m_done_init = true;
}

void ShBackend::unbind_all_programs()
{
  while (ShContext::current()->begin_bound() != ShContext::current()->end_bound()) {
    shUnbind(ShContext::current()->begin_bound()->second);
  }
}

void ShBackend::unbind_all_backends()
{
  init();
  for (BackendMap::iterator i = m_instantiated_backends->begin();
       i != m_instantiated_backends->end(); i++) {
    i->second->unbind_all_programs();
  }
}

}
<|endoftext|>


<commit_before>/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under both the Apache 2.0 license (found in the
 *  LICENSE file in the root directory of this source tree) and the GPLv2 (found
 *  in the COPYING file in the root directory of this source tree).
 *  You may select, at your option, one of the above-listed licenses.
 */

#include <asm/unistd_64.h>

#include <boost/algorithm/string.hpp>

#include <osquery/logger.h>
#include <osquery/registry_factory.h>

#include "osquery/core/conversions.h"
#include "osquery/events/linux/auditeventpublisher.h"
#include "osquery/tables/events/linux/socket_events.h"

namespace osquery {

FLAG(bool,
     audit_allow_sockets,
     false,
     "Allow the audit publisher to install socket-related rules");

HIDDEN_FLAG(bool,
            audit_allow_unix,
            false,
            "Allow socket events to collect domain sockets");

// Depend on the external getUptime table method.
namespace tables {
extern long getUptime();
}

std::string ip4FromSaddr(const std::string& saddr, ushort offset) {
  long const result = tryTo<long>(saddr.substr(offset, 8), 16).takeOr(0l);
  return std::to_string((result & 0xff000000) >> 24) + '.' +
         std::to_string((result & 0x00ff0000) >> 16) + '.' +
         std::to_string((result & 0x0000ff00) >> 8) + '.' +
         std::to_string((result & 0x000000ff));
}

bool parseSockAddr(const std::string& saddr, Row& row, bool& unix_socket) {
  unix_socket = false;

  // The protocol is not included in the audit message.
  if (saddr[0] == '0' && saddr[1] == '2') {
    // IPv4
    row["family"] = '2';
    long const result = tryTo<long>(saddr.substr(4, 4), 16).takeOr(0l);
    row["remote_port"] = INTEGER(result);
    row["remote_address"] = ip4FromSaddr(saddr, 8);
  } else if (saddr[0] == '0' && saddr[1] == 'A') {
    // IPv6
    row["family"] = "10";
    long const result = tryTo<long>(saddr.substr(4, 4), 16).takeOr(0l);
    row["remote_port"] = INTEGER(result);
    std::string address;
    for (size_t i = 0; i < 8; ++i) {
      address += saddr.substr(16 + (i * 4), 4);
      if (i == 0 || i % 7 != 0) {
        address += ':';
      }
    }
    boost::algorithm::to_lower(address);
    row["remote_address"] = std::move(address);
  } else if (saddr[0] == '0' && saddr[1] == '1' && saddr.size() > 6) {
    unix_socket = true;

    row["family"] = '1';
    row["local_port"] = '0';
    row["remote_port"] = '0';
    off_t begin = (saddr[4] == '0' && saddr[5] == '0') ? 6 : 4;
    auto end = saddr.substr(begin).find("00");
    end = (end == std::string::npos) ? saddr.size() : end + 4;
    try {
      row["socket"] = boost::algorithm::unhex(saddr.substr(begin, end - begin));
    } catch (const boost::algorithm::hex_decode_error& e) {
      row["socket"] = "unknown";
    }
  } else {
    // No idea!
    return false;
  }
  return true;
}

REGISTER(SocketEventSubscriber, "event_subscriber", "socket_events");

Status SocketEventSubscriber::init() {
  if (!FLAGS_audit_allow_sockets) {
    return Status(1, "Subscriber disabled via configuration");
  }

  auto sc = createSubscriptionContext();
  subscribe(&SocketEventSubscriber::Callback, sc);

  return Status(0, "OK");
}

Status SocketEventSubscriber::Callback(const ECRef& ec, const SCRef& sc) {
  std::vector<Row> emitted_row_list;
  auto status = ProcessEvents(emitted_row_list, ec->audit_events);
  if (!status.ok()) {
    return status;
  }

  addBatch(emitted_row_list);
  return Status(0, "Ok");
}

Status SocketEventSubscriber::ProcessEvents(
    std::vector<Row>& emitted_row_list,
    const std::vector<AuditEvent>& event_list) noexcept {
  emitted_row_list.clear();

  emitted_row_list.reserve(event_list.size());

  for (const auto& event : event_list) {
    if (event.type != AuditEvent::Type::Syscall) {
      continue;
    }

    Row row = {};
    const auto& event_data = boost::get<SyscallAuditEventData>(event.data);

    if (event_data.syscall_number == __NR_connect) {
      row["action"] = "connect";
    } else if (event_data.syscall_number == __NR_bind) {
      row["action"] = "bind";
    } else {
      continue;
    }

    const AuditEventRecord* syscall_event_record =
        GetEventRecord(event, AUDIT_SYSCALL);
    if (syscall_event_record == nullptr) {
      VLOG(1) << "Malformed syscall event. The AUDIT_SYSCALL record "
                 "is missing";
      continue;
    }

    const AuditEventRecord* sockaddr_event_record =
        GetEventRecord(event, AUDIT_SOCKADDR);
    if (sockaddr_event_record == nullptr) {
      VLOG(1) << "Malformed syscall event. The AUDIT_SOCKADDR record "
                 "is missing";
      continue;
    }

    std::string saddr;
    GetStringFieldFromMap(saddr, sockaddr_event_record->fields, "saddr");
    if (saddr.size() < 4) {
      VLOG(1) << "Invalid saddr field in AUDIT_SOCKADDR: \"" << saddr << "\"";
      continue;
    }

    // skip operations on NETLINK_ROUTE sockets
    if (saddr[0] == '1' && saddr[1] == '0') {
      continue;
    }

    CopyFieldFromMap(row, syscall_event_record->fields, "auid");
    CopyFieldFromMap(row, syscall_event_record->fields, "pid");
    GetStringFieldFromMap(row["fd"], syscall_event_record->fields, "a0");

    row["path"] = DecodeAuditPathValues(syscall_event_record->fields.at("exe"));
    row["fd"] = syscall_event_record->fields.at("a0");
    row["success"] =
        (syscall_event_record->fields.at("success") == "yes") ? "1" : "0";
    row["uptime"] = std::to_string(tables::getUptime());

    // Set some sane defaults and then attempt to parse the sockaddr value
    row["protocol"] = '0';
    row["local_port"] = '0';
    row["remote_port"] = '0';

    bool unix_socket;
    if (!parseSockAddr(saddr, row, unix_socket)) {
      VLOG(1) << "Malformed syscall event. The saddr field in the "
                 "AUDIT_SOCKADDR record could not be parsed: \""
              << saddr << "\"";
      continue;
    }

    if (unix_socket && !FLAGS_audit_allow_unix) {
      continue;
    }

    emitted_row_list.push_back(row);
  }

  return Status(0, "Ok");
}

const std::set<int>& SocketEventSubscriber::GetSyscallSet() noexcept {
  static const std::set<int> syscall_set = {__NR_bind, __NR_connect};
  return syscall_set;
}
} // namespace osquery
<commit_msg>socket_events: Use local_port/local_address for bind() (#5098)<commit_after>/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under both the Apache 2.0 license (found in the
 *  LICENSE file in the root directory of this source tree) and the GPLv2 (found
 *  in the COPYING file in the root directory of this source tree).
 *  You may select, at your option, one of the above-listed licenses.
 */

#include <asm/unistd_64.h>

#include <boost/algorithm/string.hpp>

#include <osquery/logger.h>
#include <osquery/registry_factory.h>

#include "osquery/core/conversions.h"
#include "osquery/events/linux/auditeventpublisher.h"
#include "osquery/tables/events/linux/socket_events.h"

namespace osquery {

FLAG(bool,
     audit_allow_sockets,
     false,
     "Allow the audit publisher to install socket-related rules");

HIDDEN_FLAG(bool,
            audit_allow_unix,
            false,
            "Allow socket events to collect domain sockets");

// Depend on the external getUptime table method.
namespace tables {
extern long getUptime();
}

std::string ip4FromSaddr(const std::string& saddr, ushort offset) {
  long const result = tryTo<long>(saddr.substr(offset, 8), 16).takeOr(0l);
  return std::to_string((result & 0xff000000) >> 24) + '.' +
         std::to_string((result & 0x00ff0000) >> 16) + '.' +
         std::to_string((result & 0x0000ff00) >> 8) + '.' +
         std::to_string((result & 0x000000ff));
}

bool parseSockAddr(const std::string& saddr, Row& row, bool& unix_socket) {
  unix_socket = false;

  std::string address_column;
  std::string port_column;
  if (row["action"] == "bind") {
    address_column = "local_address";
    port_column = "local_port";

    row["remote_address"] = "0";
    row["remote_port"] = "0";
  } else {
    address_column = "remote_address";
    port_column = "remote_port";

    row["local_address"] = "0";
    row["local_port"] = "0";
  }

  // The protocol is not included in the audit message.
  if (saddr[0] == '0' && saddr[1] == '2') {
    // IPv4
    row["family"] = '2';
    long const result = tryTo<long>(saddr.substr(4, 4), 16).takeOr(0l);
    row[port_column] = INTEGER(result);
    row[address_column] = ip4FromSaddr(saddr, 8);
  } else if (saddr[0] == '0' && saddr[1] == 'A') {
    // IPv6
    row["family"] = "10";
    long const result = tryTo<long>(saddr.substr(4, 4), 16).takeOr(0l);
    row[port_column] = INTEGER(result);
    std::string address;
    for (size_t i = 0; i < 8; ++i) {
      address += saddr.substr(16 + (i * 4), 4);
      if (i == 0 || i % 7 != 0) {
        address += ':';
      }
    }
    boost::algorithm::to_lower(address);
    row[address_column] = std::move(address);
  } else if (saddr[0] == '0' && saddr[1] == '1' && saddr.size() > 6) {
    unix_socket = true;

    row["family"] = '1';
    off_t begin = (saddr[4] == '0' && saddr[5] == '0') ? 6 : 4;
    auto end = saddr.substr(begin).find("00");
    end = (end == std::string::npos) ? saddr.size() : end + 4;
    try {
      row["socket"] = boost::algorithm::unhex(saddr.substr(begin, end - begin));
    } catch (const boost::algorithm::hex_decode_error& e) {
      row["socket"] = "unknown";
    }
  } else {
    // No idea!
    return false;
  }
  return true;
}

REGISTER(SocketEventSubscriber, "event_subscriber", "socket_events");

Status SocketEventSubscriber::init() {
  if (!FLAGS_audit_allow_sockets) {
    return Status(1, "Subscriber disabled via configuration");
  }

  auto sc = createSubscriptionContext();
  subscribe(&SocketEventSubscriber::Callback, sc);

  return Status(0, "OK");
}

Status SocketEventSubscriber::Callback(const ECRef& ec, const SCRef& sc) {
  std::vector<Row> emitted_row_list;
  auto status = ProcessEvents(emitted_row_list, ec->audit_events);
  if (!status.ok()) {
    return status;
  }

  addBatch(emitted_row_list);
  return Status(0, "Ok");
}

Status SocketEventSubscriber::ProcessEvents(
    std::vector<Row>& emitted_row_list,
    const std::vector<AuditEvent>& event_list) noexcept {
  emitted_row_list.clear();

  emitted_row_list.reserve(event_list.size());

  for (const auto& event : event_list) {
    if (event.type != AuditEvent::Type::Syscall) {
      continue;
    }

    Row row = {};
    const auto& event_data = boost::get<SyscallAuditEventData>(event.data);

    if (event_data.syscall_number == __NR_connect) {
      row["action"] = "connect";
    } else if (event_data.syscall_number == __NR_bind) {
      row["action"] = "bind";
    } else {
      continue;
    }

    const AuditEventRecord* syscall_event_record =
        GetEventRecord(event, AUDIT_SYSCALL);
    if (syscall_event_record == nullptr) {
      VLOG(1) << "Malformed syscall event. The AUDIT_SYSCALL record "
                 "is missing";
      continue;
    }

    const AuditEventRecord* sockaddr_event_record =
        GetEventRecord(event, AUDIT_SOCKADDR);
    if (sockaddr_event_record == nullptr) {
      VLOG(1) << "Malformed syscall event. The AUDIT_SOCKADDR record "
                 "is missing";
      continue;
    }

    std::string saddr;
    GetStringFieldFromMap(saddr, sockaddr_event_record->fields, "saddr");
    if (saddr.size() < 4) {
      VLOG(1) << "Invalid saddr field in AUDIT_SOCKADDR: \"" << saddr << "\"";
      continue;
    }

    // skip operations on NETLINK_ROUTE sockets
    if (saddr[0] == '1' && saddr[1] == '0') {
      continue;
    }

    CopyFieldFromMap(row, syscall_event_record->fields, "auid");
    CopyFieldFromMap(row, syscall_event_record->fields, "pid");
    GetStringFieldFromMap(row["fd"], syscall_event_record->fields, "a0");

    row["path"] = DecodeAuditPathValues(syscall_event_record->fields.at("exe"));
    row["fd"] = syscall_event_record->fields.at("a0");
    row["success"] =
        (syscall_event_record->fields.at("success") == "yes") ? "1" : "0";
    row["uptime"] = std::to_string(tables::getUptime());

    // Set some sane defaults and then attempt to parse the sockaddr value
    row["protocol"] = '0';
    row["local_port"] = '0';
    row["remote_port"] = '0';

    bool unix_socket;
    if (!parseSockAddr(saddr, row, unix_socket)) {
      VLOG(1) << "Malformed syscall event. The saddr field in the "
                 "AUDIT_SOCKADDR record could not be parsed: \""
              << saddr << "\"";
      continue;
    }

    if (unix_socket && !FLAGS_audit_allow_unix) {
      continue;
    }

    emitted_row_list.push_back(row);
  }

  return Status(0, "Ok");
}

const std::set<int>& SocketEventSubscriber::GetSyscallSet() noexcept {
  static const std::set<int> syscall_set = {__NR_bind, __NR_connect};
  return syscall_set;
}
} // namespace osquery
<|endoftext|>


<commit_before>#ifndef TOKENIZER_H
#define TOKENIZER_H

#include <list>
#include <string>
#include <stdexcept>
#include <sstream>
#include <iterator>

namespace sexp_cpp
{
  class Tokenizer
  {
    public:
      std::list<std::string> Tokenize(const std::string& input)
      {
        std::string code = input;
        if(code.empty())
        {
          throw std::invalid_argument("can't tokenize empty string!");
        }

        replace(code, "(", " ( ");
        replace(code, ")", " ) ");

        std::list<std::string> list;
        std::istringstream ss(code);
        list.insert(list.end(), std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>());
        return list;
      }

    private:
      void replace(std::string& string, const std::string& from, const std::string& to)
      {
        size_t i = 0;
        size_t next = 0;
        while ((next = string.find(from, i)) != std::string::npos)
        {
          string.replace(next, from.size(), to);
          i = next + to.size();
        }
      }

  };

} // sexp_cpp

#endif // TOKENIZER_H

<commit_msg>code formating<commit_after>#ifndef TOKENIZER_H
#define TOKENIZER_H

#include <list>
#include <string>
#include <stdexcept>
#include <sstream>
#include <iterator>

namespace sexp_cpp
{
  class Tokenizer
  {
    public:
      std::list<std::string> Tokenize(const std::string& input)
      {
        std::string code = input;
        if(code.empty())
        {
          throw std::invalid_argument("can't tokenize empty string!");
        }

        replace(code, "(", " ( ");
        replace(code, ")", " ) ");

        std::list<std::string> list;
        std::istringstream ss(code);
        list.insert(list.end(),
                    std::istream_iterator<std::string>(ss),
                    std::istream_iterator<std::string>());

        return list;
      }

    private:
      void replace(std::string& string, const std::string& from, const std::string& to)
      {
        size_t i = 0;
        size_t next = 0;
        while ((next = string.find(from, i)) != std::string::npos)
        {
          string.replace(next, from.size(), to);
          i = next + to.size();
        }
      }

  };

} // sexp_cpp

#endif // TOKENIZER_H

<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <tuple>
#include <map>
#include "./TinyXML/tinyxml.h"

using namespace std;

map <string, int> instanceTypes = {{"MUUR", 1}, {"TON", 2}, {"WATER", 4}, {"DOEL", 7}};
map <string, int> instanceTypesWithId = {{"SPELER", 0}, {"MONSTER", 3}, {"POORT", 5}, {"KNOP", 6}};

bool Room::loadFromXMLFile (const char* filename) {
	// Create xml dom
	TiXmlDocument doc(filename);

	bool success = doc.LoadFile();

	REQUIRE(success, "File " + filename + " not found");

	// Get root element
	TiXmlElement* root = doc.FirstChildElement();

	REQUIRE(root != NULL, "XML Error: No root element");
	REQUIRE(string(root->Value()) == "VELD", "XML Error: Root element has to be called 'VELD' but was '" + root->Value() + "'");

	vector < vector <int>> instances;
	vector < tuple <int, int, int, string>> instancesWithId;

	// Parse all tags under the root
	for (TiXmlElement* elem = root->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement()) {
		string elemName = elem->Value();

		if (elemName == "NAAM" || elemName == "LENGTE" || elemName == "BREEDTE") this->parseRoomInfo(elem);
		if (instanceTypes.count(elemName) == 1) instances.push_back(this->parseInstance(elem));
		if (instanceTypesWithId.count(elemName) == 1) instancesWithId.push_back(this->parseInstanceWithId(elem));
	}

	// The room settings have been parsed, init room and add instances and players
	this->init();

	for (auto instance : instances) {
		this->set_instance(instance[0], instance[1], instance[2]);
	}

	for (auto instance : instancesWithId) {
		this->set_instance(get<0>(instance), get<1>(instance), get<2>(instance), get<3>(instance));
	}

	return true;
}

void Room::parseRoomInfo (TiXmlElement* elem) {
	// Get the text between the name, length and width tags
	TiXmlNode* node = elem->FirstChild();
	TiXmlText* text = node->ToText();

	string str = text->Value();
	string elemName = elem->Value();

	REQUIRE(elemName == "NAAM" || elemName == "LENGTE" || elemName == "BREEDTE", "PARSE ERROR: room info element has to be NAAM, LENGTE OR BREEDTE but was: " + elemName);

	if (elemName == "NAAM") {
		this->set_name(str);
	}

	if (elemName == "LENGTE") this->set_height(atoi(str.c_str()));
	if (elemName == "BREEDTE") this->set_width(atoi(str.c_str()));
}

vector <int> Room::parseInstance (TiXmlElement* elem) {
	string elemName = elem->Value();
	vector <int> instance;

	REQUIRE(instanceTypes.count(elemName) == 1, "PARSE ERROR: Invalid instance type. Type was: " + elemName);

	int x = 0;
	int y = 0;

	elem->Attribute("x", &x);
	elem->Attribute("y", &y);

	instance.push_back(x);
	instance.push_back(y);
	instance.push_back(instanceTypes[elemName]);

	return instance;
}

tuple <int, int, int, string> Room::parseInstanceWithId (TiXmlElement* elem) {
	string elemName = elem->Value();
	const char *id = elem->Attribute("id");
	TiXmlNode* node = elem->FirstChild();
	string name;

	REQUIRE(instanceTypesWithId.count(elemName) == 1, "PARSE ERROR: Invalid instance type. Type was: " + elemName);
	REQUIRE(id != NULL || node != NULL, "PARSE ERROR: No id in attribute or in tags for element " + elemName);

	if (id != NULL) {
		name = string(id);
	} else {
		node = node->FirstChild();
		TiXmlText* text = node->ToText();
		name = text->Value();
	}

	int x = 0;
	int y = 0;

	elem->Attribute("x", &x);
	elem->Attribute("y", &y);

	tuple <int, int, int, string> player (x, y, instanceTypesWithId[elemName], name);
	return player;
}

bool Room::loadMovesFromXMLFile(const char* filename) {
	// Create xml dom
	TiXmlDocument doc(filename);

	bool success = doc.LoadFile();
	REQUIRE(success, "File " + filename + " not found while trying to parse moves from xml file");

	// Get root element
	TiXmlElement* root = doc.FirstChildElement();

	REQUIRE(root != NULL, "XML Error: No root XML element!")
	REQUIRE(string(root->Value()) == "ACTIES" || string(root->Value()) == "BEWEGINGEN", "XML Error: Root element has to be called 'BEWEGINGEN' or 'ACTIES' but was '" + root->Value() + "'");

	// Parse the tags 'BEWEGING'
	for (TiXmlElement* elem = root->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement()) {
		string elemName = elem->Value();

		if (elemName == "BEWEGING") {
			TiXmlElement* playernameElem = elem->FirstChildElement();
			TiXmlElement* directionElem = playernameElem->NextSiblingElement();

			if (playernameElem == NULL || directionElem == NULL) {
				cerr << "XML Error: BEWEGING tags need to contain 2 tags, the first is a playername, the second a direction" << endl;
			}

			if (string(playernameElem->Value()) != "ID" || string(directionElem->Value()) != "RICHTING") {
				cerr << "XML Error: BEWEGING needs to contain a tag SPELERNAAM and a tag RICHTING but contained '" << playernameElem->Value() << "' and '" << directionElem->Value() << "'" << endl;
			}

			TiXmlNode* playernameNode = playernameElem->FirstChild();
			TiXmlNode* directionNode = directionElem->FirstChild();

			TiXmlText* playernameText = playernameNode->ToText();
			TiXmlText* directionText = directionNode->ToText();

			string playername = playernameText->Value();
			string direction = directionText->Value();

			int directionint;
			if (direction == "OMHOOG") {
				directionint = 1;
			} else if (direction == "OMLAAG") {
				directionint = 3;
			} else if (direction == "LINKS") {
				directionint = 2;
			} else if (direction == "RECHTS") {
				directionint = 0;
			} else {
				cerr << "XML ERROR: Move had wrong type, accepted: LINKS OMHOOG RECHTS OMLAAG" << endl;
				continue;
			}

			this->moves.push_back(new Move(directionint, playername, false));
		}
	}
	return true;
}<commit_msg>Add aanval<commit_after>#include <iostream>
#include <vector>
#include <tuple>
#include <map>
#include "./TinyXML/tinyxml.h"

using namespace std;

map <string, int> instanceTypes = {{"MUUR", 1}, {"TON", 2}, {"WATER", 4}, {"DOEL", 7}};
map <string, int> instanceTypesWithId = {{"SPELER", 0}, {"MONSTER", 3}, {"POORT", 5}, {"KNOP", 6}};

bool Room::loadFromXMLFile (const char* filename) {
	// Create xml dom
	TiXmlDocument doc(filename);

	bool success = doc.LoadFile();

	REQUIRE(success, "File " + filename + " not found");

	// Get root element
	TiXmlElement* root = doc.FirstChildElement();

	REQUIRE(root != NULL, "XML Error: No root element");
	REQUIRE(string(root->Value()) == "VELD", "XML Error: Root element has to be called 'VELD' but was '" + root->Value() + "'");

	vector < vector <int>> instances;
	vector < tuple <int, int, int, string>> instancesWithId;

	// Parse all tags under the root
	for (TiXmlElement* elem = root->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement()) {
		string elemName = elem->Value();

		if (elemName == "NAAM" || elemName == "LENGTE" || elemName == "BREEDTE") this->parseRoomInfo(elem);
		if (instanceTypes.count(elemName) == 1) instances.push_back(this->parseInstance(elem));
		if (instanceTypesWithId.count(elemName) == 1) instancesWithId.push_back(this->parseInstanceWithId(elem));
	}

	// The room settings have been parsed, init room and add instances and players
	this->init();

	for (auto instance : instances) {
		this->set_instance(instance[0], instance[1], instance[2]);
	}

	for (auto instance : instancesWithId) {
		this->set_instance(get<0>(instance), get<1>(instance), get<2>(instance), get<3>(instance));
	}

	return true;
}

void Room::parseRoomInfo (TiXmlElement* elem) {
	// Get the text between the name, length and width tags
	TiXmlNode* node = elem->FirstChild();
	TiXmlText* text = node->ToText();

	string str = text->Value();
	string elemName = elem->Value();

	REQUIRE(elemName == "NAAM" || elemName == "LENGTE" || elemName == "BREEDTE", "PARSE ERROR: room info element has to be NAAM, LENGTE OR BREEDTE but was: " + elemName);

	if (elemName == "NAAM") {
		this->set_name(str);
	}

	if (elemName == "LENGTE") this->set_height(atoi(str.c_str()));
	if (elemName == "BREEDTE") this->set_width(atoi(str.c_str()));
}

vector <int> Room::parseInstance (TiXmlElement* elem) {
	string elemName = elem->Value();
	vector <int> instance;

	REQUIRE(instanceTypes.count(elemName) == 1, "PARSE ERROR: Invalid instance type. Type was: " + elemName);

	int x = 0;
	int y = 0;

	elem->Attribute("x", &x);
	elem->Attribute("y", &y);

	instance.push_back(x);
	instance.push_back(y);
	instance.push_back(instanceTypes[elemName]);

	return instance;
}

tuple <int, int, int, string> Room::parseInstanceWithId (TiXmlElement* elem) {
	string elemName = elem->Value();
	const char *id = elem->Attribute("id");
	TiXmlNode* node = elem->FirstChild();
	string name;

	REQUIRE(instanceTypesWithId.count(elemName) == 1, "PARSE ERROR: Invalid instance type. Type was: " + elemName);
	REQUIRE(id != NULL || node != NULL, "PARSE ERROR: No id in attribute or in tags for element " + elemName);

	if (id != NULL) {
		name = string(id);
	} else {
		node = node->FirstChild();
		TiXmlText* text = node->ToText();
		name = text->Value();
	}

	int x = 0;
	int y = 0;

	elem->Attribute("x", &x);
	elem->Attribute("y", &y);

	tuple <int, int, int, string> player (x, y, instanceTypesWithId[elemName], name);
	return player;
}

bool Room::loadMovesFromXMLFile(const char* filename) {
	// Create xml dom
	TiXmlDocument doc(filename);

	bool success = doc.LoadFile();
	REQUIRE(success, "File " + filename + " not found while trying to parse moves from xml file");

	// Get root element
	TiXmlElement* root = doc.FirstChildElement();

	REQUIRE(root != NULL, "XML Error: No root XML element!")
	REQUIRE(string(root->Value()) == "ACTIES" || string(root->Value()) == "BEWEGINGEN", "XML Error: Root element has to be called 'BEWEGINGEN' or 'ACTIES' but was '" + root->Value() + "'");

	// Parse the tags 'BEWEGING'
	for (TiXmlElement* elem = root->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement()) {
		string elemName = elem->Value();

		if (elemName == "BEWEGING" || elemName == "AANVAL") {
			TiXmlElement* playernameElem = elem->FirstChildElement();
			TiXmlElement* directionElem = playernameElem->NextSiblingElement();

			if (playernameElem == NULL || directionElem == NULL) {
				cerr << "XML Error: BEWEGING tags need to contain 2 tags, the first is a playername, the second a direction" << endl;
			}

			if (string(playernameElem->Value()) != "ID" || string(directionElem->Value()) != "RICHTING") {
				cerr << "XML Error: BEWEGING needs to contain a tag SPELERNAAM and a tag RICHTING but contained '" << playernameElem->Value() << "' and '" << directionElem->Value() << "'" << endl;
			}

			TiXmlNode* playernameNode = playernameElem->FirstChild();
			TiXmlNode* directionNode = directionElem->FirstChild();

			TiXmlText* playernameText = playernameNode->ToText();
			TiXmlText* directionText = directionNode->ToText();

			string playername = playernameText->Value();
			string direction = directionText->Value();

			int directionint;
			if (direction == "OMHOOG") {
				directionint = 1;
			} else if (direction == "OMLAAG") {
				directionint = 3;
			} else if (direction == "LINKS") {
				directionint = 2;
			} else if (direction == "RECHTS") {
				directionint = 0;
			} else {
				cerr << "XML ERROR: Move had wrong type, accepted: LINKS OMHOOG RECHTS OMLAAG" << endl;
				continue;
			}

			this->moves.push_back(new Move(directionint, playername, elemName == "AANVAL"));
		}
	}
	return true;
}<|endoftext|>


<commit_before>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *
 */

#include "aalang_cpp.hh"
#include "helper.hh"

aalang_cpp::aalang_cpp(): aalang(),action_cnt(1), tag_cnt(1), name_cnt(0),
			  istate(NULL), name(NULL), tag(false)
{
  default_guard="return true;";
  default_body="";
  default_adapter="";
  std::vector<std::string> t;
  aname.push_back(t);
  tname.push_back(t);
  amap.push_back(0);
  tmap.push_back(0);
  anames.push_back(default_body);
}

aalang_cpp::~aalang_cpp()
{
  delete istate;
  delete name;
}

void aalang_cpp::set_starter(std::string* st)
{
  s+=*st;
  delete st;
}

void aalang_cpp::set_name(std::string* name)
{
  s+="\n//action"+to_string(action_cnt)+": \""+*name+"\"\n";
  anames.push_back(*name);
  aname.back().push_back(*name);
  delete name;
  amap.push_back(action_cnt);
  name_cnt++;
}

void aalang_cpp::set_namestr(std::string* _name)
{
  name=_name;
  s+="#include \"aal.hh\"\n\n";
  s+="class _gen_"+*name+":public aal {\nprivate:\n\t";
}

void aalang_cpp::set_variables(std::string* var)
{
  s+="//variables\n"+*var+"\n";
  delete var;
}

void aalang_cpp::set_istate(std::string* ist)
{
  istate=ist;
}

void aalang_cpp::set_push(std::string* p)
{
  push=*p;
  delete p;
}

void aalang_cpp::set_pop(std::string* p)
{
  pop=*p;
  delete p;
}

void aalang_cpp::set_tagname(std::string* name)
{
  s+="\n//tag"+to_string(tag_cnt)+": \""+*name+"\"\n";
  tname.back().push_back(*name);
  delete name;
  tmap.push_back(tag_cnt);
  name_cnt++;
  tag=true;
}

void aalang_cpp::next_tag()
{
  std::vector<std::string> t;
  tname.push_back(t);
  tag_cnt+=name_cnt;
  name_cnt=0;
  tag=false;
}

void aalang_cpp::set_guard(std::string* gua)
{
  if (tag) {
    s+="bool tag"+to_string(tag_cnt)+"_guard() {\n"+
      *gua+"}\n";
  } else {
    s+="bool action"+to_string(action_cnt)+"_guard() {\n"+
      *gua+"}\n";
  }
  if (gua!=&default_guard)
    delete gua;
}

void aalang_cpp::set_body(std::string* bod)
{
  s+="void action"+to_string(action_cnt)+"_body() {\n"+*bod+"}\n";
  if (bod!=&default_body)
    delete bod;
}

void aalang_cpp::set_adapter(std::string* ada)
{
  s+="int action" + to_string(action_cnt) + "_adapter() {\n" +
      *ada + "\n"
      "\treturn " + to_string(action_cnt) + ";\n"
      "}\n";
  if (ada!=&default_adapter)
      delete ada;
}

void aalang_cpp::next_action()
{
  std::vector<std::string> t;
  aname.push_back(t);
  action_cnt+=name_cnt;
  name_cnt=0;
}

std::string aalang_cpp::stringify()
{

  s=s+
    "\npublic:\n"
    "\t_gen_"+*name+"(Log& l, std::string& params): aal(l, params) {\n\taction_names.push_back(\"\");\n";

  for(std::list<std::vector<std::string> >::iterator i=aname.begin();i!=aname.end();i++) {
    for(std::vector<std::string>::iterator j=i->begin();j!=i->end();j++) {
      s+="\taction_names.push_back(\""+*j+"\");\n";
    }
  }
  s=s+"\ttag_names.push_back(\"\");\n";

  for(std::list<std::vector<std::string> >::iterator i=tname.begin();i!=tname.end();i++) {
    for(std::vector<std::string>::iterator j=i->begin();j!=i->end();j++) {
      s+="\ttag_names.push_back(\""+*j+"\");\n";
    }
  }

  s+=*istate+"}\n"
    "virtual bool reset() {\n"+
    *istate +
    "return true;\n}\n\n";

  if (pop!="") {
    s=s+"\nvirtual void pop(){\n"+pop+"\n}\n";
    s=s+"\nvirtual void push(){\n"+push+"\n}\n";
  }

  s=s+"virtual int observe(std::vector<int>&action, bool block){\n"
    "\taction.clear();\n"
    "\tdo {\n";

  int obsa=0;

  for(int i=1;i<action_cnt;i++) {
    if (anames[i][0]=='o') {
      obsa++;
      s=s+"\tr=action"+to_string(amap[i])+"_adapter();\n"
	"\tif (r) { action.push_back(r); return 1;}\n";
    }
  }
  if (!obsa) {
    s=s+"\treturn SILENCE;\n";
  }
  s=s+"\t} while(block);"
    "\treturn 0;\n"
    "}\n";

  s=s+"virtual int adapter_execute(int action) {\n"
    "\tswitch(action) {\n";

  for(int i=1;i<action_cnt;i++) {
    if (anames[i][0]=='i') {
      s+="\t\tcase "+to_string(i)+":\n"
	"\t\treturn action"+to_string(amap[i])+
	"_adapter();\n\t\tbreak;\n";
    }
  }
  s=s+"\t\tdefault:\n"
    "\t\treturn 0;\n"
    "\t};\n"
    "}\n"
    "virtual int model_execute(int action) {\n"
    "\tswitch(action) {\n";

  for(int i=1;i<action_cnt;i++) {
    s+="\t\tcase "+to_string(i)+":\n"
      "\t\taction"+to_string(amap[i])+"_body();\n\t\treturn "+
      to_string(i)+";\n\t\tbreak;\n";
  }
  s=s+"\t\tdefault:\n"
    "\t\treturn 0;\n"
    "\t};\n"
    "}\n"
    "virtual int getActions(int** act) {\n"
    "actions.clear();\n";

  for(int i=1;i<action_cnt;i++) {
    s+="\tif (action"+to_string(amap[i])+"_guard()) {\n"
      "\t\tactions.push_back("+to_string(i)+");\n"
      "\t}\n";
  }
  s=s+"\t*act = &actions[0];\n"
    "\treturn actions.size();\n"
    "}\n";

  s=s+"virtual int getprops(int** props) {\n"
    "tags.clear();\n";

  for(int i=1;i<tag_cnt;i++) {
    s+="\tif (tag"+to_string(tmap[i])+"_guard()) {\n"
      "\t\ttags.push_back("+to_string(i)+");\n"
      "\t}\n";
  }
  s=s+"\t*props = &tags[0];\n"
    "\treturn tags.size();\n"
    "}\n"
    "};\n";

  factory_register();

  return s;
}

void aalang_cpp::factory_register()
{
  s=s+"  /* factory register */\n\n"
    "namespace {\n"
    "static aal* a=NULL;\n\n"
    "Model* model_creator(Log&l, std::string params) {\n"
    "\tif (!a) {\n"
    "\t  a=new _gen_"+*name+"(l, params);\n"
    "\t}\n"
    "\treturn new Mwrapper(l,params,a);\n"
    "}\n\n"
    "static ModelFactory::Register me1(\""+*name+"\", model_creator);\n\n"
    "Adapter* adapter_creator(Log&l, std::string params = \"\")\n"
    "{\n"
    "\tif (!a) {\n"
    "\t  a=new _gen_"+*name+"(l, params);\n"
    "\t}\n"
    "\treturn new Awrapper(l,params,a);\n"
    "}\n"
    "static AdapterFactory::Register me2(\""+*name+"\", adapter_creator);\n"+
    "}\n";
}
<commit_msg>fix observe<commit_after>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *
 */

#include "aalang_cpp.hh"
#include "helper.hh"

aalang_cpp::aalang_cpp(): aalang(),action_cnt(1), tag_cnt(1), name_cnt(0),
			  istate(NULL), name(NULL), tag(false)
{
  default_guard="return true;";
  default_body="";
  default_adapter="";
  std::vector<std::string> t;
  aname.push_back(t);
  tname.push_back(t);
  amap.push_back(0);
  tmap.push_back(0);
  anames.push_back(default_body);
}

aalang_cpp::~aalang_cpp()
{
  delete istate;
  delete name;
}

void aalang_cpp::set_starter(std::string* st)
{
  s+=*st;
  delete st;
}

void aalang_cpp::set_name(std::string* name)
{
  s+="\n//action"+to_string(action_cnt)+": \""+*name+"\"\n";
  anames.push_back(*name);
  aname.back().push_back(*name);
  delete name;
  amap.push_back(action_cnt);
  name_cnt++;
}

void aalang_cpp::set_namestr(std::string* _name)
{
  name=_name;
  s+="#include \"aal.hh\"\n\n";
  s+="class _gen_"+*name+":public aal {\nprivate:\n\t";
}

void aalang_cpp::set_variables(std::string* var)
{
  s+="//variables\n"+*var+"\n";
  delete var;
}

void aalang_cpp::set_istate(std::string* ist)
{
  istate=ist;
}

void aalang_cpp::set_push(std::string* p)
{
  push=*p;
  delete p;
}

void aalang_cpp::set_pop(std::string* p)
{
  pop=*p;
  delete p;
}

void aalang_cpp::set_tagname(std::string* name)
{
  s+="\n//tag"+to_string(tag_cnt)+": \""+*name+"\"\n";
  tname.back().push_back(*name);
  delete name;
  tmap.push_back(tag_cnt);
  name_cnt++;
  tag=true;
}

void aalang_cpp::next_tag()
{
  std::vector<std::string> t;
  tname.push_back(t);
  tag_cnt+=name_cnt;
  name_cnt=0;
  tag=false;
}

void aalang_cpp::set_guard(std::string* gua)
{
  if (tag) {
    s+="bool tag"+to_string(tag_cnt)+"_guard() {\n"+
      *gua+"}\n";
  } else {
    s+="bool action"+to_string(action_cnt)+"_guard() {\n"+
      *gua+"}\n";
  }
  if (gua!=&default_guard)
    delete gua;
}

void aalang_cpp::set_body(std::string* bod)
{
  s+="void action"+to_string(action_cnt)+"_body() {\n"+*bod+"}\n";
  if (bod!=&default_body)
    delete bod;
}

void aalang_cpp::set_adapter(std::string* ada)
{
  s+="int action" + to_string(action_cnt) + "_adapter() {\n" +
      *ada + "\n"
      "\treturn " + to_string(action_cnt) + ";\n"
      "}\n";
  if (ada!=&default_adapter)
      delete ada;
}

void aalang_cpp::next_action()
{
  std::vector<std::string> t;
  aname.push_back(t);
  action_cnt+=name_cnt;
  name_cnt=0;
}

std::string aalang_cpp::stringify()
{

  s=s+
    "\npublic:\n"
    "\t_gen_"+*name+"(Log& l, std::string& params): aal(l, params) {\n\taction_names.push_back(\"\");\n";

  for(std::list<std::vector<std::string> >::iterator i=aname.begin();i!=aname.end();i++) {
    for(std::vector<std::string>::iterator j=i->begin();j!=i->end();j++) {
      s+="\taction_names.push_back(\""+*j+"\");\n";
    }
  }
  s=s+"\ttag_names.push_back(\"\");\n";

  for(std::list<std::vector<std::string> >::iterator i=tname.begin();i!=tname.end();i++) {
    for(std::vector<std::string>::iterator j=i->begin();j!=i->end();j++) {
      s+="\ttag_names.push_back(\""+*j+"\");\n";
    }
  }

  s+=*istate+"}\n"
    "virtual bool reset() {\n"+
    *istate +
    "return true;\n}\n\n";

  if (pop!="") {
    s=s+"\nvirtual void pop(){\n"+pop+"\n}\n";
    s=s+"\nvirtual void push(){\n"+push+"\n}\n";
  }

  s=s+"virtual int observe(std::vector<int>&action, bool block){\n"
    "\taction.clear();\n"
    "\tdo {\n"
    "\tint r;\n";

  int obsa=0;

  for(int i=1;i<action_cnt;i++) {
    if (anames[i][0]=='o') {
      obsa++;
      s=s+"\tr=action"+to_string(amap[i])+"_adapter();\n"
	"\tif (r) { action.push_back(r); return 1;}\n";
    }
  }
  if (!obsa) {
    s=s+"\treturn SILENCE;\n";
  }
  s=s+"\t} while(block);"
    "\treturn 0;\n"
    "}\n";

  s=s+"virtual int adapter_execute(int action) {\n"
    "\tswitch(action) {\n";

  for(int i=1;i<action_cnt;i++) {
    if (anames[i][0]=='i') {
      s+="\t\tcase "+to_string(i)+":\n"
	"\t\treturn action"+to_string(amap[i])+
	"_adapter();\n\t\tbreak;\n";
    }
  }
  s=s+"\t\tdefault:\n"
    "\t\treturn 0;\n"
    "\t};\n"
    "}\n"
    "virtual int model_execute(int action) {\n"
    "\tswitch(action) {\n";

  for(int i=1;i<action_cnt;i++) {
    s+="\t\tcase "+to_string(i)+":\n"
      "\t\taction"+to_string(amap[i])+"_body();\n\t\treturn "+
      to_string(i)+";\n\t\tbreak;\n";
  }
  s=s+"\t\tdefault:\n"
    "\t\treturn 0;\n"
    "\t};\n"
    "}\n"
    "virtual int getActions(int** act) {\n"
    "actions.clear();\n";

  for(int i=1;i<action_cnt;i++) {
    s+="\tif (action"+to_string(amap[i])+"_guard()) {\n"
      "\t\tactions.push_back("+to_string(i)+");\n"
      "\t}\n";
  }
  s=s+"\t*act = &actions[0];\n"
    "\treturn actions.size();\n"
    "}\n";

  s=s+"virtual int getprops(int** props) {\n"
    "tags.clear();\n";

  for(int i=1;i<tag_cnt;i++) {
    s+="\tif (tag"+to_string(tmap[i])+"_guard()) {\n"
      "\t\ttags.push_back("+to_string(i)+");\n"
      "\t}\n";
  }
  s=s+"\t*props = &tags[0];\n"
    "\treturn tags.size();\n"
    "}\n"
    "};\n";

  factory_register();

  return s;
}

void aalang_cpp::factory_register()
{
  s=s+"  /* factory register */\n\n"
    "namespace {\n"
    "static aal* a=NULL;\n\n"
    "Model* model_creator(Log&l, std::string params) {\n"
    "\tif (!a) {\n"
    "\t  a=new _gen_"+*name+"(l, params);\n"
    "\t}\n"
    "\treturn new Mwrapper(l,params,a);\n"
    "}\n\n"
    "static ModelFactory::Register me1(\""+*name+"\", model_creator);\n\n"
    "Adapter* adapter_creator(Log&l, std::string params = \"\")\n"
    "{\n"
    "\tif (!a) {\n"
    "\t  a=new _gen_"+*name+"(l, params);\n"
    "\t}\n"
    "\treturn new Awrapper(l,params,a);\n"
    "}\n"
    "static AdapterFactory::Register me2(\""+*name+"\", adapter_creator);\n"+
    "}\n";
}
<|endoftext|>