<commit_before>// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <array>
#include <cstdio>
#include <iostream>
#include <iterator>
#include <string>
#include <utility>
#include <vector>

#include "iree/base/api.h"
#include "iree/base/internal/file_io.h"
#include "iree/base/internal/flags.h"
#include "iree/base/status_cc.h"
#include "iree/base/tracing.h"
#include "iree/hal/api.h"
#include "iree/hal/drivers/init.h"
#include "iree/modules/hal/module.h"
#include "iree/tools/utils/vm_util.h"
#include "iree/vm/api.h"
#include "iree/vm/bytecode_module.h"
#include "iree/vm/ref_cc.h"

IREE_FLAG(string, module_file, "-",
          "File containing the module to load that contains the entry "
          "function. Defaults to stdin.");

IREE_FLAG(string, entry_function, "",
          "Name of a function contained in the module specified by module_file "
          "to run.");

IREE_FLAG(string, driver, "vmvx", "Backend driver to use.");

IREE_FLAG(bool, print_statistics, true,
          "Prints runtime statistics to stderr on exit.");

static iree_status_t parse_function_input(iree_string_view_t flag_name,
                                          void* storage,
                                          iree_string_view_t value) {
  auto* list = (std::vector<std::string>*)storage;
  list->push_back(std::string(value.data, value.size));
  return iree_ok_status();
}
static void print_function_input(iree_string_view_t flag_name, void* storage,
                                 FILE* file) {
  auto* list = (std::vector<std::string>*)storage;
  if (list->empty()) {
    fprintf(file, "# --%.*s=\n", (int)flag_name.size, flag_name.data);
  } else {
    for (size_t i = 0; i < list->size(); ++i) {
      fprintf(file, "--%.*s=\"%s\"\n", (int)flag_name.size, flag_name.data,
              list->at(i).c_str());
    }
  }
}
static std::vector<std::string> FLAG_function_inputs;
IREE_FLAG_CALLBACK(
    parse_function_input, print_function_input, &FLAG_function_inputs,
    function_input,
    "An input value or buffer of the format:\n"
    "  [shape]xtype=[value]\n"
    "  2x2xi32=1 2 3 4\n"
    "Optionally, brackets may be used to separate the element values:\n"
    "  2x2xi32=[[1 2][3 4]]\n"
    "Each occurrence of the flag indicates an input in the order they were\n"
    "specified on the command line.");

namespace iree {
namespace {

iree_status_t GetModuleContentsFromFlags(std::string* out_contents) {
  IREE_TRACE_SCOPE0("GetModuleContentsFromFlags");
  auto module_file = std::string(FLAG_module_file);
  if (module_file == "-") {
    *out_contents = std::string{std::istreambuf_iterator<char>(std::cin),
                                std::istreambuf_iterator<char>()};
  } else {
    IREE_RETURN_IF_ERROR(GetFileContents(module_file.c_str(), out_contents));
  }
  return iree_ok_status();
}

iree_status_t Run() {
  IREE_TRACE_SCOPE0("iree-run-module");

  IREE_RETURN_IF_ERROR(iree_hal_module_register_types(),
                       "registering HAL types");
  iree_vm_instance_t* instance = nullptr;
  IREE_RETURN_IF_ERROR(
      iree_vm_instance_create(iree_allocator_system(), &instance),
      "creating instance");

  std::string module_data;
  IREE_RETURN_IF_ERROR(GetModuleContentsFromFlags(&module_data));
  iree_vm_module_t* input_module = nullptr;
  IREE_RETURN_IF_ERROR(iree_vm_bytecode_module_create(
      iree_make_const_byte_span((void*)module_data.data(), module_data.size()),
      iree_allocator_null(), iree_allocator_system(), &input_module));

  iree_hal_device_t* device = nullptr;
  IREE_RETURN_IF_ERROR(CreateDevice(FLAG_driver, &device));
  iree_vm_module_t* hal_module = nullptr;
  IREE_RETURN_IF_ERROR(
      iree_hal_module_create(device, iree_allocator_system(), &hal_module));

  iree_vm_context_t* context = nullptr;
  // Order matters. The input module will likely be dependent on the hal module.
  std::array<iree_vm_module_t*, 2> modules = {hal_module, input_module};
  IREE_RETURN_IF_ERROR(iree_vm_context_create_with_modules(
                           instance, modules.data(), modules.size(),
                           iree_allocator_system(), &context),
                       "creating context");

  std::string function_name = std::string(FLAG_entry_function);
  iree_vm_function_t function;
  if (function_name.empty()) {
    return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
                            "no --entry_function= specified");
  } else {
    IREE_RETURN_IF_ERROR(
        input_module->lookup_function(
            input_module->self, IREE_VM_FUNCTION_LINKAGE_EXPORT,
            iree_string_view_t{function_name.data(), function_name.size()},
            &function),
        "looking up function '%s'", function_name.c_str());
  }

  vm::ref<iree_vm_list_t> inputs;
  IREE_CHECK_OK(ParseToVariantList(
      iree_hal_device_allocator(device),
      iree::span<const std::string>{FLAG_function_inputs.data(),
                                    FLAG_function_inputs.size()},
      &inputs));

  vm::ref<iree_vm_list_t> outputs;
  IREE_RETURN_IF_ERROR(iree_vm_list_create(/*element_type=*/nullptr, 16,
                                           iree_allocator_system(), &outputs));

  std::cout << "EXEC @" << function_name << "\n";
  IREE_RETURN_IF_ERROR(
      iree_vm_invoke(context, function, /*policy=*/nullptr, inputs.get(),
                     outputs.get(), iree_allocator_system()),
      "invoking function '%s'", function_name.c_str());

  IREE_RETURN_IF_ERROR(PrintVariantList(outputs.get()), "printing results");

  inputs.reset();
  outputs.reset();
  iree_vm_module_release(hal_module);
  iree_vm_module_release(input_module);
  iree_vm_context_release(context);

  if (FLAG_print_statistics) {
    IREE_IGNORE_ERROR(iree_hal_allocator_statistics_fprint(
        stderr, iree_hal_device_allocator(device)));
  }

  iree_hal_device_release(device);
  iree_vm_instance_release(instance);
  return iree_ok_status();
}

}  // namespace

extern "C" int main(int argc, char** argv) {
  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_DEFAULT, &argc, &argv);
  if (argc > 1) {
    // Avoid iree-run-module spinning endlessly on stdin if the user uses single
    // dashes for flags.
    std::cout << "Error: unexpected positional argument (expected none)."
                 " Did you use pass a flag with a single dash ('-')?"
                 " Use '--' instead.\n";
    return 1;
  }
  IREE_CHECK_OK(iree_hal_register_all_available_drivers(
      iree_hal_driver_registry_default()));
  IREE_CHECK_OK(Run());
  return 0;
}

}  // namespace iree
<commit_msg>Disabling --print_statistics by default.<commit_after>// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <array>
#include <cstdio>
#include <iostream>
#include <iterator>
#include <string>
#include <utility>
#include <vector>

#include "iree/base/api.h"
#include "iree/base/internal/file_io.h"
#include "iree/base/internal/flags.h"
#include "iree/base/status_cc.h"
#include "iree/base/tracing.h"
#include "iree/hal/api.h"
#include "iree/hal/drivers/init.h"
#include "iree/modules/hal/module.h"
#include "iree/tools/utils/vm_util.h"
#include "iree/vm/api.h"
#include "iree/vm/bytecode_module.h"
#include "iree/vm/ref_cc.h"

IREE_FLAG(string, module_file, "-",
          "File containing the module to load that contains the entry "
          "function. Defaults to stdin.");

IREE_FLAG(string, entry_function, "",
          "Name of a function contained in the module specified by module_file "
          "to run.");

IREE_FLAG(string, driver, "vmvx", "Backend driver to use.");

IREE_FLAG(bool, print_statistics, false,
          "Prints runtime statistics to stderr on exit.");

static iree_status_t parse_function_input(iree_string_view_t flag_name,
                                          void* storage,
                                          iree_string_view_t value) {
  auto* list = (std::vector<std::string>*)storage;
  list->push_back(std::string(value.data, value.size));
  return iree_ok_status();
}
static void print_function_input(iree_string_view_t flag_name, void* storage,
                                 FILE* file) {
  auto* list = (std::vector<std::string>*)storage;
  if (list->empty()) {
    fprintf(file, "# --%.*s=\n", (int)flag_name.size, flag_name.data);
  } else {
    for (size_t i = 0; i < list->size(); ++i) {
      fprintf(file, "--%.*s=\"%s\"\n", (int)flag_name.size, flag_name.data,
              list->at(i).c_str());
    }
  }
}
static std::vector<std::string> FLAG_function_inputs;
IREE_FLAG_CALLBACK(
    parse_function_input, print_function_input, &FLAG_function_inputs,
    function_input,
    "An input value or buffer of the format:\n"
    "  [shape]xtype=[value]\n"
    "  2x2xi32=1 2 3 4\n"
    "Optionally, brackets may be used to separate the element values:\n"
    "  2x2xi32=[[1 2][3 4]]\n"
    "Each occurrence of the flag indicates an input in the order they were\n"
    "specified on the command line.");

