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

#include "common/scene_subdiv_mesh.h"
#include "subdivpatch1base.h"
#include "common/scene.h"

namespace embree
{

    // if (grid_size_simd_blocks == 1)
    //   {
    //     mic_m m_active = 0xffff;
    //     for (unsigned int i=grid_u_res-1;i<16;i+=grid_u_res)
    //       m_active ^= (unsigned int)1 << i;
    //     m_active &= ((unsigned int)1 << (grid_u_res * (grid_v_res-1)))-1;
    //     grid_mask = m_active;
    //   }

  void SubdivPatch1Base::updateEdgeLevels(const float edge_level[4],const SubdivMesh *const mesh)
  {
    /* init discrete edge tessellation levels and grid resolution */

    assert( edge_level[0] >= 0.0f );
    assert( edge_level[1] >= 0.0f );
    assert( edge_level[2] >= 0.0f );
    assert( edge_level[3] >= 0.0f );

    level[0] = max(ceilf(edge_level[0]),1.0f);
    level[1] = max(ceilf(edge_level[1]),1.0f);
    level[2] = max(ceilf(edge_level[2]),1.0f);
    level[3] = max(ceilf(edge_level[3]),1.0f);

    grid_u_res = max(level[0],level[2])+1; // n segments -> n+1 points
    grid_v_res = max(level[1],level[3])+1;

#if defined(__MIC__)
    grid_size_simd_blocks        = ((grid_u_res*grid_v_res+15)&(-16)) / 16;
    grid_subtree_size_64b_blocks = 5; // single leaf with u,v,x,y,z
#else
    /* 8-wide SIMD is default on Xeon */
    grid_size_simd_blocks        = ((grid_u_res*grid_v_res+7)&(-8)) / 8;
    grid_subtree_size_64b_blocks = (sizeof(Quad2x2)+63) / 64; // single Quad2x2

#endif
    /* need stiching? */

    flags &= ~TRANSITION_PATCH;

    const unsigned int int_edge_points0 = (unsigned int)level[0] + 1;
    const unsigned int int_edge_points1 = (unsigned int)level[1] + 1;
    const unsigned int int_edge_points2 = (unsigned int)level[2] + 1;
    const unsigned int int_edge_points3 = (unsigned int)level[3] + 1;

    if (int_edge_points0 < (unsigned int)grid_u_res ||
	int_edge_points2 < (unsigned int)grid_u_res ||
	int_edge_points1 < (unsigned int)grid_v_res ||
	int_edge_points3 < (unsigned int)grid_v_res)
      flags |= TRANSITION_PATCH;

    /* tessellate into grid blocks for larger grid resolutions, generate bvh4 subtree over grid blocks*/

#if defined(__MIC__)
    const size_t leafBlocks = 4;
#else
    const size_t leafBlocks = (sizeof(Quad2x2)+63) / 64;
#endif

    grid_bvh_size_64b_blocks = getSubTreeSize64bBlocks( 0 );

#if COMPACT == 1
    const size_t grid_size_xyzuv = (grid_size_simd_blocks * 8) * 4;
    grid_subtree_size_64b_blocks = grid_bvh_size_64b_blocks + (grid_size_xyzuv / 16);
#else
    grid_subtree_size_64b_blocks = getSubTreeSize64bBlocks( leafBlocks ); // u,v,x,y,z
#endif

    /* has displacements? */
    flags &= ~HAS_DISPLACEMENT;
    if (mesh->displFunc != NULL)
      flags |= HAS_DISPLACEMENT;

  }

  /*! Construction from vertices and IDs. */
  SubdivPatch1Base::SubdivPatch1Base (const CatmullClarkPatch& ipatch,
                                      const unsigned int gID,
                                      const unsigned int pID,
                                      const SubdivMesh *const mesh,
                                      const Vec2f uv[4],
                                      const float edge_level[4])
    : geom(gID),
      prim(pID),
      flags(0),
      root_ref(0)
  {
    assert(sizeof(SubdivPatch1Base) == 5 * 64);
    mtx.reset();

    for (size_t i=0;i<4;i++)
      {
        /* need to reverse input here */
        u[i] = (unsigned short)(uv[i].y * 65535.0f);
        v[i] = (unsigned short)(uv[i].x * 65535.0f);
      }

    updateEdgeLevels(edge_level,mesh);

    /* determine whether patch is regular or not */

    if (ipatch.isRegularOrFinal(0) && mesh->displFunc == NULL)
      {
        flags |= REGULAR_PATCH;
        patch.init( ipatch );
      }
    else
      {
        GregoryPatch gpatch;
        gpatch.init( ipatch );
        gpatch.exportDenseConrolPoints( patch.v );
      }
#if 0
    DBG_PRINT( grid_u_res );
    DBG_PRINT( grid_v_res );
    DBG_PRINT( grid_size_16wide_blocks );
    DBG_PRINT( grid_mask );
    DBG_PRINT( grid_subtree_size_64b_blocks );
#endif

  }

  void SubdivPatch1Base::evalToOBJ(Scene *scene,size_t &vertex_index)
  {
#if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
    __aligned(64) float grid_x[(grid_size_simd_blocks+1)*8];
    __aligned(64) float grid_y[(grid_size_simd_blocks+1)*8];
    __aligned(64) float grid_z[(grid_size_simd_blocks+1)*8];

    __aligned(64) float grid_u[(grid_size_simd_blocks+1)*8];
    __aligned(64) float grid_v[(grid_size_simd_blocks+1)*8];

#else
      const size_t array_elements = (patch.grid_size_simd_blocks + 1) * 8;
      float *const ptr = (float*)_malloca(5 * array_elements * sizeof(float) + 64);
      float *const grid_arrays = (float*)ALIGN_PTR(ptr,64);

      float *grid_x = &grid_arrays[array_elements * 0];
      float *grid_y = &grid_arrays[array_elements * 1];
      float *grid_z = &grid_arrays[array_elements * 2];
      float *grid_u = &grid_arrays[array_elements * 3];
      float *grid_v = &grid_arrays[array_elements * 4];
#endif
      SubdivMesh *mesh = (SubdivMesh *)scene->getSubdivMesh(geom);

      evalGrid(*this,grid_x,grid_y,grid_z,grid_u,grid_v,mesh);

      for (size_t v=0;v<grid_v_res;v++)
        for (size_t u=0;u<grid_u_res;u++)
          {
            size_t offset = v * grid_u_res + u;
            std::cout << "v " << grid_x[offset] << " " << grid_y[offset] << " " << grid_z[offset] << std::endl;
          }

      for (size_t v=0;v<grid_v_res-1;v++)
        for (size_t u=0;u<grid_u_res-1;u++)
          {
            size_t offset0 = vertex_index + v * grid_u_res + u;
            size_t offset1 = vertex_index + offset0 + grid_u_res;
            std::cout << "f " << offset0+1 << " " << offset0+2 << " " << offset1+2 << " " << offset1+1 << std::endl;
          }
      vertex_index += grid_u_res*grid_v_res;

#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
      _freea(ptr);
#endif

  }

}
<commit_msg>fixed compile bug<commit_after>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "common/scene_subdiv_mesh.h"
#include "subdivpatch1base.h"
#include "common/scene.h"

namespace embree
{

    // if (grid_size_simd_blocks == 1)
    //   {
    //     mic_m m_active = 0xffff;
    //     for (unsigned int i=grid_u_res-1;i<16;i+=grid_u_res)
    //       m_active ^= (unsigned int)1 << i;
    //     m_active &= ((unsigned int)1 << (grid_u_res * (grid_v_res-1)))-1;
    //     grid_mask = m_active;
    //   }

  void SubdivPatch1Base::updateEdgeLevels(const float edge_level[4],const SubdivMesh *const mesh)
  {
    /* init discrete edge tessellation levels and grid resolution */

    assert( edge_level[0] >= 0.0f );
    assert( edge_level[1] >= 0.0f );
    assert( edge_level[2] >= 0.0f );
    assert( edge_level[3] >= 0.0f );

    level[0] = max(ceilf(edge_level[0]),1.0f);
    level[1] = max(ceilf(edge_level[1]),1.0f);
    level[2] = max(ceilf(edge_level[2]),1.0f);
    level[3] = max(ceilf(edge_level[3]),1.0f);

    grid_u_res = max(level[0],level[2])+1; // n segments -> n+1 points
    grid_v_res = max(level[1],level[3])+1;

#if defined(__MIC__)
    grid_size_simd_blocks        = ((grid_u_res*grid_v_res+15)&(-16)) / 16;
    grid_subtree_size_64b_blocks = 5; // single leaf with u,v,x,y,z
#else
    /* 8-wide SIMD is default on Xeon */
    grid_size_simd_blocks        = ((grid_u_res*grid_v_res+7)&(-8)) / 8;
    grid_subtree_size_64b_blocks = (sizeof(Quad2x2)+63) / 64; // single Quad2x2

#endif
    /* need stiching? */

    flags &= ~TRANSITION_PATCH;

    const unsigned int int_edge_points0 = (unsigned int)level[0] + 1;
    const unsigned int int_edge_points1 = (unsigned int)level[1] + 1;
    const unsigned int int_edge_points2 = (unsigned int)level[2] + 1;
    const unsigned int int_edge_points3 = (unsigned int)level[3] + 1;

    if (int_edge_points0 < (unsigned int)grid_u_res ||
	int_edge_points2 < (unsigned int)grid_u_res ||
	int_edge_points1 < (unsigned int)grid_v_res ||
	int_edge_points3 < (unsigned int)grid_v_res)
      flags |= TRANSITION_PATCH;

    /* tessellate into grid blocks for larger grid resolutions, generate bvh4 subtree over grid blocks*/

#if defined(__MIC__)
    const size_t leafBlocks = 4;
#else
    const size_t leafBlocks = (sizeof(Quad2x2)+63) / 64;
#endif

    grid_bvh_size_64b_blocks = getSubTreeSize64bBlocks( 0 );

#if COMPACT == 1
    const size_t grid_size_xyzuv = (grid_size_simd_blocks * 8) * 4;
    grid_subtree_size_64b_blocks = grid_bvh_size_64b_blocks + (grid_size_xyzuv / 16);
#else
    grid_subtree_size_64b_blocks = getSubTreeSize64bBlocks( leafBlocks ); // u,v,x,y,z
#endif

    /* has displacements? */
    flags &= ~HAS_DISPLACEMENT;
    if (mesh->displFunc != NULL)
      flags |= HAS_DISPLACEMENT;

  }

