<commit_before>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * 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 "modules/map/relative_map/navigation_lane.h"

#include <algorithm>
#include <limits>

#include "modules/map/proto/map_lane.pb.h"

#include "modules/common/log.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/math/vec2d.h"
#include "modules/common/util/util.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/map/relative_map/common/relative_map_gflags.h"

namespace apollo {
namespace relative_map {

using apollo::common::VehicleStateProvider;
using apollo::common::math::Vec2d;
using apollo::common::util::DistanceXY;
using apollo::hdmap::Lane;
using apollo::common::util::operator+;
using apollo::perception::PerceptionObstacles;

NavigationLane::NavigationLane(const NavigationLaneConfig &config)
    : config_(config) {}

void NavigationLane::SetConfig(const NavigationLaneConfig &config) {
  config_ = config;
}

bool NavigationLane::GeneratePath() {
  // original_pose is in world coordination: ENU
  original_pose_ = VehicleStateProvider::instance()->original_pose();

  navigation_path_.Clear();
  auto *path = navigation_path_.mutable_path();
  const auto &lane_marker = perception_obstacles_.lane_marker();

  // priority: merge > navigation line > perception lane marker
  if (FLAGS_enable_navigation_line &&
      navigation_info_.navigation_path_size() > 0) {
    ConvertNavigationLineToPath(path);
    if (path->path_point().size() <= 0) {
      ConvertLaneMarkerToPath(lane_marker, path);
    }
  } else {
    ConvertLaneMarkerToPath(lane_marker, path);
  }
  return true;
}

double NavigationLane::EvaluateCubicPolynomial(const double c0, const double c1,
                                               const double c2, const double c3,
                                               const double z) const {
  return ((c3 * z + c2) * z + c1) * z + c0;
}

void NavigationLane::MergeNavigationLineAndLaneMarker(
    const perception::LaneMarkers &lane_marker, common::Path *path) {
  CHECK_NOTNULL(path);

  common::Path navigation_path;
  ConvertNavigationLineToPath(&navigation_path);

  common::Path lane_marker_path;
  ConvertLaneMarkerToPath(perception_obstacles_.lane_marker(),
                          &lane_marker_path);

  const double len = std::fmin(
      navigation_path.path_point(navigation_path.path_point_size() - 1).s(),
      lane_marker_path.path_point(lane_marker_path.path_point_size() - 1).s());

  const double ds = 1.0;
  int navigation_index = 0;
  int lane_marker_index = 0;
  for (double s = 0.0; s < len; s += ds) {
    auto p1 = GetPathPointByS(navigation_path, navigation_index, s,
                              &navigation_index);
    auto p2 = GetPathPointByS(lane_marker_path, lane_marker_index, s,
                              &lane_marker_index);
    auto *p = path->add_path_point();
    const double kWeight = 0.9;
    *p = common::util::GetWeightedAverageOfTwoPathPoints(p1, p2, kWeight,
                                                         1 - kWeight);
  }
}

common::PathPoint NavigationLane::GetPathPointByS(const common::Path &path,
                                                  const int start_index,
                                                  const double s,
                                                  int *matched_index) {
  CHECK_NOTNULL(matched_index);

  constexpr double kEpsilon = 1e-9;
  if (std::fabs(path.path_point(start_index).s() - s) < kEpsilon) {
    *matched_index = start_index;
    return path.path_point(start_index);
  }
  int i = start_index;
  while (i + 1 < path.path_point_size() && path.path_point(i + 1).s() < s) {
    ++i;
  }
  *matched_index = i;

  // x, y, z, theta, kappa, s, dkappa, ddkappa
  const double r = (s - path.path_point(i).s()) /
                   (path.path_point(i + 1).s() - path.path_point(i).s());
  auto p = common::util::GetWeightedAverageOfTwoPathPoints(
      path.path_point(i), path.path_point(i + 1), 1 - r, r);
  return p;
}

void NavigationLane::ConvertNavigationLineToPath(common::Path *path) {
  CHECK_NOTNULL(path);
  if (navigation_info_.navigation_path_size() == 0 ||
      !navigation_info_.navigation_path(0).has_path() ||
      navigation_info_.navigation_path(0).path().path_point_size() == 0) {
    // path is empty
    return;
  }
  path->set_name("Path from navigation.");
  if (!UpdateProjectionIndex()) {
    return;
  }

  // TODO(All): support multiple navigation path
  // currently, only 1 navigation path is supported
  const auto &navigation_path = navigation_info_.navigation_path(0).path();
  int curr_project_index = last_project_index_;

  double dist =
      navigation_path.path_point(navigation_path.path_point_size() - 1).s() -
      navigation_path.path_point(curr_project_index).s();
  if (dist < 20) {
    return;
  }

  // offset between the current vehicle state and navigation line
  const double dx = -original_pose_.position().x();
  const double dy = -original_pose_.position().y();
  const double ref_s = navigation_path.path_point(curr_project_index).s();
  for (int i = std::max(0, curr_project_index - 3);
       i < navigation_path.path_point_size(); ++i) {
    auto *point = path->add_path_point();
    point->CopyFrom(navigation_path.path_point(i));

    // shift to (0, 0)
    double enu_x = point->x() + dx;
    double enu_y = point->y() + dy;

    double flu_x = 0.0;
    double flu_y = 0.0;
    common::math::RotateAxis(original_pose_.heading(), enu_x, enu_y, &flu_x,
                             &flu_y);

    point->set_x(flu_x);
    point->set_y(flu_y);
    point->set_theta(common::math::NormalizeAngle(
        common::math::NormalizeAngle(point->theta())
            - original_pose_.heading()));
    const double accumulated_s = navigation_path.path_point(i).s() - ref_s;
    point->set_s(accumulated_s);

    if (accumulated_s > FLAGS_max_len_from_navigation_line) {
      break;
    }
  }

  const perception::LaneMarkers &lane_marker =
      perception_obstacles_.lane_marker();
  const auto &left_lane = lane_marker.left_lane_marker();
  const auto &right_lane = lane_marker.right_lane_marker();
  left_width_ = (std::fabs(left_lane.c0_position()) +
                 std::fabs(right_lane.c0_position())) /
                2.0;
  right_width_ = left_width_;
}

// project adc_state_ onto path
bool NavigationLane::UpdateProjectionIndex() {
  // TODO(All): support multiple navigation path
  // currently, only 1 navigation path is supported
  const auto &path = navigation_info_.navigation_path(0).path();
  int index = 0;
  double min_d = std::numeric_limits<double>::max();
  for (int i = last_project_index_; i + 1 < path.path_point_size(); ++i) {
    const double d = DistanceXY(original_pose_.position(), path.path_point(i));
    if (d < min_d) {
      min_d = d;
      index = i;
    }
    const double kMaxDistance = 50.0;
    if (last_project_index_ != 0 && d > kMaxDistance) {
      break;
    }
  }
  if (min_d > FLAGS_max_distance_to_navigation_line) {
    return false;
  }
  last_project_index_ = index;
  return true;
}

void NavigationLane::ConvertLaneMarkerToPath(
    const perception::LaneMarkers &lane_marker, common::Path *path) {
  CHECK_NOTNULL(path);

  path->set_name("Path from lane markers.");
  const auto &left_lane = lane_marker.left_lane_marker();
  const auto &right_lane = lane_marker.right_lane_marker();

  double path_c0 = (left_lane.c0_position() + right_lane.c0_position()) / 2.0;

  double left_quality = left_lane.quality() + 0.001;
  double right_quality = right_lane.quality() + 0.001;

  double quality_divider = left_quality + right_quality;

  double path_c1 = (left_lane.c1_heading_angle() * left_quality +
                    right_lane.c1_heading_angle() * right_quality) /
                   quality_divider;

  double path_c2 = (left_lane.c2_curvature() * left_quality +
                    right_lane.c2_curvature() * right_quality) /
                   quality_divider;

  double path_c3 =
      (left_lane.c3_curvature_derivative() * left_quality +
       right_lane.c3_curvature_derivative() * right_quality) /
      quality_divider;

  const double current_speed =
      VehicleStateProvider::instance()->vehicle_state().linear_velocity();
  double path_range = current_speed * FLAGS_ratio_navigation_lane_len_to_speed;
  if (path_range <= FLAGS_min_len_for_navigation_lane) {
    path_range = FLAGS_min_len_for_navigation_lane;
  } else {
    path_range = FLAGS_max_len_for_navigation_lane;
  }

  const double unit_z = 1.0;
  const double start_s = -2.0;
  double accumulated_s = start_s;
  for (double z = start_s; z <= path_range; z += unit_z) {
    double x1 = z;
    double y1 = 0;
    if (left_lane.view_range() > FLAGS_min_view_range_to_use_lane_marker ||
        right_lane.view_range() > FLAGS_min_view_range_to_use_lane_marker) {
      y1 = EvaluateCubicPolynomial(path_c0, path_c1, path_c2, path_c3, z);
    }
    auto *point = path->add_path_point();
    point->set_x(x1);
    point->set_y(y1);

    if (path->path_point_size() > 1) {
      auto &pre_point = path->path_point(path->path_point_size() - 2);
      accumulated_s += std::hypot(x1 - pre_point.x(), y1 - pre_point.y());
    }
    point->set_s(accumulated_s);
  }

  left_width_ = (std::fabs(left_lane.c0_position()) +
                 std::fabs(right_lane.c0_position())) /
                2.0;
  right_width_ = left_width_;
}

bool NavigationLane::CreateMap(const MapGenerationParam &map_config,
                               MapMsg *map_msg) const {
  auto *navigation_info = map_msg->mutable_navigation_path();
  auto *hdmap = map_msg->mutable_hdmap();
  auto *lane_marker = map_msg->mutable_lane_marker();

  lane_marker->CopyFrom(perception_obstacles_.lane_marker());

  const auto &path = navigation_path_.path();
  if (path.path_point_size() < 2) {
    AERROR << "The path length is invalid";
    return false;
  }
  auto *lane = hdmap->add_lane();
  lane->mutable_id()->set_id(std::to_string(navigation_path_.path_priority()) +
                             "_" + path.name());
  (*navigation_info)[lane->id().id()] = navigation_path_;
  // lane types
  lane->set_type(Lane::CITY_DRIVING);
  lane->set_turn(Lane::NO_TURN);

  // speed limit
  lane->set_speed_limit(map_config.default_speed_limit());

  // center line
  auto *curve_segment = lane->mutable_central_curve()->add_segment();
  curve_segment->set_heading(path.path_point(0).theta());
  auto *line_segment = curve_segment->mutable_line_segment();
  // left boundary
  auto *left_boundary = lane->mutable_left_boundary();
  auto *left_boundary_type = left_boundary->add_boundary_type();
  left_boundary->set_virtual_(false);
  left_boundary_type->set_s(0.0);
  left_boundary_type->add_types(
      perception_obstacles_.lane_marker().left_lane_marker().lane_type());
  auto *left_segment =
      left_boundary->mutable_curve()->add_segment()->mutable_line_segment();
  // right boundary
  auto *right_boundary = lane->mutable_right_boundary();
  auto *right_boundary_type = right_boundary->add_boundary_type();
  right_boundary->set_virtual_(false);
  right_boundary_type->set_s(0.0);
  right_boundary_type->add_types(
      perception_obstacles_.lane_marker().right_lane_marker().lane_type());
  auto *right_segment =
      right_boundary->mutable_curve()->add_segment()->mutable_line_segment();
  const double lane_left_width =
      left_width_ > 0 ? left_width_ : map_config.default_left_width();
  const double lane_right_width =
      right_width_ > 0 ? right_width_ : map_config.default_right_width();
  for (const auto &path_point : path.path_point()) {
    auto *point = line_segment->add_point();
    point->set_x(path_point.x());
    point->set_y(path_point.y());
    point->set_z(path_point.z());
    auto *left_sample = lane->add_left_sample();
    left_sample->set_s(path_point.s());
    left_sample->set_width(lane_left_width);
    left_segment->add_point()->CopyFrom(
        *point +
        lane_left_width * Vec2d::CreateUnitVec2d(path_point.theta() + M_PI_2));
    auto *right_sample = lane->add_right_sample();
    right_sample->set_s(path_point.s());
    right_sample->set_width(lane_right_width);
    right_segment->add_point()->CopyFrom(
        *point +
        lane_right_width * Vec2d::CreateUnitVec2d(path_point.theta() - M_PI_2));
  }

  return true;
}

}  // namespace relative_map
}  // namespace apollo
<commit_msg>CodeBot: REVISE navi: updated lane marker based ref line generation.<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * 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 "modules/map/relative_map/navigation_lane.h"

