<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://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 "translation.h"

#include "inquiry.h"
#include "maintenance_in.h"
#include "mode_sense.h"
#include "read.h"
#include "read_capacity_10.h"
#include "report_luns.h"
#include "request_sense.h"
#include "status.h"
#include "synchronize_cache.h"
#include "unmap.h"
#include "verify.h"

namespace translator {

// TODO: Set up persistence structure to hold
// actual page size and lba size queried from NVMe device
constexpr uint32_t kPageSize = 4096;
constexpr uint32_t kLbaSize = 512;

BeginResponse Translation::Begin(Span<const uint8_t> scsi_cmd,
                                 Span<const uint8_t> buffer_out,
                                 scsi::LunAddress lun) {
  BeginResponse response = {};
  response.status = ApiStatus::kSuccess;
  if (pipeline_status_ != StatusCode::kUninitialized) {
    DebugLog("Invalid use of API: Begin called before complete or abort");
    response.status = ApiStatus::kFailure;
    return response;
  }

  // Verify buffer is large enough to contain opcode (one byte)
  if (scsi_cmd.empty()) {
    DebugLog("Empty SCSI Command Buffer");
    pipeline_status_ = StatusCode::kFailure;
    return response;
  }

  pipeline_status_ = StatusCode::kSuccess;
  scsi_cmd_ = scsi_cmd;

  uint32_t nsid = static_cast<uint32_t>(lun) + 1;
  Span<const uint8_t> scsi_cmd_no_op = scsi_cmd.subspan(1);
  scsi::OpCode opc = static_cast<scsi::OpCode>(scsi_cmd[0]);
  switch (opc) {
    case scsi::OpCode::kInquiry:
      pipeline_status_ =
          InquiryToNvme(scsi_cmd_no_op, nvme_wrappers_[0], nvme_wrappers_[1],
                        response.alloc_len, nsid, allocations_);
      nvme_cmd_count_ = 2;
      break;
    case scsi::OpCode::kUnmap:
      pipeline_status_ = UnmapToNvme(scsi_cmd_no_op, buffer_out,
                                     nvme_wrappers_[0], allocations_[0], nsid);
      nvme_cmd_count_ = 1;
    case scsi::OpCode::kModeSense6:
      pipeline_status_ =
          ModeSense6ToNvme(scsi_cmd_no_op, nvme_wrappers_, allocations_[0],
                           nsid, nvme_cmd_count_, response.alloc_len);
      break;
    case scsi::OpCode::kModeSense10:
      pipeline_status_ =
          ModeSense10ToNvme(scsi_cmd_no_op, nvme_wrappers_, allocations_[0],
                            nsid, nvme_cmd_count_, response.alloc_len);
    case scsi::OpCode::kMaintenanceIn:
      // ReportSupportedOpCodes is the only supported MaintenanceIn command
      pipeline_status_ =
          ValidateReportSupportedOpCodes(scsi_cmd_no_op, response.alloc_len);
      nvme_cmd_count_ = 0;
    case scsi::OpCode::kReportLuns:
      pipeline_status_ = ReportLunsToNvme(scsi_cmd_no_op, nvme_wrappers_[0],
                                          allocations_[0], response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kReadCapacity10:
      pipeline_status_ =
          ReadCapacity10ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], nsid,
                               allocations_[0], response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kRequestSense:
      pipeline_status_ = RequestSenseToNvme(scsi_cmd_no_op, response.alloc_len);
      break;
    case scsi::OpCode::kRead6:
      pipeline_status_ =
          Read6ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], allocations_[0], nsid,
                      kPageSize, kLbaSize, response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kRead10:
      pipeline_status_ =
          Read10ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], allocations_[0], nsid,
                       kPageSize, kLbaSize, response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kRead12:
      pipeline_status_ =
          Read12ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], allocations_[0], nsid,
                       kPageSize, kLbaSize, response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kRead16:
      pipeline_status_ =
          Read16ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], allocations_[0], nsid,
                       kPageSize, kLbaSize, response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kSync10:
      SynchronizeCache10ToNvme(nvme_wrappers_[0], nsid);
      pipeline_status_ = StatusCode::kSuccess;
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kVerify10:
      pipeline_status_ = VerifyToNvme(scsi_cmd_no_op, nvme_wrappers_[0]);
      nvme_cmd_count_ = 1;
      break;
    default:
      DebugLog("Bad OpCode: %#x", static_cast<uint8_t>(opc));
      pipeline_status_ = StatusCode::kFailure;
      break;
  }

  if (pipeline_status_ != StatusCode::kSuccess) {
    FlushMemory();
    nvme_cmd_count_ = 0;
  }
  return response;
}

CompleteResponse Translation::Complete(
    Span<const nvme::GenericQueueEntryCpl> cpl_data, Span<uint8_t> buffer_in,
    Span<uint8_t> sense_buffer) {
  CompleteResponse resp = {};
  if (pipeline_status_ == StatusCode::kUninitialized) {
    DebugLog("Invalid use of API: Complete called before Begin");
    resp.status = ApiStatus::kFailure;
    return resp;
  }

  if (cpl_data.size() != nvme_cmd_count_) {
    DebugLog(
        "Invalid use of API, completion count %u does not equal command count "
        "%u",
        cpl_data.size(), nvme_cmd_count_);
    resp.status = ApiStatus::kFailure;
    return resp;
  }

  if (pipeline_status_ != StatusCode::kSuccess) {
    ScsiStatus scsi_status = {
        .status = scsi::Status::kCheckCondition,
        .sense_key = scsi::SenseKey::kIllegalRequest,
        .asc = scsi::AdditionalSenseCode::kInvalidFieldInCdb,
        .ascq = scsi::AdditionalSenseCodeQualifier::kNoAdditionalSenseInfo};
    FillSenseBuffer(sense_buffer, scsi_status);
    AbortPipeline();
    resp.status = ApiStatus::kSuccess;
    resp.scsi_status = scsi_status.status;
    return resp;
  }

  // Verify NVMe commands completed successfully. If not translate error.
  for (uint32_t i = 0; i < cpl_data.size(); ++i) {
    const nvme::GenericQueueEntryCpl& cpl_entry = cpl_data[i];
    const nvme::CplStatus& cpl_status = cpl_entry.cpl_status;
    ScsiStatus scsi_status = StatusToScsi(cpl_status.sct, cpl_status.sc);
    if (scsi_status.status != scsi::Status::kGood) {
      FillSenseBuffer(sense_buffer, scsi_status);
      AbortPipeline();
      resp.status = ApiStatus::kSuccess;
      resp.scsi_status = scsi_status.status;
      return resp;
    }
  }

  // Switch cases should not return
  resp.status = ApiStatus::kSuccess;
  Span<const uint8_t> scsi_cmd_no_op = scsi_cmd_.subspan(1);
  scsi::OpCode opc = static_cast<scsi::OpCode>(scsi_cmd_[0]);
  switch (opc) {
    case scsi::OpCode::kVerify10:
      // VerifyToScsi() is not needed
      break;
    case scsi::OpCode::kInquiry:
      pipeline_status_ =
          InquiryToScsi(scsi_cmd_no_op, buffer_in, nvme_wrappers_[0].cmd,
                        nvme_wrappers_[1].cmd);
      break;
    case scsi::OpCode::kModeSense6:
      // TODO: Update this when the cpl_data interface is finalized
      ModeSense6ToScsi(scsi_cmd_no_op, nvme_wrappers_[0].cmd, cpl_data[0].cdw0,
                       buffer_in);
      break;
    case scsi::OpCode::kModeSense10:
      // TODO: Update this when the cpl_data interface is finalized
      ModeSense10ToScsi(scsi_cmd_no_op, nvme_wrappers_[0].cmd, cpl_data[0].cdw0,
                        buffer_in);
      break;
    case scsi::OpCode::kMaintenanceIn:
      // ReportSupportedOpCodes is the only supported MaintenanceIn command
      WriteReportSupportedOpCodesResult(buffer_in);
      break;
    case scsi::OpCode::kReportLuns:
      pipeline_status_ = ReportLunsToScsi(nvme_wrappers_[0].cmd, buffer_in);
      break;
    case scsi::OpCode::kUnmap:
      pipeline_status_ = StatusCode::kSuccess;
      break;
    case scsi::OpCode::kReadCapacity10:
      pipeline_status_ = ReadCapacity10ToScsi(buffer_in, nvme_wrappers_[0].cmd);
      break;
    case scsi::OpCode::kRequestSense:
      pipeline_status_ = RequestSenseToScsi(scsi_cmd_no_op, buffer_in);
      break;
    case scsi::OpCode::kRead6:
    case scsi::OpCode::kRead10:
    case scsi::OpCode::kRead12:
    case scsi::OpCode::kRead16:
      pipeline_status_ = ReadToScsi(buffer_in, nvme_wrappers_[0].cmd, kLbaSize);
      break;
    case scsi::OpCode::kSync10:
      // No command specific response data to translate
      pipeline_status_ = StatusCode::kSuccess;
      break;
    default:
      DebugLog(
          "Invalid opcode case reached: %u. Please contact SCSI2NVMe devs.",
          scsi_cmd_[0]);
      break;
  }
  if (pipeline_status_ != StatusCode::kSuccess) {
    // TODO fill buffer with SCSI CHECK CONDITION response
    DebugLog("Failed to translate back to SCSI");
  }
  AbortPipeline();
  return resp;
}

Span<const NvmeCmdWrapper> Translation::GetNvmeWrappers() {
  return Span<NvmeCmdWrapper>(nvme_wrappers_, nvme_cmd_count_);
}

void Translation::AbortPipeline() {
  pipeline_status_ = StatusCode::kUninitialized;
  FlushMemory();
  nvme_cmd_count_ = 0;
}

void Translation::FlushMemory() {
  for (uint32_t i = 0; i < nvme_cmd_count_; ++i) {
    if (allocations_[i].data_addr != 0) {
      DeallocPages(allocations_[i].data_addr, allocations_[i].data_page_count);
      allocations_[i].data_addr = 0;
    }
    if (allocations_[i].mdata_addr != 0) {
      DeallocPages(allocations_[i].mdata_addr,
                   allocations_[i].mdata_page_count);
      allocations_[i].mdata_addr = 0;
    }
  }
}

};  // namespace translator
<commit_msg>Update kLbaSize and remove todo (#180)<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://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 "translation.h"

#include "inquiry.h"
#include "maintenance_in.h"
#include "mode_sense.h"
#include "read.h"
#include "read_capacity_10.h"
#include "report_luns.h"
#include "request_sense.h"
#include "status.h"
#include "synchronize_cache.h"
#include "unmap.h"
#include "verify.h"

namespace translator {

constexpr uint32_t kPageSize = 4096;
constexpr uint32_t kLbaSize = 4096;

BeginResponse Translation::Begin(Span<const uint8_t> scsi_cmd,
                                 Span<const uint8_t> buffer_out,
                                 scsi::LunAddress lun) {
  BeginResponse response = {};
  response.status = ApiStatus::kSuccess;
  if (pipeline_status_ != StatusCode::kUninitialized) {
    DebugLog("Invalid use of API: Begin called before complete or abort");
    response.status = ApiStatus::kFailure;
    return response;
  }

  // Verify buffer is large enough to contain opcode (one byte)
  if (scsi_cmd.empty()) {
    DebugLog("Empty SCSI Command Buffer");
    pipeline_status_ = StatusCode::kFailure;
    return response;
  }

  pipeline_status_ = StatusCode::kSuccess;
  scsi_cmd_ = scsi_cmd;

  uint32_t nsid = static_cast<uint32_t>(lun) + 1;
  Span<const uint8_t> scsi_cmd_no_op = scsi_cmd.subspan(1);
  scsi::OpCode opc = static_cast<scsi::OpCode>(scsi_cmd[0]);
  switch (opc) {
    case scsi::OpCode::kInquiry:
      pipeline_status_ =
          InquiryToNvme(scsi_cmd_no_op, nvme_wrappers_[0], nvme_wrappers_[1],
                        response.alloc_len, nsid, allocations_);
      nvme_cmd_count_ = 2;
      break;
    case scsi::OpCode::kUnmap:
      pipeline_status_ = UnmapToNvme(scsi_cmd_no_op, buffer_out,
                                     nvme_wrappers_[0], allocations_[0], nsid);
      nvme_cmd_count_ = 1;
    case scsi::OpCode::kModeSense6:
      pipeline_status_ =
          ModeSense6ToNvme(scsi_cmd_no_op, nvme_wrappers_, allocations_[0],
                           nsid, nvme_cmd_count_, response.alloc_len);
      break;
    case scsi::OpCode::kModeSense10:
      pipeline_status_ =
          ModeSense10ToNvme(scsi_cmd_no_op, nvme_wrappers_, allocations_[0],
                            nsid, nvme_cmd_count_, response.alloc_len);
    case scsi::OpCode::kMaintenanceIn:
      // ReportSupportedOpCodes is the only supported MaintenanceIn command
      pipeline_status_ =
          ValidateReportSupportedOpCodes(scsi_cmd_no_op, response.alloc_len);
      nvme_cmd_count_ = 0;
    case scsi::OpCode::kReportLuns:
      pipeline_status_ = ReportLunsToNvme(scsi_cmd_no_op, nvme_wrappers_[0],
                                          allocations_[0], response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kReadCapacity10:
      pipeline_status_ =
          ReadCapacity10ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], nsid,
                               allocations_[0], response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kRequestSense:
      pipeline_status_ = RequestSenseToNvme(scsi_cmd_no_op, response.alloc_len);
      break;
    case scsi::OpCode::kRead6:
      pipeline_status_ =
          Read6ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], allocations_[0], nsid,
                      kPageSize, kLbaSize, response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kRead10:
      pipeline_status_ =
          Read10ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], allocations_[0], nsid,
                       kPageSize, kLbaSize, response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kRead12:
      pipeline_status_ =
          Read12ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], allocations_[0], nsid,
                       kPageSize, kLbaSize, response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kRead16:
      pipeline_status_ =
          Read16ToNvme(scsi_cmd_no_op, nvme_wrappers_[0], allocations_[0], nsid,
                       kPageSize, kLbaSize, response.alloc_len);
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kSync10:
      SynchronizeCache10ToNvme(nvme_wrappers_[0], nsid);
      pipeline_status_ = StatusCode::kSuccess;
      nvme_cmd_count_ = 1;
      break;
    case scsi::OpCode::kVerify10:
      pipeline_status_ = VerifyToNvme(scsi_cmd_no_op, nvme_wrappers_[0]);
      nvme_cmd_count_ = 1;
      break;
    default:
      DebugLog("Bad OpCode: %#x", static_cast<uint8_t>(opc));
      pipeline_status_ = StatusCode::kFailure;
      break;
  }

  if (pipeline_status_ != StatusCode::kSuccess) {
    FlushMemory();
    nvme_cmd_count_ = 0;
  }
  return response;
}

