<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/tools/frame_analyzer/video_quality_analysis.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include <string>

#define STATS_LINE_LENGTH 32
#define Y4M_FILE_HEADER_MAX_SIZE 200
#define Y4M_FRAME_DELIMITER "FRAME"
#define Y4M_FRAME_HEADER_SIZE 6

namespace webrtc {
namespace test {

using std::string;

int GetI420FrameSize(int width, int height) {
  int half_width = (width + 1) >> 1;
  int half_height = (height + 1) >> 1;

  int y_plane = width * height;  // I420 Y plane.
  int u_plane = half_width * half_height;  // I420 U plane.
  int v_plane = half_width * half_height;  // I420 V plane.

  return y_plane + u_plane + v_plane;
}

int ExtractFrameSequenceNumber(std::string line) {
  size_t space_position = line.find(' ');
  if (space_position == string::npos) {
    return -1;
  }
  std::string frame = line.substr(0, space_position);

  size_t underscore_position = frame.find('_');
  if (underscore_position == string::npos) {
    return -1;
  }
  std::string frame_number = frame.substr(underscore_position + 1);

  return strtol(frame_number.c_str(), NULL, 10);
}

int ExtractDecodedFrameNumber(std::string line) {
  size_t space_position = line.find(' ');
  if (space_position == string::npos) {
    return -1;
  }
  std::string decoded_number = line.substr(space_position + 1);

  return strtol(decoded_number.c_str(), NULL, 10);
}

bool IsThereBarcodeError(std::string line) {
  size_t barcode_error_position = line.find("Barcode error");
  if (barcode_error_position != string::npos) {
    return true;
  }
  return false;
}

bool GetNextStatsLine(FILE* stats_file, char* line) {
  int chars = 0;
  char buf = 0;

  while (buf != '\n') {
    size_t chars_read = fread(&buf, 1, 1, stats_file);
    if (chars_read != 1 || feof(stats_file)) {
      return false;
    }
    line[chars] = buf;
    ++chars;
  }
  line[chars-1] = '\0';  // Strip the trailing \n and put end of string.
  return true;
}

bool ExtractFrameFromYuvFile(const char* i420_file_name, int width, int height,
                             int frame_number, uint8* result_frame) {
  int frame_size = GetI420FrameSize(width, height);
  int offset = frame_number * frame_size;  // Calculate offset for the frame.
  bool errors = false;

  FILE* input_file = fopen(i420_file_name, "rb");
  if (input_file == NULL) {
    fprintf(stderr, "Couldn't open input file for reading: %s\n",
            i420_file_name);
    return false;
  }

  // Change stream pointer to new offset.
  fseek(input_file, offset, SEEK_SET);

  size_t bytes_read = fread(result_frame, 1, frame_size, input_file);
  if (bytes_read != static_cast<size_t>(frame_size) &&
      ferror(input_file)) {
    fprintf(stdout, "Error while reading frame no %d from file %s\n",
            frame_number, i420_file_name);
    errors = true;
  }
  fclose(input_file);
  return !errors;
}

bool ExtractFrameFromY4mFile(const char* y4m_file_name, int width, int height,
                             int frame_number, uint8* result_frame) {
  int frame_size = GetI420FrameSize(width, height);
  int frame_offset = frame_number * frame_size
  bool errors = false;

  FILE* input_file = fopen(y4m_file_name, "rb");
  if (input_file == NULL) {
    fprintf(stderr, "Couldn't open input file for reading: %s\n",
            y4m_file_name);
    return false;
  }

  // YUV4MPEG2, a.k.a. Y4M File format has a file header and a frame header. The
  // file header has the aspect: "YUV4MPEG2 C420 W640 H360 Ip F30:1 A1:1".
  // Skip the header if this is the first frame of the file.
  if (frame_number == 0) {
    char frame_header[Y4M_FILE_HEADER_MAX_SIZE];
    size_t bytes_read =
        fread(frame_header, 1, Y4M_FILE_HEADER_MAX_SIZE, input_file);
    if (bytes_read != static_cast<size_t>(frame_size) && ferror(input_file)) {
      fprintf(stdout, "Error while reading first frame from file %s\n",
          y4m_file_name);
      fclose(input_file);
      return false;
    }
    std::string header_contents(frame_header);
    std::size_t found = header_contents.find(Y4M_FRAME_DELIMITER);
    if (found == std::string::npos) {
      fprintf(stdout, "Corrupted Y4M header, could not find \"FRAME\" in %s\n",
          header_contents.c_str());
      fclose(input_file);
      return false;
    }
    frame_offset = static_cast<int>(found);
  }

  // Change stream pointer to new offset, skipping the frame header as well.
  fseek(input_file, frame_offset + Y4M_FRAME_HEADER_SIZE, SEEK_SET);

  size_t bytes_read = fread(result_frame, 1, frame_size, input_file);
  if (bytes_read != static_cast<size_t>(frame_size) &&
      ferror(input_file)) {
    fprintf(stdout, "Error while reading frame no %d from file %s\n",
            frame_number, y4m_file_name);
    errors = true;
  }

  fclose(input_file);
  return !errors;
}

double CalculateMetrics(VideoAnalysisMetricsType video_metrics_type,
                        const uint8* ref_frame,  const uint8* test_frame,
                        int width, int height) {
  if (!ref_frame || !test_frame)
    return -1;
  else if (height < 0 || width < 0)
    return -1;
  int half_width = (width + 1) >> 1;
  int half_height = (height + 1) >> 1;
  const uint8* src_y_a = ref_frame;
  const uint8* src_u_a = src_y_a + width * height;
  const uint8* src_v_a = src_u_a + half_width * half_height;
  const uint8* src_y_b = test_frame;
  const uint8* src_u_b = src_y_b + width * height;
  const uint8* src_v_b = src_u_b + half_width * half_height;

  int stride_y = width;
  int stride_uv = half_width;

  double result = 0.0;

  switch (video_metrics_type) {
    case kPSNR:
      // In the following: stride is determined by width.
      result = libyuv::I420Psnr(src_y_a, width, src_u_a, half_width,
                                src_v_a, half_width, src_y_b, width,
                                src_u_b, half_width, src_v_b, half_width,
                                width, height);
      // LibYuv sets the max psnr value to 128, we restrict it to 48.
      // In case of 0 mse in one frame, 128 can skew the results significantly.
      result = (result > 48.0) ? 48.0 : result;
      break;
    case kSSIM:
      result = libyuv::I420Ssim(src_y_a, stride_y, src_u_a, stride_uv,
                                src_v_a, stride_uv, src_y_b, stride_y,
                                src_u_b, stride_uv, src_v_b, stride_uv,
                                width, height);
      break;
    default:
      assert(false);
  }

  return result;
}

void RunAnalysis(const char* reference_file_name, const char* test_file_name,
                 const char* stats_file_name, int width, int height,
                 ResultsContainer* results) {
  // Check if the reference_file_name ends with "y4m".
  bool y4m_mode = false;
  if (std::string(reference_file_name).find("y4m") != std::string::npos){
    y4m_mode = true;
  }

  int size = GetI420FrameSize(width, height);
  FILE* stats_file = fopen(stats_file_name, "r");

  // String buffer for the lines in the stats file.
  char line[STATS_LINE_LENGTH];

  // Allocate buffers for test and reference frames.
  uint8* test_frame = new uint8[size];
  uint8* reference_frame = new uint8[size];
  int previous_frame_number = -1;

  // While there are entries in the stats file.
  while (GetNextStatsLine(stats_file, line)) {
    int extracted_test_frame = ExtractFrameSequenceNumber(line);
    int decoded_frame_number = ExtractDecodedFrameNumber(line);

    // If there was problem decoding the barcode in this frame or the frame has
    // been duplicated, continue.
    if (IsThereBarcodeError(line) ||
        decoded_frame_number == previous_frame_number) {
      continue;
    }

    assert(extracted_test_frame != -1);
    assert(decoded_frame_number != -1);

    ExtractFrameFromYuvFile(test_file_name, width, height, extracted_test_frame,
                            test_frame);
    if (y4m_mode) {
      ExtractFrameFromY4mFile(reference_file_name, width, height,
                              decoded_frame_number, reference_frame);
    } else {
      ExtractFrameFromYuvFile(reference_file_name, width, height,
                              decoded_frame_number, reference_frame);
    }

    // Calculate the PSNR and SSIM.
    double result_psnr = CalculateMetrics(kPSNR, reference_frame, test_frame,
                                          width, height);
    double result_ssim = CalculateMetrics(kSSIM, reference_frame, test_frame,
                                          width, height);

    previous_frame_number = decoded_frame_number;

    // Fill in the result struct.
    AnalysisResult result;
    result.frame_number = decoded_frame_number;
    result.psnr_value = result_psnr;
    result.ssim_value = result_ssim;

    results->frames.push_back(result);
  }

  // Cleanup.
  fclose(stats_file);
  delete[] test_frame;
  delete[] reference_frame;
}

void PrintMaxRepeatedAndSkippedFrames(const std::string& label,
                                      const std::string& stats_file_name) {
  PrintMaxRepeatedAndSkippedFrames(stdout, label, stats_file_name);
}

void PrintMaxRepeatedAndSkippedFrames(FILE* output, const std::string& label,
                                      const std::string& stats_file_name) {
  FILE* stats_file = fopen(stats_file_name.c_str(), "r");
  if (stats_file == NULL) {
    fprintf(stderr, "Couldn't open stats file for reading: %s\n",
            stats_file_name.c_str());
    return;
  }
  char line[STATS_LINE_LENGTH];

  int repeated_frames = 1;
  int max_repeated_frames = 1;
  int max_skipped_frames = 1;
  int previous_frame_number = -1;

  while (GetNextStatsLine(stats_file, line)) {
    int decoded_frame_number = ExtractDecodedFrameNumber(line);

    if (decoded_frame_number == -1) {
      continue;
    }

    // Calculate how many frames a cluster of repeated frames contains.
    if (decoded_frame_number == previous_frame_number) {
      ++repeated_frames;
      if (repeated_frames > max_repeated_frames) {
        max_repeated_frames = repeated_frames;
      }
    } else {
      repeated_frames = 1;
    }

    // Calculate how much frames have been skipped.
    if (decoded_frame_number != 0 && previous_frame_number != -1) {
      int skipped_frames = decoded_frame_number - previous_frame_number - 1;
      if (skipped_frames > max_skipped_frames) {
        max_skipped_frames = skipped_frames;
      }
    }
    previous_frame_number = decoded_frame_number;
  }
  fprintf(output, "RESULT Max_repeated: %s= %d\n", label.c_str(),
          max_repeated_frames);
  fprintf(output, "RESULT Max_skipped: %s= %d\n", label.c_str(),
          max_skipped_frames);
  fclose(stats_file);
}

void PrintAnalysisResults(const std::string& label, ResultsContainer* results) {
  PrintAnalysisResults(stdout, label, results);
}

void PrintAnalysisResults(FILE* output, const std::string& label,
                          ResultsContainer* results) {
  std::vector<AnalysisResult>::iterator iter;

  fprintf(output, "RESULT Unique_frames_count: %s= %u\n", label.c_str(),
          static_cast<unsigned int>(results->frames.size()));

  if (results->frames.size() > 0u) {
    fprintf(output, "RESULT PSNR: %s= [", label.c_str());
    for (iter = results->frames.begin(); iter != results->frames.end() - 1;
         ++iter) {
      fprintf(output, "%f,", iter->psnr_value);
    }
    fprintf(output, "%f] dB\n", iter->psnr_value);

    fprintf(output, "RESULT SSIM: %s= [", label.c_str());
    for (iter = results->frames.begin(); iter != results->frames.end() - 1;
         ++iter) {
      fprintf(output, "%f,", iter->ssim_value);
    }
    fprintf(output, "%f]\n", iter->ssim_value);
  }
}

}  // namespace test
}  // namespace webrtc
<commit_msg>Add support for YUV4MPEG file reading to tools files. (Minor fix).<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/tools/frame_analyzer/video_quality_analysis.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include <string>

#define STATS_LINE_LENGTH 32
#define Y4M_FILE_HEADER_MAX_SIZE 200
#define Y4M_FRAME_DELIMITER "FRAME"
#define Y4M_FRAME_HEADER_SIZE 6