#include <algorithm>
#include <limits>

#include "modules/map/proto/map_lane.pb.h"

#include "modules/common/log.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/math/vec2d.h"
#include "modules/common/util/util.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/map/relative_map/common/relative_map_gflags.h"

namespace apollo {
namespace relative_map {

using apollo::common::VehicleStateProvider;
using apollo::common::math::Vec2d;
using apollo::common::util::DistanceXY;
using apollo::hdmap::Lane;
using apollo::common::util::operator+;
using apollo::perception::PerceptionObstacles;

NavigationLane::NavigationLane(const NavigationLaneConfig &config)
    : config_(config) {}

void NavigationLane::SetConfig(const NavigationLaneConfig &config) {
  config_ = config;
}

bool NavigationLane::GeneratePath() {
  // original_pose is in world coordination: ENU
  original_pose_ = VehicleStateProvider::instance()->original_pose();

  navigation_path_.Clear();
  auto *path = navigation_path_.mutable_path();
  const auto &lane_marker = perception_obstacles_.lane_marker();

  // priority: merge > navigation line > perception lane marker
  if (FLAGS_enable_navigation_line &&
      navigation_info_.navigation_path_size() > 0) {
    ConvertNavigationLineToPath(path);
    if (path->path_point().size() <= 0) {
      ConvertLaneMarkerToPath(lane_marker, path);
    }
  } else {
    ConvertLaneMarkerToPath(lane_marker, path);
  }
  return true;
}

double NavigationLane::EvaluateCubicPolynomial(const double c0, const double c1,
                                               const double c2, const double c3,
                                               const double z) const {
  return ((c3 * z + c2) * z + c1) * z + c0;
}

void NavigationLane::MergeNavigationLineAndLaneMarker(
    const perception::LaneMarkers &lane_marker, common::Path *path) {
  CHECK_NOTNULL(path);

  common::Path navigation_path;
  ConvertNavigationLineToPath(&navigation_path);

  common::Path lane_marker_path;
  ConvertLaneMarkerToPath(perception_obstacles_.lane_marker(),
                          &lane_marker_path);

  const double len = std::fmin(
      navigation_path.path_point(navigation_path.path_point_size() - 1).s(),
      lane_marker_path.path_point(lane_marker_path.path_point_size() - 1).s());

  const double ds = 1.0;
  int navigation_index = 0;
  int lane_marker_index = 0;
  for (double s = 0.0; s < len; s += ds) {
    auto p1 = GetPathPointByS(navigation_path, navigation_index, s,
                              &navigation_index);
    auto p2 = GetPathPointByS(lane_marker_path, lane_marker_index, s,
                              &lane_marker_index);
    auto *p = path->add_path_point();
    const double kWeight = 0.9;
    *p = common::util::GetWeightedAverageOfTwoPathPoints(p1, p2, kWeight,
                                                         1 - kWeight);
  }
}

common::PathPoint NavigationLane::GetPathPointByS(const common::Path &path,
                                                  const int start_index,
                                                  const double s,
                                                  int *matched_index) {
  CHECK_NOTNULL(matched_index);

  constexpr double kEpsilon = 1e-9;
  if (std::fabs(path.path_point(start_index).s() - s) < kEpsilon) {
    *matched_index = start_index;
    return path.path_point(start_index);
  }
  int i = start_index;
  while (i + 1 < path.path_point_size() && path.path_point(i + 1).s() < s) {
    ++i;
  }
  *matched_index = i;

  // x, y, z, theta, kappa, s, dkappa, ddkappa
  const double r = (s - path.path_point(i).s()) /
                   (path.path_point(i + 1).s() - path.path_point(i).s());
  auto p = common::util::GetWeightedAverageOfTwoPathPoints(
      path.path_point(i), path.path_point(i + 1), 1 - r, r);
  return p;
}

void NavigationLane::ConvertNavigationLineToPath(common::Path *path) {
  CHECK_NOTNULL(path);
  if (navigation_info_.navigation_path_size() == 0 ||
      !navigation_info_.navigation_path(0).has_path() ||
      navigation_info_.navigation_path(0).path().path_point_size() == 0) {
    // path is empty
    return;
  }
  path->set_name("Path from navigation.");
  if (!UpdateProjectionIndex()) {
    return;
  }

  // TODO(All): support multiple navigation path
  // currently, only 1 navigation path is supported
  const auto &navigation_path = navigation_info_.navigation_path(0).path();
  int curr_project_index = last_project_index_;

  double dist =
      navigation_path.path_point(navigation_path.path_point_size() - 1).s() -
      navigation_path.path_point(curr_project_index).s();
  if (dist < 20) {
    return;
  }

  // offset between the current vehicle state and navigation line
  const double dx = -original_pose_.position().x();
  const double dy = -original_pose_.position().y();
  const double ref_s = navigation_path.path_point(curr_project_index).s();
  for (int i = std::max(0, curr_project_index - 3);
       i < navigation_path.path_point_size(); ++i) {
    auto *point = path->add_path_point();
    point->CopyFrom(navigation_path.path_point(i));

    // shift to (0, 0)
    double enu_x = point->x() + dx;
    double enu_y = point->y() + dy;

    double flu_x = 0.0;
    double flu_y = 0.0;
    common::math::RotateAxis(original_pose_.heading(), enu_x, enu_y, &flu_x,
                             &flu_y);

    point->set_x(flu_x);
    point->set_y(flu_y);
    point->set_theta(common::math::NormalizeAngle(
        common::math::NormalizeAngle(point->theta()) -
        original_pose_.heading()));
    const double accumulated_s = navigation_path.path_point(i).s() - ref_s;
    point->set_s(accumulated_s);

    if (accumulated_s > FLAGS_max_len_from_navigation_line) {
      break;
    }
  }

  const perception::LaneMarkers &lane_marker =
      perception_obstacles_.lane_marker();
  const auto &left_lane = lane_marker.left_lane_marker();
  const auto &right_lane = lane_marker.right_lane_marker();
  left_width_ = (std::fabs(left_lane.c0_position()) +
                 std::fabs(right_lane.c0_position())) /
                2.0;
  right_width_ = left_width_;
}

// project adc_state_ onto path
bool NavigationLane::UpdateProjectionIndex() {
  // TODO(All): support multiple navigation path
  // currently, only 1 navigation path is supported
  const auto &path = navigation_info_.navigation_path(0).path();
  int index = 0;
  double min_d = std::numeric_limits<double>::max();
  for (int i = last_project_index_; i + 1 < path.path_point_size(); ++i) {
    const double d = DistanceXY(original_pose_.position(), path.path_point(i));
    if (d < min_d) {
      min_d = d;
      index = i;
    }
    const double kMaxDistance = 50.0;
    if (last_project_index_ != 0 && d > kMaxDistance) {
      break;
    }
  }
  if (min_d > FLAGS_max_distance_to_navigation_line) {
    return false;
  }
  last_project_index_ = index;
  return true;
}

void NavigationLane::ConvertLaneMarkerToPath(
    const perception::LaneMarkers &lane_marker, common::Path *path) {
  CHECK_NOTNULL(path);

  path->set_name("Path from lane markers.");
  const auto &left_lane = lane_marker.left_lane_marker();
  const auto &right_lane = lane_marker.right_lane_marker();

  double path_c0 = (left_lane.c0_position() + right_lane.c0_position()) / 2.0;

  double left_quality = left_lane.quality() + 0.001;
  double right_quality = right_lane.quality() + 0.001;

  double quality_divider = left_quality + right_quality;

  double path_c1 = (left_lane.c1_heading_angle() * left_quality +
                    right_lane.c1_heading_angle() * right_quality) /
                   quality_divider;

  double path_c2 = (left_lane.c2_curvature() * left_quality +
                    right_lane.c2_curvature() * right_quality) /
                   quality_divider;

  double path_c3 = (left_lane.c3_curvature_derivative() * left_quality +
                    right_lane.c3_curvature_derivative() * right_quality) /
                   quality_divider;

  const double current_speed =
      VehicleStateProvider::instance()->vehicle_state().linear_velocity();
  double path_range = current_speed * FLAGS_ratio_navigation_lane_len_to_speed;
  if (path_range <= FLAGS_min_len_for_navigation_lane) {
    path_range = FLAGS_min_len_for_navigation_lane;
  } else {
    path_range = FLAGS_max_len_for_navigation_lane;
  }

  const double unit_z = 1.0;
  const double start_s = -2.0;
  double accumulated_s = start_s;
  for (double z = start_s; z <= path_range; z += unit_z) {
    double x1 = z;
    double y1 = 0;
    if (left_lane.view_range() > FLAGS_min_view_range_to_use_lane_marker ||
        right_lane.view_range() > FLAGS_min_view_range_to_use_lane_marker) {
      y1 = EvaluateCubicPolynomial(path_c0, path_c1, path_c2, path_c3, z);
    }
    auto *point = path->add_path_point();
    point->set_x(x1);
    point->set_y(y1);

    if (path->path_point_size() > 1) {
      auto &pre_point = path->path_point(path->path_point_size() - 2);
      accumulated_s += std::hypot(x1 - pre_point.x(), y1 - pre_point.y());
    }
    point->set_s(accumulated_s);
  }

  left_width_ = (std::fabs(left_lane.c0_position()) +
                 std::fabs(right_lane.c0_position())) /
                2.0;
  right_width_ = left_width_;
}

bool NavigationLane::CreateMap(const MapGenerationParam &map_config,
                               MapMsg *map_msg) const {
  auto *navigation_info = map_msg->mutable_navigation_path();
  auto *hdmap = map_msg->mutable_hdmap();
  auto *lane_marker = map_msg->mutable_lane_marker();

  lane_marker->CopyFrom(perception_obstacles_.lane_marker());

  const auto &path = navigation_path_.path();
  if (path.path_point_size() < 2) {
    AERROR << "The path length is invalid";
    return false;
  }
  auto *lane = hdmap->add_lane();
  lane->mutable_id()->set_id(std::to_string(navigation_path_.path_priority()) +
                             "_" + path.name());
  (*navigation_info)[lane->id().id()] = navigation_path_;
  // lane types
  lane->set_type(Lane::CITY_DRIVING);
  lane->set_turn(Lane::NO_TURN);

  // speed limit
  lane->set_speed_limit(map_config.default_speed_limit());

  // center line
  auto *curve_segment = lane->mutable_central_curve()->add_segment();
  curve_segment->set_heading(path.path_point(0).theta());
  auto *line_segment = curve_segment->mutable_line_segment();
  // left boundary
  auto *left_boundary = lane->mutable_left_boundary();
  auto *left_boundary_type = left_boundary->add_boundary_type();
  left_boundary->set_virtual_(false);
  left_boundary_type->set_s(0.0);
  left_boundary_type->add_types(
      perception_obstacles_.lane_marker().left_lane_marker().lane_type());
  auto *left_segment =
      left_boundary->mutable_curve()->add_segment()->mutable_line_segment();
  // right boundary
  auto *right_boundary = lane->mutable_right_boundary();
  auto *right_boundary_type = right_boundary->add_boundary_type();
  right_boundary->set_virtual_(false);
  right_boundary_type->set_s(0.0);
  right_boundary_type->add_types(
      perception_obstacles_.lane_marker().right_lane_marker().lane_type());
  auto *right_segment =
      right_boundary->mutable_curve()->add_segment()->mutable_line_segment();
  const double lane_left_width =
      left_width_ > 0 ? left_width_ : map_config.default_left_width();
  const double lane_right_width =
      right_width_ > 0 ? right_width_ : map_config.default_right_width();
  for (const auto &path_point : path.path_point()) {
    auto *point = line_segment->add_point();
    point->set_x(path_point.x());
    point->set_y(path_point.y());
    point->set_z(path_point.z());
    auto *left_sample = lane->add_left_sample();
    left_sample->set_s(path_point.s());
    left_sample->set_width(lane_left_width);
    left_segment->add_point()->CopyFrom(
        *point +
        lane_left_width * Vec2d::CreateUnitVec2d(path_point.theta() + M_PI_2));
    auto *right_sample = lane->add_right_sample();
    right_sample->set_s(path_point.s());
    right_sample->set_width(lane_right_width);
    right_segment->add_point()->CopyFrom(
        *point +
        lane_right_width * Vec2d::CreateUnitVec2d(path_point.theta() - M_PI_2));
  }

  return true;
}

}  // namespace relative_map
}  // namespace apollo
<|endoftext|>