  /*! Construction from vertices and IDs. */
  SubdivPatch1Base::SubdivPatch1Base (const CatmullClarkPatch& ipatch,
                                      const unsigned int gID,
                                      const unsigned int pID,
                                      const SubdivMesh *const mesh,
                                      const Vec2f uv[4],
                                      const float edge_level[4])
    : geom(gID),
      prim(pID),
      flags(0),
      root_ref(0)
  {
    assert(sizeof(SubdivPatch1Base) == 5 * 64);
    mtx.reset();

    for (size_t i=0;i<4;i++)
      {
        /* need to reverse input here */
        u[i] = (unsigned short)(uv[i].y * 65535.0f);
        v[i] = (unsigned short)(uv[i].x * 65535.0f);
      }

    updateEdgeLevels(edge_level,mesh);

    /* determine whether patch is regular or not */

    if (ipatch.isRegularOrFinal(0) && mesh->displFunc == NULL)
      {
        flags |= REGULAR_PATCH;
        patch.init( ipatch );
      }
    else
      {
        GregoryPatch gpatch;
        gpatch.init( ipatch );
        gpatch.exportDenseConrolPoints( patch.v );
      }
#if 0
    DBG_PRINT( grid_u_res );
    DBG_PRINT( grid_v_res );
    DBG_PRINT( grid_size_16wide_blocks );
    DBG_PRINT( grid_mask );
    DBG_PRINT( grid_subtree_size_64b_blocks );
#endif

  }

