<commit_before>#include "Halide.h"
#include <cstdlib>
#include <chrono>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include "configure.h"
#include "fused_resnet_block_generator_tiramisu.o.h"
#include <tiramisu/utils.h>
using namespace std;

bool compareFiles(const std::string &p1, const std::string &p2)
{
    std::ifstream f1(p1, std::ifstream::binary | std::ifstream::ate);
    std::ifstream f2(p2, std::ifstream::binary | std::ifstream::ate);

    if (f1.fail() || f2.fail())
    {
        return false; //File problem
    }

    if (f1.tellg() != f2.tellg())
    {
        return false; //Size mismatch
    }

    //Seek back to beginning and use std::equal to compare contents
    f1.seekg(0, std::ifstream::beg);
    f2.seekg(0, std::ifstream::beg);
    return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
                      std::istreambuf_iterator<char>(),
                      std::istreambuf_iterator<char>(f2.rdbuf()));
}

int main(int, char **)
{
    Halide::Buffer<int> parameters(2);

    Halide::Buffer<double> input(N, N, 3, BATCH_SIZE);
    Halide::Buffer<double> filter1(3, 3, 3, 64);
    Halide::Buffer<double> filter2(3, 3, 64, 64);
    Halide::Buffer<double> padd1(N + 2, N + 2, 3, BATCH_SIZE);
    Halide::Buffer<double> conv1(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> padd2(N + 2, N + 2, 64, BATCH_SIZE);
    Halide::Buffer<double> conv2(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> bn1(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> bn2(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> mean(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> variance(N, N, 64, BATCH_SIZE);

    std::vector<std::chrono::duration<double, std::milli>> duration_vector;
    srand(1);
    for (int n = 0; n < BATCH_SIZE; ++n)
        for (int z = 0; z < 3; ++z)
            for (int y = 0; y < N; ++y)
                for (int x = 0; x < N; ++x)
                    input(x, y, z, n) = rand() % 1000;

    for (int x = 0; x < 3; ++x)
        for (int y = 0; y < 3; ++y)
            for (int z = 0; z < 3; ++z)
                for (int q = 0; q < 64; ++q)
                    filter1(x, y, z, q) = 1;

    for (int x = 0; x < 3; ++x)
        for (int y = 0; y < 3; ++y)
            for (int z = 0; z < 64; ++z)
                for (int q = 0; q < 64; ++q)
                    filter2(x, y, z, q) = 1;

    std::cout << "\t\tBuffers initialized" << std::endl;

    // Initialize parameters[]
    parameters(0) = N;
    parameters(1) = BATCH_SIZE;

    for (int i = 0; i < NB_TESTS; i++)
    {
        auto start1 = std::chrono::high_resolution_clock::now();
        fused_resnet_block(parameters.raw_buffer(), filter1.raw_buffer(),
                           filter2.raw_buffer(), input.raw_buffer(), padd1.raw_buffer(),
                           conv1.raw_buffer(), mean.raw_buffer(), variance.raw_buffer(),
                           bn1.raw_buffer(), padd2.raw_buffer(), conv2.raw_buffer(), bn2.raw_buffer());
        auto end1 = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> duration = end1 - start1;
        duration_vector.push_back(duration);
    }
    std::cout << "\t\tTiramisu convolution duration"
              << ": " << median(duration_vector) << "; " << std::endl;

    std::ofstream resultfile;
    resultfile.open("tiramisu_result.txt");

    for (int n = 0; n < BATCH_SIZE; ++n)
        for (int z = 0; z < 64; ++z)
            for (int y = 0; y < N; ++y)
                for (int x = 0; x < N; ++x)
                    resultfile << fixed << setprecision(2) << (float)((int)(bn2(x, y, z, n) * 1000) / 1000.0);
    resultfile.close();

    std::cout << "\t\t Result"
              << ":\n\n";

    FILE *fp1, *fp2;
    char line1[5], line2[5];

    float file_count = 0, corr = 0;
    fp1 = fopen("tiramisu_result.txt", "r");
    fp2 = fopen("mkldnn_result.txt", "r");

    while (!feof(fp1))
    {
        fgets(line1, sizeof(line1), fp1);
        fgets(line2, sizeof(line2), fp2);
        file_count += 1;
        if (strcmp(line1, line2) == 0)
            corr += 1;
    }
    fclose(fp1);
    fclose(fp2);

    printf("\t\t Percentage of correctness %f \n\n", corr / file_count * 100);

    return 0;
}
<commit_msg>Correctness test modifed<commit_after>#include "Halide.h"
#include <cstdlib>
#include <chrono>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include "configure.h"
#include "fused_resnet_block_generator_tiramisu.o.h"
#include <tiramisu/utils.h>
using namespace std;

bool compareFiles(const std::string &p1, const std::string &p2)
{
    std::ifstream f1(p1, std::ifstream::binary | std::ifstream::ate);
    std::ifstream f2(p2, std::ifstream::binary | std::ifstream::ate);

    if (f1.fail() || f2.fail())
    {
        return false; //File problem
    }

    if (f1.tellg() != f2.tellg())
    {
        return false; //Size mismatch
    }

    //Seek back to beginning and use std::equal to compare contents
    f1.seekg(0, std::ifstream::beg);
    f2.seekg(0, std::ifstream::beg);
    return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
                      std::istreambuf_iterator<char>(),
                      std::istreambuf_iterator<char>(f2.rdbuf()));
}

int main(int, char **)
{
    Halide::Buffer<int> parameters(2);

    Halide::Buffer<double> input(N, N, 3, BATCH_SIZE);
    Halide::Buffer<double> filter1(3, 3, 3, 64);
    Halide::Buffer<double> filter2(3, 3, 64, 64);
    Halide::Buffer<double> padd1(N + 2, N + 2, 3, BATCH_SIZE);
    Halide::Buffer<double> conv1(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> padd2(N + 2, N + 2, 64, BATCH_SIZE);
    Halide::Buffer<double> conv2(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> bn1(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> bn2(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> mean(N, N, 64, BATCH_SIZE);
    Halide::Buffer<double> variance(N, N, 64, BATCH_SIZE);

    std::vector<std::chrono::duration<double, std::milli>> duration_vector;
    srand(1);
    for (int n = 0; n < BATCH_SIZE; ++n)
        for (int z = 0; z < 3; ++z)
            for (int y = 0; y < N; ++y)
                for (int x = 0; x < N; ++x)
                    input(x, y, z, n) = rand() % 1000;

    for (int x = 0; x < 3; ++x)
        for (int y = 0; y < 3; ++y)
            for (int z = 0; z < 3; ++z)
                for (int q = 0; q < 64; ++q)
                    filter1(x, y, z, q) = 1;

    for (int x = 0; x < 3; ++x)
        for (int y = 0; y < 3; ++y)
            for (int z = 0; z < 64; ++z)
                for (int q = 0; q < 64; ++q)
                    filter2(x, y, z, q) = 1;

    std::cout << "\t\tBuffers initialized" << std::endl;

    // Initialize parameters[]
    parameters(0) = N;
    parameters(1) = BATCH_SIZE;

    for (int i = 0; i < NB_TESTS; i++)
    {
        auto start1 = std::chrono::high_resolution_clock::now();
        fused_resnet_block(parameters.raw_buffer(), filter1.raw_buffer(),
                           filter2.raw_buffer(), input.raw_buffer(), padd1.raw_buffer(),
                           conv1.raw_buffer(), mean.raw_buffer(), variance.raw_buffer(),
                           bn1.raw_buffer(), padd2.raw_buffer(), conv2.raw_buffer(), bn2.raw_buffer());
        auto end1 = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> duration = end1 - start1;
        duration_vector.push_back(duration);
    }
    std::cout << "\t\tTiramisu convolution duration"
              << ": " << median(duration_vector) << "; " << std::endl;

    std::ofstream resultfile;
    resultfile.open("tiramisu_result.txt");

    for (int n = 0; n < BATCH_SIZE; ++n)
        for (int z = 0; z < 64; ++z)
            for (int y = 0; y < N; ++y)
                for (int x = 0; x < N; ++x)
                {
                    resultfile << fixed << setprecision(2) << (float)((int)(bn2(x, y, z, n) * 1000) / 1000.0);
                    resultfile << "\n";
                }
    resultfile.close();

    std::cout << "\t\t Result"
              << ":\n\n";

    std::ifstream infile1("tiramisu_result.txt"), infile2("mkldnn_result.txt");
    std::string line1, line2;
    float file_count = 0, corr = 0, f1, f2;

    while (std::getline(infile1, line1))
    {
        std::getline(infile2, line2);
        file_count += 1;
        f1 = std::stof(line1);
        f2 = std::stof(line2);

        if (f1 - f2 <= 0.01)
            corr += 1;
    }

    printf("\t\t Percentage of correctness %f \n\n", corr / file_count * 100);

    return 0;
}
<|endoftext|>


<commit_before>#include <aleph/math/SymmetricMatrix.hh>

#include <aleph/persistenceDiagrams/Norms.hh>
#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>

#include <aleph/persistentHomology/Calculation.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <aleph/topology/io/BipartiteAdjacencyMatrix.hh>

#include <algorithm>
#include <chrono>
#include <iostream>
#include <limits>
#include <random>
#include <stdexcept>
#include <unordered_map>
#include <vector>

#include <getopt.h>

// These declarations should remain global because we have to refer to
// them in utility functions that are living outside of `main()`.
using DataType           = double;
using VertexType         = unsigned short;
using Simplex            = aleph::topology::Simplex<DataType, VertexType>;
using SimplicialComplex  = aleph::topology::SimplicialComplex<Simplex>;
using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;
using Point              = typename PersistenceDiagram::Point;

PersistenceDiagram merge( const PersistenceDiagram& D, const PersistenceDiagram& E )
{
  PersistenceDiagram F;

  if( D.dimension() != F.dimension() )
    throw std::runtime_error( "Persistence diagram dimensions have to agree" );

  for( auto&& diagram : { D, E } )
    for( auto&& p : diagram )
      F.add( p.x(), p.y() );

  return F;
}

template
<
  class Engine,       // random engine to use for weight generation (e.g. std::default_random_engine)
  class Distribution  // distribution to use for weight generation (e.g. std::uniform_real_distribution)
>
SimplicialComplex makeRandomStratifiedGraph(
  const std::vector<unsigned>& strata,
  Engine& engine,
  Distribution& distribution
)
{
  auto n = strata.size();

  if( n <= 1 )
    throw std::runtime_error( "Invalid number of strata" );

  std::vector<Simplex> simplices;

  // Create vertices ---------------------------------------------------
  //
  // The `strata` vector contains the size of each stratum, so we just
  // have to add the correct number of vertices here.

  VertexType index = VertexType(0);
  for( auto&& stratum : strata )
  {
    for( unsigned i = 0; i < stratum; i++ )
      simplices.push_back( Simplex( index++ ) );
  }

  // Create edges ------------------------------------------------------
  //
  // Every stratum is connected to every other stratum, but there are no
  // connections *within* a given stratum.

  VertexType offset = VertexType(0);
  for( decltype(n) i = 0; i < n - 1; i++ )
  {
    // All vertices in the next stratum start with this offset to their
    // indices. It depends on the sum of all vertices in *all* previous
    // strata.
    offset += strata[i];

    for( unsigned j = 0; j < strata[i]; j++ )
    {
      for( unsigned k = 0; k < strata[i+1]; k++ )
      {
        simplices.push_back(
          Simplex(
            {
              VertexType( offset - strata[i] + j ),
              VertexType( offset             + k )
            },
            distribution( engine )
          )
        );
      }
    }
  }

  return SimplicialComplex( simplices.begin(), simplices.end() );
}

SimplicialComplex applyFiltration( const SimplicialComplex& K,
                                   const std::string& strategy,
                                   bool reverse = false )
{
  auto L = K;

  if( strategy == "standard" )
  {
    if( reverse )
    {
      L.sort(
        aleph::topology::filtrations::Data<Simplex, std::greater<DataType> >()
      );
    }
    else
    {
      L.sort(
        aleph::topology::filtrations::Data<Simplex, std::less<DataType> >()
      );
    }
  }
  else if( strategy == "absolute" )
  {
    if( reverse )
    {
      auto functor = [] ( const Simplex& s, const Simplex& t )
      {
        auto w1 = s.data();
        auto w2 = t.data();

        if( std::abs( w1 ) > std::abs( w2 ) )
          return true;
        else if( std::abs( w1 ) == std::abs( w2 ) )
        {
          // This amounts to saying that w1 is positive and w2 is
          // negative.
          if( w1 > w2 )
            return true;
          else
          {
            if( s.dimension() < t.dimension() )
              return true;

            // Absolute value is equal, signed value is equal, and the
            // dimension is equal. We thus have to fall back to merely
            // using the lexicographical order.
            else
              return s < t;
          }
        }

        return false;
      };

      L.sort( functor );
    }
    else
    {
      auto functor = [] ( const Simplex& s, const Simplex& t )
      {
        auto w1 = s.data();
        auto w2 = t.data();

        if( std::abs( w1 ) < std::abs( w2 ) )
          return true;
        else if( std::abs( w1 ) == std::abs( w2 ) )
        {
          // This amounts to saying that w1 is negative and w2 is
          // positive.
          if( w1 < w2 )
            return true;
          else
          {
            if( s.dimension() < t.dimension() )
              return true;

            // Absolute value is equal, signed value is equal, and the
            // dimension is equal. We thus have to fall back to merely
            // using the lexicographical order.
            else
              return s < t;
          }
        }

        return false;
      };

      L.sort( functor );
    }
  }

  return L;
}

SimplicialComplex assignVertexWeights( const SimplicialComplex& K,
                                       const std::string& strategy,
                                       bool reverse = false )
{
  DataType minData = std::numeric_limits<DataType>::max();
  DataType maxData = std::numeric_limits<DataType>::lowest();

  for( auto&& s : K )
  {
    if( s.dimension() != 1 )
      continue;

    minData = std::min( minData, s.data() );
    maxData = std::max( maxData, s.data() );
  }

  // Setting up the weights --------------------------------------------
  //
  // This function assumes that the simplicial complex is already in
  // filtration ordering with respect to its weights. Hence, we only
  // have to take the *first* weight that we encounter (when using a
  // global vertex weight assignment) or the *extremal* value, which
  // is either a minimum or a maximum depending on the direction.

  std::unordered_map<VertexType, DataType> weight;

  for( auto&& s : K )
  {
    if( s.dimension() != 1 )
      continue;

    auto u     = s[0];
    auto v     = s[1];
    DataType w = DataType(); // weight to assign; depends on filtration

    // Assign the global minimum or maximum. This is rather wasteful
    // because the values do not change, but at least the code makes
    // it clear that all updates are done in the same place.
    if( strategy == "global" )
      w = reverse ? maxData : minData;
    else if( strategy == "local" )
      w = s.data();
    else
      throw std::runtime_error( "Unknown update strategy '" + strategy + "'" );

    // This only performs the update *once*.
    weight.insert( {u,w} );
    weight.insert( {v,w} );
  }

  // Assign the weights ------------------------------------------------
  //
  // Having set up the map of weights, we now only need to traverse it
  // in order to assign weights afterwards.

  auto L = K;

  for( auto it = L.begin(); it != L.end(); ++it )
  {
    if( it->dimension() == 0 )
    {
      auto s = *it;  // simplex
      auto v = s[0]; // vertex

      s.setData( weight.at(v) );

      auto result = L.replace( it, s );
      if( !result )
        throw std::runtime_error( "Unable to replace simplex in simplicial complex" );
    }
  }

  return L;
}

template <class Reader> std::vector<SimplicialComplex> loadSimplicialComplexes( int argc, char** argv )
{
  Reader reader;

  std::vector<SimplicialComplex> simplicialComplexes;
  simplicialComplexes.reserve( static_cast<std::size_t>( argc - optind ) );

  for( int i = optind; i < argc; i++ )
  {
    auto filename = std::string( argv[i] );

    std::cerr << "* Processing " << filename << "...";

    SimplicialComplex K;
    reader( filename, K );

    std::cerr << "finished\n";

    simplicialComplexes.emplace_back( K );
  }

  return simplicialComplexes;
}

int main( int argc, char** argv )
{
  bool bipartite             = false;
  bool normalize             = false;
  bool reverse               = false;
  bool verbose               = false;
  bool calculateDiagrams     = false;

  // The default filtration sorts simplices by their weights. Negative
  // weights are treated as being less relevant than positive ones.
  std::string filtration = "standard";

  // Defines how the minimum value for the vertices is to be set. Valid
  // options include:
  //
  //  - global    (uses the global extremal value)
  //  - local     (uses the local  extremal value over all neighbours)
  std::string weights = "global";

  {
    static option commandLineOptions[] =
    {
      { "bipartite"           , no_argument,       nullptr, 'b' },
      { "normalize"           , no_argument,       nullptr, 'n' },
      { "persistence-diagrams", no_argument,       nullptr, 'p' },
      { "reverse"             , no_argument,       nullptr, 'r' },
      { "verbose"             , no_argument,       nullptr, 'v' },
      { "filtration"          , required_argument, nullptr, 'f' },
      { "weights"             , required_argument, nullptr, 'w' },
      { nullptr               , 0                , nullptr,  0  }
    };

    int option = 0;
    while( ( option = getopt_long( argc, argv, "bnprtvf:w:", commandLineOptions, nullptr ) ) != -1 )
    {
      switch( option )
      {
      case 'b':
        bipartite = true;
        break;
      case 'f':
        filtration = optarg;
        break;
      case 'n':
        normalize = true;
        break;
      case 'p':
        calculateDiagrams = true;
        break;
      case 'r':
        reverse = true;
        break;
      case 'v':
        verbose = true;
        break;
      case 'w':
        weights = optarg;
        break;
      default:
        break;
      }
    }

    // Check filtration validity ---------------------------------------

    if(    filtration != "absolute"
        && filtration != "standard" )
    {
      std::cerr << "* Invalid filtration value '" << filtration << "', so falling back to standard one\n";
      filtration = "standard";
    }

    // Check validity of weight strategy -------------------------------

    if(    weights != "global"
        && weights != "local" )
    {
      std::cerr << "* Invalid weight strategy value '" << weights << "', so falling back to global one\n";
      weights = "global";
    }
  }

  // Be verbose about parameters ---------------------------------------

  if( bipartite )
    std::cerr << "* Mode: reading bipartite adjacency matrices\n";
  else
    std::cerr << "* Mode: reading edge lists\n";

  std::cerr << "* Filtration: " << filtration
            << " (" << ( reverse ? "" : "not " ) << "reversed" << ")\n"
            << "* Vertex weight assignment strategy: " << weights << "\n";

  if( verbose )
    std::cerr << "* Verbose output\n";

  // 1. Read simplicial complexes --------------------------------------

  std::vector<SimplicialComplex> simplicialComplexes;
  simplicialComplexes.reserve( static_cast<unsigned>( argc - optind - 1 ) );

  std::vector<DataType> minData;
  std::vector<DataType> maxData;

  minData.reserve( simplicialComplexes.size() );
  maxData.reserve( simplicialComplexes.size() );

  if( argc - optind >= 1 )
  {
    if( bipartite )
    {
      using Reader = aleph::topology::io::BipartiteAdjacencyMatrixReader;

      simplicialComplexes
        = loadSimplicialComplexes<Reader>( argc, argv );
    }
  }
  else
  {
    std::default_random_engine engine;
    engine.seed(
      static_cast<unsigned>(
        std::chrono::system_clock::now().time_since_epoch().count()
      )
    );

    DataType minWeight = DataType(-1);
    DataType maxWeight = DataType( 1);

    std::uniform_real_distribution<DataType> distribution(
      minWeight,
      std::nextafter( maxWeight, std::numeric_limits<DataType>::max() )
    );

    for( unsigned i = 0; i < 1e5; i++ )
    {
      auto K
        = makeRandomStratifiedGraph( {2,3}, // FIXME: {2,3,1} for the complete network
                                     engine,
                                     distribution
      );

      simplicialComplexes.emplace_back( K );
    }
  }

  // Determine minimum and maximum values for each complex -------------

  for( auto&& K : simplicialComplexes )
  {
    DataType minData_ = std::numeric_limits<DataType>::max();
    DataType maxData_ = std::numeric_limits<DataType>::lowest();

    // *Always* determine minimum and maximum weights so that we may
    // report them later on. They are only used for normalization in
    // the persistence diagram calculation step.
    for( auto&& s : K )
    {
      minData_ = std::min( minData_, s.data() );
      maxData_ = std::max( maxData_, s.data() );
    }

    minData.push_back( minData_ );
    maxData.push_back( maxData_ );
  }

  // Establish filtration order ----------------------------------------

  for( auto&& K : simplicialComplexes )
  {
    K = applyFiltration( K, filtration, reverse );
    K = assignVertexWeights( K, weights, reverse );
    K = applyFiltration( K, filtration, reverse );
  }

  // 2. Calculate persistent homology ----------------------------------

  for( std::size_t i = 0; i < simplicialComplexes.size(); i++ )
  {
    // The persistence diagram that will be used in the subsequent
    // analysis. This does not necessarily have to stem from data,
    // but can be calculated from a suitable transformation.
    PersistenceDiagram D;

    auto&& K = simplicialComplexes[i];
    auto diagrams = aleph::calculatePersistenceDiagrams( K );
    D             = diagrams.back(); // Use the *last* diagram of the filtration so that
                                     // we get features in the highest dimension.

    D.removeDiagonal();
    D.removeUnpaired();

    if( normalize )
    {
      // Ensures that all weights are in [0:1] for the corresponding
      // diagram. This enables the comparison of time-varying graphs
      // or different instances.
      std::transform( D.begin(), D.end(), D.begin(),
        [&i, &minData, &maxData] ( const Point& p )
        {
          auto x = p.x();
          auto y = p.y();

          if( minData[i] != maxData[i] )
          {
            x = (x - minData[i]) / (maxData[i] - minData[i]);
            y = (y - minData[i]) / (maxData[i] - minData[i]);
          }

          return Point( x,y );
        }
      );
    }

    // Determine mode of operation -------------------------------------
    //
    // Several modes of operation exist for this program. They can be
    // set using the flags specified above. At present, the following
    // operations are possible:
    //
    // - Calculate persistence diagrams
    // - Calculate 2-norm of the persistence diagrams

    if( calculateDiagrams )
      std::cout << D << "\n\n";
    else
      std::cout << i << "\t" << aleph::pNorm( D ) << "\n";
  }
}
<commit_msg>Added (untested) support for reading edge lists<commit_after>#include <aleph/math/SymmetricMatrix.hh>

#include <aleph/persistenceDiagrams/Norms.hh>
#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>

#include <aleph/persistentHomology/Calculation.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <aleph/topology/io/BipartiteAdjacencyMatrix.hh>
#include <aleph/topology/io/EdgeLists.hh>

#include <algorithm>
#include <chrono>
#include <iostream>
#include <limits>
#include <random>
#include <stdexcept>
#include <unordered_map>
#include <vector>

#include <getopt.h>

// These declarations should remain global because we have to refer to
// them in utility functions that are living outside of `main()`.
using DataType           = double;
using VertexType         = unsigned short;
using Simplex            = aleph::topology::Simplex<DataType, VertexType>;
using SimplicialComplex  = aleph::topology::SimplicialComplex<Simplex>;
using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;
using Point              = typename PersistenceDiagram::Point;

PersistenceDiagram merge( const PersistenceDiagram& D, const PersistenceDiagram& E )
{
  PersistenceDiagram F;

  if( D.dimension() != F.dimension() )
    throw std::runtime_error( "Persistence diagram dimensions have to agree" );

  for( auto&& diagram : { D, E } )
    for( auto&& p : diagram )
      F.add( p.x(), p.y() );

  return F;
}

template
<
  class Engine,       // random engine to use for weight generation (e.g. std::default_random_engine)
  class Distribution  // distribution to use for weight generation (e.g. std::uniform_real_distribution)
>
SimplicialComplex makeRandomStratifiedGraph(
  const std::vector<unsigned>& strata,
  Engine& engine,
  Distribution& distribution
)
{
  auto n = strata.size();

  if( n <= 1 )
    throw std::runtime_error( "Invalid number of strata" );

  std::vector<Simplex> simplices;

  // Create vertices ---------------------------------------------------
  //
  // The `strata` vector contains the size of each stratum, so we just
  // have to add the correct number of vertices here.

  VertexType index = VertexType(0);
  for( auto&& stratum : strata )
  {
    for( unsigned i = 0; i < stratum; i++ )
      simplices.push_back( Simplex( index++ ) );
  }

  // Create edges ------------------------------------------------------
  //
  // Every stratum is connected to every other stratum, but there are no
  // connections *within* a given stratum.

  VertexType offset = VertexType(0);
  for( decltype(n) i = 0; i < n - 1; i++ )
  {
    // All vertices in the next stratum start with this offset to their
    // indices. It depends on the sum of all vertices in *all* previous
    // strata.
    offset += strata[i];

    for( unsigned j = 0; j < strata[i]; j++ )
    {
      for( unsigned k = 0; k < strata[i+1]; k++ )
      {
        simplices.push_back(
          Simplex(
            {
              VertexType( offset - strata[i] + j ),
              VertexType( offset             + k )
            },
            distribution( engine )
          )
        );
      }
    }
  }

  return SimplicialComplex( simplices.begin(), simplices.end() );
}

SimplicialComplex applyFiltration( const SimplicialComplex& K,
                                   const std::string& strategy,
                                   bool reverse = false )
{
  auto L = K;

  if( strategy == "standard" )
  {
    if( reverse )
    {
      L.sort(
        aleph::topology::filtrations::Data<Simplex, std::greater<DataType> >()
      );
    }
    else
    {
      L.sort(
        aleph::topology::filtrations::Data<Simplex, std::less<DataType> >()
      );
    }
  }
  else if( strategy == "absolute" )
  {
    if( reverse )
    {
      auto functor = [] ( const Simplex& s, const Simplex& t )
      {
        auto w1 = s.data();
        auto w2 = t.data();

        if( std::abs( w1 ) > std::abs( w2 ) )
          return true;
        else if( std::abs( w1 ) == std::abs( w2 ) )
        {
          // This amounts to saying that w1 is positive and w2 is
          // negative.
          if( w1 > w2 )
            return true;
          else
          {
            if( s.dimension() < t.dimension() )
              return true;

            // Absolute value is equal, signed value is equal, and the
            // dimension is equal. We thus have to fall back to merely
            // using the lexicographical order.
            else
              return s < t;
          }
        }

        return false;
      };

      L.sort( functor );
    }
    else
    {
      auto functor = [] ( const Simplex& s, const Simplex& t )
      {
        auto w1 = s.data();
        auto w2 = t.data();

        if( std::abs( w1 ) < std::abs( w2 ) )
          return true;
        else if( std::abs( w1 ) == std::abs( w2 ) )
        {
          // This amounts to saying that w1 is negative and w2 is
          // positive.
          if( w1 < w2 )
            return true;
          else
          {
            if( s.dimension() < t.dimension() )
              return true;

            // Absolute value is equal, signed value is equal, and the
            // dimension is equal. We thus have to fall back to merely
            // using the lexicographical order.
            else
              return s < t;
          }
        }

        return false;
      };

      L.sort( functor );
    }
  }

  return L;
}

SimplicialComplex assignVertexWeights( const SimplicialComplex& K,
                                       const std::string& strategy,
                                       bool reverse = false )
{
  DataType minData = std::numeric_limits<DataType>::max();
  DataType maxData = std::numeric_limits<DataType>::lowest();

  for( auto&& s : K )
  {
    if( s.dimension() != 1 )
      continue;

    minData = std::min( minData, s.data() );
    maxData = std::max( maxData, s.data() );
  }

  // Setting up the weights --------------------------------------------
  //
  // This function assumes that the simplicial complex is already in
  // filtration ordering with respect to its weights. Hence, we only
  // have to take the *first* weight that we encounter (when using a
  // global vertex weight assignment) or the *extremal* value, which
  // is either a minimum or a maximum depending on the direction.

  std::unordered_map<VertexType, DataType> weight;

  for( auto&& s : K )
  {
    if( s.dimension() != 1 )
      continue;

    auto u     = s[0];
    auto v     = s[1];
    DataType w = DataType(); // weight to assign; depends on filtration

    // Assign the global minimum or maximum. This is rather wasteful
    // because the values do not change, but at least the code makes
    // it clear that all updates are done in the same place.
    if( strategy == "global" )
      w = reverse ? maxData : minData;
    else if( strategy == "local" )
      w = s.data();
    else
      throw std::runtime_error( "Unknown update strategy '" + strategy + "'" );

    // This only performs the update *once*.
    weight.insert( {u,w} );
    weight.insert( {v,w} );
  }

  // Assign the weights ------------------------------------------------
  //
  // Having set up the map of weights, we now only need to traverse it
  // in order to assign weights afterwards.

  auto L = K;

  for( auto it = L.begin(); it != L.end(); ++it )
  {
    if( it->dimension() == 0 )
    {
      auto s = *it;  // simplex
      auto v = s[0]; // vertex

      s.setData( weight.at(v) );

      auto result = L.replace( it, s );
      if( !result )
        throw std::runtime_error( "Unable to replace simplex in simplicial complex" );
    }
  }

  return L;
}

template <class Reader> std::vector<SimplicialComplex> loadSimplicialComplexes( int argc, char** argv )
{
  Reader reader;

  std::vector<SimplicialComplex> simplicialComplexes;
  simplicialComplexes.reserve( static_cast<std::size_t>( argc - optind ) );

  for( int i = optind; i < argc; i++ )
  {
    auto filename = std::string( argv[i] );

    std::cerr << "* Processing " << filename << "...";

    SimplicialComplex K;
    reader( filename, K );

    std::cerr << "finished\n";

    simplicialComplexes.emplace_back( K );
  }

  return simplicialComplexes;
}

int main( int argc, char** argv )
{
  bool bipartite             = false;
  bool normalize             = false;
  bool reverse               = false;
  bool verbose               = false;
  bool calculateDiagrams     = false;

  // The default filtration sorts simplices by their weights. Negative
  // weights are treated as being less relevant than positive ones.
  std::string filtration = "standard";

  // Defines how the minimum value for the vertices is to be set. Valid
  // options include:
  //
  //  - global    (uses the global extremal value)
  //  - local     (uses the local  extremal value over all neighbours)
  std::string weights = "global";

  {
    static option commandLineOptions[] =
    {
      { "bipartite"           , no_argument,       nullptr, 'b' },
      { "normalize"           , no_argument,       nullptr, 'n' },
      { "persistence-diagrams", no_argument,       nullptr, 'p' },
      { "reverse"             , no_argument,       nullptr, 'r' },
      { "verbose"             , no_argument,       nullptr, 'v' },
      { "filtration"          , required_argument, nullptr, 'f' },
      { "weights"             , required_argument, nullptr, 'w' },
      { nullptr               , 0                , nullptr,  0  }
    };

    int option = 0;
    while( ( option = getopt_long( argc, argv, "bnprtvf:w:", commandLineOptions, nullptr ) ) != -1 )
    {
      switch( option )
      {
      case 'b':
        bipartite = true;
        break;
      case 'f':
        filtration = optarg;
        break;
      case 'n':
        normalize = true;
        break;
      case 'p':
        calculateDiagrams = true;
        break;
      case 'r':
        reverse = true;
        break;
      case 'v':
        verbose = true;
        break;
      case 'w':
        weights = optarg;
        break;
      default:
        break;
      }
    }

    // Check filtration validity ---------------------------------------

    if(    filtration != "absolute"
        && filtration != "standard" )
    {
      std::cerr << "* Invalid filtration value '" << filtration << "', so falling back to standard one\n";
      filtration = "standard";
    }

    // Check validity of weight strategy -------------------------------

    if(    weights != "global"
        && weights != "local" )
    {
      std::cerr << "* Invalid weight strategy value '" << weights << "', so falling back to global one\n";
      weights = "global";
    }
  }

  // Be verbose about parameters ---------------------------------------

  if( bipartite )
    std::cerr << "* Mode: reading bipartite adjacency matrices\n";
  else
    std::cerr << "* Mode: reading edge lists\n";

  std::cerr << "* Filtration: " << filtration
            << " (" << ( reverse ? "" : "not " ) << "reversed" << ")\n"
            << "* Vertex weight assignment strategy: " << weights << "\n";

  if( verbose )
    std::cerr << "* Verbose output\n";

  // 1. Read simplicial complexes --------------------------------------

  std::vector<SimplicialComplex> simplicialComplexes;
  simplicialComplexes.reserve( static_cast<unsigned>( argc - optind - 1 ) );

  std::vector<DataType> minData;
  std::vector<DataType> maxData;

  minData.reserve( simplicialComplexes.size() );
  maxData.reserve( simplicialComplexes.size() );

  if( argc - optind >= 1 )
  {
    if( bipartite )
    {
      using Reader = aleph::topology::io::BipartiteAdjacencyMatrixReader;

      simplicialComplexes
        = loadSimplicialComplexes<Reader>( argc, argv );
    }
    else
    {
      using Reader = aleph::topology::io::EdgeListReader;

      simplicialComplexes
        = loadSimplicialComplexes<Reader>( argc, argv );
    }
  }
  else
  {
    std::default_random_engine engine;
    engine.seed(
      static_cast<unsigned>(
        std::chrono::system_clock::now().time_since_epoch().count()
      )
    );

    DataType minWeight = DataType(-1);
    DataType maxWeight = DataType( 1);

    std::uniform_real_distribution<DataType> distribution(
      minWeight,
      std::nextafter( maxWeight, std::numeric_limits<DataType>::max() )
    );

    for( unsigned i = 0; i < 1e5; i++ )
    {
      auto K
        = makeRandomStratifiedGraph( {2,3}, // FIXME: {2,3,1} for the complete network
                                     engine,
                                     distribution
      );

      simplicialComplexes.emplace_back( K );
    }
  }

  // Determine minimum and maximum values for each complex -------------

  for( auto&& K : simplicialComplexes )
  {
    DataType minData_ = std::numeric_limits<DataType>::max();
    DataType maxData_ = std::numeric_limits<DataType>::lowest();

    // *Always* determine minimum and maximum weights so that we may
    // report them later on. They are only used for normalization in
    // the persistence diagram calculation step.
    for( auto&& s : K )
    {
      minData_ = std::min( minData_, s.data() );
      maxData_ = std::max( maxData_, s.data() );
    }

    minData.push_back( minData_ );
    maxData.push_back( maxData_ );
  }

  // Establish filtration order ----------------------------------------

  for( auto&& K : simplicialComplexes )
  {
    K = applyFiltration( K, filtration, reverse );
    K = assignVertexWeights( K, weights, reverse );
    K = applyFiltration( K, filtration, reverse );
  }

  // 2. Calculate persistent homology ----------------------------------

  for( std::size_t i = 0; i < simplicialComplexes.size(); i++ )
  {
    // The persistence diagram that will be used in the subsequent
    // analysis. This does not necessarily have to stem from data,
    // but can be calculated from a suitable transformation.
    PersistenceDiagram D;

    auto&& K = simplicialComplexes[i];
    auto diagrams = aleph::calculatePersistenceDiagrams( K );
    D             = diagrams.back(); // Use the *last* diagram of the filtration so that
                                     // we get features in the highest dimension.

    D.removeDiagonal();
    D.removeUnpaired();

    if( normalize )
    {
      // Ensures that all weights are in [0:1] for the corresponding
      // diagram. This enables the comparison of time-varying graphs
      // or different instances.
      std::transform( D.begin(), D.end(), D.begin(),
        [&i, &minData, &maxData] ( const Point& p )
        {
          auto x = p.x();
          auto y = p.y();

          if( minData[i] != maxData[i] )
          {
            x = (x - minData[i]) / (maxData[i] - minData[i]);
            y = (y - minData[i]) / (maxData[i] - minData[i]);
          }

          return Point( x,y );
        }
      );
    }

    // Determine mode of operation -------------------------------------
    //
    // Several modes of operation exist for this program. They can be
    // set using the flags specified above. At present, the following
    // operations are possible:
    //
    // - Calculate persistence diagrams
    // - Calculate 2-norm of the persistence diagrams

    if( calculateDiagrams )
      std::cout << D << "\n\n";
    else
      std::cout << i << "\t" << aleph::pNorm( D ) << "\n";
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/predictors/predictor_database.h"

#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/stringprintf.h"
#include "chrome/browser/predictors/autocomplete_action_predictor_table.h"
#include "chrome/browser/predictors/resource_prefetch_predictor.h"
#include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
#include "sql/connection.h"
#include "sql/statement.h"

using content::BrowserThread;

namespace {

// TODO(shishir): This should move to a more generic name.
const base::FilePath::CharType kPredictorDatabaseName[] =
    FILE_PATH_LITERAL("Network Action Predictor");

}  // namespace

namespace predictors {

// Refcounted as it is created, initialized and destroyed on a different thread
// to the DB thread that is required for all methods performing database access.
class PredictorDatabaseInternal
    : public base::RefCountedThreadSafe<PredictorDatabaseInternal> {
 private:
  friend class base::RefCountedThreadSafe<PredictorDatabaseInternal>;
  friend class PredictorDatabase;

  explicit PredictorDatabaseInternal(Profile* profile);
  virtual ~PredictorDatabaseInternal();

  // Opens the database file from the profile path. Separated from the
  // constructor to ease construction/destruction of this object on one thread
  // but database access on the DB thread.
  void Initialize();
  void LogDatabaseStats();  //  DB Thread.

  // Cancels pending DB transactions. Should only be called on the UI thread.
  void SetCancelled();

  bool is_resource_prefetch_predictor_enabled_;
  base::FilePath db_path_;
  scoped_ptr<sql::Connection> db_;

  // TODO(shishir): These tables may not need to be refcounted. Maybe move them
  // to using a WeakPtr instead.
  scoped_refptr<AutocompleteActionPredictorTable> autocomplete_table_;
  scoped_refptr<ResourcePrefetchPredictorTables> resource_prefetch_tables_;

  DISALLOW_COPY_AND_ASSIGN(PredictorDatabaseInternal);
};

PredictorDatabaseInternal::PredictorDatabaseInternal(Profile* profile)
    : db_path_(profile->GetPath().Append(kPredictorDatabaseName)),
      db_(new sql::Connection()),
      autocomplete_table_(new AutocompleteActionPredictorTable()),
      resource_prefetch_tables_(new ResourcePrefetchPredictorTables()) {
  // TODO (tburkard): initialize logged_in_table_ member.
  ResourcePrefetchPredictorConfig config;
  is_resource_prefetch_predictor_enabled_ =
      IsSpeculativeResourcePrefetchingEnabled(profile, &config);
}

PredictorDatabaseInternal::~PredictorDatabaseInternal() {
  // The connection pointer needs to be deleted on the DB thread since there
  // might be a task in progress on the DB thread which uses this connection.
  BrowserThread::DeleteSoon(BrowserThread::DB, FROM_HERE, db_.release());
}

void PredictorDatabaseInternal::Initialize() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
  db_->set_exclusive_locking();
  bool success = db_->Open(db_path_);

  if (!success)
    return;

  autocomplete_table_->Initialize(db_.get());
  resource_prefetch_tables_->Initialize(db_.get());

  LogDatabaseStats();
}

void PredictorDatabaseInternal::SetCancelled() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  autocomplete_table_->SetCancelled();
  resource_prefetch_tables_->SetCancelled();
}

void PredictorDatabaseInternal::LogDatabaseStats() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));

  int64 db_size;
  bool success = file_util::GetFileSize(db_path_, &db_size);
  DCHECK(success) << "Failed to get file size for " << db_path_.value();
  UMA_HISTOGRAM_MEMORY_KB("PredictorDatabase.DatabaseSizeKB",
                          static_cast<int>(db_size / 1024));

  autocomplete_table_->LogDatabaseStats();
  if (is_resource_prefetch_predictor_enabled_)
    resource_prefetch_tables_->LogDatabaseStats();
}

PredictorDatabase::PredictorDatabase(Profile* profile)
    : db_(new PredictorDatabaseInternal(profile)) {
  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
      base::Bind(&PredictorDatabaseInternal::Initialize, db_));
}

PredictorDatabase::~PredictorDatabase() {
}

void PredictorDatabase::Shutdown() {
  db_->SetCancelled();
}

scoped_refptr<AutocompleteActionPredictorTable>
    PredictorDatabase::autocomplete_table() {
  return db_->autocomplete_table_;
}

scoped_refptr<ResourcePrefetchPredictorTables>
    PredictorDatabase::resource_prefetch_tables() {
  return db_->resource_prefetch_tables_;
}

sql::Connection* PredictorDatabase::GetDatabase() {
  return db_->db_.get();
}

}  // namespace predictors
<commit_msg>Revert 194504 "Fix build break"<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/predictors/predictor_database.h"

#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/stringprintf.h"
#include "chrome/browser/predictors/autocomplete_action_predictor_table.h"
#include "chrome/browser/predictors/resource_prefetch_predictor.h"
#include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
#include "sql/connection.h"
#include "sql/statement.h"

using content::BrowserThread;

namespace {

// TODO(shishir): This should move to a more generic name.
const base::FilePath::CharType kPredictorDatabaseName[] =
    FILE_PATH_LITERAL("Network Action Predictor");

}  // namespace

namespace predictors {

// Refcounted as it is created, initialized and destroyed on a different thread
// to the DB thread that is required for all methods performing database access.
class PredictorDatabaseInternal
    : public base::RefCountedThreadSafe<PredictorDatabaseInternal> {
 private:
  friend class base::RefCountedThreadSafe<PredictorDatabaseInternal>;
  friend class PredictorDatabase;

  explicit PredictorDatabaseInternal(Profile* profile);
  virtual ~PredictorDatabaseInternal();

  // Opens the database file from the profile path. Separated from the
  // constructor to ease construction/destruction of this object on one thread
  // but database access on the DB thread.
  void Initialize();
  void LogDatabaseStats();  //  DB Thread.

  // Cancels pending DB transactions. Should only be called on the UI thread.
  void SetCancelled();

  bool is_resource_prefetch_predictor_enabled_;
  base::FilePath db_path_;
  scoped_ptr<sql::Connection> db_;

  // TODO(shishir): These tables may not need to be refcounted. Maybe move them
  // to using a WeakPtr instead.
  scoped_refptr<AutocompleteActionPredictorTable> autocomplete_table_;
  scoped_refptr<ResourcePrefetchPredictorTables> resource_prefetch_tables_;

  DISALLOW_COPY_AND_ASSIGN(PredictorDatabaseInternal);
};

PredictorDatabaseInternal::PredictorDatabaseInternal(Profile* profile)
    : db_path_(profile->GetPath().Append(kPredictorDatabaseName)),
      db_(new sql::Connection()),
      autocomplete_table_(new AutocompleteActionPredictorTable()),
      logged_in_table_(new LoggedInPredictorTable()),
      resource_prefetch_tables_(new ResourcePrefetchPredictorTables()) {
  ResourcePrefetchPredictorConfig config;
  is_resource_prefetch_predictor_enabled_ =
      IsSpeculativeResourcePrefetchingEnabled(profile, &config);
}

PredictorDatabaseInternal::~PredictorDatabaseInternal() {
  // The connection pointer needs to be deleted on the DB thread since there
  // might be a task in progress on the DB thread which uses this connection.
  BrowserThread::DeleteSoon(BrowserThread::DB, FROM_HERE, db_.release());
}

void PredictorDatabaseInternal::Initialize() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
  db_->set_exclusive_locking();
  bool success = db_->Open(db_path_);

  if (!success)
    return;

  autocomplete_table_->Initialize(db_.get());
  resource_prefetch_tables_->Initialize(db_.get());

  LogDatabaseStats();
}

void PredictorDatabaseInternal::SetCancelled() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  autocomplete_table_->SetCancelled();
  resource_prefetch_tables_->SetCancelled();
}

void PredictorDatabaseInternal::LogDatabaseStats() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));

  int64 db_size;
  bool success = file_util::GetFileSize(db_path_, &db_size);
  DCHECK(success) << "Failed to get file size for " << db_path_.value();
  UMA_HISTOGRAM_MEMORY_KB("PredictorDatabase.DatabaseSizeKB",
                          static_cast<int>(db_size / 1024));

  autocomplete_table_->LogDatabaseStats();
  if (is_resource_prefetch_predictor_enabled_)
    resource_prefetch_tables_->LogDatabaseStats();
}