CompleteResponse Translation::Complete(
    Span<const nvme::GenericQueueEntryCpl> cpl_data, Span<uint8_t> buffer_in,
    Span<uint8_t> sense_buffer) {
  CompleteResponse resp = {};
  if (pipeline_status_ == StatusCode::kUninitialized) {
    DebugLog("Invalid use of API: Complete called before Begin");
    resp.status = ApiStatus::kFailure;
    return resp;
  }

  if (cpl_data.size() != nvme_cmd_count_) {
    DebugLog(
        "Invalid use of API, completion count %u does not equal command count "
        "%u",
        cpl_data.size(), nvme_cmd_count_);
    resp.status = ApiStatus::kFailure;
    return resp;
  }

  if (pipeline_status_ != StatusCode::kSuccess) {
    ScsiStatus scsi_status = {
        .status = scsi::Status::kCheckCondition,
        .sense_key = scsi::SenseKey::kIllegalRequest,
        .asc = scsi::AdditionalSenseCode::kInvalidFieldInCdb,
        .ascq = scsi::AdditionalSenseCodeQualifier::kNoAdditionalSenseInfo};
    FillSenseBuffer(sense_buffer, scsi_status);
    AbortPipeline();
    resp.status = ApiStatus::kSuccess;
    resp.scsi_status = scsi_status.status;
    return resp;
  }

  // Verify NVMe commands completed successfully. If not translate error.
  for (uint32_t i = 0; i < cpl_data.size(); ++i) {
    const nvme::GenericQueueEntryCpl& cpl_entry = cpl_data[i];
    const nvme::CplStatus& cpl_status = cpl_entry.cpl_status;
    ScsiStatus scsi_status = StatusToScsi(cpl_status.sct, cpl_status.sc);
    if (scsi_status.status != scsi::Status::kGood) {
      FillSenseBuffer(sense_buffer, scsi_status);
      AbortPipeline();
      resp.status = ApiStatus::kSuccess;
      resp.scsi_status = scsi_status.status;
      return resp;
    }
  }

  // Switch cases should not return
  resp.status = ApiStatus::kSuccess;
  Span<const uint8_t> scsi_cmd_no_op = scsi_cmd_.subspan(1);
  scsi::OpCode opc = static_cast<scsi::OpCode>(scsi_cmd_[0]);
  switch (opc) {
    case scsi::OpCode::kVerify10:
      // VerifyToScsi() is not needed
      break;
    case scsi::OpCode::kInquiry:
      pipeline_status_ =
          InquiryToScsi(scsi_cmd_no_op, buffer_in, nvme_wrappers_[0].cmd,
                        nvme_wrappers_[1].cmd);
      break;
    case scsi::OpCode::kModeSense6:
      // TODO: Update this when the cpl_data interface is finalized
      ModeSense6ToScsi(scsi_cmd_no_op, nvme_wrappers_[0].cmd, cpl_data[0].cdw0,
                       buffer_in);
      break;
    case scsi::OpCode::kModeSense10:
      // TODO: Update this when the cpl_data interface is finalized
      ModeSense10ToScsi(scsi_cmd_no_op, nvme_wrappers_[0].cmd, cpl_data[0].cdw0,
                        buffer_in);
      break;
    case scsi::OpCode::kMaintenanceIn:
      // ReportSupportedOpCodes is the only supported MaintenanceIn command
      WriteReportSupportedOpCodesResult(buffer_in);
      break;
    case scsi::OpCode::kReportLuns:
      pipeline_status_ = ReportLunsToScsi(nvme_wrappers_[0].cmd, buffer_in);
      break;
    case scsi::OpCode::kUnmap:
      pipeline_status_ = StatusCode::kSuccess;
      break;
    case scsi::OpCode::kReadCapacity10:
      pipeline_status_ = ReadCapacity10ToScsi(buffer_in, nvme_wrappers_[0].cmd);
      break;
    case scsi::OpCode::kRequestSense:
      pipeline_status_ = RequestSenseToScsi(scsi_cmd_no_op, buffer_in);
      break;
    case scsi::OpCode::kRead6:
    case scsi::OpCode::kRead10:
    case scsi::OpCode::kRead12:
    case scsi::OpCode::kRead16:
      pipeline_status_ = ReadToScsi(buffer_in, nvme_wrappers_[0].cmd, kLbaSize);
      break;
    case scsi::OpCode::kSync10:
      // No command specific response data to translate
      pipeline_status_ = StatusCode::kSuccess;
      break;
    default:
      DebugLog(
          "Invalid opcode case reached: %u. Please contact SCSI2NVMe devs.",
          scsi_cmd_[0]);
      break;
  }
  if (pipeline_status_ != StatusCode::kSuccess) {
    // TODO fill buffer with SCSI CHECK CONDITION response
    DebugLog("Failed to translate back to SCSI");
  }
  AbortPipeline();
  return resp;
}

Span<const NvmeCmdWrapper> Translation::GetNvmeWrappers() {
  return Span<NvmeCmdWrapper>(nvme_wrappers_, nvme_cmd_count_);
}

void Translation::AbortPipeline() {
  pipeline_status_ = StatusCode::kUninitialized;
  FlushMemory();
  nvme_cmd_count_ = 0;
}

void Translation::FlushMemory() {
  for (uint32_t i = 0; i < nvme_cmd_count_; ++i) {
    if (allocations_[i].data_addr != 0) {
      DeallocPages(allocations_[i].data_addr, allocations_[i].data_page_count);
      allocations_[i].data_addr = 0;
    }
    if (allocations_[i].mdata_addr != 0) {
      DeallocPages(allocations_[i].mdata_addr,
                   allocations_[i].mdata_page_count);
      allocations_[i].mdata_addr = 0;
    }
  }
}

};  // namespace translator
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file tuple_utils.hpp
 * \brief Contains utilities to work with std::tuple
 */

#ifndef CPP_UTILS_TUPLE_HPP
#define CPP_UTILS_TUPLE_HPP

#include <tuple>

namespace cpp {

template<size_t I, typename Tuple, typename F>
struct for_each_impl {
    static void for_each(Tuple& t, F&& f) {
        for_each_impl<I - 1, Tuple, F>::for_each(t, std::forward<F>(f));
        f(std::get<I>(t));
    }

    static void for_each_i(Tuple& t, F&& f) {
        for_each_impl<I - 1, Tuple, F>::for_each_i(t, std::forward<F>(f));
        f(I, std::get<I>(t));
    }

    static void for_each_pair(Tuple& t, F&& f) {
        for_each_impl<I - 1, Tuple, F>::for_each_pair(t, std::forward<F>(f));
        f(std::get<I>(t), std::get<I+1>(t));
    }

    static void for_each_pair_i(Tuple& t, F&& f) {
        for_each_impl<I - 1, Tuple, F>::for_each_pair_i(t, std::forward<F>(f));
        f(I, std::get<I>(t), std::get<I+1>(t));
    }

    static void for_each_rpair(Tuple& t, F&& f) {
        f(std::get<I>(t), std::get<I+1>(t));
        for_each_impl<I - 1, Tuple, F>::for_each_rpair(t, std::forward<F>(f));
    }

    static void for_each_rpair_i(Tuple& t, F&& f) {
        f(I, std::get<I>(t), std::get<I+1>(t));
        for_each_impl<I - 1, Tuple, F>::for_each_rpair_i(t, std::forward<F>(f));
    }
};

template<typename Tuple, typename F>
struct for_each_impl<0, Tuple, F> {
    static void for_each(Tuple& t, F&& f) {
        f(std::get<0>(t));
    }

    static void for_each_i(Tuple& t, F&& f) {
        f(0, std::get<0>(t));
    }

    static void for_each_pair(Tuple& t, F&& f) {
        f(std::get<0>(t), std::get<1>(t));
    }

    static void for_each_pair_i(Tuple& t, F&& f) {
        f(0, std::get<0>(t), std::get<1>(t));
    }

    static void for_each_rpair(Tuple& t, F&& f) {
        f(std::get<0>(t), std::get<1>(t));
    }

    static void for_each_rpair_i(Tuple& t, F&& f) {
        f(0, std::get<0>(t), std::get<1>(t));
    }
};

template<size_t I, typename Tuple1, typename Tuple2, typename F>
struct dual_for_each_impl {
    static void for_each(Tuple1& t1, Tuple2& t2, F&& f) {
        dual_for_each_impl<I - 1, Tuple1, Tuple2, F>::for_each(t1, t2, std::forward<F>(f));
        f(std::get<I>(t1), std::get<I>(t2));
    }

    static void for_each_i(Tuple1& t1, Tuple2& t2, F&& f) {
        dual_for_each_impl<I - 1, Tuple1, Tuple2, F>::for_each_i(t1, t2, std::forward<F>(f));
        f(I, std::get<I>(t1), std::get<I>(t2));
    }

    static void for_each_pair(Tuple1& t1, Tuple2& t2, F&& f) {
        dual_for_each_impl<I - 1, Tuple1, Tuple2, F>::for_each_pair(t1, t2, std::forward<F>(f));
        f(std::get<I>(t1), std::get<I+1>(t1), std::get<I>(t2), std::get<I+1>(t2));
    }

    static void for_each_rpair_i(Tuple1& t1, Tuple2& t2, F&& f) {
        f(I, std::get<I>(t1), std::get<I+1>(t1), std::get<I>(t2), std::get<I+1>(t2));
        dual_for_each_impl<I - 1, Tuple1, Tuple2, F>::for_each_rpair_i(t1, t2, std::forward<F>(f));
    }
};

template<typename Tuple1, typename Tuple2, typename F>
struct dual_for_each_impl<0, Tuple1, Tuple2, F> {
    static void for_each(Tuple1& t1, Tuple2& t2, F&& f) {
        f(std::get<0>(t1), std::get<0>(t2));
    }

    static void for_each_i(Tuple1& t1, Tuple2& t2, F&& f) {
        f(0, std::get<0>(t1), std::get<0>(t2));
    }

    static void for_each_pair(Tuple1& t1, Tuple2& t2, F&& f) {
        f(std::get<0>(t1), std::get<1>(t1), std::get<0>(t2), std::get<1>(t2));
    }