<commit_before>// ROOT6 modifications
#ifdef __CLING__
#include <AliAnalysisManager.h>
#include <AliAODInputHandler.h>
#include <AliDielectronVarCuts.h>

// Tell ROOT where to find AliPhysics headers
R__ADD_INCLUDE_PATH($ALICE_PHYSICS)
#endif

AliAnalysisTask *AddTask_jjung_lowmass(Bool_t getFromAlien=kFALSE,
                                      TString cFileName = "Config_jjung_lowmass.C",
                                      TString outputFileName="LMEE.root",
                                      Int_t wagonnr=0
                                      )
{
  std::cout << "AddTask_jjung_lowmass" << std::endl;
  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_jjung_lowmass", "No analysis manager found.");
    return 0;
  }

  //Base Directory for GRID / LEGO Train
  TString configBasePath= "/home/jerome/analysis/localLegotrain/005_tests_PbPbAOD/";
  if (!gSystem->AccessPathName(cFileName))
  {
    printf("file already present\n");
    configBasePath=Form("%s/",gSystem->pwd());
  }
  else if(getFromAlien && (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/j/jjung/%s file:./",cFileName.Data()))) ){
    std::cout << "ALIEN???!  " << std::endl;
    configBasePath=Form("%s/",gSystem->pwd());
  }

  TString configFilePath(configBasePath+cFileName);

  std::cout << "Configpath:  " << configFilePath << std::endl;

  //Do we have an MC handler?
  Bool_t hasMC = (AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler()!=0x0);

  if (!gROOT->GetListOfGlobalFunctions()->FindObject(cFileName.Data()))
  gROOT->LoadMacro(configFilePath.Data());  //old root5

  //create task and add it to the manager (MB)
  AliAnalysisTaskMultiDielectron *task = new AliAnalysisTaskMultiDielectron(Form("MultiDielectron_%d", wagonnr));
  if (!hasMC) task->UsePhysicsSelection();
  task->SetTriggerMask(UInt_t(AliVEvent::kCentral));
  task->SelectCollisionCandidates(UInt_t(AliVEvent::kCentral));

  std::cout << "Task created" << std::endl;

  task->SetRandomizeDaughters(kTRUE); //default kFALSE
  std::cout << "Adding event cuts" << std::endl;

  mgr->AddTask(task);
  std::cout << "Task Added" << std::endl;

  const Int_t nDie = (Int_t)gROOT->ProcessLine("GetN()");
  //add dielectron analysis with different cuts to the task
  #if defined(__CLING__)
    Int_t dot = cFileName.First('.');
    Int_t len = cFileName.Length();
    if (len > 0)
      cFileName.Remove(dot,len-dot);
    //TMacro conf_die(gSystem->ExpandPathName(configFilePath.Data())); //ROOT6
    for (Int_t i=0; i<nDie; ++i){ //nDie as argument of add task
      //AliDielectron *diel_low = reinterpret_cast<AliDielectron *>(conf_die.Exec(Form("%i",i)));
      AliDielectron *diel_low = reinterpret_cast<AliDielectron*>(gROOT->ProcessLine(Form("%s(%i,%i,%i)",cFileName.Data(),i,kFALSE,wagonnr)));
      if(!diel_low)continue;
      task->AddDielectron(diel_low);
    }
  #elif defined(__CINT__)
    gROOT->LoadMacro(configFilePath.Data()); //ROOT5 syntax
    for (Int_t i=0; i<nDie; ++i){ //nDie defined in config file
      AliDielectron *diel_low = Config_jjung_lowmass(i); // also ROOT5
      if(!diel_low)continue;
      task->AddDielectron(diel_low);
    }
  #endif

  std::cout << "Cuts Settings Added" << std::endl;

  //create output container
  AliAnalysisDataContainer *coutput1 = 0x0;
  AliAnalysisDataContainer *cOutputHist1 = 0x0;
  AliAnalysisDataContainer *cOutputHist2 = 0x0;
  AliAnalysisDataContainer *cOutputHist3 = 0x0;

  if(wagonnr == 0){
    coutput1 = mgr->CreateContainer("tree_lowmass", TTree::Class(),
                         AliAnalysisManager::kExchangeContainer, outputFileName.Data());

    cOutputHist1 = mgr->CreateContainer("Histos_diel_lowmass", TList::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

    cOutputHist2 = mgr->CreateContainer("CF_diel_lowmass", TList::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

    cOutputHist3 = mgr->CreateContainer("jjung_lowmass_EventStat", TH1D::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());
  }

  else{
    coutput1 = mgr->CreateContainer(Form("tree_lowmass_%d", wagonnr), TTree::Class(),
                         AliAnalysisManager::kExchangeContainer, outputFileName.Data());

    cOutputHist1 = mgr->CreateContainer(Form("Histos_diel_lowmass_%d", wagonnr), TList::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

    cOutputHist2 = mgr->CreateContainer(Form("CF_diel_lowmass_%d", wagonnr), TList::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

    cOutputHist3 = mgr->CreateContainer(Form("jjung_lowmass_EventStat_%d", wagonnr), TH1D::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

  }

  mgr->ConnectInput(task,  0, mgr->GetCommonInputContainer());
  mgr->ConnectOutput(task, 0, coutput1 );
  mgr->ConnectOutput(task, 1, cOutputHist1);
  mgr->ConnectOutput(task, 2, cOutputHist2);
  mgr->ConnectOutput(task, 3, cOutputHist3);

  return task;

}

<commit_msg>PWGDQ:LMee: Update personal AddTask<commit_after>// ROOT6 modifications
#ifdef __CLING__
#include <AliAnalysisManager.h>
#include <AliAODInputHandler.h>
#include <AliDielectronVarCuts.h>

// Tell ROOT where to find AliPhysics headers
R__ADD_INCLUDE_PATH($ALICE_PHYSICS)
#endif

AliAnalysisTask *AddTask_jjung_lowmass(Bool_t getFromAlien=kFALSE,
                                      TString cFileName = "Config_jjung_lowmass.C",
                                      TString outputFileName="LMEE.root",
                                      Int_t wagonnr=0,
                                      UInt_t triggerMask = AliVEvent::kCentral
                                      )
{
  std::cout << "AddTask_jjung_lowmass" << std::endl;
  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_jjung_lowmass", "No analysis manager found.");
    return 0;
  }

  //Base Directory for GRID / LEGO Train
  TString configBasePath= "/home/jerome/analysis/localLegotrain/005_tests_PbPbAOD/";
  if (!gSystem->AccessPathName(cFileName))
  {
    printf("file already present\n");
    configBasePath=Form("%s/",gSystem->pwd());
  }
  else if(getFromAlien && (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/j/jjung/%s file:./",cFileName.Data()))) ){
    std::cout << "ALIEN???!  " << std::endl;
    configBasePath=Form("%s/",gSystem->pwd());
  }

  TString configFilePath(configBasePath+cFileName);

  std::cout << "Configpath:  " << configFilePath << std::endl;

  //Do we have an MC handler?
  Bool_t hasMC = (AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler()!=0x0);

  if (!gROOT->GetListOfGlobalFunctions()->FindObject(cFileName.Data()))
  gROOT->LoadMacro(configFilePath.Data());  //old root5

  //create task and add it to the manager (MB)
  AliAnalysisTaskMultiDielectron *task = new AliAnalysisTaskMultiDielectron(Form("MultiDielectron_%d", wagonnr));
  if (!hasMC) task->UsePhysicsSelection();
  task->SetTriggerMask(UInt_t(triggerMask));
  task->SelectCollisionCandidates(UInt_t(triggerMask));

  std::cout << "Task created" << std::endl;

  task->SetRandomizeDaughters(kTRUE); //default kFALSE
  std::cout << "Adding event cuts" << std::endl;

  mgr->AddTask(task);
  std::cout << "Task Added" << std::endl;

  const Int_t nDie = (Int_t)gROOT->ProcessLine("GetN()");
  //add dielectron analysis with different cuts to the task
  #if defined(__CLING__)
    Int_t dot = cFileName.First('.');
    Int_t len = cFileName.Length();
    if (len > 0)
      cFileName.Remove(dot,len-dot);
    //TMacro conf_die(gSystem->ExpandPathName(configFilePath.Data())); //ROOT6
    for (Int_t i=0; i<nDie; ++i){ //nDie as argument of add task
      //AliDielectron *diel_low = reinterpret_cast<AliDielectron *>(conf_die.Exec(Form("%i",i)));
      AliDielectron *diel_low = reinterpret_cast<AliDielectron*>(gROOT->ProcessLine(Form("%s(%i,%i,%i)",cFileName.Data(),i,kFALSE,wagonnr)));
      if(!diel_low)continue;
      task->AddDielectron(diel_low);
    }
  #elif defined(__CINT__)
    gROOT->LoadMacro(configFilePath.Data()); //ROOT5 syntax
    for (Int_t i=0; i<nDie; ++i){ //nDie defined in config file
      AliDielectron *diel_low = Config_jjung_lowmass(i); // also ROOT5
      if(!diel_low)continue;
      task->AddDielectron(diel_low);
    }
  #endif

  std::cout << "Cuts Settings Added" << std::endl;

  //create output container
  AliAnalysisDataContainer *coutput1 = 0x0;
  AliAnalysisDataContainer *cOutputHist1 = 0x0;
  AliAnalysisDataContainer *cOutputHist2 = 0x0;
  AliAnalysisDataContainer *cOutputHist3 = 0x0;

  if(wagonnr == 0){
    coutput1 = mgr->CreateContainer("tree_lowmass", TTree::Class(),
                         AliAnalysisManager::kExchangeContainer, outputFileName.Data());

    cOutputHist1 = mgr->CreateContainer("Histos_diel_lowmass", TList::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

    cOutputHist2 = mgr->CreateContainer("CF_diel_lowmass", TList::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

    cOutputHist3 = mgr->CreateContainer("jjung_lowmass_EventStat", TH1D::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());
  }

  else{
    coutput1 = mgr->CreateContainer(Form("tree_lowmass_%d", wagonnr), TTree::Class(),
                         AliAnalysisManager::kExchangeContainer, outputFileName.Data());

    cOutputHist1 = mgr->CreateContainer(Form("Histos_diel_lowmass_%d", wagonnr), TList::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

    cOutputHist2 = mgr->CreateContainer(Form("CF_diel_lowmass_%d", wagonnr), TList::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

    cOutputHist3 = mgr->CreateContainer(Form("jjung_lowmass_EventStat_%d", wagonnr), TH1D::Class(),
                         AliAnalysisManager::kOutputContainer, outputFileName.Data());

  }

  mgr->ConnectInput(task,  0, mgr->GetCommonInputContainer());
  mgr->ConnectOutput(task, 0, coutput1 );
  mgr->ConnectOutput(task, 1, cOutputHist1);
  mgr->ConnectOutput(task, 2, cOutputHist2);
  mgr->ConnectOutput(task, 3, cOutputHist3);

  return task;

}

<|endoftext|>


<commit_before>// Copyright (c) 2014 Bauhaus-Universitaet Weimar
// This Software is distributed under the Modified BSD License, see license.txt.
//
// Virtual Reality and Visualization Research Group
// Faculty of Media, Bauhaus-Universitaet Weimar
// http://www.uni-weimar.de/medien/vr

#include <lamure/pre/io/format_xyz.h>

#include <stdexcept>
#include <fstream>
#include <sstream>
#include <iostream>

namespace lamure {
namespace pre {

void format_xyz::
read(const std::string& filename, surfel_callback_funtion callback)
{
    std::ifstream xyz_file_stream(filename);

    if (!xyz_file_stream.is_open())
        throw std::runtime_error("Unable to open file: " +
                                 filename);

    std::string line;

    real pos[3];
    unsigned int color[3];

    xyz_file_stream.seekg (0, std::ios::end);
    std::streampos end_pos = xyz_file_stream.tellg();
    xyz_file_stream.seekg (0, std::ios::beg);
    uint8_t percent_processed = 0;

    while (getline(xyz_file_stream, line)) {

        uint8_t new_percent_processed = (xyz_file_stream.tellg()/float(end_pos)) * 100;
        if (percent_processed + 1 == new_percent_processed) {
            percent_processed = new_percent_processed;
            std::cout << "\r" << (int)percent_processed << "% processed" << std::flush;
        }

        std::stringstream sstream;

        sstream << line;

        sstream >> pos[0];
        sstream >> pos[1];
        sstream >> pos[2];
        sstream >> color[0];
        sstream >> color[1];
        sstream >> color[2];

        callback(surfel(vec3r(pos[0], pos[1], pos[2]),
                        vec3b(color[0], color[1], color[2])));
    }

    xyz_file_stream.close();
}

void format_xyz::
write(const std::string& filename, buffer_callback_function callback)
{
    std::ofstream xyz_file_stream(filename);

    if (!xyz_file_stream.is_open())
        throw std::runtime_error("Unable to open file: " +
                                 filename);

    surfel_vector buffer;
    size_t count = 0;

    while (true) {
        bool ret = callback(buffer);
        if (!ret)
            break;

        for (const auto s: buffer) {
            xyz_file_stream << s.pos().x << " " << s.pos().y << " " << s.pos().z << " "
                            << int(s.color().r) << " " << int(s.color().g) << " " << int(s.color().b) << "\r\n";
        }

        count += buffer.size();
    }
    xyz_file_stream.close();
    LOGGER_TRACE("Output surfels: " << count);
}

} // namespace pre
} // namespace lamure
<commit_msg>increase default precision for preprocessing tools<commit_after>// Copyright (c) 2014 Bauhaus-Universitaet Weimar
// This Software is distributed under the Modified BSD License, see license.txt.
//
// Virtual Reality and Visualization Research Group
// Faculty of Media, Bauhaus-Universitaet Weimar
// http://www.uni-weimar.de/medien/vr

#include <lamure/pre/io/format_xyz.h>

#include <stdexcept>
#include <fstream>
#include <sstream>
#include <iostream>

#define DEFAULT_PRECISION 15

namespace lamure {
namespace pre {

void format_xyz::
read(const std::string& filename, surfel_callback_funtion callback)
{
    std::ifstream xyz_file_stream(filename);

    if (!xyz_file_stream.is_open())
        throw std::runtime_error("Unable to open file: " +
                                 filename);

    std::string line;

    real pos[3];
    unsigned int color[3];

    xyz_file_stream.seekg (0, std::ios::end);
    std::streampos end_pos = xyz_file_stream.tellg();
    xyz_file_stream.seekg (0, std::ios::beg);
    uint8_t percent_processed = 0;

    while (getline(xyz_file_stream, line)) {

        uint8_t new_percent_processed = (xyz_file_stream.tellg()/float(end_pos)) * 100;
        if (percent_processed + 1 == new_percent_processed) {
            percent_processed = new_percent_processed;
            std::cout << "\r" << (int)percent_processed << "% processed" << std::flush;
        }

        std::stringstream sstream;

        sstream << line;

        sstream >> pos[0];
        sstream >> pos[1];
        sstream >> pos[2];
        sstream >> color[0];
        sstream >> color[1];
        sstream >> color[2];

        callback(surfel(vec3r(pos[0], pos[1], pos[2]),
                        vec3b(color[0], color[1], color[2])));
    }

    xyz_file_stream.close();
}

void format_xyz::
write(const std::string& filename, buffer_callback_function callback)
{
    std::ofstream xyz_file_stream(filename);

    if (!xyz_file_stream.is_open())
        throw std::runtime_error("Unable to open file: " +
                                 filename);

    surfel_vector buffer;
    size_t count = 0;

    while (true) {
        bool ret = callback(buffer);
        if (!ret)
            break;

        for (const auto s: buffer) {
            xyz_file_stream << std::setprecision(DEFAULT_PRECISION) << s.pos().x << " " << s.pos().y << " " << s.pos().z << " "
                            << int(s.color().r) << " " << int(s.color().g) << " " << int(s.color().b) << "\r\n";
        }

        count += buffer.size();
    }
    xyz_file_stream.close();
    LOGGER_TRACE("Output surfels: " << count);
}

} // namespace pre
} // namespace lamure
<|endoftext|>


<commit_before>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "EjectOSD.h"

#include <Dbt.h>

#include "../DriveInfo.h"
#include "../HotkeyInfo.h"
#include "../Monitor.h"
#include "../NotifyIcon.h"
#include "../Skin/OSDComponent.h"
#include "../Skin/Skin.h"
#include "../Skin/SkinManager.h"

EjectOSD::EjectOSD() :
OSD(L"3RVX-EjectDispatcher"),
_mWnd(L"3RVX-EjectOSD", L"3RVX-EjectOSD") {

    SkinManager *skin = SkinManager::Instance();
    _mWnd.BackgroundImage(skin->EjectOSD()->background);
    _mWnd.EnableGlass(skin->EjectOSD()->mask);
    _mWnd.Update();

    OSD::InitMeterWnd(_mWnd);

    if (_settings->EjectIconEnabled()) {
        _iconImage = skin->EjectIcon();
        if (_iconImage != nullptr) {
            _icon = new NotifyIcon(Window::Handle(), L"Eject", _iconImage);
        }
    }

    _menu = CreatePopupMenu();
    /* Menu accepts both left and right clicks on its items: */
    _menuFlags = TPM_RIGHTBUTTON;
    if (GetSystemMetrics(SM_MENUDROPALIGNMENT) != 0) {
        _menuFlags |= TPM_RIGHTALIGN;
    } else {
        _menuFlags |= TPM_LEFTALIGN;
    }

    UpdateDriveMenu();
}

void EjectOSD::UpdateDriveMenu() {
    /* Remove any drives in the menu */
    for (unsigned int i = 0; i < _menuItems.size(); ++i) {
        RemoveMenu(_menu, 0, MF_BYPOSITION);
    }
    _menuItems.clear();

    int menuItem = 0;

    DWORD drives = GetLogicalDrives();
    /* Get the most significant bit of the drive bitset */
    DWORD msb = (DWORD) log2(drives);
    for (DWORD i = 0; i < msb; ++i, drives >>= 1) {
        if (drives & 0x1) {
            wchar_t letter = (wchar_t) i + 65;
            wchar_t drivePath[] = L" :\\";
            DriveInfo di(letter);
            if (di.IsHotPluggable() || di.HasRemovableMedia()) {
                CLOG(L"Removable Drive: %c %s %s",
                    di.DriveLetter(),
                    di.ProductID().c_str(),
                    di.VendorID().c_str());

                InsertMenu(_menu, -1, MF_ENABLED, menuItem++, di.ProductID().c_str());
                _menuItems.push_back(di);
            }
        }
    }
}

void EjectOSD::EjectDrive(std::wstring driveLetter) {
    std::wstring name = DriveInfo::DriveFileName(driveLetter);
    CLOG(L"Ejecting %s", name.c_str());

    HANDLE dev = CreateFile(
        name.c_str(),
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        NULL,
        NULL);

    if (dev == INVALID_HANDLE_VALUE) {
        CLOG(L"Failed to get device handle");
        return;
    }

    DWORD bytesReturned = 0;

    DeviceIoControl(dev, FSCTL_LOCK_VOLUME,
        NULL, NULL, NULL, NULL, &bytesReturned, NULL);

    PREVENT_MEDIA_REMOVAL pmr = { 0 };
    pmr.PreventMediaRemoval = FALSE;
    DeviceIoControl(dev, IOCTL_STORAGE_MEDIA_REMOVAL,
        &pmr, sizeof(PREVENT_MEDIA_REMOVAL), NULL, 0, &bytesReturned, NULL);

    DeviceIoControl(dev, FSCTL_DISMOUNT_VOLUME,
        NULL, NULL, NULL, NULL, &bytesReturned, NULL);

    BOOL ejected = FALSE;
    ejected = DeviceIoControl(dev, IOCTL_STORAGE_EJECT_MEDIA,
        NULL, NULL, NULL, NULL, &bytesReturned, NULL);

    if (ejected != FALSE) {
        std::wstring rootPath = driveLetter + L":\\";
        if (GetDriveType(rootPath.c_str()) != DRIVE_CDROM) {
            int driveBit = (int) pow(2, (driveLetter.at(0) - 65));
            _ignoreDrives |= driveBit;
            CLOG(L"Added drive bit %d to ignore list", driveBit);
        }
        if (OSD::Enabled()) {
            HideOthers(Eject);
            _mWnd.Show();
        }
    }

    CloseHandle(dev);
}

void EjectOSD::Hide() {
    _mWnd.Hide(false);
}

void EjectOSD::ProcessHotkeys(HotkeyInfo &hki) {
    switch (hki.action) {
    case HotkeyInfo::EjectDrive:
        if (hki.args.size() > 0) {
            EjectDrive(hki.args[0]);
        }
        break;

    case HotkeyInfo::EjectLastDisk:
        if (_latestDrive != 0) {
            wchar_t letter = MaskToDriveLetter(_latestDrive);
            std::wstring lStr(1, letter);
            EjectDrive(lStr);
            _latestDrive = 0;
        }

        break;
    }
}

LRESULT
EjectOSD::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    if (message == WM_DEVICECHANGE && wParam == DBT_DEVICEREMOVECOMPLETE) {
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lParam;
        if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) {
            PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lpdb;

            DWORD driveMask = lpdbv->dbcv_unitmask;
            CLOG(L"Eject notification received for drive %c:",
                MaskToDriveLetter(driveMask));

            if (driveMask & _ignoreDrives) {
                CLOG(L"Drive already ejected by a hotkey; not displaying OSD.");
                _ignoreDrives ^= driveMask;
            } else if (OSD::Enabled()) {
                HideOthers(Eject);
                _mWnd.Show();
            }

            if (_latestDrive == driveMask) {
                _latestDrive = 0;
            }
        }
    }

    if (message == WM_DEVICECHANGE && wParam == DBT_DEVICEARRIVAL) {
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lParam;
        if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) {
            PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lpdb;

            if (lpdbv->dbcv_flags != DBTF_NET) {
                _latestDrive = lpdbv->dbcv_unitmask;

                CLOG(L"Media inserted in drive %c:",
                    MaskToDriveLetter(_latestDrive));
            }
        }
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}

DWORD EjectOSD::DriveLetterToMask(wchar_t letter) {
    if (letter < 65 || letter > 90) {
        return 0;
    }

    return (DWORD) pow(2, (letter - 65));
}

wchar_t EjectOSD::MaskToDriveLetter(DWORD mask) {
    return (wchar_t) (log2(mask) + 65);
}

void EjectOSD::OnDisplayChange() {
    InitMeterWnd(_mWnd);
}
<commit_msg>Menu formatting<commit_after>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "EjectOSD.h"

#include <Dbt.h>

#include "../DriveInfo.h"
#include "../HotkeyInfo.h"
#include "../Monitor.h"
#include "../NotifyIcon.h"
#include "../Skin/OSDComponent.h"
#include "../Skin/Skin.h"
#include "../Skin/SkinManager.h"

EjectOSD::EjectOSD() :
OSD(L"3RVX-EjectDispatcher"),
_mWnd(L"3RVX-EjectOSD", L"3RVX-EjectOSD") {

    SkinManager *skin = SkinManager::Instance();
    _mWnd.BackgroundImage(skin->EjectOSD()->background);
    _mWnd.EnableGlass(skin->EjectOSD()->mask);
    _mWnd.Update();

    OSD::InitMeterWnd(_mWnd);

    if (_settings->EjectIconEnabled()) {
        _iconImage = skin->EjectIcon();
        if (_iconImage != nullptr) {
            _icon = new NotifyIcon(Window::Handle(), L"Eject", _iconImage);
        }
    }

    _menu = CreatePopupMenu();
    /* Menu accepts both left and right clicks on its items: */
    _menuFlags = TPM_RIGHTBUTTON;
    if (GetSystemMetrics(SM_MENUDROPALIGNMENT) != 0) {
        _menuFlags |= TPM_RIGHTALIGN;
    } else {
        _menuFlags |= TPM_LEFTALIGN;
    }

    UpdateDriveMenu();
}

void EjectOSD::UpdateDriveMenu() {
    /* Remove any drives in the menu */
    for (unsigned int i = 0; i < _menuItems.size(); ++i) {
        RemoveMenu(_menu, 0, MF_BYPOSITION);
    }
    _menuItems.clear();

    int menuItem = 0;

    DWORD drives = GetLogicalDrives();
    /* Get the most significant bit of the drive bitset */
    DWORD msb = (DWORD) log2(drives);
    for (DWORD i = 0; i < msb; ++i, drives >>= 1) {
        if (drives & 0x1) {
            wchar_t letter = (wchar_t) i + 65;
            wchar_t drivePath[] = L" :\\";
            DriveInfo di(letter);
            if (di.IsHotPluggable() || di.HasRemovableMedia()) {
                CLOG(L"Removable Drive: %c %s %s",
                    di.DriveLetter(),
                    di.ProductID().c_str(),
                    di.VendorID().c_str());

                std::wstring menuStr = L"[" + std::wstring(1, di.DriveLetter()) + L":] - " + di.ProductID();
                InsertMenu(_menu, -1, MF_ENABLED, menuItem++, menuStr.c_str());
                _menuItems.push_back(di);
            }
        }
    }
}

void EjectOSD::EjectDrive(std::wstring driveLetter) {
    std::wstring name = DriveInfo::DriveFileName(driveLetter);
    CLOG(L"Ejecting %s", name.c_str());

    HANDLE dev = CreateFile(
        name.c_str(),
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        NULL,
        NULL);

    if (dev == INVALID_HANDLE_VALUE) {
        CLOG(L"Failed to get device handle");
        return;
    }

    DWORD bytesReturned = 0;

    DeviceIoControl(dev, FSCTL_LOCK_VOLUME,
        NULL, NULL, NULL, NULL, &bytesReturned, NULL);

    PREVENT_MEDIA_REMOVAL pmr = { 0 };
    pmr.PreventMediaRemoval = FALSE;
    DeviceIoControl(dev, IOCTL_STORAGE_MEDIA_REMOVAL,
        &pmr, sizeof(PREVENT_MEDIA_REMOVAL), NULL, 0, &bytesReturned, NULL);

    DeviceIoControl(dev, FSCTL_DISMOUNT_VOLUME,
        NULL, NULL, NULL, NULL, &bytesReturned, NULL);

    BOOL ejected = FALSE;
    ejected = DeviceIoControl(dev, IOCTL_STORAGE_EJECT_MEDIA,
        NULL, NULL, NULL, NULL, &bytesReturned, NULL);

    if (ejected != FALSE) {
        std::wstring rootPath = driveLetter + L":\\";
        if (GetDriveType(rootPath.c_str()) != DRIVE_CDROM) {
            int driveBit = (int) pow(2, (driveLetter.at(0) - 65));
            _ignoreDrives |= driveBit;
            CLOG(L"Added drive bit %d to ignore list", driveBit);
        }
        if (OSD::Enabled()) {
            HideOthers(Eject);
            _mWnd.Show();
        }
    }

    CloseHandle(dev);
}

void EjectOSD::Hide() {
    _mWnd.Hide(false);
}

void EjectOSD::ProcessHotkeys(HotkeyInfo &hki) {
    switch (hki.action) {
    case HotkeyInfo::EjectDrive:
        if (hki.args.size() > 0) {
            EjectDrive(hki.args[0]);
        }
        break;

    case HotkeyInfo::EjectLastDisk:
        if (_latestDrive != 0) {
            wchar_t letter = MaskToDriveLetter(_latestDrive);
            std::wstring lStr(1, letter);
            EjectDrive(lStr);
            _latestDrive = 0;
        }

        break;
    }
}

LRESULT
EjectOSD::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    if (message == WM_DEVICECHANGE && wParam == DBT_DEVICEREMOVECOMPLETE) {
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lParam;
        if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) {
            PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lpdb;

            DWORD driveMask = lpdbv->dbcv_unitmask;
            CLOG(L"Eject notification received for drive %c:",
                MaskToDriveLetter(driveMask));

            if (driveMask & _ignoreDrives) {
                CLOG(L"Drive already ejected by a hotkey; not displaying OSD.");
                _ignoreDrives ^= driveMask;
            } else if (OSD::Enabled()) {
                HideOthers(Eject);
                _mWnd.Show();
            }

            if (_latestDrive == driveMask) {
                _latestDrive = 0;
            }
        }
    }

    if (message == WM_DEVICECHANGE && wParam == DBT_DEVICEARRIVAL) {
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lParam;
        if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) {
            PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lpdb;

            if (lpdbv->dbcv_flags != DBTF_NET) {
                _latestDrive = lpdbv->dbcv_unitmask;

                CLOG(L"Media inserted in drive %c:",
                    MaskToDriveLetter(_latestDrive));
            }
        }
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}

DWORD EjectOSD::DriveLetterToMask(wchar_t letter) {
    if (letter < 65 || letter > 90) {
        return 0;
    }

    return (DWORD) pow(2, (letter - 65));
}

wchar_t EjectOSD::MaskToDriveLetter(DWORD mask) {
    return (wchar_t) (log2(mask) + 65);
}

void EjectOSD::OnDisplayChange() {
    InitMeterWnd(_mWnd);
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Emilian Cioca
#include "Jewel3D/Precompiled.h"
#include "UniformBuffer.h"
#include "Jewel3D/Application/Logging.h"
#include "Jewel3D/Math/Vector.h"

#include <algorithm>
#include <GLEW/GL/glew.h>

namespace
{
	// Rounds val up to the nearest multiple.
	unsigned round(unsigned val, unsigned multiple)
	{
		unsigned remainder = val % multiple;
		if (remainder != 0)
		{
			val += multiple - remainder;
		}

		return val;
	}
}

namespace Jwl
{
	UniformBuffer::~UniformBuffer()
	{
		UnLoad();
	}

	UniformBuffer& UniformBuffer::operator=(const UniformBuffer& other)
	{
		UnLoad();

		table = other.table;
		bufferSize = other.bufferSize;

		if (bufferSize != 0)
		{
			// We have to create our own UBO.
			InitBuffer();

			memcpy(buffer, other.buffer, bufferSize);
		}

		return *this;
	}

	void UniformBuffer::Copy(const UniformBuffer& other)
	{
		*this = other;
	}

	void UniformBuffer::InitBuffer(VertexBufferUsage usage)
	{
		ASSERT(bufferSize != 0, "At least one uniform must be added to the buffer before it can be initialized.");
		ASSERT(UBO == GL_NONE, "UniformBuffer has already been initialized and locked.");

		// The total size of a buffer is always aligned to the size of a vec4.
		bufferSize = round(bufferSize, sizeof(vec4));

		// GPU buffer.
		glGenBuffers(1, &UBO);
		glBindBuffer(GL_UNIFORM_BUFFER, UBO);
		glBufferData(GL_UNIFORM_BUFFER, bufferSize, nullptr, ResolveVertexBufferUsage(usage));
		glBindBuffer(GL_UNIFORM_BUFFER, GL_NONE);

		// RAM buffer.
		buffer = calloc(1, bufferSize);
	}

	void UniformBuffer::UnLoad()
	{
		glDeleteBuffers(1, &UBO);
		UBO = GL_NONE;

		free(buffer);
		buffer = nullptr;

		table.clear();
		bufferSize = 0;
		dirty = true;
	}

	void UniformBuffer::Bind(unsigned slot) const
	{
		glBindBufferBase(GL_UNIFORM_BUFFER, slot, UBO);

		if (dirty)
		{
			glBufferSubData(GL_UNIFORM_BUFFER, 0, bufferSize, buffer);
			dirty = false;
		}
	}

	void UniformBuffer::UnBind(unsigned slot)
	{
		glBindBufferBase(GL_UNIFORM_BUFFER, slot, GL_NONE);
	}

	int UniformBuffer::GetByteSize() const
	{
		return bufferSize;
	}

	bool UniformBuffer::IsUniform(const std::string& name) const
	{
		return table.find(name) != table.end();
	}

	void UniformBuffer::AddUniform(const std::string& name, unsigned bytes, unsigned alignment, unsigned count)
	{
		ASSERT(UBO == GL_NONE, "UniformBuffer has already been initialized and locked.");
		ASSERT(count != 0, "Must add at least one element.");
		ASSERT(!IsUniform(name), "A member with the same name has already been added.");

		// Since we are using std140 layout, we must follow the rules in the OpenGL specification:
		// https://www.opengl.org/registry/doc/glspec45.core.pdf#page=159
		if (count == 1)
		{
			// Start of a single element is aligned to its own size.
			bufferSize = round(bufferSize, alignment);

			table[name] = bufferSize;
			bufferSize += bytes;
		}
		else
		{
			// An array must start on a vec4 boundary.
			bufferSize = round(bufferSize, sizeof(vec4));

			// The size of an individual element is aligned to the nearest vec4.
			bytes = round(bytes, sizeof(vec4));

			table[name] = bufferSize;
			bufferSize += bytes * count;

			// There must be padding after an array to the next vec4.
			bufferSize = round(bufferSize, sizeof(vec4));
		}
	}

	void* UniformBuffer::GetBufferLoc(const std::string& name) const
	{
		auto loc = table.find(name);
		if (loc != table.end())
		{
			return static_cast<char*>(buffer) + loc->second;
		}
		else
		{
			return nullptr;
		}
	}

	template<>
	void UniformBuffer::SetUniform<mat2>(const std::string& name, const mat2& data)
	{
		vec4* dest = reinterpret_cast<vec4*>(GetBufferLoc(name));
		ASSERT(dest, "Could not find uniform parameter ( %s ).", name.c_str());
		ASSERT(reinterpret_cast<char*>(dest) + sizeof(vec4) * 2 <= reinterpret_cast<char*>(buffer) + bufferSize,
			"Setting uniform ( %s ) out of bounds of the buffer.", name.c_str());

		dest[0].x = data[0];
		dest[0].y = data[1];
		dest[1].x = data[2];
		dest[1].y = data[3];
		dirty = true;
	}

	template<>
	void UniformBuffer::SetUniform<mat3>(const std::string& name, const mat3& data)
	{
		vec4* dest = reinterpret_cast<vec4*>(GetBufferLoc(name));
		ASSERT(dest, "Could not find uniform parameter ( %s ).", name.c_str());
		ASSERT(reinterpret_cast<char*>(dest) + sizeof(vec4) * 3 <= reinterpret_cast<char*>(buffer) + bufferSize,
			"Setting uniform ( %s ) out of bounds of the buffer.", name.c_str());

		dest[0].x = data[0];
		dest[0].y = data[1];
		dest[0].z = data[2];

		dest[1].x = data[3];
		dest[1].y = data[4];
		dest[1].z = data[5];

		dest[2].x = data[6];
		dest[2].y = data[7];
		dest[2].z = data[8];

		dirty = true;
	}

	//-----------------------------------------------------------------------------------------------------

	BufferSlot::BufferSlot(UniformBuffer::Ptr buffer, unsigned unit)
		: buffer(std::move(buffer)), unit(unit)
	{
	}

	void BufferSlot::Bind() const
	{
		buffer->Bind(unit);
	}

	void BufferSlot::UnBind() const
	{
		UniformBuffer::UnBind(unit);
	}

	//-----------------------------------------------------------------------------------------------------

	void BufferList::Bind() const
	{
		for (auto& slot : buffers)
		{
			slot.Bind();
		}
	}

	void BufferList::UnBind() const
	{
		for (auto& slot : buffers)
		{
			slot.UnBind();
		}
	}

	void BufferList::Add(UniformBuffer::Ptr buff, unsigned unit)
	{
		ASSERT(buff, "'buff' cannot be null.");

		for (auto& slot : buffers)
		{
			if (slot.unit == unit)
			{
				slot.buffer = std::move(buff);
				return;
			}
		}

		buffers.emplace_back(std::move(buff), unit);
	}

	void BufferList::Remove(unsigned unit)
	{
		for (auto itr = buffers.begin(); itr < buffers.end(); ++itr)
		{
			if (itr->unit == unit)
			{
				buffers.erase(itr);
				return;
			}
		}
	}

	void BufferList::Clear()
	{
		buffers.clear();
	}

	UniformBuffer::Ptr& BufferList::operator[](unsigned unit)
	{
		auto bufferSlot = std::find_if(buffers.begin(), buffers.end(), [unit](BufferSlot& slot) {
			return slot.unit == unit;
		});

		ASSERT(bufferSlot != buffers.end(), "No matching buffer found.");
		return bufferSlot->buffer;
	}

	template<>
	void UniformHandle<mat2>::Set(const mat2& value)
	{
		ASSERT(uniformBuffer, "Uniform handle is not associated with a UniformBuffer.");
		ASSERT(uniformBuffer->buffer, "The associated UniformBuffer has not been initialized yet.");

		vec4* ptr = reinterpret_cast<vec4*>(static_cast<char*>(uniformBuffer->buffer) + offset);
		ptr[0].x = value[0];
		ptr[0].y = value[1];
		ptr[1].x = value[2];
		ptr[1].y = value[3];

		uniformBuffer->dirty = true;
	}

	template<>
	void UniformHandle<mat3>::Set(const mat3& value)
	{
		ASSERT(uniformBuffer, "Uniform handle is not associated with a UniformBuffer.");
		ASSERT(uniformBuffer->buffer, "The associated UniformBuffer has not been initialized yet.");

		vec4* ptr = reinterpret_cast<vec4*>(static_cast<char*>(uniformBuffer->buffer) + offset);

		ptr[0].x = value[0];
		ptr[0].y = value[1];
		ptr[0].z = value[2];

		ptr[1].x = value[3];
		ptr[1].y = value[4];
		ptr[1].z = value[5];

		ptr[2].x = value[6];
		ptr[2].y = value[7];
		ptr[2].z = value[8];

		uniformBuffer->dirty = true;
	}

	template<>
	mat2 UniformHandle<mat2>::Get() const
	{
		ASSERT(uniformBuffer, "Uniform handle is not associated with a UniformBuffer.");
		ASSERT(uniformBuffer->buffer, "The associated UniformBuffer has not been initialized yet.");

		const vec4* data = reinterpret_cast<vec4*>(static_cast<char*>(uniformBuffer->buffer) + offset);

		return mat2(data[0].x, data[0].y, data[1].x, data[1].y);
	}

	template<>
	mat3 UniformHandle<mat3>::Get() const
	{
		ASSERT(uniformBuffer, "Uniform handle is not associated with a UniformBuffer.");
		ASSERT(uniformBuffer->buffer, "The associated UniformBuffer has not been initialized yet.");

		const mat4* data = reinterpret_cast<mat4*>(static_cast<char*>(uniformBuffer->buffer) + offset);

		return mat3(*data);
	}
}
<commit_msg>Updated to use .contains() on unordered_map<commit_after>// Copyright (c) 2017 Emilian Cioca
#include "Jewel3D/Precompiled.h"
#include "UniformBuffer.h"
#include "Jewel3D/Application/Logging.h"
#include "Jewel3D/Math/Vector.h"

#include <algorithm>
#include <GLEW/GL/glew.h>

namespace
{
	// Rounds val up to the nearest multiple.
	unsigned round(unsigned val, unsigned multiple)
	{
		unsigned remainder = val % multiple;
		if (remainder != 0)
		{
			val += multiple - remainder;
		}

		return val;
	}
}

namespace Jwl
{
	UniformBuffer::~UniformBuffer()
	{
		UnLoad();
	}

	UniformBuffer& UniformBuffer::operator=(const UniformBuffer& other)
	{
		UnLoad();

		table = other.table;
		bufferSize = other.bufferSize;

		if (bufferSize != 0)
		{
			// We have to create our own UBO.
			InitBuffer();

			memcpy(buffer, other.buffer, bufferSize);
		}

		return *this;
	}

	void UniformBuffer::Copy(const UniformBuffer& other)
	{
		*this = other;
	}

	void UniformBuffer::InitBuffer(VertexBufferUsage usage)
	{
		ASSERT(bufferSize != 0, "At least one uniform must be added to the buffer before it can be initialized.");
		ASSERT(UBO == GL_NONE, "UniformBuffer has already been initialized and locked.");

		// The total size of a buffer is always aligned to the size of a vec4.
		bufferSize = round(bufferSize, sizeof(vec4));

		// GPU buffer.
		glGenBuffers(1, &UBO);
		glBindBuffer(GL_UNIFORM_BUFFER, UBO);
		glBufferData(GL_UNIFORM_BUFFER, bufferSize, nullptr, ResolveVertexBufferUsage(usage));
		glBindBuffer(GL_UNIFORM_BUFFER, GL_NONE);

		// RAM buffer.
		buffer = calloc(1, bufferSize);
	}

	void UniformBuffer::UnLoad()
	{
		glDeleteBuffers(1, &UBO);
		UBO = GL_NONE;

		free(buffer);
		buffer = nullptr;

		table.clear();
		bufferSize = 0;
		dirty = true;
	}

	void UniformBuffer::Bind(unsigned slot) const
	{
		glBindBufferBase(GL_UNIFORM_BUFFER, slot, UBO);

		if (dirty)
		{
			glBufferSubData(GL_UNIFORM_BUFFER, 0, bufferSize, buffer);
			dirty = false;
		}
	}

	void UniformBuffer::UnBind(unsigned slot)
	{
		glBindBufferBase(GL_UNIFORM_BUFFER, slot, GL_NONE);
	}

	int UniformBuffer::GetByteSize() const
	{
		return bufferSize;
	}

	bool UniformBuffer::IsUniform(const std::string& name) const
	{
		return table.contains(name);
	}

	void UniformBuffer::AddUniform(const std::string& name, unsigned bytes, unsigned alignment, unsigned count)
	{
		ASSERT(UBO == GL_NONE, "UniformBuffer has already been initialized and locked.");
		ASSERT(count != 0, "Must add at least one element.");
		ASSERT(!IsUniform(name), "A member with the same name has already been added.");

		// Since we are using std140 layout, we must follow the rules in the OpenGL specification:
		// https://www.opengl.org/registry/doc/glspec45.core.pdf#page=159
		if (count == 1)
		{
			// Start of a single element is aligned to its own size.
			bufferSize = round(bufferSize, alignment);

			table[name] = bufferSize;
			bufferSize += bytes;
		}
		else
		{
			// An array must start on a vec4 boundary.
			bufferSize = round(bufferSize, sizeof(vec4));

			// The size of an individual element is aligned to the nearest vec4.
			bytes = round(bytes, sizeof(vec4));

			table[name] = bufferSize;
			bufferSize += bytes * count;

			// There must be padding after an array to the next vec4.
			bufferSize = round(bufferSize, sizeof(vec4));
		}
	}

	void* UniformBuffer::GetBufferLoc(const std::string& name) const
	{
		auto loc = table.find(name);
		if (loc != table.end())
		{
			return static_cast<char*>(buffer) + loc->second;
		}
		else
		{
			return nullptr;
		}
	}

	template<>
	void UniformBuffer::SetUniform<mat2>(const std::string& name, const mat2& data)
	{
		vec4* dest = reinterpret_cast<vec4*>(GetBufferLoc(name));
		ASSERT(dest, "Could not find uniform parameter ( %s ).", name.c_str());
		ASSERT(reinterpret_cast<char*>(dest) + sizeof(vec4) * 2 <= reinterpret_cast<char*>(buffer) + bufferSize,
			"Setting uniform ( %s ) out of bounds of the buffer.", name.c_str());

		dest[0].x = data[0];
		dest[0].y = data[1];
		dest[1].x = data[2];
		dest[1].y = data[3];
		dirty = true;
	}

	template<>
	void UniformBuffer::SetUniform<mat3>(const std::string& name, const mat3& data)
	{
		vec4* dest = reinterpret_cast<vec4*>(GetBufferLoc(name));
		ASSERT(dest, "Could not find uniform parameter ( %s ).", name.c_str());
		ASSERT(reinterpret_cast<char*>(dest) + sizeof(vec4) * 3 <= reinterpret_cast<char*>(buffer) + bufferSize,
			"Setting uniform ( %s ) out of bounds of the buffer.", name.c_str());

		dest[0].x = data[0];
		dest[0].y = data[1];
		dest[0].z = data[2];

		dest[1].x = data[3];
		dest[1].y = data[4];
		dest[1].z = data[5];

		dest[2].x = data[6];
		dest[2].y = data[7];
		dest[2].z = data[8];

		dirty = true;
	}

	//-----------------------------------------------------------------------------------------------------

	BufferSlot::BufferSlot(UniformBuffer::Ptr buffer, unsigned unit)
		: buffer(std::move(buffer)), unit(unit)
	{
	}

	void BufferSlot::Bind() const
	{
		buffer->Bind(unit);
	}

	void BufferSlot::UnBind() const
	{
		UniformBuffer::UnBind(unit);
	}

	//-----------------------------------------------------------------------------------------------------

	void BufferList::Bind() const
	{
		for (auto& slot : buffers)
		{
			slot.Bind();
		}
	}

	void BufferList::UnBind() const
	{
		for (auto& slot : buffers)
		{
			slot.UnBind();
		}
	}

	void BufferList::Add(UniformBuffer::Ptr buff, unsigned unit)
	{
		ASSERT(buff, "'buff' cannot be null.");

		for (auto& slot : buffers)
		{
			if (slot.unit == unit)
			{
				slot.buffer = std::move(buff);
				return;
			}
		}

		buffers.emplace_back(std::move(buff), unit);
	}

	void BufferList::Remove(unsigned unit)
	{
		for (auto itr = buffers.begin(); itr < buffers.end(); ++itr)
		{
			if (itr->unit == unit)
			{
				buffers.erase(itr);
				return;
			}
		}
	}

	void BufferList::Clear()
	{
		buffers.clear();
	}

	UniformBuffer::Ptr& BufferList::operator[](unsigned unit)
	{
		auto bufferSlot = std::find_if(buffers.begin(), buffers.end(), [unit](BufferSlot& slot) {
			return slot.unit == unit;
		});

		ASSERT(bufferSlot != buffers.end(), "No matching buffer found.");
		return bufferSlot->buffer;
	}

	template<>
	void UniformHandle<mat2>::Set(const mat2& value)
	{
		ASSERT(uniformBuffer, "Uniform handle is not associated with a UniformBuffer.");
		ASSERT(uniformBuffer->buffer, "The associated UniformBuffer has not been initialized yet.");

		vec4* ptr = reinterpret_cast<vec4*>(static_cast<char*>(uniformBuffer->buffer) + offset);
		ptr[0].x = value[0];
		ptr[0].y = value[1];
		ptr[1].x = value[2];
		ptr[1].y = value[3];

		uniformBuffer->dirty = true;
	}

	template<>
	void UniformHandle<mat3>::Set(const mat3& value)
	{
		ASSERT(uniformBuffer, "Uniform handle is not associated with a UniformBuffer.");
		ASSERT(uniformBuffer->buffer, "The associated UniformBuffer has not been initialized yet.");

		vec4* ptr = reinterpret_cast<vec4*>(static_cast<char*>(uniformBuffer->buffer) + offset);

		ptr[0].x = value[0];
		ptr[0].y = value[1];
		ptr[0].z = value[2];

		ptr[1].x = value[3];
		ptr[1].y = value[4];
		ptr[1].z = value[5];

		ptr[2].x = value[6];
		ptr[2].y = value[7];
		ptr[2].z = value[8];

		uniformBuffer->dirty = true;
	}

	template<>
	mat2 UniformHandle<mat2>::Get() const
	{
		ASSERT(uniformBuffer, "Uniform handle is not associated with a UniformBuffer.");
		ASSERT(uniformBuffer->buffer, "The associated UniformBuffer has not been initialized yet.");

		const vec4* data = reinterpret_cast<vec4*>(static_cast<char*>(uniformBuffer->buffer) + offset);

		return mat2(data[0].x, data[0].y, data[1].x, data[1].y);
	}

	template<>
	mat3 UniformHandle<mat3>::Get() const
	{
		ASSERT(uniformBuffer, "Uniform handle is not associated with a UniformBuffer.");
		ASSERT(uniformBuffer->buffer, "The associated UniformBuffer has not been initialized yet.");

		const mat4* data = reinterpret_cast<mat4*>(static_cast<char*>(uniformBuffer->buffer) + offset);

		return mat3(*data);
	}
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// order_by_test.cpp
//
// Identification: tests/executor/order_by_test.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <memory>
#include <set>
#include <string>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "backend/planner/order_by_plan.h"

#include "backend/common/types.h"
#include "backend/common/value.h"
#include "backend/executor/logical_tile.h"
#include "backend/executor/order_by_executor.h"
#include "backend/executor/logical_tile_factory.h"
#include "backend/storage/data_table.h"

#include "executor/executor_tests_util.h"
#include "executor/mock_executor.h"
#include "harness.h"

using ::testing::NotNull;
using ::testing::Return;

namespace peloton {
namespace test {

namespace {

void RunTest(executor::OrderByExecutor &executor, size_t expected_num_tuples,
             const std::vector<oid_t> &sort_keys,
             const std::vector<bool> &descend_flags) {
  EXPECT_TRUE(executor.Init());

  std::vector<std::unique_ptr<executor::LogicalTile>> result_tiles;
  while (executor.Execute()) {
    result_tiles.emplace_back(executor.GetOutput());
  }

  size_t actual_num_tuples_returned = 0;
  for (auto &tile : result_tiles) {
    actual_num_tuples_returned += tile->GetTupleCount();
  }

  EXPECT_EQ(expected_num_tuples, actual_num_tuples_returned);

  EXPECT_GT(sort_keys.size(), 0);
  EXPECT_GT(descend_flags.size(), 0);

  // Verify:
  // Lazy here: just print it out and see it by yourself.
  for (auto &tile : result_tiles) {
    for (oid_t tuple_id : *tile) {
      std::cout << "<";
      for (size_t sk = 0; sk < sort_keys.size(); sk++) {
        std::cout << tile->GetValue(tuple_id, sort_keys[sk]) << ",";
      }
      std::cout << ">";
    }
  }

  std::cout << std::endl;
}

TEST(OrderByTests, IntAscTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({1});
  std::vector<bool> descend_flags({false});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);

  delete backend;
}

TEST(OrderByTests, IntDescTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({1});
  std::vector<bool> descend_flags({true});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);

  delete backend;
}

TEST(OrderByTests, StringDescTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({3});
  std::vector<bool> descend_flags({true});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);

  delete backend;
}

TEST(OrderByTests, IntAscStringDescTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({1, 3});
  std::vector<bool> descend_flags({false, true});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);

  delete backend;
}

/**
 * Switch the order of sort keys of the previous test case
 */
TEST(OrderByTests, StringDescIntAscTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({3, 1});
  std::vector<bool> descend_flags({true, false});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);

  delete backend;
}
}

}  // namespace test
}  // namespace peloton
<commit_msg>Fix test.<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// order_by_test.cpp
//
// Identification: tests/executor/order_by_test.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <memory>
#include <set>
#include <string>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "backend/planner/order_by_plan.h"

#include "backend/common/types.h"
#include "backend/common/value.h"
#include "backend/executor/logical_tile.h"
#include "backend/executor/order_by_executor.h"
#include "backend/executor/logical_tile_factory.h"
#include "backend/storage/data_table.h"

#include "executor/executor_tests_util.h"
#include "executor/mock_executor.h"
#include "harness.h"

using ::testing::NotNull;
using ::testing::Return;

namespace peloton {
namespace test {

namespace {

void RunTest(executor::OrderByExecutor &executor, size_t expected_num_tuples,
             const std::vector<oid_t> &sort_keys,
             const std::vector<bool> &descend_flags) {
  EXPECT_TRUE(executor.Init());

  std::vector<std::unique_ptr<executor::LogicalTile>> result_tiles;
  while (executor.Execute()) {
    result_tiles.emplace_back(executor.GetOutput());
  }

  size_t actual_num_tuples_returned = 0;
  for (auto &tile : result_tiles) {
    actual_num_tuples_returned += tile->GetTupleCount();
  }

  EXPECT_EQ(expected_num_tuples, actual_num_tuples_returned);

  EXPECT_GT(sort_keys.size(), 0);
  EXPECT_GT(descend_flags.size(), 0);

  // Verify:
  // Lazy here: just print it out and see it by yourself.
  for (auto &tile : result_tiles) {
    for (oid_t tuple_id : *tile) {
      std::cout << "<";
      for (size_t sk = 0; sk < sort_keys.size(); sk++) {
        std::cout << tile->GetValue(tuple_id, sort_keys[sk]) << ",";
      }
      std::cout << ">";
    }
  }

  std::cout << std::endl;
}

TEST(OrderByTests, IntAscTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({1});
  std::vector<bool> descend_flags({false});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);

}

TEST(OrderByTests, IntDescTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({1});
  std::vector<bool> descend_flags({true});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);

}

TEST(OrderByTests, StringDescTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({3});
  std::vector<bool> descend_flags({true});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);

}

TEST(OrderByTests, IntAscStringDescTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({1, 3});
  std::vector<bool> descend_flags({false, true});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);
}

/**
 * Switch the order of sort keys of the previous test case
 */
TEST(OrderByTests, StringDescIntAscTest) {
  // Create the plan node
  std::vector<oid_t> sort_keys({3, 1});
  std::vector<bool> descend_flags({true, false});
  std::vector<oid_t> output_columns({0, 1, 2, 3});
  storage::AbstractBackend *backend = new storage::VMBackend();
  planner::OrderByPlan node(sort_keys, descend_flags, output_columns, backend);

  // Create and set up executor
  executor::OrderByExecutor executor(&node, nullptr);
  MockExecutor child_executor;
  executor.AddChild(&child_executor);

  EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true));

  EXPECT_CALL(child_executor, DExecute())
      .WillOnce(Return(true))
      .WillOnce(Return(true))
      .WillOnce(Return(false));

  // Create a table and wrap it in logical tile
  size_t tile_size = 20;
  std::unique_ptr<storage::DataTable> data_table(
      ExecutorTestsUtil::CreateTable(tile_size));
  bool random = true;
  ExecutorTestsUtil::PopulateTable(data_table.get(), tile_size * 2, false,
                                   random, false);

  std::unique_ptr<executor::LogicalTile> source_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0)));

  std::unique_ptr<executor::LogicalTile> source_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1)));

  EXPECT_CALL(child_executor, GetOutput())
      .WillOnce(Return(source_logical_tile1.release()))
      .WillOnce(Return(source_logical_tile2.release()));

  RunTest(executor, tile_size * 2, sort_keys, descend_flags);

}
}

}  // namespace test
}  // namespace peloton
<|endoftext|>


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