PredictorDatabase::PredictorDatabase(Profile* profile)
    : db_(new PredictorDatabaseInternal(profile)) {
  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
      base::Bind(&PredictorDatabaseInternal::Initialize, db_));
}

PredictorDatabase::~PredictorDatabase() {
}

void PredictorDatabase::Shutdown() {
  db_->SetCancelled();
}

scoped_refptr<AutocompleteActionPredictorTable>
    PredictorDatabase::autocomplete_table() {
  return db_->autocomplete_table_;
}

scoped_refptr<ResourcePrefetchPredictorTables>
    PredictorDatabase::resource_prefetch_tables() {
  return db_->resource_prefetch_tables_;
}

sql::Connection* PredictorDatabase::GetDatabase() {
  return db_->db_.get();
}

}  // namespace predictors
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "PersistentLDAPConnection.h"

//--- project modules used -----------------------------------------------------
#include "LDAPMessageEntry.h"
#include "LDAPConnectionManager.h"
#include "ldap-extension.h"

//--- standard modules used ----------------------------------------------------
#include "Dbg.h"
#include "Threads.h"
#include "StringStream.h"
#include "Base64.h"
#include "MD5.h"

//--- c-modules used -----------------------------------------------------------

/* Function to set up thread-specific data. */
void PersistentLDAPConnection::tsd_setup()
{
	StartTrace(PersistentLDAPConnection.tsd_setup);
	void *tsd = NULL;
	if ( GETTLSDATA(LDAPConnectionManager::fgErrnoKey, tsd, void) ) {
		Trace("Thread specific data for fgErrnoKey already set up. Thread [" << Thread::MyId() << "]");
		return;
	}

	tsd = (void *) calloc( 1, sizeof(struct ldap_error) );
	if ( !SETTLSDATA(LDAPConnectionManager::fgErrnoKey, tsd) ) {
		Trace("Setting Thread specific data for fgErrnoKey failed. Thread [" << Thread::MyId() << "]");
	}
}

