<commit_before>/*

This file is part of VROOM.

Copyright (c) 2015-2018, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include "./input_parser.h"

// Helper to get optional array of coordinates.
inline std::array<coordinate_t, 2>
parse_coordinates(const rapidjson::Value& object, const char* key) {
  if (!object[key].IsArray() or (object[key].Size() < 2) or
      !object[key][0].IsNumber() or !object[key][1].IsNumber()) {
    throw custom_exception("Invalid " + std::string(key) + " array.");
  }
  return {object[key][0].GetDouble(), object[key][1].GetDouble()};
}

inline boost::optional<amount_t> get_amount(const rapidjson::Value& object,
                                            const char* key) {
  if (!object.HasMember(key)) {
    return boost::none;
  }

  if (!object[key].IsArray()) {
    throw custom_exception("Invalid " + std::string(key) + " array.");
  }
  amount_t amount;
  for (rapidjson::SizeType i = 0; i < object[key].Size(); ++i) {
    if (!object[key][i].IsInt64()) {
      throw custom_exception("Invalid " + std::string(key) + " value.");
    }
    amount.push_back(object[key][i].GetInt64());
  }

  return amount;
}

inline bool valid_vehicle(const rapidjson::Value& v) {
  return v.IsObject() and v.HasMember("id") and v["id"].IsUint64();
}

input parse(const cl_args_t& cl_args) {
  BOOST_LOG_TRIVIAL(info) << "[Loading] Parsing input.";

  // Set relevant wrapper to retrieve the matrix and geometry.
  std::unique_ptr<routing_io<cost_t>> routing_wrapper;
  if (!cl_args.use_libosrm) {
    // Use osrm-routed.
    routing_wrapper = std::make_unique<routed_wrapper>(cl_args.osrm_address,
                                                       cl_args.osrm_port,
                                                       cl_args.osrm_profile);
  } else {
#if LIBOSRM
    // Use libosrm.
    if (cl_args.osrm_profile.empty()) {
      throw custom_exception("-l flag requires -m.");
    }
    routing_wrapper = std::make_unique<libosrm_wrapper>(cl_args.osrm_profile);
#else
    throw custom_exception("libosrm must be installed to use -l.");
#endif
  }

  // Custom input object embedding jobs, vehicles and matrix.
  input input_data(std::move(routing_wrapper), cl_args.geometry);

  // Input json object.
  rapidjson::Document json_input;

  // Parsing input string to populate the input object.
  if (json_input.Parse(cl_args.input.c_str()).HasParseError()) {
    std::string error_msg =
      std::string(rapidjson::GetParseError_En(json_input.GetParseError())) +
      " (offset: " + std::to_string(json_input.GetErrorOffset()) + ")";
    throw custom_exception(error_msg);
  }

  // Main Checks for valid json input.
  if (!json_input.HasMember("jobs") or !json_input["jobs"].IsArray() or
      json_input["jobs"].Empty()) {
    throw custom_exception("Invalid jobs.");
  }

  if (!json_input.HasMember("vehicles") or !json_input["vehicles"].IsArray() or
      json_input["vehicles"].Empty()) {
    throw custom_exception("Invalid vehicles.");
  }

  // Switch input type: explicit matrix or using OSRM.
  if (json_input.HasMember("matrix")) {
    if (!json_input["matrix"].IsArray()) {
      throw custom_exception("Invalid matrix.");
    }

    // Load custom matrix while checking if it is square.
    rapidjson::SizeType matrix_size = json_input["matrix"].Size();

    matrix<cost_t> matrix_input(matrix_size);
    for (rapidjson::SizeType i = 0; i < matrix_size; ++i) {
      if (!json_input["matrix"][i].IsArray() or
          (json_input["matrix"][i].Size() != matrix_size)) {
        throw custom_exception("Invalid matrix line " + std::to_string(i) +
                               ".");
      }
      for (rapidjson::SizeType j = 0; j < matrix_size; ++j) {
        if (!json_input["matrix"][i][j].IsUint()) {
          throw custom_exception("Invalid matrix entry (" + std::to_string(i) +
                                 "," + std::to_string(j) + ").");
        }
        cost_t cost = json_input["matrix"][i][j].GetUint();
        matrix_input[i][j] = cost;
      }
    }
    input_data.set_matrix(std::move(matrix_input));

    // Add all vehicles.
    for (rapidjson::SizeType i = 0; i < json_input["vehicles"].Size(); ++i) {
      if (!valid_vehicle(json_input["vehicles"][i])) {
        throw custom_exception("Invalid vehicle at " + std::to_string(i) + ".");
      }
      auto v_id = json_input["vehicles"][i]["id"].GetUint();

      // Check if vehicle has start_index or end_index.
      bool has_start_index = json_input["vehicles"][i].HasMember("start_index");
      index_t start_index = 0; // Initial value actually never used.
      if (has_start_index) {
        if (!json_input["vehicles"][i]["start_index"].IsUint()) {
          throw custom_exception("Invalid start_index for vehicle " +
                                 std::to_string(v_id) + ".");
        }
        start_index = json_input["vehicles"][i]["start_index"].GetUint();

        if (matrix_size <= start_index) {
          throw custom_exception(
            "start_index exceeding matrix size for vehicle" +
            std::to_string(v_id) + ".");
        }
      }

      bool has_start_coords = json_input["vehicles"][i].HasMember("start");

      bool has_end_index = json_input["vehicles"][i].HasMember("end_index");
      index_t end_index = 0; // Initial value actually never used.
      if (has_end_index) {
        if (!json_input["vehicles"][i]["end_index"].IsUint()) {
          throw custom_exception("Invalid end_index for vehicle" +
                                 std::to_string(v_id) + ".");
        }
        end_index = json_input["vehicles"][i]["end_index"].GetUint();

        if (matrix_size <= end_index) {
          throw custom_exception("end_index exceeding matrix size for vehicle" +
                                 std::to_string(v_id) + ".");
        }
      }

      bool has_end_coords = json_input["vehicles"][i].HasMember("end");

      // Add vehicle to input
      boost::optional<location_t> start;
      if (has_start_index) {
        if (has_start_coords) {
          start = boost::optional<location_t>(location_t(
            {start_index,
             parse_coordinates(json_input["vehicles"][i], "start")}));
        } else {
          start = boost::optional<location_t>(start_index);
        }
      }

      boost::optional<location_t> end;
      if (has_end_index) {
        if (has_end_coords) {
          end = boost::optional<location_t>(location_t(
            {end_index, parse_coordinates(json_input["vehicles"][i], "end")}));
        } else {
          end = boost::optional<location_t>(end_index);
        }
      }

      std::vector<skill_t> v_skills;

      vehicle_t current_v(v_id,
                          start,
                          end,
                          get_amount(json_input["vehicles"][i], "capacity"),
                          v_skills);

      input_data.add_vehicle(current_v);
    }

    // Add the jobs
    for (rapidjson::SizeType i = 0; i < json_input["jobs"].Size(); ++i) {
      if (!json_input["jobs"][i].IsObject()) {
        throw custom_exception("Invalid job.");
      }
      if (!json_input["jobs"][i].HasMember("id") or
          !json_input["jobs"][i]["id"].IsUint64()) {
        throw custom_exception("Invalid id for job at " + std::to_string(i) +
                               ".");
      }
      auto j_id = json_input["jobs"][i]["id"].GetUint64();
      if (!json_input["jobs"][i].HasMember("location_index") or
          !json_input["jobs"][i]["location_index"].IsUint()) {
        throw custom_exception("Invalid location_index for job " +
                               std::to_string(j_id) + ".");
      }
      if (matrix_size <= json_input["jobs"][i]["location_index"].GetUint()) {
        throw custom_exception("location_index exceeding matrix size for job " +
                               std::to_string(j_id) + ".");
      }

      std::vector<skill_t> job_skills;

      if (json_input["jobs"][i].HasMember("location")) {
        job_t current_job(j_id,
                          get_amount(json_input["jobs"][i], "amount"),
                          job_skills,
                          json_input["jobs"][i]["location_index"].GetUint(),
                          parse_coordinates(json_input["jobs"][i], "location"));
        input_data.add_job(current_job);
      } else {
        job_t current_job(json_input["jobs"][i]["id"].GetUint64(),
                          get_amount(json_input["jobs"][i], "amount"),
                          job_skills,
                          json_input["jobs"][i]["location_index"].GetUint());
        input_data.add_job(current_job);
      }
    }
  } else {
    // Adding vehicles and jobs only, matrix will be computed using
    // OSRM upon solving.

    // All vehicles.
    for (rapidjson::SizeType i = 0; i < json_input["vehicles"].Size(); ++i) {
      if (!valid_vehicle(json_input["vehicles"][i])) {
        throw custom_exception("Invalid vehicle at " + std::to_string(i) + ".");
      }

      // Start def is a ugly workaround as using plain:
      //
      // boost::optional<location_t> start;
      //
      // will raise a false positive -Wmaybe-uninitialized with gcc,
      // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47679

      auto start([]() -> boost::optional<location_t> { return boost::none; }());
      if (json_input["vehicles"][i].HasMember("start")) {
        start = boost::optional<location_t>(
          parse_coordinates(json_input["vehicles"][i], "start"));
      }

      boost::optional<location_t> end;
      if (json_input["vehicles"][i].HasMember("end")) {
        end = boost::optional<location_t>(
          parse_coordinates(json_input["vehicles"][i], "end"));
      }

      std::vector<skill_t> v_skills;

      vehicle_t current_v(json_input["vehicles"][i]["id"].GetUint(),
                          start,
                          end,
                          get_amount(json_input["vehicles"][i], "capacity"),
                          v_skills);

      input_data.add_vehicle(current_v);
    }

    // Getting jobs.
    for (rapidjson::SizeType i = 0; i < json_input["jobs"].Size(); ++i) {
      if (!json_input["jobs"][i].IsObject()) {
        throw custom_exception("Invalid job.");
      }
      if (!json_input["jobs"][i].HasMember("id") or
          !json_input["jobs"][i]["id"].IsUint64()) {
        throw custom_exception("Invalid id for job at " + std::to_string(i) +
                               ".");
      }
      auto j_id = json_input["jobs"][i]["id"].GetUint64();
      if (!json_input["jobs"][i].HasMember("location") or
          !json_input["jobs"][i]["location"].IsArray()) {
        throw custom_exception("Invalid location for job " +
                               std::to_string(j_id) + ".");
      }

      std::vector<skill_t> job_skills;

      job_t current_job(j_id,
                        get_amount(json_input["jobs"][i], "amount"),
                        job_skills,
                        parse_coordinates(json_input["jobs"][i], "location"));

      input_data.add_job(current_job);
    }
  }

  return input_data;
}
<commit_msg>Parse skills for jobs and vehicles in json input.<commit_after>/*

This file is part of VROOM.

Copyright (c) 2015-2018, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include "./input_parser.h"

// Helper to get optional array of coordinates.
inline std::array<coordinate_t, 2>
parse_coordinates(const rapidjson::Value& object, const char* key) {
  if (!object[key].IsArray() or (object[key].Size() < 2) or
      !object[key][0].IsNumber() or !object[key][1].IsNumber()) {
    throw custom_exception("Invalid " + std::string(key) + " array.");
  }
  return {object[key][0].GetDouble(), object[key][1].GetDouble()};
}

inline boost::optional<amount_t> get_amount(const rapidjson::Value& object,
                                            const char* key) {
  if (!object.HasMember(key)) {
    return boost::none;
  }

  if (!object[key].IsArray()) {
    throw custom_exception("Invalid " + std::string(key) + " array.");
  }
  amount_t amount;
  for (rapidjson::SizeType i = 0; i < object[key].Size(); ++i) {
    if (!object[key][i].IsInt64()) {
      throw custom_exception("Invalid " + std::string(key) + " value.");
    }
    amount.push_back(object[key][i].GetInt64());
  }

  return amount;
}

inline std::vector<skill_t> get_skills(const rapidjson::Value& object) {
  std::vector<skill_t> skills;
  if (object.HasMember("skills")) {
    if (!object["skills"].IsArray()) {
      throw custom_exception("Invalid skills object.");
    }
    for (rapidjson::SizeType i = 0; i < object["skills"].Size(); ++i) {
      if (!object["skills"][i].IsUint()) {
        throw custom_exception("Invalid skill value.");
      }
      skills.push_back(object["skills"][i].GetUint());
    }
  }

  return skills;
}

inline bool valid_vehicle(const rapidjson::Value& v) {
  return v.IsObject() and v.HasMember("id") and v["id"].IsUint64();
}

input parse(const cl_args_t& cl_args) {
  BOOST_LOG_TRIVIAL(info) << "[Loading] Parsing input.";

  // Set relevant wrapper to retrieve the matrix and geometry.
  std::unique_ptr<routing_io<cost_t>> routing_wrapper;
  if (!cl_args.use_libosrm) {
    // Use osrm-routed.
    routing_wrapper = std::make_unique<routed_wrapper>(cl_args.osrm_address,
                                                       cl_args.osrm_port,
                                                       cl_args.osrm_profile);
  } else {
#if LIBOSRM
    // Use libosrm.
    if (cl_args.osrm_profile.empty()) {
      throw custom_exception("-l flag requires -m.");
    }
    routing_wrapper = std::make_unique<libosrm_wrapper>(cl_args.osrm_profile);
#else
    throw custom_exception("libosrm must be installed to use -l.");
#endif
  }

  // Custom input object embedding jobs, vehicles and matrix.
  input input_data(std::move(routing_wrapper), cl_args.geometry);

  // Input json object.
  rapidjson::Document json_input;

  // Parsing input string to populate the input object.
  if (json_input.Parse(cl_args.input.c_str()).HasParseError()) {
    std::string error_msg =
      std::string(rapidjson::GetParseError_En(json_input.GetParseError())) +
      " (offset: " + std::to_string(json_input.GetErrorOffset()) + ")";
    throw custom_exception(error_msg);
  }

  // Main Checks for valid json input.
  if (!json_input.HasMember("jobs") or !json_input["jobs"].IsArray() or
      json_input["jobs"].Empty()) {
    throw custom_exception("Invalid jobs.");
  }

  if (!json_input.HasMember("vehicles") or !json_input["vehicles"].IsArray() or
      json_input["vehicles"].Empty()) {
    throw custom_exception("Invalid vehicles.");
  }

  // Switch input type: explicit matrix or using OSRM.
  if (json_input.HasMember("matrix")) {
    if (!json_input["matrix"].IsArray()) {
      throw custom_exception("Invalid matrix.");
    }

    // Load custom matrix while checking if it is square.
    rapidjson::SizeType matrix_size = json_input["matrix"].Size();

    matrix<cost_t> matrix_input(matrix_size);
    for (rapidjson::SizeType i = 0; i < matrix_size; ++i) {
      if (!json_input["matrix"][i].IsArray() or
          (json_input["matrix"][i].Size() != matrix_size)) {
        throw custom_exception("Invalid matrix line " + std::to_string(i) +
                               ".");
      }
      for (rapidjson::SizeType j = 0; j < matrix_size; ++j) {
        if (!json_input["matrix"][i][j].IsUint()) {
          throw custom_exception("Invalid matrix entry (" + std::to_string(i) +
                                 "," + std::to_string(j) + ").");
        }
        cost_t cost = json_input["matrix"][i][j].GetUint();
        matrix_input[i][j] = cost;
      }
    }
    input_data.set_matrix(std::move(matrix_input));

    // Add all vehicles.
    for (rapidjson::SizeType i = 0; i < json_input["vehicles"].Size(); ++i) {
      auto& json_vehicle = json_input["vehicles"][i];
      if (!valid_vehicle(json_vehicle)) {
        throw custom_exception("Invalid vehicle at " + std::to_string(i) + ".");
      }
      auto v_id = json_vehicle["id"].GetUint();

      // Check if vehicle has start_index or end_index.
      bool has_start_index = json_vehicle.HasMember("start_index");
      index_t start_index = 0; // Initial value actually never used.
      if (has_start_index) {
        if (!json_vehicle["start_index"].IsUint()) {
          throw custom_exception("Invalid start_index for vehicle " +
                                 std::to_string(v_id) + ".");
        }
        start_index = json_vehicle["start_index"].GetUint();

        if (matrix_size <= start_index) {
          throw custom_exception(
            "start_index exceeding matrix size for vehicle" +
            std::to_string(v_id) + ".");
        }
      }

      bool has_start_coords = json_vehicle.HasMember("start");

      bool has_end_index = json_vehicle.HasMember("end_index");
      index_t end_index = 0; // Initial value actually never used.
      if (has_end_index) {
        if (!json_vehicle["end_index"].IsUint()) {
          throw custom_exception("Invalid end_index for vehicle" +
                                 std::to_string(v_id) + ".");
        }
        end_index = json_vehicle["end_index"].GetUint();

        if (matrix_size <= end_index) {
          throw custom_exception("end_index exceeding matrix size for vehicle" +
                                 std::to_string(v_id) + ".");
        }
      }

      bool has_end_coords = json_vehicle.HasMember("end");

      // Add vehicle to input
      boost::optional<location_t> start;
      if (has_start_index) {
        if (has_start_coords) {
          start = boost::optional<location_t>(location_t(
            {start_index, parse_coordinates(json_vehicle, "start")}));
        } else {
          start = boost::optional<location_t>(start_index);
        }
      }

      boost::optional<location_t> end;
      if (has_end_index) {
        if (has_end_coords) {
          end = boost::optional<location_t>(
            location_t({end_index, parse_coordinates(json_vehicle, "end")}));
        } else {
          end = boost::optional<location_t>(end_index);
        }
      }

      vehicle_t current_v(v_id,
                          start,
                          end,
                          get_amount(json_vehicle, "capacity"),
                          get_skills(json_vehicle));

      input_data.add_vehicle(current_v);
    }

    // Add the jobs
    for (rapidjson::SizeType i = 0; i < json_input["jobs"].Size(); ++i) {
      auto& json_job = json_input["jobs"][i];
      if (!json_job.IsObject()) {
        throw custom_exception("Invalid job.");
      }
      if (!json_job.HasMember("id") or !json_job["id"].IsUint64()) {
        throw custom_exception("Invalid id for job at " + std::to_string(i) +
                               ".");
      }
      auto j_id = json_job["id"].GetUint64();
      if (!json_job.HasMember("location_index") or
          !json_job["location_index"].IsUint()) {
        throw custom_exception("Invalid location_index for job " +
                               std::to_string(j_id) + ".");
      }
      if (matrix_size <= json_job["location_index"].GetUint()) {
        throw custom_exception("location_index exceeding matrix size for job " +
                               std::to_string(j_id) + ".");
      }

      if (json_job.HasMember("location")) {
        job_t current_job(j_id,
                          get_amount(json_job, "amount"),
                          get_skills(json_job),
                          json_job["location_index"].GetUint(),
                          parse_coordinates(json_job, "location"));
        input_data.add_job(current_job);
      } else {
        job_t current_job(json_job["id"].GetUint64(),
                          get_amount(json_job, "amount"),
                          get_skills(json_job),
                          json_job["location_index"].GetUint());
        input_data.add_job(current_job);
      }
    }
  } else {
    // Adding vehicles and jobs only, matrix will be computed using
    // OSRM upon solving.

    // All vehicles.
    for (rapidjson::SizeType i = 0; i < json_input["vehicles"].Size(); ++i) {
      auto& json_vehicle = json_input["vehicles"][i];
      if (!valid_vehicle(json_vehicle)) {
        throw custom_exception("Invalid vehicle at " + std::to_string(i) + ".");
      }

      // Start def is a ugly workaround as using plain:
      //
      // boost::optional<location_t> start;
      //
      // will raise a false positive -Wmaybe-uninitialized with gcc,
      // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47679

      auto start([]() -> boost::optional<location_t> { return boost::none; }());
      if (json_vehicle.HasMember("start")) {
        start =
          boost::optional<location_t>(parse_coordinates(json_vehicle, "start"));
      }

      boost::optional<location_t> end;
      if (json_vehicle.HasMember("end")) {
        end =
          boost::optional<location_t>(parse_coordinates(json_vehicle, "end"));
      }

      vehicle_t current_v(json_vehicle["id"].GetUint(),
                          start,
                          end,
                          get_amount(json_vehicle, "capacity"),
                          get_skills(json_vehicle));

      input_data.add_vehicle(current_v);
    }

    // Getting jobs.
    for (rapidjson::SizeType i = 0; i < json_input["jobs"].Size(); ++i) {
      auto& json_job = json_input["jobs"][i];
      if (!json_job.IsObject()) {
        throw custom_exception("Invalid job.");
      }
      if (!json_job.HasMember("id") or !json_job["id"].IsUint64()) {
        throw custom_exception("Invalid id for job at " + std::to_string(i) +
                               ".");
      }
      auto j_id = json_job["id"].GetUint64();
      if (!json_job.HasMember("location") or !json_job["location"].IsArray()) {
        throw custom_exception("Invalid location for job " +
                               std::to_string(j_id) + ".");
      }

      job_t current_job(j_id,
                        get_amount(json_job, "amount"),
                        get_skills(json_job),
                        parse_coordinates(json_job, "location"));

      input_data.add_job(current_job);
    }
  }

  return input_data;
}
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, 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 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "sparse.h"

template<typename Scalar> void
initSPD(double density,
        Matrix<Scalar,Dynamic,Dynamic>& refMat,
        SparseMatrix<Scalar>& sparseMat)
{
  Matrix<Scalar,Dynamic,Dynamic> aux(refMat.rows(),refMat.cols());
  initSparse(density,refMat,sparseMat);
  refMat = refMat * refMat.adjoint();
  for (int k=0; k<2; ++k)
  {
    initSparse(density,aux,sparseMat,ForceNonZeroDiag);
    refMat += aux * aux.adjoint();
  }
  sparseMat.setZero();
  for (int j=0 ; j<sparseMat.cols(); ++j)
    for (int i=j ; i<sparseMat.rows(); ++i)
      if (refMat(i,j)!=Scalar(0))
        sparseMat.insert(i,j) = refMat(i,j);
  sparseMat.finalize();
}

template<typename Scalar> void sparse_solvers(int rows, int cols)
{
  double density = std::max(8./(rows*cols), 0.01);
  typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
  typedef Matrix<Scalar,Dynamic,1> DenseVector;
  // Scalar eps = 1e-6;

  DenseVector vec1 = DenseVector::Random(rows);

  std::vector<Vector2i> zeroCoords;
  std::vector<Vector2i> nonzeroCoords;

  // test triangular solver
  {
    DenseVector vec2 = vec1, vec3 = vec1;
    SparseMatrix<Scalar> m2(rows, cols);
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);

    // lower - dense
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
    VERIFY_IS_APPROX(refMat2.template marked<LowerTriangular>().solveTriangular(vec2),
                     m2.template triangular<LowerTriangular>().solve(vec3));

    // upper - dense
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
    VERIFY_IS_APPROX(refMat2.template marked<UpperTriangular>().solveTriangular(vec2),
                     m2.template triangular<UpperTriangular>().solve(vec3));

    // TODO test row major

    SparseMatrix<Scalar> matB(rows, rows);
    DenseMatrix refMatB = DenseMatrix::Zero(rows, rows);

    // lower - sparse
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular);
    initSparse<Scalar>(density, refMatB, matB);
    refMat2.template marked<LowerTriangular>().solveTriangularInPlace(refMatB);
    m2.template triangular<LowerTriangular>().solveInPlace(matB);
    VERIFY_IS_APPROX(matB.toDense(), refMatB);

    // upper - sparse
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular);
    initSparse<Scalar>(density, refMatB, matB);
    refMat2.template marked<UpperTriangular>().solveTriangularInPlace(refMatB);
    m2.template triangular<UpperTriangular>().solveInPlace(matB);
    VERIFY_IS_APPROX(matB, refMatB);

    // test deprecated API
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
    VERIFY_IS_APPROX(refMat2.template marked<LowerTriangular>().solveTriangular(vec2),
                     m2.template marked<LowerTriangular>().solveTriangular(vec3));
  }

  // test LLT
  {
    // TODO fix the issue with complex (see SparseLLT::solveInPlace)
    SparseMatrix<Scalar> m2(rows, cols);
    DenseMatrix refMat2(rows, cols);

    DenseVector b = DenseVector::Random(cols);
    DenseVector refX(cols), x(cols);

    initSPD(density, refMat2, m2);

    refMat2.llt().solve(b, &refX);
    typedef SparseMatrix<Scalar,LowerTriangular|SelfAdjoint> SparseSelfAdjointMatrix;
    if (!NumTraits<Scalar>::IsComplex)
    {
      x = b;
      SparseLLT<SparseSelfAdjointMatrix> (m2).solveInPlace(x);
      VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: default");
    }
    #ifdef EIGEN_CHOLMOD_SUPPORT
    x = b;
    SparseLLT<SparseSelfAdjointMatrix,Cholmod>(m2).solveInPlace(x);
    VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: cholmod");
    #endif
    if (!NumTraits<Scalar>::IsComplex)
    {
      #ifdef EIGEN_TAUCS_SUPPORT
      x = b;
      SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,IncompleteFactorization).solveInPlace(x);
      VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (IncompleteFactorization)");
      x = b;
      SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,SupernodalMultifrontal).solveInPlace(x);
      VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (SupernodalMultifrontal)");
      x = b;
      SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,SupernodalLeftLooking).solveInPlace(x);
      VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (SupernodalLeftLooking)");
      #endif
    }
  }

  // test LDLT
  if (!NumTraits<Scalar>::IsComplex)
  {
    // TODO fix the issue with complex (see SparseLDLT::solveInPlace)
    SparseMatrix<Scalar> m2(rows, cols);
    DenseMatrix refMat2(rows, cols);

    DenseVector b = DenseVector::Random(cols);
    DenseVector refX(cols), x(cols);

    //initSPD(density, refMat2, m2);
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, 0, 0);
    refMat2 += refMat2.adjoint();
    refMat2.diagonal() *= 0.5;

    refMat2.ldlt().solve(b, &refX);
    typedef SparseMatrix<Scalar,UpperTriangular|SelfAdjoint> SparseSelfAdjointMatrix;
    x = b;
    SparseLDLT<SparseSelfAdjointMatrix> ldlt(m2);
    if (ldlt.succeeded())
      ldlt.solveInPlace(x);
    VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LDLT: default");
  }

  // test LU
  {
    static int count = 0;
    SparseMatrix<Scalar> m2(rows, cols);
    DenseMatrix refMat2(rows, cols);

    DenseVector b = DenseVector::Random(cols);
    DenseVector refX(cols), x(cols);

    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag, &zeroCoords, &nonzeroCoords);

    LU<DenseMatrix> refLu(refMat2);
    refLu.solve(b, &refX);
    #if defined(EIGEN_SUPERLU_SUPPORT) || defined(EIGEN_UMFPACK_SUPPORT)
    Scalar refDet = refLu.determinant();
    #endif
    x.setZero();
    // // SparseLU<SparseMatrix<Scalar> > (m2).solve(b,&x);
    // // VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: default");
    #ifdef EIGEN_SUPERLU_SUPPORT
    {
      x.setZero();
      SparseLU<SparseMatrix<Scalar>,SuperLU> slu(m2);
      if (slu.succeeded())
      {
        if (slu.solve(b,&x)) {
          VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: SuperLU");
        }
        // std::cerr << refDet << " == " << slu.determinant() << "\n";
        if (slu.solve(b, &x, SvTranspose)) {
          VERIFY(b.isApprox(m2.transpose() * x, test_precision<Scalar>()));
        }

        if (slu.solve(b, &x, SvAdjoint)) {
//          VERIFY(b.isApprox(m2.adjoint() * x, test_precision<Scalar>()));
        }

        if (count==0) {
          VERIFY_IS_APPROX(refDet,slu.determinant()); // FIXME det is not very stable for complex
        }
      }
    }
    #endif
    #ifdef EIGEN_UMFPACK_SUPPORT
    {
      // check solve
      x.setZero();
      SparseLU<SparseMatrix<Scalar>,UmfPack> slu(m2);
      if (slu.succeeded()) {
        if (slu.solve(b,&x)) {
          if (count==0) {
            VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: umfpack");  // FIXME solve is not very stable for complex
          }
        }
        VERIFY_IS_APPROX(refDet,slu.determinant());
        // TODO check the extracted data
        //std::cerr << slu.matrixL() << "\n";
      }
    }
    #endif
    count++;
  }

}

void test_sparse_solvers()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST( sparse_solvers<double>(8, 8) );
    CALL_SUBTEST( sparse_solvers<std::complex<double> >(16, 16) );
    CALL_SUBTEST( sparse_solvers<double>(101, 101) );
  }
}
<commit_msg>enable testing of complex numbers for taucs<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, 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 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "sparse.h"

template<typename Scalar> void
initSPD(double density,
        Matrix<Scalar,Dynamic,Dynamic>& refMat,
        SparseMatrix<Scalar>& sparseMat)
{
  Matrix<Scalar,Dynamic,Dynamic> aux(refMat.rows(),refMat.cols());
  initSparse(density,refMat,sparseMat);
  refMat = refMat * refMat.adjoint();
  for (int k=0; k<2; ++k)
  {
    initSparse(density,aux,sparseMat,ForceNonZeroDiag);
    refMat += aux * aux.adjoint();
  }
  sparseMat.setZero();
  for (int j=0 ; j<sparseMat.cols(); ++j)
    for (int i=j ; i<sparseMat.rows(); ++i)
      if (refMat(i,j)!=Scalar(0))
        sparseMat.insert(i,j) = refMat(i,j);
  sparseMat.finalize();
}

template<typename Scalar> void sparse_solvers(int rows, int cols)
{
  double density = std::max(8./(rows*cols), 0.01);
  typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
  typedef Matrix<Scalar,Dynamic,1> DenseVector;
  // Scalar eps = 1e-6;

  DenseVector vec1 = DenseVector::Random(rows);

  std::vector<Vector2i> zeroCoords;
  std::vector<Vector2i> nonzeroCoords;

  // test triangular solver
  {
    DenseVector vec2 = vec1, vec3 = vec1;
    SparseMatrix<Scalar> m2(rows, cols);
    DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);

    // lower - dense
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
    VERIFY_IS_APPROX(refMat2.template marked<LowerTriangular>().solveTriangular(vec2),
                     m2.template triangular<LowerTriangular>().solve(vec3));

    // upper - dense
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
    VERIFY_IS_APPROX(refMat2.template marked<UpperTriangular>().solveTriangular(vec2),
                     m2.template triangular<UpperTriangular>().solve(vec3));

    // TODO test row major

    SparseMatrix<Scalar> matB(rows, rows);
    DenseMatrix refMatB = DenseMatrix::Zero(rows, rows);

    // lower - sparse
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular);
    initSparse<Scalar>(density, refMatB, matB);
    refMat2.template marked<LowerTriangular>().solveTriangularInPlace(refMatB);
    m2.template triangular<LowerTriangular>().solveInPlace(matB);
    VERIFY_IS_APPROX(matB.toDense(), refMatB);

    // upper - sparse
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular);
    initSparse<Scalar>(density, refMatB, matB);
    refMat2.template marked<UpperTriangular>().solveTriangularInPlace(refMatB);
    m2.template triangular<UpperTriangular>().solveInPlace(matB);
    VERIFY_IS_APPROX(matB, refMatB);

    // test deprecated API
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
    VERIFY_IS_APPROX(refMat2.template marked<LowerTriangular>().solveTriangular(vec2),
                     m2.template marked<LowerTriangular>().solveTriangular(vec3));
  }

  // test LLT
  {
    // TODO fix the issue with complex (see SparseLLT::solveInPlace)
    SparseMatrix<Scalar> m2(rows, cols);
    DenseMatrix refMat2(rows, cols);

    DenseVector b = DenseVector::Random(cols);
    DenseVector refX(cols), x(cols);

    initSPD(density, refMat2, m2);

    refMat2.llt().solve(b, &refX);
    typedef SparseMatrix<Scalar,LowerTriangular|SelfAdjoint> SparseSelfAdjointMatrix;
    if (!NumTraits<Scalar>::IsComplex)
    {
      x = b;
      SparseLLT<SparseSelfAdjointMatrix> (m2).solveInPlace(x);
      VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: default");
    }
    #ifdef EIGEN_CHOLMOD_SUPPORT
    x = b;
    SparseLLT<SparseSelfAdjointMatrix,Cholmod>(m2).solveInPlace(x);
    VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: cholmod");
    #endif

    #ifdef EIGEN_TAUCS_SUPPORT
    x = b;
    SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,IncompleteFactorization).solveInPlace(x);
    VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (IncompleteFactorization)");
    x = b;
    SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,SupernodalMultifrontal).solveInPlace(x);
    VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (SupernodalMultifrontal)");
    x = b;
    SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,SupernodalLeftLooking).solveInPlace(x);
    VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (SupernodalLeftLooking)");
    #endif
  }

  // test LDLT
  if (!NumTraits<Scalar>::IsComplex)
  {
    // TODO fix the issue with complex (see SparseLDLT::solveInPlace)
    SparseMatrix<Scalar> m2(rows, cols);
    DenseMatrix refMat2(rows, cols);

    DenseVector b = DenseVector::Random(cols);
    DenseVector refX(cols), x(cols);

    //initSPD(density, refMat2, m2);
    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, 0, 0);
    refMat2 += refMat2.adjoint();
    refMat2.diagonal() *= 0.5;

    refMat2.ldlt().solve(b, &refX);
    typedef SparseMatrix<Scalar,UpperTriangular|SelfAdjoint> SparseSelfAdjointMatrix;
    x = b;
    SparseLDLT<SparseSelfAdjointMatrix> ldlt(m2);
    if (ldlt.succeeded())
      ldlt.solveInPlace(x);
    VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LDLT: default");
  }

  // test LU
  {
    static int count = 0;
    SparseMatrix<Scalar> m2(rows, cols);
    DenseMatrix refMat2(rows, cols);

    DenseVector b = DenseVector::Random(cols);
    DenseVector refX(cols), x(cols);

    initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag, &zeroCoords, &nonzeroCoords);

    LU<DenseMatrix> refLu(refMat2);
    refLu.solve(b, &refX);
    #if defined(EIGEN_SUPERLU_SUPPORT) || defined(EIGEN_UMFPACK_SUPPORT)
    Scalar refDet = refLu.determinant();
    #endif
    x.setZero();
    // // SparseLU<SparseMatrix<Scalar> > (m2).solve(b,&x);
    // // VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: default");
    #ifdef EIGEN_SUPERLU_SUPPORT
    {
      x.setZero();
      SparseLU<SparseMatrix<Scalar>,SuperLU> slu(m2);
      if (slu.succeeded())
      {
        if (slu.solve(b,&x)) {
          VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: SuperLU");
        }
        // std::cerr << refDet << " == " << slu.determinant() << "\n";
        if (slu.solve(b, &x, SvTranspose)) {
          VERIFY(b.isApprox(m2.transpose() * x, test_precision<Scalar>()));
        }

        if (slu.solve(b, &x, SvAdjoint)) {
//          VERIFY(b.isApprox(m2.adjoint() * x, test_precision<Scalar>()));
        }

        if (count==0) {
          VERIFY_IS_APPROX(refDet,slu.determinant()); // FIXME det is not very stable for complex
        }
      }
    }
    #endif
    #ifdef EIGEN_UMFPACK_SUPPORT
    {
      // check solve
      x.setZero();
      SparseLU<SparseMatrix<Scalar>,UmfPack> slu(m2);
      if (slu.succeeded()) {
        if (slu.solve(b,&x)) {
          if (count==0) {
            VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: umfpack");  // FIXME solve is not very stable for complex
          }
        }
        VERIFY_IS_APPROX(refDet,slu.determinant());
        // TODO check the extracted data
        //std::cerr << slu.matrixL() << "\n";
      }
    }
    #endif
    count++;
  }

}

void test_sparse_solvers()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST( sparse_solvers<double>(8, 8) );
    CALL_SUBTEST( sparse_solvers<std::complex<double> >(16, 16) );
    CALL_SUBTEST( sparse_solvers<double>(101, 101) );
  }
}
<|endoftext|>


<commit_before>#pragma once
#include "common_defines.hpp"

#ifdef new
#undef new
#endif

#include <functional>
using std::greater;
using std::less;
using std::greater;
using std::equal_to;

#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
<commit_msg>Remove duplicating 'using' entry.<commit_after>#pragma once
#include "common_defines.hpp"

#ifdef new
#undef new
#endif

#include <functional>

using std::less;
using std::greater;
using std::equal_to;

#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <gtest/gtest.h>
#include <thread>
#include <chrono>
#include <msgrpc/thrift_struct/thrift_codec.h>

using namespace std;
using namespace std::chrono;

#include "demo/demo_api_declare.h"

#if 0
    #define ___methods_of_interface___IBuzzMath(_, ...)            \
        _(1, ResponseBar, negative_fields, RequestFoo, __VA_ARGS__)\
        _(2, ResponseBar, plus1_to_fields, RequestFoo, __VA_ARGS__)

    ___as_interface(IBuzzMath, __with_interface_id(1))
#endif

////////////////////////////////////////////////////////////////////////////////
namespace msgrpc {
    template <typename T> struct Ret {};

    typedef unsigned short msg_id_t;
    typedef unsigned short service_id_t; //TODO: how to deal with different service id types

    struct MsgChannel {
        virtual uint32_t send_msg(const service_id_t& remote_service_id, msg_id_t msg_id, const char* buf, size_t len) const = 0;
    };

    struct Config {
        void initWith(MsgChannel* msg_channel, msgrpc::msg_id_t request_msg_id, msgrpc::msg_id_t response_msg_id) {
            instance().msg_channel_ = msg_channel;
            request_msg_id_  = request_msg_id;
            response_msg_id_ = response_msg_id;
        }

        static inline Config& instance() {
            static thread_local Config instance;
            return instance;
        }

        MsgChannel* msg_channel_;
        msg_id_t request_msg_id_;
        msg_id_t response_msg_id_;
    };
}

namespace msgrpc {
    /*TODO: using static_assert to assure name length of interface and method*/
    const size_t k_max_interface_name_len = 40;
    const size_t k_max_method_name_len = 40;

    /*TODO: consider make msgHeader encoded through thrift*/
    struct MsgHeader {
        unsigned char  msgrpc_version_;
        unsigned char  method_index_in_interface_;
        unsigned short interface_index_in_service_;
    };

    struct Request : MsgHeader {
    };

    struct RpcInvokeHandler {
        void handleInvoke(const MsgHeader& msg_header) {
        }
    };
}