#include "browser/api/atom_api_protocol.h"

#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_job_manager.h"
#include "vendor/node/src/node.h"

namespace atom {

namespace api {

Protocol::HandlersMap Protocol::handlers_;

// static
v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
  std::string scheme(*v8::String::Utf8Value(args[0]));
  if (handlers_.find(scheme) != handlers_.end())
    return node::ThrowError("The scheme is already registered");

  // Store the handler in a map.
  if (!args[1]->IsFunction())
    return node::ThrowError("Handler must be a function");
  handlers_[scheme] = v8::Persistent<v8::Function>::New(
      node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));

  content::BrowserThread::PostTask(content::BrowserThread::IO,
                                   FROM_HERE,
                                   base::Bind(&RegisterProtocolInIO, scheme));

  return v8::Undefined();
}

// static
v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
  std::string scheme(*v8::String::Utf8Value(args[0]));

  // Erase the handler from map.
  HandlersMap::iterator it(handlers_.find(scheme));
  if (it == handlers_.end())
    return node::ThrowError("The scheme has not been registered");
  handlers_.erase(it);

  content::BrowserThread::PostTask(content::BrowserThread::IO,
                                   FROM_HERE,
                                   base::Bind(&UnregisterProtocolInIO, scheme));

  return v8::Undefined();
}