namespace webrtc {
namespace test {

using std::string;

int GetI420FrameSize(int width, int height) {
  int half_width = (width + 1) >> 1;
  int half_height = (height + 1) >> 1;

  int y_plane = width * height;  // I420 Y plane.
  int u_plane = half_width * half_height;  // I420 U plane.
  int v_plane = half_width * half_height;  // I420 V plane.

  return y_plane + u_plane + v_plane;
}

int ExtractFrameSequenceNumber(std::string line) {
  size_t space_position = line.find(' ');
  if (space_position == string::npos) {
    return -1;
  }
  std::string frame = line.substr(0, space_position);

  size_t underscore_position = frame.find('_');
  if (underscore_position == string::npos) {
    return -1;
  }
  std::string frame_number = frame.substr(underscore_position + 1);

  return strtol(frame_number.c_str(), NULL, 10);
}

int ExtractDecodedFrameNumber(std::string line) {
  size_t space_position = line.find(' ');
  if (space_position == string::npos) {
    return -1;
  }
  std::string decoded_number = line.substr(space_position + 1);

  return strtol(decoded_number.c_str(), NULL, 10);
}

bool IsThereBarcodeError(std::string line) {
  size_t barcode_error_position = line.find("Barcode error");
  if (barcode_error_position != string::npos) {
    return true;
  }
  return false;
}

bool GetNextStatsLine(FILE* stats_file, char* line) {
  int chars = 0;
  char buf = 0;

  while (buf != '\n') {
    size_t chars_read = fread(&buf, 1, 1, stats_file);
    if (chars_read != 1 || feof(stats_file)) {
      return false;
    }
    line[chars] = buf;
    ++chars;
  }
  line[chars-1] = '\0';  // Strip the trailing \n and put end of string.
  return true;
}

bool ExtractFrameFromYuvFile(const char* i420_file_name, int width, int height,
                             int frame_number, uint8* result_frame) {
  int frame_size = GetI420FrameSize(width, height);
  int offset = frame_number * frame_size;  // Calculate offset for the frame.
  bool errors = false;

  FILE* input_file = fopen(i420_file_name, "rb");
  if (input_file == NULL) {
    fprintf(stderr, "Couldn't open input file for reading: %s\n",
            i420_file_name);
    return false;
  }

  // Change stream pointer to new offset.
  fseek(input_file, offset, SEEK_SET);

  size_t bytes_read = fread(result_frame, 1, frame_size, input_file);
  if (bytes_read != static_cast<size_t>(frame_size) &&
      ferror(input_file)) {
    fprintf(stdout, "Error while reading frame no %d from file %s\n",
            frame_number, i420_file_name);
    errors = true;
  }
  fclose(input_file);
  return !errors;
}

bool ExtractFrameFromY4mFile(const char* y4m_file_name, int width, int height,
                             int frame_number, uint8* result_frame) {
  int frame_size = GetI420FrameSize(width, height);
  int frame_offset = frame_number * frame_size;
  bool errors = false;

  FILE* input_file = fopen(y4m_file_name, "rb");
  if (input_file == NULL) {
    fprintf(stderr, "Couldn't open input file for reading: %s\n",
            y4m_file_name);
    return false;
  }

  // YUV4MPEG2, a.k.a. Y4M File format has a file header and a frame header. The
  // file header has the aspect: "YUV4MPEG2 C420 W640 H360 Ip F30:1 A1:1".
  // Skip the header if this is the first frame of the file.
  if (frame_number == 0) {
    char frame_header[Y4M_FILE_HEADER_MAX_SIZE];
    size_t bytes_read =
        fread(frame_header, 1, Y4M_FILE_HEADER_MAX_SIZE, input_file);
    if (bytes_read != static_cast<size_t>(frame_size) && ferror(input_file)) {
      fprintf(stdout, "Error while reading first frame from file %s\n",
          y4m_file_name);
      fclose(input_file);
      return false;
    }
    std::string header_contents(frame_header);
    std::size_t found = header_contents.find(Y4M_FRAME_DELIMITER);
    if (found == std::string::npos) {
      fprintf(stdout, "Corrupted Y4M header, could not find \"FRAME\" in %s\n",
          header_contents.c_str());
      fclose(input_file);
      return false;
    }
    frame_offset = static_cast<int>(found);
  }

  // Change stream pointer to new offset, skipping the frame header as well.
  fseek(input_file, frame_offset + Y4M_FRAME_HEADER_SIZE, SEEK_SET);

  size_t bytes_read = fread(result_frame, 1, frame_size, input_file);
  if (bytes_read != static_cast<size_t>(frame_size) &&
      ferror(input_file)) {
    fprintf(stdout, "Error while reading frame no %d from file %s\n",
            frame_number, y4m_file_name);
    errors = true;
  }

  fclose(input_file);
  return !errors;
}

double CalculateMetrics(VideoAnalysisMetricsType video_metrics_type,
                        const uint8* ref_frame,  const uint8* test_frame,
                        int width, int height) {
  if (!ref_frame || !test_frame)
    return -1;
  else if (height < 0 || width < 0)
    return -1;
  int half_width = (width + 1) >> 1;
  int half_height = (height + 1) >> 1;
  const uint8* src_y_a = ref_frame;
  const uint8* src_u_a = src_y_a + width * height;
  const uint8* src_v_a = src_u_a + half_width * half_height;
  const uint8* src_y_b = test_frame;
  const uint8* src_u_b = src_y_b + width * height;
  const uint8* src_v_b = src_u_b + half_width * half_height;

  int stride_y = width;
  int stride_uv = half_width;

  double result = 0.0;

  switch (video_metrics_type) {
    case kPSNR:
      // In the following: stride is determined by width.
      result = libyuv::I420Psnr(src_y_a, width, src_u_a, half_width,
                                src_v_a, half_width, src_y_b, width,
                                src_u_b, half_width, src_v_b, half_width,
                                width, height);
      // LibYuv sets the max psnr value to 128, we restrict it to 48.
      // In case of 0 mse in one frame, 128 can skew the results significantly.
      result = (result > 48.0) ? 48.0 : result;
      break;
    case kSSIM:
      result = libyuv::I420Ssim(src_y_a, stride_y, src_u_a, stride_uv,
                                src_v_a, stride_uv, src_y_b, stride_y,
                                src_u_b, stride_uv, src_v_b, stride_uv,
                                width, height);
      break;
    default:
      assert(false);
  }

  return result;
}

void RunAnalysis(const char* reference_file_name, const char* test_file_name,
                 const char* stats_file_name, int width, int height,
                 ResultsContainer* results) {
  // Check if the reference_file_name ends with "y4m".
  bool y4m_mode = false;
  if (std::string(reference_file_name).find("y4m") != std::string::npos){
    y4m_mode = true;
  }

  int size = GetI420FrameSize(width, height);
  FILE* stats_file = fopen(stats_file_name, "r");

  // String buffer for the lines in the stats file.
  char line[STATS_LINE_LENGTH];

  // Allocate buffers for test and reference frames.
  uint8* test_frame = new uint8[size];
  uint8* reference_frame = new uint8[size];
  int previous_frame_number = -1;

  // While there are entries in the stats file.
  while (GetNextStatsLine(stats_file, line)) {
    int extracted_test_frame = ExtractFrameSequenceNumber(line);
    int decoded_frame_number = ExtractDecodedFrameNumber(line);

    // If there was problem decoding the barcode in this frame or the frame has
    // been duplicated, continue.
    if (IsThereBarcodeError(line) ||
        decoded_frame_number == previous_frame_number) {
      continue;
    }

    assert(extracted_test_frame != -1);
    assert(decoded_frame_number != -1);

    ExtractFrameFromYuvFile(test_file_name, width, height, extracted_test_frame,
                            test_frame);
    if (y4m_mode) {
      ExtractFrameFromY4mFile(reference_file_name, width, height,
                              decoded_frame_number, reference_frame);
    } else {
      ExtractFrameFromYuvFile(reference_file_name, width, height,
                              decoded_frame_number, reference_frame);
    }

    // Calculate the PSNR and SSIM.
    double result_psnr = CalculateMetrics(kPSNR, reference_frame, test_frame,
                                          width, height);
    double result_ssim = CalculateMetrics(kSSIM, reference_frame, test_frame,
                                          width, height);

    previous_frame_number = decoded_frame_number;

    // Fill in the result struct.
    AnalysisResult result;
    result.frame_number = decoded_frame_number;
    result.psnr_value = result_psnr;
    result.ssim_value = result_ssim;

    results->frames.push_back(result);
  }

  // Cleanup.
  fclose(stats_file);
  delete[] test_frame;
  delete[] reference_frame;
}

void PrintMaxRepeatedAndSkippedFrames(const std::string& label,
                                      const std::string& stats_file_name) {
  PrintMaxRepeatedAndSkippedFrames(stdout, label, stats_file_name);
}

void PrintMaxRepeatedAndSkippedFrames(FILE* output, const std::string& label,
                                      const std::string& stats_file_name) {
  FILE* stats_file = fopen(stats_file_name.c_str(), "r");
  if (stats_file == NULL) {
    fprintf(stderr, "Couldn't open stats file for reading: %s\n",
            stats_file_name.c_str());
    return;
  }
  char line[STATS_LINE_LENGTH];

  int repeated_frames = 1;
  int max_repeated_frames = 1;
  int max_skipped_frames = 1;
  int previous_frame_number = -1;

  while (GetNextStatsLine(stats_file, line)) {
    int decoded_frame_number = ExtractDecodedFrameNumber(line);

    if (decoded_frame_number == -1) {
      continue;
    }

    // Calculate how many frames a cluster of repeated frames contains.
    if (decoded_frame_number == previous_frame_number) {
      ++repeated_frames;
      if (repeated_frames > max_repeated_frames) {
        max_repeated_frames = repeated_frames;
      }
    } else {
      repeated_frames = 1;
    }

    // Calculate how much frames have been skipped.
    if (decoded_frame_number != 0 && previous_frame_number != -1) {
      int skipped_frames = decoded_frame_number - previous_frame_number - 1;
      if (skipped_frames > max_skipped_frames) {
        max_skipped_frames = skipped_frames;
      }
    }
    previous_frame_number = decoded_frame_number;
  }
  fprintf(output, "RESULT Max_repeated: %s= %d\n", label.c_str(),
          max_repeated_frames);
  fprintf(output, "RESULT Max_skipped: %s= %d\n", label.c_str(),
          max_skipped_frames);
  fclose(stats_file);
}

void PrintAnalysisResults(const std::string& label, ResultsContainer* results) {
  PrintAnalysisResults(stdout, label, results);
}

void PrintAnalysisResults(FILE* output, const std::string& label,
                          ResultsContainer* results) {
  std::vector<AnalysisResult>::iterator iter;

  fprintf(output, "RESULT Unique_frames_count: %s= %u\n", label.c_str(),
          static_cast<unsigned int>(results->frames.size()));

  if (results->frames.size() > 0u) {
    fprintf(output, "RESULT PSNR: %s= [", label.c_str());
    for (iter = results->frames.begin(); iter != results->frames.end() - 1;
         ++iter) {
      fprintf(output, "%f,", iter->psnr_value);
    }
    fprintf(output, "%f] dB\n", iter->psnr_value);

    fprintf(output, "RESULT SSIM: %s= [", label.c_str());
    for (iter = results->frames.begin(); iter != results->frames.end() - 1;
         ++iter) {
      fprintf(output, "%f,", iter->ssim_value);
    }
    fprintf(output, "%f]\n", iter->ssim_value);
  }
}

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


<commit_before>#include <stdlib.h>
#include <new>

#include "log.h"
#include "replay.h"
#include "common.h"
#include "error.h"
#include "osd.h"

////////////////////////////////////////////////////////////////
// コンストラクタ
////////////////////////////////////////////////////////////////
REPLAY::REPLAY( void ) : Ini(NULL), RepST(REP_IDLE), Matrix(NULL),
							MSize(0), RepFrm(0), EndFrm(0) {}

////////////////////////////////////////////////////////////////
// デストラクタ
////////////////////////////////////////////////////////////////
REPLAY::~REPLAY( void )
{
	switch( RepST ){
	case REP_RECORD:	StopRecord(); break;
	case REP_REPLAY:	StopReplay(); break;
	}
	if( Matrix ) delete [] Matrix;
	if( Ini ) delete Ini;
}

////////////////////////////////////////////////////////////////
// 初期化
//
// 引数:	msize	マトリクスサイズ
// 返値:	bool	true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::Init( int msize )
{
	PRINTD( GRP_LOG, "[REPLAY][Init]\n" );

	if( Ini ) delete Ini;
	Ini = NULL;

	if( Matrix ) delete [] Matrix;
	Matrix = new BYTE[msize];
	if( !Matrix ) return false;

	RepST   = REP_IDLE;
	MSize   = msize;
	RepFrm  = 0;
	EndFrm  = 0;

	return true;
}

////////////////////////////////////////////////////////////////
// ステータス取得
//
// 引数:	なし
// 返値:	int		ステータス
////////////////////////////////////////////////////////////////
int REPLAY::GetStatus( void ) const
{
	return RepST;
}

////////////////////////////////////////////////////////////////
// リプレイ記録開始
//
// 引数:	filename	出力ファイル名
// 返値:	bool		true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::StartRecord( const char *filename )
{
	// とりあえずエラー設定
	Error::SetError( Error::ReplayPlayError );
	try{
		if( RepST != REP_IDLE ) throw Error::ReplayRecError;

		Ini = new cIni();
		if( !Ini->Init( filename ) ) throw Error::ReplayRecError;
	}
	catch( std::bad_alloc ){	// new に失敗した場合
		Error::SetError( Error::MemAllocFailed );
		return false;
	}
	catch( Error::Errno i ){	// 例外発生
		Error::SetError( i );
		if( Ini ) delete Ini;
		Ini = NULL;
		return false;
	}

	memset( Matrix, 0xff, MSize );		// キーマトリクスバッファクリア

	RepFrm = 0;
	RepST  = REP_RECORD;

	// 無事だったのでエラーなし
	Error::Reset();

    return true;
}

////////////////////////////////////////////////////////////////
// リプレイ記録再開
//
// 引数:	filename	出力ファイル名
// 引数:	frame       途中再開するフレーム
// 返値:	bool		true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::ResumeRecord(const char *filename, int frame)
{
    if(!StartRecord(filename)) return false;
    char buf[16];
    sprintf(buf, "%08lX", frame);
    // 指定されたフレーム以降のリプレイを削除し、そこから再開
    Ini->DeleteAfter("REPLAY", buf);

    RepFrm = frame;
    return true;
}

////////////////////////////////////////////////////////////////
// リプレイ記録停止
//
// 引数:	なし
// 返値:	なし
////////////////////////////////////////////////////////////////
void REPLAY::StopRecord( void )
{
	if( RepST != REP_RECORD ) return;

	if( Ini ){
		Ini->PutEntry( "REPLAY", NULL, "EndFrm", "0x%08lX", RepFrm );

		Ini->Write();

		delete Ini;
		Ini = NULL;
	}

	RepST = REP_IDLE;
}

////////////////////////////////////////////////////////////////
// リプレイ1フレーム書出し
//
// 引数:	mt		キーマトリクスポインタ
// 			chg		キーマトリクス変化 true:した false:しない
// 返値:	bool	true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::ReplayWriteFrame( const BYTE *mt, bool chg )
{
	char stren[16],strva[256];

	if( ( RepST != REP_RECORD ) || !mt || !Ini ) return false;

	// マトリクスに変化があったら書出し
	if( chg ){
		sprintf( stren, "%08lX ", RepFrm );
		for( int i=0; i<MSize; i++ )
			sprintf( strva+i*2, "%02X", mt[i] );
		Ini->PutEntry( "REPLAY", NULL, stren, "%s", strva );
	}

	RepFrm++;

	return true;
}

////////////////////////////////////////////////////////////////
// リプレイ再生開始
//
// 引数:	filename	入力ファイル名
// 返値:	bool		true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::StartReplay( const char *filename )
{
	// とりあえずエラー設定
	Error::SetError( Error::ReplayPlayError );
	try{
		int st;	// ホントはDWORD

		if( RepST != REP_IDLE ) throw Error::ReplayPlayError;

		Ini = new cIni();
		if( !Ini->Init( filename ) ) throw Error::ReplayPlayError;

		if( !Ini->GetInt( "REPLAY", "EndFrm", &st, EndFrm ) ) throw Error::NoReplayData;
		else                                                  EndFrm = st;
	}
	catch( std::bad_alloc ){	// new に失敗した場合
		Error::SetError( Error::MemAllocFailed );
		return false;
	}
	catch( Error::Errno i ){	// 例外発生
		Error::SetError( i );
		if( Ini ) delete Ini;
		Ini = NULL;
		return false;
	}

	memset( Matrix, 0xff, MSize );	// キーマトリクスバッファクリア

	RepFrm = 1;
	RepST  = REP_REPLAY;

	// 無事だったのでエラーなし
	Error::Reset();

	return true;
}

////////////////////////////////////////////////////////////////
// リプレイ再生停止
//
// 引数:	なし
// 返値:	なし
////////////////////////////////////////////////////////////////
void REPLAY::StopReplay( void )
{
	if( RepST != REP_REPLAY ) return;

	if( Ini ){
		delete Ini;
		Ini = NULL;
	}

	RepST = REP_IDLE;
}

////////////////////////////////////////////////////////////////
// リプレイ1フレーム読込み
//
// 引数:	mt		キーマトリクスポインタ
// 返値:	bool	true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::ReplayReadFrame( BYTE *mt )
{
	char stren[16],strva[256];

	if( ( RepST != REP_REPLAY ) || !mt || !Ini ) return false;

	sprintf( stren, "%08lX", RepFrm );
	if( Ini->GetString( "REPLAY", stren, strva, "" ) ){
		int stl = strlen( strva ) / 2;
		for( int i=0; i<stl; i++ ){
			char dt[3] = "FF";
			strncpy( dt, &strva[i*2], 2 );
			Matrix[i] = strtol( dt, NULL, 16 );
		}
		memcpy( mt, Matrix, MSize );
	}

	if( ++RepFrm >= EndFrm ){
		// データ終端に達したらリプレイ終了
		StopReplay();
	}

	return true;
}
<commit_msg>変化があったフレームだけでなく全フレームリプレイに書きだすようにした。<commit_after>#include <stdlib.h>
#include <new>

#include "log.h"
#include "replay.h"
#include "common.h"
#include "error.h"
#include "osd.h"

////////////////////////////////////////////////////////////////
// コンストラクタ
////////////////////////////////////////////////////////////////
REPLAY::REPLAY( void ) : Ini(NULL), RepST(REP_IDLE), Matrix(NULL),
							MSize(0), RepFrm(0), EndFrm(0) {}

////////////////////////////////////////////////////////////////
// デストラクタ
////////////////////////////////////////////////////////////////
REPLAY::~REPLAY( void )
{
	switch( RepST ){
	case REP_RECORD:	StopRecord(); break;
	case REP_REPLAY:	StopReplay(); break;
	}
	if( Matrix ) delete [] Matrix;
	if( Ini ) delete Ini;
}

////////////////////////////////////////////////////////////////
// 初期化
//
// 引数:	msize	マトリクスサイズ
// 返値:	bool	true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::Init( int msize )
{
	PRINTD( GRP_LOG, "[REPLAY][Init]\n" );

	if( Ini ) delete Ini;
	Ini = NULL;

	if( Matrix ) delete [] Matrix;
	Matrix = new BYTE[msize];
	if( !Matrix ) return false;

	RepST   = REP_IDLE;
	MSize   = msize;
	RepFrm  = 0;
	EndFrm  = 0;

	return true;
}

////////////////////////////////////////////////////////////////
// ステータス取得
//
// 引数:	なし
// 返値:	int		ステータス
////////////////////////////////////////////////////////////////
int REPLAY::GetStatus( void ) const
{
	return RepST;
}

////////////////////////////////////////////////////////////////
// リプレイ記録開始
//
// 引数:	filename	出力ファイル名
// 返値:	bool		true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::StartRecord( const char *filename )
{
	// とりあえずエラー設定
	Error::SetError( Error::ReplayPlayError );
	try{
		if( RepST != REP_IDLE ) throw Error::ReplayRecError;

		Ini = new cIni();
		if( !Ini->Init( filename ) ) throw Error::ReplayRecError;
	}
	catch( std::bad_alloc ){	// new に失敗した場合
		Error::SetError( Error::MemAllocFailed );
		return false;
	}
	catch( Error::Errno i ){	// 例外発生
		Error::SetError( i );
		if( Ini ) delete Ini;
		Ini = NULL;
		return false;
	}

	memset( Matrix, 0xff, MSize );		// キーマトリクスバッファクリア

	RepFrm = 0;
	RepST  = REP_RECORD;

	// 無事だったのでエラーなし
	Error::Reset();

    return true;
}

////////////////////////////////////////////////////////////////
// リプレイ記録再開
//
// 引数:	filename	出力ファイル名
// 引数:	frame       途中再開するフレーム
// 返値:	bool		true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::ResumeRecord(const char *filename, int frame)
{
    if(!StartRecord(filename)) return false;
    char buf[16];
    sprintf(buf, "%08lX", frame);
    // 指定されたフレーム以降のリプレイを削除し、そこから再開
    Ini->DeleteAfter("REPLAY", buf);

    RepFrm = frame;
    return true;
}

////////////////////////////////////////////////////////////////
// リプレイ記録停止
//
// 引数:	なし
// 返値:	なし
////////////////////////////////////////////////////////////////
void REPLAY::StopRecord( void )
{
	if( RepST != REP_RECORD ) return;

	if( Ini ){
		Ini->PutEntry( "REPLAY", NULL, "EndFrm", "0x%08lX", RepFrm );

		Ini->Write();

		delete Ini;
		Ini = NULL;
	}

	RepST = REP_IDLE;
}

////////////////////////////////////////////////////////////////
// リプレイ1フレーム書出し
//
// 引数:	mt		キーマトリクスポインタ
// 			chg		キーマトリクス変化 true:した false:しない
// 返値:	bool	true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::ReplayWriteFrame( const BYTE *mt, bool chg )
{
	char stren[16],strva[256];

	if( ( RepST != REP_RECORD ) || !mt || !Ini ) return false;

	// マトリクスに変化があったら書出し
    if( 1/*chg*/ ){
		sprintf( stren, "%08lX ", RepFrm );
		for( int i=0; i<MSize; i++ )
			sprintf( strva+i*2, "%02X", mt[i] );
		Ini->PutEntry( "REPLAY", NULL, stren, "%s", strva );
	}

	RepFrm++;

	return true;
}

////////////////////////////////////////////////////////////////
// リプレイ再生開始
//
// 引数:	filename	入力ファイル名
// 返値:	bool		true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::StartReplay( const char *filename )
{
	// とりあえずエラー設定
	Error::SetError( Error::ReplayPlayError );
	try{
		int st;	// ホントはDWORD

		if( RepST != REP_IDLE ) throw Error::ReplayPlayError;

		Ini = new cIni();
		if( !Ini->Init( filename ) ) throw Error::ReplayPlayError;

		if( !Ini->GetInt( "REPLAY", "EndFrm", &st, EndFrm ) ) throw Error::NoReplayData;
		else                                                  EndFrm = st;
	}
	catch( std::bad_alloc ){	// new に失敗した場合
		Error::SetError( Error::MemAllocFailed );
		return false;
	}
	catch( Error::Errno i ){	// 例外発生
		Error::SetError( i );
		if( Ini ) delete Ini;
		Ini = NULL;
		return false;
	}

	memset( Matrix, 0xff, MSize );	// キーマトリクスバッファクリア

	RepFrm = 1;
	RepST  = REP_REPLAY;

	// 無事だったのでエラーなし
	Error::Reset();

	return true;
}

////////////////////////////////////////////////////////////////
// リプレイ再生停止
//
// 引数:	なし
// 返値:	なし
////////////////////////////////////////////////////////////////
void REPLAY::StopReplay( void )
{
	if( RepST != REP_REPLAY ) return;

	if( Ini ){
		delete Ini;
		Ini = NULL;
	}

	RepST = REP_IDLE;
}

////////////////////////////////////////////////////////////////
// リプレイ1フレーム読込み
//
// 引数:	mt		キーマトリクスポインタ
// 返値:	bool	true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::ReplayReadFrame( BYTE *mt )
{
	char stren[16],strva[256];

	if( ( RepST != REP_REPLAY ) || !mt || !Ini ) return false;

	sprintf( stren, "%08lX", RepFrm );
	if( Ini->GetString( "REPLAY", stren, strva, "" ) ){
		int stl = strlen( strva ) / 2;
		for( int i=0; i<stl; i++ ){
			char dt[3] = "FF";
			strncpy( dt, &strva[i*2], 2 );
			Matrix[i] = strtol( dt, NULL, 16 );
		}
		memcpy( mt, Matrix, MSize );
	}

	if( ++RepFrm >= EndFrm ){
		// データ終端に達したらリプレイ終了
		StopReplay();
	}

	return true;
}
<|endoftext|>


<commit_before>#ifndef __sitksimpletransformix_hxx_
#define __sitksimpletransformix_hxx_

#include "sitkSimpleTransformix.h"

namespace itk {
  namespace simple {

template< typename TInputImage >
Image
SimpleTransformix::ExecuteInternal( void )
{
  typedef elastix::TransformixFilter< TInputImage > TransformixFilterType;
  typedef typename TransformixFilterType::Pointer TransforimxFilterPointer;

  try
  {
    TransforimxFilterPointer transformixFilter = TransformixFilterType::New();

    if( !this->IsEmpty( this->m_InputImage ) ) {
      transformixFilter->SetInputImage( static_cast< TInputImage * >( this->GetInputImage().GetITKBase() ) );
    }

    transformixFilter->SetInputPointSetFileName( this->GetInputPointSetFileName() );
    transformixFilter->SetComputeSpatialJacobian( this->GetComputeSpatialJacobian() );
    transformixFilter->SetComputeDeterminantOfSpatialJacobian( this->GetComputeDeterminantOfSpatialJacobian() );
    transformixFilter->SetComputeDeformationField( this->GetComputeDeformationField() );

    transformixFilter->SetOutputDirectory( this->GetOutputDirectory() );
    transformixFilter->SetLogFileName( this->GetLogFileName() );
    transformixFilter->SetLogToFile( this->GetLogToFile() );
    transformixFilter->SetLogToConsole( this->GetLogToConsole() );

    ParameterObjectPointer parameterObject = ParameterObjectType::New();
    parameterObject->SetParameterMap( this->m_TransformParameterMapVector );
    transformixFilter->SetTransformParameterObject( parameterObject );

    transformixFilter->Update();

    if( !this->IsEmpty( this->m_InputImage ) )
    {
      this->m_ResultImage = Image( transformixFilter->GetOutput() );
    }
  }
  catch( itk::ExceptionObject &e )
  {
    sitkExceptionMacro( << e );
  }

  // Make a deep copy. This is important to prevent the internal data object trying to update its
  // source (this elastixFilter) outside this function (where it has gone out of scope and been destroyed).
  // TODO: We should be able to simply call DisconnectPipeline() on the ITK output image but this does not seem to work
  this->m_ResultImage.MakeUnique();

  return this->m_ResultImage;
}

} // end namespace simple
} // end namespace itk

#endif // __sitksimpletransformix_hxx_
<commit_msg>ENH: Only make result image unique if it is used<commit_after>#ifndef __sitksimpletransformix_hxx_
#define __sitksimpletransformix_hxx_

#include "sitkSimpleTransformix.h"

namespace itk {
  namespace simple {

template< typename TInputImage >
Image
SimpleTransformix::ExecuteInternal( void )
{
  typedef elastix::TransformixFilter< TInputImage > TransformixFilterType;
  typedef typename TransformixFilterType::Pointer TransforimxFilterPointer;

  try
  {
    TransforimxFilterPointer transformixFilter = TransformixFilterType::New();

    if( !this->IsEmpty( this->m_InputImage ) ) {
      transformixFilter->SetInputImage( static_cast< TInputImage* >( this->GetInputImage().GetITKBase() ) );
    }

    transformixFilter->SetInputPointSetFileName( this->GetInputPointSetFileName() );
    transformixFilter->SetComputeSpatialJacobian( this->GetComputeSpatialJacobian() );
    transformixFilter->SetComputeDeterminantOfSpatialJacobian( this->GetComputeDeterminantOfSpatialJacobian() );
    transformixFilter->SetComputeDeformationField( this->GetComputeDeformationField() );

    transformixFilter->SetOutputDirectory( this->GetOutputDirectory() );
    transformixFilter->SetLogFileName( this->GetLogFileName() );
    transformixFilter->SetLogToFile( this->GetLogToFile() );
    transformixFilter->SetLogToConsole( this->GetLogToConsole() );

    ParameterObjectPointer parameterObject = ParameterObjectType::New();
    parameterObject->SetParameterMap( this->m_TransformParameterMapVector );
    transformixFilter->SetTransformParameterObject( parameterObject );

    transformixFilter->Update();

    if( !this->IsEmpty( this->m_InputImage ) )
    {
      this->m_ResultImage = Image( transformixFilter->GetOutput() );

      // Make a deep copy. This is important to prevent the internal data object trying to update its
      // source (this transformixFilter) outside this function (where it has gone out of scope and been destroyed).
      // TODO: We should be able to simply call DisconnectPipeline() on the ITK output image but this does not seem to work
      this->m_ResultImage.MakeUnique();
    }
  }
  catch( itk::ExceptionObject &e )
  {
    sitkExceptionMacro( << e );
  }

  return this->m_ResultImage;
}

} // end namespace simple
} // end namespace itk

#endif // __sitksimpletransformix_hxx_
<|endoftext|>


<commit_before>/**
 * Identify Majority Element in an Array
 * An element which apprears atmost n/2 times in an array
 * is known as Majority Element
 *
 * I/P: 3 2 2 3 2 2 2 2
 * O/P: 2
 *
 * I/P: 3 3 2 2 4 4
 * O/P: None
 */
#include <iostream>
#include <string.h>
using namespace std;

void findMajorityElement(int A[], int size) {
    int *count = new int[size];
    if (!count) return;
    memset(count, 0, sizeof(count));

    for (int i = 0; i < size; i++)
        count[A[i]]++;
    int majority = size/2;

    bool found = false;
    for (int i = 0; i < size; i++) {
        if (count[i] >= majority) {
            cout<<"Majority element: "<<i<<endl;
            found = true;
            break;
        }
    }
    if (!found)
        cout<<"Majority Element: None"<<endl;
    delete [] count;
}

void printArray(int A[], int size) {
    for (int i = 0; i < size; i++)
        cout<<A[i]<<" ";
    cout<<endl;
}

int main() {
    int A[] = {3, 2, 2, 4, 2, 2, 3, 2, 2, 3, 3, 3, 3, 3};
    int size = sizeof(A)/sizeof(A[0]);

    printArray(A, size);
    findMajorityElement(A, size);

    int B[] = {3, 3, 2, 2, 4, 4};
    size = sizeof(B)/sizeof(B[0]);
    printArray(B, size);
    findMajorityElement(B, size);

    return 0;
}
<commit_msg>Implement Boyer Moore Linear Time Voting Algorithm<commit_after>/**
 * Identify Majority Element in an Array
 * An element which apprears atmost n/2 times in an array
 * is known as Majority Element
 *
 * I/P: 3 2 2 3 2 2 2 2
 * O/P: 2
 *
 * I/P: 3 3 2 2 4 4
 * O/P: None
 */
#include <iostream>
#include <string.h>
using namespace std;

void printArray(int A[], int size) {
    for (int i = 0; i < size; i++)
        cout<<A[i]<<" ";
    cout<<endl;
}

void findMajorityElement(int A[], int size) {
    int *count = new int[size];
    if (!count) return;
    memset(count, 0, sizeof(count));

    for (int i = 0; i < size; i++)
        count[A[i]]++;
    int majority = size/2;

    bool found = false;
    for (int i = 0; i < size; i++) {
        if (count[i] >= majority) {
            cout<<"Majority element: "<<i<<endl;
            found = true;
            break;
        }
    }
    if (!found)
        cout<<"Majority Element: None"<<endl;
    delete [] count;
}

/**
 * http://www.cs.utexas.edu/~moore/best-ideas/mjrty/index.html
 * T(n) = O(n)
 * S(n) = O(1)
 */
void boyermoore_voting_algorithm(int A[], int size) {
    // find candidate
    int cand = 0, count = 1, maj_index = 0;
    for (int i = 1; i < size; i++) {
        // sweep and change the current candidate and counter
        // initally if counter = 0 current candidate is e and counter = 1
        if (A[maj_index] == A[i]) count++;
        else count--;
        // if counter is non zero, if e is current candidate increment
        // else decrement
        if (count == 0) {
            maj_index = i;
            count = 1;
        }
    }
    cand = A[maj_index];
    // check if the candidate is majority
    count = 0;
    for (int i = 0; i < size; i++) {
        if (A[i] == cand)
            count++;
    }
    if (count >= size/2) {
        cout<<"Majority element: "<<cand<<endl;
    } else {
        cout<<"Majority element: None"<<endl;
    }

}

int main() {
    int A[] = {3, 2, 2, 4, 2, 2, 3, 2, 2, 3, 3, 3, 3, 3};
    int size = sizeof(A)/sizeof(A[0]);

    printArray(A, size);
    //findMajorityElement(A, size);
    boyermoore_voting_algorithm(A, size);

    int B[] = {3, 3, 2, 2, 4, 4};
    size = sizeof(B)/sizeof(B[0]);
    printArray(B, size);
    //findMajorityElement(B, size);
    boyermoore_voting_algorithm(B, size);

    return 0;
}
<|endoftext|>


<commit_before>#include "MetaFile.h"

#include "../../graphics/GraphicsRenderer.h"
#include "../../raster/BgraFrame.h"

#include "Emf/RendererOutput.h"
#ifndef NEW_WMF
#include "Wmf/RendererOutput.h"
#endif

namespace MetaFile
{
	CMetaFile::CMetaFile(CApplicationFonts *pAppFonts)
	{
		m_pAppFonts = pAppFonts;

		//
		m_pFontManager = pAppFonts->GenerateFontManager();
		CFontsCache* pMeasurerCache = new CFontsCache();
		pMeasurerCache->SetStreams(pAppFonts->GetStreams());
		m_pFontManager->SetOwnerCache(pMeasurerCache);
		m_oWmfFile.SetFontManager(m_pFontManager);
		m_oEmfFile.SetFontManager(m_pFontManager);

		m_lType  = 0;
	}
	CMetaFile::~CMetaFile()
	{
		Close();
		RELEASEINTERFACE(m_pFontManager);
	}
	CFontManager* CMetaFile::get_FontManager()
	{
		return m_pFontManager;
	}
	bool CMetaFile::LoadFromFile(const wchar_t *wsFilePath)
	{
		//      Wmf
		m_oWmfFile.OpenFromFile(wsFilePath);

#ifdef NEW_WMF
		m_oWmfFile.Scan();
#else
		m_oWmfFile.Scan(&m_oWmfRect);
#endif

		if (!m_oWmfFile.CheckError())
		{
			m_lType = c_lMetaWmf;
			return true;
		}

		//   Wmf,     Emf
		m_oWmfFile.Close();

		m_oEmfFile.OpenFromFile(wsFilePath);
		m_oEmfFile.Scan();

		if (!m_oEmfFile.CheckError())
		{
			m_lType = c_lMetaEmf;
			return true;
		}

		//   Emf
		m_oEmfFile.Close();

		return false;
	};
	bool CMetaFile::DrawOnRenderer(IRenderer* pRenderer, double dX, double dY, double dWidth, double dHeight)
	{
		if (NULL == pRenderer)
			return false;

		pRenderer->BeginCommand(c_nImageType);

		if (c_lMetaWmf == m_lType)
		{
#ifdef NEW_WMF
#else
			double dRendererDpix, dRendererDpiY;
			pRenderer->get_DpiX(&dRendererDpix);
			pRenderer->get_DpiY(&dRendererDpiY);

			CRendererOutput oWmfOut(&m_oWmfFile, pRenderer, dX, dY, dWidth, dHeight);

			double fSrcWidth, fSrcHeight;

			float fW, fH;
			m_oWmfFile.GetSize(&fW, &fH);
			m_oWmfFile.GetDisplaySize(&fSrcWidth, &fSrcHeight, dRendererDpix, dRendererDpiY);

			//m_oWmfFile.GetDisplaySize( &fSrcWidth, &fSrcHeight, 25.4, 25.4 );
			TWmfRectF oRectB = m_oWmfFile.GetBounds();

			//double dW = m_oRect.oBR.fX - m_oRect.oTL.fX;
			//double dH = m_oRect.oBR.fY - m_oRect.oTL.fY;
			double dW = oRectB.oBR.fX - oRectB.oTL.fX;
			double dH = oRectB.oBR.fY - oRectB.oTL.fY;

			double dScaleX = dWidth / dW;//fSrcWidth;
			double dScaleY = dHeight / dH;//fSrcHeight;
			//double dScaleX = dWidth  / fSrcWidth;
			//double dScaleY = dHeight / fSrcHeight;

			double dSrcDpiX, dSrcDpiY;
			m_oWmfFile.GetDpi(&dSrcDpiX, &dSrcDpiY);

			double dDpiKoefX = dRendererDpix / dSrcDpiX;
			double dDpiKoefY = dRendererDpiY / dSrcDpiY;

			double dDpi = dSrcDpiY * fSrcHeight / fH;
			oWmfOut.SetDpi(dRendererDpix, dDpi);
			oWmfOut.SetWmfRect(oRectB);
			oWmfOut.SetScales(dScaleX, dScaleY);

			m_oWmfFile.SetOutputDevice(&oWmfOut);

			TWmfRectF oRect;
			m_oWmfFile.Play(&oRect);
#endif
		}
		else if (c_lMetaEmf == m_lType)
		{
			CEmfRendererOutput oEmfOut(&m_oEmfFile, pRenderer, dX, dY, dWidth, dHeight);
			m_oEmfFile.SetOutputDevice(&oEmfOut);
			m_oEmfFile.PlayMetaFile();
		}

		pRenderer->EndCommand(c_nImageType);
		return true;
	};
	void CMetaFile::Close()
	{
		m_oWmfFile.Close();
		//m_oEmfFile.Close();

		m_lType  = 0;
	};
	int CMetaFile::GetType()
	{
		return m_lType;
	}
	void CMetaFile::GetBounds(double* pdX, double* pdY, double* pdW, double* pdH)
	{
		if (c_lMetaWmf == m_lType)
		{
			*pdX = m_oWmfRect.oTL.fX;
			*pdY = m_oWmfRect.oTL.fY;
			*pdW = m_oWmfRect.oBR.fX - m_oWmfRect.oTL.fX;
			*pdH = m_oWmfRect.oBR.fY - m_oWmfRect.oTL.fY;
		}
		else if (c_lMetaEmf == m_lType)
		{
			TEmfRectL* pRect = m_oEmfFile.GetBounds();
			*pdX = pRect->lLeft;
			*pdY = pRect->lTop;
			*pdW = pRect->lRight - pRect->lLeft;
			*pdH = pRect->lBottom - pRect->lTop;
		}
		else
		{
			*pdX = 0;
			*pdY = 0;
			*pdW = 0;
			*pdH = 0;
		}
	};
	void CMetaFile::ConvertToRaster(const wchar_t* wsOutFilePath, unsigned int unFileType, int nWidth, int nHeight)
	{
		CFontManager *pFontManager = m_pAppFonts->GenerateFontManager();
		CFontsCache* pFontCache = new CFontsCache();
		pFontCache->SetStreams(m_pAppFonts->GetStreams());
		pFontManager->SetOwnerCache(pFontCache);
		CImageFilesCache oCache;

		CGraphicsRenderer oRenderer;
		oRenderer.SetSwapRGB(false);
		oRenderer.SetFontManager(pFontManager);
		oRenderer.SetImageCache(&oCache);

		if (-1 == nHeight)
		{
			double dX, dY, dW, dH;
			GetBounds(&dX, &dY, &dW, &dH);
			nHeight = (int)((double)nWidth * dH / dW);
		}

		//double dDpiX, dDpiY;
		//oRenderer.get_DpiX(&dDpiX);
		//oRenderer.get_DpiX(&dDpiY);

		double dWidth  = nWidth ;//* 72 / 25.4 / dDpiX;
		double dHeight = nHeight ;//* 72 / 25.4 / dDpiY;

		BYTE* pBgraData = new BYTE[nWidth * nHeight * 4];
		CBgraFrame oFrame;
		oFrame.put_Data(pBgraData);
		oFrame.put_Width(nWidth);
		oFrame.put_Height(nHeight);
		oFrame.put_Stride(-4 * nWidth);

		oRenderer.CreateFromBgraFrame(&oFrame);
		oRenderer.put_Width(dWidth);
		oRenderer.put_Height(dHeight);

		DrawOnRenderer(&oRenderer, 0, 0, dWidth, dHeight);

		oFrame.SaveFile(wsOutFilePath, unFileType);
		RELEASEINTERFACE(pFontManager);
	}
}
<commit_msg>SwapRGB перенесен в правильное место.<commit_after>#include "MetaFile.h"

#include "../../graphics/GraphicsRenderer.h"
#include "../../raster/BgraFrame.h"

#include "Emf/RendererOutput.h"
#ifndef NEW_WMF
#include "Wmf/RendererOutput.h"
#endif

namespace MetaFile
{
	CMetaFile::CMetaFile(CApplicationFonts *pAppFonts)
	{
		m_pAppFonts = pAppFonts;

		//
		m_pFontManager = pAppFonts->GenerateFontManager();
		CFontsCache* pMeasurerCache = new CFontsCache();
		pMeasurerCache->SetStreams(pAppFonts->GetStreams());
		m_pFontManager->SetOwnerCache(pMeasurerCache);
		m_oWmfFile.SetFontManager(m_pFontManager);
		m_oEmfFile.SetFontManager(m_pFontManager);

		m_lType  = 0;
	}
	CMetaFile::~CMetaFile()
	{
		Close();
		RELEASEINTERFACE(m_pFontManager);
	}
	CFontManager* CMetaFile::get_FontManager()
	{
		return m_pFontManager;
	}
	bool CMetaFile::LoadFromFile(const wchar_t *wsFilePath)
	{
		//      Wmf
		m_oWmfFile.OpenFromFile(wsFilePath);

#ifdef NEW_WMF
		m_oWmfFile.Scan();
#else
		m_oWmfFile.Scan(&m_oWmfRect);
#endif

		if (!m_oWmfFile.CheckError())
		{
			m_lType = c_lMetaWmf;
			return true;
		}

		//   Wmf,     Emf
		m_oWmfFile.Close();

		m_oEmfFile.OpenFromFile(wsFilePath);
		m_oEmfFile.Scan();

		if (!m_oEmfFile.CheckError())
		{
			m_lType = c_lMetaEmf;
			return true;
		}

		//   Emf
		m_oEmfFile.Close();

		return false;
	};
	bool CMetaFile::DrawOnRenderer(IRenderer* pRenderer, double dX, double dY, double dWidth, double dHeight)
	{
		if (NULL == pRenderer)
			return false;

		pRenderer->BeginCommand(c_nImageType);

		if (c_lMetaWmf == m_lType)
		{
#ifdef NEW_WMF
#else
			double dRendererDpix, dRendererDpiY;
			pRenderer->get_DpiX(&dRendererDpix);
			pRenderer->get_DpiY(&dRendererDpiY);

			CRendererOutput oWmfOut(&m_oWmfFile, pRenderer, dX, dY, dWidth, dHeight);

			double fSrcWidth, fSrcHeight;

			float fW, fH;
			m_oWmfFile.GetSize(&fW, &fH);
			m_oWmfFile.GetDisplaySize(&fSrcWidth, &fSrcHeight, dRendererDpix, dRendererDpiY);

			//m_oWmfFile.GetDisplaySize( &fSrcWidth, &fSrcHeight, 25.4, 25.4 );
			TWmfRectF oRectB = m_oWmfFile.GetBounds();

			//double dW = m_oRect.oBR.fX - m_oRect.oTL.fX;
			//double dH = m_oRect.oBR.fY - m_oRect.oTL.fY;
			double dW = oRectB.oBR.fX - oRectB.oTL.fX;
			double dH = oRectB.oBR.fY - oRectB.oTL.fY;

			double dScaleX = dWidth / dW;//fSrcWidth;
			double dScaleY = dHeight / dH;//fSrcHeight;
			//double dScaleX = dWidth  / fSrcWidth;
			//double dScaleY = dHeight / fSrcHeight;

			double dSrcDpiX, dSrcDpiY;
			m_oWmfFile.GetDpi(&dSrcDpiX, &dSrcDpiY);

			double dDpiKoefX = dRendererDpix / dSrcDpiX;
			double dDpiKoefY = dRendererDpiY / dSrcDpiY;

			double dDpi = dSrcDpiY * fSrcHeight / fH;
			oWmfOut.SetDpi(dRendererDpix, dDpi);
			oWmfOut.SetWmfRect(oRectB);
			oWmfOut.SetScales(dScaleX, dScaleY);

			m_oWmfFile.SetOutputDevice(&oWmfOut);

			TWmfRectF oRect;
			m_oWmfFile.Play(&oRect);
#endif
		}
		else if (c_lMetaEmf == m_lType)
		{
			CEmfRendererOutput oEmfOut(&m_oEmfFile, pRenderer, dX, dY, dWidth, dHeight);
			m_oEmfFile.SetOutputDevice(&oEmfOut);
			m_oEmfFile.PlayMetaFile();
		}

		pRenderer->EndCommand(c_nImageType);
		return true;
	};
	void CMetaFile::Close()
	{
		m_oWmfFile.Close();
		//m_oEmfFile.Close();

		m_lType  = 0;
	};
	int CMetaFile::GetType()
	{
		return m_lType;
	}
	void CMetaFile::GetBounds(double* pdX, double* pdY, double* pdW, double* pdH)
	{
		if (c_lMetaWmf == m_lType)
		{
			*pdX = m_oWmfRect.oTL.fX;
			*pdY = m_oWmfRect.oTL.fY;
			*pdW = m_oWmfRect.oBR.fX - m_oWmfRect.oTL.fX;
			*pdH = m_oWmfRect.oBR.fY - m_oWmfRect.oTL.fY;
		}
		else if (c_lMetaEmf == m_lType)
		{
			TEmfRectL* pRect = m_oEmfFile.GetBounds();
			*pdX = pRect->lLeft;
			*pdY = pRect->lTop;
			*pdW = pRect->lRight - pRect->lLeft;
			*pdH = pRect->lBottom - pRect->lTop;
		}
		else
		{
			*pdX = 0;
			*pdY = 0;
			*pdW = 0;
			*pdH = 0;
		}
	};
	void CMetaFile::ConvertToRaster(const wchar_t* wsOutFilePath, unsigned int unFileType, int nWidth, int nHeight)
	{
		CFontManager *pFontManager = m_pAppFonts->GenerateFontManager();
		CFontsCache* pFontCache = new CFontsCache();
		pFontCache->SetStreams(m_pAppFonts->GetStreams());
		pFontManager->SetOwnerCache(pFontCache);
		CImageFilesCache oCache;

		CGraphicsRenderer oRenderer;
		oRenderer.SetFontManager(pFontManager);
		oRenderer.SetImageCache(&oCache);

		if (-1 == nHeight)
		{
			double dX, dY, dW, dH;
			GetBounds(&dX, &dY, &dW, &dH);
			nHeight = (int)((double)nWidth * dH / dW);
		}

		//double dDpiX, dDpiY;
		//oRenderer.get_DpiX(&dDpiX);
		//oRenderer.get_DpiX(&dDpiY);

		double dWidth  = nWidth ;//* 72 / 25.4 / dDpiX;
		double dHeight = nHeight ;//* 72 / 25.4 / dDpiY;

		BYTE* pBgraData = new BYTE[nWidth * nHeight * 4];
		CBgraFrame oFrame;
		oFrame.put_Data(pBgraData);
		oFrame.put_Width(nWidth);
		oFrame.put_Height(nHeight);
		oFrame.put_Stride(-4 * nWidth);

		oRenderer.CreateFromBgraFrame(&oFrame);
		oRenderer.SetSwapRGB(false);
		oRenderer.put_Width(dWidth);
		oRenderer.put_Height(dHeight);

		DrawOnRenderer(&oRenderer, 0, 0, dWidth, dHeight);

		oFrame.SaveFile(wsOutFilePath, unFileType);
		RELEASEINTERFACE(pFontManager);
	}
}
<|endoftext|>


<commit_before>/**
Copyright (c) 2013, Philip Deegan.
All rights reserved.

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

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

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

#include <string>
#include <vector>
#include <string.h>
#include <algorithm>
#include <iostream>

#include "kul/except.hpp"

namespace kul {

class StringException : public kul::Exception{
    public:
        StringException(const char*f, const uint16_t& l, const std::string& s) : kul::Exception(f, l, s){}
};

class String{
    public:
        static void REPLACE(std::string& s, const std::string& f, const std::string& r){
            size_t p = 0;
            if((p = s.find(f)) != std::string::npos) s.replace(p, f.size(), r);
        }
        static void REPLACE_ALL(std::string& s, const std::string& f, const std::string& r){
            while(s.find(f) != std::string::npos) REPLACE(s, f, r);
        }
        static void TRIM_LEFT(std::string& s, const char& delim=' '){
            while(s.find(delim) == 0)
                s.erase(0, 1);
        }
        static void TRIM_RIGHT(std::string& s, const char& delim=' '){
            while(s.rfind(delim) == s.size() - 1)
                s.pop_back();
        }
        static void TRIM(std::string& s){
            while(s.find(' ') == 0 || s.find('\t') == 0)
                s.erase(0, 1);
            if(s.size() == 0) return;
            while(s.rfind(' ') == s.size() - 1 || s.rfind('\t') == s.size() - 1)
                s.pop_back();
        }
        static void PAD(std::string& s, const uint16_t& p){
            while(s.size() < p) s += " ";
        }
        static std::vector<std::string> SPLIT(const std::string& s, const char& d){
            std::vector<std::string> v;
            SPLIT(s, d, v);
            return v;
        }
        static void SPLIT(const std::string& s, const char& d, std::vector<std::string>& v){
            if(s.find(d) != std::string::npos){
                std::string l;
                std::stringstream stream(s);
                while(std::getline(stream, l, d))
                    if(l.compare("") != 0) v.push_back(l);
            }else v.push_back(s);
        }
        static std::vector<std::string> SPLIT(const std::string& s, const std::string& d){
            std::vector<std::string> v;
            SPLIT(s, d, v);
            return v;
        }
        static void SPLIT(const std::string& s, const std::string& d, std::vector<std::string>& v){
            std::string l = s;
            size_t pos = 0;
            while((pos = l.find(d)) != std::string::npos){
                v.push_back(l.substr(0, pos));
                l = l.substr(pos + 1);
            }
            v.push_back(l);
        }
        static std::vector<std::string> ESC_SPLIT(const std::string& s, const char& d, const char& e = '\\'){
            std::vector<std::string> v;
            ESC_SPLIT(s, d, v, e);
            return v;
        }
        static void ESC_SPLIT(const std::string& s, const char& d, std::vector<std::string>& v, const char& e = '\\'){
            std::string l = s;
            size_t pos = 0, esc = 0;
            while((pos = l.find(d, esc)) != std::string::npos){
                if(pos > 0 && l.find(std::string(1, e) + std::string(1, d)) == pos - 1){
                    esc++;
                    continue;
                }
                v.push_back(l.substr(0, pos));
                l = l.substr(pos + 1);
                esc = 0;
            }
            v.push_back(l);
        }
        static bool NO_CASE_CMP(const std::string& a, const std::string& b){
                std::string aCpy(a);
                std::string bCpy(b);
                std::transform(aCpy.begin(), aCpy.end(), aCpy.begin(), ::tolower);
                std::transform(bCpy.begin(), bCpy.end(), bCpy.begin(), ::tolower);
                return (aCpy == bCpy);
        }
        static std::vector<std::string> LINES(const std::string& s){
            std::vector<std::string> v;
            LINES(s, v);
            return v;
        }
        static void LINES(const std::string& s, std::vector<std::string>& v){
            if(s.find("\n") != std::string::npos){
                std::string l;
                std::stringstream ss(s);
                while(std::getline(ss, l)) if(!l.empty()) v.push_back(l);
            }else v.push_back(s);
        }

        static bool BOOL(std::string s){
            TRIM(s);
            const std::vector<std::string>& pos {"yes", "y", "true" , "1"};
            const std::vector<std::string>& neg {"no" , "n", "false", "0"};
            std::transform(s.begin(), s.end(), s.begin(), ::tolower);
            if (std::find(pos.begin(), pos.end(), s) != pos.end()) return true;
            if (std::find(neg.begin(), neg.end(), s) != neg.end()) return false;
            KEXCEPT(StringException, "input not bool-able, " + s);
        }

        static uint16_t UINT16(const std::string& s) throw(StringException){
            try{
                uint32_t lresult = stoul(s, 0, 10);
                uint16_t result = lresult;
                if (result != lresult) KEXCEPT(StringException, "UINT failed");
                return result;
            }catch(const std::invalid_argument& e){ KEXCEPT(StringException, "UINT failed"); }
            return 0;
        }
        static int16_t INT16(const std::string& s) throw(StringException){
            try{
                return std::stoi(s);
            }catch(const std::invalid_argument& e){ KEXCEPT(StringException, "stoi failed"); }
        }
        static uint32_t UINT32(const std::string& s) throw(StringException){
            try{
                return std::stoul(s);
            }catch(const std::invalid_argument& e){ KEXCEPT(StringException, "ULONG failed"); }
            return 0;
        }
        static uint64_t UINT64(const std::string& s) throw(StringException){
            try{
                return std::stoull(s);
            }catch(const std::invalid_argument& e){ KEXCEPT(StringException, "ULONGLONG failed"); }
            return 0;
        }
};

}
#endif /* _KUL_STRING_HPP_ */
<commit_msg>whitespace<commit_after>/**
Copyright (c) 2013, Philip Deegan.
All rights reserved.

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

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

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

#include <string>
#include <vector>
#include <string.h>
#include <algorithm>
#include <iostream>

#include "kul/except.hpp"

namespace kul {

class StringException : public kul::Exception{
    public:
        StringException(const char*f, const uint16_t& l, const std::string& s) : kul::Exception(f, l, s){}
};

class String{
    public:
        static void REPLACE(std::string& s, const std::string& f, const std::string& r){
            size_t p = 0;
            if((p = s.find(f)) != std::string::npos) s.replace(p, f.size(), r);
        }
        static void REPLACE_ALL(std::string& s, const std::string& f, const std::string& r){
            while(s.find(f) != std::string::npos) REPLACE(s, f, r);
        }
        static void TRIM_LEFT(std::string& s, const char& delim=' '){
            while(s.find(delim) == 0)
                s.erase(0, 1);
        }
        static void TRIM_RIGHT(std::string& s, const char& delim=' '){
            while(s.rfind(delim) == s.size() - 1)
                s.pop_back();
        }
        static void TRIM(std::string& s){
            while(s.find(' ') == 0 || s.find('\t') == 0)
                s.erase(0, 1);
            if(s.size() == 0) return;
            while(s.rfind(' ') == s.size() - 1 || s.rfind('\t') == s.size() - 1)
                s.pop_back();
        }
        static void PAD(std::string& s, const uint16_t& p){
            while(s.size() < p) s += " ";
        }
        static std::vector<std::string> SPLIT(const std::string& s, const char& d){
            std::vector<std::string> v;
            SPLIT(s, d, v);
            return v;
        }
        static void SPLIT(const std::string& s, const char& d, std::vector<std::string>& v){
            if(s.find(d) != std::string::npos){
                std::string l;
                std::stringstream stream(s);
                while(std::getline(stream, l, d))
                    if(l.compare("") != 0) v.push_back(l);
            }else v.push_back(s);
        }
        static std::vector<std::string> SPLIT(const std::string& s, const std::string& d){
            std::vector<std::string> v;
            SPLIT(s, d, v);
            return v;
        }
        static void SPLIT(const std::string& s, const std::string& d, std::vector<std::string>& v){
            std::string l = s;
            size_t pos = 0;
            while((pos = l.find(d)) != std::string::npos){
                v.push_back(l.substr(0, pos));
                l = l.substr(pos + 1);
            }
            v.push_back(l);
        }
        static std::vector<std::string> ESC_SPLIT(const std::string& s, const char& d, const char& e = '\\'){
            std::vector<std::string> v;
            ESC_SPLIT(s, d, v, e);
            return v;
        }
        static void ESC_SPLIT(const std::string& s, const char& d, std::vector<std::string>& v, const char& e = '\\'){
            std::string l = s;
            size_t pos = 0, esc = 0;
            while((pos = l.find(d, esc)) != std::string::npos){
                if(pos > 0 && l.find(std::string(1, e) + std::string(1, d)) == pos - 1){
                    esc++;
                    continue;
                }
                v.push_back(l.substr(0, pos));
                l = l.substr(pos + 1);
                esc = 0;
            }
            v.push_back(l);
        }
        static bool NO_CASE_CMP(const std::string& a, const std::string& b){
            std::string aCpy(a);
            std::string bCpy(b);
            std::transform(aCpy.begin(), aCpy.end(), aCpy.begin(), ::tolower);
            std::transform(bCpy.begin(), bCpy.end(), bCpy.begin(), ::tolower);
            return (aCpy == bCpy);
        }
        static std::vector<std::string> LINES(const std::string& s){
            std::vector<std::string> v;
            LINES(s, v);
            return v;
        }
        static void LINES(const std::string& s, std::vector<std::string>& v){
            if(s.find("\n") != std::string::npos){
                std::string l;
                std::stringstream ss(s);
                while(std::getline(ss, l)) if(!l.empty()) v.push_back(l);
            }else v.push_back(s);
        }

        static bool BOOL(std::string s){
            TRIM(s);
            const std::vector<std::string>& pos {"yes", "y", "true" , "1"};
            const std::vector<std::string>& neg {"no" , "n", "false", "0"};
            std::transform(s.begin(), s.end(), s.begin(), ::tolower);
            if (std::find(pos.begin(), pos.end(), s) != pos.end()) return true;
            if (std::find(neg.begin(), neg.end(), s) != neg.end()) return false;
            KEXCEPT(StringException, "input not bool-able, " + s);
        }

        static uint16_t UINT16(const std::string& s) throw(StringException){
            try{
                uint32_t lresult = stoul(s, 0, 10);
                uint16_t result = lresult;
                if (result != lresult) KEXCEPT(StringException, "UINT failed");
                return result;
            }catch(const std::invalid_argument& e){ KEXCEPT(StringException, "UINT failed"); }
            return 0;
        }
        static int16_t INT16(const std::string& s) throw(StringException){
            try{
                return std::stoi(s);
            }catch(const std::invalid_argument& e){ KEXCEPT(StringException, "stoi failed"); }
        }
        static uint32_t UINT32(const std::string& s) throw(StringException){
            try{
                return std::stoul(s);
            }catch(const std::invalid_argument& e){ KEXCEPT(StringException, "ULONG failed"); }
            return 0;
        }
        static uint64_t UINT64(const std::string& s) throw(StringException){
            try{
                return std::stoull(s);
            }catch(const std::invalid_argument& e){ KEXCEPT(StringException, "ULONGLONG failed"); }
            return 0;
        }
};

}
#endif /* _KUL_STRING_HPP_ */
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

#ifndef HTTP_MIME_TYPES_HPP
#define HTTP_MIME_TYPES_HPP

#include <string>
#include <unordered_map>

namespace http {
//------------------------------------------------
using Extension       = std::string;
using Mime_Type       = std::string;
using Mime_Type_Table = std::unordered_map<Extension, Mime_Type>;
//------------------------------------------------
const Mime_Type_Table mime_types {
  //< Text mimes
  {"html", "text/html"},
  {"htm" , "text/html"},
  {"js"  , "text/javascript"},
  {"txt" , "text/plain"},
  {"css" , "text/css"},
  {"xml" , "text/xml"},

  //< Image mimes
  {"bmp" , "image/bmp"},
  {"gif" , "image/gif"},
  {"png" , "image/png"},
  {"jpg" , "image/jpeg"},
  {"jpeg", "image/jpeg"},
  {"ico" , "image/x-icon"},

  //< Audio mimes
  {"mid" , "audio/midi"},
  {"midi", "audio/midi"},
  {"kar" , "audio/midi"},
  {"mp3" , "audio/mpeg"},
  {"ogg" , "audio/ogg"},
  {"m4a" , "audio/x-m4a"},
  {"ra"  , "audio/x-realaudio"},

  //< Video mimes
  {"3gp" , "video/3gpp"},
  {"3gpp", "video/3gpp"},
  {"ts"  , "video/mp2t"},
  {"mp4" , "video/mp4"},
  {"mpg" , "video/mpeg"},
  {"mpeg", "video/mpeg"},
  {"mov" , "video/quicktime"},
  {"webm", "video/webm"},
  {"flv" , "video/x-flv"},
  {"m4v" , "video/x-m4v"},
  {"mng" , "video/x-mng"},
  {"asf" , "video/x-ms-asf"},
  {"asx" , "video/x-ms-asf"},
  {"wmv" , "video/x-ms-wmv"},
  {"avi" , "video/x-msvideo"},

  //< Application mimes
  {"zip"  , "application/zip"},
  {"7z"   , "application/x-7z-compressed"},
  {"jar"  , "application/java-archive"},
  {"war"  , "application/java-archive"},
  {"ear"  , "application/java-archive"},
  {"json" , "application/json"},
  {"pdf"  , "application/pdf"},
  {"xhtml", "application/xhtml+xml"},
  {"xspf" , "application/xspf+xml"},
  {"der" , "application/x-x509-ca-cert"},
  {"pem" , "application/x-x509-ca-cert"},
  {"crt" , "application/x-x509-ca-cert"},
  {"bin" , "application/octet-stream"},
  {"exe" , "application/octet-stream"},
  {"dll" , "application/octet-stream"},
  {"deb" , "application/octet-stream"},
  {"dmg" , "application/octet-stream"},
  {"iso" , "application/octet-stream"},
  {"img" , "application/octet-stream"},
  {"msi" , "application/octet-stream"},
  {"msp" , "application/octet-stream"},
  {"msm" , "application/octet-stream"}
}; //< mime_types

inline const Mime_Type& extension_to_type(const Extension& extension) noexcept {
  auto iter = mime_types.find(extension);
  //------------------------------------------------
  return (iter not_eq mime_types.end())
          ? iter->second
          : const_cast<Mime_Type_Table&>(mime_types)["txt"];
}

} //< namespace http

#endif //< HTTP_MIME_TYPES_HPP
<commit_msg>mime: Added svg type<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

#ifndef HTTP_MIME_TYPES_HPP
#define HTTP_MIME_TYPES_HPP

#include <string>
#include <unordered_map>

namespace http {
//------------------------------------------------
using Extension       = std::string;
using Mime_Type       = std::string;
using Mime_Type_Table = std::unordered_map<Extension, Mime_Type>;
//------------------------------------------------
const Mime_Type_Table mime_types {
  //< Text mimes
  {"html", "text/html"},
  {"htm" , "text/html"},
  {"js"  , "text/javascript"},
  {"txt" , "text/plain"},
  {"css" , "text/css"},
  {"xml" , "text/xml"},

  //< Image mimes
  {"bmp" , "image/bmp"},
  {"gif" , "image/gif"},
  {"png" , "image/png"},
  {"jpg" , "image/jpeg"},
  {"jpeg", "image/jpeg"},
  {"ico" , "image/x-icon"},
  {"svg" , "image/svg+xml"},

  //< Audio mimes
  {"mid" , "audio/midi"},
  {"midi", "audio/midi"},
  {"kar" , "audio/midi"},
  {"mp3" , "audio/mpeg"},
  {"ogg" , "audio/ogg"},
  {"m4a" , "audio/x-m4a"},
  {"ra"  , "audio/x-realaudio"},

  //< Video mimes
  {"3gp" , "video/3gpp"},
  {"3gpp", "video/3gpp"},
  {"ts"  , "video/mp2t"},
  {"mp4" , "video/mp4"},
  {"mpg" , "video/mpeg"},
  {"mpeg", "video/mpeg"},
  {"mov" , "video/quicktime"},
  {"webm", "video/webm"},
  {"flv" , "video/x-flv"},
  {"m4v" , "video/x-m4v"},
  {"mng" , "video/x-mng"},
  {"asf" , "video/x-ms-asf"},
  {"asx" , "video/x-ms-asf"},
  {"wmv" , "video/x-ms-wmv"},
  {"avi" , "video/x-msvideo"},

  //< Application mimes
  {"zip"  , "application/zip"},
  {"7z"   , "application/x-7z-compressed"},
  {"jar"  , "application/java-archive"},
  {"war"  , "application/java-archive"},
  {"ear"  , "application/java-archive"},
  {"json" , "application/json"},
  {"pdf"  , "application/pdf"},
  {"xhtml", "application/xhtml+xml"},
  {"xspf" , "application/xspf+xml"},
  {"der" , "application/x-x509-ca-cert"},
  {"pem" , "application/x-x509-ca-cert"},
  {"crt" , "application/x-x509-ca-cert"},
  {"bin" , "application/octet-stream"},
  {"exe" , "application/octet-stream"},
  {"dll" , "application/octet-stream"},
  {"deb" , "application/octet-stream"},
  {"dmg" , "application/octet-stream"},
  {"iso" , "application/octet-stream"},
  {"img" , "application/octet-stream"},
  {"msi" , "application/octet-stream"},
  {"msp" , "application/octet-stream"},
  {"msm" , "application/octet-stream"}
}; //< mime_types

inline const Mime_Type& extension_to_type(const Extension& extension) noexcept {
  auto iter = mime_types.find(extension);
  //------------------------------------------------
  return (iter not_eq mime_types.end())
          ? iter->second
          : const_cast<Mime_Type_Table&>(mime_types)["txt"];
}

} //< namespace http

#endif //< HTTP_MIME_TYPES_HPP
<|endoftext|>


<commit_before>// Copyright 2012 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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.

#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
#include <string>
#include <utility>
#include <vector>

#include "Exceptions.hpp"

#pragma once

namespace isa
{
namespace OpenCL
{

// Class that represents the configuration of an OpenCL kernel
class KernelConf
{
  public:
    KernelConf();
    ~KernelConf();
    // Get
    inline std::string getIntType() const;
    inline unsigned int getNrThreadsD0() const;
    inline unsigned int getNrThreadsD1() const;
    inline unsigned int getNrThreadsD2() const;
    inline unsigned int getNrItemsD0() const;
    inline unsigned int getNrItemsD1() const;
    inline unsigned int getNrItemsD2() const;
    // Set
    inline void setIntType(std::string &type);
    inline void setNrThreadsD0(unsigned int threads);
    inline void setNrThreadsD1(unsigned int threads);
    inline void setNrThreadsD2(unsigned int threads);
    inline void setNrItemsD0(unsigned int items);
    inline void setNrItemsD1(unsigned int items);
    inline void setNrItemsD2(unsigned int items);
    // utils
    std::string print() const;