////////////////////////////////////////////////////////////////////////////////
#include "test_util/UdpChannel.h"
namespace demo {
    const msgrpc::msg_id_t k_msgrpc_request_msg_id = 101;
    const msgrpc::msg_id_t k_msgrpc_response_msg_id = 102;

    struct UdpMsgChannel : msgrpc::MsgChannel {
        virtual uint32_t send_msg(const msgrpc::service_id_t& remote_service_id, msgrpc::msg_id_t msg_id, const char* buf, size_t len) const {
            size_t msg_len_with_msgid = sizeof(msgrpc::msg_id_t) + len;
            char* mem = (char*)malloc(msg_len_with_msgid);
            if (mem) {
                *(msgrpc::msg_id_t*)(mem) = msg_id;
                memcpy(mem + sizeof(msgrpc::msg_id_t), buf, len);
                cout << "send msg len: " << msg_len_with_msgid << endl;
                g_msg_channel->send_msg_to_remote(string(mem, msg_len_with_msgid), udp::endpoint(udp::v4(), remote_service_id));
                free(mem);
            } else {
                cout << "send msg failed: allocation failure." << endl;
            }
            return 0;
        }
    };
}

////////////////////////////////////////////////////////////////////////////////
using namespace demo;

const msgrpc::service_id_t k_remote_service_id = 2222;
const msgrpc::service_id_t k_loacl_service_id  = 3333;