  void SubdivPatch1Base::evalToOBJ(Scene *scene,size_t &vertex_index)
  {
#if defined(__MIC__)
    FATAL("EVALTOOBJ NOT SUPPORTED ON MIC");
#else

#if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
    __aligned(64) float grid_x[(grid_size_simd_blocks+1)*8];
    __aligned(64) float grid_y[(grid_size_simd_blocks+1)*8];
    __aligned(64) float grid_z[(grid_size_simd_blocks+1)*8];

    __aligned(64) float grid_u[(grid_size_simd_blocks+1)*8];
    __aligned(64) float grid_v[(grid_size_simd_blocks+1)*8];

#else
      const size_t array_elements = (patch.grid_size_simd_blocks + 1) * 8;
      float *const ptr = (float*)_malloca(5 * array_elements * sizeof(float) + 64);
      float *const grid_arrays = (float*)ALIGN_PTR(ptr,64);

      float *grid_x = &grid_arrays[array_elements * 0];
      float *grid_y = &grid_arrays[array_elements * 1];
      float *grid_z = &grid_arrays[array_elements * 2];
      float *grid_u = &grid_arrays[array_elements * 3];
      float *grid_v = &grid_arrays[array_elements * 4];
#endif
      SubdivMesh *mesh = (SubdivMesh *)scene->getSubdivMesh(geom);

      evalGrid(*this,grid_x,grid_y,grid_z,grid_u,grid_v,mesh);

      for (size_t v=0;v<grid_v_res;v++)
        for (size_t u=0;u<grid_u_res;u++)
          {
            size_t offset = v * grid_u_res + u;
            std::cout << "v " << grid_x[offset] << " " << grid_y[offset] << " " << grid_z[offset] << std::endl;
          }

      for (size_t v=0;v<grid_v_res-1;v++)
        for (size_t u=0;u<grid_u_res-1;u++)
          {
            size_t offset0 = vertex_index + v * grid_u_res + u;
            size_t offset1 = vertex_index + offset0 + grid_u_res;
            std::cout << "f " << offset0+1 << " " << offset0+2 << " " << offset1+2 << " " << offset1+1 << std::endl;
          }
      vertex_index += grid_u_res*grid_v_res;

#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
      _freea(ptr);
#endif

#endif
  }

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef otbTrainLibSVM_hxx
#define otbTrainLibSVM_hxx
#include "otbLearningApplicationBase.h"
#include "otbLibSVMMachineLearningModel.h"

namespace otb
{
namespace Wrapper
{

template <class TInputValue, class TOutputValue>
void LearningApplicationBase<TInputValue, TOutputValue>::InitLibSVMParams()
{
  AddChoice("classifier.libsvm", "LibSVM classifier");
  SetParameterDescription("classifier.libsvm", "This group of parameters allows setting SVM classifier parameters.");
  AddParameter(ParameterType_Choice, "classifier.libsvm.k", "SVM Kernel Type");
  AddChoice("classifier.libsvm.k.linear", "Linear");
  SetParameterDescription("classifier.libsvm.k.linear", "Linear Kernel, no mapping is done, this is the fastest option.");

  AddChoice("classifier.libsvm.k.rbf", "Gaussian radial basis function");
  SetParameterDescription("classifier.libsvm.k.rbf",
                          "This kernel is a good choice in most of the case. It is "
                          "an exponential function of the euclidian distance between "
                          "the vectors.");

  AddChoice("classifier.libsvm.k.poly", "Polynomial");
  SetParameterDescription("classifier.libsvm.k.poly", "Polynomial Kernel, the mapping is a polynomial function.");

  AddChoice("classifier.libsvm.k.sigmoid", "Sigmoid");
  SetParameterDescription("classifier.libsvm.k.sigmoid", "The kernel is a hyperbolic tangente function of the vectors.");

  SetParameterString("classifier.libsvm.k", "linear");
  SetParameterDescription("classifier.libsvm.k", "SVM Kernel Type.");
  AddParameter(ParameterType_Choice, "classifier.libsvm.m", "SVM Model Type");
  SetParameterDescription("classifier.libsvm.m", "Type of SVM formulation.");
  if (this->m_RegressionFlag)
  {
    AddChoice("classifier.libsvm.m.epssvr", "Epsilon Support Vector Regression");
    SetParameterDescription("classifier.libsvm.m.epssvr",
                            "The distance between feature vectors from the training set and the "
                            "fitting hyper-plane must be less than Epsilon. For outliers the penalty "
                            "multiplier C is used ");

    AddChoice("classifier.libsvm.m.nusvr", "Nu Support Vector Regression");
    SetParameterString("classifier.libsvm.m", "epssvr");
    SetParameterDescription("classifier.libsvm.m.nusvr",
                            "Same as the epsilon regression except that this time the bounded "
                            "parameter nu is used instead of epsilon");
  }
  else
  {
    AddChoice("classifier.libsvm.m.csvc", "C support vector classification");
    SetParameterDescription("classifier.libsvm.m.csvc",
                            "This formulation allows imperfect separation of classes. The penalty "
                            "is set through the cost parameter C.");

    AddChoice("classifier.libsvm.m.nusvc", "Nu support vector classification");
    SetParameterDescription("classifier.libsvm.m.nusvc",
                            "This formulation allows imperfect separation of classes. The penalty "
                            "is set through the cost parameter Nu. As compared to C, Nu is harder "
                            "to optimize, and may not be as fast.");

    AddChoice("classifier.libsvm.m.oneclass", "Distribution estimation (One Class SVM)");
    SetParameterDescription("classifier.libsvm.m.oneclass",
                            "All the training data are from the same class, SVM builds a boundary "
                            "that separates the class from the rest of the feature space.");
    SetParameterString("classifier.libsvm.m", "csvc");
  }

  AddParameter(ParameterType_Float, "classifier.libsvm.c", "Cost parameter C");
  SetParameterFloat("classifier.libsvm.c", 1.0);
  SetParameterDescription("classifier.libsvm.c",
                          "SVM models have a cost parameter C (1 by default) to control the "
                          "trade-off between training errors and forcing rigid margins.");

  AddParameter(ParameterType_Float, "classifier.libsvm.nu", "Cost parameter Nu");
  SetParameterFloat("classifier.libsvm.nu", 0.5);
  SetParameterDescription("classifier.libsvm.nu",
                          "Cost parameter Nu, in the range 0..1, the larger the value, "
                          "the smoother the decision.");

  // It seems that it miss a nu parameter for the nu-SVM use.
  AddParameter(ParameterType_Bool, "classifier.libsvm.opt", "Parameters optimization");
  SetParameterDescription("classifier.libsvm.opt", "SVM parameters optimization flag.");

  AddParameter(ParameterType_Bool, "classifier.libsvm.prob", "Probability estimation");
  SetParameterDescription("classifier.libsvm.prob", "Probability estimation flag.");

  if (this->m_RegressionFlag)
  {
    AddParameter(ParameterType_Float, "classifier.libsvm.eps", "Epsilon");
    SetParameterFloat("classifier.libsvm.eps", 1e-3);
    SetParameterDescription("classifier.libsvm.eps",
                            "The distance between feature vectors from the training set and "
                            "the fitting hyper-plane must be less than Epsilon. For outliers"
                            "the penalty mutliplier is set by C.");
  }
}

template <class TInputValue, class TOutputValue>
void LearningApplicationBase<TInputValue, TOutputValue>::TrainLibSVM(typename ListSampleType::Pointer trainingListSample,
                                                                     typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath)
{
  typedef otb::LibSVMMachineLearningModel<InputValueType, OutputValueType> LibSVMType;
  typename LibSVMType::Pointer libSVMClassifier = LibSVMType::New();
  libSVMClassifier->SetRegressionMode(this->m_RegressionFlag);
  libSVMClassifier->SetInputListSample(trainingListSample);
  libSVMClassifier->SetTargetListSample(trainingLabeledListSample);
  // SVM Option
  // TODO : Add other options ?
  libSVMClassifier->SetParameterOptimization(GetParameterInt("classifier.libsvm.opt"));
  libSVMClassifier->SetDoProbabilityEstimates(GetParameterInt("classifier.libsvm.prob"));
  libSVMClassifier->SetNu(GetParameterFloat("classifier.libsvm.nu"));
  libSVMClassifier->SetC(GetParameterFloat("classifier.libsvm.c"));

  switch (GetParameterInt("classifier.libsvm.k"))
  {
  case 0: // LINEAR
    libSVMClassifier->SetKernelType(LINEAR);
    break;
  case 1: // RBF
    libSVMClassifier->SetKernelType(RBF);
    break;
  case 2: // POLY
    libSVMClassifier->SetKernelType(POLY);
    break;
  case 3: // SIGMOID
    libSVMClassifier->SetKernelType(SIGMOID);
    break;
  default: // DEFAULT = LINEAR
    libSVMClassifier->SetKernelType(LINEAR);
    break;
  }
  if (this->m_RegressionFlag)
  {
    switch (GetParameterInt("classifier.libsvm.m"))
    {
    case 0: // EPSILON_SVR
      libSVMClassifier->SetSVMType(EPSILON_SVR);
      break;
    case 1: // NU_SVR
      libSVMClassifier->SetSVMType(NU_SVR);
      break;
    default:
      libSVMClassifier->SetSVMType(EPSILON_SVR);
      break;
    }
    libSVMClassifier->SetEpsilon(GetParameterFloat("classifier.libsvm.eps"));
  }
  else
  {
    switch (GetParameterInt("classifier.libsvm.m"))
    {
    case 0: // C_SVC
      libSVMClassifier->SetSVMType(C_SVC);
      break;
    case 1: // NU_SVC
      libSVMClassifier->SetSVMType(NU_SVC);
      break;
    case 2: // ONE_CLASS
      libSVMClassifier->SetSVMType(ONE_CLASS);
      break;
    default:
      libSVMClassifier->SetSVMType(C_SVC);
      break;
    }
  }

  libSVMClassifier->Train();
  libSVMClassifier->Save(modelPath);
}

} // end namespace wrapper
} // end namespace otb

#endif
<commit_msg>Resolve "Missing kernels parameters in libsvm"<commit_after>/*
 * Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef otbTrainLibSVM_hxx
#define otbTrainLibSVM_hxx
#include "otbLearningApplicationBase.h"
#include "otbLibSVMMachineLearningModel.h"

namespace otb
{
namespace Wrapper
{

template <class TInputValue, class TOutputValue>
void LearningApplicationBase<TInputValue, TOutputValue>::InitLibSVMParams()
{
  AddChoice("classifier.libsvm", "LibSVM classifier");
  SetParameterDescription("classifier.libsvm", "This group of parameters allows setting SVM classifier parameters.");
  AddParameter(ParameterType_Choice, "classifier.libsvm.k", "SVM Kernel Type");
  AddChoice("classifier.libsvm.k.linear", "Linear");
  SetParameterDescription("classifier.libsvm.k.linear", "Linear Kernel, no mapping is done, this is the fastest option.");

  AddChoice("classifier.libsvm.k.rbf", "Gaussian radial basis function");
  SetParameterDescription("classifier.libsvm.k.rbf",
                          "This kernel is a good choice in most of the case. It is "
                          "an exponential function of the euclidian distance between "
                          "the vectors.");

  AddChoice("classifier.libsvm.k.poly", "Polynomial");
  SetParameterDescription("classifier.libsvm.k.poly", "Polynomial Kernel, the mapping is a polynomial function.");

  AddChoice("classifier.libsvm.k.sigmoid", "Sigmoid");
  SetParameterDescription("classifier.libsvm.k.sigmoid", "The kernel is a hyperbolic tangente function of the vectors.");

  SetParameterString("classifier.libsvm.k", "linear");
  SetParameterDescription("classifier.libsvm.k", "SVM Kernel Type.");
  AddParameter(ParameterType_Choice, "classifier.libsvm.m", "SVM Model Type");
  SetParameterDescription("classifier.libsvm.m", "Type of SVM formulation.");
  if (this->m_RegressionFlag)
  {
    AddChoice("classifier.libsvm.m.epssvr", "Epsilon Support Vector Regression");
    SetParameterDescription("classifier.libsvm.m.epssvr",
                            "The distance between feature vectors from the training set and the "
                            "fitting hyper-plane must be less than Epsilon. For outliers the penalty "
                            "multiplier C is used ");

    AddChoice("classifier.libsvm.m.nusvr", "Nu Support Vector Regression");
    SetParameterString("classifier.libsvm.m", "epssvr");
    SetParameterDescription("classifier.libsvm.m.nusvr",
                            "Same as the epsilon regression except that this time the bounded "
                            "parameter nu is used instead of epsilon");
  }
  else
  {
    AddChoice("classifier.libsvm.m.csvc", "C support vector classification");
    SetParameterDescription("classifier.libsvm.m.csvc",
                            "This formulation allows imperfect separation of classes. The penalty "
                            "is set through the cost parameter C.");

    AddChoice("classifier.libsvm.m.nusvc", "Nu support vector classification");
    SetParameterDescription("classifier.libsvm.m.nusvc",
                            "This formulation allows imperfect separation of classes. The penalty "
                            "is set through the cost parameter Nu. As compared to C, Nu is harder "
                            "to optimize, and may not be as fast.");

    AddChoice("classifier.libsvm.m.oneclass", "Distribution estimation (One Class SVM)");
    SetParameterDescription("classifier.libsvm.m.oneclass",
                            "All the training data are from the same class, SVM builds a boundary "
                            "that separates the class from the rest of the feature space.");
    SetParameterString("classifier.libsvm.m", "csvc");
  }

  AddParameter(ParameterType_Float, "classifier.libsvm.c", "Cost parameter C");
  SetParameterFloat("classifier.libsvm.c", 1.0);
  SetParameterDescription("classifier.libsvm.c",
                          "SVM models have a cost parameter C (1 by default) to control the "
                          "trade-off between training errors and forcing rigid margins.");

  AddParameter(ParameterType_Float, "classifier.libsvm.gamma", "Gamma parameter");
  SetParameterFloat("classifier.libsvm.gamma", 1.0);
  SetMinimumParameterFloatValue("classifier.libsvm.gamma", 0.0);
  SetParameterDescription("classifier.libsvm.gamma", "Set gamma parameter in poly/rbf/sigmoid kernel function");

  AddParameter(ParameterType_Float, "classifier.libsvm.coef0", "Coefficient parameter");
  SetParameterFloat("classifier.libsvm.coef0", 0.0);
  SetParameterDescription("classifier.libsvm.coef0", "Set coef0 parameter in poly/sigmoid kernel function");

  AddParameter(ParameterType_Int, "classifier.libsvm.degree", "Degree parameter");
  SetParameterInt("classifier.libsvm.degree", 3);
  SetMinimumParameterIntValue("classifier.libsvm.degree", 1);
  SetParameterDescription("classifier.libsvm.degree", "Set polynomial degree in poly kernel function");

  AddParameter(ParameterType_Float, "classifier.libsvm.nu", "Cost parameter Nu");
  SetParameterFloat("classifier.libsvm.nu", 0.5);
  SetParameterDescription("classifier.libsvm.nu",
                          "Cost parameter Nu, in the range 0..1, the larger the value, "
                          "the smoother the decision.");

  // It seems that it miss a nu parameter for the nu-SVM use.
  AddParameter(ParameterType_Bool, "classifier.libsvm.opt", "Parameters optimization");
  SetParameterDescription("classifier.libsvm.opt", "SVM parameters optimization flag.");

  AddParameter(ParameterType_Bool, "classifier.libsvm.prob", "Probability estimation");
  SetParameterDescription("classifier.libsvm.prob", "Probability estimation flag.");

  if (this->m_RegressionFlag)
  {
    AddParameter(ParameterType_Float, "classifier.libsvm.eps", "Epsilon");
    SetParameterFloat("classifier.libsvm.eps", 1e-3);
    SetParameterDescription("classifier.libsvm.eps",
                            "The distance between feature vectors from the training set and "
                            "the fitting hyper-plane must be less than Epsilon. For outliers"
                            "the penalty mutliplier is set by C.");
  }
}

template <class TInputValue, class TOutputValue>
void LearningApplicationBase<TInputValue, TOutputValue>::TrainLibSVM(typename ListSampleType::Pointer trainingListSample,
                                                                     typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath)
{
  typedef otb::LibSVMMachineLearningModel<InputValueType, OutputValueType> LibSVMType;
  typename LibSVMType::Pointer libSVMClassifier = LibSVMType::New();
  libSVMClassifier->SetRegressionMode(this->m_RegressionFlag);
  libSVMClassifier->SetInputListSample(trainingListSample);
  libSVMClassifier->SetTargetListSample(trainingLabeledListSample);
  // SVM Option
  // TODO : Add other options ?
  libSVMClassifier->SetParameterOptimization(GetParameterInt("classifier.libsvm.opt"));
  libSVMClassifier->SetDoProbabilityEstimates(GetParameterInt("classifier.libsvm.prob"));
  libSVMClassifier->SetNu(GetParameterFloat("classifier.libsvm.nu"));
  libSVMClassifier->SetC(GetParameterFloat("classifier.libsvm.c"));

  switch (GetParameterInt("classifier.libsvm.k"))
  {
  case 0: // LINEAR
    libSVMClassifier->SetKernelType(LINEAR);
    break;
  case 1: // RBF
    libSVMClassifier->SetKernelType(RBF);
    libSVMClassifier->SetKernelGamma(GetParameterFloat("classifier.libsvm.gamma"));
    break;
  case 2: // POLY
    libSVMClassifier->SetKernelType(POLY);
    libSVMClassifier->SetKernelGamma(GetParameterFloat("classifier.libsvm.gamma"));
    libSVMClassifier->SetKernelCoef0(GetParameterFloat("classifier.libsvm.coef0"));
    libSVMClassifier->SetPolynomialKernelDegree(GetParameterInt("classifier.libsvm.degree"));
    break;
  case 3: // SIGMOID
    libSVMClassifier->SetKernelType(SIGMOID);
    libSVMClassifier->SetKernelGamma(GetParameterFloat("classifier.libsvm.gamma"));
    libSVMClassifier->SetKernelCoef0(GetParameterFloat("classifier.libsvm.coef0"));
    break;
  default: // DEFAULT = LINEAR
    libSVMClassifier->SetKernelType(LINEAR);
    break;
  }
  if (this->m_RegressionFlag)
  {
    switch (GetParameterInt("classifier.libsvm.m"))
    {
    case 0: // EPSILON_SVR
      libSVMClassifier->SetSVMType(EPSILON_SVR);
      break;
    case 1: // NU_SVR
      libSVMClassifier->SetSVMType(NU_SVR);
      break;
    default:
      libSVMClassifier->SetSVMType(EPSILON_SVR);
      break;
    }
    libSVMClassifier->SetEpsilon(GetParameterFloat("classifier.libsvm.eps"));
  }
  else
  {
    switch (GetParameterInt("classifier.libsvm.m"))
    {
    case 0: // C_SVC
      libSVMClassifier->SetSVMType(C_SVC);
      break;
    case 1: // NU_SVC
      libSVMClassifier->SetSVMType(NU_SVC);
      break;
    case 2: // ONE_CLASS
      libSVMClassifier->SetSVMType(ONE_CLASS);
      break;
    default:
      libSVMClassifier->SetSVMType(C_SVC);
      break;
    }
  }

  libSVMClassifier->Train();
  libSVMClassifier->Save(modelPath);
}

} // end namespace wrapper
} // end namespace otb

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/app/atom_main.h"

#include <stdlib.h>
#include <string.h>

#if defined(OS_WIN)
#include <stdio.h>
#include <io.h>
#include <fcntl.h>

#include <windows.h>
#include <shellscalingapi.h>
#include <tchar.h>
#include <shellapi.h>

#include "atom/app/atom_main_delegate.h"
#include "atom/common/crash_reporter/win/crash_service_main.h"
#include "base/environment.h"
#include "base/win/windows_version.h"
#include "content/public/app/startup_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"
#include "ui/gfx/win/dpi.h"
#elif defined(OS_LINUX)  // defined(OS_WIN)
#include "atom/app/atom_main_delegate.h"  // NOLINT
#include "content/public/app/content_main.h"
#else  // defined(OS_LINUX)
#include "atom/app/atom_library_main.h"
#endif  // defined(OS_MACOSX)

#include "atom/app/node_main.h"
#include "atom/common/atom_command_line.h"
#include "base/at_exit.h"
#include "base/i18n/icu_util.h"

#if defined(OS_WIN)

namespace {

// Win8.1 supports monitor-specific DPI scaling.
bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) {
  typedef HRESULT(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS);
  SetProcessDpiAwarenessPtr set_process_dpi_awareness_func =
      reinterpret_cast<SetProcessDpiAwarenessPtr>(
          GetProcAddress(GetModuleHandleA("user32.dll"),
                         "SetProcessDpiAwarenessInternal"));
  if (set_process_dpi_awareness_func) {
    HRESULT hr = set_process_dpi_awareness_func(value);
    if (SUCCEEDED(hr)) {
      VLOG(1) << "SetProcessDpiAwareness succeeded.";
      return true;
    } else if (hr == E_ACCESSDENIED) {
      LOG(ERROR) << "Access denied error from SetProcessDpiAwareness. "
          "Function called twice, or manifest was used.";
    }
  }
  return false;
}

// This function works for Windows Vista through Win8. Win8.1 must use
// SetProcessDpiAwareness[Wrapper].
BOOL SetProcessDPIAwareWrapper() {
  typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
  SetProcessDPIAwarePtr set_process_dpi_aware_func =
      reinterpret_cast<SetProcessDPIAwarePtr>(
      GetProcAddress(GetModuleHandleA("user32.dll"),
                      "SetProcessDPIAware"));
  return set_process_dpi_aware_func &&
    set_process_dpi_aware_func();
}

void EnableHighDPISupport() {
  if (!SetProcessDpiAwarenessWrapper(PROCESS_SYSTEM_DPI_AWARE)) {
    SetProcessDPIAwareWrapper();
  }
}

}  // namespace

int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
  int argc = 0;
  wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);

  scoped_ptr<base::Environment> env(base::Environment::Create());

  // Make output work in console if we are not in cygiwn.
  std::string os;
  if (env->GetVar("OS", &os) && os != "cygwin") {
    AttachConsole(ATTACH_PARENT_PROCESS);

    FILE* dontcare;
    freopen_s(&dontcare, "CON", "w", stdout);
    freopen_s(&dontcare, "CON", "w", stderr);
    freopen_s(&dontcare, "CON", "r", stdin);
  }

  // Convert argv to to UTF8
  char** argv = new char*[argc];
  for (int i = 0; i < argc; i++) {
    // Compute the size of the required buffer
    DWORD size = WideCharToMultiByte(CP_UTF8,
                                     0,
                                     wargv[i],
                                     -1,
                                     NULL,
                                     0,
                                     NULL,
                                     NULL);
    if (size == 0) {
      // This should never happen.
      fprintf(stderr, "Could not convert arguments to utf8.");
      exit(1);
    }
    // Do the actual conversion
    argv[i] = new char[size];
    DWORD result = WideCharToMultiByte(CP_UTF8,
                                       0,
                                       wargv[i],
                                       -1,
                                       argv[i],
                                       size,
                                       NULL,
                                       NULL);
    if (result == 0) {
      // This should never happen.
      fprintf(stderr, "Could not convert arguments to utf8.");
      exit(1);
    }
  }

  std::string node_indicator, crash_service_indicator;
  if (env->GetVar("ATOM_SHELL_INTERNAL_RUN_AS_NODE", &node_indicator) &&
      node_indicator == "1") {
    // Now that argv conversion is done, we can finally start.
    base::AtExitManager atexit_manager;
    base::i18n::InitializeICU();
    return atom::NodeMain(argc, argv);
  } else if (env->GetVar("ATOM_SHELL_INTERNAL_CRASH_SERVICE",
                         &crash_service_indicator) &&
      crash_service_indicator == "1") {
    return crash_service::Main(cmd);
  }

  sandbox::SandboxInterfaceInfo sandbox_info = {0};
  content::InitializeSandboxInfo(&sandbox_info);
  atom::AtomMainDelegate delegate;

  // We don't want to set DPI awareness on pre-Win7 because we don't support
  // DirectWrite there. GDI fonts are kerned very badly, so better to leave
  // DPI-unaware and at effective 1.0. See also ShouldUseDirectWrite().
  if (base::win::GetVersion() >= base::win::VERSION_WIN7)
    EnableHighDPISupport();

  content::ContentMainParams params(&delegate);
  params.instance = instance;
  params.sandbox_info = &sandbox_info;
  atom::AtomCommandLine::Init(argc, argv);
  return content::ContentMain(params);
}

#elif defined(OS_LINUX)  // defined(OS_WIN)

int main(int argc, const char* argv[]) {
  char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE");
  if (node_indicator != NULL && strcmp(node_indicator, "1") == 0) {
    base::i18n::InitializeICU();
    base::AtExitManager atexit_manager;
    return atom::NodeMain(argc, const_cast<char**>(argv));
  }

  atom::AtomMainDelegate delegate;
  content::ContentMainParams params(&delegate);
  params.argc = argc;
  params.argv = argv;
  atom::AtomCommandLine::Init(argc, argv);
  return content::ContentMain(params);
}

#else  // defined(OS_LINUX)

int main(int argc, const char* argv[]) {
  char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE");
  if (node_indicator != NULL && strcmp(node_indicator, "1") == 0) {
    return AtomInitializeICUandStartNode(argc, const_cast<char**>(argv));
  }

  return AtomMain(argc, argv);
}

#endif  // defined(OS_MACOSX)
<commit_msg>Check ELECTRON_RUN_AS_NODE env var<commit_after>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/app/atom_main.h"

#include <stdlib.h>
#include <string.h>

#if defined(OS_WIN)
#include <stdio.h>
#include <io.h>
#include <fcntl.h>

#include <windows.h>
#include <shellscalingapi.h>
#include <tchar.h>
#include <shellapi.h>

#include "atom/app/atom_main_delegate.h"
#include "atom/common/crash_reporter/win/crash_service_main.h"
#include "base/environment.h"
#include "base/win/windows_version.h"
#include "content/public/app/startup_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"
#include "ui/gfx/win/dpi.h"
#elif defined(OS_LINUX)  // defined(OS_WIN)
#include "atom/app/atom_main_delegate.h"  // NOLINT
#include "content/public/app/content_main.h"
#else  // defined(OS_LINUX)
#include "atom/app/atom_library_main.h"
#endif  // defined(OS_MACOSX)

#include "atom/app/node_main.h"
#include "atom/common/atom_command_line.h"
#include "base/at_exit.h"
#include "base/i18n/icu_util.h"

namespace {

const char* kRunAsNode = "ELECTRON_RUN_AS_NODE";
const char* kOldRunAsNode = "ATOM_SHELL_INTERNAL_RUN_AS_NODE";

bool IsEnvSet(const char* name) {
#if defined(OS_WIN)
  size_t required_size;
  getenv_s(&required_size, nullptr, 0, name);
  return required_size != 0;
#else
  char* indicator = getenv(name);
  return indicator && indicator[0] != '\0';
#endif
}

bool IsRunAsNode() {
  return IsEnvSet(kRunAsNode) || IsEnvSet(kOldRunAsNode);
}

#if defined(OS_WIN)
// Win8.1 supports monitor-specific DPI scaling.
bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) {
  typedef HRESULT(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS);
  SetProcessDpiAwarenessPtr set_process_dpi_awareness_func =
      reinterpret_cast<SetProcessDpiAwarenessPtr>(
          GetProcAddress(GetModuleHandleA("user32.dll"),
                         "SetProcessDpiAwarenessInternal"));
  if (set_process_dpi_awareness_func) {
    HRESULT hr = set_process_dpi_awareness_func(value);
    if (SUCCEEDED(hr)) {
      VLOG(1) << "SetProcessDpiAwareness succeeded.";
      return true;
    } else if (hr == E_ACCESSDENIED) {
      LOG(ERROR) << "Access denied error from SetProcessDpiAwareness. "
          "Function called twice, or manifest was used.";
    }
  }
  return false;
}

// This function works for Windows Vista through Win8. Win8.1 must use
// SetProcessDpiAwareness[Wrapper].
BOOL SetProcessDPIAwareWrapper() {
  typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
  SetProcessDPIAwarePtr set_process_dpi_aware_func =
      reinterpret_cast<SetProcessDPIAwarePtr>(
      GetProcAddress(GetModuleHandleA("user32.dll"),
                      "SetProcessDPIAware"));
  return set_process_dpi_aware_func &&
    set_process_dpi_aware_func();
}

void EnableHighDPISupport() {
  if (!SetProcessDpiAwarenessWrapper(PROCESS_SYSTEM_DPI_AWARE)) {
    SetProcessDPIAwareWrapper();
  }
}
#endif

}  // namespace

#if defined(OS_WIN)
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
  int argc = 0;
  wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);

  scoped_ptr<base::Environment> env(base::Environment::Create());

  // Make output work in console if we are not in cygiwn.
  std::string os;
  if (env->GetVar("OS", &os) && os != "cygwin") {
    AttachConsole(ATTACH_PARENT_PROCESS);

    FILE* dontcare;
    freopen_s(&dontcare, "CON", "w", stdout);
    freopen_s(&dontcare, "CON", "w", stderr);
    freopen_s(&dontcare, "CON", "r", stdin);
  }

  // Convert argv to to UTF8
  char** argv = new char*[argc];
  for (int i = 0; i < argc; i++) {
    // Compute the size of the required buffer
    DWORD size = WideCharToMultiByte(CP_UTF8,
                                     0,
                                     wargv[i],
                                     -1,
                                     NULL,
                                     0,
                                     NULL,
                                     NULL);
    if (size == 0) {
      // This should never happen.
      fprintf(stderr, "Could not convert arguments to utf8.");
      exit(1);
    }
    // Do the actual conversion
    argv[i] = new char[size];
    DWORD result = WideCharToMultiByte(CP_UTF8,
                                       0,
                                       wargv[i],
                                       -1,
                                       argv[i],
                                       size,
                                       NULL,
                                       NULL);
    if (result == 0) {
      // This should never happen.
      fprintf(stderr, "Could not convert arguments to utf8.");
      exit(1);
    }
  }

  if (IsRunAsNode()) {
    // Now that argv conversion is done, we can finally start.
    base::AtExitManager atexit_manager;
    base::i18n::InitializeICU();
    return atom::NodeMain(argc, argv);
  } else if (IsEnvSet("ATOM_SHELL_INTERNAL_CRASH_SERVICE")) {
    return crash_service::Main(cmd);
  }

  sandbox::SandboxInterfaceInfo sandbox_info = {0};
  content::InitializeSandboxInfo(&sandbox_info);
  atom::AtomMainDelegate delegate;

  // We don't want to set DPI awareness on pre-Win7 because we don't support
  // DirectWrite there. GDI fonts are kerned very badly, so better to leave
  // DPI-unaware and at effective 1.0. See also ShouldUseDirectWrite().
  if (base::win::GetVersion() >= base::win::VERSION_WIN7)
    EnableHighDPISupport();

  content::ContentMainParams params(&delegate);
  params.instance = instance;
  params.sandbox_info = &sandbox_info;
  atom::AtomCommandLine::Init(argc, argv);
  return content::ContentMain(params);
}

#elif defined(OS_LINUX)  // defined(OS_WIN)

int main(int argc, const char* argv[]) {
  if (IsRunAsNode()) {
    base::i18n::InitializeICU();
    base::AtExitManager atexit_manager;
    return atom::NodeMain(argc, const_cast<char**>(argv));
  }

  atom::AtomMainDelegate delegate;
  content::ContentMainParams params(&delegate);
  params.argc = argc;
  params.argv = argv;
  atom::AtomCommandLine::Init(argc, argv);
  return content::ContentMain(params);
}

#else  // defined(OS_LINUX)

int main(int argc, const char* argv[]) {
  if (IsRunAsNode()) {
    return AtomInitializeICUandStartNode(argc, const_cast<char**>(argv));
  }

  return AtomMain(argc, argv);
}

#endif  // defined(OS_MACOSX)
<|endoftext|>


<commit_before>// -*- c-basic-offset: 2 -*-

#include "kfoldertree.h"
#include <klocale.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <qpainter.h>
#include <qapplication.h>
#include <qheader.h>
#include <qstyle.h>

//-----------------------------------------------------------------------------
KFolderTreeItem::KFolderTreeItem( KFolderTree *parent, const QString & label,
				  Protocol protocol, Type type )
  : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
    mUnread(-1), mTotal(0)
{
}

//-----------------------------------------------------------------------------
KFolderTreeItem::KFolderTreeItem( KFolderTreeItem *parent,
				  const QString & label, Protocol protocol, Type type,
          int unread, int total )
    : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
      mUnread( unread ), mTotal( total )
{
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::protocolSortingKey() const
{
  // protocol dependant sorting order:
  // local < imap < news < search < other
  switch ( mProtocol ) {
  case Local:
    return 1;
  case CachedImap:
  case Imap:
    return 2;
  case News:
    return 3;
  case Search:
    return 4;
  default:
    return 42;
  }
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::typeSortingKey() const
{
  // type dependant sorting order:
  // inbox < outbox < sent-mail < trash < drafts
  // < calendar < contacts < notes < tasks
  // < normal folders
  switch ( mType ) {
  case Inbox:
    return 1;
  case Outbox:
    return 2;
  case SentMail:
    return 3;
  case Trash:
    return 4;
  case Drafts:
    return 5;
  case Calendar:
    return 6;
  case Contacts:
    return 7;
  case Notes:
    return 8;
  case Tasks:
    return 9;
  default:
    return 42;
  }
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::compare( QListViewItem * i, int col, bool ) const
{
  KFolderTreeItem* other = static_cast<KFolderTreeItem*>( i );

  if (col == 0)
  {
    // sort by folder

    // local root-folder
    if ( depth() == 0 && mProtocol == NONE )
      return -1;
    if ( other->depth() == 0 && other->protocol() == NONE )
      return 1;

    // first compare by protocol
    int thisKey = protocolSortingKey();
    int thatKey = other->protocolSortingKey();
    if ( thisKey < thatKey )
      return -1;
    if ( thisKey > thatKey )
      return 1;

    // then compare by type
    thisKey = typeSortingKey();
    thatKey = other->typeSortingKey();
    if ( thisKey < thatKey )
      return -1;
    if ( thisKey > thatKey )
      return 1;

    // and finally compare by name
    return text( 0 ).localeAwareCompare( other->text( 0 ) );
  }
  else
  {
    // sort by unread or total-column
    int a = 0, b = 0;
    if (col == static_cast<KFolderTree*>(listView())->unreadIndex())
    {
      a = mUnread;
      b = other->unreadCount();
    }
    else if (col == static_cast<KFolderTree*>(listView())->totalIndex())
    {
      a = mTotal;
      b = other->totalCount();
    }

    if ( a == b )
      return 0;
    else
      return (a < b ? -1 : 1);
  }
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::setUnreadCount( int aUnread )
{
  if ( aUnread < 0 ) return;

  mUnread = aUnread;

  QString unread = QString::null;
  if (mUnread == 0)
    unread = "- ";
  else {
    unread.setNum(mUnread);
    unread += " ";
  }

  setText( static_cast<KFolderTree*>(listView())->unreadIndex(),
      unread );
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::setTotalCount( int aTotal )
{
  if ( aTotal < 0 ) return;

  mTotal = aTotal;

  QString total = QString::null;
  if (mTotal == 0)
    total = "- ";
  else {
    total.setNum(mTotal);
    total += " ";
  }

  setText( static_cast<KFolderTree*>(listView())->totalIndex(),
      total );
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::countUnreadRecursive()
{
  int count = (mUnread > 0) ? mUnread : 0;

  for ( QListViewItem *item = firstChild() ;
      item ; item = item->nextSibling() )
  {
    count += static_cast<KFolderTreeItem*>(item)->countUnreadRecursive();
  }

  return count;
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::paintCell( QPainter * p, const QColorGroup & cg,
                                  int column, int width, int align )
{
  KFolderTree *ft = static_cast<KFolderTree*>(listView());
  /* The below is exceedingly silly, but Ingo insists that the unread
   * count that is shown in parenthesis after the folder name must
   * be configurable in color. That means that paintCell needs to do
   * two painting passes which flickers. Since that flicker is not
   * needed when there is the unread column, special case that. */
  if ( ft->isUnreadActive() ) {
    if ( (column == 0 || column == ft->unreadIndex())
          && countUnreadRecursive() > 0 )
    {
      QFont f = p->font();
      f.setWeight(QFont::Bold);
      p->setFont(f);
    }
    KListViewItem::paintCell( p, cg, column, width, align );
  } else {
    QListView *lv = listView();
    QString oldText = text(column);

    // set an empty text so that we can have our own implementation (see further down)
    // but still benefit from KListView::paintCell
    setText( column, "" );

    KListViewItem::paintCell( p, cg, column, width, align );

    int r = lv ? lv->itemMargin() : 1;
    const QPixmap *icon = pixmap( column );
    int marg = lv ? lv->itemMargin() : 1;

    QString t;
    QRect br;
    setText( column, oldText );
    if ( isSelected() )
      p->setPen( cg.highlightedText() );
    else
      p->setPen( ft->paintInfo().colFore );

    if ( icon ) {
      r += icon->width() + lv->itemMargin();
    }
    t = text( column );
    if ( !t.isEmpty() )
    {
      // use a bold-font for the folder- and the unread-columns
      if ( countUnreadRecursive() > 0 &&
          (column == 0 || column == ft->unreadIndex()) )
      {
        QFont f = p->font();
        f.setWeight(QFont::Bold);
        p->setFont(f);
      }
      p->drawText( r, 0, width-marg-r, height(),
          align | AlignVCenter, t, -1, &br );
      if (!isSelected())
        p->setPen( ft->paintInfo().colUnread );
      if (column == 0) {
        // draw the unread-count if the unread-column is not active
        QString unread = QString::null;
        if ( !ft->isUnreadActive() && mUnread > 0 )
          unread = " (" + QString::number(mUnread) + ")";
        p->drawText( br.right(), 0, width-marg-br.right(), height(),
            align | AlignVCenter, unread );
      }
    } // end !t.isEmpty()
  }
}