namespace iree {
namespace {

iree_status_t GetModuleContentsFromFlags(std::string* out_contents) {
  IREE_TRACE_SCOPE0("GetModuleContentsFromFlags");
  auto module_file = std::string(FLAG_module_file);
  if (module_file == "-") {
    *out_contents = std::string{std::istreambuf_iterator<char>(std::cin),
                                std::istreambuf_iterator<char>()};
  } else {
    IREE_RETURN_IF_ERROR(GetFileContents(module_file.c_str(), out_contents));
  }
  return iree_ok_status();
}

iree_status_t Run() {
  IREE_TRACE_SCOPE0("iree-run-module");

  IREE_RETURN_IF_ERROR(iree_hal_module_register_types(),
                       "registering HAL types");
  iree_vm_instance_t* instance = nullptr;
  IREE_RETURN_IF_ERROR(
      iree_vm_instance_create(iree_allocator_system(), &instance),
      "creating instance");

  std::string module_data;
  IREE_RETURN_IF_ERROR(GetModuleContentsFromFlags(&module_data));
  iree_vm_module_t* input_module = nullptr;
  IREE_RETURN_IF_ERROR(iree_vm_bytecode_module_create(
      iree_make_const_byte_span((void*)module_data.data(), module_data.size()),
      iree_allocator_null(), iree_allocator_system(), &input_module));

  iree_hal_device_t* device = nullptr;
  IREE_RETURN_IF_ERROR(CreateDevice(FLAG_driver, &device));
  iree_vm_module_t* hal_module = nullptr;
  IREE_RETURN_IF_ERROR(
      iree_hal_module_create(device, iree_allocator_system(), &hal_module));

  iree_vm_context_t* context = nullptr;
  // Order matters. The input module will likely be dependent on the hal module.
  std::array<iree_vm_module_t*, 2> modules = {hal_module, input_module};
  IREE_RETURN_IF_ERROR(iree_vm_context_create_with_modules(
                           instance, modules.data(), modules.size(),
                           iree_allocator_system(), &context),
                       "creating context");

  std::string function_name = std::string(FLAG_entry_function);
  iree_vm_function_t function;
  if (function_name.empty()) {
    return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
                            "no --entry_function= specified");
  } else {
    IREE_RETURN_IF_ERROR(
        input_module->lookup_function(
            input_module->self, IREE_VM_FUNCTION_LINKAGE_EXPORT,
            iree_string_view_t{function_name.data(), function_name.size()},
            &function),
        "looking up function '%s'", function_name.c_str());
  }

  vm::ref<iree_vm_list_t> inputs;
  IREE_CHECK_OK(ParseToVariantList(
      iree_hal_device_allocator(device),
      iree::span<const std::string>{FLAG_function_inputs.data(),
                                    FLAG_function_inputs.size()},
      &inputs));

  vm::ref<iree_vm_list_t> outputs;
  IREE_RETURN_IF_ERROR(iree_vm_list_create(/*element_type=*/nullptr, 16,
                                           iree_allocator_system(), &outputs));

  std::cout << "EXEC @" << function_name << "\n";
  IREE_RETURN_IF_ERROR(
      iree_vm_invoke(context, function, /*policy=*/nullptr, inputs.get(),
                     outputs.get(), iree_allocator_system()),
      "invoking function '%s'", function_name.c_str());

  IREE_RETURN_IF_ERROR(PrintVariantList(outputs.get()), "printing results");

  inputs.reset();
  outputs.reset();
  iree_vm_module_release(hal_module);
  iree_vm_module_release(input_module);
  iree_vm_context_release(context);

  if (FLAG_print_statistics) {
    IREE_IGNORE_ERROR(iree_hal_allocator_statistics_fprint(
        stderr, iree_hal_device_allocator(device)));
  }

  iree_hal_device_release(device);
  iree_vm_instance_release(instance);
  return iree_ok_status();
}

}  // namespace

extern "C" int main(int argc, char** argv) {
  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_DEFAULT, &argc, &argv);
  if (argc > 1) {
    // Avoid iree-run-module spinning endlessly on stdin if the user uses single
    // dashes for flags.
    std::cout << "Error: unexpected positional argument (expected none)."
                 " Did you use pass a flag with a single dash ('-')?"
                 " Use '--' instead.\n";
    return 1;
  }
  IREE_CHECK_OK(iree_hal_register_all_available_drivers(
      iree_hal_driver_registry_default()));
  IREE_CHECK_OK(Run());
  return 0;
}

}  // namespace iree
<|endoftext|>


<commit_before>// Copyright (C) 2015 The Regents of the University of California (Regents).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//
//     * Neither the name of The Regents or University of California nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include <Eigen/Core>
#include <Eigen/Geometry>
#include <glog/logging.h>
#include <gflags/gflags.h>
#include <theia/theia.h>

#include <algorithm>
#include <memory>
#include <string>

DEFINE_string(reference_reconstruction, "",
              "Filepath to the reconstruction that is considered the reference "
              "or 'ground truth' reconstruction.");
DEFINE_string(reconstruction_to_align, "",
              "Filepath to the reconstruction that will be aligned to the "
              "ground truth reconstruction. The reported errors/distance are "
              "the distances from this to the reference reconstruction after a "
              "robust alignment has been performed.");
DEFINE_double(robust_alignment_threshold, 0.0,
              "If greater than 0.0, this threshold sets determines inliers for "
              "RANSAC alignment of reconstructions. The inliers are then used "
              "for a least squares alignment.");

using theia::Reconstruction;
using theia::TrackId;
using theia::ViewId;

std::string PrintMeanMedianHistogram(
    const std::vector<double>& sorted_errors,
    const std::vector<double>& histogram_bins) {
  double mean = 0;
  theia::Histogram<double> histogram(histogram_bins);
  for (const auto& error : sorted_errors) {
    histogram.Add(error);
    mean += error;
  }

  mean /= static_cast<double>(sorted_errors.size());
  const std::string error_msg = theia::StringPrintf(
      "Mean = %lf\nMedian = %lf\nHistogram:\n%s",
      mean,
      sorted_errors[sorted_errors.size() / 2],
      histogram.PrintString().c_str());
  return error_msg;
}

double AngularDifference(const Eigen::Vector3d& rotation1,
                         const Eigen::Vector3d& rotation2) {
  Eigen::Matrix3d rotation1_mat(
      Eigen::AngleAxisd(rotation1.norm(), rotation1.normalized()));
  Eigen::Matrix3d rotation2_mat(
      Eigen::AngleAxisd(rotation2.norm(), rotation2.normalized()));
  Eigen::Matrix3d rotation_loop = rotation1_mat.transpose() * rotation2_mat;
  return Eigen::AngleAxisd(rotation_loop).angle();
}

// Aligns the orientations of the models (ignoring the positions) and reports
// the difference in orientations after alignment.
void EvaluateRotations(const Reconstruction& reference_reconstruction,
                       const Reconstruction& reconstruction_to_align,
                       const std::vector<std::string>& common_view_names) {
  // Gather all the rotations in common with both views.
  std::vector<Eigen::Vector3d> rotations1, rotations2;
  rotations1.reserve(common_view_names.size());
  rotations2.reserve(common_view_names.size());
  for (const std::string& view_name : common_view_names) {
    const ViewId view_id1 = reference_reconstruction.ViewIdFromName(view_name);
    const ViewId view_id2 = reconstruction_to_align.ViewIdFromName(view_name);
    rotations1.push_back(reference_reconstruction.View(view_id1)
                             ->Camera()
                             .GetOrientationAsAngleAxis());
    rotations2.push_back(reconstruction_to_align.View(view_id2)
                             ->Camera()
                             .GetOrientationAsAngleAxis());
  }

  // Align the rotation estimations.
  theia::AlignRotations(rotations1, &rotations2);

  // Measure the difference in rotations.
  std::vector<double> rotation_error_degrees(rotations1.size());
  for (int i = 0; i < rotations1.size(); i++) {
    rotation_error_degrees[i] = AngularDifference(rotations1[i], rotations2[i]);
  }
  std::sort(rotation_error_degrees.begin(), rotation_error_degrees.end());

  std::vector<double> histogram_bins = {1, 2, 5, 10, 15, 20, 45};
  const std::string rotation_error_msg =
      PrintMeanMedianHistogram(rotation_error_degrees, histogram_bins);
  LOG(INFO) << "Rotation difference when aligning orientations:\n"
            << rotation_error_msg;
}

// Align the reconstructions then evaluate the pose errors.
void EvaluateAlignedPoseError(
    const std::vector<std::string>& common_view_names,
    const Reconstruction& reference_reconstruction,
    Reconstruction* reconstruction_to_align) {
  if (FLAGS_robust_alignment_threshold > 0.0) {
    AlignReconstructionsRobust(FLAGS_robust_alignment_threshold,
                               reference_reconstruction,
                               reconstruction_to_align);
  } else {
    AlignReconstructions(reference_reconstruction, reconstruction_to_align);
  }

  std::vector<double> rotation_bins = {1, 2, 5, 10, 15, 20, 45};
  std::vector<double> position_bins = {1, 5, 10, 50, 100, 1000 };
  theia::PoseError pose_error(rotation_bins, position_bins);
  std::vector<double> focal_length_errors(common_view_names.size());
  for (int i = 0; i < common_view_names.size(); i++) {
    const ViewId view_id1 =
        reference_reconstruction.ViewIdFromName(common_view_names[i]);
    const ViewId view_id2 =
        reconstruction_to_align->ViewIdFromName(common_view_names[i]);
    const theia::Camera& camera1 =
        reference_reconstruction.View(view_id1)->Camera();
    const theia::Camera& camera2 =
        reconstruction_to_align->View(view_id2)->Camera();

    // Rotation error.
    const double rotation_error =
        AngularDifference(camera1.GetOrientationAsAngleAxis(),
                          camera2.GetOrientationAsAngleAxis());

    // Position error.
    const double position_error =
        (camera1.GetPosition() - camera2.GetPosition()).norm();
    pose_error.AddError(rotation_error, position_error);

    // Focal length error.
    focal_length_errors[i] =
        std::abs(camera1.FocalLength() - camera2.FocalLength()) /
        camera1.FocalLength();
  }
  LOG(INFO) << "Pose error:\n" << pose_error.PrintMeanMedianHistogram();

  std::sort(focal_length_errors.begin(), focal_length_errors.end());
  std::vector<double> histogram_bins = {0.01, 0.05, 0.2, 0.5, 1, 10, 100};
  const std::string focal_length_error_msg =
      PrintMeanMedianHistogram(focal_length_errors, histogram_bins);
  LOG(INFO) << "Focal length errors: \n" << focal_length_error_msg;
}

void ComputeTrackLengthHistogram(const Reconstruction& reconstruction) {
  std::vector<int> histogram_bins = {2, 3,  4,  5,  6,  7, 8,
                                     9, 10, 15, 20, 25, 50};
  theia::Histogram<int> histogram(histogram_bins);
  for (const TrackId track_id : reconstruction.TrackIds()) {
    const theia::Track* track = reconstruction.Track(track_id);
    histogram.Add(track->NumViews());
  }
  const std::string hist_msg = histogram.PrintString();
  LOG(INFO) << "Track lengths = \n" << hist_msg;
}