struct IBuzzMath {
    virtual msgrpc::Ret<ResponseBar> negative_fields(const RequestFoo&) = 0;
    virtual msgrpc::Ret<ResponseBar> plus1_to_fields(const RequestFoo&) = 0;
};

////////////////////////////////////////////////////////////////////////////////
struct IBuzzMathStub : IBuzzMath {
    virtual msgrpc::Ret<ResponseBar> negative_fields(const RequestFoo&);
    virtual msgrpc::Ret<ResponseBar> plus1_to_fields(const RequestFoo&);
};

msgrpc::Ret<ResponseBar> IBuzzMathStub::negative_fields(const RequestFoo& req) {
    uint8_t* pbuf; uint32_t len;
    /*TODO: extract interface for encode/decode for other protocol adoption such as protobuf*/
    if (!ThriftEncoder::encode(req, &pbuf, &len)) {
        /*TODO: how to do with log, maybe should extract logging interface*/
        cout << "encode failed." << endl;
        return msgrpc::Ret<ResponseBar>();
    }

    //TODO: find k_remote_service_id by interface name "IBuzzMath"
    size_t msg_len_with_header = sizeof(msgrpc::MsgHeader) + len;

    char* mem = (char*)malloc(msg_len_with_header);
    if (!mem) {
        cout << "alloc mem failed, during sending rpc request." << endl;
        return msgrpc::Ret<ResponseBar>();
    }

    auto header = (msgrpc::MsgHeader*)mem;
    header->msgrpc_version_ = 0;
    header->interface_index_in_service_ = 1;
    header->method_index_in_interface_ = 1;
    memcpy(header + 1, (const char*)pbuf, len);

    cout << "stub sending msg with length: " << msg_len_with_header << endl;
    msgrpc::Config::instance().msg_channel_->send_msg(k_remote_service_id, k_msgrpc_request_msg_id, mem, msg_len_with_header);
    free(mem);
    return msgrpc::Ret<ResponseBar>();
}