  private:
    std::string intType;
    unsigned int nrThreadsD0, nrThreadsD1, nrThreadsD2;
    unsigned int nrItemsD0, nrItemsD1, nrItemsD2;
};

cl::Kernel *compile(const std::string &name, const std::string &code, const std::string &flags, cl::Context &clContext, cl::Device &clDevice);

// Implementations
inline std::string KernelConf::getIntType() const
{
    return intType;
}

inline unsigned int KernelConf::getNrThreadsD0() const
{
    return nrThreadsD0;
}

inline unsigned int KernelConf::getNrThreadsD1() const
{
    return nrThreadsD1;
}

inline unsigned int KernelConf::getNrThreadsD2() const
{
    return nrThreadsD2;
}

inline unsigned int KernelConf::getNrItemsD0() const
{
    return nrItemsD0;
}

inline unsigned int KernelConf::getNrItemsD1() const
{
    return nrItemsD1;
}

inline unsigned int KernelConf::getNrItemsD2() const
{
    return nrItemsD2;
}

inline void KernelConf::setIntType(std::string &type)
{
    intType = type;
}

inline void KernelConf::setNrThreadsD0(unsigned int threads)
{
    nrThreadsD0 = threads;
}

inline void KernelConf::setNrThreadsD1(unsigned int threads)
{
    nrThreadsD1 = threads;
}

inline void KernelConf::setNrThreadsD2(unsigned int threads)
{
    nrThreadsD2 = threads;
}

inline void KernelConf::setNrItemsD0(unsigned int items)
{
    nrItemsD0 = items;
}

inline void KernelConf::setNrItemsD1(unsigned int items)
{
    nrItemsD1 = items;
}

inline void KernelConf::setNrItemsD2(unsigned int items)
{
    nrItemsD2 = items;
}

} // namespace OpenCL
} // namespace isa
<commit_msg>Pass the parameter by value.<commit_after>// Copyright 2012 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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.

#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
#include <string>
#include <utility>
#include <vector>

#include "Exceptions.hpp"

#pragma once

namespace isa
{
namespace OpenCL
{

// Class that represents the configuration of an OpenCL kernel
class KernelConf
{
  public:
    KernelConf();
    ~KernelConf();
    // Get
    inline std::string getIntType() const;
    inline unsigned int getNrThreadsD0() const;
    inline unsigned int getNrThreadsD1() const;
    inline unsigned int getNrThreadsD2() const;
    inline unsigned int getNrItemsD0() const;
    inline unsigned int getNrItemsD1() const;
    inline unsigned int getNrItemsD2() const;
    // Set
    inline void setIntType(std::string type);
    inline void setNrThreadsD0(unsigned int threads);
    inline void setNrThreadsD1(unsigned int threads);
    inline void setNrThreadsD2(unsigned int threads);
    inline void setNrItemsD0(unsigned int items);
    inline void setNrItemsD1(unsigned int items);
    inline void setNrItemsD2(unsigned int items);
    // utils
    std::string print() const;