//=============================================================================

KFolderTree::KFolderTree( QWidget *parent, const char* name )
  : KListView( parent, name ), mUnreadIndex(-1), mTotalIndex(-1)
{
  // GUI-options
  setStyleDependantFrameWidth();
  setAcceptDrops(true);
  setDropVisualizer(false);
  setAllColumnsShowFocus(true);
  setShowSortIndicator(true);
  setUpdatesEnabled(true);
  setItemsRenameable(false);
  setRootIsDecorated(true);
  setSelectionModeExt(Extended);
  setAlternateBackground(QColor());
  setFullWidth(true);
  disableAutoSelection();
}

//-----------------------------------------------------------------------------
void KFolderTree::setStyleDependantFrameWidth()
{
  // set the width of the frame to a reasonable value for the current GUI style
  int frameWidth;
  if( style().isA("KeramikStyle") )
    frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1;
  else
    frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth );
  if ( frameWidth < 0 )
    frameWidth = 0;
  if ( frameWidth != lineWidth() )
    setLineWidth( frameWidth );
}

//-----------------------------------------------------------------------------
void KFolderTree::styleChange( QStyle& oldStyle )
{
  setStyleDependantFrameWidth();
  KListView::styleChange( oldStyle );
}

//-----------------------------------------------------------------------------
void KFolderTree::drawContentsOffset( QPainter * p, int ox, int oy,
                                       int cx, int cy, int cw, int ch )
{
  bool oldUpdatesEnabled = isUpdatesEnabled();
  setUpdatesEnabled(false);
  KListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch );
  setUpdatesEnabled(oldUpdatesEnabled);
}