msgrpc::Ret<ResponseBar> IBuzzMathStub::plus1_to_fields(const RequestFoo& req) {
    return msgrpc::Ret<ResponseBar>();
}

void local_service() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    msgrpc::Config::instance().initWith(new UdpMsgChannel(), k_msgrpc_request_msg_id, k_msgrpc_response_msg_id);

    UdpChannel channel(k_loacl_service_id,
        [&channel](msgrpc::msg_id_t msg_id, const char* msg, size_t len) {
            if (0 == strcmp(msg, "init")) {

                IBuzzMathStub buzzMath;
                RequestFoo foo; foo.fooa = 97; foo.__set_foob(98);
                buzzMath.negative_fields(foo);

            } else {
                cout << "local received msg: " << string(msg, len) << endl;
                channel.close();
            }
        }
    );
}

////////////////////////////////////////////////////////////////////////////////
struct IBuzzMathImpl {
    bool onRpcInvoke(const msgrpc::MsgHeader& msg_header, const char* msg, size_t len, uint8_t*& pout_buf, uint32_t& out_buf_len);   //todo:remote_id
    bool do_negative_fields(const char* msg, size_t len, uint8_t*& pout_buf, uint32_t& out_buf_len);
    bool do_plus1_to_fields(const char* msg, size_t len, uint8_t*& pout_buf, uint32_t& out_buf_len);

    bool negative_fields(const RequestFoo& req, ResponseBar& rsp);
    bool plus1_to_fields(const RequestFoo& req, ResponseBar& rsp);

    template<typename REQ, typename RSP>
    bool invoke_templated_method(bool (IBuzzMathImpl::*method_impl)(const REQ&, RSP&), const char* msg, size_t len, uint8_t*& pout_buf, uint32_t& out_buf_len);

};

bool IBuzzMathImpl::onRpcInvoke(const msgrpc::MsgHeader& msg_header, const char* msg, size_t len, uint8_t*& pout_buf, uint32_t& out_buf_len) {
    cout << (int)msg_header.msgrpc_version_ << endl;
    cout << (int)msg_header.interface_index_in_service_ << endl;
    cout << (int)msg_header.method_index_in_interface_ << endl;

    this->invoke_templated_method(&IBuzzMathImpl::negative_fields, msg, len, pout_buf, out_buf_len);
    return true;
}