  private:
    std::string intType;
    unsigned int nrThreadsD0, nrThreadsD1, nrThreadsD2;
    unsigned int nrItemsD0, nrItemsD1, nrItemsD2;
};

cl::Kernel *compile(const std::string &name, const std::string &code, const std::string &flags, cl::Context &clContext, cl::Device &clDevice);

// Implementations
inline std::string KernelConf::getIntType() const
{
    return intType;
}

inline unsigned int KernelConf::getNrThreadsD0() const
{
    return nrThreadsD0;
}

inline unsigned int KernelConf::getNrThreadsD1() const
{
    return nrThreadsD1;
}

inline unsigned int KernelConf::getNrThreadsD2() const
{
    return nrThreadsD2;
}

inline unsigned int KernelConf::getNrItemsD0() const
{
    return nrItemsD0;
}

inline unsigned int KernelConf::getNrItemsD1() const
{
    return nrItemsD1;
}

inline unsigned int KernelConf::getNrItemsD2() const
{
    return nrItemsD2;
}

inline void KernelConf::setIntType(std::string type)
{
    intType = type;
}

inline void KernelConf::setNrThreadsD0(unsigned int threads)
{
    nrThreadsD0 = threads;
}

inline void KernelConf::setNrThreadsD1(unsigned int threads)
{
    nrThreadsD1 = threads;
}

inline void KernelConf::setNrThreadsD2(unsigned int threads)
{
    nrThreadsD2 = threads;
}

inline void KernelConf::setNrItemsD0(unsigned int items)
{
    nrItemsD0 = items;
}

inline void KernelConf::setNrItemsD1(unsigned int items)
{
    nrItemsD1 = items;
}

inline void KernelConf::setNrItemsD2(unsigned int items)
{
    nrItemsD2 = items;
}

} // namespace OpenCL
} // namespace isa
<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <tuple>
#include <vector>

namespace kdbush {

template <std::uint8_t I, typename T>
struct nth {
    inline static typename std::tuple_element<I, T>::type get(const T &t) {
        return std::get<I>(t);
    }
};

template <typename TPoint, typename TIndex = std::size_t>
class KDBush {

public:
    using TNumber = decltype(nth<0, TPoint>::get(std::declval<TPoint>()));
    static_assert(
        std::is_same<TNumber, decltype(nth<1, TPoint>::get(std::declval<TPoint>()))>::value,
        "point component types must be identical");