    static void for_each_rpair_i(Tuple1& t1, Tuple2& t2, F&& f) {
        f(0, std::get<0>(t1), std::get<1>(t1), std::get<0>(t2), std::get<1>(t2));
    }
};

/*!
 * \brief Call the given functor with each element of the tuple
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each(Tuple& t, F&& f) {
    for_each_impl<std::tuple_size<Tuple>::value - 1, Tuple, F>::for_each(t, std::forward<F>(f));
}

/*!
 * \brief Call the given functor with each element of the tuple and its position (zero-indexing)
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each_i(Tuple& t, F&& f) {
    for_each_impl<std::tuple_size<Tuple>::value - 1, Tuple, F>::for_each_i(t, std::forward<F>(f));
}

/*!
 * \brief Call the given functor with each contiguous pair of element of the tuple.
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each_pair(Tuple& t, F&& f) {
    if(std::tuple_size<Tuple>::value > 1){
        for_each_impl<std::tuple_size<Tuple>::value - 2, Tuple, F>::for_each_pair(t, std::forward<F>(f));
    }
}

/*!
 * \brief Call the given functor with each contiguous pair of element of the tuple and the position of the first element.
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each_pair_i(Tuple& t, F&& f) {
    if(std::tuple_size<Tuple>::value > 1){
        for_each_impl<std::tuple_size<Tuple>::value - 2, Tuple, F>::for_each_pair_i(t, std::forward<F>(f));
    }
}

template<typename Tuple, typename F>
void for_each_rpair(Tuple& t, F&& f) {
    if(std::tuple_size<Tuple>::value > 1){
        for_each_impl<std::tuple_size<Tuple>::value - 2, Tuple, F>::for_each_rpair(t, std::forward<F>(f));
    }
}

template<typename Tuple, typename F>
void for_each_rpair_i(Tuple& t, F&& f) {
    if(std::tuple_size<Tuple>::value > 1){
        for_each_impl<std::tuple_size<Tuple>::value - 2, Tuple, F>::for_each_rpair_i(t, std::forward<F>(f));
    }
}

//Dual versions

template<typename Tuple1, typename Tuple2, typename F>
void for_each(Tuple1& t1, Tuple2& t2, F&& f) {
    static_assert(std::tuple_size<Tuple1>::value == std::tuple_size<Tuple2>::value, "Can only iterate tuples of same size");

    dual_for_each_impl<std::tuple_size<Tuple1>::value - 1, Tuple1, Tuple2, F>::for_each(t1, t2, std::forward<F>(f));
}

template<typename Tuple1, typename Tuple2, typename F>
void for_each_i(Tuple1& t1, Tuple2& t2, F&& f) {
    static_assert(std::tuple_size<Tuple1>::value == std::tuple_size<Tuple2>::value, "Can only iterate tuples of same size");

    dual_for_each_impl<std::tuple_size<Tuple1>::value - 1, Tuple1, Tuple2, F>::for_each_i(t1, t2, std::forward<F>(f));
}

template<typename Tuple1, typename Tuple2, typename F>
void for_each_pair(Tuple1& t1, Tuple2& t2, F&& f) {
    static_assert(std::tuple_size<Tuple1>::value == std::tuple_size<Tuple2>::value, "Can only iterate tuples of same size");

    if(std::tuple_size<Tuple1>::value > 1){
        dual_for_each_impl<std::tuple_size<Tuple1>::value - 2, Tuple1, Tuple2, F>::for_each_pair(t1, t2, std::forward<F>(f));
    }
}

template<typename Tuple1, typename Tuple2, typename F>
void for_each_rpair_i(Tuple1& t1, Tuple2& t2, F&& f) {
    static_assert(std::tuple_size<Tuple1>::value == std::tuple_size<Tuple2>::value, "Can only iterate tuples of same size");

    if(std::tuple_size<Tuple1>::value > 1){
        dual_for_each_impl<std::tuple_size<Tuple1>::value - 2, Tuple1, Tuple2, F>::for_each_rpair_i(t1, t2, std::forward<F>(f));
    }
}

} //end of namespace cpp

#endif //CPP_UTILS_TUPLE_HPP
<commit_msg>Add doc<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file tuple_utils.hpp
 * \brief Contains utilities to work with std::tuple
 */

#ifndef CPP_UTILS_TUPLE_HPP
#define CPP_UTILS_TUPLE_HPP

#include <tuple>

namespace cpp {

namespace tuple_detail {

template<size_t I, typename Tuple, typename F>
struct for_each_impl {
    static void for_each(Tuple& t, F&& f) {
        for_each_impl<I - 1, Tuple, F>::for_each(t, std::forward<F>(f));
        f(std::get<I>(t));
    }

    static void for_each_i(Tuple& t, F&& f) {
        for_each_impl<I - 1, Tuple, F>::for_each_i(t, std::forward<F>(f));
        f(I, std::get<I>(t));
    }

    static void for_each_pair(Tuple& t, F&& f) {
        for_each_impl<I - 1, Tuple, F>::for_each_pair(t, std::forward<F>(f));
        f(std::get<I>(t), std::get<I+1>(t));
    }

    static void for_each_pair_i(Tuple& t, F&& f) {
        for_each_impl<I - 1, Tuple, F>::for_each_pair_i(t, std::forward<F>(f));
        f(I, std::get<I>(t), std::get<I+1>(t));
    }

    static void for_each_rpair(Tuple& t, F&& f) {
        f(std::get<I>(t), std::get<I+1>(t));
        for_each_impl<I - 1, Tuple, F>::for_each_rpair(t, std::forward<F>(f));
    }

    static void for_each_rpair_i(Tuple& t, F&& f) {
        f(I, std::get<I>(t), std::get<I+1>(t));
        for_each_impl<I - 1, Tuple, F>::for_each_rpair_i(t, std::forward<F>(f));
    }
};

template<typename Tuple, typename F>
struct for_each_impl<0, Tuple, F> {
    static void for_each(Tuple& t, F&& f) {
        f(std::get<0>(t));
    }

    static void for_each_i(Tuple& t, F&& f) {
        f(0, std::get<0>(t));
    }

    static void for_each_pair(Tuple& t, F&& f) {
        f(std::get<0>(t), std::get<1>(t));
    }

    static void for_each_pair_i(Tuple& t, F&& f) {
        f(0, std::get<0>(t), std::get<1>(t));
    }

    static void for_each_rpair(Tuple& t, F&& f) {
        f(std::get<0>(t), std::get<1>(t));
    }

    static void for_each_rpair_i(Tuple& t, F&& f) {
        f(0, std::get<0>(t), std::get<1>(t));
    }
};

template<size_t I, typename Tuple1, typename Tuple2, typename F>
struct dual_for_each_impl {
    static void for_each(Tuple1& t1, Tuple2& t2, F&& f) {
        dual_for_each_impl<I - 1, Tuple1, Tuple2, F>::for_each(t1, t2, std::forward<F>(f));
        f(std::get<I>(t1), std::get<I>(t2));
    }

    static void for_each_i(Tuple1& t1, Tuple2& t2, F&& f) {
        dual_for_each_impl<I - 1, Tuple1, Tuple2, F>::for_each_i(t1, t2, std::forward<F>(f));
        f(I, std::get<I>(t1), std::get<I>(t2));
    }

    static void for_each_pair(Tuple1& t1, Tuple2& t2, F&& f) {
        dual_for_each_impl<I - 1, Tuple1, Tuple2, F>::for_each_pair(t1, t2, std::forward<F>(f));
        f(std::get<I>(t1), std::get<I+1>(t1), std::get<I>(t2), std::get<I+1>(t2));
    }

    static void for_each_rpair_i(Tuple1& t1, Tuple2& t2, F&& f) {
        f(I, std::get<I>(t1), std::get<I+1>(t1), std::get<I>(t2), std::get<I+1>(t2));
        dual_for_each_impl<I - 1, Tuple1, Tuple2, F>::for_each_rpair_i(t1, t2, std::forward<F>(f));
    }
};

template<typename Tuple1, typename Tuple2, typename F>
struct dual_for_each_impl<0, Tuple1, Tuple2, F> {
    static void for_each(Tuple1& t1, Tuple2& t2, F&& f) {
        f(std::get<0>(t1), std::get<0>(t2));
    }

    static void for_each_i(Tuple1& t1, Tuple2& t2, F&& f) {
        f(0, std::get<0>(t1), std::get<0>(t2));
    }

    static void for_each_pair(Tuple1& t1, Tuple2& t2, F&& f) {
        f(std::get<0>(t1), std::get<1>(t1), std::get<0>(t2), std::get<1>(t2));
    }