template<typename REQ, typename RSP>
bool IBuzzMathImpl::invoke_templated_method(bool (IBuzzMathImpl::*method_impl)(const REQ&, RSP&), const char* msg, size_t len, uint8_t*& pout_buf, uint32_t& out_buf_len) {
    REQ req;
    if (! ThriftDecoder::decode(req, (uint8_t*)msg, len)) {
        cout << "decode failed on remote side." << endl;
        return false;
    }

    RSP rsp;
    if (! (this->*method_impl)(req, rsp)) {
        return false;
    }

    if (! ThriftEncoder::encode(rsp, &pout_buf, &out_buf_len)) {
        cout << "encode failed on remtoe side." << endl;
        return false;
    }

    return true;
}

bool IBuzzMathImpl::negative_fields(const RequestFoo& req, ResponseBar& rsp) {
    rsp.__set_bara(req.get_foob());
    if (req.__isset.foob) {
        rsp.__set_barb(req.fooa);
    }
    return true;
}

bool IBuzzMathImpl::plus1_to_fields(const RequestFoo& req, ResponseBar& rsp) {
    rsp.__set_bara(1 + req.fooa);
    if (req.__isset.foob) {
        rsp.__set_barb(1 + req.get_foob());
    }
    return true;
}

////////////////////////////////////////////////////////////////////////////////
void remote_service() {
    msgrpc::Config::instance().initWith(new UdpMsgChannel(), k_msgrpc_request_msg_id, k_msgrpc_response_msg_id);

    UdpChannel channel(k_remote_service_id,
        [&channel](msgrpc::msg_id_t msg_id, const char* msg, size_t len) {
            if (0 == strcmp(msg, "init")) {
                return;
            }
            cout << "remote received msg with length: " << len << endl;

            /*TODO: should first check msg_id == msgrpc_msg_request_id */
            if (len < sizeof(msgrpc::MsgHeader)) {
                cout << "invalid msg: without sufficient msg header info." << endl;
                return;
            }

            auto msg_header = (msgrpc::MsgHeader*)msg;
            msg += sizeof(msgrpc::MsgHeader);

            /*TODO: search interface implementation instance to handle tbis rpc request*/
            IBuzzMathImpl buzzMath;
            uint8_t* pout_buf; uint32_t out_buf_len;
            if (buzzMath.onRpcInvoke(*msg_header, msg, len - sizeof(msgrpc::MsgHeader), pout_buf, out_buf_len)) {
                /*TODO: send out msg with msgheader*/
                msgrpc::Config::instance().msg_channel_->send_msg(k_loacl_service_id, k_msgrpc_response_msg_id,(const char*)pout_buf, out_buf_len);
            }

            channel.close();
        }
    );
}

////////////////////////////////////////////////////////////////////////////////
TEST(async_rpc, should_able_to__auto__register_rpc_interface__after__application_startup) {
    demo::RequestFoo req;
    req.fooa = 1;
    req.__set_foob(2);

    std::thread local_thread(local_service);
    std::thread remote_thread(remote_service);

    local_thread.join();
    remote_thread.join();
};
<commit_msg>extract templated method for rpc reqeust decoding and response encoding.<commit_after>#include <iostream>
#include <gtest/gtest.h>
#include <thread>
#include <chrono>
#include <msgrpc/thrift_struct/thrift_codec.h>

using namespace std;
using namespace std::chrono;

#include "demo/demo_api_declare.h"

#if 0
    #define ___methods_of_interface___IBuzzMath(_, ...)            \
        _(1, ResponseBar, negative_fields, RequestFoo, __VA_ARGS__)\
        _(2, ResponseBar, plus1_to_fields, RequestFoo, __VA_ARGS__)

    ___as_interface(IBuzzMath, __with_interface_id(1))
#endif

////////////////////////////////////////////////////////////////////////////////
namespace msgrpc {
    template <typename T> struct Ret {};

    typedef unsigned short msg_id_t;
    typedef unsigned short service_id_t; //TODO: how to deal with different service id types

    struct MsgChannel {
        virtual uint32_t send_msg(const service_id_t& remote_service_id, msg_id_t msg_id, const char* buf, size_t len) const = 0;
    };

    struct Config {
        void initWith(MsgChannel* msg_channel, msgrpc::msg_id_t request_msg_id, msgrpc::msg_id_t response_msg_id) {
            instance().msg_channel_ = msg_channel;
            request_msg_id_  = request_msg_id;
            response_msg_id_ = response_msg_id;
        }

        static inline Config& instance() {
            static thread_local Config instance;
            return instance;
        }

        MsgChannel* msg_channel_;
        msg_id_t request_msg_id_;
        msg_id_t response_msg_id_;
    };
}

namespace msgrpc {
    /*TODO: using static_assert to assure name length of interface and method*/
    const size_t k_max_interface_name_len = 40;
    const size_t k_max_method_name_len = 40;

    /*TODO: consider make msgHeader encoded through thrift*/
    struct MsgHeader {
        unsigned char  msgrpc_version_;
        unsigned char  method_index_in_interface_;
        unsigned short interface_index_in_service_;
        /*TODO: call sequence number*/
    };

    /*TODO: define response header*/
    /*response code: success, failed, not_implemented*/

    struct Request : MsgHeader {
    };

    struct RpcInvokeHandler {
        void handleInvoke(const MsgHeader& msg_header) {
        }
    };
}

////////////////////////////////////////////////////////////////////////////////
#include "test_util/UdpChannel.h"
namespace demo {
    const msgrpc::msg_id_t k_msgrpc_request_msg_id = 101;
    const msgrpc::msg_id_t k_msgrpc_response_msg_id = 102;

    struct UdpMsgChannel : msgrpc::MsgChannel {
        virtual uint32_t send_msg(const msgrpc::service_id_t& remote_service_id, msgrpc::msg_id_t msg_id, const char* buf, size_t len) const {
            size_t msg_len_with_msgid = sizeof(msgrpc::msg_id_t) + len;
            char* mem = (char*)malloc(msg_len_with_msgid);
            if (mem) {
                *(msgrpc::msg_id_t*)(mem) = msg_id;
                memcpy(mem + sizeof(msgrpc::msg_id_t), buf, len);
                cout << "send msg len: " << msg_len_with_msgid << endl;
                g_msg_channel->send_msg_to_remote(string(mem, msg_len_with_msgid), udp::endpoint(udp::v4(), remote_service_id));
                free(mem);
            } else {
                cout << "send msg failed: allocation failure." << endl;
            }
            return 0;
        }
    };
}

////////////////////////////////////////////////////////////////////////////////
using namespace demo;

const msgrpc::service_id_t k_remote_service_id = 2222;
const msgrpc::service_id_t k_loacl_service_id  = 3333;

struct IBuzzMath {
    virtual msgrpc::Ret<ResponseBar> negative_fields(const RequestFoo&) = 0;
    virtual msgrpc::Ret<ResponseBar> plus1_to_fields(const RequestFoo&) = 0;
};

////////////////////////////////////////////////////////////////////////////////
struct IBuzzMathStub : IBuzzMath {
    virtual msgrpc::Ret<ResponseBar> negative_fields(const RequestFoo&);
    virtual msgrpc::Ret<ResponseBar> plus1_to_fields(const RequestFoo&);
};

msgrpc::Ret<ResponseBar> IBuzzMathStub::negative_fields(const RequestFoo& req) {
    uint8_t* pbuf; uint32_t len;
    /*TODO: extract interface for encode/decode for other protocol adoption such as protobuf*/
    if (!ThriftEncoder::encode(req, &pbuf, &len)) {
        /*TODO: how to do with log, maybe should extract logging interface*/
        cout << "encode failed." << endl;
        return msgrpc::Ret<ResponseBar>();
    }

    //TODO: find k_remote_service_id by interface name "IBuzzMath"
    size_t msg_len_with_header = sizeof(msgrpc::MsgHeader) + len;

    char* mem = (char*)malloc(msg_len_with_header);
    if (!mem) {
        cout << "alloc mem failed, during sending rpc request." << endl;
        return msgrpc::Ret<ResponseBar>();
    }

    auto header = (msgrpc::MsgHeader*)mem;
    header->msgrpc_version_ = 0;
    header->interface_index_in_service_ = 1;
    header->method_index_in_interface_ = 1;
    memcpy(header + 1, (const char*)pbuf, len);

    cout << "stub sending msg with length: " << msg_len_with_header << endl;
    msgrpc::Config::instance().msg_channel_->send_msg(k_remote_service_id, k_msgrpc_request_msg_id, mem, msg_len_with_header);
    free(mem);
    return msgrpc::Ret<ResponseBar>();
}

msgrpc::Ret<ResponseBar> IBuzzMathStub::plus1_to_fields(const RequestFoo& req) {
    return msgrpc::Ret<ResponseBar>();
}

void local_service() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    msgrpc::Config::instance().initWith(new UdpMsgChannel(), k_msgrpc_request_msg_id, k_msgrpc_response_msg_id);

    UdpChannel channel(k_loacl_service_id,
        [&channel](msgrpc::msg_id_t msg_id, const char* msg, size_t len) {
            if (0 == strcmp(msg, "init")) {

                IBuzzMathStub buzzMath;
                RequestFoo foo; foo.fooa = 97; foo.__set_foob(98);
                buzzMath.negative_fields(foo);

            } else {
                cout << "local received msg: " << string(msg, len) << endl;
                channel.close();
            }
        }
    );
}

////////////////////////////////////////////////////////////////////////////////
namespace msgrpc {

    template<typename T>
    struct InterfaceImplBase {
        template<typename REQ, typename RSP>
        bool invoke_templated_method( bool (T::*method_impl)(const REQ &, RSP &)
                                    , const char *msg, size_t len
                                    , uint8_t *&pout_buf, uint32_t &out_buf_len) {
            REQ req;
            if (!ThriftDecoder::decode(req, (uint8_t *) msg, len)) {
                cout << "decode failed on remote side." << endl;
                return false;
            }

            RSP rsp;
            if (!((T*)this->*method_impl)(req, rsp)) {
                return false;
            }

            if (!ThriftEncoder::encode(rsp, &pout_buf, &out_buf_len)) {
                cout << "encode failed on remtoe side." << endl;
                return false;
            }

            return true;
        }
    };
}

struct IBuzzMathImpl : msgrpc::InterfaceImplBase<IBuzzMathImpl> {
    bool onRpcInvoke(const msgrpc::MsgHeader& msg_header, const char* msg, size_t len, uint8_t*& pout_buf, uint32_t& out_buf_len);   //todo:remote_id
    //TODO: try to unify with stub's signature
    bool negative_fields(const RequestFoo& req, ResponseBar& rsp);
    bool plus1_to_fields(const RequestFoo& req, ResponseBar& rsp);
};

bool IBuzzMathImpl::onRpcInvoke(const msgrpc::MsgHeader& msg_header, const char* msg, size_t len, uint8_t*& pout_buf, uint32_t& out_buf_len) {
    cout << (int)msg_header.msgrpc_version_ << endl;
    cout << (int)msg_header.interface_index_in_service_ << endl;
    cout << (int)msg_header.method_index_in_interface_ << endl;

    if (msg_header.method_index_in_interface_ == 1) {
        this->invoke_templated_method(&IBuzzMathImpl::negative_fields, msg, len, pout_buf, out_buf_len);
    } else

    if (msg_header.method_index_in_interface_ == 2) {
        this->invoke_templated_method(&IBuzzMathImpl::plus1_to_fields, msg, len, pout_buf, out_buf_len);
    } else

    {
        /*TODO: return method not implemented code*/
        return false;
    }

    return true;
}