    static const std::uint8_t defaultNodeSize = 64;

    KDBush(const std::vector<TPoint> &points_, const std::uint8_t nodeSize_ = defaultNodeSize)
        : KDBush(std::begin(points_), std::end(points_), nodeSize_) {
    }

    template <typename TPointIter>
    KDBush(TPointIter points_begin,
           TPointIter points_end,
           const std::uint8_t nodeSize_ = defaultNodeSize)
        : nodeSize(nodeSize_) {

        const TIndex size = std::distance(points_begin, points_end);

        points.reserve(size);
        ids.reserve(size);

        for (TIndex i = 0; i < size; i++) {
            const auto p = *(points_begin + i);
            points.emplace_back(nth<0, TPoint>::get(p), nth<1, TPoint>::get(p));
            ids.push_back(i);
        }

        sortKD(0, size - 1, 0);
    }

    template <typename TOutputIter>
    void range(const TNumber minX,
               const TNumber minY,
               const TNumber maxX,
               const TNumber maxY,
               TOutputIter out) {
        range(minX, minY, maxX, maxY, out, 0, ids.size() - 1, 0);
    }

    template <typename TOutputIter>
    void within(const TNumber qx, const TNumber qy, const TNumber r, TOutputIter out) {
        within(qx, qy, r, out, 0, ids.size() - 1, 0);
    }

private:
    std::vector<TIndex> ids;
    std::vector<std::pair<TNumber, TNumber>> points;
    std::uint8_t nodeSize;