void PersistentLDAPConnection::tsd_destruct(void *tsd)
{
	StartTrace(PersistentLDAPConnection.tsd_destruct);
	if ( tsd != (void *) NULL ) {
		free(tsd);
	}
}

/* Function for setting an LDAP error. */
void PersistentLDAPConnection::set_ld_error( int err, char *matched, char *errmsg, void *dummy )
{
	StartTrace(PersistentLDAPConnection.set_ld_error);

	PersistentLDAPConnection::ldap_error *le = NULL;
	GETTLSDATA(LDAPConnectionManager::fgErrnoKey, le, ldap_error);
	le->le_errno = err;
	if ( le->le_matched != NULL ) {
		ldap_memfree( le->le_matched );
	}
	le->le_matched = matched;
	if ( le->le_errmsg != NULL ) {
		ldap_memfree( le->le_errmsg );
	}
	le->le_errmsg = errmsg;
}

/* Function for getting an LDAP error. */
int PersistentLDAPConnection::get_ld_error( char **matched, char **errmsg, void *dummy )
{
	StartTrace(PersistentLDAPConnection.get_ld_error);

	PersistentLDAPConnection::ldap_error *le = NULL;
	GETTLSDATA(LDAPConnectionManager::fgErrnoKey, le, ldap_error);
	if ( matched != NULL ) {
		*matched = le->le_matched;
	}
	if ( errmsg != NULL ) {
		*errmsg = le->le_errmsg;
	}
	return( le->le_errno );
}