    static void for_each_rpair_i(Tuple1& t1, Tuple2& t2, F&& f) {
        f(0, std::get<0>(t1), std::get<1>(t1), std::get<0>(t2), std::get<1>(t2));
    }
};

} //end of nanespace tuple_detail

/*!
 * \brief Call the given functor with each element of the tuple
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each(Tuple& t, F&& f) {
    tuple_detail::for_each_impl<std::tuple_size<Tuple>::value - 1, Tuple, F>::for_each(t, std::forward<F>(f));
}

/*!
 * \brief Call the given functor with each element of the tuple and its position (zero-indexing)
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each_i(Tuple& t, F&& f) {
    tuple_detail::for_each_impl<std::tuple_size<Tuple>::value - 1, Tuple, F>::for_each_i(t, std::forward<F>(f));
}

/*!
 * \brief Call the given functor with each contiguous pair of element of the tuple.
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each_pair(Tuple& t, F&& f) {
    if(std::tuple_size<Tuple>::value > 1){
        tuple_detail::for_each_impl<std::tuple_size<Tuple>::value - 2, Tuple, F>::for_each_pair(t, std::forward<F>(f));
    }
}

/*!
 * \brief Call the given functor with each contiguous pair of element of the tuple and the position of the first element.
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each_pair_i(Tuple& t, F&& f) {
    if(std::tuple_size<Tuple>::value > 1){
        tuple_detail::for_each_impl<std::tuple_size<Tuple>::value - 2, Tuple, F>::for_each_pair_i(t, std::forward<F>(f));
    }
}

/*!
 * \brief Call the given functor with each contiguous pair of element of the tuple , in reverse order.
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each_rpair(Tuple& t, F&& f) {
    if(std::tuple_size<Tuple>::value > 1){
        tuple_detail::for_each_impl<std::tuple_size<Tuple>::value - 2, Tuple, F>::for_each_rpair(t, std::forward<F>(f));
    }
}

/*!
 * \brief Call the given functor with each position of contiguous pair of element of the tuple, in reverse order.
 * \param t The tuple to iterate over
 * \param f The functor to use
 *
 * If the tuple is heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple, typename F>
void for_each_rpair_i(Tuple& t, F&& f) {
    if(std::tuple_size<Tuple>::value > 1){
        tuple_detail::for_each_impl<std::tuple_size<Tuple>::value - 2, Tuple, F>::for_each_rpair_i(t, std::forward<F>(f));
    }
}

/*!
 * \brief Call the given function with elements of both tuples.
 * \param t1 The first tuple to iterate
 * \param t2 The second tuple to iterate
 * \param f The functor to use
 *
 * If the tuples are heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple1, typename Tuple2, typename F>
void for_each(Tuple1& t1, Tuple2& t2, F&& f) {
    static_assert(std::tuple_size<Tuple1>::value == std::tuple_size<Tuple2>::value, "Can only iterate tuples of same size");

    tuple_detail::dual_for_each_impl<std::tuple_size<Tuple1>::value - 1, Tuple1, Tuple2, F>::for_each(t1, t2, std::forward<F>(f));
}

/*!
 * \brief Call the given function with position of elements of both tuples.
 * \param t1 The first tuple to iterate
 * \param t2 The second tuple to iterate
 * \param f The functor to use
 *
 * If the tuples are heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple1, typename Tuple2, typename F>
void for_each_i(Tuple1& t1, Tuple2& t2, F&& f) {
    static_assert(std::tuple_size<Tuple1>::value == std::tuple_size<Tuple2>::value, "Can only iterate tuples of same size");

    tuple_detail::dual_for_each_impl<std::tuple_size<Tuple1>::value - 1, Tuple1, Tuple2, F>::for_each_i(t1, t2, std::forward<F>(f));
}

/*!
 * \brief Call the given function with pair of elements of both tuples.
 * \param t1 The first tuple to iterate
 * \param t2 The second tuple to iterate
 * \param f The functor to use
 *
 * If the tuples are heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple1, typename Tuple2, typename F>
void for_each_pair(Tuple1& t1, Tuple2& t2, F&& f) {
    static_assert(std::tuple_size<Tuple1>::value == std::tuple_size<Tuple2>::value, "Can only iterate tuples of same size");

    if(std::tuple_size<Tuple1>::value > 1){
        tuple_detail::dual_for_each_impl<std::tuple_size<Tuple1>::value - 2, Tuple1, Tuple2, F>::for_each_pair(t1, t2, std::forward<F>(f));
    }
}

/*!
 * \brief Call the given function with position of pair of elements of both tuples, in reverse order.
 * \param t1 The first tuple to iterate
 * \param t2 The second tuple to iterate
 * \param f The functor to use
 *
 * If the tuples are heterogeneous, the functor must be generic (i.e. generic lambda)
 */
template<typename Tuple1, typename Tuple2, typename F>
void for_each_rpair_i(Tuple1& t1, Tuple2& t2, F&& f) {
    static_assert(std::tuple_size<Tuple1>::value == std::tuple_size<Tuple2>::value, "Can only iterate tuples of same size");

    if(std::tuple_size<Tuple1>::value > 1){
        tuple_detail::dual_for_each_impl<std::tuple_size<Tuple1>::value - 2, Tuple1, Tuple2, F>::for_each_rpair_i(t1, t2, std::forward<F>(f));
    }
}

} //end of namespace cpp

#endif //CPP_UTILS_TUPLE_HPP
<|endoftext|>


<commit_before>// Author: Akira Okumura
/*******************************************************************************
 * This script shows how to simulate a MST by ROBAST.
 ******************************************************************************/

#include "TCanvas.h"
#include "TGeoBBox.h"
#include "TGeoPgon.h"
#include "TGeoSphere.h"
#include "TGeoTube.h"
#include "TGeoCompositeShape.h"
#include "TH2.h"
#include "TThread.h"

#include "AFocalSurface.h"
#include "AMirror.h"
#include "AGeoUtil.h"
#include "ARayShooter.h"
#include "AObscuration.h"
#include "AOpticsManager.h"

// define useful units
const double km = AOpticsManager::km();
const double  m = AOpticsManager::m();
const double cm = AOpticsManager::cm();
const double mm = AOpticsManager::mm();
const double um = AOpticsManager::um();
const double nm = AOpticsManager::nm();

// optics parameters
const double kF = 16.00*m; // focal length
const double kDishShapeLength = 19.20*m; // dish shape length (rad. of curv)
const double kMirroF = 16.07*m; // mirror focal length
const double kMirrorR = kMirroF*2; // the radius of curvature
const double kMirrorD = 1.2*m; // facet diameter, hexagonal mirror
const double kMirrorT = 0.01*mm; // mirror thickness, intentionally use a very thin thickness to avoid unnecessary reflection on the edges

void AddMirrors(AOpticalComponent* opt);
void AddCamera(AOpticalComponent* opt);
void AddMasts(AOpticalComponent* opt);
void RayTrace(AOpticsManager* manager, TCanvas* can3D);

void MST()
{
  TThread::Initialize(); // call this first when you use the multi-thread mode

  AOpticsManager* manager = new AOpticsManager("manager", "MST");
  // Ignore Fresnel reflection in the camera window
  manager->DisableFresnelReflection(kTRUE);
  // Make the OpenGL objects more smooth
  manager->SetNsegments(50);
  // Make the world of 40-km cube
  TGeoBBox* boxWorld = new TGeoBBox("boxWorld", 20*km, 20*km, 20*km);
  AOpticalComponent* world = new AOpticalComponent("world", boxWorld);
  TGeoBBox* boxSmallWorld = new TGeoBBox("boxSmallWorld", 20*m, 20*m, 20*m);
  AOpticalComponent* small_world = new AOpticalComponent("small_world", boxSmallWorld);
  manager->SetTopVolume(world);
  world->AddNode(small_world, 1);

  AddMirrors(small_world);
  AddCamera(small_world);
  manager->CloseGeometry(); // finalize the geometry construction
#if ROOT_VERSION_CODE < ROOT_VERSION(6, 2, 0)
  manager->SetMultiThread(kTRUE); // enable multi threading
#endif
  manager->SetMaxThreads(8); // 8 threads

  TCanvas* can = new TCanvas("can3D", "can3D", 800, 800);
  small_world->Draw("ogl");

  RayTrace(manager, can);
}

void AddMirrors(AOpticalComponent* opt)
{
  double theta = TMath::ASin(kMirrorD/TMath::Sqrt(3)/kMirrorR)*TMath::RadToDeg();
  TGeoSphere* mirSphere = new TGeoSphere("mirSphere", kMirrorR, kMirrorR + kMirrorT, 180. - theta, 180.);

  // copied from cfg/CTA/mirror_CTA-100_1.20-84-0.02.dat
  const int kNMirror = 84;
  double xy[kNMirror][2] =
    {{-549.0,  105.7}, {-488.0,  211.3}, {-427.0,  317.0}, {-366.0,  422.6},
     {-549.0, -105.7}, {-488.0,    0.0}, {-427.0,  105.7}, {-366.0,  211.3},
     {-305.0,  317.0}, {-244.0,  422.6}, {-183.0,  528.3}, {-488.0, -211.3},
     {-427.0, -105.7}, {-366.0,    0.0}, {-305.0,  105.7}, {-244.0,  211.3},
     {-183.0,  317.0}, {-122.0,  422.6}, { -61.0,  528.3}, {-427.0, -317.0},
     {-366.0, -211.3}, {-305.0, -105.7}, {-244.0,    0.0}, {-183.0,  105.7},
     {-122.0,  211.3}, { -61.0,  317.0}, {   0.0,  422.6}, {  61.0,  528.3},
     {-366.0, -422.6}, {-305.0, -317.0}, {-244.0, -211.3}, {-183.0, -105.7},
     {-122.0,    0.0}, { -61.0,  105.7}, {   0.0,  211.3}, {  61.0,  317.0},
     { 122.0,  422.6}, { 183.0,  528.3}, {-244.0, -422.6}, {-183.0, -317.0},
     {-122.0, -211.3}, { -61.0, -105.7}, {  61.0,  105.7}, { 122.0,  211.3},
     { 183.0,  317.0}, { 244.0,  422.6}, {-183.0, -528.3}, {-122.0, -422.6},
     { -61.0, -317.0}, {   0.0, -211.3}, {  61.0, -105.7}, { 122.0,    0.0},
     { 183.0,  105.7}, { 244.0,  211.3}, { 305.0,  317.0}, { 366.0,  422.6},
     { -61.0, -528.3}, {   0.0, -422.6}, {  61.0, -317.0}, { 122.0, -211.3},
     { 183.0, -105.7}, { 244.0,    0.0}, { 305.0,  105.7}, { 366.0,  211.3},
     { 427.0,  317.0}, {  61.0, -528.3}, { 122.0, -422.6}, { 183.0, -317.0},
     { 244.0, -211.3}, { 305.0, -105.7}, { 366.0,    0.0}, { 427.0,  105.7},
     { 488.0,  211.3}, { 183.0, -528.3}, { 244.0, -422.6}, { 305.0, -317.0},
     { 366.0, -211.3}, { 427.0, -105.7}, { 488.0,    0.0}, { 549.0,  105.7},
     { 366.0, -422.6}, { 427.0, -317.0}, { 488.0, -211.3}, { 549.0, -105.7}};

  for(int i = 0; i < kNMirror; i++){
    double x = xy[i][0]*cm;
    double y = xy[i][1]*cm;
    double r2d = TMath::RadToDeg();
    double r2 = TMath::Power(x, 2) + TMath::Power(y, 2);
    double z = kDishShapeLength - TMath::Sqrt(TMath::Power(kDishShapeLength, 2) - r2);

    TGeoPgon* cut = new TGeoPgon("mirCut", 0., 360., 6, 2);
    cut->DefineSection(0, -kMirrorR + 1*m, 0, kMirrorD/2.);
    cut->DefineSection(1, -kMirrorR - 1*m, 0, kMirrorD/2.);

    double phi = TMath::ATan2(y, x)*r2d;
    TGeoRotation* cutrot = new TGeoRotation(Form("cutrot%d", i), -phi, 0., 0.);
    cutrot->RegisterYourself();

    TGeoCompositeShape* mir_cs
      = new TGeoCompositeShape(Form("mir_cs%d", i), Form("mirSphere*(mirCut:cutrot%d)", i));

    AMirror* mirror = new AMirror(Form("mirror%d", i), mir_cs);

    // each mirror center is relocated from the origin (0, 0, 0) to (x, y, z)
    TGeoTranslation* trans = new TGeoTranslation(Form("mirTrans%d", i), x, y, z);

    // and is rotated to compose a DC optics
    theta = TMath::ATan2(TMath::Sqrt(r2), 2*kF - z)*r2d;
    TGeoRotation* rot = new TGeoRotation("", phi - 90., theta, 0);

    // make a matrix from translation and rotation matrices
    TGeoTranslation* transZ = new TGeoTranslation(0, 0, kMirrorR);
    TGeoCombiTrans* combi = new TGeoCombiTrans(*trans, *rot);
    TGeoHMatrix* hmat = new TGeoHMatrix((*combi)*(*transZ));

    // finally add this mirror to the world
    opt->AddNode(mirror, i + 1, hmat);
  } // i
}

void AddCamera(AOpticalComponent* opt)
{
  // parameters taken from sim_telarray/cfg/hess/hess_masts.dat
  const double kCameraD = 2.5*m; // the camera diameter (N/A in cfg)
  const double kCameraBoxD = 3.39*m; // the camera box diameter
  const double kCameraBoxH = 1.5*m; // the camera box height (N/A in cfg)
  const double kCameraOffset = -2.56*cm;

  // Make a disk focal plane
  TGeoTube* tubeCamera = new TGeoTube("tubeCamera", 0, kCameraD/2., 1*mm);
  AFocalSurface* focalPlane = new AFocalSurface("focalPlane", tubeCamera);
  opt->AddNode(focalPlane, 1, new TGeoTranslation(0, 0, kF + kCameraOffset + 1*mm));

  // Make a camera box
  TGeoBBox* tubeCameraBox = new TGeoBBox("tubeCameraBox", kCameraBoxD/2., kCameraBoxD/2., kCameraBoxH/2.);
  double t = 1*cm;
  TGeoBBox* tubeCameraBox2 = new TGeoBBox("tubeCameraBox2", kCameraBoxD/2. - t, kCameraBoxD/2. - t, kCameraBoxH/2. - t);

  TGeoTranslation* transZ1 = new TGeoTranslation("transZ1", 0, 0, kF + kCameraOffset + kCameraBoxH/2.);
  transZ1->RegisterYourself();
  TGeoTranslation* transZ2 = new TGeoTranslation("transZ2", 0, 0, kF + kCameraOffset + kCameraBoxH/2. - t - 1*mm);
  transZ2->RegisterYourself();

  TGeoCompositeShape* boxComposite = new TGeoCompositeShape("boxComposite", "tubeCameraBox:transZ1-tubeCameraBox2:transZ2");

  AObscuration* cameraBox = new AObscuration("cameraBox", boxComposite);
  opt->AddNode(cameraBox, 1);
}

void RayTrace(AOpticsManager* manager, TCanvas* can3D)
{
  const int kNangle = 9;
  TH2D* h2[kNangle];
  TGraph* graph = new TGraph();
  TCanvas* can = new TCanvas("can", "can", 900, 900);
  can->Divide(3, 3, 1e-10, 1e-10);

  for(int i = 0; i < kNangle; i++){
    const double dist = 10*km;
    double angle = i*0.5;
    TGeoRotation rayrot("rayrot", 90, 180 - angle, 0);
    TGeoTranslation raytr("raytr", -dist*TMath::Sin(angle*TMath::DegToRad()),
                          0, dist*TMath::Cos(angle*TMath::DegToRad()));

    double lambda = 400*nm; // dummy

    h2[i] = new TH2D(Form("h%d", i), Form("#it{#theta} = %3.1f#circ;x (mm); y (mm)", angle), 500, -50, 100, 500, -75, 75);

    ARayArray* array = ARayShooter::RandomCone(lambda, 7.5*m, dist, 100000, &rayrot, &raytr);

    manager->TraceNonSequential(*array);

    TObjArray* focused = array->GetFocused();

    for(Int_t k = 0; k <= focused->GetLast(); k++){
      ARay* ray = (ARay*)(*focused)[k];
      Double_t p[4];
      ray->GetLastPoint(p);
      h2[i]->Fill((p[0] - 28.65*angle)/mm, p[1]/mm); // 28 is a rough plate scale

      if (i == kNangle - 1 && k < 30) {
        TPolyLine3D* pol = ray->MakePolyLine3D();
        pol->SetLineColor(2);
        pol->SetLineWidth(2);
        can3D->cd();
        //pol->Draw("same");
      } // if
    } // k

    delete array;
    can->cd(i + 1);
    h2[i]->Draw("colz");
    can->Update();
  } // i
}
<commit_msg>Add graphs to show how to calculate the PSFs in the unit of degree.<commit_after>// Author: Akira Okumura
/*******************************************************************************
 * This script shows how to simulate a MST by ROBAST.
 ******************************************************************************/

#include "TCanvas.h"
#include "TGeoBBox.h"
#include "TGeoPgon.h"
#include "TGeoSphere.h"
#include "TGeoTube.h"
#include "TGeoCompositeShape.h"
#include "TH2.h"
#include "TThread.h"

#include "AFocalSurface.h"
#include "AMirror.h"
#include "AGeoUtil.h"
#include "ARayShooter.h"
#include "AObscuration.h"
#include "AOpticsManager.h"

// define useful units
const double km = AOpticsManager::km();
const double  m = AOpticsManager::m();
const double cm = AOpticsManager::cm();
const double mm = AOpticsManager::mm();
const double um = AOpticsManager::um();
const double nm = AOpticsManager::nm();

// optics parameters
const double kF = 16.00*m; // focal length
const double kDishShapeLength = 19.20*m; // dish shape length (rad. of curv)
const double kMirroF = 16.07*m; // mirror focal length
const double kMirrorR = kMirroF*2; // the radius of curvature
const double kMirrorD = 1.2*m; // facet diameter, hexagonal mirror
const double kMirrorT = 0.01*mm; // mirror thickness, intentionally use a very thin thickness to avoid unnecessary reflection on the edges

void AddMirrors(AOpticalComponent* opt);
void AddCamera(AOpticalComponent* opt);
void AddMasts(AOpticalComponent* opt);
void RayTrace(AOpticsManager* manager, TCanvas* can3D);

void MST()
{
  TThread::Initialize(); // call this first when you use the multi-thread mode

  AOpticsManager* manager = new AOpticsManager("manager", "MST");
  // Ignore Fresnel reflection in the camera window
  manager->DisableFresnelReflection(kTRUE);
  // Make the OpenGL objects more smooth
  manager->SetNsegments(50);
  // Make the world of 40-km cube
  TGeoBBox* boxWorld = new TGeoBBox("boxWorld", 20*km, 20*km, 20*km);
  AOpticalComponent* world = new AOpticalComponent("world", boxWorld);
  TGeoBBox* boxSmallWorld = new TGeoBBox("boxSmallWorld", 20*m, 20*m, 20*m);
  AOpticalComponent* small_world = new AOpticalComponent("small_world", boxSmallWorld);
  manager->SetTopVolume(world);
  world->AddNode(small_world, 1);

  AddMirrors(small_world);
  AddCamera(small_world);
  manager->CloseGeometry(); // finalize the geometry construction
#if ROOT_VERSION_CODE < ROOT_VERSION(6, 2, 0)
  manager->SetMultiThread(kTRUE); // enable multi threading
#endif
  manager->SetMaxThreads(8); // 8 threads

  TCanvas* can = new TCanvas("can3D", "can3D", 800, 800);
  small_world->Draw("ogl");

  RayTrace(manager, can);
}

void AddMirrors(AOpticalComponent* opt)
{
  double theta = TMath::ASin(kMirrorD/TMath::Sqrt(3)/kMirrorR)*TMath::RadToDeg();
  TGeoSphere* mirSphere = new TGeoSphere("mirSphere", kMirrorR, kMirrorR + kMirrorT, 180. - theta, 180.);

  // copied from cfg/CTA/mirror_CTA-100_1.20-84-0.02.dat
  const int kNMirror = 84;
  double xy[kNMirror][2] =
    {{-549.0,  105.7}, {-488.0,  211.3}, {-427.0,  317.0}, {-366.0,  422.6},
     {-549.0, -105.7}, {-488.0,    0.0}, {-427.0,  105.7}, {-366.0,  211.3},
     {-305.0,  317.0}, {-244.0,  422.6}, {-183.0,  528.3}, {-488.0, -211.3},
     {-427.0, -105.7}, {-366.0,    0.0}, {-305.0,  105.7}, {-244.0,  211.3},
     {-183.0,  317.0}, {-122.0,  422.6}, { -61.0,  528.3}, {-427.0, -317.0},
     {-366.0, -211.3}, {-305.0, -105.7}, {-244.0,    0.0}, {-183.0,  105.7},
     {-122.0,  211.3}, { -61.0,  317.0}, {   0.0,  422.6}, {  61.0,  528.3},
     {-366.0, -422.6}, {-305.0, -317.0}, {-244.0, -211.3}, {-183.0, -105.7},
     {-122.0,    0.0}, { -61.0,  105.7}, {   0.0,  211.3}, {  61.0,  317.0},
     { 122.0,  422.6}, { 183.0,  528.3}, {-244.0, -422.6}, {-183.0, -317.0},
     {-122.0, -211.3}, { -61.0, -105.7}, {  61.0,  105.7}, { 122.0,  211.3},
     { 183.0,  317.0}, { 244.0,  422.6}, {-183.0, -528.3}, {-122.0, -422.6},
     { -61.0, -317.0}, {   0.0, -211.3}, {  61.0, -105.7}, { 122.0,    0.0},
     { 183.0,  105.7}, { 244.0,  211.3}, { 305.0,  317.0}, { 366.0,  422.6},
     { -61.0, -528.3}, {   0.0, -422.6}, {  61.0, -317.0}, { 122.0, -211.3},
     { 183.0, -105.7}, { 244.0,    0.0}, { 305.0,  105.7}, { 366.0,  211.3},
     { 427.0,  317.0}, {  61.0, -528.3}, { 122.0, -422.6}, { 183.0, -317.0},
     { 244.0, -211.3}, { 305.0, -105.7}, { 366.0,    0.0}, { 427.0,  105.7},
     { 488.0,  211.3}, { 183.0, -528.3}, { 244.0, -422.6}, { 305.0, -317.0},
     { 366.0, -211.3}, { 427.0, -105.7}, { 488.0,    0.0}, { 549.0,  105.7},
     { 366.0, -422.6}, { 427.0, -317.0}, { 488.0, -211.3}, { 549.0, -105.7}};

  for(int i = 0; i < kNMirror; i++){
    double x = xy[i][0]*cm;
    double y = xy[i][1]*cm;
    double r2d = TMath::RadToDeg();
    double r2 = TMath::Power(x, 2) + TMath::Power(y, 2);
    double z = kDishShapeLength - TMath::Sqrt(TMath::Power(kDishShapeLength, 2) - r2);

    TGeoPgon* cut = new TGeoPgon("mirCut", 0., 360., 6, 2);
    cut->DefineSection(0, -kMirrorR + 1*m, 0, kMirrorD/2.);
    cut->DefineSection(1, -kMirrorR - 1*m, 0, kMirrorD/2.);

    double phi = TMath::ATan2(y, x)*r2d;
    TGeoRotation* cutrot = new TGeoRotation(Form("cutrot%d", i), -phi, 0., 0.);
    cutrot->RegisterYourself();

    TGeoCompositeShape* mir_cs
      = new TGeoCompositeShape(Form("mir_cs%d", i), Form("mirSphere*(mirCut:cutrot%d)", i));

    AMirror* mirror = new AMirror(Form("mirror%d", i), mir_cs);

    // each mirror center is relocated from the origin (0, 0, 0) to (x, y, z)
    TGeoTranslation* trans = new TGeoTranslation(Form("mirTrans%d", i), x, y, z);

    // and is rotated to compose a DC optics
    theta = TMath::ATan2(TMath::Sqrt(r2), 2*kF - z)*r2d;
    TGeoRotation* rot = new TGeoRotation("", phi - 90., theta, 0);

    // make a matrix from translation and rotation matrices
    TGeoTranslation* transZ = new TGeoTranslation(0, 0, kMirrorR);
    TGeoCombiTrans* combi = new TGeoCombiTrans(*trans, *rot);
    TGeoHMatrix* hmat = new TGeoHMatrix((*combi)*(*transZ));

    // finally add this mirror to the world
    opt->AddNode(mirror, i + 1, hmat);
  } // i
}

void AddCamera(AOpticalComponent* opt)
{
  // parameters taken from sim_telarray/cfg/hess/hess_masts.dat
  const double kCameraD = 2.5*m; // the camera diameter (N/A in cfg)
  const double kCameraBoxD = 3.39*m; // the camera box diameter
  const double kCameraBoxH = 1.5*m; // the camera box height (N/A in cfg)
  const double kCameraOffset = -2.56*cm;

  // Make a disk focal plane
  TGeoTube* tubeCamera = new TGeoTube("tubeCamera", 0, kCameraD/2., 1*mm);
  AFocalSurface* focalPlane = new AFocalSurface("focalPlane", tubeCamera);
  opt->AddNode(focalPlane, 1, new TGeoTranslation(0, 0, kF + kCameraOffset + 1*mm));

  // Make a camera box
  TGeoBBox* tubeCameraBox = new TGeoBBox("tubeCameraBox", kCameraBoxD/2., kCameraBoxD/2., kCameraBoxH/2.);
  double t = 1*cm;
  TGeoBBox* tubeCameraBox2 = new TGeoBBox("tubeCameraBox2", kCameraBoxD/2. - t, kCameraBoxD/2. - t, kCameraBoxH/2. - t);

  TGeoTranslation* transZ1 = new TGeoTranslation("transZ1", 0, 0, kF + kCameraOffset + kCameraBoxH/2.);
  transZ1->RegisterYourself();
  TGeoTranslation* transZ2 = new TGeoTranslation("transZ2", 0, 0, kF + kCameraOffset + kCameraBoxH/2. - t - 1*mm);
  transZ2->RegisterYourself();

  TGeoCompositeShape* boxComposite = new TGeoCompositeShape("boxComposite", "tubeCameraBox:transZ1-tubeCameraBox2:transZ2");

  AObscuration* cameraBox = new AObscuration("cameraBox", boxComposite);
  opt->AddNode(cameraBox, 1);
}

void RayTrace(AOpticsManager* manager, TCanvas* can3D)
{
  const int kNangle = 9;
  TH2D* h2[kNangle];
  TCanvas* can = new TCanvas("can", "can", 900, 900);
  can->Divide(3, 3, 1e-10, 1e-10);

  TGraph* graphX = new TGraph;

  for(int i = 0; i < kNangle; i++){
    const double dist = 10*km;
    double angle = i*0.5;
    TGeoRotation rayrot("rayrot", 90, 180 - angle, 0);
    TGeoTranslation raytr("raytr", -dist*TMath::Sin(angle*TMath::DegToRad()),
                          0, dist*TMath::Cos(angle*TMath::DegToRad()));

    double lambda = 400*nm; // dummy

    ARayArray* array = ARayShooter::RandomCone(lambda, 7.5*m, dist, 100000, &rayrot, &raytr);

    manager->TraceNonSequential(*array);

    TObjArray* focused = array->GetFocused();

    const double platescale = 28.65; // (mm/deg)

    TH1D htmp("", "", 1, -1e10, 1e10);
    for(Int_t k = 0; k <= focused->GetLast(); k++){
      ARay* ray = (ARay*)(*focused)[k];
      Double_t p[4];
      ray->GetLastPoint(p);
      htmp.Fill(p[0]);
    }

    double meanx = htmp.GetMean();
    h2[i] = new TH2D(Form("h%d", i), Form("#it{#theta} = %3.1f#circ;x (mm); y (mm)", angle), 300, meanx/mm - 40, meanx/mm + 140, 300, -90, 90);

    for(Int_t k = 0; k <= focused->GetLast(); k++){
      ARay* ray = (ARay*)(*focused)[k];
      Double_t p[4];
      ray->GetLastPoint(p);
      h2[i]->Fill(p[0]/mm, p[1]/mm);

      if (i == kNangle - 1 && k < 30) {
        TPolyLine3D* pol = ray->MakePolyLine3D();
        pol->SetLineColor(2);
        pol->SetLineWidth(2);
        can3D->cd();
        //pol->Draw("same");
      } // if
    } // k

    delete array;
    can->cd(i + 1);
    h2[i]->Draw("colz");
    can->Update();

    graphX->SetPoint(graphX->GetN(), angle, meanx/mm);
  } // i

  TCanvas* can2 = new TCanvas("can2", "can2", 800, 600);
  can2->DrawFrame(0, 0, 4, 1200, ";Field Angle (deg);<#it{x}> (mm);");
  graphX->SetMarkerStyle(20);
  graphX->Draw("p same");

  Double_t pscale = graphX->GetY()[graphX->GetN() - 1]*mm/graphX->GetX()[graphX->GetN() - 1]; // plate scale

  TGraph* graphStdX = new TGraph;
  TGraph* graphStdY = new TGraph;

  for(int i = 0; i < kNangle; i++){
    Double_t stdx = h2[i]->GetStdDev(1);
    Double_t stdy = h2[i]->GetStdDev(2);
    double angle = i*0.5;
    graphStdX->SetPoint(i, angle, stdx*mm/pscale);
    graphStdY->SetPoint(i, angle, stdy*mm/pscale);
  } // i

  TCanvas* can3 = new TCanvas("can3", "can3", 800, 600);
  can3->DrawFrame(0, 0, 4, 0.11, ";Field Angle (deg);Std. Dev. (deg);");
  graphStdX->Draw("p same");
  graphStdX->SetMarkerStyle(20);
  graphStdY->Draw("p same");
  graphStdY->SetMarkerStyle(21);

  TLegend* leg = new TLegend(0.15, 0.6, 0.5, 0.85);
  leg->AddEntry(graphStdX, "Std. Dev. along X", "p");
  leg->AddEntry(graphStdY, "Std. Dev. along Y", "p");
  leg->Draw();
}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2014 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/logging.h"
#include "xenia/emulator.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam_private.h"
#include "xenia/xbox.h"

#include <commctrl.h>

namespace xe {
namespace kernel {

// http://www.se7ensins.com/forums/threads/working-xshowmessageboxui.844116/?jdfwkey=sb0vm
SHIM_CALL XamShowMessageBoxUI_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t user_index = SHIM_GET_ARG_32(0);
  uint32_t title_ptr = SHIM_GET_ARG_32(1);
  uint32_t text_ptr = SHIM_GET_ARG_32(2);
  uint32_t button_count = SHIM_GET_ARG_32(3);
  uint32_t button_ptrs = SHIM_GET_ARG_32(4);
  uint32_t active_button = SHIM_GET_ARG_32(5);
  uint32_t flags = SHIM_GET_ARG_32(6);
  uint32_t result_ptr = SHIM_GET_ARG_32(7);
  // arg8 is in stack!
  uint32_t sp = (uint32_t)ppc_state->r[1];
  uint32_t overlapped_ptr = SHIM_MEM_32(sp + 0x54);

