<commit_before>/* vim: set ts=2 expandtab: */
/**
 *       @file  test.cpp
 *      @brief
 *
 *     @author  Josh King (jheretic), jking@chambana.net
 *
 *   @internal
 *      Created  11/17/2013 06:01:11 PM
 *     Compiler  gcc/g++
 * Organization  The Open Technology Institute
 *    Copyright  Copyright (c) 2013, Josh King
 *
 * This file is part of Commotion, Copyright (c) 2013, Josh King
 *
 * Commotion is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * Commotion is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Commotion.  If not, see <http://www.gnu.org/licenses/>.
 *
 * =====================================================================================
 */
extern "C" {
#include "../src/obj.h"
#include "../src/list.h"
#include "../src/tree.h"
}
#include "gtest/gtest.h"

/*
 * NOTE: Inserting keys with different length values will be interpreted as different keys (eg insert("test", 5) and insert("test", 6) are not the same
 * and their values will be stored in different nodes in the tree
 *
 *
 */

class TreeTest : public ::testing::Test
{
  protected:
    co_obj_t *Tree16;
    co_obj_t *Tree32;
    void InsertObj();
    void DeleteObj();
    void UpdateObj();
    co_obj_t *TestString1;
    co_obj_t *TestString2;
    co_obj_t *ReplaceString1;

    co_obj_t *TestString3;

    co_obj_t *ptr;
    int ret;

    TreeTest()
    {
      Tree16 = co_tree16_create();
      Tree32 = co_tree32_create();

      TestString1 = co_str8_create("1TESTVALUE1", 12, 0);
      TestString2 = co_str8_create("2TESTVALUE2", 12, 0);

      // TestString3 = co_str8_create("1TESTVALUE1", 12, 0);

      ReplaceString1 = co_str8_create("REPLACE", 9, 0);
    }

    virtual void SetUp()
    {
    }

    ~TreeTest()
    {
      co_obj_free(Tree16);
      co_obj_free(Tree32);
    }
};

void TreeTest::InsertObj()
{
  ret = co_tree_insert(Tree16, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(TestString1, ptr);

  ret = co_tree_insert(Tree16, "2TESTKEY2", 10, TestString2);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree16, "2TESTKEY2", 10);
  ASSERT_EQ(TestString2, ptr);

  ret = co_tree_insert_force(Tree16, "1TESTKEY1", 10, ReplaceString1);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(ReplaceString1, ptr);

  // reinitialize TestString1 since it was freed by co_tree_insert_force()
  TestString1 = co_str8_create("1TESTVALUE1", 12, 0);

  // repeat for Tree 32
  ret = co_tree_insert(Tree32, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(TestString1, ptr);

  ret = co_tree_insert(Tree32, "2TESTKEY2", 10, TestString2);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree32, "2TESTKEY2", 10);
  ASSERT_EQ(TestString2, ptr);

  ret = co_tree_insert_force(Tree32, "1TESTKEY1", 10, ReplaceString1);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(ReplaceString1, ptr);

}