/* Function for setting errno. */
void PersistentLDAPConnection::set_errno( int err )
{
	StartTrace(PersistentLDAPConnection.set_errno);
	errno = err;
}

/* Function for getting errno. */
int PersistentLDAPConnection::get_errno( void )
{
	StartTrace(PersistentLDAPConnection.get_errno);
	return( errno );
}

PersistentLDAPConnection::PersistentLDAPConnection(ROAnything connectionParams) : LDAPConnection(connectionParams)
{
	StartTrace(PersistentLDAPConnection.PersistentLDAPConnection);
	fRebindTimeout = connectionParams["RebindTimeout"].AsLong(0L);
	fTryAutoRebind = connectionParams["TryAutoRebind"].AsLong(0L) > 0L;
	fMaxConnections = connectionParams["MaxConnections"].AsLong(0L);
	TraceAny(connectionParams, "ConnectionParams");
	fPoolId = "";
}

PersistentLDAPConnection::~PersistentLDAPConnection()
{
	StartTrace(PersistentLDAPConnection.~PersistentLDAPConnection);
}

int PersistentLDAPConnection::GetMaxConnections()
{
	StartTrace(PersistentLDAPConnection.GetMaxConnections);
	return fMaxConnections;
}

bool PersistentLDAPConnection::SetErrnoHandler(LDAPErrorHandler eh)
{
	StartTrace(PersistentLDAPConnection.SetErrnoHandler);

	tsd_setup();
	struct ldap_thread_fns  tfns;

	/* Set the function pointers for dealing with mutexes
	and error information. */
	memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
	tfns.ltf_get_errno = get_errno;
	tfns.ltf_set_errno = set_errno;
	tfns.ltf_get_lderrno = get_ld_error;
	tfns.ltf_set_lderrno = set_ld_error;
	tfns.ltf_lderrno_arg = NULL;

	/* Set up this session to use those function pointers. */
	if ( ::ldap_set_option( fHandle, LDAP_OPT_THREAD_FN_PTRS, (void *) &tfns ) != LDAP_SUCCESS ) {
		Trace("ldap_set_option: LDAP_OPT_THREAD_FN_PTRS FAILED");
		eh.HandleSessionError(fHandle, "Could not set errno handlers.");
		return false;
	}
	return true;
}