int main(int argc, char* argv[]) {
  google::InitGoogleLogging(argv[0]);
  THEIA_GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);

  std::unique_ptr<Reconstruction> reference_reconstruction(
      new Reconstruction());
  CHECK(theia::ReadReconstruction(FLAGS_reference_reconstruction,
                                  reference_reconstruction.get()))
      << "Could not read ground truth reconstruction file:"
      << FLAGS_reference_reconstruction;

  std::unique_ptr<Reconstruction> reconstruction_to_align(new Reconstruction());
  CHECK(theia::ReadReconstruction(FLAGS_reconstruction_to_align,
                                  reconstruction_to_align.get()))
      << "Could not read reconstruction file:" << FLAGS_reconstruction_to_align;

  const std::vector<std::string> common_view_names =
      theia::FindCommonViewsByName(*reference_reconstruction,
                                   *reconstruction_to_align);

  // Compare number of cameras.
  LOG(INFO) << "Number of cameras:\n"
            << "\tReconstruction 1: " << reference_reconstruction->NumViews()
            << "\n\tReconstruction 2: " << reconstruction_to_align->NumViews()
            << "\n\tNumber of Common cameras: "
            << common_view_names.size();

  // Compare number of 3d points.
  LOG(INFO) << "Number of 3d points:\n"
            << "\tReconstruction 1: " << reference_reconstruction->NumTracks()
            << "\n\tReconstruction 2: " << reconstruction_to_align->NumTracks();

  // Evaluate rotation independent of positions.
  EvaluateRotations(*reference_reconstruction,
                    *reconstruction_to_align,
                    common_view_names);

  // Align models and evaluate position and rotation errors.
  EvaluateAlignedPoseError(common_view_names,
                           *reference_reconstruction,
                           reconstruction_to_align.get());

  return 0;
}
<commit_msg>Bug fix for the case when two reconstructions have no vies in common.<commit_after>// Copyright (C) 2015 The Regents of the University of California (Regents).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//
//     * Neither the name of The Regents or University of California nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include <Eigen/Core>
#include <Eigen/Geometry>
#include <glog/logging.h>
#include <gflags/gflags.h>
#include <theia/theia.h>

#include <algorithm>
#include <memory>
#include <string>

DEFINE_string(reference_reconstruction, "",
              "Filepath to the reconstruction that is considered the reference "
              "or 'ground truth' reconstruction.");
DEFINE_string(reconstruction_to_align, "",
              "Filepath to the reconstruction that will be aligned to the "
              "ground truth reconstruction. The reported errors/distance are "
              "the distances from this to the reference reconstruction after a "
              "robust alignment has been performed.");
DEFINE_double(robust_alignment_threshold, 0.0,
              "If greater than 0.0, this threshold sets determines inliers for "
              "RANSAC alignment of reconstructions. The inliers are then used "
              "for a least squares alignment.");

using theia::Reconstruction;
using theia::TrackId;
using theia::ViewId;

std::string PrintMeanMedianHistogram(
    const std::vector<double>& sorted_errors,
    const std::vector<double>& histogram_bins) {
  double mean = 0;
  theia::Histogram<double> histogram(histogram_bins);
  for (const auto& error : sorted_errors) {
    histogram.Add(error);
    mean += error;
  }

  mean /= static_cast<double>(sorted_errors.size());
  const std::string error_msg = theia::StringPrintf(
      "Mean = %lf\nMedian = %lf\nHistogram:\n%s",
      mean,
      sorted_errors[sorted_errors.size() / 2],
      histogram.PrintString().c_str());
  return error_msg;
}

double AngularDifference(const Eigen::Vector3d& rotation1,
                         const Eigen::Vector3d& rotation2) {
  Eigen::Matrix3d rotation1_mat(
      Eigen::AngleAxisd(rotation1.norm(), rotation1.normalized()));
  Eigen::Matrix3d rotation2_mat(
      Eigen::AngleAxisd(rotation2.norm(), rotation2.normalized()));
  Eigen::Matrix3d rotation_loop = rotation1_mat.transpose() * rotation2_mat;
  return Eigen::AngleAxisd(rotation_loop).angle();
}

// Aligns the orientations of the models (ignoring the positions) and reports
// the difference in orientations after alignment.
void EvaluateRotations(const Reconstruction& reference_reconstruction,
                       const Reconstruction& reconstruction_to_align,
                       const std::vector<std::string>& common_view_names) {
  // Gather all the rotations in common with both views.
  std::vector<Eigen::Vector3d> rotations1, rotations2;
  rotations1.reserve(common_view_names.size());
  rotations2.reserve(common_view_names.size());
  for (const std::string& view_name : common_view_names) {
    const ViewId view_id1 = reference_reconstruction.ViewIdFromName(view_name);
    const ViewId view_id2 = reconstruction_to_align.ViewIdFromName(view_name);
    rotations1.push_back(reference_reconstruction.View(view_id1)
                             ->Camera()
                             .GetOrientationAsAngleAxis());
    rotations2.push_back(reconstruction_to_align.View(view_id2)
                             ->Camera()
                             .GetOrientationAsAngleAxis());
  }

  // Align the rotation estimations.
  theia::AlignRotations(rotations1, &rotations2);

  // Measure the difference in rotations.
  std::vector<double> rotation_error_degrees(rotations1.size());
  for (int i = 0; i < rotations1.size(); i++) {
    rotation_error_degrees[i] = AngularDifference(rotations1[i], rotations2[i]);
  }
  std::sort(rotation_error_degrees.begin(), rotation_error_degrees.end());

  std::vector<double> histogram_bins = {1, 2, 5, 10, 15, 20, 45};
  const std::string rotation_error_msg =
      PrintMeanMedianHistogram(rotation_error_degrees, histogram_bins);
  LOG(INFO) << "Rotation difference when aligning orientations:\n"
            << rotation_error_msg;
}

// Align the reconstructions then evaluate the pose errors.
void EvaluateAlignedPoseError(
    const std::vector<std::string>& common_view_names,
    const Reconstruction& reference_reconstruction,
    Reconstruction* reconstruction_to_align) {
  if (FLAGS_robust_alignment_threshold > 0.0) {
    AlignReconstructionsRobust(FLAGS_robust_alignment_threshold,
                               reference_reconstruction,
                               reconstruction_to_align);
  } else {
    AlignReconstructions(reference_reconstruction, reconstruction_to_align);
  }

  std::vector<double> rotation_bins = {1, 2, 5, 10, 15, 20, 45};
  std::vector<double> position_bins = {1, 5, 10, 50, 100, 1000 };
  theia::PoseError pose_error(rotation_bins, position_bins);
  std::vector<double> focal_length_errors(common_view_names.size());
  for (int i = 0; i < common_view_names.size(); i++) {
    const ViewId view_id1 =
        reference_reconstruction.ViewIdFromName(common_view_names[i]);
    const ViewId view_id2 =
        reconstruction_to_align->ViewIdFromName(common_view_names[i]);
    const theia::Camera& camera1 =
        reference_reconstruction.View(view_id1)->Camera();
    const theia::Camera& camera2 =
        reconstruction_to_align->View(view_id2)->Camera();

    // Rotation error.
    const double rotation_error =
        AngularDifference(camera1.GetOrientationAsAngleAxis(),
                          camera2.GetOrientationAsAngleAxis());

    // Position error.
    const double position_error =
        (camera1.GetPosition() - camera2.GetPosition()).norm();
    pose_error.AddError(rotation_error, position_error);

    // Focal length error.
    focal_length_errors[i] =
        std::abs(camera1.FocalLength() - camera2.FocalLength()) /
        camera1.FocalLength();
  }
  LOG(INFO) << "Pose error:\n" << pose_error.PrintMeanMedianHistogram();

  std::sort(focal_length_errors.begin(), focal_length_errors.end());
  std::vector<double> histogram_bins = {0.01, 0.05, 0.2, 0.5, 1, 10, 100};
  const std::string focal_length_error_msg =
      PrintMeanMedianHistogram(focal_length_errors, histogram_bins);
  LOG(INFO) << "Focal length errors: \n" << focal_length_error_msg;
}

void ComputeTrackLengthHistogram(const Reconstruction& reconstruction) {
  std::vector<int> histogram_bins = {2, 3,  4,  5,  6,  7, 8,
                                     9, 10, 15, 20, 25, 50};
  theia::Histogram<int> histogram(histogram_bins);
  for (const TrackId track_id : reconstruction.TrackIds()) {
    const theia::Track* track = reconstruction.Track(track_id);
    histogram.Add(track->NumViews());
  }
  const std::string hist_msg = histogram.PrintString();
  LOG(INFO) << "Track lengths = \n" << hist_msg;
}

int main(int argc, char* argv[]) {
  google::InitGoogleLogging(argv[0]);
  THEIA_GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);

  std::unique_ptr<Reconstruction> reference_reconstruction(
      new Reconstruction());
  CHECK(theia::ReadReconstruction(FLAGS_reference_reconstruction,
                                  reference_reconstruction.get()))
      << "Could not read ground truth reconstruction file:"
      << FLAGS_reference_reconstruction;

  std::unique_ptr<Reconstruction> reconstruction_to_align(new Reconstruction());
  CHECK(theia::ReadReconstruction(FLAGS_reconstruction_to_align,
                                  reconstruction_to_align.get()))
      << "Could not read reconstruction file:" << FLAGS_reconstruction_to_align;

  const std::vector<std::string> common_view_names =
      theia::FindCommonViewsByName(*reference_reconstruction,
                                   *reconstruction_to_align);

  // Compare number of cameras.
  LOG(INFO) << "Number of cameras:\n"
            << "\tReconstruction 1: " << reference_reconstruction->NumViews()
            << "\n\tReconstruction 2: " << reconstruction_to_align->NumViews()
            << "\n\tNumber of Common cameras: "
            << common_view_names.size();

  if (common_view_names.size() == 0) {
    LOG(INFO) << "Could not compare reconstructions because they do not have "
                 "any common view names.";
    return 0;
  }

  // Compare number of 3d points.
  LOG(INFO) << "Number of 3d points:\n"
            << "\tReconstruction 1: " << reference_reconstruction->NumTracks()
            << "\n\tReconstruction 2: " << reconstruction_to_align->NumTracks();

  // Evaluate rotation independent of positions.
  EvaluateRotations(*reference_reconstruction,
                    *reconstruction_to_align,
                    common_view_names);

  // Align models and evaluate position and rotation errors.
  EvaluateAlignedPoseError(common_view_names,
                           *reference_reconstruction,
                           reconstruction_to_align.get());

  return 0;
}
<|endoftext|>


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