  auto title = xe::load_and_swap<std::wstring>(SHIM_MEM_ADDR(title_ptr));
  auto text = xe::load_and_swap<std::wstring>(SHIM_MEM_ADDR(text_ptr));
  std::vector<std::wstring> buttons;
  std::wstring all_buttons;
  for (uint32_t j = 0; j < button_count; ++j) {
    uint32_t button_ptr = SHIM_MEM_32(button_ptrs + j * 4);
    auto button = xe::load_and_swap<std::wstring>(SHIM_MEM_ADDR(button_ptr));
    all_buttons.append(button);
    if (j + 1 < button_count) {
      all_buttons.append(L" | ");
    }
    buttons.push_back(button);
  }

  XELOGD(
      "XamShowMessageBoxUI(%d, %.8X(%S), %.8X(%S), %d, %.8X(%S), %d, %X, %.8X, "
      "%.8X)",
      user_index, title_ptr, title.c_str(), text_ptr, text.c_str(),
      button_count, button_ptrs, all_buttons.c_str(), active_button, flags,
      result_ptr, overlapped_ptr);

  uint32_t chosen_button;
  if (FLAGS_headless) {
    // Auto-pick the focused button.
    chosen_button = active_button;
  } else {
    TASKDIALOGCONFIG config = {0};
    config.cbSize = sizeof(config);
    config.hInstance = GetModuleHandle(nullptr);
    config.hwndParent = state->emulator()->main_window()->hwnd();
    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION |   // esc to exit
                     TDF_POSITION_RELATIVE_TO_WINDOW;  // center in window
    config.dwCommonButtons = 0;
    config.pszWindowTitle = title.c_str();
    switch (flags & 0xF) {
      case 0:
        config.pszMainIcon = nullptr;
        break;
      case 1:
        config.pszMainIcon = TD_ERROR_ICON;
        break;
      case 2:
        config.pszMainIcon = TD_WARNING_ICON;
        break;
      case 3:
        config.pszMainIcon = TD_INFORMATION_ICON;
        break;
    }
    config.pszMainInstruction = text.c_str();
    config.pszContent = nullptr;
    std::vector<TASKDIALOG_BUTTON> taskdialog_buttons;
    for (uint32_t i = 0; i < button_count; ++i) {
      taskdialog_buttons.push_back({1000 + int(i), buttons[i].c_str()});
    }
    config.pButtons = taskdialog_buttons.data();
    config.cButtons = button_count;
    config.nDefaultButton = active_button;
    int button_pressed = 0;
    TaskDialogIndirect(&config, &button_pressed, nullptr, nullptr);
    switch (button_pressed) {
      default:
        chosen_button = button_pressed - 1000;
        break;
      case IDCANCEL:
        // User cancelled, just pick default.
        chosen_button = active_button;
        break;
    }
  }
  SHIM_SET_MEM_32(result_ptr, chosen_button);