PersistentLDAPConnection::EConnectState PersistentLDAPConnection::DoConnectHook(ROAnything bindParams, LDAPErrorHandler &eh)
{
	StartTrace(PersistentLDAPConnection.DoConnectHook);
	TraceAny(bindParams, "bindParams");
	fPoolId = GetLdapPoolId(bindParams);
	Anything returned = LDAPConnectionManager::LDAPCONNMGR()->GetLdapConnection(eh.IsRetry(), GetMaxConnections(), fPoolId, fRebindTimeout);
	PersistentLDAPConnection::EConnectState eConnectState =
		returned["MustRebind"].AsBool(1) == false ?
		PersistentLDAPConnection::eMustNotRebind  : PersistentLDAPConnection::eMustRebind;
	fHandle = (LDAP *) returned["Handle"].AsIFAObject(0);
	if ( eConnectState == PersistentLDAPConnection::eMustNotRebind ) {
		Trace("Retrning: " << ConnectRetToString(PersistentLDAPConnection::eOk));
		eConnectState = PersistentLDAPConnection::eOk;
	}
	Trace("eConnectState: " << ConnectRetToString(eConnectState) << " Handle: " << DumpConnectionHandle(fHandle));
	return eConnectState;
}

bool PersistentLDAPConnection::ReleaseHandleInfo()
{
	StartTrace(PersistentLDAPConnection.ReleaseHandleInfo);
	bool ret = LDAPConnectionManager::LDAPCONNMGR()->ReleaseHandleInfo(fMaxConnections, fPoolId);
	return ret;
}

bool PersistentLDAPConnection::Bind(String bindName, String bindPW, int &msgId, LDAPErrorHandler eh)
{
	StartTrace(LDAPConnection.PersistentLDAPConnection);

	String errMsg = "Binding request failed. ";
	errMsg << "[Server: '" << fServer << "', Port: '" << fPort << "'] ";

	if ( bindName.IsEqual("") || bindName.IsEqual("Anonymous") ) {
		Trace("Binding as Anonymous");
		errMsg << " (Anonymous bind.)";
		msgId = ::ldap_simple_bind( fHandle, NULL, NULL );
	} else {
		errMsg << " (Authorized bind.)";

		if ( bindPW == "undefined" ) {
			Trace("Bindpassword NOT OK: pwd = ["  << bindPW << "]");
			eh.HandleSessionError(fHandle, errMsg);
			return false;
		} else {
			Trace("Binding with <" << bindName << "><" << bindPW << ">");
			msgId = ::ldap_simple_bind( fHandle, bindName, bindPW );
		}
	}

	// bind request successful?
	if ( msgId == -1 ) {
		Trace("Binding request FAILED!");
		eh.HandleSessionError(fHandle, errMsg);
		Disconnect();
		return false;
	}

	Trace("Binding request SUCCEEDED, waiting for connection...");
	return true;
}

LDAPConnection::EConnectState PersistentLDAPConnection::DoConnect(ROAnything bindParams, LDAPErrorHandler eh)
{
	StartTrace(PersistentLDAPConnection.DoConnect);

	// set handle to null
	fHandle = NULL;
	String errMsg;
	String bindName = bindParams["BindName"].AsString("");
	String bindPW = bindParams["BindPW"].AsString("");
	long maxConnections = bindParams["MaxConnections"].AsLong(0);
	PersistentLDAPConnection::EConnectState eConnectState = PersistentLDAPConnection::eNok;
	if ( (eConnectState = DoConnectHook(bindParams, eh)) == PersistentLDAPConnection::eOk ) {
		SetErrnoHandler(eh);
		return eConnectState;
	}
	// get connection handle
	if ( !(fHandle = Init(eh)) ) {
		return eInitNok;
	}

	// set protocol, timeout and rebind procedure
	if ( !SetProtocol(eh)			||
		 !SetConnectionTimeout(eh)	||
		 !SetSearchTimeout(eh)		||
		 !SetErrnoHandler(eh)
		 /* || !SetRebindProc(eh) */  ) {
		return eSetOptionsNok;
	}
	// send bind request (asynchronous)
	int msgId;
	if ( !Bind(bindName, bindPW, msgId, eh) ) {
		return eBindNok;
	}

	// wait for bind result (using msgId)
	Anything result;
	bool ret = WaitForResult(msgId, result, eh);
	if ( ret ) {
		LDAPConnectionManager::LDAPCONNMGR()->SetLdapConnection(maxConnections, fPoolId, fHandle);
		if ( eConnectState == PersistentLDAPConnection::eMustRebind ) {
			return PersistentLDAPConnection::eRebindOk;
		}
	}
	return ret ? PersistentLDAPConnection::eOk : PersistentLDAPConnection::eBindNok;
}

bool PersistentLDAPConnection::WaitForResult(int msgId, Anything &result, LDAPErrorHandler &eh)
{
	StartTrace(PersistentLDAPConnection.WaitForResult);

	timeval tv;
	tv.tv_sec  = fSearchTimeout;
	tv.tv_usec = 0;

	timeval *tvp = (fSearchTimeout == 0) ? NULL : &tv;

	bool finished = false;
	bool success = false;

	String errMsg;
	int resultCode;

	LDAPMessage *ldapResult;
	LDAPMessageEntry lmAutoDestruct(&ldapResult);	// automatic destructor for LDAPMessage
	lmAutoDestruct.Use();

	while (!finished) {
		// wait for result
		resultCode = ldap_result(fHandle, msgId, 1, tvp, &ldapResult);

		// check result
		if (resultCode == -1 && fSearchTimeout == 0) {
			// error, abandon!
			Trace("WaitForResult [Timeout: 0] received an error");
			int opRet;
			ldap_parse_result( fHandle, ldapResult, &opRet, NULL, NULL, NULL, NULL, 0 );
			errMsg << "Synchronous Wait4Result: ErrorCode: [" << (long)opRet << "] ErrorMsg: " << ldap_err2string( opRet );
			HandleWait4ResultError(msgId, errMsg, eh);
			finished = true;
		} else if (resultCode == 0 || (resultCode == -1 && fSearchTimeout != 0)) {
			// resultCode 0 means timeout, abandon
			Trace("WaitForResult [Timeout != 0] encountered a timeout ...");
			errMsg << "Asynchronous Wait4Result: The request <" << (long) msgId << "> timed out.";
			HandleWait4ResultError(msgId, errMsg, eh);
			if ( fTryAutoRebind ) {
				eh.SetShouldRetry();
			}
			finished = true;
		} else {
			// received a result
			int errCode = ldap_result2error(fHandle, ldapResult, 0);
			if (errCode == LDAP_SUCCESS || errCode == LDAP_SIZELIMIT_EXCEEDED) {
				Trace("WaitForResult recieved a result and considers it to be ok ...");
				success = true;

				// transform LDAPResult into an Anything with Meta Information
				TransformResult(ldapResult, result, eh.GetQueryParams());

				// add extra flag to inform client, if sizelimit was exceeded
				if (errCode == LDAP_SIZELIMIT_EXCEEDED) {
					result["SizeLimitExceeded"] = 1;
				}
			} else if (errCode == LDAP_COMPARE_FALSE || errCode == LDAP_COMPARE_TRUE) {
				Trace("WaitForResult recieved a result and considers it to be ok (compare) ...");
				success = true;

				// this is a bit special
				int rc;
				ldap_get_option(fHandle, LDAP_OPT_ERROR_NUMBER, &rc);
				result["Type"] = "LDAP_RES_COMPARE";
				result["Equal"] = (errCode == LDAP_COMPARE_TRUE);
				result["LdapCode"] = rc;
				result["LdapMsg"] = ldap_err2string(rc);
			} else {
				Trace("WaitForResult recieved a result and considers it to be WRONG ...");
				errMsg = "LDAP request failed.";
				eh.HandleSessionError(fHandle, errMsg);
			}
			finished = true;
		}
	}
	return success;
}

void PersistentLDAPConnection::HandleWait4ResultError(int msgId, String &errMsg, LDAPErrorHandler eh)
{
	StartTrace(PersistentLDAPConnection.HandleWait4ResultError);
	if ( msgId != -1 ) {
		int errCode = ldap_abandon(fHandle, msgId);
		errMsg << " Request abandoned: " << (errCode == LDAP_SUCCESS ? " successfully." : " FAILED!");
	} else {
		errMsg << " Request abandoned: binding handle was invalid, ldap_abandon not called";
	}
	eh.HandleSessionError(fHandle, errMsg);
	// Invalidate our handle because LDAP server might be down, will rebind next time!
	LDAPConnectionManager::LDAPCONNMGR()->SetLdapConnection(GetMaxConnections(), fPoolId, (LDAP *) NULL);
}

String PersistentLDAPConnection::Base64ArmouredMD5Hash(const String &text)
{
	StartTrace(PersistentLDAPConnection.Base64ArmouredMD5Hash);
	String hash, result;
	MD5Signer::DoHash(text, hash);
	Base64Regular b64("b64reg");
	b64.DoEncode(result, hash);
	return result;
}

String PersistentLDAPConnection::GetLdapPoolId(ROAnything bindParams)
{
	StartTrace(PersistentLDAPConnection.GetLdapPoolId);
	String bindName = bindParams["BindName"].AsString("");
	String bindPW 	= Base64ArmouredMD5Hash(bindParams["BindPW"].AsString(""));

	return	String("Host[") << fServer << "] Port[" << fPort << "] DN[" <<
			bindName << "] BindPW[" << bindPW << "] ConnTimeout[" << fConnectionTimeout << "]";
}

String PersistentLDAPConnection::GetLdapPoolId(const String &server, long port, const String &bindName,
		const String &bindPW, long connectionTimeout)
{
	StartTrace(PersistentLDAPConnection.GetLdapPoolId);
	String armouredPW = Base64ArmouredMD5Hash(bindPW);

	return	String("Host[") << server << "] Port[" << port << "] DN[" <<
			bindName << "] BindPW[" << armouredPW << "] ConnTimeout[" << connectionTimeout << "]";
}
<commit_msg>added include for memeset<commit_after>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "PersistentLDAPConnection.h"