void TreeTest::DeleteObj()
{

  ret = co_tree_insert(Tree16, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ret = co_tree_insert(Tree16, "2TESTKEY2", 10, TestString2);
  ASSERT_EQ(1, ret);

  ptr = co_tree_delete(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(TestString1, ptr);

  ptr = co_tree_delete(Tree16, "2TESTKEY2", 10);
  ASSERT_EQ(TestString2, ptr);

  // confirm deletions
  ptr = co_tree_find(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(NULL, ptr);

  ptr = co_tree_find(Tree16, "2TESTKEY2", 10);
  ASSERT_EQ(NULL, ptr);

  // repeat for Tree32
  ret = co_tree_insert(Tree32, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ret = co_tree_insert(Tree32, "2TESTKEY2", 10, TestString2);
  ASSERT_EQ(1, ret);

  ptr = co_tree_delete(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(TestString1, ptr);

  ptr = co_tree_delete(Tree32, "2TESTKEY2", 10);
  ASSERT_EQ(TestString2, ptr);

  // confirm deletions
  ptr = co_tree_find(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(NULL, ptr);

  ptr = co_tree_find(Tree32, "2TESTKEY2", 10);
  ASSERT_EQ(NULL, ptr);
}

void TreeTest::UpdateObj()
{
  ret = co_tree_insert(Tree16, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ret = co_tree_set_str(Tree16, "1TESTKEY1", 10, "REPLACE", 9);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(0, co_str_cmp(ptr, ReplaceString1));

  /*
  // repeat for Tree32
  ret = co_tree_insert(Tree32, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ret = co_tree_set_str(Tree32, "1TESTKEY1", 10, "REPLACE", 9);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(0, co_str_cmp(ptr, ReplaceString1));
  */
}

TEST_F(TreeTest, TreeInsertTest)
{
  InsertObj();
}

TEST_F(TreeTest, TreeDeleteTest)
{
  DeleteObj();
}

TEST_F(TreeTest, TreeUpdateTest)
{
    UpdateObj();
}
<commit_msg>did stuff<commit_after>/* vim: set ts=2 expandtab: */
/**
 *       @file  test.cpp
 *      @brief
 *
 *     @author  Josh King (jheretic), jking@chambana.net
 *
 *   @internal
 *      Created  11/17/2013 06:01:11 PM
 *     Compiler  gcc/g++
 * Organization  The Open Technology Institute
 *    Copyright  Copyright (c) 2013, Josh King
 *
 * This file is part of Commotion, Copyright (c) 2013, Josh King
 *
 * Commotion is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * Commotion is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Commotion.  If not, see <http://www.gnu.org/licenses/>.
 *
 * =====================================================================================
 */
extern "C" {
#include "../src/obj.h"
#include "../src/list.h"
#include "../src/tree.h"
}
#include "gtest/gtest.h"

/*
 * NOTE: Inserting keys with different length values will be interpreted as different keys (eg insert("test", 5) and insert("test", 6) are not the same
 * and their values will be stored in different nodes in the tree
 *
 *
 */

class TreeTest : public ::testing::Test
{
  protected:
    co_obj_t *Tree16;
    co_obj_t *Tree32;
    void InsertObj();
    void DeleteObj();
    void UpdateObj();
    co_obj_t *TestString1;
    co_obj_t *TestString2;
    co_obj_t *ReplaceString1;

    co_obj_t *TestString3;

    co_obj_t *ptr;
    int ret;

    TreeTest()
    {
      Tree16 = co_tree16_create();
      Tree32 = co_tree32_create();

      TestString1 = co_str8_create("1TESTVALUE1", 12, 0);
      TestString2 = co_str8_create("2TESTVALUE2", 12, 0);

      ReplaceString1 = co_str8_create("REPLACE", 9, 0);
    }

    virtual void SetUp()
    {
    }

    ~TreeTest()
    {
      co_obj_free(Tree16);
      co_obj_free(Tree32);
    }
};

void TreeTest::InsertObj()
{
  ret = co_tree_insert(Tree16, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(TestString1, ptr);

  ret = co_tree_insert(Tree16, "2TESTKEY2", 10, TestString2);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree16, "2TESTKEY2", 10);
  ASSERT_EQ(TestString2, ptr);

  ret = co_tree_insert_force(Tree16, "1TESTKEY1", 10, ReplaceString1);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(ReplaceString1, ptr);

  // reinitialize TestString1 since it was freed by co_tree_insert_force()
  TestString1 = co_str8_create("1TESTVALUE1", 12, 0);

  // repeat for Tree 32
  ret = co_tree_insert(Tree32, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(TestString1, ptr);

  ret = co_tree_insert(Tree32, "2TESTKEY2", 10, TestString2);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree32, "2TESTKEY2", 10);
  ASSERT_EQ(TestString2, ptr);

  ret = co_tree_insert_force(Tree32, "1TESTKEY1", 10, ReplaceString1);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(ReplaceString1, ptr);

}

void TreeTest::DeleteObj()
{

  ret = co_tree_insert(Tree16, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ret = co_tree_insert(Tree16, "2TESTKEY2", 10, TestString2);
  ASSERT_EQ(1, ret);

  ptr = co_tree_delete(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(TestString1, ptr);

  ptr = co_tree_delete(Tree16, "2TESTKEY2", 10);
  ASSERT_EQ(TestString2, ptr);

  // confirm deletions
  ptr = co_tree_find(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(NULL, ptr);

  ptr = co_tree_find(Tree16, "2TESTKEY2", 10);
  ASSERT_EQ(NULL, ptr);

  // reinitialize
  TestString1 = co_str8_create("1TESTVALUE1", 12, 0);
  TestString2 = co_str8_create("2TESTVALUE2", 12, 0);

  // repeat for Tree32
  ret = co_tree_insert(Tree32, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ret = co_tree_insert(Tree32, "2TESTKEY2", 10, TestString2);
  ASSERT_EQ(1, ret);

  ptr = co_tree_delete(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(TestString1, ptr);

  ptr = co_tree_delete(Tree32, "2TESTKEY2", 10);
  ASSERT_EQ(TestString2, ptr);

  // confirm deletions
  ptr = co_tree_find(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(NULL, ptr);

  ptr = co_tree_find(Tree32, "2TESTKEY2", 10);
  ASSERT_EQ(NULL, ptr);
}

void TreeTest::UpdateObj()
{
  ret = co_tree_insert(Tree16, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ret = co_tree_set_str(Tree16, "1TESTKEY1", 10, "REPLACE", 9);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree16, "1TESTKEY1", 10);
  ASSERT_EQ(0, co_str_cmp(ptr, ReplaceString1));

  // repeat for Tree32
  ret = co_tree_insert(Tree32, "1TESTKEY1", 10, TestString1);
  ASSERT_EQ(1, ret);

  ret = co_tree_set_str(Tree32, "1TESTKEY1", 10, "REPLACE", 9);
  ASSERT_EQ(1, ret);

  ptr = co_tree_find(Tree32, "1TESTKEY1", 10);
  ASSERT_EQ(0, co_str_cmp(ptr, ReplaceString1));

}

TEST_F(TreeTest, TreeInsertTest)
{
  InsertObj();
}

TEST_F(TreeTest, TreeDeleteTest)
{
  DeleteObj();
}

/*
TEST_F(TreeTest, TreeUpdateTest)
{
    UpdateObj();
}
*/<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 Northeastern University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "include/gpu_operations.h"
#include "Eigen/Dense"
#include "gtest/gtest.h"

template<class T>
class GpuMatrixMatrixSubTest : public ::testing::Test {
 public:
  Nice::Matrix<T> a;
  Nice::Matrix<T> b;
  Nice::Matrix<T> result;
  Nice::Matrix<T> correct;

  void Subtract() {
    result = Nice::GpuOperations<T>::Subtract(a, b);
  }
};

typedef ::testing::Types<float, double> dataTypes;
TYPED_TEST_CASE(GpuMatrixMatrixSubTest, dataTypes);

TYPED_TEST(GpuMatrixMatrixSubTest, SubtractFunctionality) {
  this->a.setRandom(3, 3);
  this->b.setRandom(3, 3);

  this->correct.setZero(3, 3);
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 3; ++j) {
      correct(i, j) = a(i, j) - b(i, j);
    }
  }

  this->Subtract();

  ASSERT_NEAR(this->result, this->correct, 0.0001);
}

TYPED_TEST(GpuMatrixMatrixSubTest, DifferentSizeMatricies) {
  this->a.setRandom(2, 3);
  this->b.setRandom(3, 4);
  ASSERT_DEATH(this->Subtract(), ".*");
}

TYPED_TEST(GpuMatrixMatrixSubTest, EmptyMatrix) {
  ASSERT_DEATH(this->Subtract(), ".*");
}
<commit_msg>Fixed this-> in test and ASSERT_NEAR in for loop<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Northeastern University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "include/gpu_operations.h"
#include "Eigen/Dense"
#include "gtest/gtest.h"

template<class T>
class GpuMatrixMatrixSubTest : public ::testing::Test {
 public:
  Nice::Matrix<T> a;
  Nice::Matrix<T> b;
  Nice::Matrix<T> result;
  Nice::Matrix<T> correct;

  void Subtract() {
    result = Nice::GpuOperations<T>::Subtract(a, b);
  }
};

typedef ::testing::Types<float, double> dataTypes;
TYPED_TEST_CASE(GpuMatrixMatrixSubTest, dataTypes);

TYPED_TEST(GpuMatrixMatrixSubTest, SubtractFunctionality) {
  this->a.setRandom(3, 3);
  this->b.setRandom(3, 3);

  this->correct.setZero(3, 3);
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 3; ++j) {
      this->correct(i, j) = this->a(i, j) - this->b(i, j);
    }
  }

  this->Subtract();

  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 3; ++j) {
      ASSERT_NEAR(this->result(i, j), this->correct(i, j), 0.0001);
    }
  }
}

TYPED_TEST(GpuMatrixMatrixSubTest, DifferentSizeMatricies) {
  this->a.setRandom(2, 3);
  this->b.setRandom(3, 4);
  ASSERT_DEATH(this->Subtract(), ".*");
}

TYPED_TEST(GpuMatrixMatrixSubTest, EmptyMatrix) {
  ASSERT_DEATH(this->Subtract(), ".*");
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2017 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.
 */

#include "otbWrapperCompositeApplication.h"
#include "otbWrapperApplicationFactory.h"

namespace otb
{
namespace Wrapper
{

/**
 * \class LargeScaleMeanShift
 *
 * \brief All-in-one application for the LSMS framework
 *
 * This application gathers the 4 steps of the large-scale MeanShift
 * segmentation framework.
 *
 */
class LargeScaleMeanShift : public CompositeApplication
{
public:
  /** Standard class typedefs. */
  typedef LargeScaleMeanShift           Self;
  typedef CompositeApplication          Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

/** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(LargeScaleMeanShift, otb::CompositeApplication);

private:
  void DoInit() ITK_OVERRIDE
    {
    SetName("LargeScaleMeanShift");
    SetDescription("Large-scale segmentation using MeanShift");

    // Documentation
    SetDocName("Large-Scale MeanShift");
    SetDocLongDescription("This application chains together the 4 steps of the "
      "MeanShit framework, that is the MeanShiftSmoothing [1], the "
      "LSMSSegmentation [2], the LSMSSmallRegionsMerging [3] and the "
      "LSMSVectorization [4].\n\n"
      "This application can be a preliminary step for an object-based analysis.\n\n"
      "It generates a vector data file containing the regions extracted with "
      "the MeanShift algorithm. The spatial and range radius parameters allow "
      "to adapt the sensitivity of the algorithm depending on the image dynamic "
      "and resolution. There is a step to remove small regions whose size "
      "(in pixels) is less than the given 'minsize' parameter. These regions "
      "are merged to a similar neighbor region. In the output vectors, there "
      "are additional fields to describe each region. In particular the mean "
      "and standard deviation (for each band) is computed for each region "
      "using the input image as support. If an optional 'imfield' image is "
      "given, it will be used as support image instead."
      );
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("[1] MeanShiftSmoothing\n"
      "[2] LSMSSegmentation\n"
      "[3] LSMSSmallRegionsMerging\n"
      "[4] LSMSVectorization");

    AddDocTag(Tags::Segmentation);
    AddDocTag("LSMS");

    ClearApplications();
    AddApplication("MeanShiftSmoothing", "smoothing", "Smoothing step");
    AddApplication("LSMSSegmentation", "segmentation", "Segmentation step");
    AddApplication("LSMSSmallRegionsMerging", "merging", "Small region merging step");
    AddApplication("LSMSVectorization", "vectorization", "Vectorization step");

    ShareParameter("in","smoothing.in");
    ShareParameter("spatialr","smoothing.spatialr");
    ShareParameter("ranger","smoothing.ranger");
    ShareParameter("minsize","merging.minsize");

    ShareParameter("tilesizex","segmentation.tilesizex");
    ShareParameter("tilesizey","segmentation.tilesizey");

    AddParameter(ParameterType_InputImage, "imfield", "Support image for field computation");
    SetParameterDescription( "imfield", "This is an optional support image "
      "that can be used to compute field values in each region." );
    MandatoryOff("imfield");

    ShareParameter("out","vectorization.out");

    AddParameter( ParameterType_Empty, "cleanup", "Temporary files cleaning" );
    EnableParameter( "cleanup" );
    SetParameterDescription( "cleanup",
      "If activated, the application will try to clean all temporary files it created" );
    MandatoryOff( "cleanup" );

    // Setup RAM
    ShareParameter("ram","smoothing.ram");
    Connect("merging.ram","smoothing.ram");
    Connect("vectorization.ram","smoothing.ram");

    Connect("merging.tilesizex","segmentation.tilesizex");
    Connect("merging.tilesizey","segmentation.tilesizey");
    Connect("vectorization.tilesizex","segmentation.tilesizex");
    Connect("vectorization.tilesizey","segmentation.tilesizey");

    // TODO : this is not exactly true, we used to choose the smoothed image instead
    Connect("merging.in","smoothing.in");

    // Setup constant parameters
    GetInternalApplication("smoothing")->SetParameterString("foutpos","foo");
    GetInternalApplication("smoothing")->EnableParameter("foutpos");

    // Doc example parameter settings
    SetDocExampleParameterValue("in", "QB_1_ortho.tif");
    SetDocExampleParameterValue("spatialr", "4");
    SetDocExampleParameterValue("ranger", "80");
    SetDocExampleParameterValue("minsize", "16");
    SetDocExampleParameterValue("out", "regions.shp");

    SetOfficialDocLink();
    }

  void DoUpdateParameters() ITK_OVERRIDE
  {}

  void DoExecute() ITK_OVERRIDE
    {
    std::vector<std::string> tmpFilenames;
    tmpFilenames.push_back(GetParameterString("out")+std::string("_labelmap.tif"));
    tmpFilenames.push_back(GetParameterString("out")+std::string("_labelmap_merged.tif"));
    tmpFilenames.push_back(GetParameterString("out")+std::string("_labelmap.geom"));
    tmpFilenames.push_back(GetParameterString("out")+std::string("_labelmap_merged.geom"));
    ExecuteInternal("smoothing");
    // in-memory connexion here (saves 1 additional update for foutpos)
    GetInternalApplication("segmentation")->SetParameterInputImage("in",
      GetInternalApplication("smoothing")->GetParameterOutputImage("fout"));
    GetInternalApplication("segmentation")->SetParameterInputImage("inpos",
      GetInternalApplication("smoothing")->GetParameterOutputImage("foutpos"));
    // temporary file output here
    GetInternalApplication("segmentation")->SetParameterString("out",
      tmpFilenames[0]);
    // take half of previous radii
    GetInternalApplication("segmentation")->SetParameterFloat("spatialr",
      0.5 * (double)GetInternalApplication("smoothing")->GetParameterInt("spatialr"));
    GetInternalApplication("segmentation")->SetParameterFloat("ranger",
      0.5 * GetInternalApplication("smoothing")->GetParameterFloat("ranger"));
    GetInternalApplication("segmentation")->ExecuteAndWriteOutput();

    GetInternalApplication("merging")->SetParameterString("inseg",
      tmpFilenames[0]);
    GetInternalApplication("merging")->SetParameterString("out",
      tmpFilenames[1]);
    GetInternalApplication("merging")->ExecuteAndWriteOutput();

    if (IsParameterEnabled("imfield") && HasValue("imfield"))
      {
      GetInternalApplication("vectorization")->SetParameterString("in",
        GetParameterString("imfield"));
      }
    else
      {
      GetInternalApplication("vectorization")->SetParameterString("in",
        GetParameterString("in"));
      }
    GetInternalApplication("vectorization")->SetParameterString("inseg",
      tmpFilenames[1]);
    ExecuteInternal("vectorization");

    if( IsParameterEnabled( "cleanup" ) )
      {
      otbAppLogINFO( <<"Final clean-up ..." );
      for (unsigned int i=0 ; i<tmpFilenames.size() ; ++i)
        {
        if(itksys::SystemTools::FileExists(tmpFilenames[i].c_str()))
          {
          itksys::SystemTools::RemoveFile(tmpFilenames[i].c_str());
          }
        }
      }
    }

};

} // end of namespace Wrapper
} // end of namespace otb

OTB_APPLICATION_EXPORT(otb::Wrapper::LargeScaleMeanShift)
<commit_msg>ENH: switch between raster and vector output<commit_after>/*
 * Copyright (C) 2005-2017 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.
 */

#include "otbWrapperCompositeApplication.h"
#include "otbWrapperApplicationFactory.h"

namespace otb
{
namespace Wrapper
{

/**
 * \class LargeScaleMeanShift
 *
 * \brief All-in-one application for the LSMS framework
 *
 * This application gathers the 4 steps of the large-scale MeanShift
 * segmentation framework.
 *
 */
class LargeScaleMeanShift : public CompositeApplication
{
public:
  /** Standard class typedefs. */
  typedef LargeScaleMeanShift           Self;
  typedef CompositeApplication          Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

/** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(LargeScaleMeanShift, otb::CompositeApplication);

private:
  void DoInit() ITK_OVERRIDE
    {
    SetName("LargeScaleMeanShift");
    SetDescription("Large-scale segmentation using MeanShift");

    // Documentation
    SetDocName("Large-Scale MeanShift");
    SetDocLongDescription("This application chains together the 4 steps of the "
      "MeanShit framework, that is the MeanShiftSmoothing [1], the "
      "LSMSSegmentation [2], the LSMSSmallRegionsMerging [3] and the "
      "LSMSVectorization [4].\n\n"
      "This application can be a preliminary step for an object-based analysis.\n\n"
      "It generates a vector data file containing the regions extracted with "
      "the MeanShift algorithm. The spatial and range radius parameters allow "
      "to adapt the sensitivity of the algorithm depending on the image dynamic "
      "and resolution. There is a step to remove small regions whose size "
      "(in pixels) is less than the given 'minsize' parameter. These regions "
      "are merged to a similar neighbor region. In the output vectors, there "
      "are additional fields to describe each region. In particular the mean "
      "and standard deviation (for each band) is computed for each region "
      "using the input image as support. If an optional 'imfield' image is "
      "given, it will be used as support image instead."
      );
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("[1] MeanShiftSmoothing\n"
      "[2] LSMSSegmentation\n"
      "[3] LSMSSmallRegionsMerging\n"
      "[4] LSMSVectorization");

    AddDocTag(Tags::Segmentation);
    AddDocTag("LSMS");

    ClearApplications();
    AddApplication("MeanShiftSmoothing", "smoothing", "Smoothing step");
    AddApplication("LSMSSegmentation", "segmentation", "Segmentation step");
    AddApplication("LSMSSmallRegionsMerging", "merging", "Small region merging step");
    AddApplication("LSMSVectorization", "vectorization", "Vectorization step");

    ShareParameter("in","smoothing.in");
    ShareParameter("spatialr","smoothing.spatialr");
    ShareParameter("ranger","smoothing.ranger");
    ShareParameter("minsize","merging.minsize");

    ShareParameter("tilesizex","segmentation.tilesizex");
    ShareParameter("tilesizey","segmentation.tilesizey");

    AddParameter(ParameterType_Choice, "mode","Output mode");
    SetParameterDescription("mode", "Type of segmented output");

    AddChoice("mode.vector", "Segmentation as vector output.");
    SetParameterDescription("mode.vector","In this mode, the application will "
      "produce a vector file or database and compute field values for each "
      "region");

    AddParameter(ParameterType_InputImage, "mode.vector.imfield", "Support image for field computation");
    SetParameterDescription( "mode.vector.imfield", "This is an optional support image "
      "that can be used to compute field values in each region. Otherwise, the "
      "input image is used as support." );
    MandatoryOff("mode.vector.imfield");

    ShareParameter("mode.vector.out","vectorization.out");

    AddChoice("mode.raster", "Standard segmentation with labeled raster output");
    SetParameterDescription("mode.raster","In this mode, the application will produce a standard labeled raster.");

    ShareParameter("mode.raster.out","merging.out");

    AddParameter( ParameterType_Empty, "cleanup", "Temporary files cleaning" );
    EnableParameter( "cleanup" );
    SetParameterDescription( "cleanup",
      "If activated, the application will try to clean all temporary files it created" );
    MandatoryOff( "cleanup" );

    // Setup RAM
    ShareParameter("ram","smoothing.ram");
    Connect("merging.ram","smoothing.ram");
    Connect("vectorization.ram","smoothing.ram");

    Connect("merging.tilesizex","segmentation.tilesizex");
    Connect("merging.tilesizey","segmentation.tilesizey");
    Connect("vectorization.tilesizex","segmentation.tilesizex");
    Connect("vectorization.tilesizey","segmentation.tilesizey");

    // TODO : this is not exactly true, we used to choose the smoothed image instead
    Connect("merging.in","smoothing.in");

    // Setup constant parameters
    GetInternalApplication("smoothing")->SetParameterString("foutpos","foo");
    GetInternalApplication("smoothing")->EnableParameter("foutpos");

    // Doc example parameter settings
    SetDocExampleParameterValue("in", "QB_1_ortho.tif");
    SetDocExampleParameterValue("spatialr", "4");
    SetDocExampleParameterValue("ranger", "80");
    SetDocExampleParameterValue("minsize", "16");
    SetDocExampleParameterValue("out", "regions.shp");

    SetOfficialDocLink();

    DebugOn();
    }

  void DoUpdateParameters() ITK_OVERRIDE
  {}

  void DoExecute() ITK_OVERRIDE
    {
    std::vector<std::string> tmpFilenames;
    tmpFilenames.push_back(GetParameterString("out")+std::string("_labelmap.tif"));
    tmpFilenames.push_back(GetParameterString("out")+std::string("_labelmap.geom"));
    ExecuteInternal("smoothing");
    // in-memory connexion here (saves 1 additional update for foutpos)
    GetInternalApplication("segmentation")->SetParameterInputImage("in",
      GetInternalApplication("smoothing")->GetParameterOutputImage("fout"));
    GetInternalApplication("segmentation")->SetParameterInputImage("inpos",
      GetInternalApplication("smoothing")->GetParameterOutputImage("foutpos"));
    // temporary file output here
    GetInternalApplication("segmentation")->SetParameterString("out",
      tmpFilenames[0]);
    // take half of previous radii
    GetInternalApplication("segmentation")->SetParameterFloat("spatialr",
      0.5 * (double)GetInternalApplication("smoothing")->GetParameterInt("spatialr"));
    GetInternalApplication("segmentation")->SetParameterFloat("ranger",
      0.5 * GetInternalApplication("smoothing")->GetParameterFloat("ranger"));
    GetInternalApplication("segmentation")->ExecuteAndWriteOutput();

    GetInternalApplication("merging")->SetParameterString("inseg",
      tmpFilenames[0]);
    EnableParameter("mode.raster.out");
    if (GetParameterString("mode") == "vector")
      {
      tmpFilenames.push_back(GetParameterString("out")+std::string("_labelmap_merged.tif"));
      tmpFilenames.push_back(GetParameterString("out")+std::string("_labelmap_merged.geom"));
      GetInternalApplication("merging")->SetParameterString("out",
        tmpFilenames[2]);
      GetInternalApplication("merging")->ExecuteAndWriteOutput();
      if (IsParameterEnabled("mode.vector.imfield") &&
          HasValue("mode.vector.imfield"))
        {
        GetInternalApplication("vectorization")->SetParameterString("in",
          GetParameterString("mode.vector.imfield"));
        }
      else
        {
        GetInternalApplication("vectorization")->SetParameterString("in",
          GetParameterString("in"));
        }
      GetInternalApplication("vectorization")->SetParameterString("inseg",
        tmpFilenames[2]);
      ExecuteInternal("vectorization");
      }
    else
      {
      GetInternalApplication("merging")->ExecuteAndWriteOutput();
      }
    DisableParameter("mode.raster.out");

    if( IsParameterEnabled( "cleanup" ) )
      {
      otbAppLogINFO( <<"Final clean-up ..." );
      for (unsigned int i=0 ; i<tmpFilenames.size() ; ++i)
        {
        if(itksys::SystemTools::FileExists(tmpFilenames[i].c_str()))
          {
          itksys::SystemTools::RemoveFile(tmpFilenames[i].c_str());
          }
        }
      }
    }

};

} // end of namespace Wrapper
} // end of namespace otb

OTB_APPLICATION_EXPORT(otb::Wrapper::LargeScaleMeanShift)
<|endoftext|>


<commit_before>#include "Arith256.h"
#include "Runtime.h"
#include "Type.h"

#include <llvm/IR/Function.h>

namespace dev
{
namespace eth
{
namespace jit
{

Arith256::Arith256(llvm::IRBuilder<>& _builder) :
	CompilerHelper(_builder)
{
	using namespace llvm;

	m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result");
	m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1");
	m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2");
	m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3");

	using Linkage = GlobalValue::LinkageTypes;

	llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr};
	llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr};

	m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule());
	m_div = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_div", getModule());
	m_mod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mod", getModule());
	m_sdiv = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule());
	m_smod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_smod", getModule());
	m_exp = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_exp", getModule());
	m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule());
	m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule());
}

Arith256::~Arith256()
{}

llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2)
{
	m_builder.CreateStore(_arg1, m_arg1);
	m_builder.CreateStore(_arg2, m_arg2);
	m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result);
	return m_builder.CreateLoad(m_result);
}

llvm::Value* Arith256::ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	m_builder.CreateStore(_arg1, m_arg1);
	m_builder.CreateStore(_arg2, m_arg2);
	m_builder.CreateStore(_arg3, m_arg3);
	m_builder.CreateCall4(_op, m_arg1, m_arg2, m_arg3, m_result);
	return m_builder.CreateLoad(m_result);
}

llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_mul, _arg1, _arg2);
}

llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_div, _arg1, _arg2);
}

llvm::Value* Arith256::mod(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_mod, _arg1, _arg2);
}

llvm::Value* Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_sdiv, _arg1, _arg2);
}

llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_smod, _arg1, _arg2);
}

llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_exp, _arg1, _arg2);
}

llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	return ternaryOp(m_addmod, _arg1, _arg2, _arg3);
}

llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	return ternaryOp(m_mulmod, _arg1, _arg2, _arg3);
}

namespace
{
	using s256 = boost::multiprecision::int256_t;

	inline s256 u2s(u256 _u)
	{
		static const bigint c_end = (bigint)1 << 256;
		static const u256 c_send = (u256)1 << 255;
		if (_u < c_send)
			return (s256)_u;
		else
			return (s256)-(c_end - _u);
	}

	inline u256 s2u(s256 _u)
	{
		static const bigint c_end = (bigint)1 << 256;
		if (_u >= 0)
			return (u256)_u;
		else
			return (u256)(c_end + _u);
	}
}

}
}
}

extern "C"
{

	using namespace dev::eth::jit;

	EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg1 * arg2);
	}

	EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2);
	}

	EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2);
	}

	EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) / u2s(arg2)));
	}

	EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) % u2s(arg2)));
	}

	EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result)
	{
		bigint left = llvm2eth(*_arg1);
		bigint right = llvm2eth(*_arg2);
		auto ret = static_cast<u256>(boost::multiprecision::powm(left, right, bigint(2) << 256));
		*o_result = eth2llvm(ret);
	}

	EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		auto arg3 = llvm2eth(*_arg3);
		if (arg3 != 0)
			*o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3));
		else
			*o_result = {};
	}

	EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		auto arg3 = llvm2eth(*_arg3);
		if (arg3 != 0)
			*o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3));
		else
			*o_result = {};
	}

}

<commit_msg>Internal mul256 implementation<commit_after>#include "Arith256.h"
#include "Runtime.h"
#include "Type.h"

#include <llvm/IR/Function.h>

namespace dev
{
namespace eth
{
namespace jit
{

Arith256::Arith256(llvm::IRBuilder<>& _builder) :
	CompilerHelper(_builder)
{
	using namespace llvm;

	m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result");
	m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1");
	m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2");
	m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3");

	using Linkage = GlobalValue::LinkageTypes;

	llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr};
	llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr};

	m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule());
	m_div = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_div", getModule());
	m_mod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mod", getModule());
	m_sdiv = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule());
	m_smod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_smod", getModule());
	m_exp = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_exp", getModule());
	m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule());
	m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule());
}

Arith256::~Arith256()
{}

llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2)
{
	m_builder.CreateStore(_arg1, m_arg1);
	m_builder.CreateStore(_arg2, m_arg2);
	m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result);
	return m_builder.CreateLoad(m_result);
}

llvm::Value* Arith256::ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	m_builder.CreateStore(_arg1, m_arg1);
	m_builder.CreateStore(_arg2, m_arg2);
	m_builder.CreateStore(_arg3, m_arg3);
	m_builder.CreateCall4(_op, m_arg1, m_arg2, m_arg3, m_result);
	return m_builder.CreateLoad(m_result);
}

llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_mul, _arg1, _arg2);
}

llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_div, _arg1, _arg2);
}

llvm::Value* Arith256::mod(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_mod, _arg1, _arg2);
}

llvm::Value* Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_sdiv, _arg1, _arg2);
}

llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_smod, _arg1, _arg2);
}

llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2)
{
	return binaryOp(m_exp, _arg1, _arg2);
}

llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	return ternaryOp(m_addmod, _arg1, _arg2, _arg3);
}

llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
	return ternaryOp(m_mulmod, _arg1, _arg2, _arg3);
}

namespace
{
	using s256 = boost::multiprecision::int256_t;

	inline s256 u2s(u256 _u)
	{
		static const bigint c_end = (bigint)1 << 256;
		static const u256 c_send = (u256)1 << 255;
		if (_u < c_send)
			return (s256)_u;
		else
			return (s256)-(c_end - _u);
	}

	inline u256 s2u(s256 _u)
	{
		static const bigint c_end = (bigint)1 << 256;
		if (_u >= 0)
			return (u256)_u;
		else
			return (u256)(c_end + _u);
	}

	using uint128 = __uint128_t;

//	uint128 add(uint128 a, uint128 b) { return a + b; }
//	uint128 mul(uint128 a, uint128 b) { return a * b; }
//
//	uint128 mulq(uint64_t x, uint64_t y)
//	{
//		return (uint128)x * (uint128)y;
//	}
//
//	uint128 addc(uint64_t x, uint64_t y)
//	{
//		return (uint128)x * (uint128)y;
//	}

	struct uint256
	{
		uint64_t lo;
		uint64_t mid;
		uint128 hi;
	};

//	uint256 add(uint256 x, uint256 y)
//	{
//		auto lo = (uint128) x.lo + y.lo;
//		auto mid = (uint128) x.mid + y.mid + (lo >> 64);
//		return {lo, mid, x.hi + y.hi + (mid >> 64)};
//	}

	uint256 mul(uint256 x, uint256 y)
	{
		auto t1 = (uint128) x.lo * y.lo;
		auto t2 = (uint128) x.lo * y.mid;
		auto t3 = x.lo * y.hi;
		auto t4 = (uint128) x.mid * y.lo;
		auto t5 = (uint128) x.mid * y.mid;
		auto t6 = x.mid * y.hi;
		auto t7 = x.hi * y.lo;
		auto t8 = x.hi * y.mid;

		auto lo = (uint64_t) t1;
		auto m1 = (t1 >> 64) + (uint64_t) t2;
		auto m2 = (uint64_t) m1;
		auto mid = (uint128) m2 + (uint64_t) t4;
		auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7
			 + (t8 << 64) + (m1 >> 64) + (mid >> 64);

		return {lo, (uint64_t)mid, hi};
	}
}

}
}
}

extern "C"
{

	using namespace dev::eth::jit;

	EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result)
	{
		*o_result = mul(*_arg1, *_arg2);
	}

	EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2);
	}

	EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2);
	}

	EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) / u2s(arg2)));
	}

	EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) % u2s(arg2)));
	}

	EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result)
	{
		bigint left = llvm2eth(*_arg1);
		bigint right = llvm2eth(*_arg2);
		auto ret = static_cast<u256>(boost::multiprecision::powm(left, right, bigint(2) << 256));
		*o_result = eth2llvm(ret);
	}

	EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		auto arg3 = llvm2eth(*_arg3);
		if (arg3 != 0)
			*o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3));
		else
			*o_result = {};
	}

	EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
	{
		auto arg1 = llvm2eth(*_arg1);
		auto arg2 = llvm2eth(*_arg2);
		auto arg3 = llvm2eth(*_arg3);
		if (arg3 != 0)
			*o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3));
		else
			*o_result = {};
	}

}

<|endoftext|>


<commit_before>
#include "GasMeter.h"

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>

#include <libevmface/Instruction.h>
#include <libevm/FeeStructure.h>

#include "Type.h"
#include "Ext.h"
#include "Runtime.h"

namespace dev
{
namespace eth
{
namespace jit
{

namespace // Helper functions
{

uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted)
{
	switch (inst)
	{
	case Instruction::STOP:
	case Instruction::SUICIDE:
		return 0;

	case Instruction::SSTORE:
		return static_cast<uint64_t>(c_sstoreResetGas);	// FIXME: Check store gas

	case Instruction::SLOAD:
		return static_cast<uint64_t>(c_sloadGas);

	case Instruction::SHA3:
		return static_cast<uint64_t>(c_sha3Gas);

	case Instruction::BALANCE:
		return static_cast<uint64_t>(c_sha3Gas);

	case Instruction::CALL:
	case Instruction::CALLCODE:
		return static_cast<uint64_t>(c_callGas);

	case Instruction::CREATE:
		return static_cast<uint64_t>(c_createGas);

	default: // Assumes instruction code is valid
		return static_cast<uint64_t>(c_stepGas);
	}
}

bool isCostBlockEnd(Instruction _inst)
{
	// Basic block terminators like STOP are not needed on the list
	// as cost will be commited at the end of basic block

	// CALL & CALLCODE are commited manually

	switch (_inst)
	{
	case Instruction::CALLDATACOPY:
	case Instruction::CODECOPY:
	case Instruction::MLOAD:
	case Instruction::MSTORE:
	case Instruction::MSTORE8:
	case Instruction::SSTORE:
	case Instruction::GAS:
	case Instruction::CREATE:
		return true;

	default:
		return false;
	}
}

}

GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) :
	CompilerHelper(_builder),
	m_runtimeManager(_runtimeManager)
{
	auto module = getModule();

	m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", module);
	InsertPointGuard guard(m_builder);

	auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc);
	auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc);
	auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc);

	m_builder.SetInsertPoint(checkBB);
	llvm::Value* cost = m_gasCheckFunc->arg_begin();
	cost->setName("cost");
	auto gas = m_runtimeManager.getGas();
	auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas");
	m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);

	m_builder.SetInsertPoint(outOfGasBB);
	_runtimeManager.raiseException(ReturnCode::OutOfGas);
	m_builder.CreateUnreachable();

	m_builder.SetInsertPoint(updateBB);
	gas = m_builder.CreateSub(gas, cost);
	m_runtimeManager.setGas(gas);
	m_builder.CreateRetVoid();
}

void GasMeter::count(Instruction _inst)
{
	if (!m_checkCall)
	{
		// Create gas check call with mocked block cost at begining of current cost-block
		m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256));
	}

	if (_inst != Instruction::SSTORE) // Handle cost of SSTORE separately in countSStore()
		m_blockCost += getStepCost(_inst);

	if (isCostBlockEnd(_inst))
		commitCostBlock();
}

void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue)
{
	assert(!m_checkCall); // Everything should've been commited before

	static const auto sstoreCost = static_cast<uint64_t>(c_sstoreResetGas);	// FIXME: Check store gas

	// [ADD] if oldValue == 0 and newValue != 0  =>  2*cost
	// [DEL] if oldValue != 0 and newValue == 0  =>  0

	auto oldValue = _ext.store(_index);
	auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero");
	auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero");
	auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero");
	auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
	auto isAdd = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isAdd");
	auto isDel = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDel");
	auto cost = m_builder.CreateSelect(isAdd, Constant::get(2 * sstoreCost), Constant::get(sstoreCost), "cost");
	cost = m_builder.CreateSelect(isDel, Constant::get(0), cost, "cost");
	createCall(m_gasCheckFunc, cost);
}

void GasMeter::giveBack(llvm::Value* _gas)
{
	m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas));
}

void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
{
	assert(!_additionalCost || m_checkCall); // _additionalCost => m_checkCall; Must be inside cost-block

	// If any uncommited block
	if (m_checkCall)
	{
		if (m_blockCost == 0) // Do not check 0
		{
			m_checkCall->eraseFromParent(); // Remove the gas check call
			m_checkCall = nullptr;
			return;
		}

		m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call
		m_checkCall = nullptr; // End cost-block
		m_blockCost = 0;

		if (_additionalCost)
		{
			m_builder.CreateCall(m_gasCheckFunc, _additionalCost);
		}
	}
	assert(m_blockCost == 0);
}

void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder)
{
	// Memory uses other builder, but that can be changes later
	auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast<uint64_t>(c_memoryGas)), "memcost");
	_builder.CreateCall(m_gasCheckFunc, cost);
}

}
}
}

<commit_msg>Improve GasMeter code formatting<commit_after>
#include "GasMeter.h"

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>

#include <libevmface/Instruction.h>
#include <libevm/FeeStructure.h>

#include "Type.h"
#include "Ext.h"
#include "Runtime.h"

namespace dev
{
namespace eth
{
namespace jit
{

namespace // Helper functions
{

uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted)
{
	switch (inst)
	{
	case Instruction::STOP:
	case Instruction::SUICIDE:
		return 0;

	case Instruction::SSTORE:
		return static_cast<uint64_t>(c_sstoreResetGas); // FIXME: Check store gas

	case Instruction::SLOAD:
		return static_cast<uint64_t>(c_sloadGas);

	case Instruction::SHA3:
		return static_cast<uint64_t>(c_sha3Gas);

	case Instruction::BALANCE:
		return static_cast<uint64_t>(c_sha3Gas);

	case Instruction::CALL:
	case Instruction::CALLCODE:
		return static_cast<uint64_t>(c_callGas);

	case Instruction::CREATE:
		return static_cast<uint64_t>(c_createGas);

	default: // Assumes instruction code is valid
		return static_cast<uint64_t>(c_stepGas);
	}
}

bool isCostBlockEnd(Instruction _inst)
{
	// Basic block terminators like STOP are not needed on the list
	// as cost will be commited at the end of basic block

	// CALL & CALLCODE are commited manually

	switch (_inst)
	{
	case Instruction::CALLDATACOPY:
	case Instruction::CODECOPY:
	case Instruction::MLOAD:
	case Instruction::MSTORE:
	case Instruction::MSTORE8:
	case Instruction::SSTORE:
	case Instruction::GAS:
	case Instruction::CREATE:
		return true;

	default:
		return false;
	}
}

}

GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) :
	CompilerHelper(_builder),
	m_runtimeManager(_runtimeManager)
{
	auto module = getModule();

	m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", module);
	InsertPointGuard guard(m_builder);

	auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc);
	auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc);
	auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc);

	m_builder.SetInsertPoint(checkBB);
	llvm::Value* cost = m_gasCheckFunc->arg_begin();
	cost->setName("cost");
	auto gas = m_runtimeManager.getGas();
	auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas");
	m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);

	m_builder.SetInsertPoint(outOfGasBB);
	_runtimeManager.raiseException(ReturnCode::OutOfGas);
	m_builder.CreateUnreachable();

	m_builder.SetInsertPoint(updateBB);
	gas = m_builder.CreateSub(gas, cost);
	m_runtimeManager.setGas(gas);
	m_builder.CreateRetVoid();
}

void GasMeter::count(Instruction _inst)
{
	if (!m_checkCall)
	{
		// Create gas check call with mocked block cost at begining of current cost-block
		m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256));
	}

	if (_inst != Instruction::SSTORE) // Handle cost of SSTORE separately in countSStore()
		m_blockCost += getStepCost(_inst);

	if (isCostBlockEnd(_inst))
		commitCostBlock();
}

void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue)
{
	assert(!m_checkCall); // Everything should've been commited before

	static const auto sstoreCost = static_cast<uint64_t>(c_sstoreResetGas); // FIXME: Check store gas

	// [ADD] if oldValue == 0 and newValue != 0  =>  2*cost
	// [DEL] if oldValue != 0 and newValue == 0  =>  0

	auto oldValue = _ext.store(_index);
	auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero");
	auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero");
	auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero");
	auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
	auto isAdd = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isAdd");
	auto isDel = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDel");
	auto cost = m_builder.CreateSelect(isAdd, Constant::get(2 * sstoreCost), Constant::get(sstoreCost), "cost");
	cost = m_builder.CreateSelect(isDel, Constant::get(0), cost, "cost");
	createCall(m_gasCheckFunc, cost);
}

void GasMeter::giveBack(llvm::Value* _gas)
{
	m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas));
}

void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
{
	assert(!_additionalCost || m_checkCall); // _additionalCost => m_checkCall; Must be inside cost-block

	// If any uncommited block
	if (m_checkCall)
	{
		if (m_blockCost == 0) // Do not check 0
		{
			m_checkCall->eraseFromParent(); // Remove the gas check call
			m_checkCall = nullptr;
			return;
		}

		m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call
		m_checkCall = nullptr; // End cost-block
		m_blockCost = 0;

		if (_additionalCost)
		{
			m_builder.CreateCall(m_gasCheckFunc, _additionalCost);
		}
	}
	assert(m_blockCost == 0);
}

void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder)
{
	// Memory uses other builder, but that can be changes later
	auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast<uint64_t>(c_memoryGas)), "memcost");
	_builder.CreateCall(m_gasCheckFunc, cost);
}

}
}
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2001-2007 Peter Simons <simons@cryp.to>
 *
 * This software is provided 'as-is', without any express or
 * implied warranty. In no event will the authors be held liable
 * for any damages arising from the use of this software.
 *
 * Copying and distribution of this file, with or without
 * modification, are permitted in any medium without royalty
 * provided the copyright notice and this notice are preserved.
 */

#include "fastcgi.hpp"
#include <iostream>
#include <assert.h>
#include <stdio.h>
#ifndef _WIN32
#include <memory.h>
#endif

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;

enum message_type_t
  { TYPE_BEGIN_REQUEST     =  1
  , TYPE_ABORT_REQUEST     =  2
  , TYPE_END_REQUEST       =  3
  , TYPE_PARAMS            =  4
  , TYPE_STDIN             =  5
  , TYPE_STDOUT            =  6
  , TYPE_STDERR            =  7
  , TYPE_DATA              =  8
  , TYPE_GET_VALUES        =  9
  , TYPE_GET_VALUES_RESULT = 10
  , TYPE_UNKNOWN           = 11
  };

struct Header
{
  uint8_t version;
  uint8_t type;
  uint8_t requestIdB1;
  uint8_t requestIdB0;
  uint8_t contentLengthB1;
  uint8_t contentLengthB0;
  uint8_t paddingLength;
  uint8_t reserved;

  Header()
  {
    memset(this, 0, sizeof(*this));
  }

  Header(message_type_t t, uint16_t id, uint16_t len)
    : version(1), type(t)
    , requestIdB1(id >> 8)
    , requestIdB0(id & 0xff)
    , contentLengthB1(len >> 8)
    , contentLengthB0(len & 0xff)
    , paddingLength(0), reserved(0)
  {
  }
};

struct BeginRequest
{
  uint8_t roleB1;
  uint8_t roleB0;
  uint8_t flags;
  uint8_t reserved[5];
};

static uint8_t const FLAG_KEEP_CONN = 1;

struct EndRequestMsg : public Header
{
  uint8_t appStatusB3;
  uint8_t appStatusB2;
  uint8_t appStatusB1;
  uint8_t appStatusB0;
  uint8_t protocolStatus;
  uint8_t reserved[3];

  EndRequestMsg()
  {
    memset(this, 0, sizeof(*this));
  }

  EndRequestMsg(uint16_t id, uint32_t appStatus, FCGIRequest::protocol_status_t protStatus)
    : Header(TYPE_END_REQUEST, id, sizeof(EndRequestMsg)-sizeof(Header))
    , appStatusB3((appStatus >> 24) & 0xff)
    , appStatusB2((appStatus >> 16) & 0xff)
    , appStatusB1((appStatus >>  8) & 0xff)
    , appStatusB0((appStatus >>  0) & 0xff)
    , protocolStatus(protStatus)
  {
    memset(this->reserved, 0, sizeof(this->reserved));
  }
};

struct UnknownTypeMsg : public Header
{
  uint8_t type;
  uint8_t reserved[7];

  UnknownTypeMsg()
  {
    memset(this, 0, sizeof(*this));
  }

  UnknownTypeMsg(uint8_t unknown_type)
    : Header(TYPE_UNKNOWN, 0, sizeof(UnknownTypeMsg) - sizeof(Header))
    , type(unknown_type)
  {
    memset(this->reserved, 0, sizeof(this->reserved));
  }
};

void FCGIProtocolDriver::process_unknown(uint8_t type)
{
  UnknownTypeMsg msg(type);
  output_cb(&msg, sizeof(UnknownTypeMsg));
}

void FCGIProtocolDriver::process_begin_request(uint16_t id, uint8_t const * buf, uint16_t)
{
  // Check whether we have an open request with that id already and
  // if, throw an exception.

  if (reqmap.find(id) != reqmap.end())
  {
    char tmp[256];
#ifdef _WIN32
	sprintf_s(tmp, "FCGIProtocolDriver received duplicate BEGIN_REQUEST id %u.", id);
#else
    sprintf(tmp, "FCGIProtocolDriver received duplicate BEGIN_REQUEST id %u.", id);
#endif
    throw duplicate_begin_request(tmp);
  }

  // Create a new request instance and store it away. The user may
  // get it after we've read all parameters.

  BeginRequest const * br = reinterpret_cast<BeginRequest const *>(buf);
  reqmap[id] = new FCGIRequest(*this, id,
                              FCGIRequest::role_t((br->roleB1 << 8) + br->roleB0),
                              (br->flags & FLAG_KEEP_CONN) == 1);
}

void FCGIProtocolDriver::process_abort_request(uint16_t id, uint8_t const *, uint16_t)
{
  // Find request instance for this id. Ignore message if non
  // exists, set ignore flag otherwise.

  reqmap_t::iterator req = reqmap.find(id);
  if (req == reqmap.end())
    std::cerr << "FCGIProtocolDriver received ABORT_REQUEST for non-existing id " << id << ". Ignoring."
              << std::endl;
  else
  {
    req->second->aborted = true;
    if (req->second->handler_cb) // Notify the handler associated with this request.
      (*req->second->handler_cb)(req->second);
  }
}

void FCGIProtocolDriver::process_params(uint16_t id, uint8_t const * buf, uint16_t len)
{
  // Find request instance for this id. Ignore message if non
  // exists.

  reqmap_t::iterator req = reqmap.find(id);
  if (req == reqmap.end())
  {
    std::cerr << "FCGIProtocolDriver received PARAMS for non-existing id " << id << ". Ignoring."
              << std::endl;
    return;
  }

  // Is this the last message to come? Then queue the request for
  // the user.

  if (len == 0)
  {
    new_request_queue.push(id);
    return;
  }

  // Process message.

  uint8_t const * const  bufend(buf + len);
  uint32_t               name_len;
  uint32_t               data_len;
  while(buf != bufend)
  {
    if (*buf >> 7 == 0)
      name_len = *(buf++);
    else
    {
      name_len = ((buf[0] & 0x7F) << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
      buf += 4;
    }
    if (*buf >> 7 == 0)
      data_len = *(buf++);
    else
    {
      data_len = ((buf[0] & 0x7F) << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
      buf += 4;
    }
    assert(buf + name_len + data_len <= bufend);
    std::string const name(reinterpret_cast<char const *>(buf), name_len);
    buf += name_len;
    std::string const data(reinterpret_cast<char const *>(buf), data_len);
    buf += data_len;
#ifdef DEBUG_FASTCGI
    std::cerr << "request #" << id << ": FCGIProtocolDriver received PARAM '" << name << "' = '" << data << "'"
              << std::endl;
#endif
    req->second->params[name] = data;
  }
}

void FCGIProtocolDriver::process_stdin(uint16_t id, uint8_t const * buf, uint16_t len)
{
  // Find request instance for this id. Ignore message if non
  // exists.

  reqmap_t::iterator req = reqmap.find(id);
  if (req == reqmap.end())
  {
    std::cerr << "FCGIProtocolDriver received STDIN for non-existing id " << id << ". Ignoring."
              << std::endl;
    return;
  }

  // Is this the last message to come? Then set the eof flag.
  // Otherwise, add the data to the buffer in the request structure.

  if (len == 0)
    req->second->stdin_eof = true;
  else
    req->second->stdin_stream.append((char const *)buf, len);

  // Notify the handler associated with this request.

  if (req->second->handler_cb)
    (*req->second->handler_cb)(req->second);
}

FCGIProtocolDriver::FCGIProtocolDriver(OutputCallback& cb) : output_cb(cb)
{
}

FCGIProtocolDriver::~FCGIProtocolDriver()
{
  for(reqmap_t::iterator i = reqmap.begin(); i != reqmap.end(); ++i)
  {
    delete i->second;
  }
}

void FCGIProtocolDriver::process_input(void const * buf, size_t count)
{
  // Copy data to our own buffer.

  InputBuffer.insert( InputBuffer.end()
                    , static_cast<uint8_t const *>(buf)
                    , static_cast<uint8_t const *>(buf) + count
                    );

  // If there is enough data in the input buffer to contain a
  // header, interpret it.

  while(InputBuffer.size() >= sizeof(Header))
  {
    Header const * hp = reinterpret_cast<Header const *>(&InputBuffer[0]);

    // Check whether our peer speaks the correct protocol version.

    if (hp->version != 1)
    {
      char buf[256];
#ifdef _WIN32
      sprintf_s(buf, "FCGIProtocolDriver cannot handle protocol version %u.", hp->version);
#else
	  sprintf(buf, "FCGIProtocolDriver cannot handle protocol version %u.", hp->version);
#endif
      throw unsupported_fcgi_version(buf);
    }

    // Check whether we have the whole message that follows the
    // headers in our buffer already. If not, we can't process it
    // yet.

    uint16_t msg_len = (hp->contentLengthB1 << 8) + hp->contentLengthB0;
    uint16_t msg_id  = (hp->requestIdB1 << 8) + hp->requestIdB0;

    if (InputBuffer.size() < sizeof(Header)+msg_len+hp->paddingLength)
      return;

    // Process the message. In case an exception arrives here,
    // terminate the request.

    try
    {
#ifdef DEBUG_FASTCGI
      std::cerr << "Received message: id = " << msg_id << ", "
                << "body len = " << msg_len << ", "
                << "type = " << (int)hp->type << std::endl;
#endif
      switch (hp->type)
      {
        case TYPE_BEGIN_REQUEST:
          process_begin_request(msg_id, &InputBuffer[0]+sizeof(Header), msg_len);
          break;

        case TYPE_ABORT_REQUEST:
          process_abort_request(msg_id, &InputBuffer[0]+sizeof(Header), msg_len);
          break;

        case TYPE_PARAMS:
          process_params(msg_id, &InputBuffer[0]+sizeof(Header), msg_len);
          break;

        case TYPE_STDIN:
          process_stdin(msg_id, &InputBuffer[0]+sizeof(Header), msg_len);
          break;

        case TYPE_END_REQUEST:
        case TYPE_STDOUT:
        case TYPE_STDERR:
        case TYPE_DATA:
        case TYPE_GET_VALUES:
        case TYPE_GET_VALUES_RESULT:
        case TYPE_UNKNOWN:
        default:
          process_unknown(hp->type);
      }
    }
    catch(fcgi_io_callback_error const &)
    {
      throw;
    }
    catch(std::exception const & e)
    {
      std::cerr << "Caught exception while processing request #" << msg_id << ": " << e.what() << std::endl;
      terminate_request(msg_id);
    }
    catch(...)
    {
      std::cerr << "Caught unknown exception while processing request #" << msg_id << "." << std::endl;
      terminate_request(msg_id);
    }

    // Remove the message from our buffer and contine processing
    // if there if something left.

    InputBuffer.erase( InputBuffer.begin()
                     , InputBuffer.begin()+sizeof(Header)+msg_len+hp->paddingLength
                     );
  }
}

FCGIRequest* FCGIProtocolDriver::get_request()
{
  if (new_request_queue.empty())
    return 0;

  FCGIRequest* r = reqmap[new_request_queue.front()];
  new_request_queue.pop();
  return r;
}

bool FCGIProtocolDriver::have_active_requests()
{
  if (new_request_queue.empty() && reqmap.empty())
    return false;
  else
    return true;
}

void FCGIProtocolDriver::terminate_request(uint16_t id)
{
  reqmap_t::iterator req;
  req = reqmap.find(id);
  if (req != reqmap.end())
  {
    delete req->second;
    reqmap.erase(req);
  }
}

// Pure virtual destructors must also exist somewhere.

FCGIProtocolDriver::OutputCallback::~OutputCallback()
{
}

FCGIRequest::FCGIRequest(FCGIProtocolDriver& driver_, uint16_t id_, role_t role_, bool kc)
  : id(id_), role(role_), keep_connection(kc), aborted(false), stdin_eof(false)
  , data_eof(false), handler_cb(0), driver(driver_)
{
}

FCGIRequest::~FCGIRequest()
{
  if (handler_cb)
    delete handler_cb;
}

void FCGIRequest::write(const std::string& buf, ostream_type_t stream)
{
  write(buf.data(), buf.size(), stream);
}

void FCGIRequest::write(char const * buf, size_t count, ostream_type_t stream)
{
  if (count > 0xffff)
    throw std::out_of_range("Can't send messages of that size.");
  else if (count == 0)
    return;

  // Construct message.

  Header h(stream == STDOUT ? TYPE_STDOUT : TYPE_STDERR, id, (uint16_t)count);
  driver.output_cb(&h, sizeof(Header));
  driver.output_cb(buf, count);
}

void FCGIRequest::write(const std::string  &tw)
{
	write(tw.data(), tw.size(), STDOUT);
}

void FCGIRequest::end_request(uint32_t appStatus, FCGIRequest::protocol_status_t protStatus)
{
  // Terminate the stdout and stderr stream, and send the
  // end-request message.

  uint8_t buf[64];
  uint8_t * p = buf;

  new(p) Header(TYPE_STDOUT, id, 0);
  p += sizeof(Header);
  new(p) Header(TYPE_STDERR, id, 0);
  p += sizeof(Header);
  new(p) EndRequestMsg(id, appStatus, protStatus);
  p += sizeof(EndRequestMsg);
  driver.output_cb(buf, p - buf);
  driver.terminate_request(id);
}
<commit_msg>Fix Buffer Over-read in FastCGI parameters<commit_after>/*
 * Copyright (c) 2001-2007 Peter Simons <simons@cryp.to>
 *
 * This software is provided 'as-is', without any express or
 * implied warranty. In no event will the authors be held liable
 * for any damages arising from the use of this software.
 *
 * Copying and distribution of this file, with or without
 * modification, are permitted in any medium without royalty
 * provided the copyright notice and this notice are preserved.
 */

#include "fastcgi.hpp"
#include <iostream>
#include <stdio.h>
#ifndef _WIN32
#include <memory.h>
#endif

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;

enum message_type_t
  { TYPE_BEGIN_REQUEST     =  1
  , TYPE_ABORT_REQUEST     =  2
  , TYPE_END_REQUEST       =  3
  , TYPE_PARAMS            =  4
  , TYPE_STDIN             =  5
  , TYPE_STDOUT            =  6
  , TYPE_STDERR            =  7
  , TYPE_DATA              =  8
  , TYPE_GET_VALUES        =  9
  , TYPE_GET_VALUES_RESULT = 10
  , TYPE_UNKNOWN           = 11
  };

struct Header
{
  uint8_t version;
  uint8_t type;
  uint8_t requestIdB1;
  uint8_t requestIdB0;
  uint8_t contentLengthB1;
  uint8_t contentLengthB0;
  uint8_t paddingLength;
  uint8_t reserved;

  Header()
  {
    memset(this, 0, sizeof(*this));
  }

  Header(message_type_t t, uint16_t id, uint16_t len)
    : version(1), type(t)
    , requestIdB1(id >> 8)
    , requestIdB0(id & 0xff)
    , contentLengthB1(len >> 8)
    , contentLengthB0(len & 0xff)
    , paddingLength(0), reserved(0)
  {
  }
};

struct BeginRequest
{
  uint8_t roleB1;
  uint8_t roleB0;
  uint8_t flags;
  uint8_t reserved[5];
};

static uint8_t const FLAG_KEEP_CONN = 1;

struct EndRequestMsg : public Header
{
  uint8_t appStatusB3;
  uint8_t appStatusB2;
  uint8_t appStatusB1;
  uint8_t appStatusB0;
  uint8_t protocolStatus;
  uint8_t reserved[3];

  EndRequestMsg()
  {
    memset(this, 0, sizeof(*this));
  }

  EndRequestMsg(uint16_t id, uint32_t appStatus, FCGIRequest::protocol_status_t protStatus)
    : Header(TYPE_END_REQUEST, id, sizeof(EndRequestMsg)-sizeof(Header))
    , appStatusB3((appStatus >> 24) & 0xff)
    , appStatusB2((appStatus >> 16) & 0xff)
    , appStatusB1((appStatus >>  8) & 0xff)
    , appStatusB0((appStatus >>  0) & 0xff)
    , protocolStatus(protStatus)
  {
    memset(this->reserved, 0, sizeof(this->reserved));
  }
};

struct UnknownTypeMsg : public Header
{
  uint8_t type;
  uint8_t reserved[7];

  UnknownTypeMsg()
  {
    memset(this, 0, sizeof(*this));
  }

  UnknownTypeMsg(uint8_t unknown_type)
    : Header(TYPE_UNKNOWN, 0, sizeof(UnknownTypeMsg) - sizeof(Header))
    , type(unknown_type)
  {
    memset(this->reserved, 0, sizeof(this->reserved));
  }
};

void FCGIProtocolDriver::process_unknown(uint8_t type)
{
  UnknownTypeMsg msg(type);
  output_cb(&msg, sizeof(UnknownTypeMsg));
}

void FCGIProtocolDriver::process_begin_request(uint16_t id, uint8_t const * buf, uint16_t)
{
  // Check whether we have an open request with that id already and
  // if, throw an exception.

  if (reqmap.find(id) != reqmap.end())
  {
    char tmp[256];
#ifdef _WIN32
	sprintf_s(tmp, "FCGIProtocolDriver received duplicate BEGIN_REQUEST id %u.", id);
#else
    sprintf(tmp, "FCGIProtocolDriver received duplicate BEGIN_REQUEST id %u.", id);
#endif
    throw duplicate_begin_request(tmp);
  }

  // Create a new request instance and store it away. The user may
  // get it after we've read all parameters.

  BeginRequest const * br = reinterpret_cast<BeginRequest const *>(buf);
  reqmap[id] = new FCGIRequest(*this, id,
                              FCGIRequest::role_t((br->roleB1 << 8) + br->roleB0),
                              (br->flags & FLAG_KEEP_CONN) == 1);
}

void FCGIProtocolDriver::process_abort_request(uint16_t id, uint8_t const *, uint16_t)
{
  // Find request instance for this id. Ignore message if non
  // exists, set ignore flag otherwise.

  reqmap_t::iterator req = reqmap.find(id);
  if (req == reqmap.end())
    std::cerr << "FCGIProtocolDriver received ABORT_REQUEST for non-existing id " << id << ". Ignoring."
              << std::endl;
  else
  {
    req->second->aborted = true;
    if (req->second->handler_cb) // Notify the handler associated with this request.
      (*req->second->handler_cb)(req->second);
  }
}

void FCGIProtocolDriver::process_params(uint16_t id, uint8_t const * buf, uint16_t len)
{
  // Find request instance for this id. Ignore message if non
  // exists.

  reqmap_t::iterator req = reqmap.find(id);
  if (req == reqmap.end())
  {
    std::cerr << "FCGIProtocolDriver received PARAMS for non-existing id " << id << ". Ignoring."
              << std::endl;
    return;
  }

  // Is this the last message to come? Then queue the request for
  // the user.

  if (len == 0)
  {
    new_request_queue.push(id);
    return;
  }

  // Process message.

  uint8_t const * const  bufend(buf + len);
  uint32_t               name_len;
  uint32_t               data_len;
  while(buf != bufend)
  {
	  if (*buf >> 7 == 0)
		  name_len = *(buf++);
	  else if (4 <= bufend - buf)
	  {
		  name_len = ((buf[0] & 0x7F) << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
		  buf += 4;
	  }
	  else
		  break;

	  if (*buf >> 7 == 0)
		  data_len = *(buf++);
	  else if (4 <= bufend - buf)
	  {
		  data_len = ((buf[0] & 0x7F) << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
		  buf += 4;
	  }
	  else
		  break;

	  if (name_len + data_len <= bufend - buf)
	  {
		  std::string const name(reinterpret_cast<char const *>(buf), name_len);
		  buf += name_len;
		  std::string const data(reinterpret_cast<char const *>(buf), data_len);
		  buf += data_len;
#ifdef DEBUG_FASTCGI
		  std::cerr << "request #" << id << ": FCGIProtocolDriver received PARAM '" << name << "' = '" << data << "'"
			  << std::endl;
#endif
		  req->second->params[name] = data;
	  }
	  else
	  {
		  break;
	  }
  }
}

void FCGIProtocolDriver::process_stdin(uint16_t id, uint8_t const * buf, uint16_t len)
{
  // Find request instance for this id. Ignore message if non
  // exists.

  reqmap_t::iterator req = reqmap.find(id);
  if (req == reqmap.end())
  {
    std::cerr << "FCGIProtocolDriver received STDIN for non-existing id " << id << ". Ignoring."
              << std::endl;
    return;
  }

  // Is this the last message to come? Then set the eof flag.
  // Otherwise, add the data to the buffer in the request structure.

  if (len == 0)
    req->second->stdin_eof = true;
  else
    req->second->stdin_stream.append((char const *)buf, len);

  // Notify the handler associated with this request.

  if (req->second->handler_cb)
    (*req->second->handler_cb)(req->second);
}

FCGIProtocolDriver::FCGIProtocolDriver(OutputCallback& cb) : output_cb(cb)
{
}

FCGIProtocolDriver::~FCGIProtocolDriver()
{
  for(reqmap_t::iterator i = reqmap.begin(); i != reqmap.end(); ++i)
  {
    delete i->second;
  }
}

void FCGIProtocolDriver::process_input(void const * buf, size_t count)
{
  // Copy data to our own buffer.

  InputBuffer.insert( InputBuffer.end()
                    , static_cast<uint8_t const *>(buf)
                    , static_cast<uint8_t const *>(buf) + count
                    );

  // If there is enough data in the input buffer to contain a
  // header, interpret it.

  while(InputBuffer.size() >= sizeof(Header))
  {
    Header const * hp = reinterpret_cast<Header const *>(&InputBuffer[0]);

    // Check whether our peer speaks the correct protocol version.

    if (hp->version != 1)
    {
      char buf[256];
#ifdef _WIN32
      sprintf_s(buf, "FCGIProtocolDriver cannot handle protocol version %u.", hp->version);
#else
	  sprintf(buf, "FCGIProtocolDriver cannot handle protocol version %u.", hp->version);
#endif
      throw unsupported_fcgi_version(buf);
    }

    // Check whether we have the whole message that follows the
    // headers in our buffer already. If not, we can't process it
    // yet.

    uint16_t msg_len = (hp->contentLengthB1 << 8) + hp->contentLengthB0;
    uint16_t msg_id  = (hp->requestIdB1 << 8) + hp->requestIdB0;

    if (InputBuffer.size() < sizeof(Header)+msg_len+hp->paddingLength)
      return;

    // Process the message. In case an exception arrives here,
    // terminate the request.

    try
    {
#ifdef DEBUG_FASTCGI
      std::cerr << "Received message: id = " << msg_id << ", "
                << "body len = " << msg_len << ", "
                << "type = " << (int)hp->type << std::endl;
#endif
      switch (hp->type)
      {
        case TYPE_BEGIN_REQUEST:
          process_begin_request(msg_id, &InputBuffer[0]+sizeof(Header), msg_len);
          break;

        case TYPE_ABORT_REQUEST:
          process_abort_request(msg_id, &InputBuffer[0]+sizeof(Header), msg_len);
          break;

        case TYPE_PARAMS:
          process_params(msg_id, &InputBuffer[0]+sizeof(Header), msg_len);
          break;

        case TYPE_STDIN:
          process_stdin(msg_id, &InputBuffer[0]+sizeof(Header), msg_len);
          break;

        case TYPE_END_REQUEST:
        case TYPE_STDOUT:
        case TYPE_STDERR:
        case TYPE_DATA:
        case TYPE_GET_VALUES:
        case TYPE_GET_VALUES_RESULT:
        case TYPE_UNKNOWN:
        default:
          process_unknown(hp->type);
      }
    }
    catch(fcgi_io_callback_error const &)
    {
      throw;
    }
    catch(std::exception const & e)
    {
      std::cerr << "Caught exception while processing request #" << msg_id << ": " << e.what() << std::endl;
      terminate_request(msg_id);
    }
    catch(...)
    {
      std::cerr << "Caught unknown exception while processing request #" << msg_id << "." << std::endl;
      terminate_request(msg_id);
    }

    // Remove the message from our buffer and contine processing
    // if there if something left.

    InputBuffer.erase( InputBuffer.begin()
                     , InputBuffer.begin()+sizeof(Header)+msg_len+hp->paddingLength
                     );
  }
}

FCGIRequest* FCGIProtocolDriver::get_request()
{
  if (new_request_queue.empty())
    return 0;

  FCGIRequest* r = reqmap[new_request_queue.front()];
  new_request_queue.pop();
  return r;
}

bool FCGIProtocolDriver::have_active_requests()
{
  if (new_request_queue.empty() && reqmap.empty())
    return false;
  else
    return true;
}

void FCGIProtocolDriver::terminate_request(uint16_t id)
{
  reqmap_t::iterator req;
  req = reqmap.find(id);
  if (req != reqmap.end())
  {
    delete req->second;
    reqmap.erase(req);
  }
}

// Pure virtual destructors must also exist somewhere.

FCGIProtocolDriver::OutputCallback::~OutputCallback()
{
}

FCGIRequest::FCGIRequest(FCGIProtocolDriver& driver_, uint16_t id_, role_t role_, bool kc)
  : id(id_), role(role_), keep_connection(kc), aborted(false), stdin_eof(false)
  , data_eof(false), handler_cb(0), driver(driver_)
{
}

FCGIRequest::~FCGIRequest()
{
  if (handler_cb)
    delete handler_cb;
}

void FCGIRequest::write(const std::string& buf, ostream_type_t stream)
{
  write(buf.data(), buf.size(), stream);
}

void FCGIRequest::write(char const * buf, size_t count, ostream_type_t stream)
{
  if (count > 0xffff)
    throw std::out_of_range("Can't send messages of that size.");
  else if (count == 0)
    return;

  // Construct message.

  Header h(stream == STDOUT ? TYPE_STDOUT : TYPE_STDERR, id, (uint16_t)count);
  driver.output_cb(&h, sizeof(Header));
  driver.output_cb(buf, count);
}

void FCGIRequest::write(const std::string  &tw)
{
	write(tw.data(), tw.size(), STDOUT);
}

void FCGIRequest::end_request(uint32_t appStatus, FCGIRequest::protocol_status_t protStatus)
{
  // Terminate the stdout and stderr stream, and send the
  // end-request message.

  uint8_t buf[64];
  uint8_t * p = buf;

  new(p) Header(TYPE_STDOUT, id, 0);
  p += sizeof(Header);
  new(p) Header(TYPE_STDERR, id, 0);
  p += sizeof(Header);
  new(p) EndRequestMsg(id, appStatus, protStatus);
  p += sizeof(EndRequestMsg);
  driver.output_cb(buf, p - buf);
  driver.terminate_request(id);
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cassert>

#include "kms++.h"
#include "helpers.h"

using namespace std;

namespace kms
{

static const map<int, string> connector_names = {
	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
	{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
	{ DRM_MODE_CONNECTOR_Composite, "Composite" },
	{ DRM_MODE_CONNECTOR_SVIDEO, "S-Video" },
	{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
	{ DRM_MODE_CONNECTOR_Component, "Component" },
	{ DRM_MODE_CONNECTOR_9PinDIN, "9-Pin-DIN" },
	{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
	{ DRM_MODE_CONNECTOR_TV, "TV" },
	{ DRM_MODE_CONNECTOR_eDP, "eDP" },
	{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
	{ DRM_MODE_CONNECTOR_DSI, "DSI" },
};

static const map<int, string> connection_str = {
	{ 0, "<unknown>" },
	{ DRM_MODE_CONNECTED, "Connected" },
	{ DRM_MODE_DISCONNECTED, "Disconnected" },
	{ DRM_MODE_UNKNOWNCONNECTION, "Unknown" },
};

static const map<int, string> subpix_str = {
#define DEF_SUBPIX(c) { DRM_MODE_SUBPIXEL_##c, #c }
	DEF_SUBPIX(UNKNOWN),
	DEF_SUBPIX(HORIZONTAL_RGB),
	DEF_SUBPIX(HORIZONTAL_BGR),
	DEF_SUBPIX(VERTICAL_RGB),
	DEF_SUBPIX(VERTICAL_BGR),
	DEF_SUBPIX(NONE),
#undef DEF_SUBPIX
};

struct ConnectorPriv
{
	drmModeConnectorPtr drm_connector;
};

Connector::Connector(Card &card, uint32_t id, uint32_t idx)
	:DrmPropObject(card, id, DRM_MODE_OBJECT_CONNECTOR, idx)
{
	m_priv = new ConnectorPriv();

	m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
	assert(m_priv->drm_connector);

	const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
	m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
}

Connector::~Connector()
{
	drmModeFreeConnector(m_priv->drm_connector);
	delete m_priv;
}

void Connector::setup()
{
	if (m_priv->drm_connector->encoder_id != 0)
		m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id);
	else
		m_current_encoder = 0;

	if (m_current_encoder)
		m_saved_crtc = m_current_encoder->get_crtc();
	else
		m_saved_crtc = 0;
}

void Connector::restore_mode()
{
	if (m_saved_crtc)
		m_saved_crtc->restore_mode(this);
}

Videomode Connector::get_default_mode() const
{
	if (m_priv->drm_connector->count_modes == 0)
		throw invalid_argument("no modes available\n");
	drmModeModeInfo drmmode = m_priv->drm_connector->modes[0];

	return drm_mode_to_video_mode(drmmode);
}

Videomode Connector::get_mode(const string& mode) const
{
	auto c = m_priv->drm_connector;

	for (int i = 0; i < c->count_modes; i++)
                if (mode == c->modes[i].name)
                        return drm_mode_to_video_mode(c->modes[i]);

        throw invalid_argument(mode + ": mode not found");
}

Videomode Connector::get_mode(unsigned xres, unsigned yres, unsigned refresh, bool ilace) const
{
	auto c = m_priv->drm_connector;

	for (int i = 0; i < c->count_modes; i++) {
		drmModeModeInfo& m = c->modes[i];

		if (m.hdisplay != xres || m.vdisplay != yres)
			continue;

		if (refresh && m.vrefresh != refresh)
			continue;

		if (ilace != !!(m.flags & DRM_MODE_FLAG_INTERLACE))
			continue;

		return drm_mode_to_video_mode(c->modes[i]);
	}

	throw invalid_argument("mode not found");
}

bool Connector::connected() const
{
	return m_priv->drm_connector->connection == DRM_MODE_CONNECTED ||
			m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
}

vector<Crtc*> Connector::get_possible_crtcs() const
{
	vector<Crtc*> crtcs;

	for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) {
		auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);

		auto l = enc->get_possible_crtcs();

		crtcs.insert(crtcs.end(), l.begin(), l.end());
	}

	return crtcs;
}

Crtc* Connector::get_current_crtc() const
{
	if (m_current_encoder)
		return m_current_encoder->get_crtc();
	else
		return 0;
}

uint32_t Connector::connector_type() const
{
	return m_priv->drm_connector->connector_type;
}

uint32_t Connector::connector_type_id() const
{
	return m_priv->drm_connector->connector_type_id;
}

uint32_t Connector::mmWidth() const
{
	return m_priv->drm_connector->mmWidth;
}

uint32_t Connector::mmHeight() const
{
	return m_priv->drm_connector->mmHeight;
}

uint32_t Connector::subpixel() const
{
	return m_priv->drm_connector->subpixel;
}

const string& Connector::subpixel_str() const
{
	return subpix_str.at(subpixel());
}

std::vector<Videomode> Connector::get_modes() const
{
	vector<Videomode> modes;

	for (int i = 0; i < m_priv->drm_connector->count_modes; i++)
		modes.push_back(drm_mode_to_video_mode(
					m_priv->drm_connector->modes[i]));

	return modes;
}

std::vector<Encoder*> Connector::get_encoders() const
{
	vector<Encoder*> encoders;

	for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) {
		auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
		encoders.push_back(enc);
	}
	return encoders;
}

}
<commit_msg>Connector: hack fix EDID blob ID<commit_after>#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cassert>

#include "kms++.h"
#include "helpers.h"

using namespace std;

namespace kms
{

static const map<int, string> connector_names = {
	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
	{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
	{ DRM_MODE_CONNECTOR_Composite, "Composite" },
	{ DRM_MODE_CONNECTOR_SVIDEO, "S-Video" },
	{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
	{ DRM_MODE_CONNECTOR_Component, "Component" },
	{ DRM_MODE_CONNECTOR_9PinDIN, "9-Pin-DIN" },
	{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
	{ DRM_MODE_CONNECTOR_TV, "TV" },
	{ DRM_MODE_CONNECTOR_eDP, "eDP" },
	{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
	{ DRM_MODE_CONNECTOR_DSI, "DSI" },
};

static const map<int, string> connection_str = {
	{ 0, "<unknown>" },
	{ DRM_MODE_CONNECTED, "Connected" },
	{ DRM_MODE_DISCONNECTED, "Disconnected" },
	{ DRM_MODE_UNKNOWNCONNECTION, "Unknown" },
};

static const map<int, string> subpix_str = {
#define DEF_SUBPIX(c) { DRM_MODE_SUBPIXEL_##c, #c }
	DEF_SUBPIX(UNKNOWN),
	DEF_SUBPIX(HORIZONTAL_RGB),
	DEF_SUBPIX(HORIZONTAL_BGR),
	DEF_SUBPIX(VERTICAL_RGB),
	DEF_SUBPIX(VERTICAL_BGR),
	DEF_SUBPIX(NONE),
#undef DEF_SUBPIX
};

struct ConnectorPriv
{
	drmModeConnectorPtr drm_connector;
};

Connector::Connector(Card &card, uint32_t id, uint32_t idx)
	:DrmPropObject(card, id, DRM_MODE_OBJECT_CONNECTOR, idx)
{
	m_priv = new ConnectorPriv();

	m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
	assert(m_priv->drm_connector);

	// XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id.
	// XXX So refresh the props again here.
	refresh_props();

	const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
	m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
}

Connector::~Connector()
{
	drmModeFreeConnector(m_priv->drm_connector);
	delete m_priv;
}

void Connector::setup()
{
	if (m_priv->drm_connector->encoder_id != 0)
		m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id);
	else
		m_current_encoder = 0;

	if (m_current_encoder)
		m_saved_crtc = m_current_encoder->get_crtc();
	else
		m_saved_crtc = 0;
}

void Connector::restore_mode()
{
	if (m_saved_crtc)
		m_saved_crtc->restore_mode(this);
}

Videomode Connector::get_default_mode() const
{
	if (m_priv->drm_connector->count_modes == 0)
		throw invalid_argument("no modes available\n");
	drmModeModeInfo drmmode = m_priv->drm_connector->modes[0];

	return drm_mode_to_video_mode(drmmode);
}

Videomode Connector::get_mode(const string& mode) const
{
	auto c = m_priv->drm_connector;

	for (int i = 0; i < c->count_modes; i++)
                if (mode == c->modes[i].name)
                        return drm_mode_to_video_mode(c->modes[i]);

        throw invalid_argument(mode + ": mode not found");
}

Videomode Connector::get_mode(unsigned xres, unsigned yres, unsigned refresh, bool ilace) const
{
	auto c = m_priv->drm_connector;

	for (int i = 0; i < c->count_modes; i++) {
		drmModeModeInfo& m = c->modes[i];

		if (m.hdisplay != xres || m.vdisplay != yres)
			continue;

		if (refresh && m.vrefresh != refresh)
			continue;

		if (ilace != !!(m.flags & DRM_MODE_FLAG_INTERLACE))
			continue;

		return drm_mode_to_video_mode(c->modes[i]);
	}

	throw invalid_argument("mode not found");
}

bool Connector::connected() const
{
	return m_priv->drm_connector->connection == DRM_MODE_CONNECTED ||
			m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
}

vector<Crtc*> Connector::get_possible_crtcs() const
{
	vector<Crtc*> crtcs;

	for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) {
		auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);

		auto l = enc->get_possible_crtcs();

		crtcs.insert(crtcs.end(), l.begin(), l.end());
	}

	return crtcs;
}

Crtc* Connector::get_current_crtc() const
{
	if (m_current_encoder)
		return m_current_encoder->get_crtc();
	else
		return 0;
}

uint32_t Connector::connector_type() const
{
	return m_priv->drm_connector->connector_type;
}

uint32_t Connector::connector_type_id() const
{
	return m_priv->drm_connector->connector_type_id;
}

uint32_t Connector::mmWidth() const
{
	return m_priv->drm_connector->mmWidth;
}

uint32_t Connector::mmHeight() const
{
	return m_priv->drm_connector->mmHeight;
}

uint32_t Connector::subpixel() const
{
	return m_priv->drm_connector->subpixel;
}

const string& Connector::subpixel_str() const
{
	return subpix_str.at(subpixel());
}

std::vector<Videomode> Connector::get_modes() const
{
	vector<Videomode> modes;

	for (int i = 0; i < m_priv->drm_connector->count_modes; i++)
		modes.push_back(drm_mode_to_video_mode(
					m_priv->drm_connector->modes[i]));

	return modes;
}

std::vector<Encoder*> Connector::get_encoders() const
{
	vector<Encoder*> encoders;

	for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) {
		auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
		encoders.push_back(enc);
	}
	return encoders;
}

}
<|endoftext|>


<commit_before>
#include "troymotor.h"
const int emptyQueue =-32767;

TroyMotor::TroyMotor(int pin1,int pin2){
  init(pin1,pin2);
}

void TroyMotor::init(int pin1,int pin2){

  _status=0;
  _currentStep=0;
  _goToStep=0;
  _position=false;
  _counter=0;
  _isReset=true;
  _direction=1;
  _pin=pin1;
  pinMode(pin1,OUTPUT);
  _pin2=pin2;
  pinMode(pin2,OUTPUT);

  //init queue
  _queueSize=3;
  _gotoArray= new int[_queueSize];//max assigned step
  for(int i=0;i<_queueSize;i++){
    _gotoArray[i]=0;
  }
  _queueTail=-1;
}

void TroyMotor::pushToStepQueue(int stepCount){
  if(_queueTail>=_queueSize){
    Serial.println("queue is full");
  }else{
   _gotoArray[++_queueTail]=stepCount;
  }
}

int TroyMotor::popToStepQueue(){

  if(_queueTail==-1){
    return emptyQueue;
  }
  int ret = _gotoArray[0];
  for(int i=0;i<_queueTail;i++){
    _gotoArray[i]=_gotoArray[i+1];
  }
  _queueTail--;
  return ret;
}

void TroyMotor::goToStep(int stepCount  ){
  _goToStep=stepCount;
  if(stepCount>0){
    _direction=1;
  }
  else{
    _direction=-1;
  }
}

void TroyMotor::setStatus(int status){
  _status=status;
}
int TroyMotor::getStatus(){
  return _status;
}

void TroyMotor::singleRun(){
  high();
  delay(50);
  low();
  Serial.println("singleRun");
}

void TroyMotor::step(){
  if(_counter==3){
    _currentStep+=_direction;
    _counter=0;
  }
#ifdef __DEBUG__
  Serial.print("currentStep=");
  Serial.println(_currentStep);
  Serial.print("goToStep=");
  Serial.println(_goToStep);
#endif
  if(_currentStep==_goToStep){
    _status=0;
    _counter=0;
    //check next run

    int nextStep = popToStepQueue();
    if(nextStep != emptyQueue ){
      goToStep(nextStep);
      _status=1;
    }
    return;
  }
  char ret[100];
#ifdef __DEBUG__
  sprintf(ret,"currentStep:%d,gotostep:%d",_currentStep,_goToStep);
  Serial.println(ret);
#endif

  if(_position){
    low();
    _position=false;
    _counter++;
  }
  else{
    high();
    _position=true;
    _counter++;
  }
}

void TroyMotor::run(){
  if(_isReset){
    step();
  }
  else{

    reseting();
  }

}

void TroyMotor::high(){
  if(_direction>0){
    digitalWrite(_pin,HIGH);
  }
  else{
    digitalWrite(_pin2,HIGH);
  }

}
void TroyMotor::low(){
  if(_direction>0){
    digitalWrite(_pin,LOW);
  }
  else{
    digitalWrite(_pin2,LOW);
  }
}
void TroyMotor::reseting(){
  int val = analogRead(5);
  if(val==0){
    Serial.print("reset step");
    Serial.println(_currentStep);

    _isReset=true;
    _currentStep=0;
    _position=false;
    _counter=0;
    _status=0;

  }
  else{
    step();
  }
}

void TroyMotor::reset(){
  _isReset=false;
  _status=1;
  _goToStep=3000; // give   hung steps
}

<commit_msg>fix bug: reseting method dont reset _goToStep<commit_after>
#include "troymotor.h"
const int emptyQueue =-32767;
#define __DEBUG__
TroyMotor::TroyMotor(int pin1,int pin2){
  init(pin1,pin2);
}

void TroyMotor::init(int pin1,int pin2){

  _status=0;
  _currentStep=0;
  _goToStep=0;
  _position=false;
  _counter=0;
  _isReset=true;
  _direction=1;
  _pin=pin1;
  pinMode(pin1,OUTPUT);
  _pin2=pin2;
  pinMode(pin2,OUTPUT);

  //init queue
  _queueSize=3;
  _gotoArray= new int[_queueSize];//max assigned step
  for(int i=0;i<_queueSize;i++){
    _gotoArray[i]=0;
  }
  _queueTail=-1;
}

void TroyMotor::pushToStepQueue(int stepCount){
  if(_queueTail>=_queueSize){
    Serial.println("queue is full");
  }else{
   _gotoArray[++_queueTail]=stepCount;
  }
}

int TroyMotor::popToStepQueue(){

  if(_queueTail==-1){
    return emptyQueue;
  }
  int ret = _gotoArray[0];
  for(int i=0;i<_queueTail;i++){
    _gotoArray[i]=_gotoArray[i+1];
  }
  _queueTail--;
  return ret;
}

void TroyMotor::goToStep(int stepCount  ){
  _goToStep=stepCount;
  if(stepCount>0){
    _direction=1;
  }
  else{
    _direction=-1;
  }
}

void TroyMotor::setStatus(int status){
  _status=status;
}
int TroyMotor::getStatus(){
  return _status;
}

void TroyMotor::singleRun(){
  high();
  delay(50);
  low();
  Serial.println("singleRun");
}

void TroyMotor::step(){
  if(_counter==3){
    _currentStep+=_direction;
    _counter=0;
  }
#ifdef __DEBUG__
  Serial.print("currentStep=");
  Serial.println(_currentStep);
  Serial.print("goToStep=");
  Serial.println(_goToStep);
#endif
  if(_currentStep==_goToStep){
    _status=0;
    _counter=0;
    //check next run

    int nextStep = popToStepQueue();
    if(nextStep != emptyQueue ){
      goToStep(nextStep);
      _status=1;
    }
    return;
  }
  char ret[100];
#ifdef __DEBUG__
  sprintf(ret,"currentStep:%d,gotostep:%d",_currentStep,_goToStep);
  Serial.println(ret);
#endif

  if(_position){
    low();
    _position=false;
    _counter++;
  }
  else{
    high();
    _position=true;
    _counter++;
  }
}

void TroyMotor::run(){
  if(_isReset){
    step();
  }
  else{

    reseting();
  }

}

void TroyMotor::high(){
  if(_direction>0){
    digitalWrite(_pin,HIGH);
  }
  else{
    digitalWrite(_pin2,HIGH);
  }

}
void TroyMotor::low(){
  if(_direction>0){
    digitalWrite(_pin,LOW);
  }
  else{
    digitalWrite(_pin2,LOW);
  }
}
void TroyMotor::reseting(){
  int val = analogRead(5);
  if(val==0){
    Serial.print("reset step");
    Serial.println(_currentStep);

    _isReset=true;
    _currentStep=0;
    _goToStep=0;
    _position=false;
    _counter=0;
    _status=0;

  }
  else{
    step();
  }
}

void TroyMotor::reset(){
  _isReset=false;
  _status=1;
  _goToStep=3000; // give   hung steps
}

<|endoftext|>