  state->CompleteOverlappedImmediate(overlapped_ptr, X_ERROR_SUCCESS);
  SHIM_SET_RETURN_32(X_ERROR_IO_PENDING);
}

SHIM_CALL XamShowDirtyDiscErrorUI_shim(PPCContext* ppc_state,
                                       KernelState* state) {
  uint32_t user_index = SHIM_GET_ARG_32(0);

  XELOGD("XamShowDirtyDiscErrorUI(%d)", user_index);

  int button_pressed = 0;
  TaskDialog(state->emulator()->main_window()->hwnd(), GetModuleHandle(nullptr),
             L"Disc Read Error",
             L"Game is claiming to be unable to read game data!", nullptr,
             TDCBF_CLOSE_BUTTON, TD_ERROR_ICON, &button_pressed);

  // This is death, and should never return.
  assert_always();
}

}  // namespace kernel
}  // namespace xe

void xe::kernel::xam::RegisterUIExports(
    xe::cpu::ExportResolver* export_resolver, KernelState* state) {
  SHIM_SET_MAPPING("xam.xex", XamShowMessageBoxUI, state);
  SHIM_SET_MAPPING("xam.xex", XamShowDirtyDiscErrorUI, state);
}
<commit_msg>Added XamIsUIActive.<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2014 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/logging.h"
#include "xenia/emulator.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam_private.h"
#include "xenia/xbox.h"

#include <commctrl.h>

namespace xe {
namespace kernel {

SHIM_CALL XamIsUIActive_shim(PPCContext* ppc_state, KernelState* state) {
  XELOGD("XamIsUIActive()");
  SHIM_SET_RETURN_32(0);
}

// http://www.se7ensins.com/forums/threads/working-xshowmessageboxui.844116/?jdfwkey=sb0vm
SHIM_CALL XamShowMessageBoxUI_shim(PPCContext* ppc_state, KernelState* state) {
  uint32_t user_index = SHIM_GET_ARG_32(0);
  uint32_t title_ptr = SHIM_GET_ARG_32(1);
  uint32_t text_ptr = SHIM_GET_ARG_32(2);
  uint32_t button_count = SHIM_GET_ARG_32(3);
  uint32_t button_ptrs = SHIM_GET_ARG_32(4);
  uint32_t active_button = SHIM_GET_ARG_32(5);
  uint32_t flags = SHIM_GET_ARG_32(6);
  uint32_t result_ptr = SHIM_GET_ARG_32(7);
  // arg8 is in stack!
  uint32_t sp = (uint32_t)ppc_state->r[1];
  uint32_t overlapped_ptr = SHIM_MEM_32(sp + 0x54);

  auto title = xe::load_and_swap<std::wstring>(SHIM_MEM_ADDR(title_ptr));
  auto text = xe::load_and_swap<std::wstring>(SHIM_MEM_ADDR(text_ptr));
  std::vector<std::wstring> buttons;
  std::wstring all_buttons;
  for (uint32_t j = 0; j < button_count; ++j) {
    uint32_t button_ptr = SHIM_MEM_32(button_ptrs + j * 4);
    auto button = xe::load_and_swap<std::wstring>(SHIM_MEM_ADDR(button_ptr));
    all_buttons.append(button);
    if (j + 1 < button_count) {
      all_buttons.append(L" | ");
    }
    buttons.push_back(button);
  }

  XELOGD(
      "XamShowMessageBoxUI(%d, %.8X(%S), %.8X(%S), %d, %.8X(%S), %d, %X, %.8X, "
      "%.8X)",
      user_index, title_ptr, title.c_str(), text_ptr, text.c_str(),
      button_count, button_ptrs, all_buttons.c_str(), active_button, flags,
      result_ptr, overlapped_ptr);

  uint32_t chosen_button;
  if (FLAGS_headless) {
    // Auto-pick the focused button.
    chosen_button = active_button;
  } else {
    TASKDIALOGCONFIG config = {0};
    config.cbSize = sizeof(config);
    config.hInstance = GetModuleHandle(nullptr);
    config.hwndParent = state->emulator()->main_window()->hwnd();
    config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION |   // esc to exit
                     TDF_POSITION_RELATIVE_TO_WINDOW;  // center in window
    config.dwCommonButtons = 0;
    config.pszWindowTitle = title.c_str();
    switch (flags & 0xF) {
      case 0:
        config.pszMainIcon = nullptr;
        break;
      case 1:
        config.pszMainIcon = TD_ERROR_ICON;
        break;
      case 2:
        config.pszMainIcon = TD_WARNING_ICON;
        break;
      case 3:
        config.pszMainIcon = TD_INFORMATION_ICON;
        break;
    }
    config.pszMainInstruction = text.c_str();
    config.pszContent = nullptr;
    std::vector<TASKDIALOG_BUTTON> taskdialog_buttons;
    for (uint32_t i = 0; i < button_count; ++i) {
      taskdialog_buttons.push_back({1000 + int(i), buttons[i].c_str()});
    }
    config.pButtons = taskdialog_buttons.data();
    config.cButtons = button_count;
    config.nDefaultButton = active_button;
    int button_pressed = 0;
    TaskDialogIndirect(&config, &button_pressed, nullptr, nullptr);
    switch (button_pressed) {
      default:
        chosen_button = button_pressed - 1000;
        break;
      case IDCANCEL:
        // User cancelled, just pick default.
        chosen_button = active_button;
        break;
    }
  }
  SHIM_SET_MEM_32(result_ptr, chosen_button);

  state->CompleteOverlappedImmediate(overlapped_ptr, X_ERROR_SUCCESS);
  SHIM_SET_RETURN_32(X_ERROR_IO_PENDING);
}

SHIM_CALL XamShowDirtyDiscErrorUI_shim(PPCContext* ppc_state,
                                       KernelState* state) {
  uint32_t user_index = SHIM_GET_ARG_32(0);

  XELOGD("XamShowDirtyDiscErrorUI(%d)", user_index);

  int button_pressed = 0;
  TaskDialog(state->emulator()->main_window()->hwnd(), GetModuleHandle(nullptr),
             L"Disc Read Error",
             L"Game is claiming to be unable to read game data!", nullptr,
             TDCBF_CLOSE_BUTTON, TD_ERROR_ICON, &button_pressed);

  // This is death, and should never return.
  assert_always();
}

}  // namespace kernel
}  // namespace xe

void xe::kernel::xam::RegisterUIExports(
    xe::cpu::ExportResolver* export_resolver, KernelState* state) {
  SHIM_SET_MAPPING("xam.xex", XamIsUIActive, state);
  SHIM_SET_MAPPING("xam.xex", XamShowMessageBoxUI, state);
  SHIM_SET_MAPPING("xam.xex", XamShowDirtyDiscErrorUI, state);
}
<|endoftext|>


<commit_before>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/io/MemoryFile.h>
#include <xzero/io/MemoryMap.h>
#include <xzero/io/FileUtil.h>
#include <xzero/io/FileDescriptor.h>
#include <xzero/io/FileInputStream.h>
#include <xzero/io/FileOutputStream.h>
#include <xzero/Buffer.h>
#include <xzero/hash/FNV.h>
#include <xzero/io/FileUtil.h>
#include <xzero/StringUtil.h>
#include <xzero/RuntimeError.h>
#include <xzero/sysconfig.h>

#include <fstream>
#include <ctime>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

namespace xzero {

// Since OS/X doesn't support SHM in a way Linux does, we need to work around it.
#if XZERO_OS_DARWIN
#  define XZERO_MEMORYFILE_USE_TMPFILE
#else
// Use TMPFILE here, too (for now), because create*Channel would fail otherwise.
// So let's create a posix_filebuf
//#  define XZERO_MEMORYFILE_USE_SHM
#  define XZERO_MEMORYFILE_USE_TMPFILE
#endif

MemoryFile::MemoryFile()
    : File("", ""),
      mtime_(0),
      inode_(0),
      size_(0),
      etag_(),
      fspath_(),
      fd_(-1) {
}

MemoryFile::MemoryFile(
    const std::string& path,
    const std::string& mimetype,
    const BufferRef& data,
    UnixTime mtime)
    : File(path, mimetype),
      mtime_(mtime.unixtime()),
      inode_(0),
      size_(data.size()),
      etag_(std::to_string(data.hash())),
      fspath_(),
      fd_(-1) {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  fspath_ = FileUtil::joinPaths(FileUtil::tempDirectory(), "memfile.XXXXXXXX");

  fd_ = mkstemp(const_cast<char*>(fspath_.c_str()));
  if (fd_ < 0)
    RAISE_ERRNO(errno);

  if (ftruncate(fd_, size()) < 0)
    RAISE_ERRNO(errno);

  ssize_t n = pwrite(fd_, data.data(), data.size(), 0);
  if (n < 0)
    RAISE_ERRNO(errno);
#else
  // TODO: URL-escape instead
  fspath_ = path;
  StringUtil::replaceAll(&fspath_, "/", "\%2f");

  if (fspath_.size() >= NAME_MAX)
    RAISE_ERRNO(ENAMETOOLONG);

  FileDescriptor fd = shm_open(fspath_.c_str(), O_RDWR | O_CREAT, 0600);
  if (fd < 0)
    RAISE_ERRNO(errno);

  if (ftruncate(fd, size()) < 0)
    RAISE_ERRNO(errno);

  ssize_t n = pwrite(fd, data.data(), data.size(), 0);
  if (n < 0)
    RAISE_ERRNO(errno);
#endif

  if (static_cast<size_t>(n) != data.size())
    RAISE_ERRNO(EIO);
}

MemoryFile::~MemoryFile() {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  if (fd_ >= 0) {
    FileUtil::close(fd_);
  }
#else
  shm_unlink(fspath_.c_str());
#endif
}

const std::string& MemoryFile::etag() const {
  return etag_;
}

size_t MemoryFile::size() const XZERO_NOEXCEPT {
  return size_;
}

time_t MemoryFile::mtime() const XZERO_NOEXCEPT {
  return mtime_;
}

size_t MemoryFile::inode() const XZERO_NOEXCEPT {
  return inode_;
}

bool MemoryFile::isRegular() const XZERO_NOEXCEPT {
  return true;
}

bool MemoryFile::isDirectory() const XZERO_NOEXCEPT {
  return false;
}

bool MemoryFile::isExecutable() const XZERO_NOEXCEPT {
  return false;
}

int MemoryFile::createPosixChannel(OpenFlags oflags) {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  if (fd_ < 0) {
    errno = ENOENT;
    return -1;
  }

  // XXX when using dup(fd_) we'd also need to fcntl() the flags.
  // - Both having advantages / disadvantages.
  return ::open(fspath_.c_str(), to_posix(oflags));
#else
  return shm_open(fspath_.c_str(), to_posix(oflags), 0600);
#endif
}

std::unique_ptr<InputStream> MemoryFile::createInputChannel() {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  return std::unique_ptr<InputStream>(new FileInputStream(fspath_));
#else
  RAISE(RuntimeError, "Not implemented.");
#endif
}

std::unique_ptr<OutputStream> MemoryFile::createOutputChannel(File::OpenFlags flags, int mode) {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  return std::unique_ptr<OutputStream>(new FileOutputStream(fspath_, flags, mode));
#else
  RAISE(RuntimeError, "Not implemented.");
#endif
}

std::unique_ptr<MemoryMap> MemoryFile::createMemoryMap(bool rw) {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  // use FileDescriptor for auto-closing here, in case of exceptions
  FileDescriptor fd = ::open(fspath_.c_str(), rw ? O_RDWR : O_RDONLY);
  if (fd < 0)
    RAISE_ERRNO(errno);

  return std::unique_ptr<MemoryMap>(new MemoryMap(fd, 0, size(), rw));
#else
  return std::unique_ptr<MemoryMap>(new MemoryMap(fd_, 0, size(), rw));
#endif
}

} // namespace xzero
<commit_msg>[xzero] MemoryFile: fixes bug in createPosixChannel() when fd < 0<commit_after>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/io/MemoryFile.h>
#include <xzero/io/MemoryMap.h>
#include <xzero/io/FileUtil.h>
#include <xzero/io/FileDescriptor.h>
#include <xzero/io/FileInputStream.h>
#include <xzero/io/FileOutputStream.h>
#include <xzero/Buffer.h>
#include <xzero/hash/FNV.h>
#include <xzero/io/FileUtil.h>
#include <xzero/StringUtil.h>
#include <xzero/RuntimeError.h>
#include <xzero/sysconfig.h>

#include <fstream>
#include <ctime>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