//-----------------------------------------------------------------------------
void KFolderTree::contentsMousePressEvent( QMouseEvent *e )
{
    setSelectionModeExt(Single);
    KListView::contentsMousePressEvent(e);
}

//-----------------------------------------------------------------------------
void KFolderTree::contentsMouseReleaseEvent( QMouseEvent *e )
{
    KListView::contentsMouseReleaseEvent(e);
    setSelectionModeExt(Extended);
}

//-----------------------------------------------------------------------------
void KFolderTree::addAcceptableDropMimetype( const char *mimeType, bool outsideOk )
{
  int oldSize = mAcceptableDropMimetypes.size();
  mAcceptableDropMimetypes.resize(oldSize+1);
  mAcceptOutside.resize(oldSize+1);

  mAcceptableDropMimetypes.at(oldSize) =  mimeType;
  mAcceptOutside.setBit(oldSize, outsideOk);
}

//-----------------------------------------------------------------------------
bool KFolderTree::acceptDrag( QDropEvent* event ) const
{
  QListViewItem* item = itemAt(contentsToViewport(event->pos()));

  for (uint i = 0; i < mAcceptableDropMimetypes.size(); i++)
  {
    if (event->provides(mAcceptableDropMimetypes[i]))
    {
      if (item)
        return (static_cast<KFolderTreeItem*>(item))->acceptDrag(event);
      else
        return mAcceptOutside[i];
    }
  }
  return false;
}

//-----------------------------------------------------------------------------
void KFolderTree::addUnreadColumn( const QString & name, int width )
{
  mUnreadIndex = addColumn( name, width );
  setColumnAlignment( mUnreadIndex, qApp->reverseLayout() ? Qt::AlignLeft : Qt::AlignRight );
}

//-----------------------------------------------------------------------------
void KFolderTree::addTotalColumn( const QString & name, int width )
{
  mTotalIndex = addColumn( name, width );
  setColumnAlignment( mTotalIndex, qApp->reverseLayout() ? Qt::AlignLeft : Qt::AlignRight );
}

//-----------------------------------------------------------------------------
void KFolderTree::removeUnreadColumn()
{
  if ( !isUnreadActive() ) return;
  removeColumn( mUnreadIndex );
  if ( isTotalActive() && mTotalIndex > mUnreadIndex )
    mTotalIndex--;
  mUnreadIndex = -1;
  header()->adjustHeaderSize();
}

//-----------------------------------------------------------------------------
void KFolderTree::removeTotalColumn()
{
  if ( !isTotalActive() ) return;
  removeColumn( mTotalIndex );
  if ( isUnreadActive() && mTotalIndex < mUnreadIndex )
    mUnreadIndex--;
  mTotalIndex = -1;
  header()->adjustHeaderSize();
}

//-----------------------------------------------------------------------------
void KFolderTree::setFullWidth( bool fullWidth )
{
  if (fullWidth)
    header()->setStretchEnabled( true, 0 );
}

#include "kfoldertree.moc"
<commit_msg>Patch from Severin Greimel <greimel-kde@fs-pw.uni-muenchen.de> Fixes Bug #48697, kmail folder list shouldn't bold parents if children are visible.  Thanks Severin. CCMAIL: 48697-done@bugs.kde.org CCMAIL: greimel-kde@fs-pw.uni-muenchen.de<commit_after>// -*- c-basic-offset: 2 -*-