bool IBuzzMathImpl::negative_fields(const RequestFoo& req, ResponseBar& rsp) {
    rsp.__set_bara(req.get_foob());
    if (req.__isset.foob) {
        rsp.__set_barb(req.fooa);
    }
    return true;
}

bool IBuzzMathImpl::plus1_to_fields(const RequestFoo& req, ResponseBar& rsp) {
    rsp.__set_bara(1 + req.fooa);
    if (req.__isset.foob) {
        rsp.__set_barb(1 + req.get_foob());
    }
    return true;
}

////////////////////////////////////////////////////////////////////////////////
void remote_service() {
    msgrpc::Config::instance().initWith(new UdpMsgChannel(), k_msgrpc_request_msg_id, k_msgrpc_response_msg_id);

    UdpChannel channel(k_remote_service_id,
        [&channel](msgrpc::msg_id_t msg_id, const char* msg, size_t len) {
            if (0 == strcmp(msg, "init")) {
                return;
            }
            cout << "remote received msg with length: " << len << endl;

            /*TODO: should first check msg_id == msgrpc_msg_request_id */
            if (len < sizeof(msgrpc::MsgHeader)) {
                cout << "invalid msg: without sufficient msg header info." << endl;
                return;
            }

            auto msg_header = (msgrpc::MsgHeader*)msg;
            msg += sizeof(msgrpc::MsgHeader);

            /*TODO: search interface implementation instance to handle tbis rpc request*/
            IBuzzMathImpl buzzMath;
            uint8_t* pout_buf; uint32_t out_buf_len;
            if (buzzMath.onRpcInvoke(*msg_header, msg, len - sizeof(msgrpc::MsgHeader), pout_buf, out_buf_len)) {
                /*TODO: send out msg with msgheader*/
                msgrpc::Config::instance().msg_channel_->send_msg(k_loacl_service_id, k_msgrpc_response_msg_id,(const char*)pout_buf, out_buf_len);
            }

            channel.close();
        }
    );
}

////////////////////////////////////////////////////////////////////////////////
TEST(async_rpc, should_able_to__auto__register_rpc_interface__after__application_startup) {
    demo::RequestFoo req;
    req.fooa = 1;
    req.__set_foob(2);

    std::thread local_thread(local_service);
    std::thread remote_thread(remote_service);

    local_thread.join();
    remote_thread.join();
};
<|endoftext|>


<commit_before>//
// Copyright 2020 Google LLC
//
// 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 <google/protobuf/text_format.h>
#include <cctype>
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <vector>

#include "absl/flags/flag.h"
#include "absl/flags/parse.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "src/config.pb.h"
#include "src/execute_linter.h"

ABSL_FLAG(std::string, config, "",
          "A prototxt file having configuration options.");

ABSL_FLAG(bool, quick, false,
          "This flag will read from standart input. It will read one"
          "statement and continue until reading semicolon ';'");

namespace zetasql::linter {
namespace {

std::string ReadFile(const char* filename) {
  std::ifstream file(filename);
  std::string str = "";
  for (std::string line; std::getline(file, line);) {
    str += line + "\n";
  }
  return str;
}

Config ReadFromConfigFile(const char* filename) {
  Config config;
  std::string str = ReadFile(filename);
  if (!google::protobuf::TextFormat::ParseFromString(str, &config)) {
    std::cerr << "Configuration file couldn't be parsed." << std::endl;
    config = Config();
  }
  return config;
}

bool HasValidExtension(char* filename_char) {
  std::string filename(filename_char);
  std::vector<std::string> supported_extensions{".sql", ".sqlm", ".sqlp",
                                                ".sqlt", ".gsql"};

  std::string extension_str = absl::StrJoin(supported_extensions.begin(),
                                            supported_extensions.end(), ", ");

  bool ok = false;
  std::size_t last_dot = filename.find_last_of(".");
  std::string extension = filename.substr(last_dot);

  for (std::string supported_extension : supported_extensions)
    if (supported_extension == extension) ok = true;
  if (!ok) {
    std::cerr << "Ignoring " << filename << ";  not have a valid extension ("
              << extension_str << ")" << std::endl;
    return 0;
  }
  return 1;
}

void quick_run(Config config) {
  std::string str = "";
  for (std::string line; std::getline(std::cin, line);) {
    bool end = false;
    for (char c : line) {
      str += c;
      if (c == ';') {
        end = true;
        break;
      }
    }
    str += "\n";
  }
  zetasql::linter::LinterResult result =
      zetasql::linter::RunChecks(absl::string_view(str), config, "");

  result.PrintResult();
}

void run(std::vector<char*> sql_files, Config config) {
  bool runner = true;
  for (char* filename : sql_files) {
    // The first argument is './runner'.
    if (runner || !HasValidExtension(filename)) {
      runner = false;
      continue;
    }
    std::string str = ReadFile(filename);
    LinterResult result = RunChecks(absl::string_view(str), config, filename);

    result.PrintResult();
  }
}

}  // namespace
}  // namespace zetasql::linter

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cerr << "Usage: ./runner --config=<config_file> <file_names>\n"
              << std::endl;
    return 1;
  }

  std::vector<char*> sql_files = absl::ParseCommandLine(argc, argv);

  std::string config_file = absl::GetFlag(FLAGS_config);
  bool quick = absl::GetFlag(FLAGS_quick);

  zetasql::linter::Config config =
      zetasql::linter::ReadFromConfigFile(config_file.c_str());

  if (quick)
    zetasql::linter::quick_run(config);
  else
    zetasql::linter::run(sql_files, config);

  return 0;
}
<commit_msg>don't use char *<commit_after>//
// Copyright 2020 Google LLC
//
// 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 <google/protobuf/text_format.h>
#include <cctype>
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <vector>

#include "absl/flags/flag.h"
#include "absl/flags/parse.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "src/config.pb.h"
#include "src/execute_linter.h"

ABSL_FLAG(std::string, config, "",
          "A prototxt file having configuration options.");

ABSL_FLAG(bool, quick, false,
          "This flag will read from standart input. It will read one"
          "statement and continue until reading semicolon ';'");

namespace zetasql::linter {
namespace {

std::string ReadFile(std::string filename) {
  std::ifstream file(filename.c_str());
  std::string str = "";
  for (std::string line; std::getline(file, line);) {
    str += line + "\n";
  }
  return str;
}

Config ReadFromConfigFile(std::string filename) {
  Config config;
  std::string str = ReadFile(filename);
  if (!google::protobuf::TextFormat::ParseFromString(str, &config)) {
    std::cerr << "Configuration file couldn't be parsed." << std::endl;
    config = Config();
  }
  return config;
}

bool HasValidExtension(std::string filename) {
  std::vector<std::string> supported_extensions{".sql", ".sqlm", ".sqlp",
                                                ".sqlt", ".gsql"};

  std::string extension_str = absl::StrJoin(supported_extensions.begin(),
                                            supported_extensions.end(), ", ");

  bool ok = false;
  std::size_t last_dot = filename.find_last_of(".");
  std::string extension = filename.substr(last_dot);

  for (std::string supported_extension : supported_extensions)
    if (supported_extension == extension) ok = true;
  if (!ok) {
    std::cerr << "Ignoring " << filename << ";  not have a valid extension ("
              << extension_str << ")" << std::endl;
    return 0;
  }
  return 1;
}

void quick_run(Config config) {
  std::string str = "";
  for (std::string line; std::getline(std::cin, line);) {
    bool end = false;
    for (char c : line) {
      str += c;
      if (c == ';') {
        end = true;
        break;
      }
    }
    str += "\n";
  }
  zetasql::linter::LinterResult result =
      zetasql::linter::RunChecks(absl::string_view(str), config, "");

  result.PrintResult();
}

void run(std::vector<std::string> sql_files, Config config) {
  bool runner = true;
  for (std::string filename : sql_files) {
    // The first argument is './runner'.
    if (runner || !HasValidExtension(filename)) {
      runner = false;
      continue;
    }
    std::string str = ReadFile(filename);
    LinterResult result = RunChecks(absl::string_view(str), config, filename);

    result.PrintResult();
  }
}

}  // namespace
}  // namespace zetasql::linter

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cerr << "Usage: ./runner --config=<config_file> <file_names>\n"
              << std::endl;
    return 1;
  }

  std::vector<std::string> sql_files;
  for (char* file : absl::ParseCommandLine(argc, argv))
    sql_files.push_back(std::string(file));

  std::string config_file = absl::GetFlag(FLAGS_config);
  bool quick = absl::GetFlag(FLAGS_quick);

  zetasql::linter::Config config =
      zetasql::linter::ReadFromConfigFile(config_file.c_str());

  if (quick)
    zetasql::linter::quick_run(config);
  else
    zetasql::linter::run(sql_files, config);

  return 0;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2014, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/socket_io.hpp"
#include "libtorrent/socket.hpp"

#include <string>

using namespace libtorrent;
using namespace libtorrent::detail;

int test_main()
{
	// test address_to_bytes
	TEST_EQUAL(address_to_bytes(address_v4::from_string("10.11.12.13")), "\x0a\x0b\x0c\x0d");
	TEST_EQUAL(address_to_bytes(address_v4::from_string("16.5.127.1")), "\x10\x05\x7f\x01");

	// test endpoint_to_bytes
	TEST_EQUAL(endpoint_to_bytes(udp::endpoint(address_v4::from_string("10.11.12.13"), 8080)), "\x0a\x0b\x0c\x0d\x1f\x90");
	TEST_EQUAL(endpoint_to_bytes(udp::endpoint(address_v4::from_string("16.5.127.1"), 12345)), "\x10\x05\x7f\x01\x30\x39");

	std::string buf;
	std::back_insert_iterator<std::string> out1(buf);
	write_address(address_v4::from_string("16.5.128.1"), out1);
	TEST_EQUAL(buf, "\x10\x05\x80\x01");
	std::string::iterator in = buf.begin();
	address addr4 = read_v4_address(in);
	TEST_EQUAL(addr4, address_v4::from_string("16.5.128.1"));

	buf.clear();
	std::back_insert_iterator<std::string> out2(buf);
	write_endpoint(udp::endpoint(address_v4::from_string("16.5.128.1"), 1337), out2);
	TEST_EQUAL(buf, "\x10\x05\x80\x01\x05\x39");
	in = buf.begin();
	udp::endpoint ep4 = read_v4_endpoint<udp::endpoint>(in);
	TEST_EQUAL(ep4, udp::endpoint(address_v4::from_string("16.5.128.1"), 1337));

#if TORRENT_USE_IPV6
	buf.clear();
	std::back_insert_iterator<std::string> out3(buf);
	write_address(address_v6::from_string("1000::ffff"), out3);
	TEST_CHECK(std::equal(buf.begin(), buf.end(), "\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff"));
	in = buf.begin();
	address addr6 = read_v6_address(in);
	TEST_EQUAL(addr6, address_v6::from_string("1000::ffff"));

	buf.clear();
	std::back_insert_iterator<std::string> out4(buf);
	write_endpoint(udp::endpoint(address_v6::from_string("1000::ffff"), 1337), out4);
	TEST_CHECK(std::equal(buf.begin(), buf.end(), "\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\x05\x39"));
	TEST_EQUAL(buf.size(), 18);
	in = buf.begin();
	udp::endpoint ep6 = read_v6_endpoint<udp::endpoint>(in);
	TEST_EQUAL(ep6, udp::endpoint(address_v6::from_string("1000::ffff"), 1337));
#endif

	char const eplist[] = "l6:\x10\x05\x80\x01\x05\x39" "18:\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\x05\x39" "e";
	lazy_entry e;
	error_code ec;
	lazy_bdecode(eplist, eplist + sizeof(eplist)-1, e, ec);
	TEST_CHECK(!ec);
	std::vector<udp::endpoint> list;
	read_endpoint_list<udp::endpoint>(&e, list);

	TEST_EQUAL(list.size(), 2);
	TEST_EQUAL(list[0], udp::endpoint(address_v4::from_string("16.5.128.1"), 1337));
	TEST_EQUAL(list[1], udp::endpoint(address_v6::from_string("1000::ffff"), 1337));

	entry e2 = bdecode(eplist, eplist + sizeof(eplist)-1);
	list.clear();
	read_endpoint_list<udp::endpoint>(&e2, list);

	TEST_EQUAL(list.size(), 2);
	TEST_EQUAL(list[0], udp::endpoint(address_v4::from_string("16.5.128.1"), 1337));
	TEST_EQUAL(list[1], udp::endpoint(address_v6::from_string("1000::ffff"), 1337));

	return 0;
}