//--- project modules used -----------------------------------------------------
#include "LDAPMessageEntry.h"
#include "LDAPConnectionManager.h"
#include "ldap-extension.h"

//--- standard modules used ----------------------------------------------------
#include "Dbg.h"
#include "Threads.h"
#include "StringStream.h"
#include "Base64.h"
#include "MD5.h"

//--- c-modules used -----------------------------------------------------------
#include <stdlib.h>

/* Function to set up thread-specific data. */
void PersistentLDAPConnection::tsd_setup()
{
	StartTrace(PersistentLDAPConnection.tsd_setup);
	void *tsd = NULL;
	if ( GETTLSDATA(LDAPConnectionManager::fgErrnoKey, tsd, void) ) {
		Trace("Thread specific data for fgErrnoKey already set up. Thread [" << Thread::MyId() << "]");
		return;
	}

	tsd = (void *) calloc( 1, sizeof(struct ldap_error) );
	if ( !SETTLSDATA(LDAPConnectionManager::fgErrnoKey, tsd) ) {
		Trace("Setting Thread specific data for fgErrnoKey failed. Thread [" << Thread::MyId() << "]");
	}
}

void PersistentLDAPConnection::tsd_destruct(void *tsd)
{
	StartTrace(PersistentLDAPConnection.tsd_destruct);
	if ( tsd != (void *) NULL ) {
		free(tsd);
	}
}

/* Function for setting an LDAP error. */
void PersistentLDAPConnection::set_ld_error( int err, char *matched, char *errmsg, void *dummy )
{
	StartTrace(PersistentLDAPConnection.set_ld_error);

	PersistentLDAPConnection::ldap_error *le = NULL;
	GETTLSDATA(LDAPConnectionManager::fgErrnoKey, le, ldap_error);
	le->le_errno = err;
	if ( le->le_matched != NULL ) {
		ldap_memfree( le->le_matched );
	}
	le->le_matched = matched;
	if ( le->le_errmsg != NULL ) {
		ldap_memfree( le->le_errmsg );
	}
	le->le_errmsg = errmsg;
}

/* Function for getting an LDAP error. */
int PersistentLDAPConnection::get_ld_error( char **matched, char **errmsg, void *dummy )
{
	StartTrace(PersistentLDAPConnection.get_ld_error);

	PersistentLDAPConnection::ldap_error *le = NULL;
	GETTLSDATA(LDAPConnectionManager::fgErrnoKey, le, ldap_error);
	if ( matched != NULL ) {
		*matched = le->le_matched;
	}
	if ( errmsg != NULL ) {
		*errmsg = le->le_errmsg;
	}
	return( le->le_errno );
}

/* Function for setting errno. */
void PersistentLDAPConnection::set_errno( int err )
{
	StartTrace(PersistentLDAPConnection.set_errno);
	errno = err;
}

/* Function for getting errno. */
int PersistentLDAPConnection::get_errno( void )
{
	StartTrace(PersistentLDAPConnection.get_errno);
	return( errno );
}

PersistentLDAPConnection::PersistentLDAPConnection(ROAnything connectionParams) : LDAPConnection(connectionParams)
{
	StartTrace(PersistentLDAPConnection.PersistentLDAPConnection);
	fRebindTimeout = connectionParams["RebindTimeout"].AsLong(0L);
	fTryAutoRebind = connectionParams["TryAutoRebind"].AsLong(0L) > 0L;
	fMaxConnections = connectionParams["MaxConnections"].AsLong(0L);
	TraceAny(connectionParams, "ConnectionParams");
	fPoolId = "";
}

PersistentLDAPConnection::~PersistentLDAPConnection()
{
	StartTrace(PersistentLDAPConnection.~PersistentLDAPConnection);
}

int PersistentLDAPConnection::GetMaxConnections()
{
	StartTrace(PersistentLDAPConnection.GetMaxConnections);
	return fMaxConnections;
}

bool PersistentLDAPConnection::SetErrnoHandler(LDAPErrorHandler eh)
{
	StartTrace(PersistentLDAPConnection.SetErrnoHandler);

	tsd_setup();
	struct ldap_thread_fns  tfns;

	/* Set the function pointers for dealing with mutexes
	and error information. */
	memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
	tfns.ltf_get_errno = get_errno;
	tfns.ltf_set_errno = set_errno;
	tfns.ltf_get_lderrno = get_ld_error;
	tfns.ltf_set_lderrno = set_ld_error;
	tfns.ltf_lderrno_arg = NULL;

	/* Set up this session to use those function pointers. */
	if ( ::ldap_set_option( fHandle, LDAP_OPT_THREAD_FN_PTRS, (void *) &tfns ) != LDAP_SUCCESS ) {
		Trace("ldap_set_option: LDAP_OPT_THREAD_FN_PTRS FAILED");
		eh.HandleSessionError(fHandle, "Could not set errno handlers.");
		return false;
	}
	return true;
}

PersistentLDAPConnection::EConnectState PersistentLDAPConnection::DoConnectHook(ROAnything bindParams, LDAPErrorHandler &eh)
{
	StartTrace(PersistentLDAPConnection.DoConnectHook);
	TraceAny(bindParams, "bindParams");
	fPoolId = GetLdapPoolId(bindParams);
	Anything returned = LDAPConnectionManager::LDAPCONNMGR()->GetLdapConnection(eh.IsRetry(), GetMaxConnections(), fPoolId, fRebindTimeout);
	PersistentLDAPConnection::EConnectState eConnectState =
		returned["MustRebind"].AsBool(1) == false ?
		PersistentLDAPConnection::eMustNotRebind  : PersistentLDAPConnection::eMustRebind;
	fHandle = (LDAP *) returned["Handle"].AsIFAObject(0);
	if ( eConnectState == PersistentLDAPConnection::eMustNotRebind ) {
		Trace("Retrning: " << ConnectRetToString(PersistentLDAPConnection::eOk));
		eConnectState = PersistentLDAPConnection::eOk;
	}
	Trace("eConnectState: " << ConnectRetToString(eConnectState) << " Handle: " << DumpConnectionHandle(fHandle));
	return eConnectState;
}

bool PersistentLDAPConnection::ReleaseHandleInfo()
{
	StartTrace(PersistentLDAPConnection.ReleaseHandleInfo);
	bool ret = LDAPConnectionManager::LDAPCONNMGR()->ReleaseHandleInfo(fMaxConnections, fPoolId);
	return ret;
}

bool PersistentLDAPConnection::Bind(String bindName, String bindPW, int &msgId, LDAPErrorHandler eh)
{
	StartTrace(LDAPConnection.PersistentLDAPConnection);

	String errMsg = "Binding request failed. ";
	errMsg << "[Server: '" << fServer << "', Port: '" << fPort << "'] ";

	if ( bindName.IsEqual("") || bindName.IsEqual("Anonymous") ) {
		Trace("Binding as Anonymous");
		errMsg << " (Anonymous bind.)";
		msgId = ::ldap_simple_bind( fHandle, NULL, NULL );
	} else {
		errMsg << " (Authorized bind.)";

		if ( bindPW == "undefined" ) {
			Trace("Bindpassword NOT OK: pwd = ["  << bindPW << "]");
			eh.HandleSessionError(fHandle, errMsg);
			return false;
		} else {
			Trace("Binding with <" << bindName << "><" << bindPW << ">");
			msgId = ::ldap_simple_bind( fHandle, bindName, bindPW );
		}
	}

	// bind request successful?
	if ( msgId == -1 ) {
		Trace("Binding request FAILED!");
		eh.HandleSessionError(fHandle, errMsg);
		Disconnect();
		return false;
	}

	Trace("Binding request SUCCEEDED, waiting for connection...");
	return true;
}

LDAPConnection::EConnectState PersistentLDAPConnection::DoConnect(ROAnything bindParams, LDAPErrorHandler eh)
{
	StartTrace(PersistentLDAPConnection.DoConnect);

	// set handle to null
	fHandle = NULL;
	String errMsg;
	String bindName = bindParams["BindName"].AsString("");
	String bindPW = bindParams["BindPW"].AsString("");
	long maxConnections = bindParams["MaxConnections"].AsLong(0);
	PersistentLDAPConnection::EConnectState eConnectState = PersistentLDAPConnection::eNok;
	if ( (eConnectState = DoConnectHook(bindParams, eh)) == PersistentLDAPConnection::eOk ) {
		SetErrnoHandler(eh);
		return eConnectState;
	}
	// get connection handle
	if ( !(fHandle = Init(eh)) ) {
		return eInitNok;
	}

	// set protocol, timeout and rebind procedure
	if ( !SetProtocol(eh)			||
		 !SetConnectionTimeout(eh)	||
		 !SetSearchTimeout(eh)		||
		 !SetErrnoHandler(eh)
		 /* || !SetRebindProc(eh) */  ) {
		return eSetOptionsNok;
	}
	// send bind request (asynchronous)
	int msgId;
	if ( !Bind(bindName, bindPW, msgId, eh) ) {
		return eBindNok;
	}

	// wait for bind result (using msgId)
	Anything result;
	bool ret = WaitForResult(msgId, result, eh);
	if ( ret ) {
		LDAPConnectionManager::LDAPCONNMGR()->SetLdapConnection(maxConnections, fPoolId, fHandle);
		if ( eConnectState == PersistentLDAPConnection::eMustRebind ) {
			return PersistentLDAPConnection::eRebindOk;
		}
	}
	return ret ? PersistentLDAPConnection::eOk : PersistentLDAPConnection::eBindNok;
}

bool PersistentLDAPConnection::WaitForResult(int msgId, Anything &result, LDAPErrorHandler &eh)
{
	StartTrace(PersistentLDAPConnection.WaitForResult);

	timeval tv;
	tv.tv_sec  = fSearchTimeout;
	tv.tv_usec = 0;

	timeval *tvp = (fSearchTimeout == 0) ? NULL : &tv;

	bool finished = false;
	bool success = false;

	String errMsg;
	int resultCode;

	LDAPMessage *ldapResult;
	LDAPMessageEntry lmAutoDestruct(&ldapResult);	// automatic destructor for LDAPMessage
	lmAutoDestruct.Use();

	while (!finished) {
		// wait for result
		resultCode = ldap_result(fHandle, msgId, 1, tvp, &ldapResult);

		// check result
		if (resultCode == -1 && fSearchTimeout == 0) {
			// error, abandon!
			Trace("WaitForResult [Timeout: 0] received an error");
			int opRet;
			ldap_parse_result( fHandle, ldapResult, &opRet, NULL, NULL, NULL, NULL, 0 );
			errMsg << "Synchronous Wait4Result: ErrorCode: [" << (long)opRet << "] ErrorMsg: " << ldap_err2string( opRet );
			HandleWait4ResultError(msgId, errMsg, eh);
			finished = true;
		} else if (resultCode == 0 || (resultCode == -1 && fSearchTimeout != 0)) {
			// resultCode 0 means timeout, abandon
			Trace("WaitForResult [Timeout != 0] encountered a timeout ...");
			errMsg << "Asynchronous Wait4Result: The request <" << (long) msgId << "> timed out.";
			HandleWait4ResultError(msgId, errMsg, eh);
			if ( fTryAutoRebind ) {
				eh.SetShouldRetry();
			}
			finished = true;
		} else {
			// received a result
			int errCode = ldap_result2error(fHandle, ldapResult, 0);
			if (errCode == LDAP_SUCCESS || errCode == LDAP_SIZELIMIT_EXCEEDED) {
				Trace("WaitForResult recieved a result and considers it to be ok ...");
				success = true;

				// transform LDAPResult into an Anything with Meta Information
				TransformResult(ldapResult, result, eh.GetQueryParams());

				// add extra flag to inform client, if sizelimit was exceeded
				if (errCode == LDAP_SIZELIMIT_EXCEEDED) {
					result["SizeLimitExceeded"] = 1;
				}
			} else if (errCode == LDAP_COMPARE_FALSE || errCode == LDAP_COMPARE_TRUE) {
				Trace("WaitForResult recieved a result and considers it to be ok (compare) ...");
				success = true;

				// this is a bit special
				int rc;
				ldap_get_option(fHandle, LDAP_OPT_ERROR_NUMBER, &rc);
				result["Type"] = "LDAP_RES_COMPARE";
				result["Equal"] = (errCode == LDAP_COMPARE_TRUE);
				result["LdapCode"] = rc;
				result["LdapMsg"] = ldap_err2string(rc);
			} else {
				Trace("WaitForResult recieved a result and considers it to be WRONG ...");
				errMsg = "LDAP request failed.";
				eh.HandleSessionError(fHandle, errMsg);
			}
			finished = true;
		}
	}
	return success;
}