#include "kfoldertree.h"
#include <klocale.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <qpainter.h>
#include <qapplication.h>
#include <qheader.h>
#include <qstyle.h>

//-----------------------------------------------------------------------------
KFolderTreeItem::KFolderTreeItem( KFolderTree *parent, const QString & label,
				  Protocol protocol, Type type )
  : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
    mUnread(-1), mTotal(0)
{
}

//-----------------------------------------------------------------------------
KFolderTreeItem::KFolderTreeItem( KFolderTreeItem *parent,
				  const QString & label, Protocol protocol, Type type,
          int unread, int total )
    : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
      mUnread( unread ), mTotal( total )
{
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::protocolSortingKey() const
{
  // protocol dependant sorting order:
  // local < imap < news < search < other
  switch ( mProtocol ) {
  case Local:
    return 1;
  case CachedImap:
  case Imap:
    return 2;
  case News:
    return 3;
  case Search:
    return 4;
  default:
    return 42;
  }
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::typeSortingKey() const
{
  // type dependant sorting order:
  // inbox < outbox < sent-mail < trash < drafts
  // < calendar < contacts < notes < tasks
  // < normal folders
  switch ( mType ) {
  case Inbox:
    return 1;
  case Outbox:
    return 2;
  case SentMail:
    return 3;
  case Trash:
    return 4;
  case Drafts:
    return 5;
  case Calendar:
    return 6;
  case Contacts:
    return 7;
  case Notes:
    return 8;
  case Tasks:
    return 9;
  default:
    return 42;
  }
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::compare( QListViewItem * i, int col, bool ) const
{
  KFolderTreeItem* other = static_cast<KFolderTreeItem*>( i );

  if (col == 0)
  {
    // sort by folder

    // local root-folder
    if ( depth() == 0 && mProtocol == NONE )
      return -1;
    if ( other->depth() == 0 && other->protocol() == NONE )
      return 1;

    // first compare by protocol
    int thisKey = protocolSortingKey();
    int thatKey = other->protocolSortingKey();
    if ( thisKey < thatKey )
      return -1;
    if ( thisKey > thatKey )
      return 1;

    // then compare by type
    thisKey = typeSortingKey();
    thatKey = other->typeSortingKey();
    if ( thisKey < thatKey )
      return -1;
    if ( thisKey > thatKey )
      return 1;

    // and finally compare by name
    return text( 0 ).localeAwareCompare( other->text( 0 ) );
  }
  else
  {
    // sort by unread or total-column
    int a = 0, b = 0;
    if (col == static_cast<KFolderTree*>(listView())->unreadIndex())
    {
      a = mUnread;
      b = other->unreadCount();
    }
    else if (col == static_cast<KFolderTree*>(listView())->totalIndex())
    {
      a = mTotal;
      b = other->totalCount();
    }

    if ( a == b )
      return 0;
    else
      return (a < b ? -1 : 1);
  }
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::setUnreadCount( int aUnread )
{
  if ( aUnread < 0 ) return;

  mUnread = aUnread;

  QString unread = QString::null;
  if (mUnread == 0)
    unread = "- ";
  else {
    unread.setNum(mUnread);
    unread += " ";
  }

  setText( static_cast<KFolderTree*>(listView())->unreadIndex(),
      unread );
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::setTotalCount( int aTotal )
{
  if ( aTotal < 0 ) return;

  mTotal = aTotal;

  QString total = QString::null;
  if (mTotal == 0)
    total = "- ";
  else {
    total.setNum(mTotal);
    total += " ";
  }

  setText( static_cast<KFolderTree*>(listView())->totalIndex(),
      total );
}

//-----------------------------------------------------------------------------
int KFolderTreeItem::countUnreadRecursive()
{
  int count = (mUnread > 0) ? mUnread : 0;

  for ( QListViewItem *item = firstChild() ;
      item ; item = item->nextSibling() )
  {
    count += static_cast<KFolderTreeItem*>(item)->countUnreadRecursive();
  }

  return count;
}

//-----------------------------------------------------------------------------
void KFolderTreeItem::paintCell( QPainter * p, const QColorGroup & cg,
                                  int column, int width, int align )
{
  KFolderTree *ft = static_cast<KFolderTree*>(listView());
  /* The below is exceedingly silly, but Ingo insists that the unread
   * count that is shown in parenthesis after the folder name must
   * be configurable in color. That means that paintCell needs to do
   * two painting passes which flickers. Since that flicker is not
   * needed when there is the unread column, special case that. */
  if ( ft->isUnreadActive() ) {
    if ( (column == 0 || column == ft->unreadIndex())
          && (mUnread > 0 || (!isOpen() && countUnreadRecursive() > 0)) )
    {
      QFont f = p->font();
      f.setWeight(QFont::Bold);
      p->setFont(f);
    }
    KListViewItem::paintCell( p, cg, column, width, align );
  } else {
    QListView *lv = listView();
    QString oldText = text(column);

    // set an empty text so that we can have our own implementation (see further down)
    // but still benefit from KListView::paintCell
    setText( column, "" );

    KListViewItem::paintCell( p, cg, column, width, align );

    int r = lv ? lv->itemMargin() : 1;
    const QPixmap *icon = pixmap( column );
    int marg = lv ? lv->itemMargin() : 1;

    QString t;
    QRect br;
    setText( column, oldText );
    if ( isSelected() )
      p->setPen( cg.highlightedText() );
    else
      p->setPen( ft->paintInfo().colFore );

    if ( icon ) {
      r += icon->width() + lv->itemMargin();
    }
    t = text( column );
    if ( !t.isEmpty() )
    {
      // use a bold-font for the folder- and the unread-columns
      if ( (column == 0 || column == ft->unreadIndex())
            && (mUnread > 0 || (!isOpen() && countUnreadRecursive() > 0)) )
      {
        QFont f = p->font();
        f.setWeight(QFont::Bold);
        p->setFont(f);
      }
      p->drawText( r, 0, width-marg-r, height(),
          align | AlignVCenter, t, -1, &br );
      if (!isSelected())
        p->setPen( ft->paintInfo().colUnread );
      if (column == 0) {
        // draw the unread-count if the unread-column is not active
        QString unread = QString::null;
        if ( !ft->isUnreadActive() && mUnread > 0 )
          unread = " (" + QString::number(mUnread) + ")";
        p->drawText( br.right(), 0, width-marg-br.right(), height(),
            align | AlignVCenter, unread );
      }
    } // end !t.isEmpty()
  }
}

//=============================================================================

KFolderTree::KFolderTree( QWidget *parent, const char* name )
  : KListView( parent, name ), mUnreadIndex(-1), mTotalIndex(-1)
{
  // GUI-options
  setStyleDependantFrameWidth();
  setAcceptDrops(true);
  setDropVisualizer(false);
  setAllColumnsShowFocus(true);
  setShowSortIndicator(true);
  setUpdatesEnabled(true);
  setItemsRenameable(false);
  setRootIsDecorated(true);
  setSelectionModeExt(Extended);
  setAlternateBackground(QColor());
  setFullWidth(true);
  disableAutoSelection();
}

//-----------------------------------------------------------------------------
void KFolderTree::setStyleDependantFrameWidth()
{
  // set the width of the frame to a reasonable value for the current GUI style
  int frameWidth;
  if( style().isA("KeramikStyle") )
    frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1;
  else
    frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth );
  if ( frameWidth < 0 )
    frameWidth = 0;
  if ( frameWidth != lineWidth() )
    setLineWidth( frameWidth );
}

//-----------------------------------------------------------------------------
void KFolderTree::styleChange( QStyle& oldStyle )
{
  setStyleDependantFrameWidth();
  KListView::styleChange( oldStyle );
}

//-----------------------------------------------------------------------------
void KFolderTree::drawContentsOffset( QPainter * p, int ox, int oy,
                                       int cx, int cy, int cw, int ch )
{
  bool oldUpdatesEnabled = isUpdatesEnabled();
  setUpdatesEnabled(false);
  KListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch );
  setUpdatesEnabled(oldUpdatesEnabled);
}

//-----------------------------------------------------------------------------
void KFolderTree::contentsMousePressEvent( QMouseEvent *e )
{
    setSelectionModeExt(Single);
    KListView::contentsMousePressEvent(e);
}

//-----------------------------------------------------------------------------
void KFolderTree::contentsMouseReleaseEvent( QMouseEvent *e )
{
    KListView::contentsMouseReleaseEvent(e);
    setSelectionModeExt(Extended);
}

//-----------------------------------------------------------------------------
void KFolderTree::addAcceptableDropMimetype( const char *mimeType, bool outsideOk )
{
  int oldSize = mAcceptableDropMimetypes.size();
  mAcceptableDropMimetypes.resize(oldSize+1);
  mAcceptOutside.resize(oldSize+1);

  mAcceptableDropMimetypes.at(oldSize) =  mimeType;
  mAcceptOutside.setBit(oldSize, outsideOk);
}

//-----------------------------------------------------------------------------
bool KFolderTree::acceptDrag( QDropEvent* event ) const
{
  QListViewItem* item = itemAt(contentsToViewport(event->pos()));

  for (uint i = 0; i < mAcceptableDropMimetypes.size(); i++)
  {
    if (event->provides(mAcceptableDropMimetypes[i]))
    {
      if (item)
        return (static_cast<KFolderTreeItem*>(item))->acceptDrag(event);
      else
        return mAcceptOutside[i];
    }
  }
  return false;
}

//-----------------------------------------------------------------------------
void KFolderTree::addUnreadColumn( const QString & name, int width )
{
  mUnreadIndex = addColumn( name, width );
  setColumnAlignment( mUnreadIndex, qApp->reverseLayout() ? Qt::AlignLeft : Qt::AlignRight );
}

//-----------------------------------------------------------------------------
void KFolderTree::addTotalColumn( const QString & name, int width )
{
  mTotalIndex = addColumn( name, width );
  setColumnAlignment( mTotalIndex, qApp->reverseLayout() ? Qt::AlignLeft : Qt::AlignRight );
}

//-----------------------------------------------------------------------------
void KFolderTree::removeUnreadColumn()
{
  if ( !isUnreadActive() ) return;
  removeColumn( mUnreadIndex );
  if ( isTotalActive() && mTotalIndex > mUnreadIndex )
    mTotalIndex--;
  mUnreadIndex = -1;
  header()->adjustHeaderSize();
}

//-----------------------------------------------------------------------------
void KFolderTree::removeTotalColumn()
{
  if ( !isTotalActive() ) return;
  removeColumn( mTotalIndex );
  if ( isUnreadActive() && mTotalIndex < mUnreadIndex )
    mUnreadIndex--;
  mTotalIndex = -1;
  header()->adjustHeaderSize();
}

//-----------------------------------------------------------------------------
void KFolderTree::setFullWidth( bool fullWidth )
{
  if (fullWidth)
    header()->setStretchEnabled( true, 0 );
}

#include "kfoldertree.moc"
<|endoftext|>


<commit_before>/// \file FunctionCompiler.cpp

#include "chi/FunctionCompiler.hpp"
#include "chi/Context.hpp"
#include "chi/DataType.hpp"
#include "chi/FunctionValidator.hpp"
#include "chi/GraphFunction.hpp"
#include "chi/GraphModule.hpp"
#include "chi/LLVMVersion.hpp"
#include "chi/LangModule.hpp"
#include "chi/NameMangler.hpp"
#include "chi/NodeInstance.hpp"
#include "chi/NodeType.hpp"
#include "chi/Support/Result.hpp"

#include <boost/bimap.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/range/join.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <unordered_map>

#include <llvm/IR/DIBuilder.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>

namespace fs = boost::filesystem;

namespace chi {

FunctionCompiler::FunctionCompiler(const chi::GraphFunction& func, llvm::Module& moduleToGenInto,
                                   llvm::DICompileUnit& debugCU, llvm::DIBuilder& debugBuilder)
    : mModule{&moduleToGenInto}, mDIBuilder{&debugBuilder}, mDebugCU{&debugCU}, mFunction{&func} {}

Result FunctionCompiler::initialize(bool validate) {
	assert(initialized() == false && "Cannot initialize a FunctionCompiler more than once");

	mInitialized = true;

	Result res;
	auto   compilerCtx = res.addScopedContext(
	    {{"Function", function().name()}, {"Module", function().module().fullName()}});

	if (validate) {
		res += validateFunction(function());
		if (!res) { return res; }
	}

	// get the entry node
	auto entry = function().entryNode();
	if (entry == nullptr) {
		res.addEntry("EUKN", "No entry node", {});
		return res;
	}

	// create function
	auto mangledName = mangleFunctionName(module().fullName(), function().name());
	mLLFunction      = llvm::cast<llvm::Function>(
	    llvmModule().getOrInsertFunction(mangledName, function().functionType()));

	// create the debug file
	mDIFile = diBuilder().createFile(debugCompileUnit()->getFilename(),
	                                        debugCompileUnit()->getDirectory());

	auto subroutineType = createSubroutineType();

	mNodeLocations = module().createLineNumberAssoc();
	auto entryLN   = nodeLineNumber(*entry);

	// TODO(#65): line numbers?
	mDebugFunc =
	    diBuilder().createFunction(mDIFile, module().fullName() + ":" + function().name(),
	                               mangledName, mDIFile, entryLN, subroutineType, false, true, 0,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
	                               0,
#else
	                               llvm::DINode::DIFlags{},
#endif
	                               false);

#if LLVM_VERSION_LESS_EQUAL(3, 7)
	mDebugFunc.replaceFunction(mLLFunction);
#else
	mLLFunction->setSubprogram(mDebugFunc);
#endif

	mAllocBlock = llvm::BasicBlock::Create(context().llvmContext(), "alloc", mLLFunction);

	// set argument names
	auto idx = 0ull;
	for (auto& arg : mLLFunction->
#if LLVM_VERSION_AT_LEAST(5, 0)
	                 args()
#else
	                 getArgumentList()
#endif
	         ) {
		// the first one is the input exec ID
		if (idx == 0) {
			arg.setName("inputexec_id");

			// create debug info
			DataType intDataType;
			res += context().typeFromModule("lang", "i32", &intDataType);
			assert(intDataType.valid());
			auto debugParam = diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 7)
			                  createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, mDebugFunc,
			                                      "inputexec_id", mDIFile, entryLN,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			                                      *
#endif
			                                      intDataType.debugType());
#else

			                  createParameterVariable(mDebugFunc, "inputexec_id", 1, mDIFile,
			                                          entryLN, intDataType.debugType());
#endif
			diBuilder()
			    .insertDeclare(&arg, debugParam,
#if LLVM_VERSION_AT_LEAST(3, 6)
			                   diBuilder().createExpression(),
#if LLVM_VERSION_AT_LEAST(3, 7)
			                   llvm::DebugLoc::get(entryLN, 1, mDebugFunc),
#endif
#endif
			                   &allocBlock())
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			    ->setDebugLoc(llvm::DebugLoc::get(entryLN, 1, mDebugFunc))
#endif
			    ;  // TODO(#65): "line" numbers

			++idx;
			continue;
		}

		NamedDataType tyAndName;
		// all the - 1's is becaues the first is the inputexec_id
		if (idx - 1 < function().dataInputs().size()) {
			tyAndName = function().dataInputs()[idx - 1];
		} else {
			tyAndName = function().dataOutputs()[idx - 1 - entry->type().dataOutputs().size()];
		}
		arg.setName(tyAndName.name);

		// create debug info

		// create DIType*
		llvm::DIType* dType      = tyAndName.type.debugType();
		auto          debugParam = diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 7)
		                  createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, mDebugFunc,
		                                      tyAndName.name, mDIFile, entryLN,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		                                      *
#endif
		                                      dType);
#else
		                  createParameterVariable(mDebugFunc, tyAndName.name,
		                                          idx + 1,  // + 1 because it starts at 1
		                                          mDIFile, entryLN, dType);
#endif
		diBuilder()
		    .insertDeclare(&arg, debugParam,
#if LLVM_VERSION_AT_LEAST(3, 6)
		                   diBuilder().createExpression(),
#if LLVM_VERSION_AT_LEAST(3, 7)
		                   llvm::DebugLoc::get(entryLN, 1, mDebugFunc),
#endif
#endif
		                   &allocBlock())
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    ->setDebugLoc(llvm::DebugLoc::get(entryLN, 1, mDebugFunc))
#endif
		    ;  // TODO(#65): line numbers

		++idx;
	}

	// create mPostPureBreak
	llvm::IRBuilder<> allocBuilder{&allocBlock()};
	mPostPureBreak = allocBuilder.CreateAlloca(
	    llvm::IntegerType::getInt8PtrTy(context().llvmContext()), nullptr, "pure_jumpback");

	// alloc local variables and zero them
	for (const auto& localVar : function().localVariables()) {
		mLocalVariables[localVar.name] =
		    allocBuilder.CreateAlloca(localVar.type.llvmType(), nullptr, "var_" + localVar.name);
		allocBuilder.CreateStore(llvm::Constant::getNullValue(localVar.type.llvmType()),
		                         mLocalVariables[localVar.name]);
	}

	return res;
}