namespace xzero {

// Since OS/X doesn't support SHM in a way Linux does, we need to work around it.
#if XZERO_OS_DARWIN
#  define XZERO_MEMORYFILE_USE_TMPFILE
#else
// Use TMPFILE here, too (for now), because create*Channel would fail otherwise.
// So let's create a posix_filebuf
//#  define XZERO_MEMORYFILE_USE_SHM
#  define XZERO_MEMORYFILE_USE_TMPFILE
#endif

MemoryFile::MemoryFile()
    : File("", ""),
      mtime_(0),
      inode_(0),
      size_(0),
      etag_(),
      fspath_(),
      fd_(-1) {
}

MemoryFile::MemoryFile(
    const std::string& path,
    const std::string& mimetype,
    const BufferRef& data,
    UnixTime mtime)
    : File(path, mimetype),
      mtime_(mtime.unixtime()),
      inode_(0),
      size_(data.size()),
      etag_(std::to_string(data.hash())),
      fspath_(),
      fd_(-1) {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  fspath_ = FileUtil::joinPaths(FileUtil::tempDirectory(), "memfile.XXXXXXXX");

  fd_ = mkstemp(const_cast<char*>(fspath_.c_str()));
  if (fd_ < 0)
    RAISE_ERRNO(errno);

  if (ftruncate(fd_, size()) < 0)
    RAISE_ERRNO(errno);

  ssize_t n = pwrite(fd_, data.data(), data.size(), 0);
  if (n < 0)
    RAISE_ERRNO(errno);
#else
  // TODO: URL-escape instead
  fspath_ = path;
  StringUtil::replaceAll(&fspath_, "/", "\%2f");

  if (fspath_.size() >= NAME_MAX)
    RAISE_ERRNO(ENAMETOOLONG);

  FileDescriptor fd = shm_open(fspath_.c_str(), O_RDWR | O_CREAT, 0600);
  if (fd < 0)
    RAISE_ERRNO(errno);

  if (ftruncate(fd, size()) < 0)
    RAISE_ERRNO(errno);

  ssize_t n = pwrite(fd, data.data(), data.size(), 0);
  if (n < 0)
    RAISE_ERRNO(errno);
#endif

  if (static_cast<size_t>(n) != data.size())
    RAISE_ERRNO(EIO);
}

MemoryFile::~MemoryFile() {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  if (fd_ >= 0) {
    FileUtil::close(fd_);
  }
#else
  shm_unlink(fspath_.c_str());
#endif
}

const std::string& MemoryFile::etag() const {
  return etag_;
}

size_t MemoryFile::size() const XZERO_NOEXCEPT {
  return size_;
}

time_t MemoryFile::mtime() const XZERO_NOEXCEPT {
  return mtime_;
}

size_t MemoryFile::inode() const XZERO_NOEXCEPT {
  return inode_;
}

bool MemoryFile::isRegular() const XZERO_NOEXCEPT {
  return true;
}

bool MemoryFile::isDirectory() const XZERO_NOEXCEPT {
  return false;
}

bool MemoryFile::isExecutable() const XZERO_NOEXCEPT {
  return false;
}

int MemoryFile::createPosixChannel(OpenFlags oflags) {
  if (fd_ < 0) {
    errno = ENOENT;
    return -1;
  }

#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  // XXX when using dup(fd_) we'd also need to fcntl() the flags.
  // - Both having advantages / disadvantages.
  return ::open(fspath_.c_str(), to_posix(oflags));
#else
  return shm_open(fspath_.c_str(), to_posix(oflags), 0600);
#endif
}

std::unique_ptr<InputStream> MemoryFile::createInputChannel() {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  return std::unique_ptr<InputStream>(new FileInputStream(fspath_));
#else
  RAISE(RuntimeError, "Not implemented.");
#endif
}

std::unique_ptr<OutputStream> MemoryFile::createOutputChannel(File::OpenFlags flags, int mode) {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  return std::unique_ptr<OutputStream>(new FileOutputStream(fspath_, flags, mode));
#else
  RAISE(RuntimeError, "Not implemented.");
#endif
}

std::unique_ptr<MemoryMap> MemoryFile::createMemoryMap(bool rw) {
#if defined(XZERO_MEMORYFILE_USE_TMPFILE)
  // use FileDescriptor for auto-closing here, in case of exceptions
  FileDescriptor fd = ::open(fspath_.c_str(), rw ? O_RDWR : O_RDONLY);
  if (fd < 0)
    RAISE_ERRNO(errno);

  return std::unique_ptr<MemoryMap>(new MemoryMap(fd, 0, size(), rw));
#else
  return std::unique_ptr<MemoryMap>(new MemoryMap(fd_, 0, size(), rw));
#endif
}

} // namespace xzero
<|endoftext|>