<commit_msg>fix non-ipv6 build of unit tests<commit_after>/*

Copyright (c) 2014, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/socket_io.hpp"
#include "libtorrent/socket.hpp"

#include <string>

using namespace libtorrent;
using namespace libtorrent::detail;

int test_main()
{
	// test address_to_bytes
	TEST_EQUAL(address_to_bytes(address_v4::from_string("10.11.12.13")), "\x0a\x0b\x0c\x0d");
	TEST_EQUAL(address_to_bytes(address_v4::from_string("16.5.127.1")), "\x10\x05\x7f\x01");

	// test endpoint_to_bytes
	TEST_EQUAL(endpoint_to_bytes(udp::endpoint(address_v4::from_string("10.11.12.13"), 8080)), "\x0a\x0b\x0c\x0d\x1f\x90");
	TEST_EQUAL(endpoint_to_bytes(udp::endpoint(address_v4::from_string("16.5.127.1"), 12345)), "\x10\x05\x7f\x01\x30\x39");

	std::string buf;
	std::back_insert_iterator<std::string> out1(buf);
	write_address(address_v4::from_string("16.5.128.1"), out1);
	TEST_EQUAL(buf, "\x10\x05\x80\x01");
	std::string::iterator in = buf.begin();
	address addr4 = read_v4_address(in);
	TEST_EQUAL(addr4, address_v4::from_string("16.5.128.1"));

	buf.clear();
	std::back_insert_iterator<std::string> out2(buf);
	write_endpoint(udp::endpoint(address_v4::from_string("16.5.128.1"), 1337), out2);
	TEST_EQUAL(buf, "\x10\x05\x80\x01\x05\x39");
	in = buf.begin();
	udp::endpoint ep4 = read_v4_endpoint<udp::endpoint>(in);
	TEST_EQUAL(ep4, udp::endpoint(address_v4::from_string("16.5.128.1"), 1337));

#if TORRENT_USE_IPV6
	buf.clear();
	std::back_insert_iterator<std::string> out3(buf);
	write_address(address_v6::from_string("1000::ffff"), out3);
	TEST_CHECK(std::equal(buf.begin(), buf.end(), "\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff"));
	in = buf.begin();
	address addr6 = read_v6_address(in);
	TEST_EQUAL(addr6, address_v6::from_string("1000::ffff"));

	buf.clear();
	std::back_insert_iterator<std::string> out4(buf);
	write_endpoint(udp::endpoint(address_v6::from_string("1000::ffff"), 1337), out4);
	TEST_CHECK(std::equal(buf.begin(), buf.end(), "\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\x05\x39"));
	TEST_EQUAL(buf.size(), 18);
	in = buf.begin();
	udp::endpoint ep6 = read_v6_endpoint<udp::endpoint>(in);
	TEST_EQUAL(ep6, udp::endpoint(address_v6::from_string("1000::ffff"), 1337));
#endif

	char const eplist[] = "l6:\x10\x05\x80\x01\x05\x39" "18:\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\x05\x39" "e";
	lazy_entry e;
	error_code ec;
	lazy_bdecode(eplist, eplist + sizeof(eplist)-1, e, ec);
	TEST_CHECK(!ec);
	std::vector<udp::endpoint> list;
	read_endpoint_list<udp::endpoint>(&e, list);

#if TORRENT_USE_IPV6
	TEST_EQUAL(list.size(), 2);
	TEST_EQUAL(list[1], udp::endpoint(address_v6::from_string("1000::ffff"), 1337));
#else
	TEST_EQUAL(list.size(), 1);
#endif
	TEST_EQUAL(list[0], udp::endpoint(address_v4::from_string("16.5.128.1"), 1337));

	entry e2 = bdecode(eplist, eplist + sizeof(eplist)-1);
	list.clear();
	read_endpoint_list<udp::endpoint>(&e2, list);

#if TORRENT_USE_IPV6
	TEST_EQUAL(list.size(), 2);
	TEST_EQUAL(list[1], udp::endpoint(address_v6::from_string("1000::ffff"), 1337));
#else
	TEST_EQUAL(list.size(), 1);
#endif
	TEST_EQUAL(list[0], udp::endpoint(address_v4::from_string("16.5.128.1"), 1337));

	return 0;
}

<|endoftext|>


<commit_before>#include "./scene.h"
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <string>
#include <vector>
#include "./graphics/gl.h"
#include "./input/invoke_manager.h"
#include "./graphics/render_data.h"
#include "./graphics/managers.h"
#include "./graphics/volume_manager.h"
#include "./graphics/shader_program.h"
#include "./camera_controllers.h"
#include "./nodes.h"
#include "./labelling/labeller_frame_data.h"
#include "./label_node.h"
#include "./eigen_qdebug.h"
#include "./utils/path_helper.h"
#include "./placement/to_gray.h"
#include "./placement/distance_transform.h"
#include "./placement/occupancy.h"
#include "./placement/apollonius.h"
#include "./texture_mapper_manager.h"
#include "./constraint_buffer.h"

Scene::Scene(std::shared_ptr<InvokeManager> invokeManager,
             std::shared_ptr<Nodes> nodes, std::shared_ptr<Labels> labels,
             std::shared_ptr<Forces::Labeller> forcesLabeller,
             std::shared_ptr<Placement::Labeller> placementLabeller,
             std::shared_ptr<TextureMapperManager> textureMapperManager)

  : nodes(nodes), labels(labels), forcesLabeller(forcesLabeller),
    placementLabeller(placementLabeller), frustumOptimizer(nodes),
    textureMapperManager(textureMapperManager)
{
  cameraControllers =
      std::make_shared<CameraControllers>(invokeManager, camera);

  fbo = std::make_shared<Graphics::FrameBufferObject>();
  constraintBuffer = std::make_shared<ConstraintBuffer>();
  managers = std::make_shared<Graphics::Managers>();
}

Scene::~Scene()
{
  nodes->clear();
  qInfo() << "Destructor of Scene"
          << "Remaining managers instances" << managers.use_count();
}

void Scene::initialize()
{
  glAssert(gl->glClearColor(0.9f, 0.9f, 0.8f, 1.0f));

  quad = std::make_shared<Graphics::ScreenQuad>(
      ":shader/pass.vert", ":shader/textureForRenderBuffer.frag");
  positionQuad = std::make_shared<Graphics::ScreenQuad>(
      ":shader/pass.vert", ":shader/positionRenderTarget.frag");
  distanceTransformQuad = std::make_shared<Graphics::ScreenQuad>(
      ":shader/pass.vert", ":shader/distanceTransform.frag");

  fbo->initialize(gl, width, height);
  constraintBuffer->initialize(gl, width, height);
  haBuffer =
      std::make_shared<Graphics::HABuffer>(Eigen::Vector2i(width, height));
  managers->getShaderManager()->initialize(gl, haBuffer);

  managers->getObjectManager()->initialize(gl, 128, 10000000);
  haBuffer->initialize(gl, managers);
  quad->initialize(gl, managers);
  positionQuad->initialize(gl, managers);
  distanceTransformQuad->initialize(gl, managers);

  managers->getTextureManager()->initialize(gl, true, 8);

  textureMapperManager->resize(width, height);
  textureMapperManager->initialize(gl, fbo);

  placementLabeller->initialize(
      textureMapperManager->getOccupancyTextureMapper(),
      textureMapperManager->getDistanceTransformTextureMapper(),
      textureMapperManager->getApolloniusTextureMapper());
}

void Scene::cleanup()
{
  placementLabeller->cleanup();
  textureMapperManager->cleanup();
}

void Scene::update(double frameTime, QSet<Qt::Key> keysPressed)
{
  this->frameTime = frameTime;
  cameraControllers->update(frameTime);

  frustumOptimizer.update(camera.getViewMatrix());
  camera.updateNearAndFarPlanes(frustumOptimizer.getNear(),
                                frustumOptimizer.getFar());
  haBuffer->updateNearAndFarPlanes(frustumOptimizer.getNear(),
                                   frustumOptimizer.getFar());

  /*
  auto newPositions = forcesLabeller->update(LabellerFrameData(
      frameTime, camera.getProjectionMatrix(), camera.getViewMatrix()));
      */
  auto newPositions = placementLabeller->getLastPlacementResult();
  for (auto &labelNode : nodes->getLabelNodes())
  {
    labelNode->labelPosition = newPositions[labelNode->label.id];
  }
}

void Scene::render()
{
  if (shouldResize)
  {
    camera.resize(width, height);
    fbo->resize(width, height);
    shouldResize = false;
  }
  glAssert(gl->glViewport(0, 0, width, height));
  glAssert(gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));

  fbo->bind();
  glAssert(gl->glViewport(0, 0, width, height));
  glAssert(gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));

  RenderData renderData;
  renderData.projectionMatrix = camera.getProjectionMatrix();
  renderData.viewMatrix = camera.getViewMatrix();
  renderData.cameraPosition = camera.getPosition();
  renderData.modelMatrix = Eigen::Matrix4f::Identity();
  renderData.windowPixelSize = Eigen::Vector2f(width, height);

  haBuffer->clearAndPrepare(managers);

  nodes->render(gl, managers, renderData);

  managers->getObjectManager()->render(renderData);

  haBuffer->render(managers, renderData);

  // doPick();

  fbo->unbind();

  glAssert(gl->glDisable(GL_DEPTH_TEST));
  renderScreenQuad();

  textureMapperManager->update();

  renderDebuggingViews(renderData);

  glAssert(gl->glEnable(GL_DEPTH_TEST));

  nodes->renderLabels(gl, managers, renderData);
}