// static
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
}

// static
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
}

// static
void Protocol::Initialize(v8::Handle<v8::Object> target) {
  node::SetMethod(target, "registerProtocol", RegisterProtocol);
  node::SetMethod(target, "unregisterProtocol", UnregisterProtocol);
}

}  // namespace api

}  // namespace atom

NODE_MODULE(atom_browser_protocol, atom::api::Protocol::Initialize)
<commit_msg>Actually set and remove protocol handlers in IO thread..<commit_after>// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "browser/api/atom_api_protocol.h"

#include "browser/atom_browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "vendor/node/src/node.h"

namespace atom {

namespace api {

namespace {

net::URLRequestJobFactoryImpl* GetRequestJobFactory() {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
  // Get the job factory.
  net::URLRequestJobFactoryImpl* job_factory =
      static_cast<net::URLRequestJobFactoryImpl*>(
          const_cast<net::URLRequestJobFactory*>(
              static_cast<content::BrowserContext*>(AtomBrowserContext::Get())->
                  GetRequestContext()->GetURLRequestContext()->job_factory()));
  return job_factory;
}

class AdapterProtocolHandler
    : public net::URLRequestJobFactory::ProtocolHandler {
 public:
  AdapterProtocolHandler() {}
  virtual net::URLRequestJob* MaybeCreateJob(
      net::URLRequest* request,
      net::NetworkDelegate* network_delegate) const OVERRIDE {
    return NULL;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(AdapterProtocolHandler);
};

}  // namespace

Protocol::HandlersMap Protocol::handlers_;

// static
v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
  std::string scheme(*v8::String::Utf8Value(args[0]));
  if (handlers_.find(scheme) != handlers_.end())
    return node::ThrowError("The scheme is already registered");