    template <typename TOutputIter>
    void range(const TNumber minX,
               const TNumber minY,
               const TNumber maxX,
               const TNumber maxY,
               TOutputIter out,
               const TIndex left,
               const TIndex right,
               const std::uint8_t axis) {

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                const TNumber x = std::get<0>(points[i]);
                const TNumber y = std::get<1>(points[i]);
                if (x >= minX && x <= maxX && y >= minY && y <= maxY) *out++ = ids[i];
            }
            return;
        }

        const TIndex m = (left + right) >> 1;
        const TNumber x = std::get<0>(points[m]);
        const TNumber y = std::get<1>(points[m]);

        if (x >= minX && x <= maxX && y >= minY && y <= maxY) *out++ = ids[m];

        if (axis == 0 ? minX <= x : minY <= y)
            range(minX, minY, maxX, maxY, out, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? maxX >= x : maxY >= y)
            range(minX, minY, maxX, maxY, out, m + 1, right, (axis + 1) % 2);
    }

    template <typename TOutputIter>
    void within(const TNumber qx,
                const TNumber qy,
                const TNumber r,
                TOutputIter out,
                const TIndex left,
                const TIndex right,
                const std::uint8_t axis) {

        const TNumber r2 = r * r;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                const TNumber x = std::get<0>(points[i]);
                const TNumber y = std::get<1>(points[i]);
                if (sqDist(x, y, qx, qy) <= r2) *out++ = ids[i];
            }
            return;
        }