Result FunctionCompiler::compile() {
	assert(initialized() && "You must initialize a FunctionCompiler before you compile it");
	assert(compiled() == false && "You cannot compile a FunctionCompiler twice");

	// compile the entry
	auto entry = function().entryNode();
	assert(entry != nullptr);

	std::deque<std::pair<NodeInstance*, size_t>> nodesToCompile;
	nodesToCompile.emplace_back(entry, 0);

	Result res;

	auto compilePureDependencies = [this](NodeInstance& node) {
		Result res;

		auto depPures = dependentPuresRecursive(node);
		for (auto pure : depPures) {
			auto compiler = getOrCreateNodeCompiler(*pure);
			res += compiler->compile_stage2({}, 0);

			if (!res) { return res; }
		}
		return res;
	};

	while (!nodesToCompile.empty()) {
		auto& node        = *nodesToCompile[0].first;
		auto  inputExecID = nodesToCompile[0].second;

		assert(!node.type().pure());

		auto compiler = getOrCreateNodeCompiler(node);
		if (compiler->compiled(inputExecID)) {
			nodesToCompile.pop_front();

			continue;
		}

		// compile dependent pures
		res += compilePureDependencies(node);
		if (!res) { return res; }

		std::vector<llvm::BasicBlock*> outputBlocks;
		// make sure the output nodes have done stage 1 and collect output blocks
		for (const auto& conn : node.outputExecConnections) {
			res += compilePureDependencies(*conn.first);
			if (!res) { return res; }

			auto depCompiler = getOrCreateNodeCompiler(*conn.first);
			depCompiler->compile_stage1(conn.second);

			outputBlocks.push_back(&depCompiler->firstBlock(conn.second));
		}

		// compile this one
		res += compiler->compile_stage2(outputBlocks, inputExecID);
		if (!res) { return res; }

		// recurse
		for (const auto& conn : node.outputExecConnections) {
			// add them to the end
			nodesToCompile.emplace_back(conn.first, conn.second);
		}

		// pop it off
		nodesToCompile.pop_front();
	}

	if (!res) { return res; }

	llvm::IRBuilder<> allocBuilder{&allocBlock()};
	allocBuilder.CreateBr(&nodeCompiler(*entry)->firstBlock(0));

	return res;
}

FunctionCompiler::DebugFunctionType FunctionCompiler::createSubroutineType() {
	// create param list
	std::vector<
#if LLVM_VERSION_LESS_EQUAL(3, 5)
	    llvm::Value*
#else
	    llvm::Metadata*
#endif
	    >
	    params;
	{
		// ret first
		DataType intType = function().context().langModule()->typeFromName("i32");
		assert(intType.valid());

		params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    *
#endif
		    intType.debugType());

		// then first in inputexec id
		params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    *
#endif
		    intType.debugType());

		// add paramters
		for (const auto& dType :
		     boost::range::join(function().dataInputs(), function().dataOutputs())) {
			params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			    *
#endif
			    dType.type.debugType());
		}
	}

	// create type
	auto subroutineType = diBuilder().createSubroutineType(
#if LLVM_VERSION_LESS_EQUAL(3, 7)
	    mDIFile,
#endif
	    diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 5)
	    getOrCreateArray
#else
	    getOrCreateTypeArray
#endif
	    (params));

	return subroutineType;
}

llvm::Value* FunctionCompiler::localVariable(boost::string_view name) {
	assert(initialized() &&
	       "Please initialize the function compiler before getting a local variable");

	auto iter = mLocalVariables.find(name.to_string());
	if (iter != mLocalVariables.end()) { return iter->second; }
	return nullptr;
}

GraphModule& FunctionCompiler::module() const { return function().module(); }
Context&     FunctionCompiler::context() const { return function().context(); }

int FunctionCompiler::nodeLineNumber(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get node line number for a node not in the function");

	auto iter = mNodeLocations.right.find(&node);
	if (iter == mNodeLocations.right.end()) {
		return -1;  // ?
	}
	return iter->second;
}

NodeCompiler* FunctionCompiler::nodeCompiler(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get a NodeCompiler for a node instance not in this function");

	auto iter = mNodeCompilers.find(&node);
	if (iter != mNodeCompilers.end()) { return &iter->second; }
	return nullptr;
}

NodeCompiler* FunctionCompiler::getOrCreateNodeCompiler(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get a NodeCompiler for a node instance not in this function");

	auto iter = mNodeCompilers.find(&node);
	if (iter != mNodeCompilers.end()) { return &iter->second; }
	return &mNodeCompilers.emplace(&node, NodeCompiler{*this, node}).first->second;
}

Result compileFunction(const GraphFunction& func, llvm::Module* mod, llvm::DICompileUnit* debugCU,
                       llvm::DIBuilder& debugBuilder) {
	FunctionCompiler compiler{func, *mod, *debugCU, debugBuilder};

	auto res = compiler.initialize();
	if (!res) { return res; }

	res += compiler.compile();

	return res;
}

}  // namespace chi
<commit_msg>Fix Version switch<commit_after>/// \file FunctionCompiler.cpp