#include <iterator>
#include <memory>
#include <random>
#include "GLFWOSPRayWindow.h"

#include "ospcommon/library.h"
#include "ospcommon/FileName.h"
#include "ospcommon/utility/ArrayView.h"
#include "ospcommon/range.h"
#include "ospray_testing.h"

#include <imgui.h>

using namespace ospcommon;

static const std::string renderer_type = "scivis";

// ALOK: AMRVolume context info
std::vector<osp_amr_brick_info> brickInfo; // holds brick metadata
std::vector<float *> brickPtrs;            // holds actual data
std::vector<OSPData> brickData;            // holds actual data as OSPData
range1f valueRange;
float *actualData;

// ALOK: TODO
// this is ugly
// somehow we're using vec/box types that don't have size() or
// product(). that needs to change!
int numCellsInBrick(const osp_amr_brick_info &bi)
{
    vec3i size = {bi.bounds.upper.x - bi.bounds.lower.x + 1,
                  bi.bounds.upper.y - bi.bounds.lower.y + 1,
                  bi.bounds.upper.z - bi.bounds.lower.z + 1};
    int product = size.x * size.y * size.z;
    return product;
}

std::ostream &operator<<(std::ostream &os, const osp_vec3i &v)
{
    os << "<" << v.x << ", " <<
                 v.y << ", " <<
                 v.z << ">";
    return os;
}

std::ostream &operator<<(std::ostream &os, const osp_amr_brick_info &bi)
{
    os << "    ________" << std::endl
       << "   /\\       \\      bounds lower" << std::endl
       << "  /::\\       \\      " << bi.bounds.lower << std::endl
       << " /::::\\       \\    bounds upper" << std::endl
       << " \\:::::\\       \\    " << bi.bounds.upper << std::endl
       << "  \\:::::\\       \\  refinementLevel" << std::endl
       << "   \\:::::\\_______\\  " << bi.refinementLevel << std::endl
       << "    \\::::/ZZZZZZZ/ cellWidth" << std::endl
       << "     \\::/ZZZZZZZ/   " << bi.cellWidth << std::endl
       << "      \\/ZZZZZZZ/" << std::endl;
    return os;
}

void parseRaw2AmrFile(const FileName &fileName,
                      int BS,
                      int maxLevel)
{
    // filename arg needs to be base filename without extension
    FileName infoFileName = fileName.str() + std::string(".info");
    FileName dataFileName = fileName.str() + std::string(".data");

    FILE *infoFile = fopen(infoFileName.c_str(), "rb");
    FILE *dataFile = fopen(dataFileName.c_str(), "rb");

    if (infoFile == nullptr) {
        throw std::runtime_error(std::string("#osp:sg - ERROR could not open '")
                + infoFileName.c_str() + "'");
    }

    if (dataFile == nullptr) {
        throw std::runtime_error(std::string("#osp:sg - ERROR could not open '")
                + dataFileName.c_str() + "'");
    }

    osp_amr_brick_info bi;

    auto bounds = box3f(-1, 1);
    auto numCells = BS * BS * BS;

    // populate brickInfo and brickPtrs
    // by reading in osp_amr_brick_info structs from infoFile
    // and reading corresponding data from dataFile
    while (fread(&bi, sizeof(bi), 1, infoFile)) {
        if(bi.refinementLevel > maxLevel) {
            // ALOK: need to move the data file pointer forward
            // so that we're reading the correct data from next
            // block
            fseek(dataFile, numCells * sizeof(float), SEEK_CUR);
            continue;
        }

        //std::cout << bi << std::endl;

        utility::ArrayView<float> bd(new float[numCells], numCells);

        int nr = fread(bd.data(), sizeof(float), numCells, dataFile);
        UNUSED(nr);

        // ALOK: this is ugly way of doing bounds.extend
        // did it this way because there's no copy constructor between f and i
        brickInfo.push_back(bi);
        vec3f boundsf = {bi.bounds.upper.x,
                         bi.bounds.upper.y,
                         bi.bounds.upper.z};
        boundsf += vec3f(1.f);
        bounds.extend(boundsf * bi.cellWidth);

        assert(nr == numCells);
        for (const auto &c : bd)
            valueRange.extend(c);

        brickPtrs.push_back(bd);
    }

    fclose(infoFile);
    fclose(dataFile);
}

OSPVolume createDummyAMRVolume()
{
    // ALOK: TODO
    // create a testing volume, e.g. gravity spheres,
    // run raw2amr on it,
    // and return that volume
    OSPVolume dummy = ospNewVolume("amr_volume");
    ospSetString(dummy, "voxelType", "float");

    //FileName fname("/mnt/ssd/test_data/test_amr");
    FileName fname("/mnt/ssd/magnetic_amr");
    parseRaw2AmrFile(fname, 4, 3);

    // ALOK: taken from ospray/master's AMRVolume::preCommit()
    // convert raw pointers in brickPtrs to OSPData in brickData
    for(size_t bID = 0; bID < brickInfo.size(); bID++) {
        const osp_amr_brick_info &bi = brickInfo[bID];
        int numCells = numCellsInBrick(bi);
        OSPData data = ospNewData(numCells, OSP_FLOAT, brickPtrs[bID], OSP_DATA_SHARED_BUFFER);
        brickData.push_back(data);
    }

    OSPData brickInfoData = ospNewData(brickInfo.size()*sizeof(osp_amr_brick_info), OSP_RAW, brickInfo.data());
    ospCommit(brickInfoData);

    OSPData brickDataData = ospNewData(brickData.size(), OSP_DATA, brickData.data(), OSP_DATA_SHARED_BUFFER);
    ospCommit(brickDataData);

    ospSetData(dummy, "brickInfo", brickInfoData);
    ospSetData(dummy, "brickData", brickDataData);

    osp_vec2f amrValueRange = {valueRange.lower, valueRange.upper};
    OSPTransferFunction tf = ospTestingNewTransferFunction(amrValueRange, "jet");

    ospSetObject(dummy, "transferFunction", tf);
    ospCommit(dummy);

    return dummy;
}