        const TIndex m = (left + right) >> 1;
        const TNumber x = std::get<0>(points[m]);
        const TNumber y = std::get<1>(points[m]);

        if (sqDist(x, y, qx, qy) <= r2) *out++ = ids[m];

        if (axis == 0 ? qx - r <= x : qy - r <= y)
            within(qx, qy, r, out, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? qx + r >= x : qy + r >= y)
            within(qx, qy, r, out, m + 1, right, (axis + 1) % 2);
    }

    void sortKD(const TIndex left, const TIndex right, const std::uint8_t axis) {
        if (right - left <= nodeSize) return;
        const TIndex m = (left + right) >> 1;
        if (axis == 0) {
            select<0>(m, left, right);
        } else {
            select<1>(m, left, right);
        }
        sortKD(left, m - 1, (axis + 1) % 2);
        sortKD(m + 1, right, (axis + 1) % 2);
    }

    template <std::uint8_t axis>
    void select(const TIndex k, TIndex left, TIndex right) {

        while (right > left) {
            if (right - left > 600) {
                const TIndex n = right - left + 1;
                const TIndex m = k - left + 1;
                const double z = log(n);
                const double s = 0.5 * exp(2 * z / 3);
                const double sd = 0.5 * sqrt(z * s * (n - s) / n) * (2 * m < n ? -1 : 1);
                const TIndex newLeft = std::max(left, TIndex(k - m * s / n + sd));
                const TIndex newRight = std::min(right, TIndex(k + (n - m) * s / n + sd));
                select<axis>(k, newLeft, newRight);
            }

            const TNumber t = std::get<axis>(points[k]);
            TIndex i = left;
            TIndex j = right;

            swapItem(left, k);
            if (std::get<axis>(points[right]) > t) swapItem(left, right);

            while (i < j) {
                swapItem(i, j);
                i++;
                j--;
                while (std::get<axis>(points[i]) < t) i++;
                while (std::get<axis>(points[j]) > t) j--;
            }

            if (std::get<axis>(points[left]) == t)
                swapItem(left, j);
            else {
                j++;
                swapItem(j, right);
            }

            if (j <= k) left = j + 1;
            if (k <= j) right = j - 1;
        }
    }

    void swapItem(const TIndex i, const TIndex j) {
        std::iter_swap(ids.begin() + i, ids.begin() + j);
        std::iter_swap(points.begin() + i, points.begin() + j);
    }

    TNumber sqDist(const TNumber ax, const TNumber ay, const TNumber bx, const TNumber by) {
        const TNumber dx = ax - bx;
        const TNumber dy = ay - by;
        return dx * dx + dy * dy;
    }
};

} // namespace kdbush
<commit_msg>avoid iterators copy in constructor<commit_after>#pragma once

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <tuple>
#include <vector>