void PersistentLDAPConnection::HandleWait4ResultError(int msgId, String &errMsg, LDAPErrorHandler eh)
{
	StartTrace(PersistentLDAPConnection.HandleWait4ResultError);
	if ( msgId != -1 ) {
		int errCode = ldap_abandon(fHandle, msgId);
		errMsg << " Request abandoned: " << (errCode == LDAP_SUCCESS ? " successfully." : " FAILED!");
	} else {
		errMsg << " Request abandoned: binding handle was invalid, ldap_abandon not called";
	}
	eh.HandleSessionError(fHandle, errMsg);
	// Invalidate our handle because LDAP server might be down, will rebind next time!
	LDAPConnectionManager::LDAPCONNMGR()->SetLdapConnection(GetMaxConnections(), fPoolId, (LDAP *) NULL);
}

String PersistentLDAPConnection::Base64ArmouredMD5Hash(const String &text)
{
	StartTrace(PersistentLDAPConnection.Base64ArmouredMD5Hash);
	String hash, result;
	MD5Signer::DoHash(text, hash);
	Base64Regular b64("b64reg");
	b64.DoEncode(result, hash);
	return result;
}

String PersistentLDAPConnection::GetLdapPoolId(ROAnything bindParams)
{
	StartTrace(PersistentLDAPConnection.GetLdapPoolId);
	String bindName = bindParams["BindName"].AsString("");
	String bindPW 	= Base64ArmouredMD5Hash(bindParams["BindPW"].AsString(""));

	return	String("Host[") << fServer << "] Port[" << fPort << "] DN[" <<
			bindName << "] BindPW[" << bindPW << "] ConnTimeout[" << fConnectionTimeout << "]";
}

String PersistentLDAPConnection::GetLdapPoolId(const String &server, long port, const String &bindName,
		const String &bindPW, long connectionTimeout)
{
	StartTrace(PersistentLDAPConnection.GetLdapPoolId);
	String armouredPW = Base64ArmouredMD5Hash(bindPW);

	return	String("Host[") << server << "] Port[" << port << "] DN[" <<
			bindName << "] BindPW[" << armouredPW << "] ConnTimeout[" << connectionTimeout << "]";
}
<|endoftext|>


<commit_before>/**
 * LLVM transformation pass to resolve indirect calls
 *
 * The transformation performs "devirtualization" which consists of
 * looking for indirect function calls and transforming them into a
 * switch statement that selects one of several direct function calls
 * to execute. Devirtualization happens if a pointer analysis can
 * resolve the indirect calls and compute all possible callees.
 **/

#include "transforms/DevirtFunctions.hh"
#include "llvm/Pass.h"
//#include "llvm/Analysis/CallGraph.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "seadsa/CompleteCallGraph.hh"
#include "seadsa/InitializePasses.hh"

static llvm::cl::opt<unsigned> MaxNumTargets(
    "Pmax-num-targets",
    llvm::cl::desc(
        "Do not resolve if number of targets is greater than this number."),
    llvm::cl::init(9999));

/*
* Resolve first C++ virtual calls by using a Class Hierarchy Analysis (CHA)
* before using seadsa.
**/
static llvm::cl::opt<bool>
    ResolveCallsByCHA("Pdevirt-with-cha",
                      llvm::cl::desc("Resolve virtual calls by using CHA "
                                     "(useful for C++ programs)"),
                      llvm::cl::init(false));

static llvm::cl::opt<bool> ResolveIncompleteCalls(
    "Presolve-incomplete-calls",
    llvm::cl::desc("Resolve indirect calls that might still require "
                   "further reasoning about other modules"
                   "(enable this option may be unsound)"),
    llvm::cl::init(false), llvm::cl::Hidden);

namespace previrt {
namespace transforms {

using namespace llvm;

/**
 ** Resolve indirect calls by one direct call for possible callee
 ** function
 **/
class DevirtualizeFunctionsPass : public ModulePass {
public:
  static char ID;

  DevirtualizeFunctionsPass() : ModulePass(ID) {
    // Initialize sea-dsa pass
    llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
    llvm::initializeCompleteCallGraphPass(Registry);
  }

  virtual bool runOnModule(Module &M) override {
    // -- Get the call graph
    // CallGraph* CG = &(getAnalysis<CallGraphWrapperPass> ().getCallGraph ());

    bool res = false;

    // -- Access to analysis pass which finds targets of indirect function calls
    DevirtualizeFunctions DF(/*CG*/ nullptr);

    if (ResolveCallsByCHA) {
      CallSiteResolverByCHA CSResolver(M);
      res |= DF.resolveCallSites(M, &CSResolver);
    }

    CallSiteResolverBySeaDsa CSResolver(
        M, getAnalysis<seadsa::CompleteCallGraph>(), ResolveIncompleteCalls,
        MaxNumTargets);
    res |= DF.resolveCallSites(M, &CSResolver);

    return res;
  }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
    // AU.addRequired<CallGraphWrapperPass>();
    AU.addRequired<seadsa::CompleteCallGraph>();
    // FIXME: DevirtualizeFunctions does not fully update the call
    // graph so we don't claim it's preserved.
    // AU.setPreservesAll();
    // AU.addPreserved<CallGraphWrapperPass>();
  }

  virtual StringRef getPassName() const override {
    return "Devirtualize indirect calls";
  }
};

// Currently unused but it might be useful in the future.
/** Annotate indirect calls with all possible callees.
 *
 *  For a given call site, the metadata, if present, indicates the
 *  set of functions the call site could possibly target at
 *  run-time.
 **/
class AnnotateIndirectCalls : public ModulePass {
public:
  static char ID;

  AnnotateIndirectCalls() : ModulePass(ID) {
    // Initialize sea-dsa pass
    llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
    llvm::initializeCompleteCallGraphPass(Registry);
  }

  virtual bool runOnModule(Module &M) override {
    bool change = false;

    CallSiteResolverBySeaDsa CallSiteResolver(
        M, getAnalysis<seadsa::CompleteCallGraph>(), ResolveIncompleteCalls,
        MaxNumTargets);
    MDBuilder MDB(M.getContext());

    for (auto &F : M) {
      for (auto &B : F) {
        for (auto &I : B) {
          if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
            CallSite CS(&I);
            if (CS.isIndirectCall()) {
              const SmallVector<const Function *, 16> *Targets =
                  CallSiteResolver.getTargets(CS);
              if (Targets) {
                std::vector<Function *> Callees;
                // remove constness
                for (const Function *CalleeF : *Targets) {
                  Callees.push_back(const_cast<Function *>(CalleeF));
                }
                MDNode *MDCallees = MDB.createCallees(Callees);
                I.setMetadata(LLVMContext::MD_callees, MDCallees);
                change = true;
              }
            }
          }
        }
      }
    }
    return change;
  }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.addRequired<seadsa::CompleteCallGraph>();
    AU.setPreservesAll();
  }

  virtual StringRef getPassName() const override {
    return "Annotate indirect calls with all possible callees";
  }
};

char DevirtualizeFunctionsPass::ID = 0;
char AnnotateIndirectCalls::ID = 0;

} // end namespace
} // end namespace

static llvm::RegisterPass<previrt::transforms::DevirtualizeFunctionsPass>
    X("Pdevirt",
      "Devirtualize indirect function calls by adding bounce functions");

static llvm::RegisterPass<previrt::transforms::AnnotateIndirectCalls>
    Y("Pannotate-indirect-calls",
      "Annotate indirect calls with metadata listing all possible callees");
<commit_msg>doc(DevirtFunctionsPass): fix description<commit_after>/**
 * LLVM transformation pass to resolve indirect calls
 *
 * The transformation performs "devirtualization" which consists of
 * looking for indirect function calls and transforming them into a
 * switch statement that selects one of several direct function calls
 * to execute. Devirtualization happens if a pointer analysis can
 * resolve the indirect calls and compute all possible callees.
 **/

#include "transforms/DevirtFunctions.hh"
#include "llvm/Pass.h"
//#include "llvm/Analysis/CallGraph.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "seadsa/CompleteCallGraph.hh"
#include "seadsa/InitializePasses.hh"

static llvm::cl::opt<unsigned> MaxNumTargets(
    "Pmax-num-targets",
    llvm::cl::desc(
        "Do not resolve if number of targets is greater than this number."),
    llvm::cl::init(9999));

/*
* Resolve first C++ virtual calls by using a Class Hierarchy Analysis (CHA)
* before using seadsa.
**/
static llvm::cl::opt<bool>
    ResolveCallsByCHA("Pdevirt-with-cha",
                      llvm::cl::desc("Resolve virtual calls by using CHA "
                                     "(useful for C++ programs)"),
                      llvm::cl::init(false));

static llvm::cl::opt<bool> ResolveIncompleteCalls(
    "Presolve-incomplete-calls",
    llvm::cl::desc("Resolve indirect calls that might still require "
                   "further reasoning about other modules"
                   "(enable this option may be unsound)"),
    llvm::cl::init(false), llvm::cl::Hidden);

namespace previrt {
namespace transforms {

using namespace llvm;

/**
 ** Resolve indirect calls by one direct call for possible callee
 ** function
 **/
class DevirtualizeFunctionsPass : public ModulePass {
public:
  static char ID;

  DevirtualizeFunctionsPass() : ModulePass(ID) {
    // Initialize sea-dsa pass
    llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
    llvm::initializeCompleteCallGraphPass(Registry);
  }

  virtual bool runOnModule(Module &M) override {
    // -- Get the call graph
    // CallGraph* CG = &(getAnalysis<CallGraphWrapperPass> ().getCallGraph ());

    bool res = false;

    // -- Access to analysis pass which finds targets of indirect function calls
    DevirtualizeFunctions DF(/*CG*/ nullptr);

    if (ResolveCallsByCHA) {
      CallSiteResolverByCHA CSResolver(M);
      res |= DF.resolveCallSites(M, &CSResolver);
    }

    CallSiteResolverBySeaDsa CSResolver(
        M, getAnalysis<seadsa::CompleteCallGraph>(), ResolveIncompleteCalls,
        MaxNumTargets);
    res |= DF.resolveCallSites(M, &CSResolver);

    return res;
  }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
    // AU.addRequired<CallGraphWrapperPass>();
    AU.addRequired<seadsa::CompleteCallGraph>();
    // FIXME: DevirtualizeFunctions does not fully update the call
    // graph so we don't claim it's preserved.
    // AU.setPreservesAll();
    // AU.addPreserved<CallGraphWrapperPass>();
  }

  virtual StringRef getPassName() const override {
    return "Devirtualize indirect calls";
  }
};

// Currently unused but it might be useful in the future.
/** Annotate indirect calls with all possible callees.
 *
 *  For a given call site, the metadata, if present, indicates the
 *  set of functions the call site could possibly target at
 *  run-time.
 **/
class AnnotateIndirectCalls : public ModulePass {
public:
  static char ID;

  AnnotateIndirectCalls() : ModulePass(ID) {
    // Initialize sea-dsa pass
    llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
    llvm::initializeCompleteCallGraphPass(Registry);
  }

  virtual bool runOnModule(Module &M) override {
    bool change = false;

    CallSiteResolverBySeaDsa CallSiteResolver(
        M, getAnalysis<seadsa::CompleteCallGraph>(), ResolveIncompleteCalls,
        MaxNumTargets);
    MDBuilder MDB(M.getContext());

    for (auto &F : M) {
      for (auto &B : F) {
        for (auto &I : B) {
          if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
            CallSite CS(&I);
            if (CS.isIndirectCall()) {
              const SmallVector<const Function *, 16> *Targets =
                  CallSiteResolver.getTargets(CS);
              if (Targets) {
                std::vector<Function *> Callees;
                // remove constness
                for (const Function *CalleeF : *Targets) {
                  Callees.push_back(const_cast<Function *>(CalleeF));
                }
                MDNode *MDCallees = MDB.createCallees(Callees);
                I.setMetadata(LLVMContext::MD_callees, MDCallees);
                change = true;
              }
            }
          }
        }
      }
    }
    return change;
  }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.addRequired<seadsa::CompleteCallGraph>();
    AU.setPreservesAll();
  }

  virtual StringRef getPassName() const override {
    return "Annotate indirect calls with all possible callees";
  }
};