int main(int argc, const char **argv)
{
  // initialize OSPRay; OSPRay parses (and removes) its commandline parameters,
  // e.g. "--osp:debug"
  OSPError initError = ospInit(&argc, argv);

  if (initError != OSP_NO_ERROR)
    return initError;

  // we must load the testing library explicitly on Windows to look up
  // object creation functions
  loadLibrary("ospray_testing");

  // set an error callback to catch any OSPRay errors and exit the application
  ospDeviceSetErrorFunc(
      ospGetCurrentDevice(), [](OSPError error, const char *errorDetails) {
        std::cerr << "OSPRay error: " << errorDetails << std::endl;
        exit(error);
      });

  // create the world which will contain all of our geometries
  OSPWorld world = ospNewWorld();

  // add in AMR volume
  OSPVolume amrVolume = createDummyAMRVolume();

  // add volume to the world
  ospAddVolume(world, amrVolume);
  box3f bounds(-1, 1);

  // commit the world
  ospCommit(world);

  // create OSPRay renderer
  OSPRenderer renderer = ospNewRenderer(renderer_type.c_str());

  OSPData lightsData = ospTestingNewLights("ambient_only");
  ospSetData(renderer, "lights", lightsData);
  ospRelease(lightsData);

  ospCommit(renderer);

  // create a GLFW OSPRay window: this object will create and manage the OSPRay
  // frame buffer and camera directly
  auto glfwOSPRayWindow =
      std::unique_ptr<GLFWOSPRayWindow>(new GLFWOSPRayWindow(
          vec2i{1024, 768}, bounds, world, renderer));

  glfwOSPRayWindow->registerImGuiCallback([&]() {
    static int spp = 1;
    if (ImGui::SliderInt("spp", &spp, 1, 64)) {
      ospSet1i(renderer, "spp", spp);
      glfwOSPRayWindow->addObjectToCommit(renderer);
    }
  });

  // start the GLFW main loop, which will continuously render
  glfwOSPRayWindow->mainLoop();

  // cleanly shut OSPRay down
  ospShutdown();

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

#include <iterator>
#include <memory>
#include <random>
#include "GLFWOSPRayWindow.h"

#include "ospcommon/library.h"
#include "ospcommon/FileName.h"
#include "ospcommon/utility/ArrayView.h"
#include "ospcommon/range.h"
#include "ospray_testing.h"

#include <imgui.h>

using namespace ospcommon;

static const std::string renderer_type = "scivis";

// ALOK: AMRVolume context info
std::vector<osp_amr_brick_info> brickInfo; // holds brick metadata
std::vector<float *> brickPtrs;            // holds actual data
std::vector<OSPData> brickData;            // holds actual data as OSPData
range1f valueRange;
float *actualData;

// ALOK: TODO
// this is ugly
// somehow we're using vec/box types that don't have size() or
// product(). that needs to change!
int numCellsInBrick(const osp_amr_brick_info &bi)
{
    vec3i size = {bi.bounds[0] - bi.bounds[3] + 1,
                  bi.bounds[1] - bi.bounds[4] + 1,
                  bi.bounds[2] - bi.bounds[5] + 1};
    int product = size.x * size.y * size.z;
    return product;
}

std::ostream &operator<<(std::ostream &os, const vec3i &v)
{
    os << "<" << v.x << ", " <<
                 v.y << ", " <<
                 v.z << ">";
    return os;
}

std::ostream &operator<<(std::ostream &os, const osp_amr_brick_info &bi)
{
    os << "    ________" << std::endl
       << "   /\\       \\      bounds lower" << std::endl
       << "  /::\\       \\      " << bi.bounds[0] << " " <<  bi.bounds[1] << " " << bi.bounds[2] << " " << std::endl
       << " /::::\\       \\    bounds upper" << std::endl
       << " \\:::::\\       \\    " << bi.bounds[3] << " " <<  bi.bounds[4] << " " << bi.bounds[5] << " " << std::endl
       << "  \\:::::\\       \\  refinementLevel" << std::endl
       << "   \\:::::\\_______\\  " << bi.refinementLevel << std::endl
       << "    \\::::/ZZZZZZZ/ cellWidth" << std::endl
       << "     \\::/ZZZZZZZ/   " << bi.cellWidth << std::endl
       << "      \\/ZZZZZZZ/" << std::endl;
    return os;
}

void parseRaw2AmrFile(const FileName &fileName,
                      int BS,
                      int maxLevel)
{
    // filename arg needs to be base filename without extension
    FileName infoFileName = fileName.str() + std::string(".info");
    FileName dataFileName = fileName.str() + std::string(".data");

    FILE *infoFile = fopen(infoFileName.c_str(), "rb");
    FILE *dataFile = fopen(dataFileName.c_str(), "rb");

    if (infoFile == nullptr) {
        throw std::runtime_error(std::string("#osp:sg - ERROR could not open '")
                + infoFileName.c_str() + "'");
    }

    if (dataFile == nullptr) {
        throw std::runtime_error(std::string("#osp:sg - ERROR could not open '")
                + dataFileName.c_str() + "'");
    }

    osp_amr_brick_info bi;

    auto bounds = box3f(-1, 1);
    auto numCells = BS * BS * BS;

    // populate brickInfo and brickPtrs
    // by reading in osp_amr_brick_info structs from infoFile
    // and reading corresponding data from dataFile
    while (fread(&bi, sizeof(bi), 1, infoFile)) {
        if(bi.refinementLevel > maxLevel) {
            // ALOK: need to move the data file pointer forward
            // so that we're reading the correct data from next
            // block
            fseek(dataFile, numCells * sizeof(float), SEEK_CUR);
            continue;
        }

        //std::cout << bi << std::endl;

        utility::ArrayView<float> bd(new float[numCells], numCells);

        int nr = fread(bd.data(), sizeof(float), numCells, dataFile);
        UNUSED(nr);

        // ALOK: this is ugly way of doing bounds.extend
        // did it this way because there's no copy constructor between f and i
        brickInfo.push_back(bi);
        vec3f boundsf = {bi.bounds[0],
                         bi.bounds[1],
                         bi.bounds[2]};
        boundsf += vec3f(1.f);
        bounds.extend(boundsf * bi.cellWidth);

        assert(nr == numCells);
        for (const auto &c : bd)
            valueRange.extend(c);

        brickPtrs.push_back(bd);
    }

    fclose(infoFile);
    fclose(dataFile);
}

OSPVolume createDummyAMRVolume()
{
    // ALOK: TODO
    // create a testing volume, e.g. gravity spheres,
    // run raw2amr on it,
    // and return that volume
    OSPVolume dummy = ospNewVolume("amr_volume");
    ospSetString(dummy, "voxelType", "float");

    //FileName fname("/mnt/ssd/test_data/test_amr");
    FileName fname("/mnt/ssd/magnetic_amr");
    parseRaw2AmrFile(fname, 4, 3);

    // ALOK: taken from ospray/master's AMRVolume::preCommit()
    // convert raw pointers in brickPtrs to OSPData in brickData
    for(size_t bID = 0; bID < brickInfo.size(); bID++) {
        const osp_amr_brick_info &bi = brickInfo[bID];
        int numCells = numCellsInBrick(bi);
        OSPData data = ospNewData(numCells, OSP_FLOAT, brickPtrs[bID], OSP_DATA_SHARED_BUFFER);
        brickData.push_back(data);
    }

    OSPData brickInfoData = ospNewData(brickInfo.size()*sizeof(osp_amr_brick_info), OSP_RAW, brickInfo.data());
    ospCommit(brickInfoData);

    OSPData brickDataData = ospNewData(brickData.size(), OSP_DATA, brickData.data(), OSP_DATA_SHARED_BUFFER);
    ospCommit(brickDataData);

    ospSetData(dummy, "brickInfo", brickInfoData);
    ospSetData(dummy, "brickData", brickDataData);

    ospCommit(dummy);

    return dummy;
}

int main(int argc, const char **argv)
{
  // initialize OSPRay; OSPRay parses (and removes) its commandline parameters,
  // e.g. "--osp:debug"
  OSPError initError = ospInit(&argc, argv);

  if (initError != OSP_NO_ERROR)
    return initError;

  // we must load the testing library explicitly on Windows to look up
  // object creation functions
  loadLibrary("ospray_testing");

  // set an error callback to catch any OSPRay errors and exit the application
  ospDeviceSetErrorFunc(
      ospGetCurrentDevice(), [](OSPError error, const char *errorDetails) {
        std::cerr << "OSPRay error: " << errorDetails << std::endl;
        exit(error);
      });

  // create the world which will contain all of our geometries
  OSPWorld world = ospNewWorld();

  // add in AMR volume
  OSPVolume amrVolume = createDummyAMRVolume();

  // create a volume instance container
  OSPVolumeInstance instance = ospNewVolumeInstance(amrVolume);

  // apply a transfer function to the instance
  osp_vec2f amrValueRange = {valueRange.lower, valueRange.upper};
  OSPTransferFunction tf = ospTestingNewTransferFunction(amrValueRange, "jet");
  ospSetObject(instance, "transferFunction", tf);
  ospCommit(instance);

  // create a data array of all instances
  OSPData volumeInstances = ospNewData(1, OSP_OBJECT, &instance);

  // add volume instance to the world
  ospSetObject(world, "volumes", volumeInstances);
  box3f bounds(0, 64);

  // commit the world
  ospCommit(world);

  // create OSPRay renderer
  OSPRenderer renderer = ospNewRenderer(renderer_type.c_str());

  OSPData lightsData = ospTestingNewLights("ambient_only");
  ospSetData(renderer, "lights", lightsData);
  ospRelease(lightsData);

  ospCommit(renderer);

  // create a GLFW OSPRay window: this object will create and manage the OSPRay
  // frame buffer and camera directly
  auto glfwOSPRayWindow =
      std::unique_ptr<GLFWOSPRayWindow>(new GLFWOSPRayWindow(
          vec2i{1024, 768}, bounds, world, renderer));

  // start the GLFW main loop, which will continuously render
  glfwOSPRayWindow->mainLoop();

  // cleanly shut OSPRay down
  ospShutdown();

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Make bzflag compile on vc again<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: adoc_tok.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: vg $ $Date: 2007-09-18 14:07:06 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <precomp.h>
#include <adoc/adoc_tok.hxx>

// NOT FULLY DEFINED SERVICES
#include <adoc/atokdeal.hxx>
#include <../cpp/c_dealer.hxx>

namespace adoc {

void
Token::DealOut( ::TokenDealer & o_rDealer )
{
    o_rDealer.AsDistributor()->Deal_AdcDocu(*this);
}

}   // namespace adoc

<commit_msg>INTEGRATION: CWS changefileheader (1.6.26); FILE MERGED 2008/03/28 16:02:21 rt 1.6.26.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: adoc_tok.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <precomp.h>
#include <adoc/adoc_tok.hxx>

// NOT FULLY DEFINED SERVICES
#include <adoc/atokdeal.hxx>
#include <../cpp/c_dealer.hxx>

namespace adoc {

void
Token::DealOut( ::TokenDealer & o_rDealer )
{
    o_rDealer.AsDistributor()->Deal_AdcDocu(*this);
}

}   // namespace adoc

<|endoftext|>


<commit_before>#include "bn_layer_generator_tiramisu.o.h"
#include "Halide.h"
#include <cstdlib>
#include <chrono>
#include <fstream>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include "configure.h"
#include <tiramisu/utils.h>
#include <iomanip>

using namespace std;

int main(int, char **)
{
    Halide::Buffer<float> input(N, N, FIn, BATCH_SIZE);
    Halide::Buffer<float> output(N, N, FIn, BATCH_SIZE);
    Halide::Buffer<int> parameters(3);
    Halide::Buffer<float> mean(N, N, FIn, BATCH_SIZE);
    Halide::Buffer<float> variance(N, N, FIn, BATCH_SIZE);

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

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

    for (int i = 0; i < NB_TESTS; i++)
    {
        auto start1 = std::chrono::high_resolution_clock::now();
        bn_tiramisu(input.raw_buffer(), parameters.raw_buffer(), mean.raw_buffer(), variance.raw_buffer(), output.raw_buffer());
        auto end1 = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> duration = end1 - start1;
        duration_vector_2.push_back(duration);
    }
    std::cout << "\t\tTiramisu BN duration"
              << ": " << median(duration_vector_2) << "; " << std::endl;
    std::ofstream resultfile;
    resultfile.open("tiramisu_result.txt");
    for (int n = 0; n < BATCH_SIZE; ++n)
        for (int z = 0; z < FIn; ++z)
            for (int y = 0; y < N; ++y)
                for (int x = 0; x < N; ++x)
                    resultfile << (float)((int)(output(x, y, z, n) * 100) / 100.0);

    resultfile.close();

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

    FILE *fp1, *fp2;

    char line1[5], line2[5];

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

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

    printf("\t\t Percentage of correctness %f \n\n", corr / file_count * 100);
    return 0;
}
<commit_msg>Delete wrapper_nn.cpp<commit_after><|endoftext|>


<commit_before>/*
  This file is part of KOrganizer.

  Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
  Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeventviewerdialog.h"
#include "koeventviewer.h"
#include <klocale.h>

KOEventViewerDialog::KOEventViewerDialog( QWidget *parent, bool compact )
  : KDialog( parent )
{
  setCaption( i18n( "Event Viewer" ) );
  setButtons( Ok | User1 | User2 );
  setModal( false );
  setButtonGuiItem( User1, KGuiItem( i18n( "Edit..." ) ) );
  setButtonGuiItem( User2, KGuiItem( i18n( "Show in Context" ) ) );
  mEventViewer = new KOEventViewer( this );
  setMainWidget( mEventViewer );

  // FIXME: Set a sensible size (based on the content?).
  if ( compact ) {
    setFixedSize( 240, 284 );
    move( 0, 15 );
  } else {
    setMinimumSize( 300, 200 );
    resize( 320, 300 );
  }
  connect( this, SIGNAL(finished()), this, SLOT(delayedDestruct()) );
  connect( this, SIGNAL( user1Clicked() ), mEventViewer,
           SLOT( editIncidence() ) );
  connect( this, SIGNAL( user2Clicked() ), mEventViewer,
           SLOT( showIncidenceContext() ) );
}

KOEventViewerDialog::~KOEventViewerDialog()
{
}

void KOEventViewerDialog::addText( const QString &text )
{
  mEventViewer->addText(text);
}

#include "koeventviewerdialog.moc"
<commit_msg>Close is better here than Ok<commit_after>/*
  This file is part of KOrganizer.

  Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
  Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeventviewerdialog.h"
#include "koeventviewer.h"
#include <klocale.h>

KOEventViewerDialog::KOEventViewerDialog( QWidget *parent, bool compact )
  : KDialog( parent )
{
  setCaption( i18n( "Event Viewer" ) );
  setButtons( Close | User1 | User2 );
  setModal( false );
  setButtonGuiItem( User1, KGuiItem( i18n( "Edit..." ) ) );
  setButtonGuiItem( User2, KGuiItem( i18n( "Show in Context" ) ) );
  mEventViewer = new KOEventViewer( this );
  setMainWidget( mEventViewer );

  // FIXME: Set a sensible size (based on the content?).
  if ( compact ) {
    setFixedSize( 240, 284 );
    move( 0, 15 );
  } else {
    setMinimumSize( 300, 200 );
    resize( 320, 300 );
  }
  connect( this, SIGNAL(finished()), this, SLOT(delayedDestruct()) );
  connect( this, SIGNAL( user1Clicked() ), mEventViewer,
           SLOT( editIncidence() ) );
  connect( this, SIGNAL( user2Clicked() ), mEventViewer,
           SLOT( showIncidenceContext() ) );
}

KOEventViewerDialog::~KOEventViewerDialog()
{
}

void KOEventViewerDialog::addText( const QString &text )
{
  mEventViewer->addText(text);
}

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


<commit_before><commit_msg>Fixed object_list layouts<commit_after><|endoftext|>


<commit_before><commit_msg>Fixed a logical error in substitution of the selected language with the system language: System language returned by Windows for pt_BR is pt_PT, and this language was then used incorrectly to select the dictionary.<commit_after><|endoftext|>


<commit_before><commit_msg>disabled warning when parsing date time strings<commit_after><|endoftext|>


<commit_before>//===- MultiplexConsumer.cpp - AST Consumer for PCH Generation --*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the MultiplexConsumer class. It also declares and defines
//  MultiplexASTDeserializationListener and  MultiplexASTMutationListener, which
//  are implementation details of MultiplexConsumer.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/MultiplexConsumer.h"

#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Serialization/ASTDeserializationListener.h"

using namespace clang;

namespace clang {

// This ASTDeserializationListener forwards its notifications to a set of
// child listeners.
class MultiplexASTDeserializationListener
    : public ASTDeserializationListener {
public:
  // Does NOT take ownership of the elements in L.
  MultiplexASTDeserializationListener(
      const std::vector<ASTDeserializationListener*>& L);
  virtual void ReaderInitialized(ASTReader *Reader);
  virtual void IdentifierRead(serialization::IdentID ID,
                              IdentifierInfo *II);
  virtual void TypeRead(serialization::TypeIdx Idx, QualType T);
  virtual void DeclRead(serialization::DeclID ID, const Decl *D);
  virtual void SelectorRead(serialization::SelectorID iD, Selector Sel);
  virtual void MacroDefinitionRead(serialization::PreprocessedEntityID,
                                   MacroDefinition *MD);
private:
  std::vector<ASTDeserializationListener*> Listeners;
};

MultiplexASTDeserializationListener::MultiplexASTDeserializationListener(
      const std::vector<ASTDeserializationListener*>& L)
    : Listeners(L) {
}

void MultiplexASTDeserializationListener::ReaderInitialized(
    ASTReader *Reader) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->ReaderInitialized(Reader);
}

void MultiplexASTDeserializationListener::IdentifierRead(
    serialization::IdentID ID, IdentifierInfo *II) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->IdentifierRead(ID, II);
}

void MultiplexASTDeserializationListener::TypeRead(
    serialization::TypeIdx Idx, QualType T) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->TypeRead(Idx, T);
}

void MultiplexASTDeserializationListener::DeclRead(
    serialization::DeclID ID, const Decl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->DeclRead(ID, D);
}

void MultiplexASTDeserializationListener::SelectorRead(
    serialization::SelectorID ID, Selector Sel) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->SelectorRead(ID, Sel);
}

void MultiplexASTDeserializationListener::MacroDefinitionRead(
    serialization::PreprocessedEntityID ID, MacroDefinition *MD) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->MacroDefinitionRead(ID, MD);
}

// This ASTMutationListener forwards its notifications to a set of
// child listeners.
class MultiplexASTMutationListener : public ASTMutationListener {
public:
  // Does NOT take ownership of the elements in L.
  MultiplexASTMutationListener(const std::vector<ASTMutationListener*>& L);
  virtual void CompletedTagDefinition(const TagDecl *D);
  virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D);
  virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
  virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
                                    const ClassTemplateSpecializationDecl *D);
  virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
                                              const FunctionDecl *D);
  virtual void CompletedImplicitDefinition(const FunctionDecl *D);
  virtual void StaticDataMemberInstantiated(const VarDecl *D);
  virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
                                            const ObjCInterfaceDecl *IFD);
  virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
                                            const ObjCPropertyDecl *OrigProp,
                                            const ObjCCategoryDecl *ClassExt);
private:
  std::vector<ASTMutationListener*> Listeners;
};

MultiplexASTMutationListener::MultiplexASTMutationListener(
    const std::vector<ASTMutationListener*>& L)
    : Listeners(L) {
}

void MultiplexASTMutationListener::CompletedTagDefinition(const TagDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->CompletedTagDefinition(D);
}

void MultiplexASTMutationListener::AddedVisibleDecl(
    const DeclContext *DC, const Decl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedVisibleDecl(DC, D);
}

void MultiplexASTMutationListener::AddedCXXImplicitMember(
    const CXXRecordDecl *RD, const Decl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedCXXImplicitMember(RD, D);
}
void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
    const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
}
void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
    const FunctionTemplateDecl *TD, const FunctionDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
}
void MultiplexASTMutationListener::CompletedImplicitDefinition(
                                                        const FunctionDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->CompletedImplicitDefinition(D);
}
void MultiplexASTMutationListener::StaticDataMemberInstantiated(
                                                             const VarDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->StaticDataMemberInstantiated(D);
}
void MultiplexASTMutationListener::AddedObjCCategoryToInterface(
                                                 const ObjCCategoryDecl *CatD,
                                                 const ObjCInterfaceDecl *IFD) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedObjCCategoryToInterface(CatD, IFD);
}
void MultiplexASTMutationListener::AddedObjCPropertyInClassExtension(
                                             const ObjCPropertyDecl *Prop,
                                             const ObjCPropertyDecl *OrigProp,
                                             const ObjCCategoryDecl *ClassExt) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedObjCPropertyInClassExtension(Prop, OrigProp, ClassExt);
}

}  // end namespace clang

MultiplexConsumer::MultiplexConsumer(ArrayRef<ASTConsumer*> C)
    : Consumers(C.begin(), C.end()),
      MutationListener(0), DeserializationListener(0) {
  // Collect the mutation listeners and deserialization listeners of all
  // children, and create a multiplex listener each if so.
  std::vector<ASTMutationListener*> mutationListeners;
  std::vector<ASTDeserializationListener*> serializationListeners;
  for (size_t i = 0, e = Consumers.size(); i != e; ++i) {
    ASTMutationListener* mutationListener =
        Consumers[i]->GetASTMutationListener();
    if (mutationListener)
      mutationListeners.push_back(mutationListener);
    ASTDeserializationListener* serializationListener =
        Consumers[i]->GetASTDeserializationListener();
    if (serializationListener)
      serializationListeners.push_back(serializationListener);
  }
  if (mutationListeners.size()) {
    MutationListener.reset(new MultiplexASTMutationListener(mutationListeners));
  }
  if (serializationListeners.size()) {
    DeserializationListener.reset(
        new MultiplexASTDeserializationListener(serializationListeners));
  }
}

MultiplexConsumer::~MultiplexConsumer() {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    delete Consumers[i];
}

void MultiplexConsumer::Initialize(ASTContext &Context) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->Initialize(Context);
}

bool MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) {
  bool Continue = true;
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Continue = Continue && Consumers[i]->HandleTopLevelDecl(D);
  return Continue;
}

void MultiplexConsumer::HandleInterestingDecl(DeclGroupRef D) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleInterestingDecl(D);
}

void MultiplexConsumer::HandleTranslationUnit(ASTContext &Ctx) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleTranslationUnit(Ctx);
}

void MultiplexConsumer::HandleTagDeclDefinition(TagDecl *D) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleTagDeclDefinition(D);
}

void MultiplexConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleTopLevelDeclInObjCContainer(D);
}

void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->CompleteTentativeDefinition(D);
}

void MultiplexConsumer::HandleVTable(
    CXXRecordDecl *RD, bool DefinitionRequired) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleVTable(RD, DefinitionRequired);
}

ASTMutationListener *MultiplexConsumer::GetASTMutationListener() {
  return MutationListener.get();
}

ASTDeserializationListener *MultiplexConsumer::GetASTDeserializationListener() {
  return DeserializationListener.get();
}

void MultiplexConsumer::PrintStats() {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->PrintStats();
}

void MultiplexConsumer::InitializeSema(Sema &S) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i]))
      SC->InitializeSema(S);
}

void MultiplexConsumer::ForgetSema() {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i]))
      SC->ForgetSema();
}
<commit_msg>Add ArrayRef goodness in MultiplexASTMutationListener.<commit_after>//===- MultiplexConsumer.cpp - AST Consumer for PCH Generation --*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the MultiplexConsumer class. It also declares and defines
//  MultiplexASTDeserializationListener and  MultiplexASTMutationListener, which
//  are implementation details of MultiplexConsumer.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/MultiplexConsumer.h"

#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Serialization/ASTDeserializationListener.h"

using namespace clang;

namespace clang {

// This ASTDeserializationListener forwards its notifications to a set of
// child listeners.
class MultiplexASTDeserializationListener
    : public ASTDeserializationListener {
public:
  // Does NOT take ownership of the elements in L.
  MultiplexASTDeserializationListener(
      const std::vector<ASTDeserializationListener*>& L);
  virtual void ReaderInitialized(ASTReader *Reader);
  virtual void IdentifierRead(serialization::IdentID ID,
                              IdentifierInfo *II);
  virtual void TypeRead(serialization::TypeIdx Idx, QualType T);
  virtual void DeclRead(serialization::DeclID ID, const Decl *D);
  virtual void SelectorRead(serialization::SelectorID iD, Selector Sel);
  virtual void MacroDefinitionRead(serialization::PreprocessedEntityID,
                                   MacroDefinition *MD);
private:
  std::vector<ASTDeserializationListener*> Listeners;
};

MultiplexASTDeserializationListener::MultiplexASTDeserializationListener(
      const std::vector<ASTDeserializationListener*>& L)
    : Listeners(L) {
}

void MultiplexASTDeserializationListener::ReaderInitialized(
    ASTReader *Reader) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->ReaderInitialized(Reader);
}

void MultiplexASTDeserializationListener::IdentifierRead(
    serialization::IdentID ID, IdentifierInfo *II) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->IdentifierRead(ID, II);
}

void MultiplexASTDeserializationListener::TypeRead(
    serialization::TypeIdx Idx, QualType T) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->TypeRead(Idx, T);
}

void MultiplexASTDeserializationListener::DeclRead(
    serialization::DeclID ID, const Decl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->DeclRead(ID, D);
}

void MultiplexASTDeserializationListener::SelectorRead(
    serialization::SelectorID ID, Selector Sel) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->SelectorRead(ID, Sel);
}

void MultiplexASTDeserializationListener::MacroDefinitionRead(
    serialization::PreprocessedEntityID ID, MacroDefinition *MD) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->MacroDefinitionRead(ID, MD);
}

// This ASTMutationListener forwards its notifications to a set of
// child listeners.
class MultiplexASTMutationListener : public ASTMutationListener {
public:
  // Does NOT take ownership of the elements in L.
  MultiplexASTMutationListener(ArrayRef<ASTMutationListener*> L);
  virtual void CompletedTagDefinition(const TagDecl *D);
  virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D);
  virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
  virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
                                    const ClassTemplateSpecializationDecl *D);
  virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
                                              const FunctionDecl *D);
  virtual void CompletedImplicitDefinition(const FunctionDecl *D);
  virtual void StaticDataMemberInstantiated(const VarDecl *D);
  virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
                                            const ObjCInterfaceDecl *IFD);
  virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
                                            const ObjCPropertyDecl *OrigProp,
                                            const ObjCCategoryDecl *ClassExt);
private:
  std::vector<ASTMutationListener*> Listeners;
};

MultiplexASTMutationListener::MultiplexASTMutationListener(
    ArrayRef<ASTMutationListener*> L)
    : Listeners(L.begin(), L.end()) {
}

void MultiplexASTMutationListener::CompletedTagDefinition(const TagDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->CompletedTagDefinition(D);
}

void MultiplexASTMutationListener::AddedVisibleDecl(
    const DeclContext *DC, const Decl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedVisibleDecl(DC, D);
}

void MultiplexASTMutationListener::AddedCXXImplicitMember(
    const CXXRecordDecl *RD, const Decl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedCXXImplicitMember(RD, D);
}
void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
    const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
}
void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
    const FunctionTemplateDecl *TD, const FunctionDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
}
void MultiplexASTMutationListener::CompletedImplicitDefinition(
                                                        const FunctionDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->CompletedImplicitDefinition(D);
}
void MultiplexASTMutationListener::StaticDataMemberInstantiated(
                                                             const VarDecl *D) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->StaticDataMemberInstantiated(D);
}
void MultiplexASTMutationListener::AddedObjCCategoryToInterface(
                                                 const ObjCCategoryDecl *CatD,
                                                 const ObjCInterfaceDecl *IFD) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedObjCCategoryToInterface(CatD, IFD);
}
void MultiplexASTMutationListener::AddedObjCPropertyInClassExtension(
                                             const ObjCPropertyDecl *Prop,
                                             const ObjCPropertyDecl *OrigProp,
                                             const ObjCCategoryDecl *ClassExt) {
  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
    Listeners[i]->AddedObjCPropertyInClassExtension(Prop, OrigProp, ClassExt);
}

}  // end namespace clang

MultiplexConsumer::MultiplexConsumer(ArrayRef<ASTConsumer*> C)
    : Consumers(C.begin(), C.end()),
      MutationListener(0), DeserializationListener(0) {
  // Collect the mutation listeners and deserialization listeners of all
  // children, and create a multiplex listener each if so.
  std::vector<ASTMutationListener*> mutationListeners;
  std::vector<ASTDeserializationListener*> serializationListeners;
  for (size_t i = 0, e = Consumers.size(); i != e; ++i) {
    ASTMutationListener* mutationListener =
        Consumers[i]->GetASTMutationListener();
    if (mutationListener)
      mutationListeners.push_back(mutationListener);
    ASTDeserializationListener* serializationListener =
        Consumers[i]->GetASTDeserializationListener();
    if (serializationListener)
      serializationListeners.push_back(serializationListener);
  }
  if (mutationListeners.size()) {
    MutationListener.reset(new MultiplexASTMutationListener(mutationListeners));
  }
  if (serializationListeners.size()) {
    DeserializationListener.reset(
        new MultiplexASTDeserializationListener(serializationListeners));
  }
}

MultiplexConsumer::~MultiplexConsumer() {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    delete Consumers[i];
}

void MultiplexConsumer::Initialize(ASTContext &Context) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->Initialize(Context);
}

bool MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) {
  bool Continue = true;
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Continue = Continue && Consumers[i]->HandleTopLevelDecl(D);
  return Continue;
}

void MultiplexConsumer::HandleInterestingDecl(DeclGroupRef D) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleInterestingDecl(D);
}

void MultiplexConsumer::HandleTranslationUnit(ASTContext &Ctx) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleTranslationUnit(Ctx);
}

void MultiplexConsumer::HandleTagDeclDefinition(TagDecl *D) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleTagDeclDefinition(D);
}

void MultiplexConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleTopLevelDeclInObjCContainer(D);
}

void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->CompleteTentativeDefinition(D);
}

void MultiplexConsumer::HandleVTable(
    CXXRecordDecl *RD, bool DefinitionRequired) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->HandleVTable(RD, DefinitionRequired);
}

ASTMutationListener *MultiplexConsumer::GetASTMutationListener() {
  return MutationListener.get();
}

ASTDeserializationListener *MultiplexConsumer::GetASTDeserializationListener() {
  return DeserializationListener.get();
}

void MultiplexConsumer::PrintStats() {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    Consumers[i]->PrintStats();
}

void MultiplexConsumer::InitializeSema(Sema &S) {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i]))
      SC->InitializeSema(S);
}

void MultiplexConsumer::ForgetSema() {
  for (size_t i = 0, e = Consumers.size(); i != e; ++i)
    if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i]))
      SC->ForgetSema();
}
<|endoftext|>


<commit_before>#include "Limiter.h"
#include "Testing.h"

#include <iostream>

static auto CurrentTime() { return std::chrono::high_resolution_clock::now(); }
static constexpr auto oneSecond = std::chrono::seconds(1);

std::ostream& operator<<(std::ostream& os, HttpResult::Code code)
{
    const auto str =
        code == HttpResult::Code::Ok ? "Ok (200)" :
        code == HttpResult::Code::TooManyRequests ? "Too many requests (429)" :
        "Unknown code";
    os << str;
    return os;
}

template <typename Clock, typename Duration>
std::string millisecondsSinceStart(std::chrono::time_point<Clock, Duration> timepoint)
{
    const static auto start = timepoint.time_since_epoch().count();
    return std::to_string((timepoint.time_since_epoch().count() - start) / 1'000'000);
}

static auto TestAllRequestsBelowMaxAreAccepted(int maxAllowedRps)
{
    Limiter limiter(maxAllowedRps, 100);
    const auto startTime = CurrentTime();
    for (int i = 0; i < maxAllowedRps; ++i)
        if (CurrentTime() < startTime + oneSecond)
            ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
}

static auto TestAllRequestsAboveMaxAreDeclined(int maxAllowedRps)
{
    Limiter limiter(maxAllowedRps, 100);
    const auto startTime = CurrentTime();
    for (int i = 0; i < maxAllowedRps; ++i)
        if (CurrentTime() < startTime + oneSecond)
            limiter.ValidateRequest();

    while (CurrentTime() < startTime + oneSecond)
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);
}

struct TimeStamps
{
    const std::chrono::time_point<std::chrono::high_resolution_clock> firstAcceptedRequest;
    const std::chrono::time_point<std::chrono::high_resolution_clock> lastAcceptedRequest;
};

static auto TestWithPeakLoadAtStart(Limiter& limiter)
{
    // Accepting the requests until we hit the limit.
    const auto firstAcceptedRequestTime = CurrentTime();
    for (int i = 0; i < limiter.maxRPS(); ++i)
    {
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
    }
    const auto lastAcceptedRequestTime = CurrentTime();

    // Do not accept requests if less than one second has elapsed after the first request.
    if (CurrentTime() < firstAcceptedRequestTime + oneSecond)
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);

    std::this_thread::sleep_until(firstAcceptedRequestTime + std::chrono::milliseconds(900));
    if (CurrentTime() < firstAcceptedRequestTime + oneSecond)
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);

    return TimeStamps{ firstAcceptedRequestTime, lastAcceptedRequestTime };
}

static auto TestWithPeakLoadAtStart_SingleIteration(int maxAllowedRps)
{
    Limiter limiter(maxAllowedRps, 1000);

    const auto timeStamps = TestWithPeakLoadAtStart(limiter);

    // Herewith we ensure that NOT MORE than maxAllowedRps requests are allowed per second.
    // It is possible that the limiter will allow a bit LESS, though, hence this "delta" allowance
    // in the assertion below.
    constexpr auto delayDueToTimerIssueObtainedEmpirically = std::chrono::milliseconds(42);
    std::this_thread::sleep_until(timeStamps.firstAcceptedRequest + oneSecond + delayDueToTimerIssueObtainedEmpirically);
    ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
}

static auto TestWithPeakLoadAtStart_MultipleIterations(int maxAllowedRps, int iterations)
{
    Limiter limiter(maxAllowedRps, 100);

    for (int i = 0; i < iterations; ++i)
    {
        const auto timeStamps = TestWithPeakLoadAtStart(limiter);
        std::this_thread::sleep_until(timeStamps.lastAcceptedRequest + oneSecond);
    }
}

static auto TestWithEvenLoad(int maxAllowedRps)
{
    Limiter limiter(maxAllowedRps, 100);
    const auto intervalBetweenRequests = oneSecond / (2 * maxAllowedRps);

    for (int iterations = 0; iterations < 5; ++iterations)
    {
        int requestsSent = 0;
        const auto startTime = CurrentTime();

        while (requestsSent < maxAllowedRps &&
               CurrentTime() < startTime + oneSecond)
        {
            ++requestsSent;
            const auto result = limiter.ValidateRequest();

            ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
            std::this_thread::sleep_for(intervalBetweenRequests);
        }
        const auto lastValidRequestTime = CurrentTime();

        while (CurrentTime() < startTime + oneSecond)
        {
            ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);
            std::this_thread::sleep_for(intervalBetweenRequests);
        }

        std::this_thread::sleep_until(lastValidRequestTime + oneSecond);
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
    }
}

static auto TestWithAdjacentPeaks(int maxAllowedRps)
{
    const auto startTime = CurrentTime();

    Limiter limiter(maxAllowedRps, 1000);

    std::this_thread::sleep_until(startTime + std::chrono::milliseconds(900));
    int requestsSent = 0;
    while (requestsSent < maxAllowedRps * 0.8)
    {
        requestsSent++;
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
    }

    std::this_thread::sleep_until(startTime + std::chrono::milliseconds(1500));
    while (requestsSent < maxAllowedRps)
    {
        requestsSent++;
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
    }

    while (CurrentTime() < startTime + std::chrono::milliseconds(1900))
    {
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);
    }

    std::this_thread::sleep_until(startTime + std::chrono::milliseconds(2000));
    ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
}

namespace LimiterSpecs
{
    static constexpr int minRPS = 1;
    static constexpr int maxRPS = 100'000;
};

int main()
{
    // Failing tests are commented out.
    try
    {
        TestAllRequestsBelowMaxAreAccepted(LimiterSpecs::maxRPS);
        TestAllRequestsAboveMaxAreDeclined(LimiterSpecs::maxRPS);
        TestWithPeakLoadAtStart_SingleIteration(LimiterSpecs::maxRPS);
        //TestWithPeakLoadAtStart_MultipleIterations(LimiterSpecs::maxRPS, 10);
        TestWithAdjacentPeaks(LimiterSpecs::maxRPS);
        TestWithEvenLoad(LimiterSpecs::maxRPS);
        std::cout << "All Tests passed successfully\n";
    }
    catch (AssertionException& e)
    {
        std::cout << "One or more of tests failed: " << e.what() << '\n';
    }
    system("pause");
    return 0;
}
<commit_msg>Use type alias Clock instead of explicit chrono clock type<commit_after>#include "Limiter.h"
#include "Testing.h"

#include <iostream>

static auto CurrentTime() { return Clock::now(); }
static constexpr auto oneSecond = std::chrono::seconds(1);

std::ostream& operator<<(std::ostream& os, HttpResult::Code code)
{
    const auto str =
        code == HttpResult::Code::Ok ? "Ok (200)" :
        code == HttpResult::Code::TooManyRequests ? "Too many requests (429)" :
        "Unknown code";
    os << str;
    return os;
}

template <typename Clock, typename Duration>
std::string millisecondsSinceStart(std::chrono::time_point<Clock, Duration> timepoint)
{
    const static auto start = timepoint.time_since_epoch().count();
    return std::to_string((timepoint.time_since_epoch().count() - start) / 1'000'000);
}

static auto TestAllRequestsBelowMaxAreAccepted(int maxAllowedRps)
{
    Limiter limiter(maxAllowedRps, 100);
    const auto startTime = CurrentTime();
    for (int i = 0; i < maxAllowedRps; ++i)
        if (CurrentTime() < startTime + oneSecond)
            ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
}

static auto TestAllRequestsAboveMaxAreDeclined(int maxAllowedRps)
{
    Limiter limiter(maxAllowedRps, 100);
    const auto startTime = CurrentTime();
    for (int i = 0; i < maxAllowedRps; ++i)
        if (CurrentTime() < startTime + oneSecond)
            limiter.ValidateRequest();

    while (CurrentTime() < startTime + oneSecond)
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);
}

struct TimeStamps
{
    const std::chrono::time_point<Clock> firstAcceptedRequest;
    const std::chrono::time_point<Clock> lastAcceptedRequest;
};

static auto TestWithPeakLoadAtStart(Limiter& limiter)
{
    // Accepting the requests until we hit the limit.
    const auto firstAcceptedRequestTime = CurrentTime();
    for (int i = 0; i < limiter.maxRPS(); ++i)
    {
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
    }
    const auto lastAcceptedRequestTime = CurrentTime();

    // Do not accept requests if less than one second has elapsed after the first request.
    if (CurrentTime() < firstAcceptedRequestTime + oneSecond)
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);

    std::this_thread::sleep_until(firstAcceptedRequestTime + std::chrono::milliseconds(900));
    if (CurrentTime() < firstAcceptedRequestTime + oneSecond)
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);

    return TimeStamps{ firstAcceptedRequestTime, lastAcceptedRequestTime };
}

static auto TestWithPeakLoadAtStart_SingleIteration(int maxAllowedRps)
{
    Limiter limiter(maxAllowedRps, 1000);

    const auto timeStamps = TestWithPeakLoadAtStart(limiter);

    // Herewith we ensure that NOT MORE than maxAllowedRps requests are allowed per second.
    // It is possible that the limiter will allow a bit LESS, though, hence this "delta" allowance
    // in the assertion below.
    constexpr auto delayDueToTimerIssueObtainedEmpirically = std::chrono::milliseconds(42);
    std::this_thread::sleep_until(timeStamps.firstAcceptedRequest + oneSecond + delayDueToTimerIssueObtainedEmpirically);
    ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
}

static auto TestWithPeakLoadAtStart_MultipleIterations(int maxAllowedRps, int iterations)
{
    Limiter limiter(maxAllowedRps, 100);

    for (int i = 0; i < iterations; ++i)
    {
        const auto timeStamps = TestWithPeakLoadAtStart(limiter);
        std::this_thread::sleep_until(timeStamps.lastAcceptedRequest + oneSecond);
    }
}

static auto TestWithEvenLoad(int maxAllowedRps)
{
    Limiter limiter(maxAllowedRps, 100);
    const auto intervalBetweenRequests = oneSecond / (2 * maxAllowedRps);

    for (int iterations = 0; iterations < 5; ++iterations)
    {
        int requestsSent = 0;
        const auto startTime = CurrentTime();

        while (requestsSent < maxAllowedRps &&
               CurrentTime() < startTime + oneSecond)
        {
            ++requestsSent;
            const auto result = limiter.ValidateRequest();

            ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
            std::this_thread::sleep_for(intervalBetweenRequests);
        }
        const auto lastValidRequestTime = CurrentTime();

        while (CurrentTime() < startTime + oneSecond)
        {
            ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);
            std::this_thread::sleep_for(intervalBetweenRequests);
        }

        std::this_thread::sleep_until(lastValidRequestTime + oneSecond);
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
    }
}

static auto TestWithAdjacentPeaks(int maxAllowedRps)
{
    const auto startTime = CurrentTime();

    Limiter limiter(maxAllowedRps, 1000);

    std::this_thread::sleep_until(startTime + std::chrono::milliseconds(900));
    int requestsSent = 0;
    while (requestsSent < maxAllowedRps * 0.8)
    {
        requestsSent++;
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
    }

    std::this_thread::sleep_until(startTime + std::chrono::milliseconds(1500));
    while (requestsSent < maxAllowedRps)
    {
        requestsSent++;
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
    }

    while (CurrentTime() < startTime + std::chrono::milliseconds(1900))
    {
        ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::TooManyRequests);
    }

    std::this_thread::sleep_until(startTime + std::chrono::milliseconds(2000));
    ASSERT_EQUAL(limiter.ValidateRequest(), HttpResult::Code::Ok);
}

namespace LimiterSpecs
{
    static constexpr int minRPS = 1;
    static constexpr int maxRPS = 100'000;
};

int main()
{
    // Failing tests are commented out.
    try
    {
        TestAllRequestsBelowMaxAreAccepted(LimiterSpecs::maxRPS);
        TestAllRequestsAboveMaxAreDeclined(LimiterSpecs::maxRPS);
        TestWithPeakLoadAtStart_SingleIteration(LimiterSpecs::maxRPS);
        //TestWithPeakLoadAtStart_MultipleIterations(LimiterSpecs::maxRPS, 10);
        TestWithAdjacentPeaks(LimiterSpecs::maxRPS);
        TestWithEvenLoad(LimiterSpecs::maxRPS);
        std::cout << "All Tests passed successfully\n";
    }
    catch (AssertionException& e)
    {
        std::cout << "One or more of tests failed: " << e.what() << '\n';
    }
    system("pause");
    return 0;
}
<|endoftext|>