<commit_before>/* Copyright 2022 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/compiler/mlir/quantization/tensorflow/utils/quant_spec.h"

#include <memory>

#include "tensorflow/compiler/mlir/lite/quantization/quantization_utils.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"

namespace mlir {
namespace quant {

std::unique_ptr<OpQuantScaleSpec> GetTfQuantScaleSpec(Operation* op) {
  auto scale_spec = std::make_unique<OpQuantScaleSpec>();
  if (llvm::isa<
          // clang-format off
          // go/keep-sorted start
          TF::IdentityOp,
          TF::MaxPoolOp,
          TF::ReshapeOp
          // go/keep-sorted end
          // clang-format on
          >(op)) {
    scale_spec->has_same_scale_requirement = true;
  }
  return scale_spec;
}

}  // namespace quant
}  // namespace mlir
<commit_msg>Add ConcatV2 to the list of same scale ops<commit_after>/* Copyright 2022 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/compiler/mlir/quantization/tensorflow/utils/quant_spec.h"

#include <memory>

#include "tensorflow/compiler/mlir/lite/quantization/quantization_utils.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"

namespace mlir {
namespace quant {

std::unique_ptr<OpQuantScaleSpec> GetTfQuantScaleSpec(Operation* op) {
  auto scale_spec = std::make_unique<OpQuantScaleSpec>();
  if (llvm::isa<
          // clang-format off
          // go/keep-sorted start
          TF::ConcatV2Op,
          TF::IdentityOp,
          TF::MaxPoolOp,
          TF::ReshapeOp
          // go/keep-sorted end
          // clang-format on
          >(op)) {
    scale_spec->has_same_scale_requirement = true;
  }
  return scale_spec;
}

}  // namespace quant
}  // namespace mlir
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <fstream>

// template <class charT, class traits = char_traits<charT> >
// class basic_fstream

// explicit basic_fstream(const string& s, ios_base::openmode mode = ios_base::in|ios_base::out);

#include <fstream>
#include <cassert>

int main()
{
    {
        std::fstream fs(std::string("test.dat"),
                        std::ios_base::in | std::ios_base::out
                                          | std::ios_base::trunc);
        double x = 0;
        fs << 3.25;
        fs.seekg(0);
        fs >> x;
        assert(x == 3.25);
    }
    std::remove("test.dat");
    {
        std::wfstream fs(std::string("test.dat"),
                         std::ios_base::in | std::ios_base::out
                                           | std::ios_base::trunc);
        double x = 0;
        fs << 3.25;
        fs.seekg(0);
        fs >> x;
        assert(x == 3.25);
    }
    std::remove("test.dat");
}
<commit_msg>Do a litmus test of using tmpnam to generate safe temporary file names for the tests that open new data files.<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <fstream>

// template <class charT, class traits = char_traits<charT> >
// class basic_fstream

// explicit basic_fstream(const string& s, ios_base::openmode mode = ios_base::in|ios_base::out);

#include <fstream>
#include <cassert>

int main()
{
    char temp [L_tmpnam];
    tmpnam(temp);
    {
        std::fstream fs(std::string(temp),
                        std::ios_base::in | std::ios_base::out
                                          | std::ios_base::trunc);
        double x = 0;
        fs << 3.25;
        fs.seekg(0);
        fs >> x;
        assert(x == 3.25);
    }
    std::remove(temp);
    {
        std::wfstream fs(std::string(temp),
                         std::ios_base::in | std::ios_base::out
                                           | std::ios_base::trunc);
        double x = 0;
        fs << 3.25;
        fs.seekg(0);
        fs >> x;
        assert(x == 3.25);
    }
    std::remove(temp);
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include <fxdiv.h>

TEST(uint32_t, cases) {
	EXPECT_EQ(UINT32_C(42) / UINT32_C(7),
		fxdiv_quotient_uint32_t(UINT32_C(42),
			fxdiv_init_uint32_t(UINT32_C(7))));
	EXPECT_EQ(UINT32_C(42) / UINT32_C(6),
		fxdiv_quotient_uint32_t(UINT32_C(42),
			fxdiv_init_uint32_t(UINT32_C(6))));
	EXPECT_EQ(UINT32_C(42) / UINT32_C(5),
		fxdiv_quotient_uint32_t(UINT32_C(42),
			fxdiv_init_uint32_t(UINT32_C(5))));
	EXPECT_EQ(UINT32_C(1) / UINT32_C(1),
		fxdiv_quotient_uint32_t(UINT32_C(1),
			fxdiv_init_uint32_t(UINT32_C(1))));
	EXPECT_EQ(UINT32_MAX / UINT32_C(1),
		fxdiv_quotient_uint32_t(UINT32_MAX,
			fxdiv_init_uint32_t(UINT32_C(1))));
	EXPECT_EQ(UINT32_MAX / UINT32_MAX,
		fxdiv_quotient_uint32_t(UINT32_MAX,
			fxdiv_init_uint32_t(UINT32_MAX)));
	EXPECT_EQ((UINT32_MAX - 1) / UINT32_MAX,
		fxdiv_quotient_uint32_t(UINT32_MAX - 1,
			fxdiv_init_uint32_t(UINT32_MAX)));
	EXPECT_EQ(UINT32_MAX / (UINT32_MAX - 1),
		fxdiv_quotient_uint32_t(UINT32_MAX,
			fxdiv_init_uint32_t(UINT32_MAX - 1)));
	EXPECT_EQ(UINT32_C(0) / UINT32_C(1),
		fxdiv_quotient_uint32_t(UINT32_C(0),
			fxdiv_init_uint32_t(UINT32_C(1))));
}

TEST(uint32_t, divide_by_1) {
	const fxdiv_uint32_t d = fxdiv_init_uint32_t(UINT32_C(1));
	const uint32_t step = UINT32_C(487);
	for (uint32_t n = 0; n <= UINT32_MAX - step + 1; n += step) {
		EXPECT_EQ(n, fxdiv_quotient_uint32_t(n, d));
	}
}

TEST(uint32_t, divide_zero) {
	const uint32_t step = UINT32_C(491);
	for (uint32_t d = 1; d <= UINT32_MAX - step + 1; d += step) {
		EXPECT_EQ(0,
			fxdiv_quotient_uint32_t(0,
				fxdiv_init_uint32_t(d)));
	}
}

TEST(uint32_t, divide_by_n_minus_1) {
	const uint32_t step = UINT32_C(523);
	for (uint32_t n = 3; n <= UINT32_MAX - step + 1; n += step) {
		EXPECT_EQ(UINT32_C(1),
			fxdiv_quotient_uint32_t(n,
				fxdiv_init_uint32_t(n - 1)));
	}
}

TEST(uint32_t, divide_by_power_of_2) {
	const uint32_t step = UINT32_C(25183);
	for (uint32_t n = 0; n <= UINT32_MAX - step + 1; n += step) {
		for (uint32_t p = 0; p < 32; p += 1) {
			EXPECT_EQ(n >> p,
				fxdiv_quotient_uint32_t(n,
					fxdiv_init_uint32_t(UINT32_C(1) << p)));
		}
	}
}

TEST(uint32_t, match_native) {
	const uint32_t stepN = UINT32_C(821641);
	const uint32_t stepD = UINT32_C(821603);
	for (uint32_t n = UINT32_MAX; n >= stepN; n -= stepN) {
		for (uint32_t d = UINT32_MAX; d >= stepD; d -= stepD) {
			EXPECT_EQ(n / d,
				fxdiv_quotient_uint32_t(n,
					fxdiv_init_uint32_t(d)));
		}
	}
}

TEST(uint64_t, cases) {
	EXPECT_EQ(UINT64_C(42) / UINT64_C(7),
		fxdiv_quotient_uint64_t(UINT64_C(42),
			fxdiv_init_uint64_t(UINT64_C(7))));
	EXPECT_EQ(UINT64_C(42) / UINT64_C(6),
		fxdiv_quotient_uint64_t(UINT64_C(42),
			fxdiv_init_uint64_t(UINT64_C(6))));
	EXPECT_EQ(UINT64_C(42) / UINT64_C(5),
		fxdiv_quotient_uint64_t(UINT64_C(42),
			fxdiv_init_uint64_t(UINT64_C(5))));
	EXPECT_EQ(UINT64_C(1) / UINT64_C(1),
		fxdiv_quotient_uint64_t(UINT64_C(1),
			fxdiv_init_uint64_t(UINT64_C(1))));
	EXPECT_EQ(UINT64_MAX / UINT64_C(1),
		fxdiv_quotient_uint64_t(UINT64_MAX,
			fxdiv_init_uint64_t(UINT64_C(1))));
	EXPECT_EQ(UINT64_MAX / UINT64_MAX,
		fxdiv_quotient_uint64_t(UINT64_MAX,
			fxdiv_init_uint64_t(UINT64_MAX)));
	EXPECT_EQ((UINT64_MAX - 1) / UINT64_MAX,
		fxdiv_quotient_uint64_t(UINT64_MAX - 1,
			fxdiv_init_uint64_t(UINT64_MAX)));
	EXPECT_EQ(UINT64_MAX / (UINT64_MAX - 1),
		fxdiv_quotient_uint64_t(UINT64_MAX,
			fxdiv_init_uint64_t(UINT64_MAX - 1)));
	EXPECT_EQ(UINT64_C(0) / UINT64_C(1),
		fxdiv_quotient_uint64_t(UINT64_C(0),
			fxdiv_init_uint64_t(UINT64_C(1))));
}

TEST(uint64_t, divide_by_1) {
	const fxdiv_uint64_t d = fxdiv_init_uint64_t(UINT64_C(1));
	const uint64_t step = UINT64_C(2048116998241);
	for (uint64_t n = 0; n <= UINT64_MAX - step + 1; n += step) {
		EXPECT_EQ(n, fxdiv_quotient_uint64_t(n, d));
	}
}

TEST(uint64_t, divide_zero) {
	const uint64_t step = UINT64_C(8624419641811);
	for (uint64_t d = 1; d <= UINT64_MAX - step + 1; d += step) {
		EXPECT_EQ(0,
			fxdiv_quotient_uint64_t(0,
				fxdiv_init_uint64_t(d)));
	}
}

TEST(uint64_t, divide_by_n_minus_1) {
	const uint64_t step = UINT64_C(8624419641833);
	for (uint64_t n = 3; n <= UINT64_MAX - step + 1; n += step) {
		EXPECT_EQ(UINT64_C(1),
			fxdiv_quotient_uint64_t(n,
				fxdiv_init_uint64_t(n - 1)));
	}
}

TEST(uint64_t, divide_by_power_of_2) {
	const uint64_t step = UINT64_C(93400375993241);
	for (uint64_t n = 0; n <= UINT64_MAX - step + 1; n += step) {
		for (uint64_t p = 0; p < 32; p += 1) {
			EXPECT_EQ(n >> p,
				fxdiv_quotient_uint64_t(n,
					fxdiv_init_uint64_t(UINT64_C(1) << p)));
		}
	}
}

TEST(uint64_t, match_native) {
	const uint64_t stepN = UINT64_C(7093600525704677);
	const uint64_t stepD = UINT64_C(7093600525704701);
	for (uint64_t n = UINT64_MAX; n >= stepN; n -= stepN) {
		for (uint64_t d = UINT64_MAX; d >= stepD; d -= stepD) {
			EXPECT_EQ(n / d,
				fxdiv_quotient_uint64_t(n,
					fxdiv_init_uint64_t(d)));
		}
	}
}

TEST(size_t, cases) {
	EXPECT_EQ(42 / 7,
		fxdiv_quotient_size_t(42,
			fxdiv_init_size_t(7)));
	EXPECT_EQ(42 / 6,
		fxdiv_quotient_size_t(42,
			fxdiv_init_size_t(6)));
	EXPECT_EQ(42 / 5,
		fxdiv_quotient_size_t(42,
			fxdiv_init_size_t(5)));
	EXPECT_EQ(1 / 1,
		fxdiv_quotient_size_t(1,
			fxdiv_init_size_t(1)));
	EXPECT_EQ(SIZE_MAX / 1,
		fxdiv_quotient_size_t(SIZE_MAX,
			fxdiv_init_size_t(1)));
	EXPECT_EQ(SIZE_MAX / SIZE_MAX,
		fxdiv_quotient_size_t(SIZE_MAX,
			fxdiv_init_size_t(SIZE_MAX)));
	EXPECT_EQ((SIZE_MAX - 1) / SIZE_MAX,
		fxdiv_quotient_size_t(SIZE_MAX - 1,
			fxdiv_init_size_t(SIZE_MAX)));
	EXPECT_EQ(SIZE_MAX / (SIZE_MAX - 1),
		fxdiv_quotient_size_t(SIZE_MAX,
			fxdiv_init_size_t(SIZE_MAX - 1)));
	EXPECT_EQ(0 / 1,
		fxdiv_quotient_size_t(0,
			fxdiv_init_size_t(1)));
}
<commit_msg>Test: reuse precomputed divisor in test vs native division<commit_after>#include <gtest/gtest.h>

#include <fxdiv.h>

TEST(uint32_t, cases) {
	EXPECT_EQ(UINT32_C(42) / UINT32_C(7),
		fxdiv_quotient_uint32_t(UINT32_C(42),
			fxdiv_init_uint32_t(UINT32_C(7))));
	EXPECT_EQ(UINT32_C(42) / UINT32_C(6),
		fxdiv_quotient_uint32_t(UINT32_C(42),
			fxdiv_init_uint32_t(UINT32_C(6))));
	EXPECT_EQ(UINT32_C(42) / UINT32_C(5),
		fxdiv_quotient_uint32_t(UINT32_C(42),
			fxdiv_init_uint32_t(UINT32_C(5))));
	EXPECT_EQ(UINT32_C(1) / UINT32_C(1),
		fxdiv_quotient_uint32_t(UINT32_C(1),
			fxdiv_init_uint32_t(UINT32_C(1))));
	EXPECT_EQ(UINT32_MAX / UINT32_C(1),
		fxdiv_quotient_uint32_t(UINT32_MAX,
			fxdiv_init_uint32_t(UINT32_C(1))));
	EXPECT_EQ(UINT32_MAX / UINT32_MAX,
		fxdiv_quotient_uint32_t(UINT32_MAX,
			fxdiv_init_uint32_t(UINT32_MAX)));
	EXPECT_EQ((UINT32_MAX - 1) / UINT32_MAX,
		fxdiv_quotient_uint32_t(UINT32_MAX - 1,
			fxdiv_init_uint32_t(UINT32_MAX)));
	EXPECT_EQ(UINT32_MAX / (UINT32_MAX - 1),
		fxdiv_quotient_uint32_t(UINT32_MAX,
			fxdiv_init_uint32_t(UINT32_MAX - 1)));
	EXPECT_EQ(UINT32_C(0) / UINT32_C(1),
		fxdiv_quotient_uint32_t(UINT32_C(0),
			fxdiv_init_uint32_t(UINT32_C(1))));
}

TEST(uint32_t, divide_by_1) {
	const fxdiv_uint32_t d = fxdiv_init_uint32_t(UINT32_C(1));
	const uint32_t step = UINT32_C(487);
	for (uint32_t n = 0; n <= UINT32_MAX - step + 1; n += step) {
		EXPECT_EQ(n, fxdiv_quotient_uint32_t(n, d));
	}
}

TEST(uint32_t, divide_zero) {
	const uint32_t step = UINT32_C(491);
	for (uint32_t d = 1; d <= UINT32_MAX - step + 1; d += step) {
		EXPECT_EQ(0,
			fxdiv_quotient_uint32_t(0,
				fxdiv_init_uint32_t(d)));
	}
}

TEST(uint32_t, divide_by_n_minus_1) {
	const uint32_t step = UINT32_C(523);
	for (uint32_t n = 3; n <= UINT32_MAX - step + 1; n += step) {
		EXPECT_EQ(UINT32_C(1),
			fxdiv_quotient_uint32_t(n,
				fxdiv_init_uint32_t(n - 1)));
	}
}

TEST(uint32_t, divide_by_power_of_2) {
	const uint32_t step = UINT32_C(25183);
	for (uint32_t n = 0; n <= UINT32_MAX - step + 1; n += step) {
		for (uint32_t p = 0; p < 32; p += 1) {
			EXPECT_EQ(n >> p,
				fxdiv_quotient_uint32_t(n,
					fxdiv_init_uint32_t(UINT32_C(1) << p)));
		}
	}
}

TEST(uint32_t, match_native) {
	const uint32_t stepD = UINT32_C(821603);
	const uint32_t stepN = UINT32_C(821641);
	for (uint32_t d = UINT32_MAX; d >= stepD; d -= stepD) {
		const fxdiv_uint32_t divisor = fxdiv_init_uint32_t(d);
		for (uint32_t n = UINT32_MAX; n >= stepN; n -= stepN) {
			EXPECT_EQ(n / d, fxdiv_quotient_uint32_t(n, divisor));
		}
	}
}

TEST(uint64_t, cases) {
	EXPECT_EQ(UINT64_C(42) / UINT64_C(7),
		fxdiv_quotient_uint64_t(UINT64_C(42),
			fxdiv_init_uint64_t(UINT64_C(7))));
	EXPECT_EQ(UINT64_C(42) / UINT64_C(6),
		fxdiv_quotient_uint64_t(UINT64_C(42),
			fxdiv_init_uint64_t(UINT64_C(6))));
	EXPECT_EQ(UINT64_C(42) / UINT64_C(5),
		fxdiv_quotient_uint64_t(UINT64_C(42),
			fxdiv_init_uint64_t(UINT64_C(5))));
	EXPECT_EQ(UINT64_C(1) / UINT64_C(1),
		fxdiv_quotient_uint64_t(UINT64_C(1),
			fxdiv_init_uint64_t(UINT64_C(1))));
	EXPECT_EQ(UINT64_MAX / UINT64_C(1),
		fxdiv_quotient_uint64_t(UINT64_MAX,
			fxdiv_init_uint64_t(UINT64_C(1))));
	EXPECT_EQ(UINT64_MAX / UINT64_MAX,
		fxdiv_quotient_uint64_t(UINT64_MAX,
			fxdiv_init_uint64_t(UINT64_MAX)));
	EXPECT_EQ((UINT64_MAX - 1) / UINT64_MAX,
		fxdiv_quotient_uint64_t(UINT64_MAX - 1,
			fxdiv_init_uint64_t(UINT64_MAX)));
	EXPECT_EQ(UINT64_MAX / (UINT64_MAX - 1),
		fxdiv_quotient_uint64_t(UINT64_MAX,
			fxdiv_init_uint64_t(UINT64_MAX - 1)));
	EXPECT_EQ(UINT64_C(0) / UINT64_C(1),
		fxdiv_quotient_uint64_t(UINT64_C(0),
			fxdiv_init_uint64_t(UINT64_C(1))));
}

TEST(uint64_t, divide_by_1) {
	const fxdiv_uint64_t d = fxdiv_init_uint64_t(UINT64_C(1));
	const uint64_t step = UINT64_C(2048116998241);
	for (uint64_t n = 0; n <= UINT64_MAX - step + 1; n += step) {
		EXPECT_EQ(n, fxdiv_quotient_uint64_t(n, d));
	}
}

TEST(uint64_t, divide_zero) {
	const uint64_t step = UINT64_C(8624419641811);
	for (uint64_t d = 1; d <= UINT64_MAX - step + 1; d += step) {
		EXPECT_EQ(0,
			fxdiv_quotient_uint64_t(0,
				fxdiv_init_uint64_t(d)));
	}
}

TEST(uint64_t, divide_by_n_minus_1) {
	const uint64_t step = UINT64_C(8624419641833);
	for (uint64_t n = 3; n <= UINT64_MAX - step + 1; n += step) {
		EXPECT_EQ(UINT64_C(1),
			fxdiv_quotient_uint64_t(n,
				fxdiv_init_uint64_t(n - 1)));
	}
}

TEST(uint64_t, divide_by_power_of_2) {
	const uint64_t step = UINT64_C(93400375993241);
	for (uint64_t n = 0; n <= UINT64_MAX - step + 1; n += step) {
		for (uint64_t p = 0; p < 32; p += 1) {
			EXPECT_EQ(n >> p,
				fxdiv_quotient_uint64_t(n,
					fxdiv_init_uint64_t(UINT64_C(1) << p)));
		}
	}
}

TEST(uint64_t, match_native) {
	const uint64_t stepD = UINT64_C(7093600525704701);
	const uint64_t stepN = UINT64_C(7093600525704677);
	for (uint64_t d = UINT64_MAX; d >= stepD; d -= stepD) {
		const fxdiv_uint64_t divisor = fxdiv_init_uint64_t(d);
		for (uint64_t n = UINT64_MAX; n >= stepN; n -= stepN) {
			EXPECT_EQ(n / d, fxdiv_quotient_uint64_t(n, divisor));
		}
	}
}

TEST(size_t, cases) {
	EXPECT_EQ(42 / 7,
		fxdiv_quotient_size_t(42,
			fxdiv_init_size_t(7)));
	EXPECT_EQ(42 / 6,
		fxdiv_quotient_size_t(42,
			fxdiv_init_size_t(6)));
	EXPECT_EQ(42 / 5,
		fxdiv_quotient_size_t(42,
			fxdiv_init_size_t(5)));
	EXPECT_EQ(1 / 1,
		fxdiv_quotient_size_t(1,
			fxdiv_init_size_t(1)));
	EXPECT_EQ(SIZE_MAX / 1,
		fxdiv_quotient_size_t(SIZE_MAX,
			fxdiv_init_size_t(1)));
	EXPECT_EQ(SIZE_MAX / SIZE_MAX,
		fxdiv_quotient_size_t(SIZE_MAX,
			fxdiv_init_size_t(SIZE_MAX)));
	EXPECT_EQ((SIZE_MAX - 1) / SIZE_MAX,
		fxdiv_quotient_size_t(SIZE_MAX - 1,
			fxdiv_init_size_t(SIZE_MAX)));
	EXPECT_EQ(SIZE_MAX / (SIZE_MAX - 1),
		fxdiv_quotient_size_t(SIZE_MAX,
			fxdiv_init_size_t(SIZE_MAX - 1)));
	EXPECT_EQ(0 / 1,
		fxdiv_quotient_size_t(0,
			fxdiv_init_size_t(1)));
}
<|endoftext|>