void Scene::renderDebuggingViews(const RenderData &renderData)
{
  fbo->bindDepthTexture(GL_TEXTURE0);
  auto transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(-0.8, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(quad, transformation.matrix());

  placementLabeller->update(LabellerFrameData(
      frameTime, camera.getProjectionMatrix(), camera.getViewMatrix()));

  textureMapperManager->bindOccupancyTexture();
  transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(-0.4, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(quad, transformation.matrix());

  textureMapperManager->bindDistanceTransform();
  transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(0.0, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(distanceTransformQuad, transformation.matrix());

  textureMapperManager->bindApollonius();
  transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(0.4, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(quad, transformation.matrix());

  constraintBuffer->bindTexture(GL_TEXTURE0);
  transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(0.8, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(quad, transformation.matrix());
}

void Scene::renderQuad(std::shared_ptr<Graphics::ScreenQuad> quad,
                       Eigen::Matrix4f modelMatrix)
{
  RenderData renderData;
  renderData.projectionMatrix = Eigen::Matrix4f::Identity();
  renderData.viewMatrix = Eigen::Matrix4f::Identity();
  renderData.modelMatrix = modelMatrix;

  quad->getShaderProgram()->bind();
  quad->getShaderProgram()->setUniform("textureSampler", 0);
  quad->renderImmediately(gl, managers, renderData);
}

void Scene::renderScreenQuad()
{
  fbo->bindColorTexture(GL_TEXTURE0);

  renderQuad(quad, Eigen::Matrix4f::Identity());
}

void Scene::resize(int width, int height)
{
  this->width = width;
  this->height = height;

  placementLabeller->resize(width, height);

  shouldResize = true;

  forcesLabeller->resize(width, height);
}

void Scene::pick(int id, Eigen::Vector2f position)
{
  pickingPosition = position;
  performPicking = true;
  pickingLabelId = id;
}

void Scene::doPick()
{
  if (!performPicking)
    return;

  float depth = -2.0f;

  fbo->bindDepthTexture(GL_TEXTURE0);

  glAssert(gl->glReadPixels(pickingPosition.x(),
                            height - pickingPosition.y() - 1, 1, 1,
                            GL_DEPTH_COMPONENT, GL_FLOAT, &depth));
  Eigen::Vector4f positionNDC(pickingPosition.x() * 2.0f / width - 1.0f,
                              pickingPosition.y() * -2.0f / height + 1.0f,
                              depth * 2.0f - 1.0f, 1.0f);

  Eigen::Matrix4f viewProjection =
      camera.getProjectionMatrix() * camera.getViewMatrix();
  Eigen::Vector4f positionWorld = viewProjection.inverse() * positionNDC;
  positionWorld = positionWorld / positionWorld.w();

  qWarning() << "picked:" << positionWorld;

  performPicking = false;
  auto label = labels->getById(pickingLabelId);
  label.anchorPosition = toVector3f(positionWorld);

  labels->update(label);
}

<commit_msg>Call PlacementLabeller::update outside of renderDebuggingViews.<commit_after>#include "./scene.h"
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <string>
#include <vector>
#include "./graphics/gl.h"
#include "./input/invoke_manager.h"
#include "./graphics/render_data.h"
#include "./graphics/managers.h"
#include "./graphics/volume_manager.h"
#include "./graphics/shader_program.h"
#include "./camera_controllers.h"
#include "./nodes.h"
#include "./labelling/labeller_frame_data.h"
#include "./label_node.h"
#include "./eigen_qdebug.h"
#include "./utils/path_helper.h"
#include "./placement/to_gray.h"
#include "./placement/distance_transform.h"
#include "./placement/occupancy.h"
#include "./placement/apollonius.h"
#include "./texture_mapper_manager.h"
#include "./constraint_buffer.h"

Scene::Scene(std::shared_ptr<InvokeManager> invokeManager,
             std::shared_ptr<Nodes> nodes, std::shared_ptr<Labels> labels,
             std::shared_ptr<Forces::Labeller> forcesLabeller,
             std::shared_ptr<Placement::Labeller> placementLabeller,
             std::shared_ptr<TextureMapperManager> textureMapperManager)

  : nodes(nodes), labels(labels), forcesLabeller(forcesLabeller),
    placementLabeller(placementLabeller), frustumOptimizer(nodes),
    textureMapperManager(textureMapperManager)
{
  cameraControllers =
      std::make_shared<CameraControllers>(invokeManager, camera);

  fbo = std::make_shared<Graphics::FrameBufferObject>();
  constraintBuffer = std::make_shared<ConstraintBuffer>();
  managers = std::make_shared<Graphics::Managers>();
}

Scene::~Scene()
{
  nodes->clear();
  qInfo() << "Destructor of Scene"
          << "Remaining managers instances" << managers.use_count();
}

void Scene::initialize()
{
  glAssert(gl->glClearColor(0.9f, 0.9f, 0.8f, 1.0f));

  quad = std::make_shared<Graphics::ScreenQuad>(
      ":shader/pass.vert", ":shader/textureForRenderBuffer.frag");
  positionQuad = std::make_shared<Graphics::ScreenQuad>(
      ":shader/pass.vert", ":shader/positionRenderTarget.frag");
  distanceTransformQuad = std::make_shared<Graphics::ScreenQuad>(
      ":shader/pass.vert", ":shader/distanceTransform.frag");

  fbo->initialize(gl, width, height);
  constraintBuffer->initialize(gl, width, height);
  haBuffer =
      std::make_shared<Graphics::HABuffer>(Eigen::Vector2i(width, height));
  managers->getShaderManager()->initialize(gl, haBuffer);

  managers->getObjectManager()->initialize(gl, 128, 10000000);
  haBuffer->initialize(gl, managers);
  quad->initialize(gl, managers);
  positionQuad->initialize(gl, managers);
  distanceTransformQuad->initialize(gl, managers);

  managers->getTextureManager()->initialize(gl, true, 8);

  textureMapperManager->resize(width, height);
  textureMapperManager->initialize(gl, fbo);

  placementLabeller->initialize(
      textureMapperManager->getOccupancyTextureMapper(),
      textureMapperManager->getDistanceTransformTextureMapper(),
      textureMapperManager->getApolloniusTextureMapper());
}

void Scene::cleanup()
{
  placementLabeller->cleanup();
  textureMapperManager->cleanup();
}

void Scene::update(double frameTime, QSet<Qt::Key> keysPressed)
{
  this->frameTime = frameTime;
  cameraControllers->update(frameTime);

  frustumOptimizer.update(camera.getViewMatrix());
  camera.updateNearAndFarPlanes(frustumOptimizer.getNear(),
                                frustumOptimizer.getFar());
  haBuffer->updateNearAndFarPlanes(frustumOptimizer.getNear(),
                                   frustumOptimizer.getFar());

  /*
  auto newPositions = forcesLabeller->update(LabellerFrameData(
      frameTime, camera.getProjectionMatrix(), camera.getViewMatrix()));
      */
  auto newPositions = placementLabeller->getLastPlacementResult();
  for (auto &labelNode : nodes->getLabelNodes())
  {
    labelNode->labelPosition = newPositions[labelNode->label.id];
  }
}

void Scene::render()
{
  if (shouldResize)
  {
    camera.resize(width, height);
    fbo->resize(width, height);
    shouldResize = false;
  }
  glAssert(gl->glViewport(0, 0, width, height));
  glAssert(gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));

  fbo->bind();
  glAssert(gl->glViewport(0, 0, width, height));
  glAssert(gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));

  RenderData renderData;
  renderData.projectionMatrix = camera.getProjectionMatrix();
  renderData.viewMatrix = camera.getViewMatrix();
  renderData.cameraPosition = camera.getPosition();
  renderData.modelMatrix = Eigen::Matrix4f::Identity();
  renderData.windowPixelSize = Eigen::Vector2f(width, height);

  haBuffer->clearAndPrepare(managers);

  nodes->render(gl, managers, renderData);

  managers->getObjectManager()->render(renderData);

  haBuffer->render(managers, renderData);

  // doPick();

  fbo->unbind();

  glAssert(gl->glDisable(GL_DEPTH_TEST));
  renderScreenQuad();

  textureMapperManager->update();

  placementLabeller->update(LabellerFrameData(
      frameTime, camera.getProjectionMatrix(), camera.getViewMatrix()));

  renderDebuggingViews(renderData);

  glAssert(gl->glEnable(GL_DEPTH_TEST));

  nodes->renderLabels(gl, managers, renderData);
}

void Scene::renderDebuggingViews(const RenderData &renderData)
{
  fbo->bindDepthTexture(GL_TEXTURE0);
  auto transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(-0.8, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(quad, transformation.matrix());

  textureMapperManager->bindOccupancyTexture();
  transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(-0.4, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(quad, transformation.matrix());

  textureMapperManager->bindDistanceTransform();
  transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(0.0, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(distanceTransformQuad, transformation.matrix());

  textureMapperManager->bindApollonius();
  transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(0.4, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(quad, transformation.matrix());

  constraintBuffer->bindTexture(GL_TEXTURE0);
  transformation =
      Eigen::Affine3f(Eigen::Translation3f(Eigen::Vector3f(0.8, -0.8, 0)) *
                      Eigen::Scaling(Eigen::Vector3f(0.2, 0.2, 1)));
  renderQuad(quad, transformation.matrix());
}

void Scene::renderQuad(std::shared_ptr<Graphics::ScreenQuad> quad,
                       Eigen::Matrix4f modelMatrix)
{
  RenderData renderData;
  renderData.projectionMatrix = Eigen::Matrix4f::Identity();
  renderData.viewMatrix = Eigen::Matrix4f::Identity();
  renderData.modelMatrix = modelMatrix;

  quad->getShaderProgram()->bind();
  quad->getShaderProgram()->setUniform("textureSampler", 0);
  quad->renderImmediately(gl, managers, renderData);
}

void Scene::renderScreenQuad()
{
  fbo->bindColorTexture(GL_TEXTURE0);

  renderQuad(quad, Eigen::Matrix4f::Identity());
}

void Scene::resize(int width, int height)
{
  this->width = width;
  this->height = height;

  placementLabeller->resize(width, height);

  shouldResize = true;

  forcesLabeller->resize(width, height);
}

void Scene::pick(int id, Eigen::Vector2f position)
{
  pickingPosition = position;
  performPicking = true;
  pickingLabelId = id;
}

void Scene::doPick()
{
  if (!performPicking)
    return;

  float depth = -2.0f;

  fbo->bindDepthTexture(GL_TEXTURE0);

  glAssert(gl->glReadPixels(pickingPosition.x(),
                            height - pickingPosition.y() - 1, 1, 1,
                            GL_DEPTH_COMPONENT, GL_FLOAT, &depth));
  Eigen::Vector4f positionNDC(pickingPosition.x() * 2.0f / width - 1.0f,
                              pickingPosition.y() * -2.0f / height + 1.0f,
                              depth * 2.0f - 1.0f, 1.0f);

  Eigen::Matrix4f viewProjection =
      camera.getProjectionMatrix() * camera.getViewMatrix();
  Eigen::Vector4f positionWorld = viewProjection.inverse() * positionNDC;
  positionWorld = positionWorld / positionWorld.w();

  qWarning() << "picked:" << positionWorld;

  performPicking = false;
  auto label = labels->getById(pickingLabelId);
  label.anchorPosition = toVector3f(positionWorld);

  labels->update(label);
}

<|endoftext|>