#include "chi/FunctionCompiler.hpp"
#include "chi/Context.hpp"
#include "chi/DataType.hpp"
#include "chi/FunctionValidator.hpp"
#include "chi/GraphFunction.hpp"
#include "chi/GraphModule.hpp"
#include "chi/LLVMVersion.hpp"
#include "chi/LangModule.hpp"
#include "chi/NameMangler.hpp"
#include "chi/NodeInstance.hpp"
#include "chi/NodeType.hpp"
#include "chi/Support/Result.hpp"

#include <boost/bimap.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/range/join.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <unordered_map>

#include <llvm/IR/DIBuilder.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>

namespace fs = boost::filesystem;

namespace chi {

FunctionCompiler::FunctionCompiler(const chi::GraphFunction& func, llvm::Module& moduleToGenInto,
                                   llvm::DICompileUnit& debugCU, llvm::DIBuilder& debugBuilder)
    : mModule{&moduleToGenInto}, mDIBuilder{&debugBuilder}, mDebugCU{&debugCU}, mFunction{&func} {}

Result FunctionCompiler::initialize(bool validate) {
	assert(initialized() == false && "Cannot initialize a FunctionCompiler more than once");

	mInitialized = true;

	Result res;
	auto   compilerCtx = res.addScopedContext(
	    {{"Function", function().name()}, {"Module", function().module().fullName()}});

	if (validate) {
		res += validateFunction(function());
		if (!res) { return res; }
	}

	// get the entry node
	auto entry = function().entryNode();
	if (entry == nullptr) {
		res.addEntry("EUKN", "No entry node", {});
		return res;
	}

	// create function
	auto mangledName = mangleFunctionName(module().fullName(), function().name());
	mLLFunction      = llvm::cast<llvm::Function>(
	    llvmModule().getOrInsertFunction(mangledName, function().functionType()));

	// create the debug file
	mDIFile = diBuilder().createFile(debugCompileUnit()->getFilename(),
	                                        debugCompileUnit()->getDirectory());

	auto subroutineType = createSubroutineType();

	mNodeLocations = module().createLineNumberAssoc();
	auto entryLN   = nodeLineNumber(*entry);

	// TODO(#65): line numbers?
	mDebugFunc =
	    diBuilder().createFunction(mDIFile, module().fullName() + ":" + function().name(),
	                               mangledName, mDIFile, entryLN, subroutineType, false, true, 0,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
	                               0,
#else
	                               llvm::DINode::DIFlags{},
#endif
	                               false);

#if LLVM_VERSION_LESS_EQUAL(3, 6)
	mDebugFunc.replaceFunction(mLLFunction);
#elif LLVM_VERSION_LESS_EQUAL(3, 7)
	mDebugFunc->replaceFunction(mLLFunction);
#else
	mLLFunction->setSubprogram(mDebugFunc);
#endif

	mAllocBlock = llvm::BasicBlock::Create(context().llvmContext(), "alloc", mLLFunction);

	// set argument names
	auto idx = 0ull;
	for (auto& arg : mLLFunction->
#if LLVM_VERSION_AT_LEAST(5, 0)
	                 args()
#else
	                 getArgumentList()
#endif
	         ) {
		// the first one is the input exec ID
		if (idx == 0) {
			arg.setName("inputexec_id");

			// create debug info
			DataType intDataType;
			res += context().typeFromModule("lang", "i32", &intDataType);
			assert(intDataType.valid());
			auto debugParam = diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 7)
			                  createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, mDebugFunc,
			                                      "inputexec_id", mDIFile, entryLN,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			                                      *
#endif
			                                      intDataType.debugType());
#else

			                  createParameterVariable(mDebugFunc, "inputexec_id", 1, mDIFile,
			                                          entryLN, intDataType.debugType());
#endif
			diBuilder()
			    .insertDeclare(&arg, debugParam,
#if LLVM_VERSION_AT_LEAST(3, 6)
			                   diBuilder().createExpression(),
#if LLVM_VERSION_AT_LEAST(3, 7)
			                   llvm::DebugLoc::get(entryLN, 1, mDebugFunc),
#endif
#endif
			                   &allocBlock())
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			    ->setDebugLoc(llvm::DebugLoc::get(entryLN, 1, mDebugFunc))
#endif
			    ;  // TODO(#65): "line" numbers

			++idx;
			continue;
		}

		NamedDataType tyAndName;
		// all the - 1's is becaues the first is the inputexec_id
		if (idx - 1 < function().dataInputs().size()) {
			tyAndName = function().dataInputs()[idx - 1];
		} else {
			tyAndName = function().dataOutputs()[idx - 1 - entry->type().dataOutputs().size()];
		}
		arg.setName(tyAndName.name);

		// create debug info

		// create DIType*
		llvm::DIType* dType      = tyAndName.type.debugType();
		auto          debugParam = diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 7)
		                  createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, mDebugFunc,
		                                      tyAndName.name, mDIFile, entryLN,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		                                      *
#endif
		                                      dType);
#else
		                  createParameterVariable(mDebugFunc, tyAndName.name,
		                                          idx + 1,  // + 1 because it starts at 1
		                                          mDIFile, entryLN, dType);
#endif
		diBuilder()
		    .insertDeclare(&arg, debugParam,
#if LLVM_VERSION_AT_LEAST(3, 6)
		                   diBuilder().createExpression(),
#if LLVM_VERSION_AT_LEAST(3, 7)
		                   llvm::DebugLoc::get(entryLN, 1, mDebugFunc),
#endif
#endif
		                   &allocBlock())
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    ->setDebugLoc(llvm::DebugLoc::get(entryLN, 1, mDebugFunc))
#endif
		    ;  // TODO(#65): line numbers

		++idx;
	}

	// create mPostPureBreak
	llvm::IRBuilder<> allocBuilder{&allocBlock()};
	mPostPureBreak = allocBuilder.CreateAlloca(
	    llvm::IntegerType::getInt8PtrTy(context().llvmContext()), nullptr, "pure_jumpback");

	// alloc local variables and zero them
	for (const auto& localVar : function().localVariables()) {
		mLocalVariables[localVar.name] =
		    allocBuilder.CreateAlloca(localVar.type.llvmType(), nullptr, "var_" + localVar.name);
		allocBuilder.CreateStore(llvm::Constant::getNullValue(localVar.type.llvmType()),
		                         mLocalVariables[localVar.name]);
	}

	return res;
}

Result FunctionCompiler::compile() {
	assert(initialized() && "You must initialize a FunctionCompiler before you compile it");
	assert(compiled() == false && "You cannot compile a FunctionCompiler twice");

	// compile the entry
	auto entry = function().entryNode();
	assert(entry != nullptr);

	std::deque<std::pair<NodeInstance*, size_t>> nodesToCompile;
	nodesToCompile.emplace_back(entry, 0);

	Result res;

	auto compilePureDependencies = [this](NodeInstance& node) {
		Result res;

		auto depPures = dependentPuresRecursive(node);
		for (auto pure : depPures) {
			auto compiler = getOrCreateNodeCompiler(*pure);
			res += compiler->compile_stage2({}, 0);

			if (!res) { return res; }
		}
		return res;
	};

	while (!nodesToCompile.empty()) {
		auto& node        = *nodesToCompile[0].first;
		auto  inputExecID = nodesToCompile[0].second;

		assert(!node.type().pure());

		auto compiler = getOrCreateNodeCompiler(node);
		if (compiler->compiled(inputExecID)) {
			nodesToCompile.pop_front();

			continue;
		}

		// compile dependent pures
		res += compilePureDependencies(node);
		if (!res) { return res; }

		std::vector<llvm::BasicBlock*> outputBlocks;
		// make sure the output nodes have done stage 1 and collect output blocks
		for (const auto& conn : node.outputExecConnections) {
			res += compilePureDependencies(*conn.first);
			if (!res) { return res; }

			auto depCompiler = getOrCreateNodeCompiler(*conn.first);
			depCompiler->compile_stage1(conn.second);

			outputBlocks.push_back(&depCompiler->firstBlock(conn.second));
		}

		// compile this one
		res += compiler->compile_stage2(outputBlocks, inputExecID);
		if (!res) { return res; }

		// recurse
		for (const auto& conn : node.outputExecConnections) {
			// add them to the end
			nodesToCompile.emplace_back(conn.first, conn.second);
		}

		// pop it off
		nodesToCompile.pop_front();
	}

	if (!res) { return res; }

	llvm::IRBuilder<> allocBuilder{&allocBlock()};
	allocBuilder.CreateBr(&nodeCompiler(*entry)->firstBlock(0));

	return res;
}

FunctionCompiler::DebugFunctionType FunctionCompiler::createSubroutineType() {
	// create param list
	std::vector<
#if LLVM_VERSION_LESS_EQUAL(3, 5)
	    llvm::Value*
#else
	    llvm::Metadata*
#endif
	    >
	    params;
	{
		// ret first
		DataType intType = function().context().langModule()->typeFromName("i32");
		assert(intType.valid());

		params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    *
#endif
		    intType.debugType());

		// then first in inputexec id
		params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    *
#endif
		    intType.debugType());

		// add paramters
		for (const auto& dType :
		     boost::range::join(function().dataInputs(), function().dataOutputs())) {
			params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			    *
#endif
			    dType.type.debugType());
		}
	}

	// create type
	auto subroutineType = diBuilder().createSubroutineType(
#if LLVM_VERSION_LESS_EQUAL(3, 7)
	    mDIFile,
#endif
	    diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 5)
	    getOrCreateArray
#else
	    getOrCreateTypeArray
#endif
	    (params));

	return subroutineType;
}

llvm::Value* FunctionCompiler::localVariable(boost::string_view name) {
	assert(initialized() &&
	       "Please initialize the function compiler before getting a local variable");

	auto iter = mLocalVariables.find(name.to_string());
	if (iter != mLocalVariables.end()) { return iter->second; }
	return nullptr;
}

GraphModule& FunctionCompiler::module() const { return function().module(); }
Context&     FunctionCompiler::context() const { return function().context(); }

int FunctionCompiler::nodeLineNumber(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get node line number for a node not in the function");

	auto iter = mNodeLocations.right.find(&node);
	if (iter == mNodeLocations.right.end()) {
		return -1;  // ?
	}
	return iter->second;
}

NodeCompiler* FunctionCompiler::nodeCompiler(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get a NodeCompiler for a node instance not in this function");

	auto iter = mNodeCompilers.find(&node);
	if (iter != mNodeCompilers.end()) { return &iter->second; }
	return nullptr;
}

NodeCompiler* FunctionCompiler::getOrCreateNodeCompiler(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get a NodeCompiler for a node instance not in this function");

	auto iter = mNodeCompilers.find(&node);
	if (iter != mNodeCompilers.end()) { return &iter->second; }
	return &mNodeCompilers.emplace(&node, NodeCompiler{*this, node}).first->second;
}

Result compileFunction(const GraphFunction& func, llvm::Module* mod, llvm::DICompileUnit* debugCU,
                       llvm::DIBuilder& debugBuilder) {
	FunctionCompiler compiler{func, *mod, *debugCU, debugBuilder};

	auto res = compiler.initialize();
	if (!res) { return res; }

	res += compiler.compile();

	return res;
}

}  // namespace chi
<|endoftext|>