namespace kdbush {

template <std::uint8_t I, typename T>
struct nth {
    inline static typename std::tuple_element<I, T>::type get(const T &t) {
        return std::get<I>(t);
    }
};

template <typename TPoint, typename TIndex = std::size_t>
class KDBush {

public:
    using TNumber = decltype(nth<0, TPoint>::get(std::declval<TPoint>()));
    static_assert(
        std::is_same<TNumber, decltype(nth<1, TPoint>::get(std::declval<TPoint>()))>::value,
        "point component types must be identical");

    static const std::uint8_t defaultNodeSize = 64;

    KDBush(const std::vector<TPoint> &points_, const std::uint8_t nodeSize_ = defaultNodeSize)
        : KDBush(std::begin(points_), std::end(points_), nodeSize_) {
    }

    template <typename TPointIter>
    KDBush(const TPointIter &points_begin,
           const TPointIter &points_end,
           const std::uint8_t nodeSize_ = defaultNodeSize)
        : nodeSize(nodeSize_) {

        const TIndex size = std::distance(points_begin, points_end);

        points.reserve(size);
        ids.reserve(size);

        for (TIndex i = 0; i < size; i++) {
            const auto p = *(points_begin + i);
            points.emplace_back(nth<0, TPoint>::get(p), nth<1, TPoint>::get(p));
            ids.push_back(i);
        }

        sortKD(0, size - 1, 0);
    }

    template <typename TOutputIter>
    void range(const TNumber minX,
               const TNumber minY,
               const TNumber maxX,
               const TNumber maxY,
               TOutputIter out) {
        range(minX, minY, maxX, maxY, out, 0, ids.size() - 1, 0);
    }

    template <typename TOutputIter>
    void within(const TNumber qx, const TNumber qy, const TNumber r, TOutputIter out) {
        within(qx, qy, r, out, 0, ids.size() - 1, 0);
    }

private:
    std::vector<TIndex> ids;
    std::vector<std::pair<TNumber, TNumber>> points;
    std::uint8_t nodeSize;

    template <typename TOutputIter>
    void range(const TNumber minX,
               const TNumber minY,
               const TNumber maxX,
               const TNumber maxY,
               TOutputIter out,
               const TIndex left,
               const TIndex right,
               const std::uint8_t axis) {

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                const TNumber x = std::get<0>(points[i]);
                const TNumber y = std::get<1>(points[i]);
                if (x >= minX && x <= maxX && y >= minY && y <= maxY) *out++ = ids[i];
            }
            return;
        }

        const TIndex m = (left + right) >> 1;
        const TNumber x = std::get<0>(points[m]);
        const TNumber y = std::get<1>(points[m]);

        if (x >= minX && x <= maxX && y >= minY && y <= maxY) *out++ = ids[m];

        if (axis == 0 ? minX <= x : minY <= y)
            range(minX, minY, maxX, maxY, out, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? maxX >= x : maxY >= y)
            range(minX, minY, maxX, maxY, out, m + 1, right, (axis + 1) % 2);
    }

    template <typename TOutputIter>
    void within(const TNumber qx,
                const TNumber qy,
                const TNumber r,
                TOutputIter out,
                const TIndex left,
                const TIndex right,
                const std::uint8_t axis) {

        const TNumber r2 = r * r;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                const TNumber x = std::get<0>(points[i]);
                const TNumber y = std::get<1>(points[i]);
                if (sqDist(x, y, qx, qy) <= r2) *out++ = ids[i];
            }
            return;
        }

        const TIndex m = (left + right) >> 1;
        const TNumber x = std::get<0>(points[m]);
        const TNumber y = std::get<1>(points[m]);

        if (sqDist(x, y, qx, qy) <= r2) *out++ = ids[m];

        if (axis == 0 ? qx - r <= x : qy - r <= y)
            within(qx, qy, r, out, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? qx + r >= x : qy + r >= y)
            within(qx, qy, r, out, m + 1, right, (axis + 1) % 2);
    }

    void sortKD(const TIndex left, const TIndex right, const std::uint8_t axis) {
        if (right - left <= nodeSize) return;
        const TIndex m = (left + right) >> 1;
        if (axis == 0) {
            select<0>(m, left, right);
        } else {
            select<1>(m, left, right);
        }
        sortKD(left, m - 1, (axis + 1) % 2);
        sortKD(m + 1, right, (axis + 1) % 2);
    }

    template <std::uint8_t axis>
    void select(const TIndex k, TIndex left, TIndex right) {

        while (right > left) {
            if (right - left > 600) {
                const TIndex n = right - left + 1;
                const TIndex m = k - left + 1;
                const double z = log(n);
                const double s = 0.5 * exp(2 * z / 3);
                const double sd = 0.5 * sqrt(z * s * (n - s) / n) * (2 * m < n ? -1 : 1);
                const TIndex newLeft = std::max(left, TIndex(k - m * s / n + sd));
                const TIndex newRight = std::min(right, TIndex(k + (n - m) * s / n + sd));
                select<axis>(k, newLeft, newRight);
            }

            const TNumber t = std::get<axis>(points[k]);
            TIndex i = left;
            TIndex j = right;

            swapItem(left, k);
            if (std::get<axis>(points[right]) > t) swapItem(left, right);

            while (i < j) {
                swapItem(i, j);
                i++;
                j--;
                while (std::get<axis>(points[i]) < t) i++;
                while (std::get<axis>(points[j]) > t) j--;
            }

            if (std::get<axis>(points[left]) == t)
                swapItem(left, j);
            else {
                j++;
                swapItem(j, right);
            }

            if (j <= k) left = j + 1;
            if (k <= j) right = j - 1;
        }
    }

    void swapItem(const TIndex i, const TIndex j) {
        std::iter_swap(ids.begin() + i, ids.begin() + j);
        std::iter_swap(points.begin() + i, points.begin() + j);
    }

    TNumber sqDist(const TNumber ax, const TNumber ay, const TNumber bx, const TNumber by) {
        const TNumber dx = ax - bx;
        const TNumber dy = ay - by;
        return dx * dx + dy * dy;
    }
};

} // namespace kdbush
<|endoftext|>