char DevirtualizeFunctionsPass::ID = 0;
char AnnotateIndirectCalls::ID = 0;

} // end namespace
} // end namespace

static llvm::RegisterPass<previrt::transforms::DevirtualizeFunctionsPass>
    X("Pdevirt",
      "Devirtualize indirect function calls by adding multiple direct calls");

static llvm::RegisterPass<previrt::transforms::AnnotateIndirectCalls>
    Y("Pannotate-indirect-calls",
      "Annotate indirect calls with metadata listing all possible callees");
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2016 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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 OWNER 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.
 *
 ****************************************************************************/

/**
 * @file qshell.cpp
 * Listener for shell commands from posix
 *
 * @author Nicolas de Palezieux <ndepal@gmail.com>
 */

#include "qshell.h"

#include <px4_log.h>
#include <px4_tasks.h>
#include <px4_time.h>
#include <px4_posix.h>
#include <px4_middleware.h>
#include <dspal_platform.h>

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

#include "modules/uORB/uORB.h"
#include <drivers/drv_hrt.h>
#include "DriverFramework.hpp"

extern void init_app_map(std::map<std::string, px4_main_t> &apps);
extern void list_builtins(std::map<std::string, px4_main_t> &apps);

using std::map;
using std::string;

px4::AppState QShell::appState;

QShell::QShell()
{
	init_app_map(apps);
}

int QShell::main()
{
	int rc;
	appState.setRunning(true);
	int sub_qshell_req = orb_subscribe(ORB_ID(qshell_req));

	if (sub_qshell_req == PX4_ERROR) {
		PX4_ERR("Error subscribing to qshell_req topic");
		return -1;
	}

	int i = 0;

	while (!appState.exitRequested()) {
		bool updated = false;

		if (orb_check(sub_qshell_req, &updated) == 0) {
			if (updated) {
				PX4_DEBUG("[%d]qshell_req status is updated... reading new value", i);

				if (orb_copy(ORB_ID(qshell_req), sub_qshell_req, &m_qshell_req) != 0) {
					PX4_ERR("[%d]Error calling orb copy for qshell_req... ", i);
					break;
				}

				char current_char;
				std::string arg;
				std::vector<std::string> appargs;

				for (int str_idx = 0; str_idx < m_qshell_req.strlen; str_idx++) {
					current_char = m_qshell_req.string[str_idx];

					if (isspace(current_char)) { // split at spaces
						if (arg.length()) {
							appargs.push_back(arg);
							arg = "";
						}

					} else {
						arg += current_char;
					}
				}

				appargs.push_back(arg);  // push last argument

				int ret = run_cmd(appargs);

				if (ret) {
					PX4_ERR("Failed to execute command");
				}
			}

		} else {
			PX4_ERR("[%d]Error checking the updated status for qshell_req ", i);
			break;
		}

		// sleep for 1/2 sec.
		usleep(500000);

		++i;
	}

	return 0;
	appState.setRunning(false);
	return rc;
}

int QShell::run_cmd(const std::vector<std::string> &appargs)
{
	// command is appargs[0]
	std::string command = appargs[0];

	if (command.compare("help") == 0) {
		list_builtins(apps);
	}

	//replaces app.find with iterator code to avoid null pointer exception
	for (map<string, px4_main_t>::iterator it = apps.begin(); it != apps.end(); ++it) {
		if (it->first == command) {
			const char *arg[2 + 1];

			unsigned int i = 0;

			while (i < appargs.size() && appargs[i].c_str()[0] != '\0') {
				arg[i] = (char *)appargs[i].c_str();
				PX4_DEBUG("  arg%d = '%s'\n", i, arg[i]);
				++i;
			}

			arg[i] = (char *)0;

			//PX4_DEBUG_PRINTF(i);
			if (apps[command] == NULL) {
				PX4_ERR("Null function !!\n");

			} else {
				return apps[command](i, (char **)arg);
			}

		}
	}

	PX4_ERR("Command %s not found", command.c_str());
	return 1;
}
<commit_msg>Proper return value on qshell help<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2016 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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 OWNER 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.
 *
 ****************************************************************************/

/**
 * @file qshell.cpp
 * Listener for shell commands from posix
 *
 * @author Nicolas de Palezieux <ndepal@gmail.com>
 */

#include "qshell.h"

#include <px4_log.h>
#include <px4_tasks.h>
#include <px4_time.h>
#include <px4_posix.h>
#include <px4_middleware.h>
#include <dspal_platform.h>

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

#include "modules/uORB/uORB.h"
#include <drivers/drv_hrt.h>
#include "DriverFramework.hpp"

extern void init_app_map(std::map<std::string, px4_main_t> &apps);
extern void list_builtins(std::map<std::string, px4_main_t> &apps);

using std::map;
using std::string;

px4::AppState QShell::appState;

QShell::QShell()
{
	init_app_map(apps);
}

int QShell::main()
{
	int rc;
	appState.setRunning(true);
	int sub_qshell_req = orb_subscribe(ORB_ID(qshell_req));

	if (sub_qshell_req == PX4_ERROR) {
		PX4_ERR("Error subscribing to qshell_req topic");
		return -1;
	}

	int i = 0;

	while (!appState.exitRequested()) {
		bool updated = false;

		if (orb_check(sub_qshell_req, &updated) == 0) {
			if (updated) {
				PX4_DEBUG("[%d]qshell_req status is updated... reading new value", i);

				if (orb_copy(ORB_ID(qshell_req), sub_qshell_req, &m_qshell_req) != 0) {
					PX4_ERR("[%d]Error calling orb copy for qshell_req... ", i);
					break;
				}

				char current_char;
				std::string arg;
				std::vector<std::string> appargs;

				for (int str_idx = 0; str_idx < m_qshell_req.strlen; str_idx++) {
					current_char = m_qshell_req.string[str_idx];

					if (isspace(current_char)) { // split at spaces
						if (arg.length()) {
							appargs.push_back(arg);
							arg = "";
						}

					} else {
						arg += current_char;
					}
				}

				appargs.push_back(arg);  // push last argument

				int ret = run_cmd(appargs);

				if (ret) {
					PX4_ERR("Failed to execute command");
				}
			}

		} else {
			PX4_ERR("[%d]Error checking the updated status for qshell_req ", i);
			break;
		}

		// sleep for 1/2 sec.
		usleep(500000);

		++i;
	}

	return 0;
	appState.setRunning(false);
	return rc;
}

int QShell::run_cmd(const std::vector<std::string> &appargs)
{
	// command is appargs[0]
	std::string command = appargs[0];

	if (command.compare("help") == 0) {
		list_builtins(apps);
		return 0;
	}

	//replaces app.find with iterator code to avoid null pointer exception
	for (map<string, px4_main_t>::iterator it = apps.begin(); it != apps.end(); ++it) {
		if (it->first == command) {
			const char *arg[2 + 1];

			unsigned int i = 0;

			while (i < appargs.size() && appargs[i].c_str()[0] != '\0') {
				arg[i] = (char *)appargs[i].c_str();
				PX4_DEBUG("  arg%d = '%s'\n", i, arg[i]);
				++i;
			}

			arg[i] = (char *)0;

			//PX4_DEBUG_PRINTF(i);
			if (apps[command] == NULL) {
				PX4_ERR("Null function !!\n");

			} else {
				return apps[command](i, (char **)arg);
			}

		}
	}

	PX4_ERR("Command %s not found", command.c_str());
	return 1;
}
<|endoftext|>


<commit_before>/*
 * ClusterContracter.cpp
 *
 *  Created on: 30.10.2012
 *      Author: Christian Staudt (christian.staudt@kit.edu)
 */

#include "ClusterContracter.h"

namespace NetworKit {

ClusterContracter::ClusterContracter() {
	// TODO Auto-generated constructor stub

}

ClusterContracter::~ClusterContracter() {
	// TODO Auto-generated destructor stub
}

std::pair<Graph, NodeMap<node> > ClusterContracter::run(Graph& G, Clustering& zeta) {

	Graph Gcon(0); // empty graph
	Gcon.markAsWeighted(); // Gcon will be a weighted graph

	IndexMap<cluster, node> clusterToSuperNode(zeta.upperBound(), none); // there is one supernode for each cluster

	// populate map cluster -> supernode
	G.forNodes([&](node v){
		cluster c = zeta.clusterOf(v);
		if (! clusterToSuperNode.hasBeenSet(c)) {
			clusterToSuperNode[c] = Gcon.addNode(); // TODO: probably does not scale well, think about allocating ranges of nodes
		}
	});

	int64_t n = G.numberOfNodes();
	NodeMap<node> nodeToSuperNode(n);

	// set entries node -> supernode
	G.parallelForNodes([&](node v){
		nodeToSuperNode[v] = clusterToSuperNode[zeta.clusterOf(v)];
	});

	// iterate over edges of G and create edges in Gcon or update edge and node weights in Gcon
	G.forWeightedEdges([&](node u, node v, edgeweight ew) {
		node su = nodeToSuperNode[u];
		node sv = nodeToSuperNode[v];
		if (zeta.clusterOf(u) == zeta.clusterOf(v)) {
			// add edge weight to supernode (self-loop) weight
			Gcon.setWeight(su, su, Gcon.weight(su, su) + ew);
		} else {
			// add edge weight to weight between two supernodes (or insert edge)
			Gcon.setWeight(su, sv, Gcon.weight(su, sv) + ew);
		}
	}); // TODO: parallel?

	return std::make_pair(Gcon, nodeToSuperNode);

}

}
<commit_msg>bugfix TRACE<commit_after>/*
 * ClusterContracter.cpp
 *
 *  Created on: 30.10.2012
 *      Author: Christian Staudt (christian.staudt@kit.edu)
 */

#include "ClusterContracter.h"

namespace NetworKit {

ClusterContracter::ClusterContracter() {
	// TODO Auto-generated constructor stub

}

ClusterContracter::~ClusterContracter() {
	// TODO Auto-generated destructor stub
}

std::pair<Graph, NodeMap<node> > ClusterContracter::run(Graph& G, Clustering& zeta) {

	Graph Gcon(0); // empty graph
	Gcon.markAsWeighted(); // Gcon will be a weighted graph

	IndexMap<cluster, node> clusterToSuperNode(zeta.upperBound(), none); // there is one supernode for each cluster

	// populate map cluster -> supernode
	G.forNodes([&](node v){
		cluster c = zeta.clusterOf(v);
		if (! clusterToSuperNode.hasBeenSet(c)) {
			clusterToSuperNode[c] = Gcon.addNode(); // TODO: probably does not scale well, think about allocating ranges of nodes
		}
	});

	int64_t n = G.numberOfNodes();
	NodeMap<node> nodeToSuperNode(n);

	// set entries node -> supernode
	G.parallelForNodes([&](node v){
		nodeToSuperNode[v] = clusterToSuperNode[zeta.clusterOf(v)];
	});

	// iterate over edges of G and create edges in Gcon or update edge and node weights in Gcon
	G.forWeightedEdges([&](node u, node v, edgeweight ew) {
		node su = nodeToSuperNode[u];
		node sv = nodeToSuperNode[v];
		TRACE("edge (", su, ", ", sv, ")");
		if (zeta.clusterOf(u) == zeta.clusterOf(v)) {
			// add edge weight to supernode (self-loop) weight
			Gcon.setWeight(su, su, Gcon.weight(su, su) + ew);
		} else {
			// add edge weight to weight between two supernodes (or insert edge)
			Gcon.setWeight(su, sv, Gcon.weight(su, sv) + ew);
		}
	}); // TODO: parallel?

	return std::make_pair(Gcon, nodeToSuperNode);

}

}
<|endoftext|>