  // Store the handler in a map.
  if (!args[1]->IsFunction())
    return node::ThrowError("Handler must be a function");
  handlers_[scheme] = v8::Persistent<v8::Function>::New(
      node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));

  content::BrowserThread::PostTask(content::BrowserThread::IO,
                                   FROM_HERE,
                                   base::Bind(&RegisterProtocolInIO, scheme));

  return v8::Undefined();
}

// static
v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
  std::string scheme(*v8::String::Utf8Value(args[0]));

  // Erase the handler from map.
  HandlersMap::iterator it(handlers_.find(scheme));
  if (it == handlers_.end())
    return node::ThrowError("The scheme has not been registered");
  handlers_.erase(it);

  content::BrowserThread::PostTask(content::BrowserThread::IO,
                                   FROM_HERE,
                                   base::Bind(&UnregisterProtocolInIO, scheme));

  return v8::Undefined();
}

// static
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
  net::URLRequestJobFactoryImpl* job_factory(GetRequestJobFactory());
  job_factory->SetProtocolHandler(scheme, new AdapterProtocolHandler);
}

// static
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
  net::URLRequestJobFactoryImpl* job_factory(GetRequestJobFactory());
  job_factory->SetProtocolHandler(scheme, NULL);
}

// static
void Protocol::Initialize(v8::Handle<v8::Object> target) {
  node::SetMethod(target, "registerProtocol", RegisterProtocol);
  node::SetMethod(target, "unregisterProtocol", UnregisterProtocol);
}

}  // namespace api

}  // namespace atom

NODE_MODULE(atom_browser_protocol, atom::api::Protocol::Initialize)
<|endoftext|>